57 files changed, 13558 insertions, 0 deletions
diff --git a/core/pim/addressbook/.cvsignore b/core/pim/addressbook/.cvsignore new file mode 100644 index 0000000..28d87f2 --- a/dev/null +++ b/core/pim/addressbook/.cvsignore @@ -0,0 +1,16 @@ +moc_* +Makefile +abeditorbase.h +abaddress.h +abcompanybase.h +abnamebase.h +abeditorbase.cpp +abaddress.cpp +abcompanybase.cpp +abnamebase.cpp +abeditorpage2base.ui +abeditorpage2base.h +abeditorpage2base.cpp +addresssettingsbase.h +addresssettingsbase.cpp + diff --git a/core/pim/addressbook/Makefile.in b/core/pim/addressbook/Makefile.in new file mode 100644 index 0000000..93c73c3 --- a/dev/null +++ b/core/pim/addressbook/Makefile.in @@ -0,0 +1,244 @@ +############################################################################# + +####### Compiler, tools and options + +CXX = $(SYSCONF_CXX) $(QT_CXX_MT) +CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) +CC = $(SYSCONF_CC) $(QT_C_MT) +CFLAGS = $(SYSCONF_CFLAGS) +INCPATH = -I$(QPEDIR)/include +LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT) +LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS) $(SYSCONF_LIBS_QTAPP) +MOC = $(SYSCONF_MOC) +UIC = $(SYSCONF_UIC) + +####### Target + +DESTDIR = $(QPEDIR)/bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = addressbook +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = addressbook.h \ + abeditor.h \ + ablabel.h \ + abtable.h \ + addresssettings.h +SOURCES = main.cpp \ + addressbook.cpp \ + abeditor.cpp \ + ablabel.cpp \ + abtable.cpp \ + addresssettings.cpp +OBJECTS = main.o \ + addressbook.o \ + abeditor.o \ + ablabel.o \ + abtable.o \ + addresssettings.o \ + addresssettingsbase.o +INTERFACES = addresssettingsbase.ui +UICDECLS = addresssettingsbase.h +UICIMPLS = addresssettingsbase.cpp +SRCMOC = moc_addressbook.cpp \ + moc_abeditor.cpp \ + moc_ablabel.cpp \ + moc_abtable.cpp \ + moc_addresssettings.cpp \ + moc_addresssettingsbase.cpp +OBJMOC = moc_addressbook.o \ + moc_abeditor.o \ + moc_ablabel.o \ + moc_abtable.o \ + moc_addresssettings.o \ + moc_addresssettingsbase.o + + +####### Implicit rules + +.SUFFIXES: .cpp .cxx .cc .C .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.C.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + + +all: $(DESTDIR)$(TARGET) + +$(DESTDIR)$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS) + $(SYSCONF_LINK) $(LFLAGS) -o $(DESTDIR)$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) + +moc: $(SRCMOC) + +tmake: + tmake p4addressbook.pro + +clean: + -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) + -rm -f *~ core + -rm -f allmoc.cpp + +####### Extension Modules + +listpromodules: + @echo + +listallmodules: + @echo + +listaddonpromodules: + @echo + +listaddonentmodules: + @echo + + +REQUIRES= + +####### Sub-libraries + + +###### Combined headers + + + +####### Compile + +main.o: main.cpp \ + addressbook.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/qcopenvelope_qws.h + +addressbook.o: addressbook.cpp \ + abeditor.h \ + $(QPEDIR)/include/qpe/contact.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/recordfields.h \ + ablabel.h \ + abtable.h \ + $(QPEDIR)/include/qpe/categories.h \ + addresssettings.h \ + addresssettingsbase.h \ + addressbook.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/finddialog.h \ + $(QPEDIR)/include/qpe/global.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/ir.h \ + $(QPEDIR)/include/qpe/qpemessagebox.h \ + $(QPEDIR)/include/qpe/qcopenvelope_qws.h \ + $(QPEDIR)/include/qpe/qpemenubar.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h + +abeditor.o: abeditor.cpp \ + abeditor.h \ + $(QPEDIR)/include/qpe/contact.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/recordfields.h \ + addresspicker.h \ + $(QPEDIR)/include/qpe/categoryselect.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/qpedialog.h + +ablabel.o: ablabel.cpp \ + ablabel.h \ + $(QPEDIR)/include/qpe/contact.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/recordfields.h \ + $(QPEDIR)/include/qpe/stringutil.h + +abtable.o: abtable.cpp \ + $(QPEDIR)/include/qpe/categoryselect.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/stringutil.h \ + $(QPEDIR)/include/qpe/qcopenvelope_qws.h \ + abtable.h \ + $(QPEDIR)/include/qpe/categories.h \ + $(QPEDIR)/include/qpe/contact.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/recordfields.h + +addresssettings.o: addresssettings.cpp \ + addresssettings.h \ + addresssettingsbase.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/contact.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/recordfields.h + +addresssettingsbase.h: addresssettingsbase.ui + $(UIC) addresssettingsbase.ui -o $(INTERFACE_DECL_PATH)/addresssettingsbase.h + +addresssettingsbase.cpp: addresssettingsbase.ui + $(UIC) addresssettingsbase.ui -i addresssettingsbase.h -o addresssettingsbase.cpp + +addresssettingsbase.o: addresssettingsbase.cpp \ + addresssettingsbase.h \ + addresssettingsbase.ui + +moc_addressbook.o: moc_addressbook.cpp \ + addressbook.h + +moc_abeditor.o: moc_abeditor.cpp \ + abeditor.h \ + $(QPEDIR)/include/qpe/contact.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/recordfields.h + +moc_ablabel.o: moc_ablabel.cpp \ + ablabel.h \ + $(QPEDIR)/include/qpe/contact.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/recordfields.h + +moc_abtable.o: moc_abtable.cpp \ + abtable.h \ + $(QPEDIR)/include/qpe/categories.h \ + $(QPEDIR)/include/qpe/contact.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/recordfields.h + +moc_addresssettings.o: moc_addresssettings.cpp \ + addresssettings.h \ + addresssettingsbase.h + +moc_addresssettingsbase.o: moc_addresssettingsbase.cpp \ + addresssettingsbase.h + +moc_addressbook.cpp: addressbook.h + $(MOC) addressbook.h -o moc_addressbook.cpp + +moc_abeditor.cpp: abeditor.h + $(MOC) abeditor.h -o moc_abeditor.cpp + +moc_ablabel.cpp: ablabel.h + $(MOC) ablabel.h -o moc_ablabel.cpp + +moc_abtable.cpp: abtable.h + $(MOC) abtable.h -o moc_abtable.cpp + +moc_addresssettings.cpp: addresssettings.h + $(MOC) addresssettings.h -o moc_addresssettings.cpp + +moc_addresssettingsbase.cpp: addresssettingsbase.h + $(MOC) addresssettingsbase.h -o moc_addresssettingsbase.cpp + + diff --git a/core/pim/addressbook/abeditor.cpp b/core/pim/addressbook/abeditor.cpp new file mode 100644 index 0000000..6354db9 --- a/dev/null +++ b/core/pim/addressbook/abeditor.cpp @@ -0,0 +1,619 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 "abeditor.h" +#include "addresspicker.h" + +#include <qpe/categoryselect.h> +#include <qpe/qpeapplication.h> +#include <qpe/qpedialog.h> + +#include <qcombobox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qmultilineedit.h> +#include <qscrollview.h> +#include <qtoolbutton.h> +#include <qpushbutton.h> +#include <qmainwindow.h> + + +static inline bool containsAlphaNum( const QString &str ); +static inline bool constainsWhiteSpace( const QString &str ); + + +// helper functions, convert our comma delimited list to proper +// file format... +void parseEmailFrom( const QString &txt, QString &strDefaultEmail, + QString &strAll ); + +// helper convert from file format to comma delimited... +void parseEmailTo( const QString &strDefaultEmail, + const QString &strOtherEmail, QString &strBack ); + + + +AbEditor::AbEditor( const Contact &entry, const QValueList<int> *newOrdered, + QStringList *slNewOrdered, + QWidget *parent = 0, const char *name = 0, WFlags fl = 0 ) + : QDialog( parent, name, TRUE, fl ), + orderedValues( newOrdered ), + slOrdered( slNewOrdered ) +{ + init(); + initMap(); + setEntry( entry ); +} + +AbEditor::~AbEditor() +{ +} + +void AbEditor::init() +{ + middleEdit = 0; + QVBoxLayout *vb = new QVBoxLayout( this ); + svPage = new QScrollView( this ); + svPage->setHScrollBarMode( QScrollView::AlwaysOff ); + vb->addWidget( svPage ); + svPage->setResizePolicy( QScrollView::AutoOneFit ); + svPage->setFrameStyle( QFrame::NoFrame ); + + QWidget *container = new QWidget( svPage->viewport() ); + svPage->addChild( container ); + + QGridLayout *gl = new QGridLayout( container, 20, 2, 4, 2 ); + + QLabel *l = new QLabel( tr("First Name"), container ); + gl->addWidget( l, 0, 0 ); + firstEdit = new QLineEdit( container ); + gl->addWidget( firstEdit, 0, 1 ); + + l = new QLabel( tr("Last Name"), container ); + gl->addWidget( l, 1, 0 ); + lastEdit = new QLineEdit( container ); + gl->addWidget( lastEdit, 1, 1 ); + + l = new QLabel( tr("Categories"), container ); + gl->addWidget( l, 2, 0 ); + + cmbCat = new CategorySelect( container ); + gl->addWidget( cmbCat, 2, 1 ); + + int i; + bool foundGender, + foundNotes; + foundGender = foundNotes = false; + QStringList::ConstIterator it = slOrdered->begin(); + for ( i = 0; it != slOrdered->end(); i++, ++it ) { + if ( !foundGender && *it == tr("Gender") ) { + foundGender = true; + } else if ( !foundNotes && *it == tr("Notes") ) { + foundNotes = true; + } else { + l = new QLabel( *it, container ); + listName.append( l ); + gl->addWidget( l, i + 3, 0 ); + QLineEdit *e = new QLineEdit( container ); + listValue.append( e ); + gl->addWidget( e, i + 3, 1 ); + if ( *it == tr( "Middle Name" ) ) + middleEdit = e; + } + } + l = new QLabel( tr("Gender"), container ); + gl->addWidget( l, slOrdered->count() + 3, 0 ); + genderCombo = new QComboBox( container ); + genderCombo->insertItem( "", 0 ); + genderCombo->insertItem( tr( "Male" ), 1 ); + genderCombo->insertItem( tr( "Female" ), 2 ); + gl->addWidget( genderCombo, slOrdered->count() + 3, 1 ); + + dlgNote = new QDialog( this, "Note Dialog", TRUE ); + dlgNote->setCaption( tr("Enter Note") ); + QVBoxLayout *vbNote = new QVBoxLayout( dlgNote ); + // lblNote = new QLabel( dlgNote ); + // lblNote->setMinimumSize( lblNote->sizeHint() + QSize( 0, 4 ) ); + // vbNote->addWidget( lblNote ); + txtNote = new QMultiLineEdit( dlgNote ); + vbNote->addWidget( txtNote ); + + QHBoxLayout *hb = new QHBoxLayout( vb ); + hb->addStretch( 2 ); + QPushButton *pb = new QPushButton( tr("Notes..."), this ); + hb->addWidget( pb ); + connect( pb, SIGNAL(clicked()), this, SLOT(slotNote()) ); + + new QPEDialogListener(this); +} + +void AbEditor::initMap() +{ + /* + // since the fields and the XML fields exist, create a map + // between them... + Config cfg1( "AddressBook" ); + Config cfg2( "AddressBook" ); + QString strCfg1, + strCfg2; + int i; + + // This stuff better exist... + cfg1.setGroup( "AddressFields" ); + cfg2.setGroup( "XMLFields" ); + i = 0; + strCfg1 = cfg1.readEntry( "Field" + QString::number(i), QString::null ); + strCfg2 = cfg2.readEntry( "XMLField" + QString::number(i++), + QString::null ); + while ( !strCfg1.isNull() && !strCfg2.isNull() ) { + mapField.insert( strCfg1, strCfg2 ); + strCfg1 = cfg1.readEntry( "Field" + QString::number(i), + QString::null ); + strCfg2 = cfg2.readEntry( "XMLField" + QString::number(i++), + QString::null ); + } + */ +} + +void AbEditor::loadFields() +{ + QStringList::ConstIterator it; + QListIterator<QLabel> lit( listName ); + for ( it = slOrdered->begin(); *lit; ++lit, ++it ) { + (*lit)->setText( *it ); + } +} + +void AbEditor::setEntry( const Contact &entry ) +{ + ent = entry; + QListIterator<QLineEdit> it( listValue ); + firstEdit->setText( ent.firstName() ); + lastEdit->setText( ent.lastName() ); + cmbCat->setCategories( ent.categories(), "Contacts", tr("Contacts") ); + + // ### Fix... + QValueList<int>::ConstIterator itVl; + for ( itVl = orderedValues->begin(); *it && itVl != orderedValues->end(); + ++itVl, ++it ) { + switch( *itVl ) { + case Qtopia::Title: + (*it)->setText(ent.title()); + break; + case Qtopia::MiddleName: + (*it)->setText( ent.middleName() ); + break; + case Qtopia::Suffix: + (*it)->setText( ent.suffix() ); + break; + + // email + case Qtopia::DefaultEmail: + case Qtopia::Emails: + { + QString strDefEmail = ent.defaultEmail(); + QString strAllEmail = ent.emails(); + QString strFinal; + parseEmailTo( strDefEmail, strAllEmail, strFinal ); + (*it)->setText( strFinal ); + // make sure we see the "default" + (*it)->home( false ); + break; + } + + // home + case Qtopia::HomeStreet: + (*it)->setText(ent.homeStreet() ); + break; + case Qtopia::HomeCity: + (*it)->setText( ent.homeCity() ); + break; + case Qtopia::HomeState: + (*it)->setText( ent.homeState() ); + break; + case Qtopia::HomeZip: + (*it)->setText( ent.homeZip() ); + break; + case Qtopia::HomeCountry: + (*it)->setText( ent.homeCountry() ); + break; + case Qtopia::HomePhone: + (*it)->setText( ent.homePhone() ); + break; + case Qtopia::HomeFax: + (*it)->setText( ent.homeFax() ); + break; + case Qtopia::HomeMobile: + (*it)->setText( ent.homeMobile() ); + break; + case Qtopia::HomeWebPage: + (*it)->setText( ent.homeWebpage() ); + break; + + // business + case Qtopia::Company: + (*it)->setText( ent.company() ); + break; + case Qtopia::BusinessStreet: + (*it)->setText( ent.businessStreet() ); + break; + case Qtopia::BusinessCity: + (*it)->setText( ent.businessCity() ); + break; + case Qtopia::BusinessState: + (*it)->setText( ent.businessState() ); + break; + case Qtopia::BusinessZip: + (*it)->setText( ent.businessZip() ); + break; + case Qtopia::BusinessCountry: + (*it)->setText( ent.businessCountry() ); + break; + case Qtopia::BusinessWebPage: + (*it)->setText( ent.businessWebpage() ); + break; + case Qtopia::JobTitle: + (*it)->setText( ent.jobTitle() ); + break; + case Qtopia::Department: + (*it)->setText( ent.department() ); + break; + case Qtopia::Office: + (*it)->setText( ent.office() ); + break; + case Qtopia::BusinessPhone: + (*it)->setText( ent.businessPhone() ); + break; + case Qtopia::BusinessFax: + (*it)->setText( ent.businessFax() ); + break; + case Qtopia::BusinessMobile: + (*it)->setText( ent.businessMobile() ); + break; + case Qtopia::BusinessPager: + (*it)->setText( ent.businessPager() ); + break; + case Qtopia::Profession: + (*it)->setText( ent.profession() ); + break; + case Qtopia::Assistant: + (*it)->setText( ent.assistant() ); + break; + case Qtopia::Manager: + (*it)->setText( ent.manager() ); + break; + + // personal + case Qtopia::Spouse: + (*it)->setText( ent.spouse() ); + break; + case Qtopia::Children: + (*it)->setText( ent.children() ); + break; + case Qtopia::Birthday: + (*it)->setText( ent.birthday() ); + break; + case Qtopia::Anniversary: + (*it)->setText( ent.anniversary() ); + break; + case Qtopia::Nickname: + (*it)->setText( ent.nickname() ); + break; + + } + } + + QString gender = ent.gender(); + genderCombo->setCurrentItem( gender.toInt() ); + + txtNote->setText( ent.notes() ); +} + +void AbEditor::accept() +{ + if ( isEmpty() ) + reject(); + else { + saveEntry(); + QDialog::accept(); + } +} + +bool AbEditor::isEmpty() +{ + // analyze all the fields and make sure there is _something_ there + // that warrants saving... + QString t = firstEdit->text(); + if ( !t.isEmpty() && containsAlphaNum( t ) ) + return false; + + t = lastEdit->text(); + if ( !t.isEmpty() && containsAlphaNum( t ) ) + return false; + + QListIterator<QLineEdit> it( listValue ); + for ( ; it.current(); ++it ) { + t = it.current()->text(); + if ( !t.isEmpty() && containsAlphaNum( t ) ) + return false; + } + + t = txtNote->text(); + if ( !t.isEmpty() && containsAlphaNum( t ) ) + return false; + + return true; +} + +void AbEditor::saveEntry() +{ + QString strDefaultEmail, strOtherEmail; + + // determine if there has been a change in names + if ( ent.firstName() != firstEdit->text() || + ent.lastName() != lastEdit->text() + || (middleEdit && ent.middleName() != middleEdit->text()) ) { + // set the names + ent.setFirstName( firstEdit->text() ); + ent.setLastName( lastEdit->text() ); + if ( middleEdit ) + ent.setMiddleName( middleEdit->text() ); + ent.setFileAs(); + } + + ent.setCategories( cmbCat->currentCategories() ); + + QListIterator<QLineEdit> it( listValue ); + int i; + QValueList<int>::ConstIterator<int> vlIt; + for ( i = 0, vlIt = orderedValues->begin(); + it.current(); ++it, ++vlIt, i++ ) { + switch( *vlIt ) { + case Qtopia::Title: + ent.setTitle( it.current()->text() ); + break; + case Qtopia::MiddleName: + ent.setMiddleName( it.current()->text() ); + break; + case Qtopia::Suffix: + ent.setSuffix( it.current()->text() ); + break; +// case Qtopia::Category: +// { +// // QStringList slCat = QStringList::split( ";", value ); +// // QValueList<int> cat; +// // for ( QStringList::ConstIterator it = slCat.begin(); +// // it != slCat.end(); ++it ) +// // cat.append( (*it).toInt() ); +// // ent.setCategories( cat ); +// } +// break; + + // email + case Qtopia::DefaultEmail: + case Qtopia::Emails: + parseEmailFrom( it.current()->text(), strDefaultEmail, + strOtherEmail ); + ent.setDefaultEmail( strDefaultEmail ); + ent.setEmails( strOtherEmail ); + break; + + // home + case Qtopia::HomeStreet: + ent.setHomeStreet( it.current()->text() ); + break; + case Qtopia::HomeCity: + ent.setHomeCity( it.current()->text() ); + break; + case Qtopia::HomeState: + ent.setHomeState( it.current()->text() ); + break; + case Qtopia::HomeZip: + ent.setHomeZip( it.current()->text() ); + break; + case Qtopia::HomeCountry: + ent.setHomeCountry( it.current()->text() ); + break; + case Qtopia::HomePhone: + ent.setHomePhone( it.current()->text() ); + break; + case Qtopia::HomeFax: + ent.setHomeFax( it.current()->text() ); + break; + case Qtopia::HomeMobile: + ent.setHomeMobile( it.current()->text() ); + break; + case Qtopia::HomeWebPage: + ent.setHomeWebpage( it.current()->text() ); + break; + + // business + case Qtopia::Company: + ent.setCompany( it.current()->text() ); + break; + case Qtopia::BusinessStreet: + ent.setBusinessStreet( it.current()->text() ); + break; + case Qtopia::BusinessCity: + ent.setBusinessCity( it.current()->text() ); + break; + case Qtopia::BusinessState: + ent.setBusinessState( it.current()->text() ); + break; + case Qtopia::BusinessZip: + ent.setBusinessZip( it.current()->text() ); + break; + case Qtopia::BusinessCountry: + ent.setBusinessCountry( it.current()->text() ); + break; + case Qtopia::BusinessWebPage: + ent.setBusinessWebpage( it.current()->text() ); + break; + case Qtopia::JobTitle: + ent.setJobTitle( it.current()->text() ); + break; + case Qtopia::Department: + ent.setDepartment( it.current()->text() ); + break; + case Qtopia::Office: + ent.setOffice( it.current()->text() ); + break; + case Qtopia::BusinessPhone: + ent.setBusinessPhone( it.current()->text() ); + break; + case Qtopia::BusinessFax: + ent.setBusinessFax( it.current()->text() ); + break; + case Qtopia::BusinessMobile: + ent.setBusinessMobile( it.current()->text() ); + break; + case Qtopia::BusinessPager: + ent.setBusinessPager( it.current()->text() ); + break; + case Qtopia::Profession: + ent.setProfession( it.current()->text() ); + break; + case Qtopia::Assistant: + ent.setAssistant( it.current()->text() ); + break; + case Qtopia::Manager: + ent.setManager( it.current()->text() ); + break; + + // personal + case Qtopia::Spouse: + ent.setSpouse( it.current()->text() ); + break; + case Qtopia::Children: + ent.setChildren( it.current()->text() ); + break; + case Qtopia::Birthday: + ent.setBirthday( it.current()->text() ); + break; + case Qtopia::Anniversary: + ent.setAnniversary( it.current()->text() ); + break; + case Qtopia::Nickname: + ent.setNickname( it.current()->text() ); + break; + default: + break; + + } + } + + int gender = genderCombo->currentItem(); + ent.setGender( QString::number( gender ) ); + + QString str = txtNote->text(); + if ( !str.isNull() ) + ent.setNotes( str ); +} + +void AbEditor::slotNote() +{ + dlgNote->showMaximized(); + if ( !dlgNote->exec() ) { + // reset the note... + txtNote->setText( ent.notes() ); + } +} + +void AbEditor::setNameFocus() +{ + firstEdit->setFocus(); +} + +void parseEmailFrom( const QString &txt, QString &strDefaultEmail, + QString &strAll ) +{ + int where, + start; + if ( txt.isEmpty() ) + return; + // find the first + where = txt.find( ',' ); + if ( where < 0 ) { + strDefaultEmail = txt; + strAll = txt; + } else { + strDefaultEmail = txt.left( where ).stripWhiteSpace(); + strAll = strDefaultEmail; + while ( where > -1 ) { + strAll.append(" "); + start = where; + where = txt.find( ',', where + 1 ); + if ( where > - 1 ) + strAll.append( txt.mid(start + 1, where - start - 1).stripWhiteSpace() ); + else // grab until the end... + strAll.append( txt.right(txt.length() - start - 1).stripWhiteSpace() ); + } + } +} + +void parseEmailTo( const QString &strDefaultEmail, + const QString &strOtherEmail, QString &strBack ) +{ + // create a comma dilimeted set of emails... + // use the power of short circuiting... + bool foundDefault = false; + QString strTmp; + int start = 0; + int where; + // start at the beginng. + strBack = strDefaultEmail; + where = 0; + while ( where > -1 ) { + start = where; + where = strOtherEmail.find( ' ', where + 1 ); + if ( where > 0 ) { + strTmp = strOtherEmail.mid( start, where - start ).stripWhiteSpace(); + } else + strTmp = strOtherEmail.right( strOtherEmail.length() - start ).stripWhiteSpace(); + if ( foundDefault || strTmp != strDefaultEmail ) { + strBack.append( ", " ); + strBack.append( strTmp ); + } else + foundDefault = true; + } +} + + +static inline bool containsAlphaNum( const QString &str ) +{ + int i, + count = str.length(); + for ( i = 0; i < count; i++ ) + if ( !str[i].isSpace() ) + return TRUE; + return FALSE; +} + +static inline bool constainsWhiteSpace( const QString &str ) +{ + int i, + count = str.length(); + for (i = 0; i < count; i++ ) + if ( str[i].isSpace() ) + return TRUE; + return FALSE; +} + diff --git a/core/pim/addressbook/abeditor.h b/core/pim/addressbook/abeditor.h new file mode 100644 index 0000000..9ce6704 --- a/dev/null +++ b/core/pim/addressbook/abeditor.h @@ -0,0 +1,79 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 ABEDITOR_H +#define ABEDITOR_H + +#include <qpe/contact.h> + +#include <qdialog.h> +#include <qlist.h> +#include <qmap.h> +#include <qstringlist.h> + +class QScrollView; +class QMultiLineEdit; +class QLineEdit; +class QLabel; +class QComboBox; +class CategorySelect; + +class AbEditor : public QDialog +{ + Q_OBJECT +public: + AbEditor( const Contact &entry, const QValueList<int> *newOrdedValues, + QStringList *slNewOrdered, + QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + ~AbEditor(); + void loadFields(); + void setNameFocus(); + Contact entry() const { return ent; } + +public slots: + void slotNote(); + void setEntry( const Contact &entry ); + +protected slots: + void accept(); + +private: + void init(); + void initMap(); + void saveEntry(); + bool isEmpty(); + +private: + QDialog *dlgNote; + QLabel *lblNote; + QMultiLineEdit *txtNote; + Contact ent; + QScrollView *svPage; + QLineEdit *firstEdit; + QLineEdit *lastEdit; + QLineEdit *middleEdit; + QComboBox *genderCombo; + QList<QLineEdit> listValue; + QList<QLabel> listName; + const QValueList<int> *orderedValues; + QStringList *slOrdered; + CategorySelect *cmbCat; +}; + +#endif diff --git a/core/pim/addressbook/ablabel.cpp b/core/pim/addressbook/ablabel.cpp new file mode 100644 index 0000000..3bf3e12 --- a/dev/null +++ b/core/pim/addressbook/ablabel.cpp @@ -0,0 +1,53 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 "ablabel.h" + +#include <qpe/stringutil.h> + +#include <qregexp.h> +#include <qstylesheet.h> + +AbLabel::AbLabel( QWidget *parent, const char *name ) + : QTextView( parent, name ) +{ +} + +AbLabel::~AbLabel() +{ +} + +void AbLabel::init( const Contact &entry ) +{ + ent = entry; +} + +void AbLabel::sync() +{ + QString text = ent.toRichText(); + setText( text ); +} + +void AbLabel::keyPressEvent( QKeyEvent *e ) +{ + if ( e->key() == Qt::Key_F33 ) { + emit okPressed(); + } +} diff --git a/core/pim/addressbook/ablabel.h b/core/pim/addressbook/ablabel.h new file mode 100644 index 0000000..cfbd999 --- a/dev/null +++ b/core/pim/addressbook/ablabel.h @@ -0,0 +1,50 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 ABLABEL_H +#define ABLABEL_H + +#include <qpe/contact.h> +#include <qtextview.h> + +class AbLabel : public QTextView +{ + Q_OBJECT + +public: + AbLabel( QWidget *parent, const char *name = 0 ); + ~AbLabel(); + +public slots: + void init( const Contact &entry ); + void sync(); + +signals: + void okPressed(); + +protected: + void keyPressEvent( QKeyEvent * ); + +private: + Contact ent; + +}; + +#endif // ABLABEL_H + diff --git a/core/pim/addressbook/abtable.cpp b/core/pim/addressbook/abtable.cpp new file mode 100644 index 0000000..0911edf --- a/dev/null +++ b/core/pim/addressbook/abtable.cpp @@ -0,0 +1,1091 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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/categoryselect.h> +#include <qpe/config.h> +#include <qpe/stringutil.h> +#include <qpe/qcopenvelope_qws.h> + +#include <qasciidict.h> +#include <qdatetime.h> +#include <qfile.h> + +#include "abtable.h" + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> + +#include <ctype.h> //toupper() for key hack + +static bool contactCompare( const Contact &cnt, const QRegExp &r, int category ); + +//### qtmail/addresslist.cpp hardcodes this filename as well +static QString journalFileName() +{ + QString str = getenv("HOME"); + str +="/.abjournal"; + return str; +} + + + +/*! + \class AbTableItem abtable.h + + \brief QTableItem based class for showing a field of an entry +*/ + +AbTableItem::AbTableItem( QTable *t, EditType et, const QString &s, + const QString &secondSortKey) + : QTableItem( t, et, s ) +{ + // sortKey = s.lower() + QChar( '\0' ) + secondSortKey.lower(); + sortKey = Qtopia::buildSortKey( s, secondSortKey ); +} + +int AbTableItem::alignment() const +{ + return AlignLeft|AlignVCenter; +} + +QString AbTableItem::key() const +{ + return sortKey; +} + +// A way to reset the item, without out doing a delete or a new... +void AbTableItem::setItem( const QString &txt, const QString &secondKey ) +{ + setText( txt ); + sortKey = Qtopia::buildSortKey( txt, secondKey ); + + // sortKey = txt.lower() + QChar( '\0' ) + secondKey.lower(); +} + +/*! + \class AbPickItem abtable.h + + \brief QTableItem based class for showing slection of an entry +*/ + +AbPickItem::AbPickItem( QTable *t ) : + QTableItem(t, WhenCurrent, "?") +{ +} + +QWidget *AbPickItem::createEditor() const +{ + QComboBox* combo = new QComboBox( table()->viewport() ); + ( (AbPickItem*)this )->cb = combo; + AbTable* t = static_cast<AbTable*>(table()); + QStringList c = t->choiceNames(); + int cur = 0; + for (QStringList::ConstIterator it = c.begin(); it!=c.end(); ++it) { + if ( *it == text() ) + cur = combo->count(); + combo->insertItem(*it); + } + combo->setCurrentItem(cur); + return combo; +} + +void AbPickItem::setContentFromEditor( QWidget *w ) +{ + if ( w->inherits("QComboBox") ) + setText( ( (QComboBox*)w )->currentText() ); + else + QTableItem::setContentFromEditor( w ); +} + +/*! + \class AbTable abtable.h + + \brief QTable based class for showing a list of entries +*/ + +AbTable::AbTable( const QValueList<int> *order, QWidget *parent, const char *name ) +// #ifdef QT_QTABLE_NOHEADER_CONSTRUCTOR +// : QTable( 0, 0, parent, name, TRUE ), +// #else + : QTable( parent, name ), +// #endif + lastSortCol( -1 ), + asc( TRUE ), + intFields( order ), + currFindRow( -2 ), + mCat( 0 ) +{ + mCat.load( categoryFileName() ); + setSelectionMode( NoSelection ); + init(); + setSorting( TRUE ); + connect( this, SIGNAL(clicked(int,int,int,const QPoint &)), + this, SLOT(itemClicked(int,int)) ); +} + +AbTable::~AbTable() +{ +} + +void AbTable::init() +{ + setNumRows( 0 ); + setNumCols( 2 ); + + horizontalHeader()->setLabel( 0, tr( "Full Name" )); + horizontalHeader()->setLabel( 1, tr( "Contact" )); + setLeftMargin( 0 ); + verticalHeader()->hide(); +} + +void AbTable::columnClicked( int col ) +{ + if ( !sorting() ) + return; + + if ( lastSortCol == -1 ) + lastSortCol = col; + + if ( col == lastSortCol ) { + asc = !asc; + } else { + lastSortCol = col; + asc = TRUE; + } + resort(); +} + +void AbTable::resort() +{ + if ( sorting() ) { + if ( lastSortCol == -1 ) + lastSortCol = 0; + sortColumn( lastSortCol, asc, TRUE ); + updateVisible(); + } +} + +Contact AbTable::currentEntry() +{ + Contact cnt; + AbTableItem *abItem; + abItem = static_cast<AbTableItem*>(item( currentRow(), 0 )); + if ( abItem ) { + cnt = contactList[abItem]; + } + return cnt; +} + +void AbTable::replaceCurrentEntry( const Contact &newContact ) +{ + int row = currentRow(); + updateJournal( newContact, Contact::ACTION_REPLACE, row ); + updateVisible(); + + journalFreeReplace( newContact, row ); +} + +void AbTable::deleteCurrentEntry() +{ + int row = currentRow(); + AbTableItem *abItem; + abItem = static_cast<AbTableItem*>(item( row, 0 )); + Contact oldContact; + oldContact = contactList[abItem]; + updateJournal( oldContact, Contact::ACTION_REMOVE, row ); + + // a little wasteful, but it ensure's there is only one place + // where we delete. + journalFreeRemove( row ); + updateVisible(); + + if ( numRows() == 0 ) + emit empty( TRUE ); +} + +void AbTable::clear() +{ + contactList.clear(); + for ( int r = 0; r < numRows(); ++r ) { + for ( int c = 0; c < numCols(); ++c ) { + if ( cellWidget( r, c ) ) + clearCellWidget( r, c ); + clearCell( r, c ); + } + } + setNumRows( 0 ); +} + +void AbTable::refresh() +{ + int rows = numRows(); + QString value; + AbTableItem *abi; + for ( int r = 0; r < rows; ++r ) { + abi = static_cast<AbTableItem*>( item(r, 0) ); + value = findContactContact( contactList[abi] ); + static_cast<AbTableItem*>( item(r, 1) )->setItem( value, abi->text() ); + } + resort(); +} + +void AbTable::keyPressEvent( QKeyEvent *e ) +{ + char key = toupper( e->ascii() ); + + if ( key >= 'A' && key <= 'Z' ) + moveTo( key ); + + switch( e->key() ) { + case Qt::Key_Space: + case Qt::Key_Return: + case Qt::Key_Enter: + emit details(); + break; + default: + QTable::keyPressEvent( e ); + } +} + +void AbTable::moveTo( char c ) +{ + + int rows = numRows(); + QString value; + AbTableItem *abi; + int r; + if ( asc ) { + r = 0; + while ( r < rows-1) { + abi = static_cast<AbTableItem*>( item(r, 0) ); + QChar first = abi->key()[0]; + //### is there a bug in QChar to char comparison??? + if ( first.row() || first.cell() >= c ) + break; + r++; + } + } else { + //### should probably disable reverse sorting instead + r = rows - 1; + while ( r > 0 ) { + abi = static_cast<AbTableItem*>( item(r, 0) ); + QChar first = abi->key()[0]; + //### is there a bug in QChar to char comparison??? + if ( first.row() || first.cell() >= c ) + break; + r--; + } + } + setCurrentCell( r, currentColumn() ); +} + + +QString AbTable::findContactName( const Contact &entry ) +{ + // We use the fileAs, then company, defaultEmail + QString str; + str = entry.fileAs(); + if ( str.isEmpty() ) { + str = entry.company(); + if ( str.isEmpty() ) { + str = entry.defaultEmail(); + } + } + return str; +} + +QString AbTable::findContactContact( const Contact &entry ) +{ + QString value; + value = ""; + for ( QValueList<int>::ConstIterator it = intFields->begin(); + it != intFields->end(); ++it ) { + switch ( *it ) { + default: + break; + case Qtopia::Title: + value = entry.title(); + break; + case Qtopia::Suffix: + value = entry.suffix(); + break; + case Qtopia::FileAs: + value = entry.fileAs(); + break; + case Qtopia::DefaultEmail: + value = entry.defaultEmail(); + case Qtopia::Emails: + value = entry.emails(); + break; + case Qtopia::HomeStreet: + value = entry.homeStreet(); + break; + case Qtopia::HomeCity: + value = entry.homeCity(); + break; + case Qtopia::HomeState: + value = entry.homeState(); + break; + case Qtopia::HomeZip: + value = entry.homeZip(); + break; + case Qtopia::HomeCountry: + value = entry.homeCountry(); + break; + case Qtopia::HomePhone: + value = entry.homePhone(); + break; + case Qtopia::HomeFax: + value = entry.homeFax(); + break; + case Qtopia::HomeMobile: + value = entry.homeMobile(); + break; + case Qtopia::HomeWebPage: + value = entry.homeWebpage(); + break; + case Qtopia::Company: + value = entry.company(); + break; + case Qtopia::BusinessCity: + value = entry.businessCity(); + break; + case Qtopia::BusinessStreet: + value = entry.businessStreet(); + break; + case Qtopia::BusinessZip: + value = entry.businessZip(); + break; + case Qtopia::BusinessCountry: + value = entry.businessCountry(); + break; + case Qtopia::BusinessWebPage: + value = entry.businessWebpage(); + break; + case Qtopia::JobTitle: + value = entry.jobTitle(); + break; + case Qtopia::Department: + value = entry.department(); + break; + case Qtopia::Office: + value = entry.office(); + break; + case Qtopia::BusinessPhone: + value = entry.businessPhone(); + break; + case Qtopia::BusinessFax: + value = entry.businessFax(); + break; + case Qtopia::BusinessMobile: + value = entry.businessMobile(); + break; + case Qtopia::BusinessPager: + value = entry.businessPager(); + break; + case Qtopia::Profession: + value = entry.profession(); + break; + case Qtopia::Assistant: + value = entry.assistant(); + break; + case Qtopia::Manager: + value = entry.manager(); + break; + case Qtopia::Spouse: + value = entry.spouse(); + break; + case Qtopia::Gender: + value = entry.gender(); + break; + case Qtopia::Birthday: + value = entry.birthday(); + break; + case Qtopia::Anniversary: + value = entry.anniversary(); + break; + case Qtopia::Nickname: + value = entry.nickname(); + break; + case Qtopia::Children: + value = entry.children(); + break; + case Qtopia::Notes: + value = entry.notes(); + break; + } + if ( !value.isEmpty() ) + break; + } + return value; +} + +void AbTable::addEntry( const Contact &newCnt ) +{ + int row = numRows(); + setNumRows( row + 1 ); + updateJournal( newCnt, Contact::ACTION_ADD ); + insertIntoTable( newCnt, row ); + setCurrentCell( row, 0 ); + updateVisible(); +} + +void AbTable::updateJournal( const Contact &cnt, + Contact::journal_action action, int row ) +{ + QFile f( journalFileName() ); + if ( !f.open(IO_WriteOnly|IO_Append) ) + return; + QString buf; + QCString str; + buf = "<Contact "; + cnt.save( buf ); + buf += " action=\"" + QString::number( (int)action ) + "\" "; + if ( action == Contact::ACTION_REMOVE || action == Contact::ACTION_REPLACE) + buf += " actionrow=\"" + QString::number(row) + "\" "; + buf += "/>\n"; + QCString cstr = buf.utf8(); + f.writeBlock( cstr.data(), cstr.length() ); + QCopEnvelope( "QPE/PIM", "addressbookUpdated()" ); +} + +bool AbTable::save( const QString &fn ) +{ +// QTime t; +// t.start(); + + QString strNewFile = fn + ".new"; + QFile f( strNewFile ); + if ( !f.open( IO_WriteOnly|IO_Raw ) ) + return false; + + int total_written; + QString out; + out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" + " <Groups>\n" + " </Groups>\n" + " <Contacts>\n"; + QMapIterator<AbTableItem*, Contact> it; + for ( it = contactList.begin(); it != contactList.end(); ++it ) { + out += "<Contact "; + it.data().save( out ); + out += "/>\n"; + QCString cstr = out.utf8(); + total_written = f.writeBlock( cstr.data(), cstr.length() ); + if ( total_written != int(cstr.length()) ) { + f.close(); + QFile::remove( strNewFile ); + return false; + } + out = ""; + } + out += " </Contacts>\n</AddressBook>\n"; + + QCString 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(); + +// qDebug("saving: %d", t.elapsed() ); + + // 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(), fn.latin1() ) < 0 ) { + qWarning( "problem renaming file %s to %s, errno: %d", + strNewFile.latin1(), fn.latin1(), errno ); + // remove the tmp file... + QFile::remove( strNewFile ); + } + // remove the journal... + QFile::remove( journalFileName() ); + return true; +} + +void AbTable::load( const QString &fn ) +{ + setSorting( false ); + loadFile( fn, false ); + // merge in the journal + if ( QFile::exists( journalFileName() ) ) { + loadFile( journalFileName(), true ); + save( fn ); + } + setSorting( true ); + resort(); +} + +void AbTable::loadFile( const QString &strFile, bool journalFile ) +{ +// QTime t; +// t.start(); + QFile f( strFile ); + if ( !f.open(IO_ReadOnly) ) + return; + QList<Contact> list; + list.setAutoDelete( TRUE ); + QByteArray ba = f.readAll(); + f.close(); + char *uc = ba.data();//(QChar *)data.unicode(); + int len = ba.size();//data.length(); + bool foundAction = false; + Contact::journal_action action; + bool foundKey = false; + int journalKey = 0; + + const int JOURNALACTION = Qtopia::Notes + 1; + const int JOURNALROW = JOURNALACTION + 1; + + // ********************************** + // CHANGE THE SIZE OF THE DICT IF YOU ADD ANY MORE FIELDS!!!! + // ********************************** + 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) ); + + int i = 0; + int num = 0; + char *point; + while ( (point = strstr( uc+i, "<Contact " ) ) != NULL ) { + i = point - uc; + // if we are reading the standard file, we just need to + // insert info, so just say we'll do an insert... + action = Contact::ACTION_ADD; + // new Contact + Contact *cnt = new Contact; + i += 9; + while ( 1 ) { + while ( i < len && (uc[i] == ' ' || uc[i] == '\n' || uc[i] == '\r') ) + i++; + if ( i >= len-2 || (uc[i] == '/' && uc[i+1] == '>') ) + break; + // we have another attribute read it. + int j = i; + while ( j < len && uc[j] != '=' ) + j++; + char *attr = uc+i; + uc[j] = '\0'; + //qDebug("attr=%s", attr.latin1() ); + i = ++j; // skip = + while ( i < len && uc[i] != '"' ) + i++; + j = ++i; + bool haveEnt = FALSE; + bool haveUtf = FALSE; + while ( j < len && uc[j] != '"' ) { + if ( uc[j] == '&' ) + haveEnt = TRUE; + if ( ((unsigned char)uc[j]) > 0x7f ) + haveUtf = TRUE; + j++; + } + + if ( j == i ) { + // empty value + i = j + 1; + continue; + } + + QString value = haveUtf ? QString::fromUtf8( uc+i, j-i ) + : QString::fromLatin1( uc+i, j-i ); + if ( haveEnt ) + value = Qtopia::plainString( value ); + i = j + 1; + + int *find = dict[ attr ]; + if ( !find ) { + cnt->setCustomField(attr, value); + continue; + } +#if 1 + switch( *find ) { + case Qtopia::AddressUid: + cnt->setUid( value.toInt() ); + break; + case Qtopia::AddressCategory: + cnt->setCategories( Qtopia::Record::idsFromString( value )); + break; + case JOURNALACTION: + action = Contact::journal_action(value.toInt()); + break; + case JOURNALROW: + journalKey = value.toInt(); + break; + + default: + cnt->insert( *find, value ); + break; + } +#endif + } + + // sadly we can't delay adding of items from the journal to get + // the proper effect, but then, the journal should _never_ be + // that huge, and recovering from a crash is not necessarily + // a *fast* thing. + switch ( action ) { + case Contact::ACTION_ADD: + if ( journalFile ) { + int myrows = numRows(); + setNumRows( myrows + 1 ); + insertIntoTable( *cnt, myrows ); + delete cnt; + } + else + list.append( cnt ); + break; + case Contact::ACTION_REMOVE: + // yup, we don't use the entry to remove the object... + journalFreeRemove( journalKey ); + delete cnt; + break; + case Contact::ACTION_REPLACE: + journalFreeReplace( *cnt, journalKey ); + delete cnt; + break; + default: + break; + } + num++; + foundAction = false; + foundKey = false; +// if ( num % 100 == 0 ) { +// qDebug("loading file, num=%d, t=%d", num, t.elapsed() ); +// } + } + if ( list.count() > 0 ) { + internalAddEntries( list ); + } +// qDebug("done loading %d, t=%d", num, t.elapsed() ); + +} + +void AbTable::realignTable( int row ) +{ + QTableItem *ti1, + *ti2; + int totalRows = numRows(); + for ( int curr = row; curr < totalRows - 1; curr++ ) { + // the same info from the todo list still applies, but I + // don't think it is _too_ bad. + ti1 = item( curr + 1, 0 ); + ti2 = item( curr + 1, 1 ); + takeItem( ti1 ); + takeItem( ti2 ); + setItem( curr, 0, ti1 ); + setItem( curr, 1, ti2 ); + } + setNumRows( totalRows - 1 ); + resort(); +} + +void AbTable::insertIntoTable( const Contact &cnt, int row ) +{ + QString strName, + strContact; + + strName = findContactName( cnt ); + strContact = findContactContact( cnt ); + + AbTableItem *ati; + ati = new AbTableItem( this, QTableItem::Never, strName, strContact); + contactList.insert( ati, cnt ); + setItem( row, 0, ati ); + ati = new AbTableItem( this, QTableItem::Never, strContact, strName); + setItem( row, 1, ati ); + + //### cannot do this; table only has two columns at this point + // setItem( row, 2, new AbPickItem( this ) ); + + // resort at some point? +} + +void AbTable::internalAddEntries( QList<Contact> &list ) +{ + setUpdatesEnabled( FALSE ); + setNumRows( list.count() ); + int row = 0; + Contact *it; + for ( it = list.first(); it; it = list.next() ) + insertIntoTable( *it, row++ ); + resort(); + setUpdatesEnabled( TRUE ); +} + + +void AbTable::journalFreeReplace( const Contact &cnt, int row ) +{ + QString strName, + strContact; + AbTableItem *ati; + + strName = findContactName( cnt ); + strContact = findContactContact( cnt ); + ati = static_cast<AbTableItem*>(item(row, 0)); + contactList.remove( ati ); + ati->setItem( strName, strContact ); + contactList.insert( ati, cnt ); + + ati = static_cast<AbTableItem*>(item(row, 1)); + ati->setItem( strContact, strName ); +} + +void AbTable::journalFreeRemove( int row ) +{ + AbTableItem *ati; + ati = static_cast<AbTableItem*>(item(row, 0)); + if ( !ati ) + return; + contactList.remove( ati ); + realignTable( row ); +} + +#if QT_VERSION <= 230 +#ifndef SINGLE_APP +void QTable::paintEmptyArea( QPainter *p, int cx, int cy, int cw, int ch ) +{ + // Region of the rect we should draw + QRegion reg( QRect( cx, cy, cw, ch ) ); + // Subtract the table from it + reg = reg.subtract( QRect( QPoint( 0, 0 ), tableSize() ) ); + // And draw the rectangles (transformed as needed) + QArray<QRect> r = reg.rects(); + for (unsigned int i=0; i<r.count(); i++) + p->fillRect( r[i], colorGroup().brush( QColorGroup::Base ) ); +} +#endif +#endif + + +// int AbTable::rowHeight( int ) const +// { +// return 18; +// } + +// int AbTable::rowPos( int row ) const +// { +// return 18*row; +// } + +// int AbTable::rowAt( int pos ) const +// { +// return QMIN( pos/18, numRows()-1 ); +// } + +void AbTable::slotDoFind( const QString &findString, bool caseSensitive, + bool backwards, int category ) +{ + if ( currFindRow < -1 ) + currFindRow = currentRow() - 1; + clearSelection( TRUE ); + int rows, + row; + AbTableItem *ati; + QRegExp r( findString ); + r.setCaseSensitive( caseSensitive ); + rows = numRows(); + static bool wrapAround = true; + + if ( !backwards ) { + for ( row = currFindRow + 1; row < rows; row++ ) { + ati = static_cast<AbTableItem*>( item(row, 0) ); + if ( contactCompare( contactList[ati], r, category ) ) + break; + + } + } else { + for ( row = currFindRow - 1; row > -1; row-- ) { + ati = static_cast<AbTableItem*>( item(row, 0) ); + if ( contactCompare( contactList[ati], r, category ) ) + break; + } + } + if ( row >= rows || row < 0 ) { + if ( row < 0 ) + currFindRow = rows; + else + currFindRow = -1; + + if ( wrapAround ) + emit signalWrapAround(); + else + emit signalNotFound(); + + wrapAround = !wrapAround; + } else { + currFindRow = row; + QTableSelection foundSelection; + foundSelection.init( currFindRow, 0 ); + foundSelection.expandTo( currFindRow, numCols() - 1 ); + addSelection( foundSelection ); + setCurrentCell( currFindRow, numCols() - 1 ); + wrapAround = true; + } +} + +static bool contactCompare( const Contact &cnt, const QRegExp &r, int category ) +{ + bool returnMe; + QArray<int> cats; + cats = cnt.categories(); + + returnMe = false; + if ( (category == -1 && cats.count() == 0) || category == -2 ) + returnMe = cnt.match( r ); + else { + int i; + for ( i = 0; i < int(cats.count()); i++ ) { + if ( cats[i] == category ) { + returnMe = cnt.match( r ); + break; + } + } + } + return returnMe; +} + +void AbTable::fitColumns() +{ + int contentsWidth = visibleWidth(); + int n = numCols(); + int pw = n == 3 ? columnWidth(2) : 0; + setColumnWidth( 0, contentsWidth - contentsWidth / 2 ); + setColumnWidth( 1, contentsWidth / 2 - pw ); +} + +void AbTable::show() +{ + fitColumns(); + QTable::show(); +} + +void AbTable::setChoiceNames( const QStringList& list) +{ + choicenames = list; + if ( choicenames.isEmpty() ) { + // hide pick column + setNumCols( 2 ); + } else { + // show pick column + setNumCols( 3 ); + setColumnWidth( 2, fontMetrics().width(tr( "Pick" ))+8 ); + horizontalHeader()->setLabel( 2, tr( "Pick" )); + } + fitColumns(); +} + +void AbTable::itemClicked(int,int col) +{ + if ( col == 2 ) { + return; + } else { + emit details(); + } +} + +QStringList AbTable::choiceNames() const +{ + return choicenames; +} + +void AbTable::setChoiceSelection(int /*index*/, const QStringList& /*list*/) +{ + /* ###### + + QString selname = choicenames.at(index); + for (each row) { + Contact *c = contactForRow(row); + if ( list.contains(c->email) ) { + list.remove(c->email); + setText(row, 2, selname); + } + } + for (remaining list items) { + Contact *c = new contact(item); + setText(newrow, 2, selname); + } + + */ +} + +QStringList AbTable::choiceSelection(int /*index*/) const +{ + QStringList r; + /* ###### + + QString selname = choicenames.at(index); + for (each row) { + Contact *c = contactForRow(row); + if ( text(row,2) == selname ) { + r.append(c->email); + } + } + + */ + return r; +} + +void AbTable::setShowCategory( const QString &c ) +{ + showCat = c; + updateVisible(); +} + +QString AbTable::showCategory() const +{ + return showCat; +} + + +QStringList AbTable::categories() +{ + mCat.load( categoryFileName() ); + QStringList categoryList = mCat.labels( "Contacts" ); + return categoryList; +} + +void AbTable::updateVisible() +{ + int visible, + totalRows, + id, + totalCats, + it, + row; + bool hide; + AbTableItem *ati; + Contact *cnt; + visible = 0; + + setPaintingEnabled( FALSE ); + + totalRows = numRows(); + id = mCat.id( "Contacts", showCat ); + QArray<int> cats; + for ( row = 0; row < totalRows; row++ ) { + ati = static_cast<AbTableItem*>( item(row, 0) ); + cnt = &contactList[ati]; + cats = cnt->categories(); + hide = false; + if ( !showCat.isEmpty() ) { + if ( showCat == tr( "Unfiled" ) ) { + if ( cats.count() > 0 ) + hide = true; + } else { + // do some comparing + if ( !hide ) { + hide = true; + totalCats = int(cats.count()); + for ( it = 0; it < totalCats; it++ ) { + if ( cats[it] == id ) { + hide = false; + break; + } + } + } + } + } + if ( hide ) { + if ( currentRow() == row ) + setCurrentCell( -1, 0 ); + if ( rowHeight(row) > 0 ) + hideRow( row ); + } else { + if ( rowHeight(row) == 0 ) { + showRow( row ); + adjustRow( row ); + } + visible++; + } + } + if ( !visible ) + setCurrentCell( -1, 0 ); + + setPaintingEnabled( TRUE ); +} + + +void AbTable::setPaintingEnabled( bool e ) +{ + if ( e != enablePainting ) { + if ( !enablePainting ) { + enablePainting = true; + rowHeightChanged( 0 ); + viewport()->update(); + } else { + enablePainting = false; + } + } +} + +void AbTable::rowHeightChanged( int row ) +{ + if ( enablePainting ) + QTable::rowHeightChanged( row ); +} diff --git a/core/pim/addressbook/abtable.h b/core/pim/addressbook/abtable.h new file mode 100644 index 0000000..9b96997 --- a/dev/null +++ b/core/pim/addressbook/abtable.h @@ -0,0 +1,140 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 ABTABLE_H +#define ABTABLE_H + +#include <qpe/categories.h> +#include <qpe/contact.h> + +#include <qmap.h> +#include <qtable.h> +#include <qstringlist.h> +#include <qcombobox.h> + +class AbTableItem : public QTableItem +{ +public: + AbTableItem( QTable *t, EditType et, const QString &s, + const QString &secondSortKey); + QString entryKey() const; + void setEntryKey( const QString & k ); + virtual int alignment() const; + virtual QString key() const; + void setItem( const QString &txt, const QString &secondKey ); + +private: + QString sortKey; +}; + +class AbPickItem : public QTableItem +{ +public: + AbPickItem( QTable *t ); + + QWidget *createEditor() const; + void setContentFromEditor( QWidget *w ); + +private: + QGuardedPtr<QComboBox> cb; +}; + +class AbTable : public QTable +{ + Q_OBJECT + +public: + AbTable( const QValueList<int> *ordered, QWidget *parent, const char *name=0 ); + ~AbTable(); + // NEW + void addEntry( const Contact &newContact ); + Contact currentEntry(); + void replaceCurrentEntry( const Contact &newContact ); + + void init(); + + void deleteCurrentEntry(); + void clear(); + void clearFindRow() { currFindRow = -2; } + void loadFields(); + void refresh(); + bool save( const QString &fn ); + void load( const QString &fn ); + + // addresspicker mode + void setChoiceNames( const QStringList& list); + QStringList choiceNames() const; + void setChoiceSelection(int index, const QStringList& list); + QStringList choiceSelection(int index) const; + void setShowCategory( const QString &c ); + QString showCategory() const; + QStringList categories(); + + void show(); + void setPaintingEnabled( bool e ); + +public slots: + void slotDoFind( const QString &str, bool caseSensitive, bool backwards, + int category ); +signals: + void empty( bool ); + void details(); + void signalNotFound(); + void signalWrapAround(); + +protected: + virtual void keyPressEvent( QKeyEvent *e ); + +// int rowHeight( int ) const; +// int rowPos( int row ) const; +// virtual int rowAt( int pos ) const; + + +protected slots: + void moveTo( char ); + virtual void columnClicked( int col ); + void itemClicked(int,int col); + void rowHeightChanged( int row ); + +private: + void loadFile( const QString &strFile, bool journalFile ); + void fitColumns(); + void resort(); + void updateJournal( const Contact &contact, Contact::journal_action action, + int row = -1 ); + void insertIntoTable( const Contact &contact, int row ); + void internalAddEntries( QList<Contact> &list ); + QString findContactName( const Contact &entry ); + QString findContactContact( const Contact &entry ); + void journalFreeReplace( const Contact &cnt, int row ); + void journalFreeRemove( int row ); + void realignTable( int ); + void updateVisible(); + int lastSortCol; + bool asc; + QMap<AbTableItem*, Contact> contactList; + const QValueList<int> *intFields; + int currFindRow; + QString showCat; + QStringList choicenames; + bool enablePainting; + Categories mCat; +}; +#endif // ABTABLE_H diff --git a/core/pim/addressbook/addressbook.cpp b/core/pim/addressbook/addressbook.cpp new file mode 100644 index 0000000..b694e4f --- a/dev/null +++ b/core/pim/addressbook/addressbook.cpp @@ -0,0 +1,829 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 "abeditor.h" +#include "ablabel.h" +#include "abtable.h" +#include "addresssettings.h" +#include "addressbook.h" + +#include <qpe/qpeapplication.h> +#include <qpe/config.h> +#include <qpe/contact.h> +#include <qpe/finddialog.h> +#include <qpe/global.h> +#include <qpe/resource.h> +#include <qpe/ir.h> +#include <qpe/qpemessagebox.h> +#include <qpe/qcopenvelope_qws.h> + +#include <qaction.h> +#include <qdialog.h> +#include <qdir.h> +#include <qfile.h> +#include <qimage.h> +#include <qlayout.h> +#include <qpe/qpemenubar.h> +#include <qmessagebox.h> +#include <qpixmap.h> +#include <qpopupmenu.h> +#include <qpe/qpetoolbar.h> +#include <qstringlist.h> +#include <qtoolbutton.h> +#include <qwhatsthis.h> + +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> + +#include <qdatetime.h> + +static QString addressbookOldXMLFilename() +{ + QString filename = QPEApplication::documentDir() + "addressbook.xml"; + return filename; +} + +static QString addressbookXMLFilename() +{ + QString filename = Global::applicationFileName("addressbook", + "addressbook.xml"); + return filename; +} + +static QString addressbookPersonalVCardName() +{ + QString filename = Global::applicationFileName("addressbook", + "businesscard.vcf"); + return filename; +} + + +AddressbookWindow::AddressbookWindow( QWidget *parent, const char *name, + WFlags f ) + : QMainWindow( parent, name, f ), + abEditor(0), + bAbEditFirstTime(TRUE), + syncing(FALSE) +{ + initFields(); + + setCaption( tr("Contacts") ); + setIcon( Resource::loadPixmap( "AddressBook" ) ); + + setToolBarsMovable( FALSE ); + + // Create Toolbars + + QPEToolBar *bar = new QPEToolBar( this ); + bar->setHorizontalStretchable( TRUE ); + + QPEMenuBar *mbList = new QPEMenuBar( bar ); + mbList->setMargin( 0 ); + + QPopupMenu *edit = new QPopupMenu( this ); + mbList->insertItem( tr( "Contact" ), edit ); + + listTools = new QPEToolBar( this, "list operations" ); + + + QAction *a = new QAction( tr( "New" ), Resource::loadPixmap( "new" ), QString::null, + 0, this, 0 ); + actionNew = a; + connect( a, SIGNAL( activated() ), this, SLOT( slotListNew() ) ); + a->addTo( edit ); + a->addTo( listTools ); + + a = new QAction( tr( "Edit" ), Resource::loadPixmap( "edit" ), QString::null, + 0, this, 0 ); + actionEdit = a; + connect( a, SIGNAL( activated() ), this, SLOT( slotViewEdit() ) ); + a->addTo( edit ); + a->addTo( listTools ); + + a = new QAction( tr( "Delete" ), Resource::loadPixmap( "trash" ), QString::null, + 0, this, 0 ); + actionTrash = a; + connect( a, SIGNAL( activated() ), this, SLOT( slotListDelete() ) ); + a->addTo( edit ); + a->addTo( listTools ); + + a = new QAction( tr( "Find" ), Resource::loadPixmap( "mag" ), + QString::null, 0, this, 0 ); + actionFind = a; + connect( a, SIGNAL(activated()), this, SLOT(slotFind()) ); + a->addTo( edit ); + a->addTo( listTools ); + + + a = new QAction( tr( "Write Mail To" ), Resource::loadPixmap( "qtmail/reply" ), + QString::null, 0, this, 0 ); + a->setEnabled( FALSE ); + actionMail = a; + connect( a, SIGNAL( activated() ), this, SLOT( writeMail() ) ); + a->addTo( edit ); + a->addTo( listTools ); + + + + if ( Ir::supported() ) { + a = new QAction( tr ("Beam Entry" ), Resource::loadPixmap( "beam" ), QString::null, + 0, this, 0 ); + actionBeam = a; + connect( a, SIGNAL( activated() ), this, SLOT( slotBeam() ) ); + a->addTo( edit ); + a->addTo( listTools ); + } + + edit->insertSeparator(); + + a = new QAction( tr("My Personal Details"), QString::null, 0, 0, 0, TRUE ); + actionPersonal = a; + connect( a, SIGNAL( activated() ), this, SLOT( slotPersonalView() ) ); + a->addTo( edit ); + + + a = new QAction( tr( "Arrange Edit Fields"), QString::null, 0, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( slotSettings() ) ); + a->addTo( edit ); + + // Create Views + + // This is safe to call without checking to see if it exists... + // not to mention it also does the necessary stuff for the + // journaling... + QString str = addressbookXMLFilename(); + if ( str.isNull() ) { + QMessageBox::warning( this, tr("Out of Space"), + tr("There is not enough space to create\n" + "neccessary startup files.\n" + "\nFree up some space before\nentering data!") + ); + } + + abList = new AbTable( &orderedFields, this, "table" ); + abList->setHScrollBarMode( QScrollView::AlwaysOff ); + connect( abList, SIGNAL( empty( bool ) ), + this, SLOT( listIsEmpty( bool ) ) ); + connect( abList, SIGNAL( details() ), + this, SLOT( slotListView() ) ); + connect( abList, SIGNAL(currentChanged(int,int)), + this, SLOT(slotUpdateToolbar()) ); + + mView = 0; + + abList->load( addressbookXMLFilename() ); + if ( QFile::exists(addressbookOldXMLFilename()) ) { + abList->load( addressbookOldXMLFilename() ); + QFile::remove(addressbookOldXMLFilename()); + } + + catMenu = new QPopupMenu( this ); + catMenu->setCheckable( TRUE ); + connect( catMenu, SIGNAL(activated(int)), this, SLOT(slotSetCategory(int)) ); + populateCategories(); + + mbList->insertItem( tr("View"), catMenu ); + setCentralWidget( abList ); + + // qDebug("adressbook contrsuction: t=%d", t.elapsed() ); +} + +void AddressbookWindow::setDocument( const QString &filename ) +{ + if ( filename.find(".vcf") != int(filename.length()) - 4 ) return; + + QValueList<Contact> cl = Contact::readVCard( filename ); + for( QValueList<Contact>::Iterator it = cl.begin(); it != cl.end(); ++it ) { +// QString msg = tr("You received a vCard for\n%1.\nDo You want to add it to your\naddressbook?") +// .arg( (*it).fullName() ); +// if ( QMessageBox::information( this, tr("received contact"), msg, QMessageBox::Ok, QMessageBox::Cancel ) == +// QMessageBox::Ok ) { + abList->addEntry( *it ); +// } + } + +} + +void AddressbookWindow::resizeEvent( QResizeEvent *e ) +{ + QMainWindow::resizeEvent( e ); + + if ( centralWidget() == abList ) + showList(); + else if ( centralWidget() == mView ) + showView(); +} + +AddressbookWindow::~AddressbookWindow() +{ +} + +void AddressbookWindow::slotUpdateToolbar() +{ + Contact ce = abList->currentEntry(); + actionMail->setEnabled( !ce.defaultEmail().isEmpty() ); +} + +void AddressbookWindow::showList() +{ + if ( mView ) mView->hide(); + setCentralWidget( abList ); + abList->show(); + // update our focues... (or use a stack widget!); + abList->setFocus(); +} + +void AddressbookWindow::showView() +{ + if ( abList->numRows() > 0 ) { + abList->hide(); + setCentralWidget( abView() ); + mView->show(); + mView->setFocus(); + } +} + +void AddressbookWindow::slotListNew() +{ + Contact cnt; + if( !syncing ) { + if ( abEditor ) + abEditor->setEntry( cnt ); + abView()->init( cnt ); + editEntry( NewEntry ); + } else { + QMessageBox::warning(this, tr("Contacts"), + tr("Can not edit data, currently syncing")); + } +} + +void AddressbookWindow::slotListView() +{ + abView()->init( abList->currentEntry() ); + mView->sync(); + showView(); +} + +void AddressbookWindow::slotListDelete() +{ + if(!syncing) { + Contact tmpEntry = abList->currentEntry(); + + // get a name, do the best we can... + QString strName = tmpEntry.fullName(); + if ( strName.isEmpty() ) { + strName = tmpEntry.company(); + if ( strName.isEmpty() ) + strName = "No Name"; + } + + + if ( QPEMessageBox::confirmDelete( this, tr( "Contacts" ), + strName ) ) { + abList->deleteCurrentEntry(); + showList(); + } + } else { + QMessageBox::warning( this, tr("Contacts"), + tr("Can not edit data, currently syncing") ); + } +} + +void AddressbookWindow::slotViewBack() +{ + showList(); +} + +void AddressbookWindow::slotViewEdit() +{ + if(!syncing) { + if (actionPersonal->isOn()) { + editPersonal(); + } else { + if ( !bAbEditFirstTime ) + abEditor->setEntry( abList->currentEntry() ); + editEntry( EditEntry ); + } + } else { + QMessageBox::warning( this, tr("Contacts"), + tr("Can not edit data, currently syncing") ); + } +} + + + +void AddressbookWindow::writeMail() +{ + Contact c = abList->currentEntry(); + QString name = c.fileAs(); + QString email = c.defaultEmail(); + QCopEnvelope e("QPE/Application/qtmail", "writeMail(QString,QString)"); + e << name << email; +} + + + + +static const char * beamfile = "/tmp/obex/contact.vcf"; + +void AddressbookWindow::slotBeam() +{ + QString filename; + Contact c; + if ( actionPersonal->isOn() ) { + filename = addressbookPersonalVCardName(); + if (!QFile::exists(filename)) + return; // can't beam a non-existent file + c = Contact::readVCard( filename )[0]; + } else { + unlink( beamfile ); // delete if exists + c = abList->currentEntry(); + mkdir("/tmp/obex/", 0755); + Contact::writeVCard( beamfile, c ); + filename = beamfile; + } + Ir *ir = new Ir( this ); + connect( ir, SIGNAL( done( Ir * ) ), this, SLOT( beamDone( Ir * ) ) ); + QString description = c.fullName(); + ir->send( filename, description, "text/x-vCard" ); +} + +void AddressbookWindow::beamDone( Ir *ir ) +{ + delete ir; + unlink( beamfile ); +} + + +static void parseName( const QString& name, QString *first, QString *middle, + QString * last ) +{ + + int comma = name.find ( "," ); + QString rest; + if ( comma > 0 ) { + *last = name.left( comma ); + comma++; + while ( comma < int(name.length()) && name[comma] == ' ' ) + comma++; + rest = name.mid( comma ); + } else { + int space = name.findRev( ' ' ); + *last = name.mid( space+1 ); + rest = name.left( space ); + } + int space = rest.find( ' ' ); + if ( space <= 0 ) { + *first = rest; + } else { + *first = rest.left( space ); + *middle = rest.mid( space+1 ); + } + +} + + +void AddressbookWindow::appMessage(const QCString &msg, const QByteArray &data) +{ + if (msg == "editPersonal()") { + editPersonal(); + } else if (msg == "editPersonalAndClose()") { + editPersonal(); + close(); + } else if ( msg == "addContact(QString,QString)" ) { + QDataStream stream(data,IO_ReadOnly); + QString name, email; + stream >> name >> email; + + Contact cnt; + QString fn, mn, ln; + parseName( name, &fn, &mn, &ln ); + // qDebug( " %s - %s - %s", fn.latin1(), mn.latin1(), ln.latin1() ); + cnt.setFirstName( fn ); + cnt.setMiddleName( mn ); + cnt.setLastName( ln ); + cnt.setEmails( email ); + cnt.setDefaultEmail( email ); + cnt.setFileAs(); + + if ( bAbEditFirstTime ) { + abEditor = new AbEditor( cnt, &orderedFields, &slOrderedFields, + this, "editor" ); + bAbEditFirstTime = FALSE; + } else { + abEditor->setEntry( cnt ); + } + abView()->init( cnt ); + editEntry( NewEntry ); + + + + } +#if 0 + else if (msg == "pickAddresses(QCString,QCString,QStringList,...)" ) { + QDataStream stream(data,IO_ReadOnly); + QCString ch,m; + QStringList types; + stream >> ch >> m >> types; + AddressPicker picker(abList,this,0,TRUE); + picker.showMaximized(); + picker.setChoiceNames(types); + int i=0; + for (QStringList::ConstIterator it = types.begin(); it!=types.end(); ++it) { + QStringList sel; + stream >> sel; + picker.setSelection(i++,sel); + } + picker.showMaximized(); + picker.exec(); + + // ###### note: contacts may have been added - save here! + + setCentralWidget(abList); + QCopEnvelope e(ch,m); + i=0; + for (QStringList::ConstIterator it = types.begin(); it!=types.end(); ++it) { + QStringList sel = picker.selection(i++); + e << sel; + } + } +#endif + +} + +void AddressbookWindow::editPersonal() +{ + QString filename = addressbookPersonalVCardName(); + Contact me; + if (QFile::exists(filename)) + me = Contact::readVCard( filename )[0]; + if (bAbEditFirstTime) { + abEditor = new AbEditor( me, &orderedFields, &slOrderedFields, + this, "editor" ); + // don't create a new editor every time + bAbEditFirstTime = FALSE; + } else + abEditor->setEntry( me ); + + abEditor->setCaption(tr("Edit My Personal Details")); + abEditor->showMaximized(); + + // fix the foxus... + abEditor->setNameFocus(); + if ( abEditor->exec() ) { + setFocus(); + Contact new_personal = abEditor->entry(); + QString fname = addressbookPersonalVCardName(); + Contact::writeVCard( fname, new_personal ); + abView()->init(new_personal); + abView()->sync(); + } + abEditor->setCaption( tr("Edit Address") ); +} + +void AddressbookWindow::slotPersonalView() +{ + if (!actionPersonal->isOn()) { + // we just turned it off + setCaption( tr("Contacts") ); + actionNew->setEnabled(TRUE); + actionTrash->setEnabled(TRUE); + actionFind->setEnabled(TRUE); + slotUpdateToolbar(); // maybe some of the above could be moved there + showList(); + return; + } + + // XXX need to disable some QActions. + actionNew->setEnabled(FALSE); + actionTrash->setEnabled(FALSE); + actionFind->setEnabled(FALSE); + actionMail->setEnabled(FALSE); + + setCaption( tr("Contacts - My Personal Details") ); + QString filename = addressbookPersonalVCardName(); + Contact me; + if (QFile::exists(filename)) + me = Contact::readVCard( filename )[0]; + + abView()->init( me ); + abView()->sync(); + abList->hide(); + setCentralWidget( abView() ); + mView->show(); + mView->setFocus(); +} + +void AddressbookWindow::editEntry( EntryMode entryMode ) +{ + Contact entry; + if ( bAbEditFirstTime ) { + abEditor = new AbEditor( entry, &orderedFields, &slOrderedFields, + this, "editor" ); + bAbEditFirstTime = FALSE; + if ( entryMode == EditEntry ) + abEditor->setEntry( abList->currentEntry() ); + } + // other things may chane the caption. + abEditor->setCaption( tr("Edit Address") ); + +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + abEditor->showMaximized(); +#endif + // fix the foxus... + abEditor->setNameFocus(); + if ( abEditor->exec() ) { + setFocus(); + if ( entryMode == NewEntry ) { + Contact insertEntry = abEditor->entry(); + insertEntry.assignUid(); + abList->addEntry( insertEntry ); + } else { + Contact replaceEntry = abEditor->entry(); + if ( !replaceEntry.isValidUid() ) + replaceEntry.assignUid(); + abList->replaceCurrentEntry( replaceEntry ); + } + } + populateCategories(); + showList(); +} + +void AddressbookWindow::listIsEmpty( bool empty ) +{ + if ( !empty ) { + deleteButton->setEnabled( TRUE ); + } +} + +void AddressbookWindow::reload() +{ + syncing = FALSE; + abList->clear(); + abList->load( addressbookXMLFilename() ); +} + +void AddressbookWindow::flush() +{ + syncing = TRUE; + abList->save( addressbookXMLFilename() ); +} + + +void AddressbookWindow::closeEvent( QCloseEvent *e ) +{ + if ( centralWidget() == mView ) { + if (actionPersonal->isOn()) { + // pretend we clicked it off + actionPersonal->setOn(FALSE); + slotPersonalView(); + } else { + showList(); + } + e->ignore(); + return; + } + + if(syncing) { + /* shouldn't we save, I hear you say? well its already been set + so that an edit can not occur during a sync, and we flushed + at the start of the sync, so there is no need to save + Saving however itself would cause problems. */ + e->accept(); + return; + } +//################## shouldn't always save + if ( save() ) + e->accept(); + else + e->ignore(); +} + +/* + Returns TRUE if it is OK to exit + */ + +bool AddressbookWindow::save() +{ + QString str = addressbookXMLFilename(); + if ( str.isNull() ) { + if ( QMessageBox::critical( 0, tr("Out of space"), + tr("Unable to save information.\n" + "Free up some space\n" + "and try again.\n" + "\nQuit anyway?"), + QMessageBox::Yes|QMessageBox::Escape, + QMessageBox::No|QMessageBox::Default ) + != QMessageBox::No ) + return TRUE; + else + return FALSE; + } else { + if ( !abList->save( str ) ) { + if ( QMessageBox::critical( 0, tr( "Out of space" ), + tr("Unable to save information.\n" + "Free up some space\n" + "and try again.\n" + "\nQuit anyway?"), + QMessageBox::Yes|QMessageBox::Escape, + QMessageBox::No|QMessageBox::Default ) + != QMessageBox::No ) + return TRUE; + else + return FALSE; + } + } + return TRUE; +} + +void AddressbookWindow::slotSettings() +{ + AddressSettings frmSettings( this ); +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + frmSettings.showMaximized(); +#endif + + if ( frmSettings.exec() ) { + allFields.clear(); + orderedFields.clear(); + slOrderedFields.clear(); + initFields(); + if ( abEditor ) + abEditor->loadFields(); + abList->refresh(); + } +} + + +void AddressbookWindow::initFields() +{ + // we really don't need the things from the configuration, anymore + // only thing that is important are the important categories. So, + // Call the contact functions that correspond to these old functions... + + QStringList xmlFields = Contact::fields(); + QStringList visibleFields = Contact::trfields(); + xmlFields.remove( "Title" ); + visibleFields.remove( tr("Name Title") ); + visibleFields.remove( tr("Notes") ); + + int i, + version; + Config cfg( "AddressBook" ); + QString zn; + + // ### Write a function to keep this from happening again... + QStringList::ConstIterator it; + for ( i = 0, it = xmlFields.begin(); it != xmlFields.end(); ++it, i++ ) { + allFields.append( i + 3 ); + } + + cfg.setGroup( "Version" ); + version = cfg.readNumEntry( "version" ); + i = 0; + if ( version >= ADDRESSVERSION ) { + + cfg.setGroup( "ImportantCategory" ); + + zn = cfg.readEntry( "Category" + QString::number(i), QString::null ); + while ( !zn.isNull() ) { + if ( zn.contains( tr("Work") ) || zn.contains( tr("Mb") ) ) { + slOrderedFields.clear(); + break; + } + slOrderedFields.append( zn ); + zn = cfg.readEntry( "Category" + QString::number(++i), QString::null ); + } + } else { + QString str; + str = getenv("HOME"); + str += "/Settings/AddressBook.conf"; + QFile::remove( str ); + } + if ( slOrderedFields.count() > 0 ) { + for( QStringList::ConstIterator it = slOrderedFields.begin(); + it != slOrderedFields.end(); ++it ) { + QValueList<int>::ConstIterator itVl; + QStringList::ConstIterator itVis; + itVl = allFields.begin(); + for ( itVis = visibleFields.begin(); + itVis != visibleFields.end() && itVl != allFields.end(); + ++itVis, ++itVl ) { + if ( *it == *itVis && itVl != allFields.end() ) { + orderedFields.append( *itVl ); + } + } + } + } else { + QValueList<int>::ConstIterator it; + for ( it = allFields.begin(); it != allFields.end(); ++it ) + orderedFields.append( *it ); + + slOrderedFields = visibleFields; + orderedFields.remove( Qtopia::AddressUid ); + orderedFields.remove( Qtopia::Title ); + orderedFields.remove( Qtopia::Groups ); + orderedFields.remove( Qtopia::AddressCategory ); + orderedFields.remove( Qtopia::FirstName ); + orderedFields.remove( Qtopia::LastName ); + orderedFields.remove( Qtopia::DefaultEmail ); + orderedFields.remove( Qtopia::FileAs ); + orderedFields.remove( Qtopia::Notes ); + orderedFields.remove( Qtopia::Gender ); + slOrderedFields.remove( tr("Name Title") ); + slOrderedFields.remove( tr("First Name") ); + slOrderedFields.remove( tr("Last Name") ); + slOrderedFields.remove( tr("File As") ); + slOrderedFields.remove( tr("Default Email") ); + slOrderedFields.remove( tr("Notes") ); + slOrderedFields.remove( tr("Gender") ); + + } +} + + +AbLabel *AddressbookWindow::abView() +{ + if ( !mView ) { + mView = new AbLabel( this, "viewer" ); + mView->init( Contact() ); + connect( mView, SIGNAL( okPressed() ), this, SLOT( slotListView() ) ); + } + return mView; +} + +void AddressbookWindow::slotFind() +{ + if ( centralWidget() == abView() ) + showList(); + FindDialog frmFind( "Contacts", this ); + QObject::connect( &frmFind, SIGNAL(signalFindClicked(const QString &, bool, bool, int)), abList, SLOT(slotDoFind( const QString&,bool,bool,int))); + QObject::connect( abList, SIGNAL(signalNotFound()), &frmFind, SLOT(slotNotFound()) ); + QObject::connect( abList, SIGNAL(signalWrapAround()), &frmFind, SLOT(slotWrapAround()) ); + frmFind.exec(); + if ( abList->numSelections() ) + abList->clearSelection(); + abList->clearFindRow(); +} + +void AddressbookWindow::slotSetCategory( int c ) +{ + if ( c <= 0 ) + return; + for ( unsigned int i = 1; i < catMenu->count(); i++ ) + catMenu->setItemChecked( i, c == (int)i ); + if ( c == 1 ) { + abList->setShowCategory( QString::null ); + setCaption( tr("Contacts") + " - " + tr ( "All" ) ); + } else if ( c == (int)catMenu->count() ) { + abList->setShowCategory( tr( "Unfiled" ) ); + setCaption( tr("Contacts") + " - " + tr( "Unfiled" ) ); + } else { + QString cat = abList->categories()[c - 2]; + abList->setShowCategory( cat ); + setCaption( tr("Contacts") + " - " + cat ); + } +} + +void AddressbookWindow::populateCategories() +{ + catMenu->clear(); + + int id, + rememberId; + id = 1; + catMenu->insertItem( tr( "All" ), id++ ); + QStringList categories = abList->categories(); + categories.append( tr( "Unfiled" ) ); + for ( QStringList::Iterator it = categories.begin(); + it != categories.end(); ++it ) { + catMenu->insertItem( *it, id ); + if ( *it == abList->showCategory() ) + rememberId = id; + ++id; + } + if ( abList->showCategory().isEmpty() ) + slotSetCategory( 1 ); + else + slotSetCategory( rememberId ); +} diff --git a/core/pim/addressbook/addressbook.cw b/core/pim/addressbook/addressbook.cw new file mode 100644 index 0000000..452df36 --- a/dev/null +++ b/core/pim/addressbook/addressbook.cw @@ -0,0 +1,26 @@ +<!DOCTYPE CW><CW> +<customwidgets> + <customwidget> + <class>AbLineEdit</class> + <header location="local">ablineedit.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <pixmap> + <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data> + </pixmap> + </customwidget> + <customwidget> + <class>AbMultiLineEdit</class> + <header location="local">abmultilineedit.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <pixmap> + <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data> + </pixmap> + </customwidget> +</customwidgets> +</CW> diff --git a/core/pim/addressbook/addressbook.h b/core/pim/addressbook/addressbook.h new file mode 100644 index 0000000..9694465 --- a/dev/null +++ b/core/pim/addressbook/addressbook.h @@ -0,0 +1,99 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 Addressbook_H +#define Addressbook_H + +#include <qmainwindow.h> + +class AbEditor; +class AbLabel; +class AbTable; +class QPEToolBar; +class QPopupMenu; +class QToolButton; +class QDialog; +class Ir; +class QAction; + +class AddressbookWindow: public QMainWindow +{ + Q_OBJECT +public: + AddressbookWindow( QWidget *parent = 0, const char *name = 0, WFlags f = 0 ); + ~AddressbookWindow(); + +protected: + void resizeEvent( QResizeEvent * e ); + void showList(); + void showView(); + enum EntryMode { NewEntry=0, EditEntry }; + void editPersonal(); + void editEntry( EntryMode ); + void closeEvent( QCloseEvent *e ); + bool save(); + +public slots: + void flush(); + void reload(); + void appMessage(const QCString &, const QByteArray &); + void setDocument( const QString & ); + +private slots: + void slotListNew(); + void slotListView(); + void slotListDelete(); + void slotViewBack(); + void slotViewEdit(); + void slotPersonalView(); + void listIsEmpty( bool ); + void slotSettings(); + void writeMail(); + void slotBeam(); + void beamDone( Ir * ); + void slotFind(); + void slotSetCategory( int ); + void slotUpdateToolbar(); + +private: + void initFields(); // inititialize our fields... + AbLabel *abView(); + void populateCategories(); + + QPopupMenu *catMenu; + QPEToolBar *listTools; + QToolButton *deleteButton; + QValueList<int> allFields, + orderedFields; + QStringList slOrderedFields; + enum Panes { paneList=0, paneView, paneEdit }; + AbEditor *abEditor; + AbLabel *mView; + AbTable *abList; + + QAction *actionNew, *actionEdit, *actionTrash, *actionFind, *actionBeam, + *actionPersonal, *actionMail; + + bool bAbEditFirstTime; + int viewMargin; + + bool syncing; +}; + +#endif diff --git a/core/pim/addressbook/addressbook.pro b/core/pim/addressbook/addressbook.pro new file mode 100644 index 0000000..8d3401d --- a/dev/null +++ b/core/pim/addressbook/addressbook.pro @@ -0,0 +1,22 @@ +TEMPLATE = app +CONFIG = qt warn_on release +DESTDIR = $(QPEDIR)/bin +HEADERS = addressbook.h \ + abeditor.h \ + ablabel.h \ + abtable.h \ + addresssettings.h +SOURCES = main.cpp \ + addressbook.cpp \ + abeditor.cpp \ + ablabel.cpp \ + abtable.cpp \ + addresssettings.cpp +INTERFACES = addresssettingsbase.ui + +TARGET = addressbook +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe + +TRANSLATIONS = ../i18n/de/addressbook.ts diff --git a/core/pim/addressbook/addresspicker.cpp b/core/pim/addressbook/addresspicker.cpp new file mode 100644 index 0000000..79c4d43 --- a/dev/null +++ b/core/pim/addressbook/addresspicker.cpp @@ -0,0 +1,52 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 "addresspicker.h" +#include "abtable.h" + +#include <qlayout.h> + +/*! + \a tab is reparented for use in the picker. Take it back out if you want + to regain ownership. +*/ +AddressPicker::AddressPicker(AbTable* tab, QWidget* parent, const char* name, bool modal) : + QDialog(parent,name,modal) +{ + QVBoxLayout* vb = new QVBoxLayout(this); + tab->reparent(this,QPoint(0,0)); + table = tab; + vb->addWidget(table); +} + +void AddressPicker::setChoiceNames(const QStringList& list) +{ + table->setChoiceNames(list); +} + +void AddressPicker::setSelection(int index, const QStringList& list) +{ + table->setChoiceSelection(index,list); +} + +QStringList AddressPicker::selection(int index) const +{ + return table->choiceSelection(index); +} diff --git a/core/pim/addressbook/addresspicker.h b/core/pim/addressbook/addresspicker.h new file mode 100644 index 0000000..8a57479 --- a/dev/null +++ b/core/pim/addressbook/addresspicker.h @@ -0,0 +1,39 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 AddressPicker_H +#define AddressPicker_H + +#include <qdialog.h> + +class AbTable; + +class AddressPicker : public QDialog { +public: + AddressPicker(AbTable* table, QWidget* parent, const char* name=0, bool modal=FALSE); + + void setChoiceNames(const QStringList&); + void setSelection(int index, const QStringList&); + QStringList selection(int index) const; + +private: + AbTable* table; +}; + +#endif diff --git a/core/pim/addressbook/addresssettings.cpp b/core/pim/addressbook/addresssettings.cpp new file mode 100644 index 0000000..e7c2210 --- a/dev/null +++ b/core/pim/addressbook/addresssettings.cpp @@ -0,0 +1,136 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 "addresssettings.h" + +#include <qpe/config.h> +#include <qpe/contact.h> + +#include <qfile.h> +#include <qlistbox.h> + +#include <stdlib.h> + +AddressSettings::AddressSettings( QWidget *parent, const char *name ) + : AddressSettingsBase( parent, name, TRUE ) +{ + init(); +} + +AddressSettings::~AddressSettings() +{ +} + +void AddressSettings::init() +{ + QStringList slFields = Contact::trfields(); + // Make this match what is in initFields + slFields.remove( tr("Name Title") ); + slFields.remove( tr("First Name") ); + slFields.remove( tr("Last Name") ); + slFields.remove( tr("File As") ); + slFields.remove( tr("Default Email") ); + slFields.remove( tr("Notes") ); + slFields.remove( tr("Gender") ); + + + for( QStringList::Iterator it = slFields.begin(); + it != slFields.end(); ++it ) { + fieldListBox->insertItem( *it ); + } + + Config cfg( "AddressBook" ); + + cfg.setGroup( "Version" ); + int version; + version = cfg.readNumEntry( "version" ); + if ( version >= ADDRESSVERSION ) { + int i = 0; + int p = 0; + cfg.setGroup( "ImportantCategory" ); + QString zn = cfg.readEntry( "Category" + QString::number(i), + QString::null ); + while ( !zn.isNull() ) { + for ( int m = i; m < (int)fieldListBox->count(); m++ ) { + if ( fieldListBox->text( m ) == zn ) { + if ( m != p ) { + fieldListBox->removeItem( m ); + fieldListBox->insertItem( zn, p ); + } + p++; + break; + } + } + zn = cfg.readEntry( "Category" + QString::number(++i), + QString::null ); + } + + fieldListBox->setCurrentItem( 0 ); + } else { + QString str; + str = getenv("HOME"); + + str += "/Settings/AddressBook.conf"; + QFile::remove( str ); + } +} + +void AddressSettings::itemUp() +{ + int i = fieldListBox->currentItem(); + if ( i > 0 ) { + QString item = fieldListBox->currentText(); + fieldListBox->removeItem( i ); + fieldListBox->insertItem( item, i-1 ); + fieldListBox->setCurrentItem( i-1 ); + } +} + +void AddressSettings::itemDown() +{ + int i = fieldListBox->currentItem(); + if ( i < (int)fieldListBox->count() - 1 ) { + QString item = fieldListBox->currentText(); + fieldListBox->removeItem( i ); + fieldListBox->insertItem( item, i+1 ); + fieldListBox->setCurrentItem( i+1 ); + } +} + +void AddressSettings::accept() +{ + save(); + QDialog::accept(); +} + + +void AddressSettings::save() +{ + Config cfg( "AddressBook" ); + cfg.setGroup( "Version" ); + // *** To change the version change it here... + cfg.writeEntry( "version", QString::number(ADDRESSVERSION) ); + cfg.setGroup( "ImportantCategory" ); + + for ( int i = 0; i < (int)fieldListBox->count(); i++ ) { + cfg.writeEntry( "Category"+QString::number(i), fieldListBox->text(i) ); + } +} diff --git a/core/pim/addressbook/addresssettings.h b/core/pim/addressbook/addresssettings.h new file mode 100644 index 0000000..0fdfa77 --- a/dev/null +++ b/core/pim/addressbook/addresssettings.h @@ -0,0 +1,47 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 _ADDRESSSETTINGS_H_ +#define _ADDRESSSETTINGS_H_ + +#include <qlist.h> +#include <qstringlist.h> +#include "addresssettingsbase.h" + +const int ADDRESSVERSION = 3; + +class AddressSettings : public AddressSettingsBase +{ + Q_OBJECT +public: + AddressSettings( QWidget *parent = 0, const char *name = 0 ); + ~AddressSettings(); + +protected: + void accept(); + virtual void itemUp(); + virtual void itemDown(); + +private: + void init(); + void save(); +}; + +#endif // _ADDRESSSETTINGS_H_ diff --git a/core/pim/addressbook/addresssettingsbase.ui b/core/pim/addressbook/addresssettingsbase.ui new file mode 100644 index 0000000..bd3b85b --- a/dev/null +++ b/core/pim/addressbook/addresssettingsbase.ui @@ -0,0 +1,170 @@ +<!DOCTYPE UI><UI> +<class>AddressSettingsBase</class> +<comment>/********************************************************************** +** Copyright (C) 2001 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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>AddressSettingsBase</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>244</width> + <height>207</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>Arrange Edit Fields</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <grid> + <property stdset="1"> + <name>margin</name> + <number>6</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget row="1" column="0" rowspan="3" colspan="1" > + <class>QListBox</class> + <property stdset="1"> + <name>name</name> + <cstring>fieldListBox</cstring> + </property> + </widget> + <widget row="0" column="0" rowspan="1" colspan="2" > + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>lblExplain</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>MShape</enum> + </property> + <property stdset="1"> + <name>frameShadow</name> + <enum>MShadow</enum> + </property> + <property stdset="1"> + <name>text</name> + <string>Select the field order:</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 row="1" column="1" > + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>upButton</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Up</string> + </property> + <property stdset="1"> + <name>autoRepeat</name> + <bool>true</bool> + </property> + </widget> + <widget row="2" column="1" > + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>downButton</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Down</string> + </property> + <property stdset="1"> + <name>autoRepeat</name> + <bool>true</bool> + </property> + </widget> + <spacer row="3" column="1" > + <property> + <name>name</name> + <cstring>Spacer2</cstring> + </property> + <property stdset="1"> + <name>orientation</name> + <enum>Vertical</enum> + </property> + <property stdset="1"> + <name>sizeType</name> + <enum>Expanding</enum> + </property> + <property> + <name>sizeHint</name> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> +</widget> +<connections> + <connection> + <sender>upButton</sender> + <signal>clicked()</signal> + <receiver>AddressSettingsBase</receiver> + <slot>itemUp()</slot> + </connection> + <connection> + <sender>downButton</sender> + <signal>clicked()</signal> + <receiver>AddressSettingsBase</receiver> + <slot>itemDown()</slot> + </connection> + <slot access="protected">itemUp()</slot> + <slot access="protected">itemDown()</slot> +</connections> +</UI> diff --git a/core/pim/addressbook/main.cpp b/core/pim/addressbook/main.cpp new file mode 100644 index 0000000..2ea1819 --- a/dev/null +++ b/core/pim/addressbook/main.cpp @@ -0,0 +1,41 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qt Palmtop 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 "addressbook.h" + +#include <qpe/qpeapplication.h> +#include <qpe/qcopenvelope_qws.h> +#include <qstring.h> + +int main( int argc, char ** argv ) +{ + QPEApplication a( argc, argv ); + + AddressbookWindow mw; + QObject::connect( &a, SIGNAL( flush() ), &mw, SLOT( flush() ) ); + QObject::connect( &a, SIGNAL( reload() ), &mw, SLOT( reload() ) ); + QObject::connect( &a, SIGNAL( appMessage(const QCString &, const QByteArray &) ), + &mw, SLOT( appMessage(const QCString &, const QByteArray &) ) ); + + mw.setCaption( AddressbookWindow::tr("Contacts") ); + a.showMainDocumentWidget(&mw); + + return a.exec(); +} diff --git a/core/pim/addressbook/qpe-addressbook.control b/core/pim/addressbook/qpe-addressbook.control new file mode 100644 index 0000000..cca98f3 --- a/dev/null +++ b/core/pim/addressbook/qpe-addressbook.control @@ -0,0 +1,9 @@ +Files: bin/addressbook apps/Applications/addressbook.desktop +Priority: optional +Section: qpe/applications +Maintainer: Warwick Allison <warwick@trolltech.com> +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Contacts + A simple addressbook for the Qtopia environment. diff --git a/core/pim/datebook/.cvsignore b/core/pim/datebook/.cvsignore new file mode 100644 index 0000000..4ba477d --- a/dev/null +++ b/core/pim/datebook/.cvsignore @@ -0,0 +1,12 @@ +moc_* +Makefile +dateentry.h +datebookdayheader.h +dateentry.cpp +datebookdayheader.cpp +datebookweekheader.cpp +datebookweekheader.h +datebooksettingsbase.h +datebooksettingsbase.cpp +repeatentrybase.cpp +repeatentrybase.h diff --git a/core/pim/datebook/Makefile.in b/core/pim/datebook/Makefile.in new file mode 100644 index 0000000..bdc69dc --- a/dev/null +++ b/core/pim/datebook/Makefile.in @@ -0,0 +1,385 @@ +############################################################################# + +####### Compiler, tools and options + +CXX = $(SYSCONF_CXX) $(QT_CXX_MT) +CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) +CC = $(SYSCONF_CC) $(QT_C_MT) +CFLAGS = $(SYSCONF_CFLAGS) +INCPATH = -I$(QPEDIR)/include +LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT) +LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS) $(SYSCONF_LIBS_QTAPP) +MOC = $(SYSCONF_MOC) +UIC = $(SYSCONF_UIC) + +####### Target + +DESTDIR = $(QPEDIR)/bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = datebook +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = datebookday.h \ + datebook.h \ + dateentryimpl.h \ + datebookdayheaderimpl.h \ + datebooksettings.h \ + datebookweek.h \ + datebookweekheaderimpl.h \ + repeatentry.h +SOURCES = main.cpp \ + datebookday.cpp \ + datebook.cpp \ + dateentryimpl.cpp \ + datebookdayheaderimpl.cpp \ + datebooksettings.cpp \ + datebookweek.cpp \ + datebookweekheaderimpl.cpp \ + repeatentry.cpp +OBJECTS = main.o \ + datebookday.o \ + datebook.o \ + dateentryimpl.o \ + datebookdayheaderimpl.o \ + datebooksettings.o \ + datebookweek.o \ + datebookweekheaderimpl.o \ + repeatentry.o \ + dateentry.o \ + datebookdayheader.o \ + datebooksettingsbase.o \ + datebookweekheader.o \ + repeatentrybase.o +INTERFACES = dateentry.ui \ + datebookdayheader.ui \ + datebooksettingsbase.ui \ + datebookweekheader.ui \ + repeatentrybase.ui +UICDECLS = dateentry.h \ + datebookdayheader.h \ + datebooksettingsbase.h \ + datebookweekheader.h \ + repeatentrybase.h +UICIMPLS = dateentry.cpp \ + datebookdayheader.cpp \ + datebooksettingsbase.cpp \ + datebookweekheader.cpp \ + repeatentrybase.cpp +SRCMOC = moc_datebookday.cpp \ + moc_datebook.cpp \ + moc_dateentryimpl.cpp \ + moc_datebookdayheaderimpl.cpp \ + moc_datebookweek.cpp \ + moc_datebookweekheaderimpl.cpp \ + moc_repeatentry.cpp \ + moc_dateentry.cpp \ + moc_datebookdayheader.cpp \ + moc_datebooksettingsbase.cpp \ + moc_datebookweekheader.cpp \ + moc_repeatentrybase.cpp +OBJMOC = moc_datebookday.o \ + moc_datebook.o \ + moc_dateentryimpl.o \ + moc_datebookdayheaderimpl.o \ + moc_datebookweek.o \ + moc_datebookweekheaderimpl.o \ + moc_repeatentry.o \ + moc_dateentry.o \ + moc_datebookdayheader.o \ + moc_datebooksettingsbase.o \ + moc_datebookweekheader.o \ + moc_repeatentrybase.o + + +####### Implicit rules + +.SUFFIXES: .cpp .cxx .cc .C .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.C.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + + +all: $(DESTDIR)$(TARGET) + +$(DESTDIR)$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS) + $(SYSCONF_LINK) $(LFLAGS) -o $(DESTDIR)$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) + +moc: $(SRCMOC) + +tmake: + tmake datebook.pro + +clean: + -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) + -rm -f *~ core + -rm -f allmoc.cpp + +####### Extension Modules + +listpromodules: + @echo + +listallmodules: + @echo + +listaddonpromodules: + @echo + +listaddonentmodules: + @echo + + +REQUIRES= + +####### Sub-libraries + + +###### Combined headers + + + +####### Compile + +main.o: main.cpp \ + datebook.h \ + $(QPEDIR)/include/qpe/datebookdb.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +datebookday.o: datebookday.cpp \ + datebookday.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + datebookdayheaderimpl.h \ + datebookdayheader.h \ + $(QPEDIR)/include/qpe/datebookdb.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/timestring.h \ + $(QPEDIR)/include/qpe/qpedebug.h + +datebook.o: datebook.cpp \ + datebook.h \ + $(QPEDIR)/include/qpe/datebookdb.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + datebookday.h \ + datebooksettings.h \ + datebooksettingsbase.h \ + datebookweek.h \ + dateentryimpl.h \ + dateentry.h \ + $(QPEDIR)/include/qpe/datebookmonth.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/qpedebug.h \ + $(QPEDIR)/include/qpe/finddialog.h \ + $(QPEDIR)/include/qpe/ir.h \ + $(QPEDIR)/include/qpe/qpemenubar.h \ + $(QPEDIR)/include/qpe/qpemessagebox.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/sound.h \ + $(QPEDIR)/include/qpe/timestring.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h \ + $(QPEDIR)/include/qpe/tzselect.h \ + $(QPEDIR)/include/qpe/xmlreader.h + +dateentryimpl.o: dateentryimpl.cpp \ + dateentryimpl.h \ + dateentry.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + repeatentry.h \ + repeatentrybase.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/categoryselect.h \ + $(QPEDIR)/include/qpe/datebookmonth.h \ + $(QPEDIR)/include/qpe/global.h \ + $(QPEDIR)/include/qpe/timeconversion.h \ + $(QPEDIR)/include/qpe/timestring.h \ + $(QPEDIR)/include/qpe/tzselect.h + +datebookdayheaderimpl.o: datebookdayheaderimpl.cpp \ + datebookdayheaderimpl.h \ + datebookdayheader.h \ + $(QPEDIR)/include/qpe/datebookmonth.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/timestring.h + +datebooksettings.o: datebooksettings.cpp \ + datebooksettings.h \ + datebooksettingsbase.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +datebookweek.o: datebookweek.cpp \ + datebookweek.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + datebookweekheaderimpl.h \ + datebookweekheader.h \ + $(QPEDIR)/include/qpe/calendar.h \ + $(QPEDIR)/include/qpe/datebookdb.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/timestring.h + +datebookweekheaderimpl.o: datebookweekheaderimpl.cpp \ + datebookweekheaderimpl.h \ + datebookweekheader.h + +repeatentry.o: repeatentry.cpp \ + repeatentry.h \ + repeatentrybase.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/datebookmonth.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/timestring.h + +dateentry.h: dateentry.ui + $(UIC) dateentry.ui -o $(INTERFACE_DECL_PATH)/dateentry.h + +dateentry.cpp: dateentry.ui + $(UIC) dateentry.ui -i dateentry.h -o dateentry.cpp + +datebookdayheader.h: datebookdayheader.ui + $(UIC) datebookdayheader.ui -o $(INTERFACE_DECL_PATH)/datebookdayheader.h + +datebookdayheader.cpp: datebookdayheader.ui + $(UIC) datebookdayheader.ui -i datebookdayheader.h -o datebookdayheader.cpp + +datebooksettingsbase.h: datebooksettingsbase.ui + $(UIC) datebooksettingsbase.ui -o $(INTERFACE_DECL_PATH)/datebooksettingsbase.h + +datebooksettingsbase.cpp: datebooksettingsbase.ui + $(UIC) datebooksettingsbase.ui -i datebooksettingsbase.h -o datebooksettingsbase.cpp + +datebookweekheader.h: datebookweekheader.ui + $(UIC) datebookweekheader.ui -o $(INTERFACE_DECL_PATH)/datebookweekheader.h + +datebookweekheader.cpp: datebookweekheader.ui + $(UIC) datebookweekheader.ui -i datebookweekheader.h -o datebookweekheader.cpp + +repeatentrybase.h: repeatentrybase.ui + $(UIC) repeatentrybase.ui -o $(INTERFACE_DECL_PATH)/repeatentrybase.h + +repeatentrybase.cpp: repeatentrybase.ui + $(UIC) repeatentrybase.ui -i repeatentrybase.h -o repeatentrybase.cpp + +dateentry.o: dateentry.cpp + +datebookdayheader.o: datebookdayheader.cpp + +datebooksettingsbase.o: datebooksettingsbase.cpp + +datebookweekheader.o: datebookweekheader.cpp + +repeatentrybase.o: repeatentrybase.cpp + +moc_datebookday.o: moc_datebookday.cpp \ + datebookday.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h + +moc_datebook.o: moc_datebook.cpp \ + datebook.h \ + $(QPEDIR)/include/qpe/datebookdb.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h + +moc_dateentryimpl.o: moc_dateentryimpl.cpp \ + dateentryimpl.h \ + dateentry.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h + +moc_datebookdayheaderimpl.o: moc_datebookdayheaderimpl.cpp \ + datebookdayheaderimpl.h \ + datebookdayheader.h + +moc_datebookweek.o: moc_datebookweek.cpp \ + datebookweek.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h + +moc_datebookweekheaderimpl.o: moc_datebookweekheaderimpl.cpp \ + datebookweekheaderimpl.h \ + datebookweekheader.h + +moc_repeatentry.o: moc_repeatentry.cpp \ + repeatentry.h \ + repeatentrybase.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h + +moc_dateentry.o: moc_dateentry.cpp \ + dateentry.h + +moc_datebookdayheader.o: moc_datebookdayheader.cpp \ + datebookdayheader.h + +moc_datebooksettingsbase.o: moc_datebooksettingsbase.cpp \ + datebooksettingsbase.h + +moc_datebookweekheader.o: moc_datebookweekheader.cpp \ + datebookweekheader.h + +moc_repeatentrybase.o: moc_repeatentrybase.cpp \ + repeatentrybase.h + +moc_datebookday.cpp: datebookday.h + $(MOC) datebookday.h -o moc_datebookday.cpp + +moc_datebook.cpp: datebook.h + $(MOC) datebook.h -o moc_datebook.cpp + +moc_dateentryimpl.cpp: dateentryimpl.h + $(MOC) dateentryimpl.h -o moc_dateentryimpl.cpp + +moc_datebookdayheaderimpl.cpp: datebookdayheaderimpl.h + $(MOC) datebookdayheaderimpl.h -o moc_datebookdayheaderimpl.cpp + +moc_datebookweek.cpp: datebookweek.h + $(MOC) datebookweek.h -o moc_datebookweek.cpp + +moc_datebookweekheaderimpl.cpp: datebookweekheaderimpl.h + $(MOC) datebookweekheaderimpl.h -o moc_datebookweekheaderimpl.cpp + +moc_repeatentry.cpp: repeatentry.h + $(MOC) repeatentry.h -o moc_repeatentry.cpp + +moc_dateentry.cpp: dateentry.h + $(MOC) dateentry.h -o moc_dateentry.cpp + +moc_datebookdayheader.cpp: datebookdayheader.h + $(MOC) datebookdayheader.h -o moc_datebookdayheader.cpp + +moc_datebooksettingsbase.cpp: datebooksettingsbase.h + $(MOC) datebooksettingsbase.h -o moc_datebooksettingsbase.cpp + +moc_datebookweekheader.cpp: datebookweekheader.h + $(MOC) datebookweekheader.h -o moc_datebookweekheader.cpp + +moc_repeatentrybase.cpp: repeatentrybase.h + $(MOC) repeatentrybase.h -o moc_repeatentrybase.cpp + + diff --git a/core/pim/datebook/datebook.cpp b/core/pim/datebook/datebook.cpp new file mode 100644 index 0000000..6ec6cc2 --- a/dev/null +++ b/core/pim/datebook/datebook.cpp @@ -0,0 +1,854 @@ +/********************************************************************** +** 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$ +** +**********************************************************************/ + +#include "datebook.h" +#include "datebookday.h" +#include "datebooksettings.h" +#include "datebookweek.h" +#include "dateentryimpl.h" + +#include <qpe/datebookmonth.h> +#include <qpe/qpeapplication.h> +#include <qpe/config.h> +#include <qpe/qpedebug.h> +#include <qpe/event.h> +#include <qpe/finddialog.h> +#include <qpe/ir.h> +#include <qpe/qpemenubar.h> +#include <qpe/qpemessagebox.h> +#include <qpe/resource.h> +#include <qpe/sound.h> +#include <qpe/timestring.h> +#include <qpe/qpetoolbar.h> +#include <qpe/tzselect.h> +#include <qpe/xmlreader.h> + +#include <qaction.h> +#include <qcopchannel_qws.h> +#include <qdatetime.h> +#include <qdialog.h> +#include <qfile.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qmessagebox.h> +#include <qpopupmenu.h> +#include <qpushbutton.h> +#include <qtextcodec.h> +#include <qtextstream.h> +#include <qtl.h> +#include <qwidgetstack.h> +#include <qwindowsystem_qws.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> + +#include <stdlib.h> + +#define DAY 1 +#define WEEK 2 +#define MONTH 3 + + +DateBook::DateBook( QWidget *parent, const char *, WFlags f ) + : QMainWindow( parent, "datebook", f ), + aPreset( FALSE ), + presetTime( -1 ), + startTime( 8 ), // an acceptable default + syncing(FALSE), + inSearch(FALSE) +{ + QTime t; + t.start(); + db = new DateBookDB; + qDebug("loading db t=%d", t.elapsed() ); + loadSettings(); + setCaption( tr("Calendar") ); + setIcon( Resource::loadPixmap( "datebook_icon" ) ); + + setToolBarsMovable( FALSE ); + + QPEToolBar *bar = new QPEToolBar( this ); + bar->setHorizontalStretchable( TRUE ); + + QPEMenuBar *mb = new QPEMenuBar( bar ); + mb->setMargin( 0 ); + + QPEToolBar *sub_bar = new QPEToolBar(this); + + QPopupMenu *view = new QPopupMenu( this ); + QPopupMenu *settings = new QPopupMenu( this ); + + mb->insertItem( tr( "View" ), view ); + mb->insertItem( tr( "Settings" ), settings ); + + QActionGroup *g = new QActionGroup( this ); + g->setExclusive( TRUE ); + + QAction *a = new QAction( tr( "New" ), Resource::loadPixmap( "new" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( fileNew() ) ); + a->addTo( sub_bar ); + + a = new QAction( tr( "Day" ), Resource::loadPixmap( "day" ), QString::null, 0, g, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( viewDay() ) ); + a->addTo( sub_bar ); + a->addTo( view ); + a->setToggleAction( TRUE ); + a->setOn( TRUE ); + dayAction = a; + a = new QAction( tr( "Week" ), Resource::loadPixmap( "week" ), QString::null, 0, g, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( viewWeek() ) ); + a->addTo( sub_bar ); + a->addTo( view ); + a->setToggleAction( TRUE ); + weekAction = a; + a = new QAction( tr( "Month" ), Resource::loadPixmap( "month" ), QString::null, 0, g, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( viewMonth() ) ); + a->addTo( sub_bar ); + a->addTo( view ); + a->setToggleAction( TRUE ); + monthAction = a; + + a = new QAction( tr( "Find" ), Resource::loadPixmap( "mag" ), QString::null, 0, g, 0 ); + connect( a, SIGNAL(activated()), this, SLOT(slotFind()) ); + a->addTo( sub_bar ); + + a = new QAction( tr( "Today" ), QString::null, 0, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( slotToday() ) ); + a->addTo( view ); + + a = new QAction( tr( "Alarm and Start Time..." ), QString::null, 0, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( slotSettings() ) ); + a->addTo( settings ); + + views = new QWidgetStack( this ); + setCentralWidget( views ); + + dayView = 0; + weekView = 0; + monthView = 0; + + viewDay(); + connect( qApp, SIGNAL(clockChanged(bool)), + this, SLOT(changeClock(bool)) ); + connect( qApp, SIGNAL(weekChanged(bool)), + this, SLOT(changeWeek(bool)) ); + +#if defined(Q_WS_QWS) && !defined(QT_NO_COP) + connect( qApp, SIGNAL(appMessage(const QCString&, const QByteArray&)), + this, SLOT(appMessage(const QCString&, const QByteArray&)) ); +#endif + + // listen on QPE/System +#if defined(Q_WS_QWS) +#if !defined(QT_NO_COP) + QCopChannel *channel = new QCopChannel( "QPE/System", this ); + connect( channel, SIGNAL(received(const QCString&, const QByteArray&)), + this, SLOT(receive(const QCString&, const QByteArray&)) ); +#endif +#endif + + qDebug("done t=%d", t.elapsed() ); + +} + +void DateBook::receive( const QCString &msg, const QByteArray &data ) +{ + QDataStream stream( data, IO_ReadOnly ); + if ( msg == "timeChange(QString)" ) { + // update active view! + if ( dayAction->isOn() ) + viewDay(); + else if ( weekAction->isOn() ) + viewWeek(); + else if ( monthAction->isOn() ) + viewMonth(); + } +} + +DateBook::~DateBook() +{ +} + +void DateBook::slotSettings() +{ + DateBookSettings frmSettings( ampm, this ); + frmSettings.setStartTime( startTime ); + frmSettings.setAlarmPreset( aPreset, presetTime ); +#if defined (Q_WS_QWS) || defined(_WS_QWS_) + frmSettings.showMaximized(); +#endif + + if ( frmSettings.exec() ) { + aPreset = frmSettings.alarmPreset(); + presetTime = frmSettings.presetTime(); + startTime = frmSettings.startTime(); + if ( dayView ) + dayView->setStartViewTime( startTime ); + if ( weekView ) + weekView->setStartViewTime( startTime ); + saveSettings(); + + // make the change obvious + if ( views->visibleWidget() ) { + if ( views->visibleWidget() == dayView ) + dayView->redraw(); + else if ( views->visibleWidget() == weekView ) + weekView->redraw(); + } + } +} + +void DateBook::fileNew() +{ + slotNewEventFromKey(""); +} + +QString DateBook::checkEvent(const Event &e) +{ + /* check if overlaps with itself */ + bool checkFailed = FALSE; + + /* check the next 12 repeats. should catch most problems */ + QDate current_date = e.start().date(); + Event previous = e; + for(int i = 0; i < 12; i++) + { + QDateTime next; + if (!nextOccurance(previous, current_date.addDays(1), next)) { + break; // no more repeats + } + if(next < previous.end()) { + checkFailed = TRUE; + break; + } + current_date = next.date(); + } + + if(checkFailed) + return tr("Event duration is potentially longer\n" + "than interval between repeats."); + + return QString::null; +} + +QDate DateBook::currentDate() +{ + QDate d = QDate::currentDate(); + + if ( dayView && views->visibleWidget() == dayView ) { + d = dayView->date(); + } else if ( weekView && views->visibleWidget() == weekView ) { + d = weekView->date(); + } else if ( monthView && views->visibleWidget() == monthView ) { + d = monthView->selectedDate(); + } + + return d; +} + +void DateBook::viewDay() +{ + initDay(); + dayAction->setOn( TRUE ); + QDate d = currentDate(); + dayView->setDate( d ); + views->raiseWidget( dayView ); + dayView->redraw(); +} + +void DateBook::viewWeek() +{ + initWeek(); + weekAction->setOn( TRUE ); + QDate d = currentDate(); + weekView->setDate( d ); + views->raiseWidget( weekView ); + weekView->redraw(); +} + +void DateBook::viewMonth() +{ + initMonth(); + monthAction->setOn( TRUE ); + QDate d = currentDate(); + monthView->setDate( d.year(), d.month(), d.day() ); + views->raiseWidget( monthView ); + monthView->redraw(); +} + +void DateBook::editEvent( const Event &e ) +{ + if (syncing) { + QMessageBox::warning( this, tr("Calendar"), + tr( "Can not edit data, currently syncing") ); + return; + } + + // workaround added for text input. + QDialog editDlg( this, 0, TRUE ); + DateEntry *entry; + editDlg.setCaption( tr("Edit Event") ); + QVBoxLayout *vb = new QVBoxLayout( &editDlg ); + QScrollView *sv = new QScrollView( &editDlg, "scrollview" ); + sv->setResizePolicy( QScrollView::AutoOneFit ); + // KLUDGE!!! + sv->setHScrollBarMode( QScrollView::AlwaysOff ); + vb->addWidget( sv ); + entry = new DateEntry( onMonday, e, ampm, &editDlg, "editor" ); + entry->timezone->setEnabled( FALSE ); + sv->addChild( entry ); + +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + editDlg.showMaximized(); +#endif + while (editDlg.exec() ) { + Event newEv = entry->event(); + QString error = checkEvent(newEv); + if (!error.isNull()) { + if (QMessageBox::warning(this, "error box", + error, "Fix it", "Continue", 0, 0, 1) == 0) + continue; + } + db->editEvent(e, newEv); + emit newEvent(); + break; + } +} + +void DateBook::removeEvent( const Event &e ) +{ + if (syncing) { + QMessageBox::warning( this, tr("Calendar"), + tr( "Can not edit data, currently syncing") ); + return; + } + + QString strName = e.description(); + + if ( !QPEMessageBox::confirmDelete( this, tr( "Calendar" ),strName ) ) + return; + + db->removeEvent( e ); + if ( views->visibleWidget() == dayView && dayView ) + dayView->redraw(); +} + +void DateBook::addEvent( const Event &e ) +{ + QDate d = e.start().date(); + initDay(); + dayView->setDate( d ); +} + +void DateBook::showDay( int year, int month, int day ) +{ + initDay(); + dayView->setDate( year, month, day ); + views->raiseWidget( dayView ); + dayAction->setOn( TRUE ); +} + +void DateBook::initDay() +{ + if ( !dayView ) { + dayView = new DateBookDay( ampm, onMonday, db, views, "day view" ); + views->addWidget( dayView, DAY ); + dayView->setStartViewTime( startTime ); + connect( this, SIGNAL( newEvent() ), + dayView, SLOT( redraw() ) ); + connect( dayView, SIGNAL( newEvent() ), + this, SLOT( fileNew() ) ); + connect( dayView, SIGNAL( removeEvent( const Event & ) ), + this, SLOT( removeEvent( const Event & ) ) ); + connect( dayView, SIGNAL( editEvent( const Event & ) ), + this, SLOT( editEvent( const Event & ) ) ); + connect( dayView, SIGNAL( beamEvent( const Event & ) ), + this, SLOT( beamEvent( const Event & ) ) ); + connect( dayView, SIGNAL(sigNewEvent(const QString &)), + this, SLOT(slotNewEventFromKey(const QString &)) ); + } +} + +void DateBook::initWeek() +{ + if ( !weekView ) { + weekView = new DateBookWeek( ampm, onMonday, db, views, "week view" ); + weekView->setStartViewTime( startTime ); + views->addWidget( weekView, WEEK ); + connect( weekView, SIGNAL( showDate( int, int, int ) ), + this, SLOT( showDay( int, int, int ) ) ); + connect( this, SIGNAL( newEvent() ), + weekView, SLOT( redraw() ) ); + } + //But also get it right: the year that we display can be different + //from the year of the current date. So, first find the year + //number of the current week. + + int yearNumber, totWeeks; + calcWeek( currentDate(), totWeeks, yearNumber, onMonday ); + + QDate d = QDate( yearNumber, 12, 31 ); + calcWeek( d, totWeeks, yearNumber, onMonday ); + + while ( totWeeks == 1 ) { + d = d.addDays( -1 ); + calcWeek( d, totWeeks, yearNumber, onMonday ); + } + if ( totWeeks != weekView->totalWeeks() ) + weekView->setTotalWeeks( totWeeks ); +} + +void DateBook::initMonth() +{ + if ( !monthView ) { + monthView = new DateBookMonth( views, "month view", FALSE, db ); + views->addWidget( monthView, MONTH ); + connect( monthView, SIGNAL( dateClicked( int, int, int ) ), + this, SLOT( showDay( int, int, int ) ) ); + connect( this, SIGNAL( newEvent() ), + monthView, SLOT( redraw() ) ); + qApp->processEvents(); + } +} + +void DateBook::loadSettings() +{ + { + Config config( "qpe" ); + config.setGroup("Time"); + ampm = config.readBoolEntry( "AMPM", TRUE ); + onMonday = config.readBoolEntry( "MONDAY" ); + } + + { + Config config("DateBook"); + config.setGroup("Main"); + startTime = config.readNumEntry("startviewtime", 8); + aPreset = config.readBoolEntry("alarmpreset"); + presetTime = config.readNumEntry("presettime"); + } +} + +void DateBook::saveSettings() +{ + Config config( "qpe" ); + Config configDB( "DateBook" ); + configDB.setGroup( "Main" ); + configDB.writeEntry("startviewtime",startTime); + configDB.writeEntry("alarmpreset",aPreset); + configDB.writeEntry("presettime",presetTime); +} + +void DateBook::appMessage(const QCString& msg, const QByteArray& data) +{ + bool needShow = FALSE; + if ( msg == "alarm(QDateTime,int)" ) { + QDataStream ds(data,IO_ReadOnly); + QDateTime when; int warn; + ds >> when >> warn; + + // check to make it's okay to continue, + // this is the case that the time was set ahead, and + // we are forced given a stale alarm... + QDateTime current = QDateTime::currentDateTime(); + if ( current.time().hour() != when.time().hour() + && current.time().minute() != when.time().minute() ) + return; + + QValueList<EffectiveEvent> list = db->getEffectiveEvents(when.addSecs(warn*60)); + if ( list.count() > 0 ) { + QString msg; + bool bSound = FALSE; + int stopTimer = 0; + bool found = FALSE; + for ( QValueList<EffectiveEvent>::ConstIterator it=list.begin(); + it!=list.end(); ++it ) { + if ( (*it).event().hasAlarm() ) { + found = TRUE; + msg += "<CENTER><B>" + (*it).description() + "</B>" + + "<BR>" + (*it).location() + "<BR>" + + TimeString::dateString((*it).event().start(),ampm) + + (warn + ? tr(" (in " + QString::number(warn) + + tr(" minutes)")) + : QString("")) + + "<BR>" + + (*it).notes() + "</CENTER>"; + if ( (*it).event().alarmSound() != Event::Silent ) { + bSound = TRUE; + } + } + } + if ( found ) { + if ( bSound ) { + Sound::soundAlarm(); + stopTimer = startTimer( 5000 ); + } + + QDialog dlg( this, 0, TRUE ); + QVBoxLayout *vb = new QVBoxLayout( &dlg ); + QScrollView *view = new QScrollView( &dlg, "scrollView"); + view->setResizePolicy( QScrollView::AutoOneFit ); + vb->addWidget( view ); + QLabel *lblMsg = new QLabel( msg, &dlg ); + view->addChild( lblMsg ); + QPushButton *cmdOk = new QPushButton( tr("OK"), &dlg ); + connect( cmdOk, SIGNAL(clicked()), &dlg, SLOT(accept()) ); + vb->addWidget( cmdOk ); + +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + dlg.showMaximized(); +#endif + needShow = dlg.exec(); + + if ( bSound ) + killTimer( stopTimer ); + } + } + } else if ( msg == "nextView()" ) { + QWidget* cur = views->visibleWidget(); + if ( cur ) { + if ( cur == dayView ) + viewWeek(); + else if ( cur == weekView ) + viewMonth(); + else if ( cur == monthView ) + viewDay(); + needShow = TRUE; + } + } + if ( needShow ) { +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + showMaximized(); +#else + show(); +#endif + raise(); + QPEApplication::setKeepRunning(); + setActiveWindow(); + } +} + +void DateBook::reload() +{ + db->reload(); + if ( dayAction->isOn() ) + viewDay(); + else if ( weekAction->isOn() ) + viewWeek(); + else if ( monthAction->isOn() ) + viewMonth(); + syncing = FALSE; +} + +void DateBook::flush() +{ + syncing = TRUE; + db->save(); +} + +void DateBook::timerEvent( QTimerEvent *e ) +{ + static int stop = 0; + if ( stop < 10 ) { + Sound::soundAlarm(); + stop++; + } else { + stop = 0; + killTimer( e->timerId() ); + } +} + +void DateBook::changeClock( bool newClock ) +{ + ampm = newClock; + // repaint the affected objects... + if (dayView) dayView->redraw(); + if (weekView) weekView->redraw(); +} + +void DateBook::changeWeek( bool m ) +{ + /* no need to redraw, each widget catches. Do need to + store though for widgets we haven't made yet */ + onMonday = m; +} + +void DateBook::slotToday() +{ + // we need to view today + QDate dt = QDate::currentDate(); + showDay( dt.year(), dt.month(), dt.day() ); +} + +void DateBook::closeEvent( QCloseEvent *e ) +{ + if(syncing) { + /* no need to save, did that at flush */ + e->accept(); + return; + } + + // save settings will generate it's own error messages, no + // need to do checking ourselves. + saveSettings(); + if ( db->save() ) + e->accept(); + else { + if ( QMessageBox::critical( this, tr( "Out of space" ), + tr("Calendar was unable to save\n" + "your changes.\n" + "Free up some space and try again.\n" + "\nQuit anyway?"), + QMessageBox::Yes|QMessageBox::Escape, + QMessageBox::No|QMessageBox::Default ) + != QMessageBox::No ) + e->accept(); + else + e->ignore(); + } +} + +// Entering directly from the "keyboard" +void DateBook::slotNewEventFromKey( const QString &str ) +{ + if (syncing) { + QMessageBox::warning( this, tr("Calendar"), + tr( "Can not edit data, currently syncing") ); + return; + } + + // We get to here from a key pressed in the Day View + // So we can assume some things. We want the string + // passed in to be part of the description. + QDateTime start, end; + if ( views->visibleWidget() == dayView ) { + dayView->selectedDates( start, end ); + } else if ( views->visibleWidget() == monthView ) { + QDate d = monthView->selectedDate(); + start = end = d; + start.setTime( QTime( 10, 0 ) ); + end.setTime( QTime( 12, 0 ) ); + } else if ( views->visibleWidget() == weekView ) { + QDate d = weekView->date(); + start = end = d; + start.setTime( QTime( 10, 0 ) ); + end.setTime( QTime( 12, 0 ) ); + } + + // argh! This really needs to be encapsulated in a class + // or function. + QDialog newDlg( this, 0, TRUE ); + newDlg.setCaption( DateEntryBase::tr("New Event") ); + DateEntry *e; + QVBoxLayout *vb = new QVBoxLayout( &newDlg ); + QScrollView *sv = new QScrollView( &newDlg ); + sv->setResizePolicy( QScrollView::AutoOneFit ); + sv->setFrameStyle( QFrame::NoFrame ); + sv->setHScrollBarMode( QScrollView::AlwaysOff ); + vb->addWidget( sv ); + + Event ev; + ev.setDescription( str ); + // When the new gui comes in, change this... + ev.setLocation( tr("(Unknown)") ); + ev.setStart( start ); + ev.setEnd( end ); + + e = new DateEntry( onMonday, ev, ampm, &newDlg ); + e->setAlarmEnabled( aPreset, presetTime, Event::Loud ); + sv->addChild( e ); +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + newDlg.showMaximized(); +#endif + while (newDlg.exec()) { + ev = e->event(); + ev.assignUid(); + QString error = checkEvent( ev ); + if ( !error.isNull() ) { + if ( QMessageBox::warning( this, tr("Error!"), + error, tr("Fix it"), tr("Continue"), 0, 0, 1 ) == 0 ) + continue; + } + db->addEvent( ev ); + emit newEvent(); + break; + } +} + +void DateBook::setDocument( const QString &filename ) +{ + if ( filename.find(".vcs") != int(filename.length()) - 4 ) return; + + QValueList<Event> tl = Event::readVCalendar( filename ); + for( QValueList<Event>::Iterator it = tl.begin(); it != tl.end(); ++it ) { + db->addEvent( *it ); + } +} + +static const char * beamfile = "/tmp/obex/event.vcs"; + +void DateBook::beamEvent( const Event &e ) +{ + qDebug("trying to beamn"); + unlink( beamfile ); // delete if exists + mkdir("/tmp/obex/", 0755); + Event::writeVCalendar( beamfile, e ); + Ir *ir = new Ir( this ); + connect( ir, SIGNAL( done( Ir * ) ), this, SLOT( beamDone( Ir * ) ) ); + QString description = e.description(); + ir->send( beamfile, description, "text/x-vCalendar" ); +} + +void DateBook::beamDone( Ir *ir ) +{ + delete ir; + unlink( beamfile ); +} + +void DateBook::slotFind() +{ + // move it to the day view... + viewDay(); + FindDialog frmFind( "Calendar", this ); + frmFind.setUseDate( true ); + frmFind.setDate( currentDate() ); + QObject::connect( &frmFind, + SIGNAL(signalFindClicked(const QString&, const QDate&, + bool, bool, int)), + this, + SLOT(slotDoFind(const QString&, const QDate&, + bool, bool, int)) ); + QObject::connect( this, + SIGNAL(signalNotFound()), + &frmFind, + SLOT(slotNotFound()) ); + QObject::connect( this, + SIGNAL(signalWrapAround()), + &frmFind, + SLOT(slotWrapAround()) ); + frmFind.exec(); + inSearch = false; +} + +bool catComp( QArray<int> cats, int category ) +{ + bool returnMe; + int i, + count; + + count = int(cats.count()); + returnMe = false; + if ( (category == -1 && count == 0) || category == -2 ) + returnMe = true; + else { + for ( i = 0; i < count; i++ ) { + if ( category == cats[i] ) { + returnMe = true; + break; + } + } + } + return returnMe; +} + + +void DateBook::slotDoFind( const QString& txt, const QDate &dt, + bool caseSensitive, bool /*backwards*/, + int category ) +{ + QDateTime dtEnd( QDate(3001, 1, 1), QTime(0, 0, 0) ), + next; + + QRegExp r( txt ); + r.setCaseSensitive( caseSensitive ); + + + static Event rev, + nonrev; + if ( !inSearch ) { + rev.setStart( QDateTime(QDate(1960, 1, 1), QTime(0, 0, 0)) ); + nonrev.setStart( rev.start() ); + inSearch = true; + } + static QDate searchDate = dt; + static bool wrapAround = true; + bool candidtate; + candidtate = false; + + QValueList<Event> repeats = db->getRawRepeats(); + + // find the candidate for the first repeat that matches... + QValueListConstIterator<Event> it; + QDate start = dt; + for ( it = repeats.begin(); it != repeats.end(); ++it ) { + if ( catComp( (*it).categories(), category ) ) { + while ( nextOccurance( *it, start, next ) ) { + if ( next < dtEnd ) { + if ( (*it).match( r ) && !(next <= rev.start()) ) { + rev = *it; + dtEnd = next; + rev.setStart( next ); + candidtate = true; + wrapAround = true; + start = dt; + break; + } else + start = next.date().addDays( 1 ); + } + } + } + } + + // now the for first non repeat... + QValueList<Event> nonRepeats = db->getNonRepeatingEvents( dt, dtEnd.date() ); + qHeapSort( nonRepeats.begin(), nonRepeats.end() ); + for ( it = nonRepeats.begin(); it != nonRepeats.end(); ++it ) { + if ( catComp( (*it).categories(), category ) ) { + if ( (*it).start() < dtEnd ) { + if ( (*it).match( r ) && !(*it <= nonrev) ) { + nonrev = *it; + dtEnd = nonrev.start(); + candidtate = true; + wrapAround = true; + break; + } + } + } + } + if ( candidtate ) { + dayView->setStartViewTime( dtEnd.time().hour() ); + dayView->setDate( dtEnd.date().year(), dtEnd.date().month(), + dtEnd.date().day() ); + } else { + if ( wrapAround ) { + emit signalWrapAround(); + rev.setStart( QDateTime(QDate(1960, 1, 1), QTime(0, 0, 0)) ); + nonrev.setStart( rev.start() ); + } else + emit signalNotFound(); + wrapAround = !wrapAround; + } +} diff --git a/core/pim/datebook/datebook.h b/core/pim/datebook/datebook.h new file mode 100644 index 0000000..44627bb --- a/dev/null +++ b/core/pim/datebook/datebook.h @@ -0,0 +1,111 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ +#ifndef DATEBOOK_H +#define DATEBOOK_H + +#include <qpe/datebookdb.h> + +#include <qmainwindow.h> + +class QAction; +class QWidgetStack; +class DateBookDay; +class DateBookWeek; +class DateBookMonth; +class Event; +class QDate; +class Ir; + +class DateBook : public QMainWindow +{ + Q_OBJECT + +public: + DateBook( QWidget *parent = 0, const char *name = 0, WFlags f = 0 ); + ~DateBook(); + +signals: + void newEvent(); + void signalNotFound(); + void signalWrapAround(); + +protected: + QDate currentDate(); + void timerEvent( QTimerEvent *e ); + void closeEvent( QCloseEvent *e ); + +public slots: + void flush(); + void reload(); + +private slots: + void fileNew(); + void slotSettings(); + void slotToday(); // view today + void changeClock( bool newClock ); + void changeWeek( bool newDay ); + void appMessage(const QCString& msg, const QByteArray& data); + // handle key events in the day view... + void slotNewEventFromKey( const QString &str ); + void slotFind(); + void slotDoFind( const QString &, const QDate &, bool, bool, int ); + + void viewDay(); + void viewWeek(); + void viewMonth(); + + void showDay( int y, int m, int d ); + + void editEvent( const Event &e ); + void removeEvent( const Event &e ); + + void receive( const QCString &msg, const QByteArray &data ); + void setDocument( const QString & ); + void beamEvent( const Event &e ); + void beamDone( Ir *ir ); + +private: + void addEvent( const Event &e ); + void initDay(); + void initWeek(); + void initMonth(); + void loadSettings(); + void saveSettings(); + +private: + DateBookDB *db; + QWidgetStack *views; + DateBookDay *dayView; + DateBookWeek *weekView; + DateBookMonth *monthView; + QAction *dayAction, *weekAction, *monthAction; + bool aPreset; // have everything set to alarm? + int presetTime; // the standard time for the alarm + int startTime; + bool ampm; + bool onMonday; + + bool syncing; + bool inSearch; + + QString checkEvent(const Event &); +}; + +#endif diff --git a/core/pim/datebook/datebook.pro b/core/pim/datebook/datebook.pro new file mode 100644 index 0000000..17c02ec --- a/dev/null +++ b/core/pim/datebook/datebook.pro @@ -0,0 +1,36 @@ +TEMPLATE = app +CONFIG += qt warn_on release +DESTDIR = $(QPEDIR)/bin + +HEADERS = datebookday.h \ + datebook.h \ + dateentryimpl.h \ + datebookdayheaderimpl.h \ + datebooksettings.h \ + datebookweek.h \ + datebookweekheaderimpl.h \ + repeatentry.h + +SOURCES = main.cpp \ + datebookday.cpp \ + datebook.cpp \ + dateentryimpl.cpp \ + datebookdayheaderimpl.cpp \ + datebooksettings.cpp \ + datebookweek.cpp \ + datebookweekheaderimpl.cpp \ + repeatentry.cpp + +INTERFACES = dateentry.ui \ + datebookdayheader.ui \ + datebooksettingsbase.ui \ + datebookweekheader.ui \ + repeatentrybase.ui + +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe + +TARGET = datebook + +TRANSLATIONS = ../i18n/de/datebook.ts diff --git a/core/pim/datebook/datebookday.cpp b/core/pim/datebook/datebookday.cpp new file mode 100644 index 0000000..d5daab2 --- a/dev/null +++ b/core/pim/datebook/datebookday.cpp @@ -0,0 +1,553 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#include "datebookday.h" +#include "datebookdayheaderimpl.h" + +#include <qpe/datebookdb.h> +#include <qpe/resource.h> +#include <qpe/event.h> +#include <qpe/qpeapplication.h> +#include <qpe/timestring.h> +#include <qpe/qpedebug.h> + +#include <qheader.h> +#include <qdatetime.h> +#include <qpainter.h> +#include <qsimplerichtext.h> +#include <qpopupmenu.h> +#include <qtextcodec.h> +#include <qpalette.h> + +DateBookDayView::DateBookDayView( bool whichClock, QWidget *parent, + const char *name ) + : QTable( 24, 1, parent, name ), + ampm( whichClock ) +{ + enableClipper(TRUE); + setTopMargin( 0 ); + horizontalHeader()->hide(); + setLeftMargin(38); + setColumnStretchable( 0, TRUE ); + setHScrollBarMode( QScrollView::AlwaysOff ); + verticalHeader()->setPalette(white); + verticalHeader()->setResizeEnabled(FALSE); + setSelectionMode( Single ); + + // get rid of being able to edit things... + QTableItem *tmp; + int row; + for ( row = 0; row < numRows(); row++ ) { + tmp = new QTableItem( this, QTableItem::Never, QString::null); + setItem( row, 0, tmp ); + } + initHeader(); + QObject::connect( qApp, SIGNAL(clockChanged(bool)), + this, SLOT(slotChangeClock(bool)) ); +} + +void DateBookDayView::initHeader() +{ + QString strTmp; + for ( int i = 0; i < 24; ++i ) { + if ( ampm ) { + if ( i == 0 ) + strTmp = QString::number(12) + ":00"; + else if ( i == 12 ) + strTmp = QString::number(12) + tr(":00p"); + else if ( i > 12 ) + strTmp = QString::number( i - 12 ) + tr(":00p"); + else + strTmp = QString::number(i) + ":00"; + } else { + if ( i < 10 ) + strTmp = "0" + QString::number(i) + ":00"; + else + strTmp = QString::number(i) + ":00"; + } + strTmp = strTmp.rightJustify( 6, ' ' ); + verticalHeader()->setLabel( i, strTmp ); + setRowStretchable( i, FALSE ); + } +} + +void DateBookDayView::slotChangeClock( bool newClock ) +{ + ampm = newClock; + initHeader(); +} + +bool DateBookDayView::whichClock() const +{ + return ampm; +} + +void DateBookDayView::moveUp() +{ + scrollBy(0, -20); +} + +void DateBookDayView::moveDown() +{ + scrollBy(0, 20); +} + +void DateBookDayView::paintCell( QPainter *p, int, int, const QRect &cr, bool ) +{ + int w = cr.width(); + int h = cr.height(); + p->fillRect( 0, 0, w, h, colorGroup().brush( QColorGroup::Base ) ); + if ( showGrid() ) { + // Draw our lines + int x2 = w - 1; + int y2 = h - 1; + QPen pen( p->pen() ); + p->setPen( colorGroup().mid() ); + p->drawLine( x2, 0, x2, y2 ); + p->drawLine( 0, y2, x2, y2 ); + p->setPen( pen ); + } +} + +void DateBookDayView::paintFocus( QPainter *, const QRect & ) +{ +} + + +void DateBookDayView::resizeEvent( QResizeEvent *e ) +{ + QTable::resizeEvent( e ); + columnWidthChanged( 0 ); + emit sigColWidthChanged(); +} + +void DateBookDayView::keyPressEvent( QKeyEvent *e ) +{ + QString txt = e->text(); + if ( !txt.isNull() && txt[0] > ' ' && e->key() < 0x1000 ) { + // we this is some sort of thing we know about... + e->accept(); + emit sigCapturedKey( txt ); + } else { + // I don't know what this key is, do you? + e->ignore(); + } +} + + +//=========================================================================== + +DateBookDay::DateBookDay( bool ampm, bool startOnMonday, + DateBookDB *newDb, QWidget *parent, + const char *name ) + : QVBox( parent, name ), + currDate( QDate::currentDate() ), + db( newDb ), + startTime( 0 ) +{ + widgetList.setAutoDelete( true ); + header = new DateBookDayHeader( startOnMonday, this, "day header" ); + header->setDate( currDate.year(), currDate.month(), currDate.day() ); + view = new DateBookDayView( ampm, this, "day view" ); + connect( header, SIGNAL( dateChanged( int, int, int ) ), + this, SLOT( dateChanged( int, int, int ) ) ); + connect( view, SIGNAL( sigColWidthChanged() ), + this, SLOT( slotColWidthChanged() ) ); + connect( qApp, SIGNAL(weekChanged(bool)), + this, SLOT(slotWeekChanged(bool)) ); + connect( view, SIGNAL(sigCapturedKey(const QString &)), + this, SIGNAL(sigNewEvent(const QString&)) ); +} + +void DateBookDay::selectedDates( QDateTime &start, QDateTime &end ) +{ + start.setDate( currDate ); + end.setDate( currDate ); + + int sh=99,eh=-1; + + int n = dayView()->numSelections(); + + for (int i=0; i<n; i++) { + QTableSelection sel = dayView()->selection( i ); + sh = QMIN(sh,sel.topRow()); + eh = QMAX(sh,sel.bottomRow()+1); + } + if (sh > 23 || eh < 1) { + sh=8; + eh=9; + } + + start.setTime( QTime( sh, 0, 0 ) ); + end.setTime( QTime( eh, 0, 0 ) ); +} + +void DateBookDay::setDate( int y, int m, int d ) +{ + header->setDate( y, m, d ); +} + +void DateBookDay::setDate( QDate d) +{ + header->setDate( d.year(), d.month(), d.day() ); +} + +void DateBookDay::dateChanged( int y, int m, int d ) +{ + QDate date( y, m, d ); + if ( currDate == date ) + return; + currDate.setYMD( y, m, d ); + relayoutPage(); + dayView()->clearSelection(); + QTableSelection ts; + ts.init( startTime, 0 ); + ts.expandTo( startTime, 0 ); + dayView()->addSelection( ts ); +} + +void DateBookDay::redraw() +{ + if ( isUpdatesEnabled() ) + relayoutPage(); +} + +void DateBookDay::getEvents() +{ + widgetList.clear(); + + QValueList<EffectiveEvent> eventList = db->getEffectiveEvents( currDate, + currDate ); + QValueListIterator<EffectiveEvent> it; + for ( it = eventList.begin(); it != eventList.end(); ++it ) { + DateBookDayWidget* w = new DateBookDayWidget( *it, this ); + connect( w, SIGNAL( deleteMe( const Event & ) ), + this, SIGNAL( removeEvent( const Event & ) ) ); + connect( w, SIGNAL( editMe( const Event & ) ), + this, SIGNAL( editEvent( const Event & ) ) ); + connect( w, SIGNAL( beamMe( const Event & ) ), + this, SIGNAL( beamEvent( const Event & ) ) ); + widgetList.append( w ); + } +} + +static int place( const DateBookDayWidget *item, bool *used, int maxn ) +{ + int place = 0; + int start = item->event().start().hour(); + QTime e = item->event().end(); + int end = e.hour(); + if ( e.minute() < 5 ) + end--; + if ( end < start ) + end = start; + while ( place < maxn ) { + bool free = TRUE; + int s = start; + while( s <= end ) { + if ( used[10*s+place] ) { + free = FALSE; + break; + } + s++; + } + if ( free ) break; + place++; + } + if ( place == maxn ) { + return -1; + } + while( start <= end ) { + used[10*start+place] = TRUE; + start++; + } + return place; +} + + +void DateBookDay::relayoutPage( bool fromResize ) +{ + setUpdatesEnabled( FALSE ); + if ( !fromResize ) + getEvents(); // no need we already have them! + + int wCount = widgetList.count(); + int wid = view->columnWidth(0)-1; + int n = 1; + + if ( wCount < 20 ) { + for ( int i = 0; i < wCount; ) { + DateBookDayWidget *w = widgetList.at(i); + int x = 0; + int xp = 0; + QRect geom = w->geometry(); + geom.setX( x ); + geom.setWidth( wid ); + while ( xp < n && intersects( w, geom ) ) { + x += wid; + xp++; + geom.moveBy( wid, 0 ); + } + if ( xp >= n ) { + n++; + wid = ( view->columnWidth(0)-1 ) / n; + i = 0; + } else { + w->setGeometry( geom ); + i++; + } + } + view->setContentsPos( 0, startTime * view->rowHeight(0) ); + } else { + + + int hours[24]; + memset( hours, 0, 24*sizeof( int ) ); + bool overFlow = FALSE; + for ( int i = 0; i < wCount; i++ ) { + DateBookDayWidget *w = widgetList.at(i); + int start = w->event().start().hour(); + QTime e = w->event().end(); + int end = e.hour(); + if ( e.minute() < 5 ) + end--; + if ( end < start ) + end = start; + while( start <= end ) { + hours[start]++; + if ( hours[start] >= 10 ) + overFlow = TRUE; + ++start; + } + if ( overFlow ) + break; + } + for ( int i = 0; i < 24; i++ ) { + n = QMAX( n, hours[i] ); + } + wid = ( view->columnWidth(0)-1 ) / n; + + bool used[24*10]; + memset( used, FALSE, 24*10*sizeof( bool ) ); + + for ( int i = 0; i < wCount; i++ ) { + DateBookDayWidget *w = widgetList.at(i); + int xp = place( w, used, n ); + if ( xp != -1 ) { + QRect geom = w->geometry(); + geom.setX( xp*wid ); + geom.setWidth( wid ); + w->setGeometry( geom ); + } + } + view->setContentsPos( 0, startTime * view->rowHeight(0) ); + } + setUpdatesEnabled( TRUE ); + return; +} + +DateBookDayWidget *DateBookDay::intersects( const DateBookDayWidget *item, const QRect &geom ) +{ + int i = 0; + DateBookDayWidget *w = widgetList.at(i); + int wCount = widgetList.count(); + while ( i < wCount && w != item ) { + if ( w->geometry().intersects( geom ) ) { + return w; + } + w = widgetList.at(++i); + } + + return 0; +} + + +QDate DateBookDay::date() const +{ + return currDate; +} + +void DateBookDay::setStartViewTime( int startHere ) +{ + startTime = startHere; + dayView()->clearSelection(); + QTableSelection ts; + ts.init( startTime, 0 ); + ts.expandTo( startTime, 0 ); + dayView()->addSelection( ts ); +} + +int DateBookDay::startViewTime() const +{ + return startTime; +} + +void DateBookDay::slotWeekChanged( bool bStartOnMonday ) +{ + header->setStartOfWeek( bStartOnMonday ); + // redraw(); +} + +void DateBookDay::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Key_Up: + view->moveUp(); + break; + case Key_Down: + view->moveDown(); + break; + case Key_Left: + setDate(QDate(currDate).addDays(-1)); + break; + case Key_Right: + setDate(QDate(currDate).addDays(1)); + break; + default: + e->ignore(); + } +} + +//=========================================================================== + +DateBookDayWidget::DateBookDayWidget( const EffectiveEvent &e, + DateBookDay *db ) + : QWidget( db->dayView()->viewport() ), ev( e ), dateBook( db ) +{ + bool whichClock = db->dayView()->whichClock(); + + // why would someone use "<"? Oh well, fix it up... + // I wonder what other things may be messed up... + QString strDesc = ev.description(); + int where = strDesc.find( "<" ); + while ( where != -1 ) { + strDesc.remove( where, 1 ); + strDesc.insert( where, "<" ); + where = strDesc.find( "<", where ); + } + + QString strCat; + // ### Fix later... +// QString strCat = ev.category(); +// where = strCat.find( "<" ); +// while ( where != -1 ) { +// strCat.remove( where, 1 ); +// strCat.insert( where, "<" ); +// where = strCat.find( "<", where ); +// } + + QString strNote = ev.notes(); + where = strNote.find( "<" ); + while ( where != -1 ) { + strNote.remove( where, 1 ); + strNote.insert( where, "<" ); + where = strNote.find( "<", where ); + } + + text = "<b>" + strDesc + "</b><br>" + "<i>" + + strCat + "</i>" + + "<br><b>" + tr("Start") + "</b>: "; + + + if ( e.startDate() != ev.date() ) { + // multi-day event. Show start date + text += TimeString::longDateString( e.startDate() ); + } else { + // Show start time. + text += TimeString::timeString( ev.start(), whichClock, FALSE ); + } + + text += "<br><b>" + tr("End") + "</b>: "; + if ( e.endDate() != ev.date() ) { + // multi-day event. Show end date + text += TimeString::longDateString( e.endDate() ); + } else { + // Show end time. + text += TimeString::timeString( ev.end(), whichClock, FALSE ); + } + text += "<br><br>" + strNote; + setBackgroundMode( PaletteBase ); + + QTime s = ev.start(); + QTime e = ev.end(); + int y = s.hour()*60+s.minute(); + int h = e.hour()*60+e.minute()-y; + int rh = dateBook->dayView()->rowHeight(0); + y = y*rh/60; + h = h*rh/60; + if ( h < 3 ) + h = 3; + geom.setY( y ); + geom.setHeight( h ); +} + +DateBookDayWidget::~DateBookDayWidget() +{ +} + +void DateBookDayWidget::paintEvent( QPaintEvent *e ) +{ + QPainter p( this ); + p.setPen( QColor(100, 100, 100) ); + p.setBrush( QColor( 255, 240, 230 ) ); // based on priority? + p.drawRect(rect()); + + int y = 0; + int d = 0; + + if ( ev.event().hasAlarm() ) { + p.drawPixmap( width() - 16, 0, Resource::loadPixmap( "bell" ) ); + y = 20; + d = 20; + } + + if ( ev.event().hasRepeat() ) { + p.drawPixmap( width() - 16, y, Resource::loadPixmap( "repeat" ) ); + d = 20; + } + + QSimpleRichText rt( text, font() ); + rt.setWidth( geom.width() - d - 6 ); + rt.draw( &p, 3, 0, e->region(), colorGroup() ); +} + +void DateBookDayWidget::mousePressEvent( QMouseEvent *e ) +{ + QPopupMenu m; + m.insertItem( tr( "Edit" ), 1 ); + m.insertItem( tr( "Delete" ), 2 ); + m.insertItem( tr( "Beam" ), 3 ); + int r = m.exec( e->globalPos() ); + if ( r == 1 ) { + emit editMe( ev.event() ); + } else if ( r == 2 ) { + emit deleteMe( ev.event() ); + } else if ( r == 3 ) { + emit beamMe( ev.event() ); + } +} + +void DateBookDayWidget::setGeometry( const QRect &r ) +{ + geom = r; + setFixedSize( r.width()+1, r.height()+1 ); + dateBook->dayView()->moveChild( this, r.x(), r.y()-1 ); + show(); +} diff --git a/core/pim/datebook/datebookday.h b/core/pim/datebook/datebookday.h new file mode 100644 index 0000000..531fded --- a/dev/null +++ b/core/pim/datebook/datebookday.h @@ -0,0 +1,138 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ +#ifndef DATEBOOKDAY_H +#define DATEBOOKDAY_H + +#include <qpe/event.h> + +#include <qdatetime.h> +#include <qtable.h> +#include <qvbox.h> +#include <qlist.h> + +class DateBookDayHeader; +class DateBookDB; +class QDateTime; +class QMouseEvent; +class QPaintEvent; +class QResizeEvent; + +class DateBookDayView : public QTable +{ + Q_OBJECT +public: + DateBookDayView( bool hourClock, QWidget *parent, const char *name ); + bool whichClock() const; + +public slots: + void moveUp(); + void moveDown(); + +signals: + void sigColWidthChanged(); + void sigCapturedKey( const QString &txt ); +protected slots: + void slotChangeClock( bool ); +protected: + virtual void paintCell( QPainter *p, int row, int col, const QRect &cr, bool selected ); + virtual void paintFocus( QPainter *p, const QRect &cr ); + virtual void resizeEvent( QResizeEvent *e ); + void keyPressEvent( QKeyEvent *e ); + void initHeader(); +private: + bool ampm; +}; + +class DateBookDay; +class DateBookDayWidget : public QWidget +{ + Q_OBJECT + +public: + DateBookDayWidget( const EffectiveEvent &e, DateBookDay *db ); + ~DateBookDayWidget(); + + const QRect &geometry() { return geom; } + void setGeometry( const QRect &r ); + + const EffectiveEvent &event() const { return ev; } + +signals: + void deleteMe( const Event &e ); + void editMe( const Event &e ); + void beamMe( const Event &e ); + +protected: + void paintEvent( QPaintEvent *e ); + void mousePressEvent( QMouseEvent *e ); + +private: + const EffectiveEvent ev; + DateBookDay *dateBook; + QString text; + QRect geom; +}; + +class DateBookDay : public QVBox +{ + Q_OBJECT + +public: + DateBookDay( bool ampm, bool startOnMonday, DateBookDB *newDb, + QWidget *parent, const char *name ); + void selectedDates( QDateTime &start, QDateTime &end ); + QDate date() const; + DateBookDayView *dayView() const { return view; } + void setStartViewTime( int startHere ); + int startViewTime() const; + +public slots: + void setDate( int y, int m, int d ); + void setDate( QDate ); + void redraw(); + void slotWeekChanged( bool bStartOnMonday ); + +signals: + void removeEvent( const Event& ); + void editEvent( const Event& ); + void beamEvent( const Event& ); + void newEvent(); + void sigNewEvent( const QString & ); + +protected slots: + void keyPressEvent(QKeyEvent *); + +private slots: + void dateChanged( int y, int m, int d ); + void slotColWidthChanged() { relayoutPage(); }; + +private: + void getEvents(); + void relayoutPage( bool fromResize = false ); + DateBookDayWidget *intersects( const DateBookDayWidget *item, const QRect &geom ); + QDate currDate; + DateBookDayView *view; + DateBookDayHeader *header; + DateBookDB *db; + QList<DateBookDayWidget> widgetList; + int startTime; +}; + +#endif diff --git a/core/pim/datebook/datebookdayheader.ui b/core/pim/datebook/datebookdayheader.ui new file mode 100644 index 0000000..8bc284f --- a/dev/null +++ b/core/pim/datebook/datebookdayheader.ui @@ -0,0 +1,424 @@ +<!DOCTYPE UI><UI> +<class>DateBookDayHeaderBase</class> +<comment>/********************************************************************** +** Copyright (C) 2001 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>QWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>DateBookDayHeaderBase</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>249</width> + <height>26</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>Form1</string> + </property> + <property> + <name>layoutMargin</name> + </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>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>back</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string></string> + </property> + <property stdset="1"> + <name>pixmap</name> + <pixmap>image0</pixmap> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>false</bool> + </property> + <property stdset="1"> + <name>autoRepeat</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>autoRaise</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>false</bool> + </property> + <property> + <name>toolTip</name> + <string></string> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>date</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>font</name> + <font> + <bold>1</bold> + </font> + </property> + <property stdset="1"> + <name>text</name> + <string></string> + </property> + <property stdset="1"> + <name>pixmap</name> + <pixmap></pixmap> + </property> + <property stdset="1"> + <name>autoRepeat</name> + <bool>false</bool> + </property> + <property stdset="1"> + <name>autoRaise</name> + <bool>false</bool> + </property> + </widget> + <widget> + <class>QButtonGroup</class> + <property stdset="1"> + <name>name</name> + <cstring>grpDays</cstring> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>NoFrame</enum> + </property> + <property stdset="1"> + <name>frameShadow</name> + <enum>Plain</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>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>1</number> + </property> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdDay1</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>M</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>autoRaise</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property> + <name>toolTip</name> + <string></string> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdDay2</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>T</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>autoRaise</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property> + <name>toolTip</name> + <string></string> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdDay3</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>W</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>autoRaise</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property> + <name>toolTip</name> + <string></string> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdDay4</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>T</string> + </property> + <property stdset="1"> + <name>pixmap</name> + <pixmap></pixmap> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>autoRepeat</name> + <bool>false</bool> + </property> + <property stdset="1"> + <name>autoRaise</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property> + <name>toolTip</name> + <string></string> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdDay5</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>F</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>autoRaise</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property> + <name>toolTip</name> + <string></string> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdDay6</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>S</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>autoRaise</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property> + <name>toolTip</name> + <string></string> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdDay7</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>S</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>autoRaise</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property> + <name>toolTip</name> + <string></string> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>forward</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string></string> + </property> + <property stdset="1"> + <name>pixmap</name> + <pixmap>image1</pixmap> + </property> + <property stdset="1"> + <name>autoRepeat</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>autoRaise</name> + <bool>true</bool> + </property> + </widget> + </hbox> +</widget> +<images> + <image> + <name>image0</name> + <data format="XPM.GZ" length="582">789c6dcfcd4e843010c0f13b4fd1d01b31bb6cb325211b1f41e3d1c4789876a60bcbd7aeae07637c773b6d5985d870e0f7ef50605b88e7a707516cb3f72b5c5b2b6c036fa2c08f61f87c79bdffcaf2dd5ef0558b5d7e97e51b61c5e33412df4b7f2fcbb09896a94ab557817063cd744cad74a915734aac35308740d018d9332d5ab0c8ec1229f2c2448d156a661b489ee1ab4e4cf2a08a790e24020abb0dd355442eec8e914e45526215790c749e8e89891069125de466b1fe14295705ccaa5863e2d05cc01894925b2a7e8217dd8a631eb169fd509af10fd1a9ebfbdf32008d9d0c07cd274f70ee162773ba2cdfee935c977ffe6b2edf87ec07796f81cd</data> + </image> + <image> + <name>image1</name> + <data format="XPM.GZ" length="627">789c7dcfc94ec3301006e07b9ec28a6f114a13cbb1a8108f00e28884387819676993340b07847877329ea8697a60ec83bfdf232f8784bdbfbdb0e4104db39e6bcb6ca54796b8afb6fdfef87cfe89e25cb2650ac1f2f8218a5366d96bdf01aef9b2e65928a4458a0c07b25c29890352e63293e19c53a0968f52230159e8c22981744495133552097554a1f982b4ce6aeb9013d215165c81ec894e109b4070ca85378f2b35f18c04050214b20d04d010762ba457003eecd6442f88f34a45f4817ea147762b35d1acf4c47457d784737d9f18ebee1363614bf852c6f812b6c460f90abb6e93ba694ed7c49fdbaeee2f76b83da71ba772e0db5d9ccf4b07dfdd5e858edd9b2948fff9d796fc3e457f660e8d47</data> + </image> +</images> +<connections> + <connection> + <sender>forward</sender> + <signal>clicked()</signal> + <receiver>DateBookDayHeaderBase</receiver> + <slot>goForward()</slot> + </connection> + <connection> + <sender>back</sender> + <signal>clicked()</signal> + <receiver>DateBookDayHeaderBase</receiver> + <slot>goBack()</slot> + </connection> + <connection> + <sender>grpDays</sender> + <signal>clicked(int)</signal> + <receiver>DateBookDayHeaderBase</receiver> + <slot>setDay( int )</slot> + </connection> + <slot access="public">goBack()</slot> + <slot access="public">goForward()</slot> + <slot access="public">setDate( int, int, int )</slot> + <slot access="public">setDay( int )</slot> +</connections> +</UI> diff --git a/core/pim/datebook/datebookdayheaderimpl.cpp b/core/pim/datebook/datebookdayheaderimpl.cpp new file mode 100644 index 0000000..fbcb3d2 --- a/dev/null +++ b/core/pim/datebook/datebookdayheaderimpl.cpp @@ -0,0 +1,181 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ +#include "datebookdayheaderimpl.h" + +#include <qpe/datebookmonth.h> +#include <qpe/timestring.h> + +#include <qbuttongroup.h> +#include <qpopupmenu.h> +#include <qstringlist.h> +#include <qtimer.h> +#include <qtoolbutton.h> + +/* + * Constructs a DateBookDayHeader which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +DateBookDayHeader::DateBookDayHeader( bool useMonday, + QWidget* parent, const char* name ) + : DateBookDayHeaderBase( parent, name ), + bUseMonday( useMonday ) +{ + connect(date,SIGNAL(pressed()),this,SLOT(pickDate())); + + setupNames(); + + setBackgroundMode( PaletteButton ); + grpDays->setBackgroundMode( PaletteButton ); +} + +/* + * Destroys the object and frees any allocated resources + */ +DateBookDayHeader::~DateBookDayHeader() +{ + // no need to delete child widgets, Qt does it all for us +} + +void DateBookDayHeader::setStartOfWeek( bool onMonday ) +{ + bUseMonday = onMonday; + setupNames(); + setDate( currDate.year(), currDate.month(), currDate.day() ); +} + +void DateBookDayHeader::setupNames() +{ + if ( bUseMonday ) { + cmdDay1->setText( DateBookDayHeaderBase::tr("Monday").left(1) ); + cmdDay2->setText( DateBookDayHeaderBase::tr("Tuesday").left(1) ); + cmdDay3->setText( DateBookDayHeaderBase::tr("Wednesday").left(1) ); + cmdDay4->setText( DateBookDayHeaderBase::tr("Thursday").left(1) ); + cmdDay5->setText( DateBookDayHeaderBase::tr("Friday").left(1) ); + cmdDay6->setText( DateBookDayHeaderBase::tr("Saturday").left(1) ); + cmdDay7->setText( DateBookDayHeaderBase::tr("Sunday").left(1) ); + } else { + cmdDay1->setText( DateBookDayHeaderBase::tr("Sunday").left(1) ); + cmdDay2->setText( DateBookDayHeaderBase::tr("Monday").left(1) ); + cmdDay3->setText( DateBookDayHeaderBase::tr("Tuesday").left(1) ); + cmdDay4->setText( DateBookDayHeaderBase::tr("Wednesday").left(1) ); + cmdDay5->setText( DateBookDayHeaderBase::tr("Thursday").left(1) ); + cmdDay6->setText( DateBookDayHeaderBase::tr("Friday").left(1) ); + cmdDay7->setText( DateBookDayHeaderBase::tr("Saturday").left(1) ); + } +} + + +void DateBookDayHeader::pickDate() +{ + static QPopupMenu *m1 = 0; + static DateBookMonth *picker = 0; + if ( !m1 ) { + m1 = new QPopupMenu( this ); + picker = new DateBookMonth( m1, 0, TRUE ); + m1->insertItem( picker ); + connect( picker, SIGNAL( dateClicked( int, int, int ) ), + this, SLOT( setDate( int, int, int ) ) ); + connect( m1, SIGNAL( aboutToHide() ), + this, SLOT( gotHide() ) ); + } + picker->setDate( currDate.year(), currDate.month(), currDate.day() ); + m1->popup(mapToGlobal(date->pos()+QPoint(0,date->height()))); + picker->setFocus(); +} + +void DateBookDayHeader::gotHide() +{ + // we have to redo the button... + date->setDown( false ); +} + +/* + * public slot + */ +void DateBookDayHeader::goBack() +{ + currDate = currDate.addDays( -1 ); + setDate( currDate.year(), currDate.month(), currDate.day() ); +} +/* + * public slot + */ +void DateBookDayHeader::goForward() +{ + currDate = currDate.addDays( 1 ); + setDate( currDate.year(), currDate.month(), currDate.day() ); +} + + +/* + * public slot + */ +void DateBookDayHeader::setDate( int y, int m, int d ) +{ + currDate.setYMD( y, m, d ); + date->setText( TimeString::shortDate( currDate ) ); + + int iDayOfWeek = currDate.dayOfWeek(); + // cleverly adjust the day depending on how we start the week + if ( bUseMonday ) + iDayOfWeek--; + else { + if ( iDayOfWeek == 7 ) // Sunday + iDayOfWeek = 0; + } + grpDays->setButton( iDayOfWeek ); + emit dateChanged( y, m, d ); +} + +/* + * public slot + */ +void DateBookDayHeader::setDay( int day ) +{ + int realDay; + int dayOfWeek = currDate.dayOfWeek(); + + // a little adjustment is needed... + if ( bUseMonday ) + realDay = day + 1 ; + else if ( !bUseMonday && day == 0 ) // sunday + realDay = 7; + else + realDay = day; + // special cases first... + if ( realDay == 7 && !bUseMonday ) { + while ( currDate.dayOfWeek() != realDay ) + currDate = currDate.addDays( -1 ); + } else if ( !bUseMonday && dayOfWeek == 7 && dayOfWeek > realDay ) { + while ( currDate.dayOfWeek() != realDay ) + currDate = currDate.addDays( 1 ); + } else if ( dayOfWeek < realDay ) { + while ( currDate.dayOfWeek() < realDay ) + currDate = currDate.addDays( 1 ); + } else if ( dayOfWeek > realDay ) { + while ( currDate.dayOfWeek() > realDay ) + currDate = currDate.addDays( -1 ); + } + // update the date... + setDate( currDate.year(), currDate.month(), currDate.day() ); +} diff --git a/core/pim/datebook/datebookdayheaderimpl.h b/core/pim/datebook/datebookdayheaderimpl.h new file mode 100644 index 0000000..43f3a93 --- a/dev/null +++ b/core/pim/datebook/datebookdayheaderimpl.h @@ -0,0 +1,57 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ +#ifndef DATEBOOKDAYHEADER_H +#define DATEBOOKDAYHEADER_H +#include "datebookdayheader.h" + +#include <qdatetime.h> + +class DateBookDayHeader : public DateBookDayHeaderBase +{ + Q_OBJECT + +public: + DateBookDayHeader( bool bUseMonday, QWidget* parent = 0, + const char* name = 0 ); + ~DateBookDayHeader(); + void setStartOfWeek( bool onMonday ); + +public slots: + void goBack(); + void goForward(); + void setDate( int, int, int ); + void setDay( int ); + void gotHide(); + +signals: + void dateChanged( int y, int m, int d ); + +private slots: + void pickDate(); + + +private: + QDate currDate; + bool bUseMonday; + void setupNames(); + +}; + +#endif // DATEBOOKDAYHEADER_H diff --git a/core/pim/datebook/datebooksettings.cpp b/core/pim/datebook/datebooksettings.cpp new file mode 100644 index 0000000..c5d8ac1 --- a/dev/null +++ b/core/pim/datebook/datebooksettings.cpp @@ -0,0 +1,135 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#include "datebooksettings.h" + +#include <qpe/qpeapplication.h> + +#include <qspinbox.h> +#include <qcheckbox.h> +#include <qcombobox.h> + +DateBookSettings::DateBookSettings( bool whichClock, QWidget *parent, + const char *name, bool modal, WFlags fl ) + : DateBookSettingsBase( parent, name, modal, fl ), + ampm( whichClock ) +{ + init(); + QObject::connect( qApp, SIGNAL( clockChanged( bool ) ), + this, SLOT( slotChangeClock( bool ) ) ); +} + +DateBookSettings::~DateBookSettings() +{ +} + +void DateBookSettings::setStartTime( int newStartViewTime ) +{ + if ( ampm ) { + if ( newStartViewTime >= 12 ) { + newStartViewTime %= 12; + if ( newStartViewTime == 0 ) + newStartViewTime = 12; + spinStart->setSuffix( tr(":00 PM") ); + } + else if ( newStartViewTime == 0 ) { + newStartViewTime = 12; + spinStart->setSuffix( tr(":00 AM") ); + } + oldtime = newStartViewTime; + } + spinStart->setValue( newStartViewTime ); +} + +int DateBookSettings::startTime() const +{ + int returnMe = spinStart->value(); + if ( ampm ) { + if ( returnMe != 12 && spinStart->suffix().contains(tr("PM"), FALSE) ) + returnMe += 12; + else if (returnMe == 12 && spinStart->suffix().contains(tr("AM"), TRUE)) + returnMe = 0; + } + return returnMe; +} + + +void DateBookSettings::setAlarmPreset( bool bAlarm, int presetTime ) +{ + chkAlarmPreset->setChecked( bAlarm ); + if ( presetTime >=5 ) + spinPreset->setValue( presetTime ); +} + +bool DateBookSettings::alarmPreset() const +{ + return chkAlarmPreset->isChecked(); +} + +int DateBookSettings::presetTime() const +{ + return spinPreset->value(); +} + + +void DateBookSettings::slot12Hour( int i ) +{ + if ( ampm ) { + if ( spinStart->suffix().contains( tr("AM"), FALSE ) ) { + if ( oldtime == 12 && i == 11 || oldtime == 11 && i == 12 ) + spinStart->setSuffix( tr(":00 PM") ); + } else { + if ( oldtime == 12 && i == 11 || oldtime == 11 && i == 12 ) + spinStart->setSuffix( tr(":00 AM") ); + } + oldtime = i; + } +} + +void DateBookSettings::init() +{ + if ( ampm ) { + spinStart->setMinValue( 1 ); + spinStart->setMaxValue( 12 ); + spinStart->setValue( 12 ); + spinStart->setSuffix( tr(":00 AM") ); + oldtime = 12; + } else { + spinStart->setMinValue( 0 ); + spinStart->setMaxValue( 23 ); + spinStart->setSuffix( tr(":00") ); + } +} + +void DateBookSettings::slotChangeClock( bool whichClock ) +{ + int saveMe; + saveMe = spinStart->value(); + if ( ampm && spinStart->suffix().contains( tr("AM"), FALSE ) ) { + if ( saveMe == 12 ) + saveMe = 0; + } else if ( ampm && spinStart->suffix().contains( tr("PM"), FALSE ) ) { + if ( saveMe != 12 ) + saveMe += 12; + } + ampm = whichClock; + init(); + setStartTime( saveMe ); +} diff --git a/core/pim/datebook/datebooksettings.h b/core/pim/datebook/datebooksettings.h new file mode 100644 index 0000000..ee9f39c --- a/dev/null +++ b/core/pim/datebook/datebooksettings.h @@ -0,0 +1,48 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#ifndef DATEBOOKSETTINGS_H +#define DATEBOOKSETTINGS_H +#include "datebooksettingsbase.h" + +class DateBookSettings : public DateBookSettingsBase +{ +public: + DateBookSettings( bool whichClock, QWidget *parent = 0, + const char *name = 0, bool modal = TRUE, WFlags = 0 ); + ~DateBookSettings(); + void setStartTime( int newStartViewTime ); + int startTime() const; + void setAlarmPreset( bool bAlarm, int presetTime ); + bool alarmPreset() const; + int presetTime() const; + void setAlarmType( int alarmType ); + int alarmType() const; + +private slots: + void slot12Hour( int ); + void slotChangeClock( bool ); + +private: + void init(); + bool ampm; + int oldtime; +}; +#endif diff --git a/core/pim/datebook/datebooksettingsbase.ui b/core/pim/datebook/datebooksettingsbase.ui new file mode 100644 index 0000000..0f40773 --- a/dev/null +++ b/core/pim/datebook/datebooksettingsbase.ui @@ -0,0 +1,232 @@ +<!DOCTYPE UI><UI> +<class>DateBookSettingsBase</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>DateBookSettingsBase</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>232</width> + <height>290</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>Preferences</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>QGroupBox</class> + <property stdset="1"> + <name>name</name> + <cstring>fraStart</cstring> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>Box</enum> + </property> + <property stdset="1"> + <name>frameShadow</name> + <enum>Sunken</enum> + </property> + <property stdset="1"> + <name>title</name> + <string>Start viewing events</string> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>11</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout1</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>lblStartTime</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Start Time:</string> + </property> + </widget> + <widget> + <class>QSpinBox</class> + <property stdset="1"> + <name>name</name> + <cstring>spinStart</cstring> + </property> + <property stdset="1"> + <name>suffix</name> + <string>:00</string> + </property> + <property stdset="1"> + <name>wrapping</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>maxValue</name> + <number>23</number> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget> + <class>QGroupBox</class> + <property stdset="1"> + <name>name</name> + <cstring>fraAlarm</cstring> + </property> + <property stdset="1"> + <name>title</name> + <string>Alarm Settings</string> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>11</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout6</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>QCheckBox</class> + <property stdset="1"> + <name>name</name> + <cstring>chkAlarmPreset</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Alarm Preset</string> + </property> + </widget> + <widget> + <class>QSpinBox</class> + <property stdset="1"> + <name>name</name> + <cstring>spinPreset</cstring> + </property> + <property stdset="1"> + <name>enabled</name> + <bool>false</bool> + </property> + <property stdset="1"> + <name>suffix</name> + <string> minutes</string> + </property> + <property stdset="1"> + <name>maxValue</name> + <number>180</number> + </property> + <property stdset="1"> + <name>minValue</name> + <number>0</number> + </property> + <property stdset="1"> + <name>lineStep</name> + <number>5</number> + </property> + <property stdset="1"> + <name>value</name> + <number>5</number> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>chkAlarmPreset</sender> + <signal>toggled(bool)</signal> + <receiver>spinPreset</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>spinStart</sender> + <signal>valueChanged(int)</signal> + <receiver>DateBookSettingsBase</receiver> + <slot>slot12Hour( int )</slot> + </connection> + <slot access="public">slotChangeClock( bool )</slot> + <slot access="public">slot12Hour( int )</slot> +</connections> +</UI> diff --git a/core/pim/datebook/datebookweek.cpp b/core/pim/datebook/datebookweek.cpp new file mode 100644 index 0000000..e9fcc39 --- a/dev/null +++ b/core/pim/datebook/datebookweek.cpp @@ -0,0 +1,687 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ +#include "datebookweek.h" +#include "datebookweekheaderimpl.h" + +#include <qpe/calendar.h> +#include <qpe/datebookdb.h> +#include <qpe/event.h> +#include <qpe/qpeapplication.h> +#include <qpe/timestring.h> + +#include <qdatetime.h> +#include <qheader.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qpopupmenu.h> +#include <qtimer.h> +#include <qspinbox.h> +#include <qstyle.h> + +//----------------------------------------------------------------- + + +DateBookWeekItem::DateBookWeekItem( const EffectiveEvent e ) + : ev( e ) +{ + // with the current implementation change the color for all day events + if ( ev.event().type() == Event::AllDay && !ev.event().hasAlarm() ) { + c = Qt::green; + } else { + c = ev.event().hasAlarm() ? Qt::red : Qt::blue; + } +} + +void DateBookWeekItem::setGeometry( int x, int y, int w, int h ) +{ + r.setRect( x, y, w, h ); +} + + +//------------------=--------------------------------------------- + +DateBookWeekView::DateBookWeekView( bool ap, bool startOnMonday, + QWidget *parent, const char *name ) + : QScrollView( parent, name ), ampm( ap ), bOnMonday( startOnMonday ), + showingEvent( false ) +{ + items.setAutoDelete( true ); + + viewport()->setBackgroundMode( PaletteBase ); + + header = new QHeader( this ); + header->addLabel( "" ); + + header->setMovingEnabled( false ); + header->setResizeEnabled( false ); + header->setClickEnabled( false, 0 ); + initNames(); + + + connect( header, SIGNAL(clicked(int)), this, SIGNAL(showDay(int)) ); + + QObject::connect(qApp, SIGNAL(clockChanged(bool)), + this, SLOT(slotChangeClock(bool))); + + QFontMetrics fm( font() ); + rowHeight = fm.height()+2; + + resizeContents( width(), 24*rowHeight ); +} + +void DateBookWeekView::initNames() +{ + static bool bFirst = true; + if ( bFirst ) { + if ( bOnMonday ) { + header->addLabel( tr("M", "Monday" ) ); + header->addLabel( tr("T", "Tuesday") ); + header->addLabel( tr("W", "Wednesday" ) ); + header->addLabel( tr("T", "Thursday" ) ); + header->addLabel( tr("F", "Friday" ) ); + header->addLabel( tr("S", "Saturday" ) ); + header->addLabel( tr("S", "Sunday" ) ); + } else { + header->addLabel( tr("S", "Sunday" ) ); + header->addLabel( tr("M", "Monday") ); + header->addLabel( tr("T", "Tuesday") ); + header->addLabel( tr("W", "Wednesday" ) ); + header->addLabel( tr("T", "Thursday" ) ); + header->addLabel( tr("F", "Friday" ) ); + header->addLabel( tr("S", "Saturday" ) ); + } + bFirst = false; + } else { + // we are change things... + if ( bOnMonday ) { + header->setLabel( 1, tr("M", "Monday") ); + header->setLabel( 2, tr("T", "Tuesday") ); + header->setLabel( 3, tr("W", "Wednesday" ) ); + header->setLabel( 4, tr("T", "Thursday" ) ); + header->setLabel( 5, tr("F", "Friday" ) ); + header->setLabel( 6, tr("S", "Saturday" ) ); + header->setLabel( 7, tr("S", "Sunday" ) ); + } else { + header->setLabel( 1, tr("S", "Sunday" ) ); + header->setLabel( 2, tr("M", "Monday") ); + header->setLabel( 3, tr("T", "Tuesday") ); + header->setLabel( 4, tr("W", "Wednesday" ) ); + header->setLabel( 5, tr("T", "Thursday" ) ); + header->setLabel( 6, tr("F", "Friday" ) ); + header->setLabel( 7, tr("S", "Saturday" ) ); + } + } +} + + + +void DateBookWeekView::showEvents( QValueList<EffectiveEvent> &ev ) +{ + items.clear(); + QValueListIterator<EffectiveEvent> it; + for ( it = ev.begin(); it != ev.end(); ++it ) { + DateBookWeekItem *i = new DateBookWeekItem( *it ); + positionItem( i ); + items.append( i ); + } + viewport()->update(); +} + +void DateBookWeekView::moveToHour( int h ) +{ + int offset = h*rowHeight; + setContentsPos( 0, offset ); +} + +void DateBookWeekView::keyPressEvent( QKeyEvent *e ) +{ + e->ignore(); +} + +void DateBookWeekView::slotChangeClock( bool c ) +{ + ampm = c; + viewport()->update(); +} + +static inline int db_round30min( int m ) +{ + if ( m < 15 ) + m = 0; + else if ( m < 45 ) + m = 1; + else + m = 2; + + return m; +} + +void DateBookWeekView::alterDay( int day ) +{ + if ( !bOnMonday ) { + day--; + } + emit showDay( day ); +} + +void DateBookWeekView::positionItem( DateBookWeekItem *i ) +{ + const int Width = 8; + const EffectiveEvent ev = i->event(); + + // 30 minute intervals + int y = ev.start().hour() * 2; + y += db_round30min( ev.start().minute() ); + if ( y > 47 ) + y = 47; + y = y * rowHeight / 2; + + int h; + if ( ev.event().type() == Event::AllDay ) { + h = 48; + y = 0; + } else { + h = ( ev.end().hour() - ev.start().hour() ) * 2; + h += db_round30min( ev.end().minute() - ev.start().minute() ); + if ( h < 1 ) h = 1; + } + h = h * rowHeight / 2; + + int dow = ev.date().dayOfWeek(); + if ( !bOnMonday ) { + if ( dow == 7 ) + dow = 1; + else + dow++; + } + int x = header->sectionPos( dow ) - 1; + int xlim = header->sectionPos( dow ) + header->sectionSize( dow ); + DateBookWeekItem *isect = 0; + do { + i->setGeometry( x, y, Width, h ); + isect = intersects( i ); + x += Width - 1; + } while ( isect && x < xlim ); +} + +DateBookWeekItem *DateBookWeekView::intersects( const DateBookWeekItem *item ) +{ + QRect geom = item->geometry(); + + // We allow the edges to overlap + geom.moveBy( 1, 1 ); + geom.setSize( geom.size()-QSize(2,2) ); + + QListIterator<DateBookWeekItem> it(items); + for ( ; it.current(); ++it ) { + DateBookWeekItem *i = it.current(); + if ( i != item ) { + if ( i->geometry().intersects( geom ) ) { + return i; + } + } + } + + return 0; +} + +void DateBookWeekView::contentsMousePressEvent( QMouseEvent *e ) +{ + QListIterator<DateBookWeekItem> it(items); + for ( ; it.current(); ++it ) { + DateBookWeekItem *i = it.current(); + if ( i->geometry().contains( e->pos() ) ) { + showingEvent = true; + emit signalShowEvent( i->event() ); + break; + } + } +} + +void DateBookWeekView::contentsMouseReleaseEvent( QMouseEvent *e ) +{ + if ( showingEvent ) { + showingEvent = false; + emit signalHideEvent(); + } else { + int d = header->sectionAt( e->pos().x() ); + if ( d > 0 ) { +// if ( !bOnMonday ) +// d--; + emit showDay( d ); + } + } +} + +void DateBookWeekView::drawContents( QPainter *p, int cx, int cy, int cw, int ch ) +{ + QRect ur( cx, cy, cw, ch ); + p->setPen( lightGray ); + for ( int i = 1; i <= 7; i++ ) + p->drawLine( header->sectionPos(i)-2, cy, header->sectionPos(i)-2, cy+ch ); + + p->setPen( black ); + for ( int t = 0; t < 24; t++ ) { + int y = t*rowHeight; + if ( QRect( 1, y, 20, rowHeight ).intersects( ur ) ) { + QString s; + if ( ampm ) { + if ( t == 0 ) + s = QString::number( 12 ); + else if ( t == 12 ) + s = QString::number(12) + tr( "p" ); + else if ( t > 12 ) { + if ( t - 12 < 10 ) + s = " "; + else + s = ""; + s += QString::number( t - 12 ) + tr("p"); + } else { + if ( 12 - t < 3 ) + s = ""; + else + s = " "; + s += QString::number( t ); + } + } else { + s = QString::number( t ); + if ( s.length() == 1 ) + s.prepend( "0" ); + } + p->drawText( 1, y+p->fontMetrics().ascent()+1, s ); + } + } + + QListIterator<DateBookWeekItem> it(items); + for ( ; it.current(); ++it ) { + DateBookWeekItem *i = it.current(); + if ( i->geometry().intersects( ur ) ) { + p->setBrush( i->color() ); + p->drawRect( i->geometry() ); + } + } +} + +void DateBookWeekView::resizeEvent( QResizeEvent *e ) +{ + const int hourWidth = 20; + QScrollView::resizeEvent( e ); + int avail = width()-qApp->style().scrollBarExtent().width()-1; + header->setGeometry( 0, 0, avail, header->sizeHint().height() ); + setMargins( 0, header->height(), 0, 0 ); + header->resizeSection( 0, hourWidth ); + int sw = (avail - hourWidth) / 7; + for ( int i = 1; i < 7; i++ ) + header->resizeSection( i, sw ); + header->resizeSection( 7, avail - hourWidth - sw*6 ); +} + +void DateBookWeekView::setStartOfWeek( bool bStartOnMonday ) +{ + bOnMonday = bStartOnMonday; + initNames(); +} + +//------------------------------------------------------------------- + +DateBookWeek::DateBookWeek( bool ap, bool startOnMonday, DateBookDB *newDB, + QWidget *parent, const char *name ) + : QWidget( parent, name ), + db( newDB ), + startTime( 0 ), + ampm( ap ), + bStartOnMonday( startOnMonday ) +{ + setFocusPolicy(StrongFocus); + QVBoxLayout *vb = new QVBoxLayout( this ); + header = new DateBookWeekHeader( bStartOnMonday, this ); + view = new DateBookWeekView( ampm, startOnMonday, this ); + vb->addWidget( header ); + vb->addWidget( view ); + + lblDesc = new QLabel( this, "event label" ); + lblDesc->setFrameStyle( QFrame::Plain | QFrame::Box ); + lblDesc->setBackgroundColor( yellow ); + lblDesc->hide(); + + tHide = new QTimer( this ); + + connect( view, SIGNAL( showDay( int ) ), + this, SLOT( showDay( int ) ) ); + connect( view, SIGNAL(signalShowEvent(const EffectiveEvent&)), + this, SLOT(slotShowEvent(const EffectiveEvent&)) ); + connect( view, SIGNAL(signalHideEvent()), + this, SLOT(slotHideEvent()) ); + connect( header, SIGNAL( dateChanged( int, int ) ), + this, SLOT( dateChanged( int, int ) ) ); + connect( tHide, SIGNAL( timeout() ), + lblDesc, SLOT( hide() ) ); + connect( header->spinYear, SIGNAL(valueChanged(int)), + this, SLOT(slotYearChanged(int)) ); + connect( qApp, SIGNAL(weekChanged(bool)), + this, SLOT(slotWeekChanged(bool)) ); + connect( qApp, SIGNAL(clockChanged(bool)), + this, SLOT(slotClockChanged(bool))); + setDate(QDate::currentDate()); + +} + +void DateBookWeek::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Key_Up: + view->scrollBy(0, -20); + break; + case Key_Down: + view->scrollBy(0, 20); + break; + case Key_Left: + setDate(date().addDays(-7)); + break; + case Key_Right: + setDate(date().addDays(7)); + break; + default: + e->ignore(); + } +} + +void DateBookWeek::showDay( int day ) +{ + QDate d; + d = dateFromWeek( _week, year, bStartOnMonday ); + day--; + d = d.addDays( day ); + emit showDate( d.year(), d.month(), d.day() ); +} + +void DateBookWeek::setDate( int y, int m, int d ) +{ + QDate date; + date.setYMD( y, m, d ); + setDate(QDate(y, m, d)); +} + +void DateBookWeek::setDate(QDate date) +{ + dow = date.dayOfWeek(); + int w, y; + calcWeek( date, w, y, bStartOnMonday ); + header->setDate( y, w ); +} + +void DateBookWeek::dateChanged( int y, int w ) +{ + year = y; + _week = w; + getEvents(); +} + +QDate DateBookWeek::date() const +{ + QDate d; + d = dateFromWeek( _week - 1, year, bStartOnMonday ); + if ( bStartOnMonday ) + d = d.addDays( 7 + dow - 1 ); + else { + if ( dow == 7 ) + d = d.addDays( dow ); + else + d = d.addDays( 7 + dow ); + } + return d; +} + +void DateBookWeek::getEvents() +{ + QDate startWeek = weekDate(); + + QDate endWeek = startWeek.addDays( 6 ); + QValueList<EffectiveEvent> eventList = db->getEffectiveEvents(startWeek, + endWeek); + view->showEvents( eventList ); + view->moveToHour( startTime ); +} + +void DateBookWeek::slotShowEvent( const EffectiveEvent &ev ) +{ + if ( tHide->isActive() ) + tHide->stop(); + + // why would someone use "<"? Oh well, fix it up... + // I wonder what other things may be messed up... + QString strDesc = ev.description(); + int where = strDesc.find( "<" ); + while ( where != -1 ) { + strDesc.remove( where, 1 ); + strDesc.insert( where, "<" ); + where = strDesc.find( "<", where ); + } + + QString strCat; + // ### FIX later... +// QString strCat = ev.category(); +// where = strCat.find( "<" ); +// while ( where != -1 ) { +// strCat.remove( where, 1 ); +// strCat.insert( where, "<" ); +// where = strCat.find( "<", where ); +// } + + QString strNote = ev.notes(); + where = strNote.find( "<" ); + while ( where != -1 ) { + strNote.remove( where, 1 ); + strNote.insert( where, "<" ); + where = strNote.find( "<", where ); + } + + QString str = "<b>" + strDesc + "</b><br>" + "<i>" + + strCat + "</i>" + + "<br>" + TimeString::longDateString( ev.date() ) + + "<br><b>" + QObject::tr("Start") + "</b>: "; + + if ( ev.startDate() != ev.date() ) { + // multi-day event. Show start date + str += TimeString::longDateString( ev.startDate() ); + } else { + // Show start time. + str += TimeString::timeString(ev.start(), ampm, FALSE ); + } + + str += "<br><b>" + QObject::tr("End") + "</b>: "; + if ( ev.endDate() != ev.date() ) { + // multi-day event. Show end date + str += TimeString::longDateString( ev.endDate() ); + } else { + // Show end time. + str += TimeString::timeString( ev.end(), ampm, FALSE ); + } + str += "<br><br>" + strNote; + + lblDesc->setText( str ); + lblDesc->resize( lblDesc->sizeHint() ); + // move the label so it is "centerd" horizontally... + lblDesc->move( QMAX(0,(width() - lblDesc->width()) / 2), 0 ); + lblDesc->show(); +} + +void DateBookWeek::slotHideEvent() +{ + tHide->start( 2000, true ); +} + +void DateBookWeek::setStartViewTime( int startHere ) +{ + startTime = startHere; + view->moveToHour( startTime ); +} + +int DateBookWeek::startViewTime() const +{ + return startTime; +} + +void DateBookWeek::redraw() +{ + getEvents(); +} + +void DateBookWeek::slotYearChanged( int y ) +{ + int totWeek; + QDate d( y, 12, 31 ); + int throwAway; + calcWeek( d, totWeek, throwAway, bStartOnMonday ); + while ( totWeek == 1 ) { + d = d.addDays( -1 ); + calcWeek( d, totWeek, throwAway, bStartOnMonday ); + } + if ( totWeek != totalWeeks() ) + setTotalWeeks( totWeek ); +} + + +void DateBookWeek::setTotalWeeks( int numWeeks ) +{ + header->spinWeek->setMaxValue( numWeeks ); +} + +int DateBookWeek::totalWeeks() const +{ + return header->spinWeek->maxValue(); +} + +void DateBookWeek::slotWeekChanged( bool onMonday ) +{ + bStartOnMonday = onMonday; + view->setStartOfWeek( bStartOnMonday ); + header->setStartOfWeek( bStartOnMonday ); + redraw(); +} + +void DateBookWeek::slotClockChanged( bool ap ) +{ + ampm = ap; +} + +// return the date at the beginning of the week... +QDate DateBookWeek::weekDate() const +{ + return dateFromWeek( _week, year, bStartOnMonday ); +} + +// this used to only be needed by datebook.cpp, but now we need it inside +// week view since +// we need to be able to figure out our total number of weeks on the fly... +// this is probably the best place to put it.. + +// For Weeks that start on Monday... (EASY!) +// At the moment we will use ISO 8601 method for computing +// the week. Granted, other countries use other methods, +// bet we aren't doing any Locale stuff at the moment. So, +// this should pass. This Algorithim is public domain and +// available at: +// http://personal.ecu.edu/mccartyr/ISOwdALG.txt +// the week number is return, and the year number is returned in year +// for Instance 2001/12/31 is actually the first week in 2002. +// There is a more mathematical definition, but I will implement it when +// we are pass our deadline. + +// For Weeks that start on Sunday... (ahh... home rolled) +// okay, if Jan 1 is on Friday or Saturday, +// it will go to the pervious +// week... + +bool calcWeek( const QDate &d, int &week, int &year, + bool startOnMonday = false ) +{ + int weekNumber; + int yearNumber; + + // remove a pesky warning, (Optimizations on g++) + weekNumber = -1; + int jan1WeekDay = QDate(d.year(), 1, 1).dayOfWeek(); + int dayOfWeek = d.dayOfWeek(); + + if ( !d.isValid() ) + return false; + + if ( startOnMonday ) { + // find the Jan1Weekday; + if ( d.dayOfYear() <= ( 8 - jan1WeekDay) && jan1WeekDay > 4 ) { + yearNumber = d.year() - 1; + if ( jan1WeekDay == 5 || ( jan1WeekDay == 6 && QDate::leapYear(yearNumber) ) ) + weekNumber = 53; + else + weekNumber = 52; + } else + yearNumber = d.year(); + if ( yearNumber == d.year() ) { + int totalDays = 365; + if ( QDate::leapYear(yearNumber) ) + totalDays++; + if ( ((totalDays - d.dayOfYear()) < (4 - dayOfWeek) ) + || (jan1WeekDay == 7) && (totalDays - d.dayOfYear()) < 3) { + yearNumber++; + weekNumber = 1; + } + } + if ( yearNumber == d.year() ) { + int j = d.dayOfYear() + (7 - dayOfWeek) + ( jan1WeekDay - 1 ); + weekNumber = j / 7; + if ( jan1WeekDay > 4 ) + weekNumber--; + } + } else { + // it's better to keep these cases separate... + if ( d.dayOfYear() <= (7 - jan1WeekDay) && jan1WeekDay > 4 + && jan1WeekDay != 7 ) { + yearNumber = d.year() - 1; + if ( jan1WeekDay == 6 + || (jan1WeekDay == 7 && QDate::leapYear(yearNumber) ) ) { + weekNumber = 53; + }else + weekNumber = 52; + } else + yearNumber = d.year(); + if ( yearNumber == d.year() ) { + int totalDays = 365; + if ( QDate::leapYear( yearNumber ) ) + totalDays++; + if ( ((totalDays - d.dayOfYear()) < (4 - dayOfWeek % 7)) ) { + yearNumber++; + weekNumber = 1; + } + } + if ( yearNumber == d.year() ) { + int j = d.dayOfYear() + (7 - dayOfWeek % 7) + ( jan1WeekDay - 1 ); + weekNumber = j / 7; + if ( jan1WeekDay > 4 ) { + weekNumber--; + } + } + } + year = yearNumber; + week = weekNumber; + return true; +} + diff --git a/core/pim/datebook/datebookweek.h b/core/pim/datebook/datebookweek.h new file mode 100644 index 0000000..6e675f1 --- a/dev/null +++ b/core/pim/datebook/datebookweek.h @@ -0,0 +1,152 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ +#ifndef DATEBOOKWEEK +#define DATEBOOKWEEK + +#include <qpe/event.h> + +#include <qlist.h> +#include <qscrollview.h> +#include <qstring.h> +#include <qvaluelist.h> + +class DateBookDB; +class DateBookWeekHeader; +class QDate; +class QLabel; +class QResizeEvent; +class QSpinBox; +class QTimer; +class QHeader; + +class DateBookWeekItem +{ +public: + DateBookWeekItem( const EffectiveEvent e ); + + void setGeometry( int x, int y, int w, int h ); + QRect geometry() const { return r; } + + const QColor &color() const { return c; } + const EffectiveEvent event() const { return ev; } + +private: + const EffectiveEvent ev; + QRect r; + QColor c; +}; + +class DateBookWeekView : public QScrollView +{ + Q_OBJECT +public: + DateBookWeekView( bool ampm, bool weekOnMonday, QWidget *parent = 0, + const char *name = 0 ); + + bool whichClock() const; + void showEvents( QValueList<EffectiveEvent> &ev ); + void moveToHour( int h ); + void setStartOfWeek( bool bOnMonday ); + +signals: + void showDay( int d ); + void signalShowEvent( const EffectiveEvent & ); + void signalHideEvent(); + +protected slots: + void keyPressEvent(QKeyEvent *); + +private slots: + void slotChangeClock( bool ); + void alterDay( int ); + +private: + void positionItem( DateBookWeekItem *i ); + DateBookWeekItem *intersects( const DateBookWeekItem * ); + void drawContents( QPainter *p, int cx, int cy, int cw, int ch ); + void contentsMousePressEvent( QMouseEvent * ); + void contentsMouseReleaseEvent( QMouseEvent * ); + void resizeEvent( QResizeEvent * ); + void initNames(); + +private: + bool ampm; + bool bOnMonday; + QHeader *header; + QList<DateBookWeekItem> items; + int rowHeight; + bool showingEvent; +}; + +class DateBookWeek : public QWidget +{ + Q_OBJECT + +public: + DateBookWeek( bool ampm, bool weekOnMonday, DateBookDB *newDB, + QWidget *parent = 0, const char *name = 0 ); + void setDate( int y, int m, int d ); + void setDate( QDate d ); + QDate date() const; + DateBookWeekView *weekView() const { return view; } + void setStartViewTime( int startHere ); + int startViewTime() const; + int week() const { return _week; }; + void setTotalWeeks( int totalWeeks ); + int totalWeeks() const; + QDate weekDate() const; + +public slots: + void redraw(); + void slotWeekChanged( bool bStartOnMonday ); + void slotClockChanged( bool a ); + +signals: + void showDate( int y, int m, int d ); + +protected slots: + void keyPressEvent(QKeyEvent *); + +private slots: + void showDay( int day ); + void dateChanged( int y, int w ); + void slotShowEvent( const EffectiveEvent & ); + void slotHideEvent(); + void slotYearChanged( int ); + +private: + void getEvents(); + int year; + int _week; + int dow; + DateBookWeekHeader *header; + DateBookWeekView *view; + DateBookDB *db; + QLabel *lblDesc; + QTimer *tHide; + int startTime; + bool ampm; + bool bStartOnMonday; +}; + + +bool calcWeek( const QDate &d, int &week, int &year, + bool startOnMonday = false ); +#endif diff --git a/core/pim/datebook/datebookweekheader.ui b/core/pim/datebook/datebookweekheader.ui new file mode 100644 index 0000000..dd6a5b1 --- a/dev/null +++ b/core/pim/datebook/datebookweekheader.ui @@ -0,0 +1,167 @@ +<!DOCTYPE UI><UI> +<class>DateBookWeekHeaderBase</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. +** +*********************************************************************</comment> +<widget> + <class>QWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>DateBookWeekHeaderBase</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>281</width> + <height>30</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>Form1</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QSpinBox</class> + <property stdset="1"> + <name>name</name> + <cstring>spinYear</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>prefix</name> + <string>Y: </string> + </property> + <property stdset="1"> + <name>maxValue</name> + <number>2037</number> + </property> + <property stdset="1"> + <name>minValue</name> + <number>1970</number> + </property> + <property stdset="1"> + <name>value</name> + <number>2002</number> + </property> + </widget> + <widget> + <class>QSpinBox</class> + <property stdset="1"> + <name>name</name> + <cstring>spinWeek</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>prefix</name> + <string>W: </string> + </property> + <property stdset="1"> + <name>maxValue</name> + <number>52</number> + </property> + <property stdset="1"> + <name>minValue</name> + <number>1</number> + </property> + <property stdset="1"> + <name>value</name> + <number>1</number> + </property> + </widget> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>labelDate</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>1</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>font</name> + <font> + <bold>1</bold> + </font> + </property> + <property stdset="1"> + <name>text</name> + <string>00. Jan-00. Jan</string> + </property> + <property stdset="1"> + <name>alignment</name> + <set>AlignCenter</set> + </property> + <property> + <name>hAlign</name> + </property> + </widget> + </hbox> +</widget> +<connections> + <connection> + <sender>spinYear</sender> + <signal>valueChanged(int)</signal> + <receiver>DateBookWeekHeaderBase</receiver> + <slot>yearChanged( int )</slot> + </connection> + <connection> + <sender>spinWeek</sender> + <signal>valueChanged(int)</signal> + <receiver>DateBookWeekHeaderBase</receiver> + <slot>weekChanged( int )</slot> + </connection> + <slot access="public">yearChanged( int )</slot> + <slot access="public">nextWeek()</slot> + <slot access="public">prevWeek()</slot> + <slot access="public">weekChanged( int )</slot> +</connections> +</UI> diff --git a/core/pim/datebook/datebookweekheaderimpl.cpp b/core/pim/datebook/datebookweekheaderimpl.cpp new file mode 100644 index 0000000..e7c7208 --- a/dev/null +++ b/core/pim/datebook/datebookweekheaderimpl.cpp @@ -0,0 +1,126 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ +#include "datebookweekheaderimpl.h" +#include <qlabel.h> +#include <qspinbox.h> +#include <qdatetime.h> + +/* + * Constructs a DateBookWeekHeader which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + */ +DateBookWeekHeader::DateBookWeekHeader( bool startOnMonday, QWidget* parent, + const char* name, WFlags fl ) + : DateBookWeekHeaderBase( parent, name, fl ), + bStartOnMonday( startOnMonday ) +{ + setBackgroundMode( PaletteButton ); + labelDate->setBackgroundMode( PaletteButton ); +} + +/* + * Destroys the object and frees any allocated resources + */ +DateBookWeekHeader::~DateBookWeekHeader() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * public slot + */ +void DateBookWeekHeader::yearChanged( int y ) +{ + setDate( y, week ); +} +/* + * public slot + */ +void DateBookWeekHeader::nextWeek() +{ + if ( week < 52 ) + week++; + setDate( year, week ); +} +/* + * public slot + */ +void DateBookWeekHeader::prevWeek() +{ + if ( week > 1 ) + week--; + setDate( year, week ); +} +/* + * public slot + */ +void DateBookWeekHeader::weekChanged( int w ) +{ + setDate( year, w ); +} + +void DateBookWeekHeader::setDate( int y, int w ) +{ + year = y; + week = w; + spinYear->setValue( y ); + spinWeek->setValue( w ); + + QDate d = dateFromWeek( week, year, bStartOnMonday ); + + QString s = QString::number( d.day() ) + ". " + d.monthName( d.month() ) + + "-"; + d = d.addDays( 6 ); + s += QString::number( d.day() ) + ". " + d.monthName( d.month() ); + labelDate->setText( s ); + + emit dateChanged( y, w ); +} + +void DateBookWeekHeader::setStartOfWeek( bool onMonday ) +{ + bStartOnMonday = onMonday; + setDate( year, week ); +} + +// dateFromWeek +// compute the date from the week in the year + +QDate dateFromWeek( int week, int year, bool startOnMonday ) +{ + QDate d; + d.setYMD( year, 1, 1 ); + int dayOfWeek = d.dayOfWeek(); + if ( startOnMonday ) { + if ( dayOfWeek <= 4 ) { + d = d.addDays( ( week - 1 ) * 7 - dayOfWeek + 1 ); + } else { + d = d.addDays( (week) * 7 - dayOfWeek + 1 ); + } + } else { + if ( dayOfWeek <= 4 || dayOfWeek == 7) { + d = d.addDays( ( week - 1 ) * 7 - dayOfWeek % 7 ); + } else { + d = d.addDays( ( week ) * 7 - dayOfWeek % 7 ); + } + } + return d; +} + diff --git a/core/pim/datebook/datebookweekheaderimpl.h b/core/pim/datebook/datebookweekheaderimpl.h new file mode 100644 index 0000000..2abef46 --- a/dev/null +++ b/core/pim/datebook/datebookweekheaderimpl.h @@ -0,0 +1,62 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ +#ifndef DATEBOOKDAYHEADER_H +#define DATEBOOKDAYHEADER_H +#include <qdatetime.h> +#include "datebookweekheader.h" + + +class DateBookWeekHeader : public DateBookWeekHeaderBase +{ + Q_OBJECT + +public: + DateBookWeekHeader( bool startOnMonday, QWidget* parent = 0, + const char* name = 0, WFlags fl = 0 ); + ~DateBookWeekHeader(); + + void setDate( int y, int w ); + void setStartOfWeek( bool onMonday ); + +signals: + void dateChanged( int y, int w ); + +public slots: + void yearChanged( int ); + void nextWeek(); + void prevWeek(); + void weekChanged( int ); + +protected slots: + void keyPressEvent(QKeyEvent *e) + { + e->ignore(); + } + +private: + int year, + week; + bool bStartOnMonday; + +}; + +QDate dateFromWeek( int week, int year, bool startOnMonday ); + +#endif // DATEBOOKDAYHEADER_H diff --git a/core/pim/datebook/dateentry.ui b/core/pim/datebook/dateentry.ui new file mode 100644 index 0000000..0c363a4 --- a/dev/null +++ b/core/pim/datebook/dateentry.ui @@ -0,0 +1,1095 @@ +<!DOCTYPE UI><UI> +<class>DateEntryBase</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>QWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>DateEntryBase</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>242</width> + <height>339</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>New Event</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <grid> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>0</number> + </property> + <widget row="1" column="0" > + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel2</cstring> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>MShape</enum> + </property> + <property stdset="1"> + <name>frameShadow</name> + <enum>MShadow</enum> + </property> + <property stdset="1"> + <name>text</name> + <string>Location</string> + </property> + </widget> + <widget row="2" column="0" > + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel2_2</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Category</string> + </property> + <property> + <name>buddy</name> + <cstring>comboPriority</cstring> + </property> + </widget> + <widget row="0" column="1" rowspan="1" colspan="3" > + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string>(None)</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>Meeting</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>Lunch</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>Dinner</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>Travel</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>comboDescription</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>editable</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>currentItem</name> + <number>0</number> + </property> + <property stdset="1"> + <name>duplicatesEnabled</name> + <bool>false</bool> + </property> + </widget> + <widget row="0" column="0" > + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel1</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Description:</string> + </property> + </widget> + <widget row="1" column="1" rowspan="1" colspan="3" > + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string>(Unknown)</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>Office</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>Home</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>comboLocation</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>editable</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>currentItem</name> + <number>0</number> + </property> + <property stdset="1"> + <name>duplicatesEnabled</name> + <bool>false</bool> + </property> + </widget> + <widget row="2" column="1" rowspan="1" colspan="3" > + <class>CategorySelect</class> + <property stdset="1"> + <name>name</name> + <cstring>comboCategory</cstring> + </property> + </widget> + <widget row="3" column="0" > + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel3</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Start</string> + </property> + </widget> + <widget row="3" column="1" > + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>buttonStart</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Jan 02 00</string> + </property> + </widget> + <widget row="3" column="2" rowspan="1" colspan="2" > + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string>00:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>00:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>01:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>01:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>02:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>02:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>03:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>03:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>04:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>04:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>05:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>05:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>06:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>06:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>07:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>07:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>08:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>08:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>09:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>09:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>10:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>10:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>11:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>11:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>12:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>12:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>13:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>13:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>14:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>14:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>15:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>15:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>16:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>16:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>17:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>17:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>18:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>18:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>19:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>19:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>20:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>20:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>21:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>21:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>22:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>22:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>23:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>23:30</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>comboStart</cstring> + </property> + <property stdset="1"> + <name>editable</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>duplicatesEnabled</name> + <bool>false</bool> + </property> + </widget> + <widget row="4" column="1" > + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>buttonEnd</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Jan 02 00</string> + </property> + </widget> + <widget row="4" column="2" rowspan="1" colspan="2" > + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string>00:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>00:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>01:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>01:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>02:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>02:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>03:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>03:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>04:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>04:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>05:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>05:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>06:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>06:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>07:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>07:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>08:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>08:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>09:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>09:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>10:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>10:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>11:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>11:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>12:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>12:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>13:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>13:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>14:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>14:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>15:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>15:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>16:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>16:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>17:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>17:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>18:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>18:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>19:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>19:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>20:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>20:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>21:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>21:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>22:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>22:30</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>23:00</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>23:30</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>comboEnd</cstring> + </property> + <property stdset="1"> + <name>editable</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>duplicatesEnabled</name> + <bool>false</bool> + </property> + </widget> + <widget row="4" column="0" > + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel3_2</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>End</string> + </property> + </widget> + <widget row="5" column="0" > + <class>QCheckBox</class> + <property stdset="1"> + <name>name</name> + <cstring>checkAllDay</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>All day</string> + </property> + </widget> + <widget row="6" column="0" > + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel3_2_2</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Time zone:</string> + </property> + </widget> + <widget row="6" column="1" rowspan="1" colspan="3" > + <class>TimeZoneSelector</class> + <property stdset="1"> + <name>name</name> + <cstring>timezone</cstring> + </property> + </widget> + <widget row="7" column="0" > + <class>QCheckBox</class> + <property stdset="1"> + <name>name</name> + <cstring>checkAlarm</cstring> + </property> + <property stdset="1"> + <name>enabled</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>autoMask</name> + <bool>false</bool> + </property> + <property stdset="1"> + <name>text</name> + <string>&Alarm</string> + </property> + <property stdset="1"> + <name>checked</name> + <bool>false</bool> + </property> + </widget> + <widget row="7" column="1" rowspan="1" colspan="2" > + <class>QSpinBox</class> + <property stdset="1"> + <name>name</name> + <cstring>spinAlarm</cstring> + </property> + <property stdset="1"> + <name>enabled</name> + <bool>false</bool> + </property> + <property stdset="1"> + <name>suffix</name> + <string> minutes</string> + </property> + <property stdset="1"> + <name>maxValue</name> + <number>180</number> + </property> + <property stdset="1"> + <name>minValue</name> + <number>0</number> + </property> + <property stdset="1"> + <name>lineStep</name> + <number>5</number> + </property> + <property stdset="1"> + <name>value</name> + <number>5</number> + </property> + </widget> + <widget row="7" column="3" > + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string>Silent</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>Loud</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>comboSound</cstring> + </property> + <property stdset="1"> + <name>enabled</name> + <bool>false</bool> + </property> + </widget> + <widget row="8" column="0" > + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>lblRepeat</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Repeat</string> + </property> + </widget> + <widget row="8" column="1" rowspan="1" colspan="3" > + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdRepeat</cstring> + </property> + <property stdset="1"> + <name>focusPolicy</name> + <enum>TabFocus</enum> + </property> + <property stdset="1"> + <name>text</name> + <string>No Repeat...</string> + </property> + </widget> + <widget row="9" column="0" rowspan="1" colspan="4" > + <class>QMultiLineEdit</class> + <property stdset="1"> + <name>name</name> + <cstring>editNote</cstring> + </property> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>TimeZoneSelector</class> + <header location="global">qpe/tzselect.h</header> + <sizehint> + <width>21</width> + <height>10</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>7</hordata> + <verdata>1</verdata> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> + <customwidget> + <class>CategorySelect</class> + <header location="global">qpe/categoryselect.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>7</hordata> + <verdata>1</verdata> + </sizepolicy> + <pixmap>image1</pixmap> + </customwidget> +</customwidgets> +<images> + <image> + <name>image0</name> + <data format="XPM.GZ" length="45">789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade6523250004143a55a6b2e0026630c4f</data> + </image> + <image> + <name>image1</name> + <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data> + </image> +</images> +<connections> + <connection> + <sender>checkAlarm</sender> + <signal>toggled(bool)</signal> + <receiver>spinAlarm</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>comboEnd</sender> + <signal>activated(const QString&)</signal> + <receiver>DateEntryBase</receiver> + <slot>endTimeChanged( const QString & )</slot> + </connection> + <connection> + <sender>cmdRepeat</sender> + <signal>clicked()</signal> + <receiver>DateEntryBase</receiver> + <slot>slotRepeat()</slot> + </connection> + <connection> + <sender>comboStart</sender> + <signal>activated(int)</signal> + <receiver>DateEntryBase</receiver> + <slot>startTimeChanged( int )</slot> + </connection> + <connection> + <sender>checkAllDay</sender> + <signal>toggled(bool)</signal> + <receiver>comboEnd</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>checkAlarm</sender> + <signal>toggled(bool)</signal> + <receiver>comboSound</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>checkAllDay</sender> + <signal>toggled(bool)</signal> + <receiver>comboStart</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <slot access="public">endDateChanged( const QString & )</slot> + <slot access="public">endDateChanged( int, int, int )</slot> + <slot access="public">endTimeChanged( const QString & )</slot> + <slot access="public">slotRepeat()</slot> + <slot access="public">slotWait( int )</slot> + <slot access="public">startDateChanged( const QString & )</slot> + <slot access="public">startDateChanged(int, int, int)</slot> + <slot access="public">startTimeChanged( int )</slot> + <slot access="public">typeChanged( const QString & )</slot> + <slot access="public">tzexecute(void)</slot> +</connections> +</UI> diff --git a/core/pim/datebook/dateentryimpl.cpp b/core/pim/datebook/dateentryimpl.cpp new file mode 100644 index 0000000..1122f79 --- a/dev/null +++ b/core/pim/datebook/dateentryimpl.cpp @@ -0,0 +1,474 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#include "dateentryimpl.h" +#include "repeatentry.h" + +#include <qpe/qpeapplication.h> +#include <qpe/categoryselect.h> +#include <qpe/datebookmonth.h> +#include <qpe/global.h> +#include <qpe/timeconversion.h> +#include <qpe/timestring.h> +#include <qpe/tzselect.h> + +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qmultilineedit.h> +#include <qpopupmenu.h> +#include <qscrollview.h> +#include <qspinbox.h> +#include <qtoolbutton.h> + +#include <stdlib.h> + +/* + * Constructs a DateEntry which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ + +DateEntry::DateEntry( bool startOnMonday, const QDateTime &start, + const QDateTime &end, bool whichClock, QWidget* parent, + const char* name ) + : DateEntryBase( parent, name ), + ampm( whichClock ), + startWeekOnMonday( startOnMonday ) +{ + init(); + setDates(start,end); +} + +static void addOrPick( QComboBox* combo, const QString& t ) +{ + for (int i=0; i<combo->count(); i++) { + if ( combo->text(i) == t ) { + combo->setCurrentItem(i); + return; + } + } + combo->setEditText(t); +} + +DateEntry::DateEntry( bool startOnMonday, const Event &event, bool whichClock, + QWidget* parent, const char* name ) + : DateEntryBase( parent, name ), + ampm( whichClock ), + startWeekOnMonday( startOnMonday ) +{ + init(); + setDates(event.start(),event.end()); + comboCategory->setCategories( event.categories(), "Calendar", tr("Calendar") ); + if(!event.description().isEmpty()) + addOrPick( comboDescription, event.description() ); + if(!event.location().isEmpty()) + addOrPick( comboLocation, event.location() ); + checkAlarm->setChecked( event.hasAlarm() ); + checkAllDay->setChecked( event.type() == Event::AllDay ); + if(!event.notes().isEmpty()) + editNote->setText(event.notes()); + spinAlarm->setValue(event.alarmTime()); + if ( event.alarmSound() != Event::Silent ) + comboSound->setCurrentItem( 1 ); + if ( event.hasRepeat() ) { + rp = event.repeatPattern(); + cmdRepeat->setText( tr("Repeat...") ); + } + setRepeatLabel(); +} + +void DateEntry::setDates( const QDateTime& s, const QDateTime& e ) +{ + int shour, + ehour; + QString strStart, + strEnd; + startDate = s.date(); + endDate = e.date(); + startTime = s.time(); + endTime = e.time(); + startDateChanged( s.date().year(), s.date().month(), s.date().day() ); + if ( ampm ) { + shour = s.time().hour(); + ehour = e.time().hour(); + if ( shour >= 12 ) { + if ( shour > 12 ) + shour -= 12; + strStart.sprintf( "%d:%02d PM", shour, s.time().minute() ); + } else { + if ( shour == 0 ) + shour = 12; + strStart.sprintf( "%d:%02d AM", shour, s.time().minute() ); + } + if ( ehour == 24 && e.time().minute() == 0 ) { + strEnd = "11:59 PM"; // or "midnight" + } else if ( ehour >= 12 ) { + if ( ehour > 12 ) + ehour -= 12; + strEnd.sprintf( "%d:%02d PM", ehour, e.time().minute() ); + } else { + if ( ehour == 0 ) + ehour = 12; + strEnd.sprintf( "%d:%02d AM", ehour, e.time().minute() ); + } + } else { + strStart.sprintf( "%02d:%02d", s.time().hour(), s.time().minute() ); + strEnd.sprintf( "%02d:%02d", e.time().hour(), e.time().minute() ); + } + addOrPick(comboStart, strStart ); + endDateChanged( e.date().year(), e.date().month(), e.date().day() ); + addOrPick(comboEnd, strEnd ); +} + +void DateEntry::init() +{ + comboDescription->setInsertionPolicy(QComboBox::AtCurrent); + comboLocation->setInsertionPolicy(QComboBox::AtCurrent); + + initCombos(); + QPopupMenu *m1 = new QPopupMenu( this ); + startPicker = new DateBookMonth( m1, 0, TRUE ); + m1->insertItem( startPicker ); + buttonStart->setPopup( m1 ); + connect( startPicker, SIGNAL( dateClicked( int, int, int ) ), + this, SLOT( startDateChanged( int, int, int ) ) ); + + //Let start button change both start and end dates + connect( startPicker, SIGNAL( dateClicked( int, int, int ) ), + this, SLOT( endDateChanged( int, int, int ) ) ); + connect( qApp, SIGNAL( clockChanged( bool ) ), + this, SLOT( slotChangeClock( bool ) ) ); + connect( qApp, SIGNAL(weekChanged(bool)), + this, SLOT(slotChangeStartOfWeek(bool)) ); + + QPopupMenu *m2 = new QPopupMenu( this ); + endPicker = new DateBookMonth( m2, 0, TRUE ); + m2->insertItem( endPicker ); + buttonEnd->setPopup( m2 ); + connect( endPicker, SIGNAL( dateClicked( int, int, int ) ), + this, SLOT( endDateChanged( int, int, int ) ) ); +} + +/* + * Destroys the object and frees any allocated resources + */ +DateEntry::~DateEntry() +{ + // no need to delete child widgets, Qt does it all for us +} + +/* + * public slot + */ +void DateEntry::endDateChanged( int y, int m, int d ) +{ + endDate.setYMD( y, m, d ); + if ( endDate < startDate ) { + endDate = startDate; + } + + buttonEnd->setText( TimeString::shortDate( endDate ) ); + + endPicker->setDate( endDate.year(), endDate.month(), endDate.day() ); +} + +static QTime parseTime( const QString& s, bool ampm ) +{ + QTime tmpTime; + QStringList l = QStringList::split( ':', s ); + int hour = l[0].toInt(); + if ( ampm ) { + int i=0; + while (i<int(l[1].length()) && l[1][i]>='0' && l[1][i]<='9') + i++; + QString digits = l[1].left(i); + if ( l[1].contains( "PM", FALSE ) ) { + if ( hour != 12 ) + hour += 12; + } else { + if ( hour == 12 ) + hour = 0; + } + l[1] = digits; + } + int minute = l[1].toInt(); + if ( minute > 59 ) + minute = 59; + else if ( minute < 0 ) + minute = 0; + if ( hour > 23 ) { + hour = 23; + minute = 59; + } else if ( hour < 0 ) + hour = 0; + tmpTime.setHMS( hour, minute, 0 ); + return tmpTime; +} + +/* + * public slot + */ +void DateEntry::endTimeChanged( const QString &s ) +{ + QTime tmpTime = parseTime(s,ampm); + if ( endDate > startDate || tmpTime >= startTime ) { + endTime = tmpTime; + } else { + endTime = startTime; + comboEnd->setCurrentItem( comboStart->currentItem() ); + } +} + +/* + * public slot + */ +void DateEntry::startDateChanged( int y, int m, int d ) +{ + QDate prev = startDate; + startDate.setYMD( y, m, d ); + if ( rp.type == Event::Weekly && + startDate.dayOfWeek() != prev.dayOfWeek() ) { + // if we change the start of a weekly repeating event + // set the repeating day appropriately + char mask = 1 << (prev.dayOfWeek()-1); + rp.days &= (~mask); + rp.days |= 1 << (startDate.dayOfWeek()-1); + } + + buttonStart->setText( TimeString::shortDate( startDate ) ); + + // our pickers must be reset... + startPicker->setDate( y, m, d ); + endPicker->setDate( y, m, d ); +} + +/* + * public slot + */ +void DateEntry::startTimeChanged( int index ) +{ + startTime = parseTime(comboStart->text(index),ampm); + changeEndCombo( index ); +} +/* + * public slot + */ +void DateEntry::typeChanged( const QString &s ) +{ + bool b = s != "All Day"; + buttonStart->setEnabled( b ); + comboStart->setEnabled( b ); + comboEnd->setEnabled( b ); +} +/* + * public slot + */ +void DateEntry::changeEndCombo( int change ) +{ + if ( change + 2 < comboEnd->count() ) + change += 2; + comboEnd->setCurrentItem( change ); + endTimeChanged( comboEnd->currentText() ); +} + +void DateEntry::slotRepeat() +{ + // Work around for compiler Bug.. + RepeatEntry *e; + + // it is better in my opinion to just grab this from the mother, + // since, this dialog doesn't need to keep track of it... + if ( rp.type != Event::NoRepeat ) + e = new RepeatEntry( startWeekOnMonday, rp, startDate, this); + else + e = new RepeatEntry( startWeekOnMonday, startDate, this ); + +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + e->showMaximized(); +#endif + if ( e->exec() ) { + rp = e->repeatPattern(); + setRepeatLabel(); + } +} + +void DateEntry::slotChangeStartOfWeek( bool onMonday ) +{ + startWeekOnMonday = onMonday; +} + +Event DateEntry::event() +{ + Event ev; + Event::SoundTypeChoice st; + ev.setDescription( comboDescription->currentText() ); + ev.setLocation( comboLocation->currentText() ); + ev.setCategories( comboCategory->currentCategories() ); + ev.setType( checkAllDay->isChecked() ? Event::AllDay : Event::Normal ); + if ( startDate > endDate ) { + QDate tmp = endDate; + endDate = startDate; + startDate = tmp; + } + startTime = parseTime( comboStart->currentText(), ampm ); + endTime = parseTime( comboEnd->currentText(), ampm ); + if ( startTime > endTime && endDate == startDate ) { + QTime tmp = endTime; + endTime = startTime; + startTime = tmp; + } + // don't set the time if theres no need too + if ( ev.type() == Event::AllDay ) { + startTime.setHMS( 0, 0, 0 ); + endTime.setHMS( 23, 59, 59 ); + } + + // adjust start and end times based on timezone + QDateTime start( startDate, startTime ); + QDateTime end( endDate, endTime ); + time_t start_utc, end_utc; + +// qDebug( "tz: %s", timezone->currentZone().latin1() ); + + // get real timezone + QString realTZ; + realTZ = QString::fromLocal8Bit( getenv("TZ") ); + + // set timezone + if ( setenv( "TZ", timezone->currentZone(), true ) != 0 ) + qWarning( "There was a problem setting the timezone." ); + + // convert to UTC based on selected TZ (calling tzset internally) + start_utc = TimeConversion::toUTC( start ); + end_utc = TimeConversion::toUTC( end ); + + // done playing around... put it all back + unsetenv( "TZ" ); + if ( !realTZ.isNull() ) + if ( setenv( "TZ", realTZ, true ) != 0 ) + qWarning( "There was a problem setting the timezone." ); + + // convert UTC to local time (calling tzset internally) + ev.setStart( TimeConversion::fromUTC( start_utc ) ); + ev.setEnd( TimeConversion::fromUTC( end_utc ) ); + + // we only have one type of sound at the moment... LOUD!!! + if ( comboSound->currentItem() != 0 ) + st = Event::Loud; + else + st = Event::Silent; + ev.setAlarm( checkAlarm->isChecked(), spinAlarm->value(), st ); + if ( rp.type != Event::NoRepeat ) + ev.setRepeat( TRUE, rp ); + ev.setNotes( editNote->text() ); + return ev; +} + +void DateEntry::setRepeatLabel() +{ + + switch( rp.type ) { + case Event::Daily: + cmdRepeat->setText( tr("Daily...") ); + break; + case Event::Weekly: + cmdRepeat->setText( tr("Weekly...") ); + break; + case Event::MonthlyDay: + case Event::MonthlyDate: + cmdRepeat->setText( tr("Monthly...") ); + break; + case Event::Yearly: + cmdRepeat->setText( tr("Yearly...") ); + break; + default: + cmdRepeat->setText( tr("No Repeat...") ); + } +} + +void DateEntry::setAlarmEnabled( bool alarmPreset, int presetTime, Event::SoundTypeChoice sound ) +{ + checkAlarm->setChecked( alarmPreset ); + spinAlarm->setValue( presetTime ); + if ( sound != Event::Silent ) + comboSound->setCurrentItem( 1 ); + else + comboSound->setCurrentItem( 0 ); +} + +void DateEntry::initCombos() +{ + comboStart->clear(); + comboEnd->clear(); + if ( ampm ) { + for ( int i = 0; i < 24; i++ ) { + if ( i == 0 ) { + comboStart->insertItem( "12:00 AM" ); + comboStart->insertItem( "12:30 AM" ); + comboEnd->insertItem( "12:00 AM" ); + comboEnd->insertItem( "12:30 AM" ); + } else if ( i == 12 ) { + comboStart->insertItem( "12:00 PM" ); + comboStart->insertItem( "12:30 PM" ); + comboEnd->insertItem( "12:00 PM" ); + comboEnd->insertItem( "12:30 PM" ); + } else if ( i > 12 ) { + comboStart->insertItem( QString::number( i - 12 ) + ":00 PM" ); + comboStart->insertItem( QString::number( i - 12 ) + ":30 PM" ); + comboEnd->insertItem( QString::number( i - 12 ) + ":00 PM" ); + comboEnd->insertItem( QString::number( i - 12 ) + ":30 PM" ); + } else { + comboStart->insertItem( QString::number( i) + ":00 AM" ); + comboStart->insertItem( QString::number( i ) + ":30 AM" ); + comboEnd->insertItem( QString::number( i ) + ":00 AM" ); + comboEnd->insertItem( QString::number( i ) + ":30 AM" ); + } + } + } else { + for ( int i = 0; i < 24; i++ ) { + if ( i < 10 ) { + comboStart->insertItem( QString("0") + + QString::number(i) + ":00" ); + comboStart->insertItem( QString("0") + + QString::number(i) + ":30" ); + comboEnd->insertItem( QString("0") + + QString::number(i) + ":00" ); + comboEnd->insertItem( QString("0") + + QString::number(i) + ":30" ); + } else { + comboStart->insertItem( QString::number(i) + ":00" ); + comboStart->insertItem( QString::number(i) + ":30" ); + comboEnd->insertItem( QString::number(i) + ":00" ); + comboEnd->insertItem( QString::number(i) + ":30" ); + } + } + } +} + +void DateEntry::slotChangeClock( bool whichClock ) +{ + ampm = whichClock; + initCombos(); + setDates( QDateTime( startDate, startTime ), QDateTime( endDate, endTime ) ); +} diff --git a/core/pim/datebook/dateentryimpl.h b/core/pim/datebook/dateentryimpl.h new file mode 100644 index 0000000..785af7a --- a/dev/null +++ b/core/pim/datebook/dateentryimpl.h @@ -0,0 +1,71 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ +#ifndef DATEENTRY_H +#define DATEENTRY_H + +#include "dateentry.h" + +#include <qpe/event.h> + +#include <qdatetime.h> + +class DateBookMonth; + +class DateEntry : public DateEntryBase +{ + Q_OBJECT + +public: + DateEntry( bool startOnMonday, const QDateTime &start, + const QDateTime &end, bool whichClock = FALSE, + QWidget* parent = 0, const char* name = 0 ); + DateEntry( bool startOnMonday, const Event &event, bool whichCLock = FALSE, + QWidget* parent = 0, const char* name = 0 ); + ~DateEntry(); + + Event event(); + void setAlarmEnabled( bool alarmPreset, int presetTime, Event::SoundTypeChoice ); + +public slots: + void endDateChanged( int, int, int ); + void endTimeChanged( const QString & ); + void startDateChanged(int, int, int); + void startTimeChanged( int index ); + void typeChanged( const QString & ); + void changeEndCombo( int change ); + void slotRepeat(); + void slotChangeClock( bool ); + void slotChangeStartOfWeek( bool ); + +private: + void init(); + void initCombos(); + void setDates( const QDateTime& s, const QDateTime& e ); + void setRepeatLabel(); + + DateBookMonth *startPicker, *endPicker; + QDate startDate, endDate; + QTime startTime, endTime; + Event::RepeatPattern rp; + bool ampm; + bool startWeekOnMonday; +}; + +#endif // DATEENTRY_H diff --git a/core/pim/datebook/main.cpp b/core/pim/datebook/main.cpp new file mode 100644 index 0000000..caa5fb6 --- a/dev/null +++ b/core/pim/datebook/main.cpp @@ -0,0 +1,38 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#include "datebook.h" +#include <qpe/qpeapplication.h> + + +int main( int argc, char **argv ) +{ + QPEApplication a( argc, argv ); + + DateBook e; + QObject::connect( &a, SIGNAL( flush() ), &e, SLOT( flush() ) ); + QObject::connect( &a, SIGNAL( reload() ), &e, SLOT( reload() ) ); + + + e.setCaption( DateBook::tr("Calendar") ); + a.showMainWidget(&e); + + return a.exec(); +} diff --git a/core/pim/datebook/qpe-datebook.control b/core/pim/datebook/qpe-datebook.control new file mode 100644 index 0000000..c6ab81a --- a/dev/null +++ b/core/pim/datebook/qpe-datebook.control @@ -0,0 +1,9 @@ +Files: bin/datebook apps/Applications/datebook.desktop +Priority: optional +Section: qpe/applications +Maintainer: Warwick Allison <warwick@trolltech.com> +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: A datebook/appointment manager + A datebook/appointment manager for the Qtopia environment. diff --git a/core/pim/datebook/repeatentry.cpp b/core/pim/datebook/repeatentry.cpp new file mode 100644 index 0000000..5637c4d --- a/dev/null +++ b/core/pim/datebook/repeatentry.cpp @@ -0,0 +1,595 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#include "repeatentry.h" + +#include <qpe/datebookmonth.h> +#include <qpe/qpeapplication.h> +#include <qpe/timestring.h> + +#include <qbuttongroup.h> +#include <qlabel.h> +#include <qpopupmenu.h> +#include <qspinbox.h> +#include <qtoolbutton.h> + +#include <time.h> + +// Global Templates for use in setting up the repeat label... +const QString strDayTemplate = QObject::tr("Every"); +const QString strYearTemplate = QObject::tr("%1 %2 every "); +const QString strMonthDateTemplate = QObject::tr("The %1 every "); +const QString strMonthDayTemplate = QObject::tr("The %1 %1 of every"); +const QString strWeekTemplate = QObject::tr("Every "); +const QString dayLabel[] = { QObject::tr("Monday"), + QObject::tr("Tuesday"), + QObject::tr("Wednesday"), + QObject::tr("Thursday"), + QObject::tr("Friday"), + QObject::tr("Saturday"), + 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? + +RepeatEntry::RepeatEntry( bool startOnMonday, + const QDate &newStart, QWidget *parent, + const char *name, bool modal, WFlags fl ) + : RepeatEntryBase( parent, name, modal, fl ), + start( newStart ), + currInterval( NONE ), + startWeekOnMonday( startOnMonday ) +{ + init(); + fraType->setButton( currInterval ); + chkNoEnd->setChecked( TRUE ); + setupNone(); +} + +RepeatEntry::RepeatEntry( bool startOnMonday, const Event::RepeatPattern &rp, + const QDate &startDate, + QWidget *parent, const char *name, bool modal, + WFlags fl ) + : RepeatEntryBase( parent, name, modal, fl ), + start( startDate ), + end( rp.endDate() ), + startWeekOnMonday( startOnMonday ) +{ + // do some stuff with the repeat pattern + init(); + switch ( rp.type ) { + default: + case Event::NoRepeat: + currInterval = NONE; + setupNone(); + break; + case Event::Daily: + currInterval = DAY; + setupDaily(); + break; + case Event::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 Event::MonthlyDay: + currInterval = MONTH; + setupMonthly(); + fraExtra->setButton( 0 ); + slotMonthLabel( 0 ); + break; + case Event::MonthlyDate: + currInterval = MONTH; + setupMonthly(); + fraExtra->setButton( 1 ); + slotMonthLabel( 1 ); + break; + case Event::Yearly: + currInterval = YEAR; + setupYearly(); + break; + } + fraType->setButton( currInterval ); + spinFreq->setValue( rp.frequency ); + if ( !rp.hasEndDate ) { + cmdEnd->setText( RepeatEntryBase::tr("No End Date") ); + chkNoEnd->setChecked( TRUE ); + } else + cmdEnd->setText( TimeString::shortDate( end ) ); +} + +RepeatEntry::~RepeatEntry() +{ +} + +Event::RepeatPattern RepeatEntry::repeatPattern() +{ + QListIterator<QToolButton> it( listRTypeButtons ); + QListIterator<QToolButton> itExtra( listExtra ); + Event::RepeatPattern rpTmp; + int i; + for ( i = 0; *it; ++it, i++ ) { + if ( (*it)->isOn() ) { + switch ( i ) { + case NONE: + rpTmp.type = Event::NoRepeat; + break; + case DAY: + rpTmp.type = Event::Daily; + break; + case WEEK: + rpTmp.type = Event::Weekly; + rpTmp.days = 0; + int day; + for ( day = 1; *itExtra; ++itExtra, day = day << 1 ) { + if ( (*itExtra)->isOn() ) { + if ( startWeekOnMonday ) + rpTmp.days |= day; + else { + if ( day == 1 ) + rpTmp.days |= Event::SUN; + else + rpTmp.days |= day >> 1; + } + } + } + break; + case MONTH: + if ( cmdExtra1->isOn() ) + rpTmp.type = Event::MonthlyDay; + else if ( cmdExtra2->isOn() ) + rpTmp.type = Event::MonthlyDate; + // figure out the montly day... + rpTmp.position = week( start ); + break; + case YEAR: + rpTmp.type = Event::Yearly; + break; + } + break; // no need to keep looking! + } + } + rpTmp.frequency = spinFreq->value(); + rpTmp.hasEndDate = !chkNoEnd->isChecked(); + if ( rpTmp.hasEndDate ) { + rpTmp.setEndDate( end ); + } + // timestamp it... + rpTmp.createTime = time( NULL ); + return rpTmp; +} + +void RepeatEntry::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 RepeatEntry::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 RepeatEntry::setupDaily() +{ + hideExtras(); + lblWeekVar->hide(); + spinFreq->setValue( 1 ); + lblFreq->setText( tr("day(s)") ); + lblVar2->show(); + showRepeatStuff(); + lblRepeat->setText( strDayTemplate ); + setupRepeatLabel( 1 ); +} + +void RepeatEntry::setupWeekly() +{ + // reshow the buttons... + fraExtra->setTitle( RepeatEntryBase::tr("Repeat On") ); + fraExtra->setExclusive( FALSE ); + fraExtra->show(); + if ( startWeekOnMonday ) { + cmdExtra1->setText( RepeatEntryBase::tr("Mon") ); + cmdExtra2->setText( RepeatEntryBase::tr("Tue") ); + cmdExtra3->setText( RepeatEntryBase::tr("Wed") ); + cmdExtra4->setText( RepeatEntryBase::tr("Thu") ); + cmdExtra5->setText( RepeatEntryBase::tr("Fri") ); + cmdExtra6->setText( RepeatEntryBase::tr("Sat") ); + cmdExtra7->setText( RepeatEntryBase::tr("Sun") ); + } else { + cmdExtra1->setText( RepeatEntryBase::tr("Sun") ); + cmdExtra2->setText( RepeatEntryBase::tr("Mon") ); + cmdExtra3->setText( RepeatEntryBase::tr("Tue") ); + cmdExtra4->setText( RepeatEntryBase::tr("Wed") ); + cmdExtra5->setText( RepeatEntryBase::tr("Thu") ); + cmdExtra6->setText( RepeatEntryBase::tr("Fri") ); + cmdExtra7->setText( RepeatEntryBase::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 RepeatEntry::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 RepeatEntry::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 RepeatEntry::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 RepeatEntry::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( RepeatEntryBase::tr("No End Date") ); + } else { + end = start; + cmdEnd->setText( TimeString::shortDate(end) ); + } +} + +void RepeatEntry::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 RepeatEntry::setupRepeatLabel( const QString &s ) +{ + lblVar1->setText( s ); +} + +void RepeatEntry::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 = RepeatEntryBase::tr( "months" ); + else + strVar2 = tr( "month" ); + break; + case YEAR: + if ( x > 1 ) + strVar2 = RepeatEntryBase::tr( "years" ); + else + strVar2 = tr( "year" ); + break; + } + if ( !strVar2.isNull() ) + lblVar2->setText( strVar2 ); +} + +void RepeatEntry::showRepeatStuff() +{ + cmdEnd->show(); + chkNoEnd->show(); + lblFreq->show(); + lblEvery->show(); + lblFreq->show(); + spinFreq->show(); + lblEnd->show(); + lblRepeat->setText( RepeatEntryBase::tr("Every") ); +} + +void RepeatEntry::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( "on " ); + lblWeekVar->setText( str ); +} + +void RepeatEntry::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 RepeatEntry::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 |= Event::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(); +} + +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/core/pim/datebook/repeatentry.h b/core/pim/datebook/repeatentry.h new file mode 100644 index 0000000..949fecd --- a/dev/null +++ b/core/pim/datebook/repeatentry.h @@ -0,0 +1,98 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#ifndef REPEATENTRY_H +#define REPEATENTRY_H + +#include "repeatentrybase.h" + +#include <qpe/event.h> + +#include <qcheckbox.h> +#include <qbuttongroup.h> +#include <qdatetime.h> +#include <qlist.h> +#include <qtoolbutton.h> + +class DateBookMonth; + +class RepeatEntry : public RepeatEntryBase +{ + Q_OBJECT +public: + RepeatEntry( bool startOnMonday, + const QDate &start, QWidget *parent = 0, const char *name = 0, + bool modal = TRUE, WFlags fl = 0 ); + RepeatEntry( bool startOnMonday, + const Event::RepeatPattern &rp, const QDate &start, + QWidget *parent = 0, const char *name = 0, bool modal = TRUE, + WFlags fl = 0 ); + ~RepeatEntry(); + + Event::RepeatPattern repeatPattern(); + QDate endDate() { return end; }; + +public slots: + void slotSetRType( int ); + void endDateChanged( int, int, int ); + void slotNoEnd( bool unused ); + +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(); + inline void hideExtras(); + void showRepeatStuff(); + + QList<QToolButton> listRTypeButtons; + QList<QToolButton> listExtra; + QDate start; // only used in one spot... + QDate end; + repeatButtons currInterval; + bool startWeekOnMonday; + DateBookMonth *repeatPicker; +}; + +inline void RepeatEntry::hideExtras() +{ + // hide the extra buttons... + fraExtra->hide(); + chkNoEnd->hide(); + QListIterator<QToolButton> it( listExtra ); + for ( ; *it; ++it ) { + (*it)->hide(); + (*it)->setOn( FALSE ); + } + +} + +#endif diff --git a/core/pim/datebook/repeatentrybase.ui b/core/pim/datebook/repeatentrybase.ui new file mode 100644 index 0000000..9621d74 --- a/dev/null +++ b/core/pim/datebook/repeatentrybase.ui @@ -0,0 +1,713 @@ +<!DOCTYPE UI><UI> +<class>RepeatEntryBase</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>RepeatEntryBase</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>250</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>RepeatEntryBase</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>RepeatEntryBase</receiver> + <slot>setupRepeatLabel( int )</slot> + </connection> + <connection> + <sender>fraType</sender> + <signal>clicked(int)</signal> + <receiver>RepeatEntryBase</receiver> + <slot>slotSetRType( int )</slot> + </connection> + <connection> + <sender>fraExtra</sender> + <signal>clicked(int)</signal> + <receiver>RepeatEntryBase</receiver> + <slot>slotMonthLabel( int )</slot> + </connection> + <connection> + <sender>fraExtra</sender> + <signal>clicked(int)</signal> + <receiver>RepeatEntryBase</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/core/pim/todo/.cvsignore b/core/pim/todo/.cvsignore new file mode 100644 index 0000000..5ed04d8 --- a/dev/null +++ b/core/pim/todo/.cvsignore @@ -0,0 +1,4 @@ +moc_* +Makefile +todoentry.h +todoentry.cpp diff --git a/core/pim/todo/Makefile.in b/core/pim/todo/Makefile.in new file mode 100644 index 0000000..f3c5f0e --- a/dev/null +++ b/core/pim/todo/Makefile.in @@ -0,0 +1,201 @@ +############################################################################# + +####### Compiler, tools and options + +CXX = $(SYSCONF_CXX) $(QT_CXX_MT) +CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) +CC = $(SYSCONF_CC) $(QT_C_MT) +CFLAGS = $(SYSCONF_CFLAGS) +INCPATH = -I$(QPEDIR)/include +LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT) +LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS) $(SYSCONF_LIBS_QTAPP) +MOC = $(SYSCONF_MOC) +UIC = $(SYSCONF_UIC) + +####### Target + +DESTDIR = $(QPEDIR)/bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = todolist +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = mainwindow.h \ + todotable.h \ + todoentryimpl.h +SOURCES = main.cpp \ + mainwindow.cpp \ + todotable.cpp \ + todoentryimpl.cpp +OBJECTS = main.o \ + mainwindow.o \ + todotable.o \ + todoentryimpl.o \ + todoentry.o +INTERFACES = todoentry.ui +UICDECLS = todoentry.h +UICIMPLS = todoentry.cpp +SRCMOC = moc_mainwindow.cpp \ + moc_todotable.cpp \ + moc_todoentryimpl.cpp \ + moc_todoentry.cpp +OBJMOC = moc_mainwindow.o \ + moc_todotable.o \ + moc_todoentryimpl.o \ + moc_todoentry.o + + +####### Implicit rules + +.SUFFIXES: .cpp .cxx .cc .C .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.C.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + + +all: $(DESTDIR)$(TARGET) + +$(DESTDIR)$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS) + $(SYSCONF_LINK) $(LFLAGS) -o $(DESTDIR)$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) + +moc: $(SRCMOC) + +tmake: + tmake todo.pro + +clean: + -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) + -rm -f *~ core + -rm -f allmoc.cpp + +####### Extension Modules + +listpromodules: + @echo + +listallmodules: + @echo + +listaddonpromodules: + @echo + +listaddonentmodules: + @echo + + +REQUIRES= + +####### Sub-libraries + + +###### Combined headers + + + +####### Compile + +main.o: main.cpp \ + mainwindow.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +mainwindow.o: mainwindow.cpp \ + mainwindow.h \ + todoentryimpl.h \ + todoentry.h \ + $(QPEDIR)/include/qpe/task.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/stringutil.h \ + todotable.h \ + $(QPEDIR)/include/qpe/categories.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/finddialog.h \ + $(QPEDIR)/include/qpe/global.h \ + $(QPEDIR)/include/qpe/ir.h \ + $(QPEDIR)/include/qpe/qpemenubar.h \ + $(QPEDIR)/include/qpe/qpemessagebox.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h + +todotable.o: todotable.cpp \ + todotable.h \ + $(QPEDIR)/include/qpe/categories.h \ + $(QPEDIR)/include/qpe/task.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/stringutil.h \ + $(QPEDIR)/include/qpe/categoryselect.h \ + $(QPEDIR)/include/qpe/xmlreader.h + +todoentryimpl.o: todoentryimpl.cpp \ + todoentryimpl.h \ + todoentry.h \ + $(QPEDIR)/include/qpe/task.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/stringutil.h \ + $(QPEDIR)/include/qpe/categoryselect.h \ + $(QPEDIR)/include/qpe/datebookmonth.h \ + $(QPEDIR)/include/qpe/event.h \ + $(QPEDIR)/include/qpe/global.h \ + $(QPEDIR)/include/qpe/imageedit.h \ + $(QPEDIR)/include/qpe/timestring.h + +todoentry.h: todoentry.ui + $(UIC) todoentry.ui -o $(INTERFACE_DECL_PATH)/todoentry.h + +todoentry.cpp: todoentry.ui + $(UIC) todoentry.ui -i todoentry.h -o todoentry.cpp + +todoentry.o: todoentry.cpp \ + todoentry.h \ + todoentry.ui + +moc_mainwindow.o: moc_mainwindow.cpp \ + mainwindow.h + +moc_todotable.o: moc_todotable.cpp \ + todotable.h \ + $(QPEDIR)/include/qpe/categories.h \ + $(QPEDIR)/include/qpe/task.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/stringutil.h + +moc_todoentryimpl.o: moc_todoentryimpl.cpp \ + todoentryimpl.h \ + todoentry.h \ + $(QPEDIR)/include/qpe/task.h \ + $(QPEDIR)/include/qpe/palmtoprecord.h \ + $(QPEDIR)/include/qpe/stringutil.h + +moc_todoentry.o: moc_todoentry.cpp \ + todoentry.h + +moc_mainwindow.cpp: mainwindow.h + $(MOC) mainwindow.h -o moc_mainwindow.cpp + +moc_todotable.cpp: todotable.h + $(MOC) todotable.h -o moc_todotable.cpp + +moc_todoentryimpl.cpp: todoentryimpl.h + $(MOC) todoentryimpl.h -o moc_todoentryimpl.cpp + +moc_todoentry.cpp: todoentry.h + $(MOC) todoentry.h -o moc_todoentry.cpp + + diff --git a/core/pim/todo/main.cpp b/core/pim/todo/main.cpp new file mode 100644 index 0000000..4e1c8a1 --- a/dev/null +++ b/core/pim/todo/main.cpp @@ -0,0 +1,36 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#include "mainwindow.h" + +#include <qpe/qpeapplication.h> + +int main( int argc, char **argv ) +{ + QPEApplication a( argc, argv ); + + TodoWindow mw; + QObject::connect( &a, SIGNAL( flush() ), &mw, SLOT( flush() ) ); + QObject::connect( &a, SIGNAL( reload() ), &mw, SLOT( reload() ) ); + + a.showMainWidget(&mw); + + return a.exec(); +} diff --git a/core/pim/todo/mainwindow.cpp b/core/pim/todo/mainwindow.cpp new file mode 100644 index 0000000..fb85a09 --- a/dev/null +++ b/core/pim/todo/mainwindow.cpp @@ -0,0 +1,466 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#include "mainwindow.h" +#include "todoentryimpl.h" +#include "todotable.h" + +#include <qpe/qpeapplication.h> +#include <qpe/config.h> +#include <qpe/finddialog.h> +#include <qpe/global.h> +#include <qpe/ir.h> +#include <qpe/qpemenubar.h> +#include <qpe/qpemessagebox.h> +#include <qpe/resource.h> +#include <qpe/task.h> +#include <qpe/qpetoolbar.h> + +#include <qaction.h> +#include <qarray.h> +#include <qdatastream.h> +#include <qdatetime.h> +#include <qfile.h> +#include <qmessagebox.h> +#include <qpopupmenu.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> + +#include <stdlib.h> + +static QString todolistXMLFilename() +{ + return Global::applicationFileName("todolist","todolist.xml"); +} + +static QString categoriesXMLFilename() +{ + return Global::applicationFileName("todolist","categories.xml"); +} + +TodoWindow::TodoWindow( QWidget *parent, const char *name, WFlags f = 0 ) : + QMainWindow( parent, name, f ), syncing(FALSE) +{ +// QTime t; +// t.start(); + + setCaption( tr("Todo") ); + QString str; + table = new TodoTable( this ); + table->setColumnWidth( 2, 10 ); + table->setPaintingEnabled( FALSE ); + table->setUpdatesEnabled( FALSE ); + table->viewport()->setUpdatesEnabled( FALSE ); + + { + str = todolistXMLFilename(); + if ( str.isNull() ) + QMessageBox::critical( this, + tr("Out of Space"), + tr("Unable to create startup files\n" + "Free up some space\n" + "before you enter any data") ); + else + table->load( str ); + } + + // repeat for categories... + str = categoriesXMLFilename(); + if ( str.isNull() ) + QMessageBox::critical( this, + tr( "Out of Space" ), + tr( "Unable to create startup files\n" + "Free up some space\n" + "before you enter any data") ); + + setCentralWidget( table ); + setToolBarsMovable( FALSE ); + +// qDebug("after load: t=%d", t.elapsed() ); + + Config config( "todo" ); + config.setGroup( "View" ); + bool complete = config.readBoolEntry( "ShowComplete", true ); + table->setShowCompleted( complete ); + QString category = config.readEntry( "Category", QString::null ); + table->setShowCategory( category ); + + QPEToolBar *bar = new QPEToolBar( this ); + bar->setHorizontalStretchable( TRUE ); + + QPEMenuBar *mb = new QPEMenuBar( bar ); + + catMenu = new QPopupMenu( this ); + QPopupMenu *edit = new QPopupMenu( this ); + contextMenu = new QPopupMenu( this ); + + bar = new QPEToolBar( this ); + + QAction *a = new QAction( tr( "New Task" ), Resource::loadPixmap( "new" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), + this, SLOT( slotNew() ) ); + a->addTo( bar ); + a->addTo( edit ); + a = new QAction( tr( "Edit" ), Resource::loadIconSet( "edit" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), + this, SLOT( slotEdit() ) ); + a->addTo( bar ); + a->addTo( edit ); + a->addTo( contextMenu ); + a->setEnabled( FALSE ); + editAction = a; + a = new QAction( tr( "Delete" ), Resource::loadIconSet( "trash" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), + this, SLOT( slotDelete() ) ); + a->addTo( bar ); + a->addTo( edit ); + a->addTo( contextMenu ); + a->setEnabled( FALSE ); + deleteAction = a; + + if ( Ir::supported() ) { + a = new QAction( tr( "Beam" ), Resource::loadPixmap( "beam" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), + this, SLOT( slotBeam() ) ); + a->addTo( edit ); + a->addTo( bar ); + } + + a = new QAction( tr( "Find" ), Resource::loadIconSet( "mag" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), + this, SLOT( slotFind() ) ); + a->addTo( bar ); + a->addTo( edit ); + if ( table->numRows() ) + a->setEnabled( TRUE ); + else + a->setEnabled( FALSE ); + + //a->setEnabled( FALSE ); + findAction = a; +// qDebug("mainwindow #2: t=%d", t.elapsed() ); + + completedAction = new QAction( QString::null, tr("Completed tasks"), 0, this, 0, TRUE ); + + catMenu->setCheckable( true ); + populateCategories(); + + mb->insertItem( tr( "Task" ), edit ); + mb->insertItem( tr( "View" ), catMenu ); + + resize( 200, 300 ); + if ( table->numRows() > 0 ) + currentEntryChanged( 0, 0 ); + connect( table, SIGNAL( signalEdit() ), + this, SLOT( slotEdit() ) ); + connect( table, SIGNAL(signalShowMenu(const QPoint &)), + this, SLOT( slotShowPopup(const QPoint &)) ); + +// qDebug("mainwindow #3: t=%d", t.elapsed() ); + table->updateVisible(); + table->setUpdatesEnabled( TRUE ); + table->setPaintingEnabled( TRUE ); + table->viewport()->setUpdatesEnabled( TRUE ); + + connect( completedAction, SIGNAL( toggled(bool) ), this, SLOT( showCompleted(bool) ) ); + connect( catMenu, SIGNAL(activated(int)), this, SLOT(setCategory(int)) ); + connect( table, SIGNAL( currentChanged( int, int ) ), + this, SLOT( currentEntryChanged( int, int ) ) ); + +// qDebug("done: t=%d", t.elapsed() ); +} + +void TodoWindow::slotNew() +{ + if(syncing) { + QMessageBox::warning(this, tr("Todo"), + tr("Can not edit data, currently syncing")); + return; + } + + int id; + id = -1; + QArray<int> ids; + ids = table->currentEntry().categories(); + if ( ids.count() ) + id = ids[0]; + NewTaskDialog e( id, this, 0, TRUE ); + + Task todo; + +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + e.showMaximized(); +#endif + int ret = e.exec(); + + if ( ret == QDialog::Accepted ) { + table->setPaintingEnabled( false ); + todo = e.todoEntry(); + todo.assignUid(); + table->addEntry( todo ); + table->setPaintingEnabled( true ); + findAction->setEnabled( TRUE ); + } + // I'm afraid we must call this every time now, otherwise + // spend expensive time comparing all these strings... + populateCategories(); +} + +TodoWindow::~TodoWindow() +{ +} + +void TodoWindow::slotDelete() +{ + if(syncing) { + QMessageBox::warning(this, tr("Todo"), + tr("Can not edit data, currently syncing")); + return; + } + + if ( table->currentRow() == -1 ) + return; + + QString strName = table->text( table->currentRow(), 2 ).left( 30 ); + + if ( !QPEMessageBox::confirmDelete( this, tr( "Todo" ), strName ) ) + return; + + + + table->setPaintingEnabled( false ); + table->removeCurrentEntry(); + table->setPaintingEnabled( true ); + + if ( table->numRows() == 0 ) { + currentEntryChanged( -1, 0 ); + findAction->setEnabled( FALSE ); + } +} + +void TodoWindow::slotEdit() +{ + if(syncing) { + QMessageBox::warning(this, tr("Todo"), + tr("Can not edit data, currently syncing")); + return; + } + + Task todo = table->currentEntry(); + + NewTaskDialog e( todo, this, 0, TRUE ); + e.setCaption( tr( "Edit Task" ) ); + +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + e.showMaximized(); +#endif + int ret = e.exec(); + + if ( ret == QDialog::Accepted ) { + table->setPaintingEnabled( false ); + todo = e.todoEntry(); + table->replaceCurrentEntry( todo ); + table->setPaintingEnabled( true ); + } + populateCategories(); + +} + +void TodoWindow::slotShowPopup( const QPoint &p ) +{ + contextMenu->popup( p ); +} + +void TodoWindow::showCompleted( bool s ) +{ + if ( !table->isUpdatesEnabled() ) + return; + table->setPaintingEnabled( false ); + table->setShowCompleted( s ); + table->setPaintingEnabled( true ); +} + +void TodoWindow::currentEntryChanged( int r, int ) +{ + if ( r != -1 && table->rowHeight( r ) > 0 ) { + editAction->setEnabled( TRUE ); + deleteAction->setEnabled( TRUE ); + } else { + editAction->setEnabled( FALSE ); + deleteAction->setEnabled( FALSE ); + } +} + +void TodoWindow::setCategory( int c ) +{ + if ( c <= 0 ) return; + if ( !table->isUpdatesEnabled() ) + return; + table->setPaintingEnabled( false ); + for ( unsigned int i = 1; i < catMenu->count(); i++ ) + catMenu->setItemChecked( i, c == (int)i ); + if ( c == 1 ) { + table->setShowCategory( QString::null ); + setCaption( tr("Todo") + " - " + tr( "All" ) ); + } else if ( c == (int)catMenu->count() - 1 ) { + table->setShowCategory( tr( "Unfiled" ) ); + setCaption( tr("Todo") + " - " + tr( "Unfiled" ) ); + } else { + QString cat = table->categories()[c - 2]; + table->setShowCategory( cat ); + setCaption( tr("Todo") + " - " + cat ); + } + table->setPaintingEnabled( true ); +} + +void TodoWindow::populateCategories() +{ + catMenu->clear(); + + completedAction->addTo( catMenu ); + completedAction->setOn( table->showCompleted() ); + + int id, + rememberId; + id = 1; + catMenu->insertItem( tr( "All" ), id++ ); +// catMenu->insertSeparator(); + QStringList categories = table->categories(); + categories.append( tr( "Unfiled" ) ); + for ( QStringList::Iterator it = categories.begin(); + it != categories.end(); ++it ) { + catMenu->insertItem( *it, id ); + if ( *it == table->showCategory() ) + rememberId = id; + ++id; + } + if ( table->showCategory().isEmpty() ) + setCategory( 1 ); + else + setCategory( rememberId ); +} + +void TodoWindow::reload() +{ + table->clear(); + table->load( todolistXMLFilename() ); + syncing = FALSE; +} + +void TodoWindow::flush() +{ + syncing = TRUE; + table->save( todolistXMLFilename() ); +} + +void TodoWindow::closeEvent( QCloseEvent *e ) +{ + if(syncing) { + /* no need to save if in the middle of syncing */ + e->accept(); + return; + } + + if ( table->save( todolistXMLFilename() ) ) { + e->accept(); + // repeat for categories... + // if writing configs fail, it will emit an + // error, but I feel that it is "ok" for us to exit + // espically since we aren't told if the write succeeded... + Config config( "todo" ); + config.setGroup( "View" ); + config.writeEntry( "ShowComplete", table->showCompleted() ); + config.writeEntry( "Category", table->showCategory() ); + } else { + if ( QMessageBox::critical( this, tr("Out of space"), + tr("Todo was unable\n" + "to save your changes.\n" + "Free up some space\n" + "and try again.\n" + "\nQuit Anyway?"), + QMessageBox::Yes|QMessageBox::Escape, + QMessageBox::No|QMessageBox::Default) + != QMessageBox::No ) + e->accept(); + else + e->ignore(); + } +} + +void TodoWindow::slotFind() +{ + // put everything back to view all for searching... + if ( !catMenu->isItemChecked( 0 ) ) + setCategory( 0 ); + + FindDialog dlg( "Todo List", this ); + QObject::connect( &dlg, + SIGNAL(signalFindClicked(const QString &, + bool, bool, int)), + table, + SLOT(slotDoFind(const QString&, bool, bool, int)) ); + QObject::connect( table, SIGNAL(signalNotFound()), &dlg, + SLOT(slotNotFound()) ); + QObject::connect( table, SIGNAL(signalWrapAround()), &dlg, + SLOT(slotWrapAround()) ); + dlg.exec(); + if ( table->numSelections() ) + table->clearSelection(); + table->clearFindRow(); +} + + +void TodoWindow::setDocument( const QString &filename ) +{ + if ( filename.find(".vcs") != int(filename.length()) - 4 ) return; + + QValueList<Task> tl = Task::readVCalendar( filename ); + for( QValueList<Task>::Iterator it = tl.begin(); it != tl.end(); ++it ) { + table->addEntry( *it ); + } +} + +static const char * beamfile = "/tmp/obex/todo.vcs"; + +void TodoWindow::slotBeam() +{ + unlink( beamfile ); // delete if exists + Task c = table->currentEntry(); + mkdir("/tmp/obex/", 0755); + Task::writeVCalendar( beamfile, c ); + Ir *ir = new Ir( this ); + connect( ir, SIGNAL( done( Ir * ) ), this, SLOT( beamDone( Ir * ) ) ); + QString description = c.description(); + ir->send( beamfile, description, "text/x-vCalendar" ); +} + +void TodoWindow::beamDone( Ir *ir ) +{ + delete ir; + unlink( beamfile ); +} diff --git a/core/pim/todo/mainwindow.h b/core/pim/todo/mainwindow.h new file mode 100644 index 0000000..f4fcd1b --- a/dev/null +++ b/core/pim/todo/mainwindow.h @@ -0,0 +1,73 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <qmainwindow.h> + +class TodoTable; +class QAction; +class QPopupMenu; +class Ir; + +class TodoWindow : public QMainWindow +{ + Q_OBJECT + +public: + TodoWindow( QWidget *parent = 0, const char *name = 0, WFlags f = 0 ); + ~TodoWindow(); + +public slots: + void flush(); + void reload(); + +protected slots: + void slotNew(); + void slotDelete(); + void slotEdit(); + void slotShowPopup( const QPoint & ); + void showCompleted( bool ); + void currentEntryChanged( int r, int c ); + void setCategory( int ); + void slotFind(); + void setDocument( const QString & ); + void slotBeam(); + void beamDone( Ir * ); + +protected: + void closeEvent( QCloseEvent *e ); + +private: + void populateCategories(); + +private: + TodoTable *table; + QAction *editAction, + *deleteAction, + *findAction, + * completedAction; + QPopupMenu *contextMenu, *catMenu; + + bool syncing; +}; + +#endif diff --git a/core/pim/todo/qpe-todo.control b/core/pim/todo/qpe-todo.control new file mode 100644 index 0000000..80195a0 --- a/dev/null +++ b/core/pim/todo/qpe-todo.control @@ -0,0 +1,9 @@ +Files: bin/todolist apps/Applications/todo.desktop +Priority: optional +Section: qpe/applications +Maintainer: Warwick Allison <warwick@trolltech.com> +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: TODO-list manager + A Todo-list manager for the Qtopia environment. diff --git a/core/pim/todo/todo.pro b/core/pim/todo/todo.pro new file mode 100644 index 0000000..e28ea1c --- a/dev/null +++ b/core/pim/todo/todo.pro @@ -0,0 +1,19 @@ +TEMPLATE = app +CONFIG = qt warn_on release +DESTDIR = $(QPEDIR)/bin +HEADERS = mainwindow.h \ + todotable.h \ + todoentryimpl.h +SOURCES = main.cpp \ + mainwindow.cpp \ + todotable.cpp \ + todoentryimpl.cpp + +INTERFACES = todoentry.ui + +TARGET = todolist +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe + +TRANSLATIONS = ../i18n/de/todolist.ts diff --git a/core/pim/todo/todoentry.ui b/core/pim/todo/todoentry.ui new file mode 100644 index 0000000..c735e76 --- a/dev/null +++ b/core/pim/todo/todoentry.ui @@ -0,0 +1,266 @@ +<!DOCTYPE UI><UI> +<class>NewTaskDialogBase</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. +** +*********************************************************************</comment> +<widget> + <class>QDialog</class> + <property stdset="1"> + <name>name</name> + <cstring>NewTaskDialogBase</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>249</width> + <height>321</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>New Task</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>0</number> + </property> + <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>TextLabel2</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Priority:</string> + </property> + </widget> + <widget> + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string>1 - Very High</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>2 - High</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>3 - Normal</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>4 - Low</string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>5 - Very Low</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>comboPriority</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>currentItem</name> + <number>2</number> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout3</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>TextLabel3</cstring> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>NoFrame</enum> + </property> + <property stdset="1"> + <name>text</name> + <string>Category:</string> + </property> + </widget> + <widget> + <class>CategorySelect</class> + <property stdset="1"> + <name>name</name> + <cstring>comboCategory</cstring> + </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>QCheckBox</class> + <property stdset="1"> + <name>name</name> + <cstring>checkCompleted</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>&Completed</string> + </property> + </widget> + <widget> + <class>QCheckBox</class> + <property stdset="1"> + <name>name</name> + <cstring>checkDate</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>D&ue</string> + </property> + </widget> + <widget> + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>buttonDate</cstring> + </property> + <property stdset="1"> + <name>enabled</name> + <bool>false</bool> + </property> + <property stdset="1"> + <name>text</name> + <string>1 Jan 2001</string> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QMultiLineEdit</class> + <property stdset="1"> + <name>name</name> + <cstring>txtTodo</cstring> + </property> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>CategorySelect</class> + <header location="global">qpe/categoryselect.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">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data> + </image> +</images> +<connections> + <connection> + <sender>checkDate</sender> + <signal>toggled(bool)</signal> + <receiver>buttonDate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <slot access="protected">dateChanged( const QString & )</slot> + <slot access="protected">dateChanged( int, int, int )</slot> +</connections> +</UI> diff --git a/core/pim/todo/todoentryimpl.cpp b/core/pim/todo/todoentryimpl.cpp new file mode 100644 index 0000000..79206de --- a/dev/null +++ b/core/pim/todo/todoentryimpl.cpp @@ -0,0 +1,142 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#include "todoentryimpl.h" + +#include <qpe/categoryselect.h> +#include <qpe/datebookmonth.h> +#include <qpe/global.h> +#include <qpe/imageedit.h> +#include <qpe/task.h> +#include <qpe/timestring.h> + +#include <qmessagebox.h> +#include <qpopupmenu.h> +#include <qtoolbutton.h> +#include <qcombobox.h> +#include <qcheckbox.h> +#include <qlineedit.h> +#include <qmultilineedit.h> +#include <qlabel.h> +#include <qtimer.h> +#include <qapplication.h> + + +NewTaskDialog::NewTaskDialog( const Task& task, QWidget *parent, + const char *name, bool modal, WFlags fl ) + : NewTaskDialogBase( parent, name, modal, fl ), + todo( task ) +{ + todo.setCategories( task.categories() ); + if ( todo.hasDueDate() ) + date = todo.dueDate(); + else + date = QDate::currentDate(); + + init(); + comboPriority->setCurrentItem( task.priority() - 1 ); + + checkCompleted->setChecked( task.isCompleted() ); + checkDate->setChecked( task.hasDueDate() ); + buttonDate->setText( TimeString::longDateString( date ) ); + + txtTodo->setText( task.description() ); +} + +/* + * Constructs a NewTaskDialog which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +NewTaskDialog::NewTaskDialog( int id, QWidget* parent, const char* name, bool modal, + WFlags fl ) + : NewTaskDialogBase( parent, name, modal, fl ), + date( QDate::currentDate() ) +{ + if ( id != -1 ) { + QArray<int> ids( 1 ); + ids[0] = id; + todo.setCategories( ids ); + } + init(); +} + +void NewTaskDialog::init() +{ + QPopupMenu *m1 = new QPopupMenu( this ); + picker = new DateBookMonth( m1, 0, TRUE ); + m1->insertItem( picker ); + buttonDate->setPopup( m1 ); + comboCategory->setCategories( todo.categories(), "Todo List", tr("Todo List") ); + + connect( picker, SIGNAL( dateClicked( int, int, int ) ), + this, SLOT( dateChanged( int, int, int ) ) ); + + buttonDate->setText( TimeString::longDateString( date ) ); + picker->setDate( date.year(), date.month(), date.day() ); +} + +/* + * Destroys the object and frees any allocated resources + */ +NewTaskDialog::~NewTaskDialog() +{ + // no need to delete child widgets, Qt does it all for us +} +void NewTaskDialog::dateChanged( int y, int m, int d ) +{ + date = QDate( y, m, d ); + buttonDate->setText( TimeString::longDateString( date ) ); +} + +/*! +*/ + +Task NewTaskDialog::todoEntry() +{ + todo.setDueDate( date, checkDate->isChecked() ); + if ( comboCategory->currentCategory() != -1 ) { + todo.setCategories( comboCategory->currentCategories() ); + } + todo.setPriority( comboPriority->currentItem() + 1 ); + todo.setCompleted( checkCompleted->isChecked() ); + + todo.setDescription( txtTodo->text() ); + + return todo; +} + + +/*! + +*/ + +void NewTaskDialog::accept() +{ + QString strText = txtTodo->text(); + if ( !strText || strText == "") { + // hmm... just decline it then, the user obviously didn't care about it + QDialog::reject(); + return; + } + QDialog::accept(); +} diff --git a/core/pim/todo/todoentryimpl.h b/core/pim/todo/todoentryimpl.h new file mode 100644 index 0000000..932d66e --- a/dev/null +++ b/core/pim/todo/todoentryimpl.h @@ -0,0 +1,61 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#ifndef NEWTASKDIALOG_H +#define NEWTASKDIALOG_H + +#include "todoentry.h" + +#include <qpe/task.h> + +#include <qdatetime.h> +#include <qpalette.h> + +class QLabel; +class QTimer; +class DateBookMonth; + +class NewTaskDialog : public NewTaskDialogBase +{ + Q_OBJECT + +public: + NewTaskDialog( const Task &task, QWidget *parent = 0, const char* name = 0, + bool modal = FALSE, WFlags fl = 0 ); + NewTaskDialog( int id, QWidget* parent = 0, const char* name = 0, + bool modal = FALSE, WFlags fl = 0 ); + ~NewTaskDialog(); + + Task todoEntry(); + +protected slots: + void dateChanged( int y, int m, int d ); + +protected: + virtual void accept(); + +private: + void init(); + Task todo; + QDate date; + DateBookMonth *picker; +}; + +#endif // NEWTASKDIALOG_H diff --git a/core/pim/todo/todotable.cpp b/core/pim/todo/todotable.cpp new file mode 100644 index 0000000..77d3389 --- a/dev/null +++ b/core/pim/todo/todotable.cpp @@ -0,0 +1,859 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#include "todotable.h" + +#include <qpe/categoryselect.h> +#include <qpe/xmlreader.h> + +#include <qasciidict.h> +#include <qcombobox.h> +#include <qfile.h> +#include <qpainter.h> +#include <qtextcodec.h> +#include <qtimer.h> +#include <qdatetime.h> + +#include <qcursor.h> +#include <qregexp.h> + +#include <errno.h> +#include <stdlib.h> + + + +static bool taskCompare( const Task &task, const QRegExp &r, int category ); + +static QString journalFileName(); + +CheckItem::CheckItem( QTable *t, const QString &key ) + : QTableItem( t, Never, "" ), checked( FALSE ), sortKey( key ) +{ +} + +QString CheckItem::key() const +{ + return sortKey; +} + +void CheckItem::setChecked( bool b ) +{ + checked = b; + table()->updateCell( row(), col() ); +} + +void CheckItem::toggle() +{ + TodoTable *parent = static_cast<TodoTable*>(table()); + Task newTodo = parent->currentEntry(); + checked = !checked; + newTodo.setCompleted( checked ); + table()->updateCell( row(), col() ); + parent->replaceCurrentEntry( newTodo, true ); +} + +bool CheckItem::isChecked() const +{ + return checked; +} + +static const int BoxSize = 10; + +void CheckItem::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 ( 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 ); + } +} + + +ComboItem::ComboItem( QTable *t, EditType et ) + : QTableItem( t, et, "3" ), cb( 0 ) +{ + setReplaceable( FALSE ); +} + +QWidget *ComboItem::createEditor() const +{ + QString txt = text(); + ( (ComboItem*)this )->cb = new QComboBox( table()->viewport() ); + cb->insertItem( "1" ); + cb->insertItem( "2" ); + cb->insertItem( "3" ); + cb->insertItem( "4" ); + cb->insertItem( "5" ); + cb->setCurrentItem( txt.toInt() - 1 ); + return cb; +} + +void ComboItem::setContentFromEditor( QWidget *w ) +{ + TodoTable *parent = static_cast<TodoTable*>(table()); + Task newTodo = parent->currentEntry(); + + if ( w->inherits( "QComboBox" ) ) + setText( ( (QComboBox*)w )->currentText() ); + else + QTableItem::setContentFromEditor( w ); + newTodo.setPriority( text().toInt() ); + parent->replaceCurrentEntry( newTodo, true ); +} + +void ComboItem::setText( const QString &s ) +{ + if ( cb ) + cb->setCurrentItem( s.toInt() - 1 ); + QTableItem::setText( s ); +} + +QString ComboItem::text() const +{ + if ( cb ) + return cb->currentText(); + return QTableItem::text(); +} + + + +TodoTable::TodoTable( QWidget *parent, const char *name ) +// #ifdef QT_QTABLE_NOHEADER_CONSTRUCTOR +// : QTable( 0, 3, parent, name, TRUE ), +// #else + : QTable( 0, 3, parent, name ), +// #endif + showComp( true ), + enablePainting( true ), + mCat( 0 ), + currFindRow( -2 ) +{ + mCat.load( categoryFileName() ); + setSorting( TRUE ); + setSelectionMode( NoSelection ); + setColumnStretchable( 2, TRUE ); + setColumnWidth( 0, 20 ); + setColumnWidth( 1, 35 ); + setLeftMargin( 0 ); + verticalHeader()->hide(); + horizontalHeader()->setLabel( 0, tr( "C." ) ); + horizontalHeader()->setLabel( 1, tr( "Prior." ) ); + horizontalHeader()->setLabel( 2, tr( "Description" ) ); + connect( this, SIGNAL( clicked( int, int, int, const QPoint & ) ), + this, SLOT( slotClicked( int, int, int, const QPoint & ) ) ); + connect( this, SIGNAL( pressed( int, int, int, const QPoint & ) ), + this, SLOT( slotPressed( int, int, int, const QPoint & ) ) ); + connect( this, SIGNAL( valueChanged( int, int ) ), + this, SLOT( slotCheckPriority( int, int ) ) ); + connect( this, SIGNAL( currentChanged( int, int ) ), + this, SLOT( slotCurrentChanged( int, int ) ) ); + + menuTimer = new QTimer( this ); + connect( menuTimer, SIGNAL(timeout()), this, SLOT(slotShowMenu()) ); +} + +void TodoTable::addEntry( const Task &todo ) +{ + int row = numRows(); + setNumRows( row + 1 ); + updateJournal( todo, ACTION_ADD ); + insertIntoTable( new Task(todo), row ); + setCurrentCell(row, currentColumn()); + updateVisible(); +} + +void TodoTable::slotClicked( int row, int col, int, const QPoint &pos ) +{ + if ( !cellGeometry( row, col ).contains(pos) ) + return; + // let's switch on the column number... + switch ( col ) + { + case 0: { + CheckItem *i = static_cast<CheckItem*>(item( row, col )); + if ( i ) { + int x = pos.x() - columnPos( col ); + int y = pos.y() - rowPos( row ); + int w = columnWidth( col ); + int h = rowHeight( row ); + if ( i && x >= ( w - BoxSize ) / 2 && x <= ( w - BoxSize ) / 2 + BoxSize && + y >= ( h - BoxSize ) / 2 && y <= ( h - BoxSize ) / 2 + BoxSize ) { + i->toggle(); + } + emit signalDoneChanged( i->isChecked() ); + } + } + break; + case 1: + break; + case 2: + // may as well edit it... + menuTimer->stop(); +// emit signalEdit(); + break; + } +} + +void TodoTable::slotPressed( int row, int col, int, const QPoint &pos ) +{ + if ( col == 2 && cellGeometry( row, col ).contains(pos) ) + menuTimer->start( 750, TRUE ); +} + +void TodoTable::slotShowMenu() +{ + emit signalShowMenu( QCursor::pos() ); +} + +void TodoTable::slotCurrentChanged( int, int ) +{ + menuTimer->stop(); +} + +void TodoTable::internalAddEntries( QList<Task> &list ) +{ + setNumRows( list.count() ); + int row = 0; + Task *it; + for ( it = list.first(); it; it = list.next() ) + insertIntoTable( it, row++ ); +} + + +Task TodoTable::currentEntry() const +{ + QTableItem *i = item( currentRow(), 0 ); + if ( !i || rowHeight( currentRow() ) <= 0 ) + return Task(); + Task *todo = todoList[(CheckItem*)i]; + todo->setCompleted( ( (CheckItem*)item( currentRow(), 0 ) )->isChecked() ); + todo->setPriority( ( (ComboItem*)item( currentRow(), 1 ) )->text().toInt() ); + return *todo; +} + +void TodoTable::replaceCurrentEntry( const Task &todo, bool fromTableItem ) +{ + int row = currentRow(); + updateJournal( todo, ACTION_REPLACE, row ); + + if ( !fromTableItem ) { + journalFreeReplaceEntry( todo, row ); + updateVisible(); + } +} + +void TodoTable::removeCurrentEntry() +{ + Task *oldTodo; + int row = currentRow(); + CheckItem *chk; + + chk = static_cast<CheckItem*>(item(row, 0 )); + if ( !chk ) + return; + oldTodo = todoList[chk]; + todoList.remove( chk ); + oldTodo->setCompleted( chk->isChecked() ); + oldTodo->setPriority( static_cast<ComboItem*>(item(row, 1))->text().toInt() ); + realignTable( row ); + updateVisible(); + updateJournal( *oldTodo, ACTION_REMOVE, row ); + delete oldTodo; +} + + +bool TodoTable::save( const QString &fn ) +{ + QString strNewFile = fn + ".new"; + QFile f( strNewFile ); + if ( !f.open( IO_WriteOnly|IO_Raw ) ) + return false; + + QString buf("<!DOCTYPE Tasks>\n<Tasks>\n"); + QCString str; + int total_written; + + for ( QMap<CheckItem*, Task *>::Iterator it = todoList.begin(); + it != todoList.end(); ++it ) { + if ( !item( it.key()->row(), 0 ) ) + continue; + Task *todo = *it; + // sync item with table + todo->setCompleted( ((CheckItem*)item(it.key()->row(), 0))->isChecked() ); + todo->setPriority( ((ComboItem*)item( it.key()->row(), 1))->text().toInt() ); + buf += "<Task"; + todo->save( buf ); + buf += " />\n"; + str = buf.utf8(); + total_written = f.writeBlock( str.data(), str.length() ); + if ( total_written != int(str.length()) ) { + f.close(); + QFile::remove( strNewFile ); + return false; + } + buf = ""; + } + + buf += "</Tasks>\n"; + str = buf.utf8(); + total_written = f.writeBlock( str.data(), str.length() ); + if ( total_written != int(str.length()) ) { + f.close(); + QFile::remove( strNewFile ); + return false; + } + f.close(); + + // now do the rename + if ( ::rename( strNewFile, fn ) < 0 ) + qWarning( "problem renaming file %s to %s errno %d", + strNewFile.latin1(), fn.latin1(), errno ); + + // remove the journal + QFile::remove( journalFileName() ); + return true; +} + +void TodoTable::load( const QString &fn ) +{ + loadFile( fn, false ); + if ( QFile::exists(journalFileName()) ) { + loadFile( journalFileName(), true ); + save( fn ); + } +// QTable::sortColumn(2,TRUE,TRUE); +// QTable::sortColumn(1,TRUE,TRUE); + QTable::sortColumn(0,TRUE,TRUE); + setCurrentCell( 0, 2 ); +} + +void TodoTable::updateVisible() +{ + if ( !isUpdatesEnabled() ) + return; + +// qDebug("--> updateVisible!"); + + int visible = 0; + int id = mCat.id( "Todo List", showCat ); + for ( int row = 0; row < numRows(); row++ ) { + CheckItem *ci = (CheckItem *)item( row, 0 ); + Task *t = todoList[ci]; + QArray<int> vlCats = t->categories(); + bool hide = false; + if ( !showComp && ci->isChecked() ) + hide = true; + if ( !showCat.isEmpty() ) { + if ( showCat == tr( "Unfiled" ) ) { + if ( vlCats.count() > 0 ) + hide = true; + } else { + // do some comparing, we have to reverse our idea here... + if ( !hide ) { + hide = true; + for ( uint it = 0; it < vlCats.count(); ++it ) { + if ( vlCats[it] == id ) { + hide = false; + break; + } + } + } + } + } + if ( hide ) { + if ( currentRow() == row ) + setCurrentCell( -1, 0 ); + if ( rowHeight( row ) > 0 ) + hideRow( row ); + } else { + if ( rowHeight( row ) == 0 ) { + showRow( row ); + adjustRow( row ); + } + visible++; + } + } + if ( !visible ) + setCurrentCell( -1, 0 ); +} + +void TodoTable::viewportPaintEvent( QPaintEvent *pe ) +{ + if ( enablePainting ) + QTable::viewportPaintEvent( pe ); +} + +void TodoTable::setPaintingEnabled( bool e ) +{ + if ( e != enablePainting ) { + if ( !enablePainting ) { + enablePainting = true; + rowHeightChanged( 0 ); + viewport()->update(); + } else { + enablePainting = false; + } + } +} + +void TodoTable::clear() +{ + for ( QMap<CheckItem*, Task *>::Iterator it = todoList.begin(); + it != todoList.end(); ++it ) { + Task *todo = *it; + delete todo; + } + todoList.clear(); + for ( int r = 0; r < numRows(); ++r ) { + for ( int c = 0; c < numCols(); ++c ) { + if ( cellWidget( r, c ) ) + clearCellWidget( r, c ); + clearCell( r, c ); + } + } + setNumRows( 0 ); +} + +void TodoTable::sortColumn( int col, bool /*ascending*/, bool /*wholeRows*/ ) +{ + // The default for wholeRows is false, however + // for this todo table we want to exchange complete + // rows when sorting. Also, we always want ascending, since + // the values have a logical order. + QTable::sortColumn( col, TRUE, TRUE ); + updateVisible(); +} + +void TodoTable::slotCheckPriority(int row, int col ) +{ + // kludgey work around to make forward along the updated priority... + if ( col == 1 ) { + // let everyone know!! + ComboItem* i = static_cast<ComboItem*>( item( row, col ) ); + emit signalPriorityChanged( i->text().toInt() ); + } +} + + +void TodoTable::updateJournal( const Task &todo, journal_action action, int row ) +{ + QFile f( journalFileName() ); + if ( !f.open(IO_WriteOnly|IO_Append) ) + return; + QString buf; + QCString str; + buf = "<Task"; + todo.save( buf ); + buf += " Action=\"" + QString::number( int(action) ) + "\""; + buf += " Row=\"" + QString::number( row ) + "\""; + buf += "/>\n"; + str = buf.utf8(); + f.writeBlock( str.data(), str.length() ); + f.close(); +} + +void TodoTable::rowHeightChanged( int row ) +{ + if ( enablePainting ) + QTable::rowHeightChanged( row ); +} + +void TodoTable::loadFile( const QString &strFile, bool fromJournal ) +{ + QFile f( strFile ); + if ( !f.open(IO_ReadOnly) ) + return; + + int action, row; + action = 0; row = 0; + + enum Attribute { + FCompleted = 0, + FHasDate, + FPriority, + FCategories, + FDescription, + FDateYear, + FDateMonth, + FDateDay, + FUid, + FAction, + FRow + }; + + QAsciiDict<int> dict( 31 ); + QList<Task> list; + dict.setAutoDelete( TRUE ); + dict.insert( "Completed", new int(FCompleted) ); + dict.insert( "HasDate", new int(FHasDate) ); + dict.insert( "Priority", new int(FPriority) ); + dict.insert( "Categories", new int(FCategories) ); + dict.insert( "Description", new int(FDescription) ); + dict.insert( "DateYear", new int(FDateYear) ); + dict.insert( "DateMonth", new int(FDateMonth) ); + dict.insert( "DateDay", new int(FDateDay) ); + dict.insert( "Uid", new int(FUid) ); + dict.insert( "Action", new int(FAction) ); + dict.insert( "Row", new int(FRow) ); + + QByteArray ba = f.readAll(); + f.close(); + char* dt = ba.data(); + int len = ba.size(); + bool hasDueDate = FALSE; + + action = ACTION_ADD; + int i = 0; + char *point; + while ( ( point = strstr( dt+i, "<Task " ) ) != NULL ) { + // new Task + i = point - dt; + Task *todo = new Task; + int dtY = 0, dtM = 0, dtD = 0; + + i += 5; + + while( 1 ) { + 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; + char *attr = dt+i; + dt[j] = '\0'; + i = ++j; // skip = + 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; + int *lookup = dict[ attr ]; + if ( !lookup ) { + todo->setCustomField(attr, value); + continue; + } + switch( *lookup ) { + case FCompleted: + todo->setCompleted( value.toInt() ); + break; + case FHasDate: + // leave... + hasDueDate = value.toInt(); + break; + case FPriority: + todo->setPriority( value.toInt() ); + break; + case FCategories: { + //QString str = Qtopia::plainString( value ); + todo->setCategories( Qtopia::Record::idsFromString( value ) ); + break; + } + case FDescription: + { + QString str = (haveUtf ? QString::fromUtf8( value ) + : QString::fromLatin1( value ) ); + if ( haveEnt ) + str = Qtopia::plainString( str ); + todo->setDescription( str ); + break; + } + case FDateYear: + dtY = value.toInt(); + break; + case FDateMonth: + dtM = value.toInt(); + break; + case FDateDay: + dtD = value.toInt(); + break; + case FUid: + todo->setUid( value.toInt() ); + break; + case FAction: + action = value.toInt(); + break; + case FRow: + row = value.toInt(); + break; + default: + qDebug( "huh??? missing enum? -- attr.: %s", attr ); + break; + } + } + + if ( dtY != 0 && dtM != 0 && dtD != 0 ) + todo->setDueDate( QDate( dtY, dtM, dtD), hasDueDate ); + else + todo->setHasDueDate( hasDueDate ); + +// if ( categoryList.find( todo.category() ) == categoryList.end() ) +// categoryList.append( todo.category() ); + + + // sadly we can't delay adding of items from the journal to get + // the proper effect, but then, the journal should _never_ be + // that huge + + switch( action ) { + case ACTION_ADD: + if ( fromJournal ) { + int myrows = numRows(); + setNumRows( myrows + 1 ); + insertIntoTable( todo, myrows ); + delete todo; + } else + list.append( todo ); + break; + case ACTION_REMOVE: + journalFreeRemoveEntry( row ); + break; + case ACTION_REPLACE: + journalFreeReplaceEntry( *todo, row ); + delete todo; + break; + default: + break; + } + } +// qDebug("parsing done=%d", t.elapsed() ); + if ( list.count() > 0 ) { + internalAddEntries( list ); + list.clear(); + } +// qDebug("loading done: t=%d", t.elapsed() ); +} + +void TodoTable::journalFreeReplaceEntry( const Task &todo, int row ) +{ + QString strTodo; + strTodo = todo.description().left(40).simplifyWhiteSpace(); + if ( row == -1 ) { + QMapIterator<CheckItem*, Task *> it; + for ( it = todoList.begin(); it != todoList.end(); ++it ) { + if ( *(*it) == todo ) { + row = it.key()->row(); + it.key()->setChecked( todo.isCompleted() ); + static_cast<ComboItem*>(item(row, 1))->setText( QString::number(todo.priority()) ); + item( row, 2 )->setText( strTodo ); + *(*it) = todo; + } + } + } else { + Task *t = todoList[static_cast<CheckItem*>(item(row, 0))]; + todoList.remove( static_cast<CheckItem*>(item(row, 0)) ); + delete t; + static_cast<CheckItem*>(item(row, 0))->setChecked( todo.isCompleted() ); + static_cast<ComboItem*>(item(row, 1))->setText( QString::number(todo.priority()) ); + item( row, 2 )->setText( strTodo ); + todoList.insert( static_cast<CheckItem*>(item(row,0)), new Task(todo) ); + } +} + +void TodoTable::journalFreeRemoveEntry( int row ) +{ + CheckItem *chk; + chk = static_cast<CheckItem*>(item(row, 0 )); + if ( !chk ) + return; + todoList.remove( chk ); + + realignTable( row ); +} + +void TodoTable::keyPressEvent( QKeyEvent *e ) +{ + if ( e->key() == Key_Space || e->key() == Key_Return ) { + switch ( currentColumn() ) { + case 0: { + CheckItem *i = static_cast<CheckItem*>(item(currentRow(), + currentColumn())); + if ( i ) + i->toggle(); + break; + } + case 1: + break; + case 2: + emit signalEdit(); + default: + break; + } + } else { + QTable::keyPressEvent( e ); + } +} + +QStringList TodoTable::categories() +{ + // This is called seldom, so calling a load in here + // should be fine. + mCat.load( categoryFileName() ); + QStringList categoryList = mCat.labels( "Todo List" ); + return categoryList; +} + +void TodoTable::slotDoFind( const QString &findString, bool caseSensitive, + bool backwards, int category ) +{ + // we have to iterate through the table, this gives the illusion that + // sorting is actually being used. + if ( currFindRow < -1 ) + currFindRow = currentRow() - 1; + clearSelection( TRUE ); + int rows, + row; + CheckItem *chk; + QRegExp r( findString ); + + r.setCaseSensitive( caseSensitive ); + rows = numRows(); + static bool wrapAround = true; + + if ( !backwards ) { + for ( row = currFindRow + 1; row < rows; row++ ) { + chk = static_cast<CheckItem*>( item(row, 0) ); + if ( taskCompare(*(todoList[chk]), r, category) ) + break; + } + } else { + for ( row = currFindRow - 1; row > -1; row-- ) { + chk = static_cast<CheckItem*>( item(row, 0) ); + if ( taskCompare(*(todoList[chk]), r, category) ) + break; + } + } + if ( row >= rows || row < 0 ) { + if ( row < 0 ) + currFindRow = rows; + else + currFindRow = -1; + if ( wrapAround ) + emit signalWrapAround(); + else + emit signalNotFound(); + wrapAround = !wrapAround; + } else { + currFindRow = row; + QTableSelection foundSelection; + foundSelection.init( currFindRow, 0 ); + foundSelection.expandTo( currFindRow, numCols() - 1 ); + addSelection( foundSelection ); + setCurrentCell( currFindRow, numCols() - 1 ); + // we should always be able to wrap around and find this again, + // so don't give confusing not found message... + wrapAround = true; + } +} + +int TodoTable::showCategoryId() const +{ + int id; + id = -1; + // if allcategories are selected, you get unfiled... + if ( showCat != tr( "Unfiled" ) && showCat != tr( "All" ) ) + id = mCat.id( "Todo List", showCat ); + return id; +} + +static bool taskCompare( const Task &task, const QRegExp &r, int category ) +{ + bool returnMe; + QArray<int> cats; + cats = task.categories(); + + returnMe = false; + if ( (category == -1 && cats.count() == 0) || category == -2 ) + returnMe = task.match( r ); + else { + int i; + for ( i = 0; i < int(cats.count()); i++ ) { + if ( cats[i] == category ) { + returnMe = task.match( r ); + break; + } + } + } + return returnMe; +} + +static QString journalFileName() +{ + QString str; + str = getenv( "HOME" ); + str += "/.todojournal"; + return str; +} + +// int TodoTable::rowHeight( int ) const +// { +// return 18; +// } + +// int TodoTable::rowPos( int row ) const +// { +// return 18*row; +// } + +// int TodoTable::rowAt( int pos ) const +// { +// return QMIN( pos/18, numRows()-1 ); +// } diff --git a/core/pim/todo/todotable.h b/core/pim/todo/todotable.h new file mode 100644 index 0000000..4f3a064 --- a/dev/null +++ b/core/pim/todo/todotable.h @@ -0,0 +1,207 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +#ifndef TODOTABLE_H +#define TODOTABLE_H + +#include <qpe/categories.h> +#include <qpe/stringutil.h> +#include <qpe/task.h> + +#include <qtable.h> +#include <qmap.h> +#include <qguardedptr.h> + +class Node; +class QComboBox; +class QTimer; + +class CheckItem : public QTableItem +{ +public: + CheckItem( QTable *t, const QString &sortkey ); + + void setChecked( bool b ); + void toggle(); + bool isChecked() const; + void setKey( const QString &key ) { sortKey = key; } + QString key() const; + + void paint( QPainter *p, const QColorGroup &cg, const QRect &cr, bool selected ); + +private: + bool checked; + QString sortKey; +}; + +class ComboItem : public QTableItem +{ +public: + ComboItem( QTable *t, EditType et ); + QWidget *createEditor() const; + void setContentFromEditor( QWidget *w ); + void setText( const QString &s ); + int alignment() const { return Qt::AlignCenter; } + + QString text() const; + +private: + QGuardedPtr<QComboBox> cb; + +}; + +class TodoTextItem : public QTableItem +{ +public: + TodoTextItem( QTable *t, const QString & str ) + :QTableItem( t, QTableItem::Never, str ) {} + + QString key () const { return Qtopia::buildSortKey( text() ); } +}; + + + +enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; + +class TodoTable : public QTable +{ + Q_OBJECT + +public: + TodoTable( QWidget *parent = 0, const char * name = 0 ); + void addEntry( const Task &todo ); + void clearFindRow() { currFindRow = -2; } + + Task currentEntry() const; + void replaceCurrentEntry( const Task &todo, bool fromTableItem = false ); + + QStringList categories(); + + void setShowCompleted( bool sc ) { showComp = sc; updateVisible(); } + bool showCompleted() const { return showComp; } + + void setShowCategory( const QString &c ) { showCat = c; updateVisible(); } + const QString &showCategory() const { return showCat; } + int showCategoryId() const; + + bool save( const QString &fn ); + void load( const QString &fn ); + void clear(); + void removeCurrentEntry(); + + void setPaintingEnabled( bool e ); + + virtual void sortColumn( int col, bool ascending, bool /*wholeRows*/ ); + +// int rowHeight( int ) const; +// int rowPos( int row ) const; +// virtual int rowAt( int pos ) const; + +signals: + void signalEdit(); + void signalDoneChanged( bool b ); + void signalPriorityChanged( int i ); + void signalShowMenu( const QPoint & ); + void signalNotFound(); + void signalWrapAround(); + +protected: + void keyPressEvent( QKeyEvent *e ); + +private: + void updateVisible(); + void viewportPaintEvent( QPaintEvent * ); + void internalAddEntries( QList<Task> &list); + inline void insertIntoTable( Task *todo, int row ); + void updateJournal( const Task &todo, journal_action action, int row = -1); + void mergeJournal(); + void journalFreeReplaceEntry( const Task &todo, int row ); + void journalFreeRemoveEntry( int row ); + inline void realignTable( int row ); + void loadFile( const QString &strFile, bool fromJournal = false ); + +private slots: + void slotClicked( int row, int col, int button, const QPoint &pos ); + void slotPressed( int row, int col, int button, const QPoint &pos ); + void slotCheckPriority(int row, int col ); + void slotCurrentChanged(int row, int col ); + void slotDoFind( const QString &findString, bool caseSensetive, + bool backwards, int category ); + void slotShowMenu(); + void rowHeightChanged( int row ); + +private: + friend class TodoWindow; + + QMap<CheckItem*, Task *> todoList; + QStringList categoryList; + bool showComp; + QString showCat; + QTimer *menuTimer; + bool enablePainting; + Categories mCat; + int currFindRow; +}; + + +inline void TodoTable::insertIntoTable( Task *todo, int row ) +{ + QString sortKey = (char) ((todo->isCompleted() ? 'a' : 'A') + + todo->priority() ) + + Qtopia::buildSortKey( todo->description() ); + CheckItem *chk = new CheckItem( this, sortKey ); + chk->setChecked( todo->isCompleted() ); + ComboItem *cmb = new ComboItem( this, QTableItem::WhenCurrent ); + cmb->setText( QString::number( todo->priority() ) ); + QTableItem *ti = new TodoTextItem( this, todo->description().left(40).simplifyWhiteSpace() ); + ti->setReplaceable( false ); + + setItem( row, 0, chk ); + setItem( row, 1, cmb ); + setItem( row, 2, ti ); + + todoList.insert( chk, todo ); +} + +inline void TodoTable::realignTable( int row ) +{ + QTableItem *ti1, + *ti2, + *ti3; + int totalRows = numRows(); + for ( int curr = row; curr < totalRows - 1; curr++ ) { + // this is bad, we must take the item out and then + // set it. In the end, it behaves no worse (time wise) + // then the old way of saving the entries to file, clearing + // the table re-reading in the file and resetting the table + ti1 = item( curr + 1, 0 ); + ti2 = item( curr + 1, 1 ); + ti3 = item( curr + 1, 2 ); + takeItem( ti1 ); + takeItem( ti2 ); + takeItem( ti3 ); + setItem( curr, 0, ti1 ); + setItem( curr, 1, ti2 ); + setItem( curr, 2, ti3 ); + } + setNumRows( totalRows - 1 ); +} + +#endif |