-rw-r--r-- | korganizer/koeventviewer.cpp | 23 | ||||
-rw-r--r-- | libkcal/kincidenceformatter.cpp | 24 | ||||
-rw-r--r-- | libkcal/recurrence.cpp | 2 | ||||
-rw-r--r-- | microkde/kdeui/ktoolbar.cpp | 2 | ||||
-rw-r--r-- | microkde/kdeui/ktoolbar.h | 2 |
5 files changed, 32 insertions, 21 deletions
diff --git a/korganizer/koeventviewer.cpp b/korganizer/koeventviewer.cpp index de11c13..39921a0 100644 --- a/korganizer/koeventviewer.cpp +++ b/korganizer/koeventviewer.cpp @@ -1,660 +1,663 @@ /* This file is part of KOrganizer. Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <qcstring.h> #include <qwhatsthis.h> #include <qdialog.h> #include <qapplication.h> #include <qlabel.h> #include <qlayout.h> #include <klocale.h> #include <kapplication.h> #include <libkcal/event.h> #include <libkcal/todo.h> #include <kdebug.h> #include <kiconloader.h> #include <krun.h> #include <kglobal.h> #include <kprocess.h> #include "koprefs.h" #include <kabc/stdaddressbook.h> #ifndef KORG_NODCOP #include <dcopclient.h> #include "korganizer.h" #include "koprefs.h" #include "actionmanager.h" #endif #include "koeventviewer.h" //#ifndef KORG_NOKABC //#include <kabc/stdaddressbook.h> //#define size count //#endif #ifdef DESKTOP_VERSION #include <kabc/addresseedialog.h> #include <kabc/addresseeview.h> #else //DESKTOP_VERSION #include <externalapphandler.h> #include <qtopia/qcopenvelope_qws.h> #endif //DESKTOP_VERSION KOEventViewer::KOEventViewer(QWidget *parent,const char *name) : QTextBrowser(parent,name) { mSyncMode = false; mColorMode = 0; } KOEventViewer::~KOEventViewer() { } void KOEventViewer::setSource(const QString& n) { if ( n.left(3) == "uid" ) #ifdef DESKTOP_VERSION { KABC::StdAddressBook* AddressBook = KABC::StdAddressBook::self( true ); KABC::AddressBook::Iterator it; for( it = AddressBook->begin(); it != AddressBook->end(); ++it ) { // LR I do not understand, why the uid string is different on zaurus and desktop QString uid = "uid://"+(*it).uid(); //qDebug("for *%s* +%s+ ", n.latin1(), uid.latin1()); if (n == uid ) { //qDebug("found %s ",(*it).mobileHomePhone().latin1() ); QDialog dia( this,"dia123", true ); dia.setCaption( i18n("Details of attendee") ); QVBoxLayout lay ( &dia ); KABC::AddresseeView av ( &dia ); av.setAddressee( (*it) ); lay.addWidget( &av ); if ( QApplication::desktop()->width() < 480 ) dia.resize( 220, 240); else { dia.resize( 400,400); } dia.exec(); break; } } return; } #else { if ( "uid:organizer" == n ) { ExternalAppHandler::instance()->requestDetailsFromKAPI("", mCurrentIncidence->organizer(),""); return; } QPtrList<Attendee> attendees = mCurrentIncidence->attendees(); if (attendees.count()) { Attendee *a; for(a=attendees.first();a;a=attendees.next()) { if ( "uid:"+a->uid() == n ) { bool res = ExternalAppHandler::instance()->requestDetailsFromKAPI(a->name(), a->email(), a->uid()); return; } } } return; } //requestNameEmailUidListFromKAPI("QPE/Application/kopi", this->name() /* name is here the unique uid*/); // the result should now arrive through method insertAttendees //QString uid = "uid:"+(*it).uid(); #endif if ( n.left(6) == "mailto" ) { // qDebug("KOEventViewer::setSource %s ", n.mid(7).latin1()); #ifndef DESKTOP_VERSION if ( n.mid(7,3) == "ALL" ) { qDebug("all "); mailToAttendees( true ); } else if ( n.mid(7,4) == "RSVP" ) { mailToAttendees( false ); qDebug("rsvp "); } else { QCopEnvelope e("QPE/Application/ompi", "newMail(QString)" ); e << n.mid(7); } #endif } #ifndef KORG_NODCOP kdDebug() << "KOEventViewer::setSource(): " << n << endl; QString tmpStr; if (n.startsWith("mailto:")) { KApplication::kApplication()->invokeMailer(n.mid(7),QString::null); //emit showIncidence(n); return; } else if (n.startsWith("uid:")) { DCOPClient *client = KApplication::kApplication()->dcopClient(); const QByteArray noParamData; const QByteArray paramData; QByteArray replyData; QCString replyTypeStr; #define PING_ABBROWSER (client->call("kaddressbook", "KAddressBookIface", "interfaces()", noParamData, replyTypeStr, replyData)) bool foundAbbrowser = PING_ABBROWSER; if (foundAbbrowser) { //KAddressbook is already running, so just DCOP to it to bring up the contact editor //client->send("kaddressbook","KAddressBookIface", QDataStream arg(paramData, IO_WriteOnly); arg << n.mid(6); client->send("kaddressbook", "KAddressBookIface", "showContactEditor( QString )", paramData); return; } else { /* KaddressBook is not already running. Pass it the UID of the contact via the command line while starting it - its neater. We start it without its main interface */ KIconLoader* iconLoader = new KIconLoader(); QString iconPath = iconLoader->iconPath("go",KIcon::Small); ActionManager::setStartedKAddressBook(true); tmpStr = "kaddressbook --editor-only --uid "; tmpStr += KProcess::quote(n.mid(6)); KRun::runCommand(tmpStr,"KAddressBook",iconPath); return; } } else { //QTextBrowser::setSource(n); } #endif } void KOEventViewer::mailToAttendees( bool all ) { QPtrList<Attendee> attendees = mCurrentIncidence->attendees(); if (attendees.count() == 0) return; QStringList nameList; QStringList emailList; QStringList uidList; Attendee* a; for(a=attendees.first();a;a=attendees.next()) { if ( !all && !a->RSVP() ) continue; if (!a->email().isEmpty()) { nameList.append (a->name() ); emailList.append (a->email() ); uidList.append (a->uid() ); } } QString uid = "ComposeMailUIpick2"+mMailSubject; #ifndef DESKTOP_VERSION bool res = ExternalAppHandler::instance()->returnNameEmailUidListFromKAPI("QPE/Application/ompi", uid, nameList, emailList, uidList); #endif } void KOEventViewer::addTag(const QString & tag,const QString & text) { int number=text.contains("\n"); QString str = "<" + tag + ">"; QString tmpText=text; QString tmpStr=str; if(number !=-1) { if (number > 0) { int pos=0; QString tmp; for(int i=0;i<=number;i++) { pos=tmpText.find("\n"); tmp=tmpText.left(pos); tmpText=tmpText.right(tmpText.length()-pos-1); tmpStr+=tmp+"<br>"; } } else tmpStr += tmpText; tmpStr+="</" + tag + ">"; mText.append(tmpStr); } else { str += text + "</" + tag + ">"; mText.append(str); } } void KOEventViewer::setColorMode( int m ) { mColorMode = m; } void KOEventViewer::appendEvent(Event *event, int mode ) { mMailSubject = ""; mCurrentIncidence = event; bool shortDate = KOPrefs::instance()->mShortDateInViewer; topLevelWidget()->setCaption(i18n("Event Viewer")); if ( mode == 0 ) { addTag("h2",event->summary()); } else { if ( mColorMode == 1 ) { mText +="<font color=\"#00A000\">"; } if ( mColorMode == 2 ) { mText +="<font color=\"#C00000\">"; } // mText +="<font color=\"#F00000\">" + i18n("O-due!") + "</font>"; if ( mode == 1 ) { addTag("h2",i18n( "Local: " ) +event->summary()); } else { addTag("h2",i18n( "Remote: " ) +event->summary()); } addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) ); if ( mColorMode ) mText += "</font>"; } mMailSubject += i18n( "Meeting " )+ event->summary(); if (event->cancelled ()) { mText +="<font color=\"#B00000\">"; addTag("i",i18n("This event has been cancelled!")); mText.append("<br>"); mText += "</font>"; mMailSubject += i18n("(cancelled)"); } if (!event->location().isEmpty()) { addTag("b",i18n("Location: ")); mText.append(event->location()+"<br>"); mMailSubject += i18n(" at ") + event->location(); } if (event->doesFloat()) { if (event->isMultiDay()) { mText.append(i18n("<p><b>From:</b> %1 </p><p><b>To:</b> %2</p>") .arg(event->dtStartDateStr(shortDate)) .arg(event->dtEndDateStr(shortDate))); } else { mText.append(i18n("<p><b>On:</b> %1</p>").arg(event->dtStartDateStr( shortDate ))); } } else { if (event->isMultiDay()) { mText.append(i18n("<p><b>From:</b> %1</p> ") .arg(event->dtStartStr( shortDate))); mText.append(i18n("<p><b>To:</b> %1</p>") .arg(event->dtEndStr(shortDate))); } else { mText.append(i18n("<p><b>On:</b> %1</p> ") .arg(event->dtStartDateStr( shortDate ))); mText.append(i18n("<p><b>From:</b> %1 <b>To:</b> %2</p>") .arg(event->dtStartTimeStr()) .arg(event->dtEndTimeStr())); } } if (event->recurrence()->doesRecur()) { QString recurText = event->recurrence()->recurrenceText(); addTag("p","<em>" + i18n("This is a %1 recurring event.").arg(recurText ) + "</em>"); - bool last; + bool ok; QDate start = QDate::currentDate(); - QDate next; - next = event->recurrence()->getPreviousDate( start , &last ); - if ( !last ) { - next = event->recurrence()->getNextDate( start.addDays( - 1 ) ); + QDateTime next; + next = event->getNextOccurence( QDateTime::currentDateTime() , &ok ); + if ( ok ) { addTag("p",i18n("<b>Next recurrence is on:</b>") ); - addTag("p", KGlobal::locale()->formatDate( next, shortDate )); - QDateTime nextdt = QDateTime( next, event->dtStart().time()); - mMailSubject += i18n(" - " )+ KGlobal::locale()->formatDateTime( nextdt, true ); + addTag("p", KGlobal::locale()->formatDate( next.date(), shortDate )); + mMailSubject += i18n(" - " )+ KGlobal::locale()->formatDateTime( next, true ); } else { - addTag("p",i18n("<b>Last recurrence was on:</b>") ); - addTag("p", KGlobal::locale()->formatDate( next, shortDate )); + bool last; + QDate nextd; + nextd = event->recurrence()->getPreviousDate( QDate::currentDate() , &last ); + if ( last ) { + addTag("p",i18n("<b>Last recurrence was on:</b>") ); + addTag("p", KGlobal::locale()->formatDate( nextd, shortDate )); + } } } else { mMailSubject += i18n(" - " )+event->dtStartStr( true ); } if (event->isAlarmEnabled()) { Alarm *alarm =event->alarms().first() ; QDateTime t = alarm->time(); int min = t.secsTo( event->dtStart() )/60; QString s =i18n("( %1 min before )").arg( min ); addTag("p",i18n("<b>Alarm on: ") + s +" </b>"); addTag("p", KGlobal::locale()->formatDateTime( t, shortDate )); //addTag("p",s); } addTag("b",i18n("Access: ")); mText.append(event->secrecyStr()+"<br>"); if (!event->description().isEmpty()) { addTag("p",i18n("<b>Details: </b>")); addTag("p",event->description()); } formatCategories(event); formatReadOnly(event); formatAttendees(event); setText(mText); //QWhatsThis::add(this,mText); } void KOEventViewer::appendTodo(Todo *event, int mode ) { mMailSubject = ""; mCurrentIncidence = event; topLevelWidget()->setCaption(i18n("Todo Viewer")); bool shortDate = KOPrefs::instance()->mShortDateInViewer; if (mode == 0 ) addTag("h2",event->summary()); else { if ( mColorMode == 1 ) { mText +="<font color=\"#00A000\">"; } if ( mColorMode == 2 ) { mText +="<font color=\"#B00000\">"; } if ( mode == 1 ) { addTag("h2",i18n( "Local: " ) +event->summary()); } else { addTag("h2",i18n( "Remote: " ) +event->summary()); } addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) ); if ( mColorMode ) mText += "</font>"; } mMailSubject += i18n( "Todo " )+ event->summary(); if ( event->percentComplete() == 100 && event->hasCompletedDate() ) { mText +="<font color=\"#B00000\">"; addTag("i", i18n("<p><i>Completed on %1</i></p>").arg( event->completedStr(KOPrefs::instance()->mShortDateInViewer) ) ); mText += "</font>"; } else { mText.append(i18n("<p><i>%1 % completed</i></p>") .arg(event->percentComplete())); } if (event->cancelled ()) { mText +="<font color=\"#B00000\">"; addTag("i",i18n("This todo has been cancelled!")); mText.append("<br>"); mText += "</font>"; mMailSubject += i18n("(cancelled)"); } if (!event->location().isEmpty()) { addTag("b",i18n("Location: ")); mText.append(event->location()+"<br>"); mMailSubject += i18n(" at ") + event->location(); } if (event->hasStartDate()) { mText.append(i18n("<p><b>Start on:</b> %1</p>").arg(event->dtStartStr(KOPrefs::instance()->mShortDateInViewer))); } if (event->hasDueDate()) { mText.append(i18n("<p><b>Due on:</b> %1</p>").arg(event->dtDueStr(KOPrefs::instance()->mShortDateInViewer))); mMailSubject += i18n(" - " )+event->dtDueStr( true ); } addTag("b",i18n("Access: ")); mText.append(event->secrecyStr()+"<br>"); if (!event->description().isEmpty()) { addTag("p",i18n("<b>Details: </b>")); addTag("p",event->description()); } formatCategories(event); mText.append(i18n("<p><b>Priority:</b> %2</p>") .arg(QString::number(event->priority()))); formatReadOnly(event); formatAttendees(event); if ( event->relatedTo() ) { addTag("b",i18n("Parent todo:<br>")); mText.append(event->relatedTo()->summary()+" [" +QString::number(event->relatedTo()->priority()) + "/" + QString::number(((Todo*)event->relatedTo())->percentComplete())+"%] <br>"); } QPtrList<Incidence> Relations = event->relations(); Incidence *to; if ( Relations.first() ) addTag("b",i18n("Sub todos:<br>")); for (to=Relations.first();to;to=Relations.next()) { mText.append( to->summary()+" [" +QString::number(to->priority()) + "/" + QString::number(((Todo*)to)->percentComplete())+"%]<br>"); } setText(mText); } void KOEventViewer::formatCategories(Incidence *event) { if (!event->categoriesStr().isEmpty()) { if (event->categories().count() == 1) { addTag("h3",i18n("Category")); } else { addTag("h3",i18n("Categories")); } addTag("p",event->categoriesStr()); } } void KOEventViewer::formatAttendees(Incidence *event) { QPtrList<Attendee> attendees = event->attendees(); if (attendees.count()) { QString iconPath = KGlobal::iconLoader()->iconPath("mailappt",KIcon::Small); QString NOiconPath = KGlobal::iconLoader()->iconPath("nomailappt",KIcon::Small); addTag("h3",i18n("Organizer")); mText.append("<ul><li>"); #ifndef KORG_NOKABC #ifdef DESKTOP_VERSION KABC::AddressBook *add_book = KABC::StdAddressBook::self(); KABC::Addressee::List addressList; addressList = add_book->findByEmail(event->organizer()); KABC::Addressee o = addressList.first(); if (!o.isEmpty() && addressList.size()<2) { mText += "<a href=\"uid:" + o.uid() + "\">"; mText += o.formattedName(); mText += "</a>\n"; } else { mText.append(event->organizer()); } #else //DESKTOP_VERSION mText += "<a href=\"uid:organizer\">"; mText += event->organizer(); mText += "</a>\n"; #endif //DESKTOP_VERSION #else mText.append(event->organizer()); #endif if (iconPath) { mText += " <a href=\"mailto:" + event->organizer() + "\">"; mText += "<IMG src=\"" + iconPath + "\">"; mText += "</a>\n"; } mText.append("</li></ul>"); addTag("h3",i18n("Attendees")); Attendee *a; mText.append("<ul>"); int a_count = 0; int a_count_nr = 0; for(a=attendees.first();a;a=attendees.next()) { #ifndef KORG_NOKABC #ifdef DESKTOP_VERSION if (a->name().isEmpty()) { addressList = add_book->findByEmail(a->email()); KABC::Addressee o = addressList.first(); if (!o.isEmpty() && addressList.size()<2) { mText += "<a href=\"uid:" + o.uid() + "\">"; mText += o.formattedName(); mText += "</a>\n"; } else { mText += "<li>"; mText.append(a->email()); mText += "\n"; } } else { mText += "<li><a href=\"uid:" + a->uid() + "\">"; if (!a->name().isEmpty()) mText += a->name(); else mText += a->email(); mText += "</a>\n"; } #else //DESKTOP_VERSION mText += "<li><a href=\"uid:" + a->uid() + "\">"; if (!a->name().isEmpty()) mText += a->name(); else mText += a->email(); mText += "</a>\n"; #endif //DESKTOP_VERSION #else //qDebug("nokabc "); mText += "<li><a href=\"uid:" + a->uid() + "\">"; if (!a->name().isEmpty()) mText += a->name(); else mText += a->email(); mText += "</a>\n"; #endif if (!a->email().isEmpty()) { if (iconPath) { mText += "<a href=\"mailto:" + a->name() +" <" + a->email() + ">:" + mMailSubject + "\">"; if ( a->RSVP() ) { ++a_count_nr; mText += "<IMG src=\"" + iconPath + "\">"; } else { ++a_count; mText += "<IMG src=\"" + NOiconPath + "\">"; } mText += "</a>\n"; } } if (a->status() != Attendee::NeedsAction ) mText +="[" + a->statusStr() + "] "; if (a->role() == Attendee::Chair ) mText +="(" + a->roleStr().left(1) + ".)"; } mText.append("</li></ul>"); if ( (a_count+a_count_nr) > 1 ) { mText += "<a href=\"mailto:ALL\">"; mText += i18n( "Mail to all" ); mText += "</a> ( "; mText += "<IMG src=\"" + iconPath + "\">"; mText += i18n( " and " ); mText += "<IMG src=\"" + NOiconPath + "\"> )"; mText += "<br>\n"; } if ( a_count_nr > 1 ) { mText += "<a href=\"mailto:RSVP\">"; mText += i18n( "Mail to selected" ); mText += "</a> ( "; mText += i18n( "<IMG src=\"%1\"> only )").arg ( iconPath ); mText += "<br>\n"; } } } void KOEventViewer::appendJournal(Journal *jour, int mode ) { bool shortDate = KOPrefs::instance()->mShortDateInViewer; if (mode == 0 ) { addTag("h2",i18n("Journal from: ")); } else { if ( mode == 1 ) { addTag("h2",i18n( "Local: " ) +i18n("Journal from: ")); } else { addTag("h2",i18n( "Remote: " ) +i18n("Journal from: ")); } } topLevelWidget()->setCaption("Journal Viewer"); mText.append(i18n("<h3> %1 </h3> ").arg(jour->dtStartDateStr(KOPrefs::instance()->mShortDateInViewer))); addTag("b",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(jour->lastModified(),shortDate ) ); if (!jour->description().isEmpty()) { addTag("p",jour->description()); } setText(mText); } void KOEventViewer::formatReadOnly(Incidence *event) { if (event->isReadOnly()) { addTag("p","<em>(" + i18n("read-only") + ")</em>"); } } void KOEventViewer::setSyncMode( bool b ) { mSyncMode = b; } void KOEventViewer::setTodo(Todo *event, bool clearV ) { if ( clearV ) clearEvents(); if ( mSyncMode ) { if ( clearV ) appendTodo(event,1 ); else appendTodo(event,2); } else appendTodo(event); } void KOEventViewer::setJournal(Journal *event, bool clearV ) { if ( clearV ) clearEvents(); if ( mSyncMode ) { if ( clearV ) appendJournal(event, 1); else appendJournal(event, 2); } else appendJournal(event); } void KOEventViewer::setEvent(Event *event) { clearEvents(); if ( mSyncMode ) appendEvent(event, 1); else appendEvent(event); } void KOEventViewer::addEvent(Event *event) { if ( mSyncMode ) appendEvent(event, 2); else appendEvent(event); } void KOEventViewer::clearEvents(bool now) { mText = ""; if (now) setText(mText); } void KOEventViewer::addText(QString text) { mText.append(text); setText(mText); } diff --git a/libkcal/kincidenceformatter.cpp b/libkcal/kincidenceformatter.cpp index 6d07d4c..0d9c3f4 100644 --- a/libkcal/kincidenceformatter.cpp +++ b/libkcal/kincidenceformatter.cpp @@ -1,338 +1,344 @@ #include "kincidenceformatter.h" #include <kstaticdeleter.h> #include <kglobal.h> #include <klocale.h> #ifdef DEKTOP_VERSION #include <kabc/stdaddressbook.h> #define size count #endif KIncidenceFormatter* KIncidenceFormatter::mInstance = 0; static KStaticDeleter<KIncidenceFormatter> insd; QString KIncidenceFormatter::getFormattedText( Incidence * inc ) { // #ifndef QT_NO_INPUTDIALOG // return QInputDialog::getItem( caption, label, items, current, editable ); // #else // return QString::null; // #endif mText = ""; if ( inc->type() == "Event" ) setEvent((Event *) inc ); else if ( inc->type() == "Todo" ) setTodo((Todo *) inc ); return mText; } KIncidenceFormatter* KIncidenceFormatter::instance() { if (!mInstance) { mInstance = insd.setObject(new KIncidenceFormatter()); } return mInstance; } KIncidenceFormatter::~KIncidenceFormatter() { if (mInstance == this) mInstance = insd.setObject(0); //qDebug("KIncidenceFormatter::~KIncidenceFormatter "); } KIncidenceFormatter::KIncidenceFormatter() { mColorMode = 0; } void KIncidenceFormatter::setEvent(Event *event) { int mode = 0; mCurrentIncidence = event; bool shortDate = true; if ( mode == 0 ) { addTag("h3",event->summary()); } else { if ( mColorMode == 1 ) { mText +="<font color=\"#00A000\">"; } if ( mColorMode == 2 ) { mText +="<font color=\"#C00000\">"; } // mText +="<font color=\"#F00000\">" + i18n("O-due!") + "</font>"; if ( mode == 1 ) { addTag("h2",i18n( "Local: " ) +event->summary()); } else { addTag("h2",i18n( "Remote: " ) +event->summary()); } addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) ); if ( mColorMode ) mText += "</font>"; } if (event->cancelled ()) { mText +="<font color=\"#B00000\">"; addTag("i",i18n("This event has been cancelled!")); mText.append("<br>"); mText += "</font>"; } if (!event->location().isEmpty()) { addTag("b",i18n("Location: ")); mText.append(event->location()+"<br>"); } if (event->doesFloat()) { if (event->isMultiDay()) { mText.append(i18n("<p><b>From:</b> %1 </p><p><b>To:</b> %2</p>") .arg(event->dtStartDateStr(shortDate)) .arg(event->dtEndDateStr(shortDate))); } else { mText.append(i18n("<p><b>On:</b> %1</p>").arg(event->dtStartDateStr( shortDate ))); } } else { if (event->isMultiDay()) { mText.append(i18n("<p><b>From:</b> %1</p> ") .arg(event->dtStartStr( shortDate))); mText.append(i18n("<p><b>To:</b> %1</p>") .arg(event->dtEndStr(shortDate))); } else { mText.append(i18n("<p><b>On:</b> %1</p> ") .arg(event->dtStartDateStr( shortDate ))); mText.append(i18n("<p><b>From:</b> %1 <b>To:</b> %2</p>") .arg(event->dtStartTimeStr()) .arg(event->dtEndTimeStr())); } } if (event->recurrence()->doesRecur()) { QString recurText = event->recurrence()->recurrenceText(); addTag("p","<em>" + i18n("This is a %1 recurring event.").arg(recurText ) + "</em>"); - bool last; + + bool ok; QDate start = QDate::currentDate(); - QDate next; - next = event->recurrence()->getPreviousDate( start , &last ); - if ( !last ) { - next = event->recurrence()->getNextDate( start.addDays( - 1 ) ); - addTag("p",i18n("Next recurrence is on: ")+ KGlobal::locale()->formatDate( next, shortDate ) ); - //addTag("p", KGlobal::locale()->formatDate( next, shortDate )); + QDateTime next; + next = event->getNextOccurence( QDateTime::currentDateTime() , &ok ); + if ( ok ) { + addTag("p",i18n("<b>Next recurrence is on:</b>") ); + addTag("p", KGlobal::locale()->formatDate( next.date(), shortDate )); + } else { - addTag("p",i18n("<b>Last recurrence was on:</b>") ); - addTag("p", KGlobal::locale()->formatDate( next, shortDate )); + bool last; + QDate nextd; + nextd = event->recurrence()->getPreviousDate( QDate::currentDate() , &last ); + if ( last ) { + addTag("p",i18n("<b>Last recurrence was on:</b>") ); + addTag("p", KGlobal::locale()->formatDate( nextd, shortDate )); + } } } if (event->isAlarmEnabled()) { Alarm *alarm =event->alarms().first() ; QDateTime t = alarm->time(); int min = t.secsTo( event->dtStart() )/60; QString s =i18n("(%1 min before)").arg( min ); addTag("p",i18n("<b>Alarm on: </b>") + s + ": "+KGlobal::locale()->formatDateTime( t, shortDate )); //addTag("p", KGlobal::locale()->formatDateTime( t, shortDate )); //addTag("p",s); } addTag("p",i18n("<b>Access: </b>") +event->secrecyStr() ); // mText.append(event->secrecyStr()+"<br>"); formatCategories(event); if (!event->description().isEmpty()) { addTag("p",i18n("<b>Details: </b>")); addTag("p",event->description()); } formatReadOnly(event); formatAttendees(event); } void KIncidenceFormatter::setTodo(Todo *event ) { int mode = 0; mCurrentIncidence = event; bool shortDate = true; if (mode == 0 ) addTag("h3",event->summary()); else { if ( mColorMode == 1 ) { mText +="<font color=\"#00A000\">"; } if ( mColorMode == 2 ) { mText +="<font color=\"#B00000\">"; } if ( mode == 1 ) { addTag("h2",i18n( "Local: " ) +event->summary()); } else { addTag("h2",i18n( "Remote: " ) +event->summary()); } addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) ); if ( mColorMode ) mText += "</font>"; } if ( event->percentComplete() == 100 && event->hasCompletedDate() ) { mText +="<font color=\"#B00000\">"; addTag("i", i18n("<p><i>Completed on %1</i></p>").arg( event->completedStr(shortDate) ) ); mText += "</font>"; } else { mText.append(i18n("<p><i>%1 % completed</i></p>") .arg(event->percentComplete())); } if (event->cancelled ()) { mText +="<font color=\"#B00000\">"; addTag("i",i18n("This todo has been cancelled!")); mText.append("<br>"); mText += "</font>"; } if (!event->location().isEmpty()) { addTag("b",i18n("Location: ")); mText.append(event->location()+"<br>"); } if (event->hasDueDate()) { mText.append(i18n("<p><b>Due on:</b> %1</p>").arg(event->dtDueStr(shortDate))); } mText.append(i18n("<p><b>Priority:</b> %2</p>") .arg(QString::number(event->priority()))); addTag("p",i18n("<b>Access: </b>") +event->secrecyStr() ); formatCategories(event); if (!event->description().isEmpty()) { addTag("p",i18n("<b>Details: </b>")); addTag("p",event->description()); } formatReadOnly(event); formatAttendees(event); } void KIncidenceFormatter::setJournal(Journal* ) { } void KIncidenceFormatter::formatCategories(Incidence *event) { if (!event->categoriesStr().isEmpty()) { addTag("p",i18n("<b>Categories: </b>")+event->categoriesStr() ); //mText.append(event->categoriesStr()); } } void KIncidenceFormatter::addTag(const QString & tag,const QString & text) { int number=text.contains("\n"); QString str = "<" + tag + ">"; QString tmpText=text; QString tmpStr=str; if(number !=-1) { if (number > 0) { int pos=0; QString tmp; for(int i=0;i<=number;i++) { pos=tmpText.find("\n"); tmp=tmpText.left(pos); tmpText=tmpText.right(tmpText.length()-pos-1); tmpStr+=tmp+"<br>"; } } else tmpStr += tmpText; tmpStr+="</" + tag + ">"; mText.append(tmpStr); } else { str += text + "</" + tag + ">"; mText.append(str); } } void KIncidenceFormatter::formatAttendees(Incidence *event) { QPtrList<Attendee> attendees = event->attendees(); if (attendees.count()) { QString iconPath = KGlobal::iconLoader()->iconPath("mailappt",KIcon::Small); QString NOiconPath = KGlobal::iconLoader()->iconPath("nomailappt",KIcon::Small); addTag("h3",i18n("Organizer")); mText.append("<ul><li>"); #if 0 //ndef KORG_NOKABC KABC::AddressBook *add_book = KABC::StdAddressBook::self(); KABC::Addressee::List addressList; addressList = add_book->findByEmail(event->organizer()); KABC::Addressee o = addressList.first(); if (!o.isEmpty() && addressList.size()<2) { mText += "<a href=\"uid:" + o.uid() + "\">"; mText += o.formattedName(); mText += "</a>\n"; } else { mText.append(event->organizer()); } #else mText.append(event->organizer()); #endif if (iconPath) { mText += " <a href=\"mailto:" + event->organizer() + "\">"; mText += "<IMG src=\"" + iconPath + "\">"; mText += "</a>\n"; } mText.append("</li></ul>"); addTag("h3",i18n("Attendees")); Attendee *a; mText.append("<ul>"); for(a=attendees.first();a;a=attendees.next()) { #if 0 //ndef KORG_NOKABC if (a->name().isEmpty()) { addressList = add_book->findByEmail(a->email()); KABC::Addressee o = addressList.first(); if (!o.isEmpty() && addressList.size()<2) { mText += "<a href=\"uid:" + o.uid() + "\">"; mText += o.formattedName(); mText += "</a>\n"; } else { mText += "<li>"; mText.append(a->email()); mText += "\n"; } } else { mText += "<li><a href=\"uid:" + a->uid() + "\">"; if (!a->name().isEmpty()) mText += a->name(); else mText += a->email(); mText += "</a>\n"; } #else //qDebug("nokabc "); mText += "<li><a href=\"uid:" + a->uid() + "\">"; if (!a->name().isEmpty()) mText += a->name(); else mText += a->email(); mText += "</a>\n"; #endif if (!a->email().isEmpty()) { if (iconPath) { mText += "<a href=\"mailto:" + a->name() +" "+ "<" + a->email() + ">" + "\">"; if ( a->RSVP() ) mText += "<IMG src=\"" + iconPath + "\">"; else mText += "<IMG src=\"" + NOiconPath + "\">"; mText += "</a>\n"; } } if (a->status() != Attendee::NeedsAction ) mText +="[" + a->statusStr() + "] "; if (a->role() == Attendee::Chair ) mText +="(" + a->roleStr().left(1) + ".)"; } mText.append("</li></ul>"); } } void KIncidenceFormatter::formatReadOnly(Incidence *event) { if (event->isReadOnly()) { addTag("p","<em>(" + i18n("read-only") + ")</em>"); } } diff --git a/libkcal/recurrence.cpp b/libkcal/recurrence.cpp index e84f672..5181eaf 100644 --- a/libkcal/recurrence.cpp +++ b/libkcal/recurrence.cpp @@ -1,3216 +1,3218 @@ /* This file is part of libkcal. Copyright (c) 1998 Preston Brown Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> Copyright (c) 2002 David Jarvie <software@astrojar.org.uk> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <limits.h> #include <kdebug.h> #include <kglobal.h> #include <klocale.h> #include "incidence.h" #include "recurrence.h" using namespace KCal; Recurrence::Feb29Type Recurrence::mFeb29YearlyDefaultType = Recurrence::rMar1; Recurrence::Recurrence(Incidence *parent, int compatVersion) : recurs(rNone), // by default, it's not a recurring event rWeekStart(1), // default is Monday rDays(7), mFloats(parent ? parent->doesFloat() : false), mRecurReadOnly(false), mRecurExDatesCount(0), mFeb29YearlyType(mFeb29YearlyDefaultType), mCompatVersion(compatVersion ? compatVersion : INT_MAX), mCompatRecurs(rNone), mCompatDuration(0), mParent(parent) { rMonthDays.setAutoDelete( true ); rMonthPositions.setAutoDelete( true ); rYearNums.setAutoDelete( true ); } Recurrence::Recurrence(const Recurrence &r, Incidence *parent) : recurs(r.recurs), rWeekStart(r.rWeekStart), rDays(r.rDays.copy()), rFreq(r.rFreq), rDuration(r.rDuration), rEndDateTime(r.rEndDateTime), mRecurStart(r.mRecurStart), mFloats(r.mFloats), mRecurReadOnly(r.mRecurReadOnly), mRecurExDatesCount(r.mRecurExDatesCount), mFeb29YearlyType(r.mFeb29YearlyType), mCompatVersion(r.mCompatVersion), mCompatRecurs(r.mCompatRecurs), mCompatDuration(r.mCompatDuration), mParent(parent) { for (QPtrListIterator<rMonthPos> mp(r.rMonthPositions); mp.current(); ++mp) { rMonthPos *tmp = new rMonthPos; tmp->rPos = mp.current()->rPos; tmp->negative = mp.current()->negative; tmp->rDays = mp.current()->rDays.copy(); rMonthPositions.append(tmp); } for (QPtrListIterator<int> md(r.rMonthDays); md.current(); ++md) { int *tmp = new int; *tmp = *md.current(); rMonthDays.append(tmp); } for (QPtrListIterator<int> yn(r.rYearNums); yn.current(); ++yn) { int *tmp = new int; *tmp = *yn.current(); rYearNums.append(tmp); } rMonthDays.setAutoDelete( true ); rMonthPositions.setAutoDelete( true ); rYearNums.setAutoDelete( true ); } Recurrence::~Recurrence() { } bool Recurrence::operator==( const Recurrence& r2 ) const { // the following line is obvious if ( recurs == rNone && r2.recurs == rNone ) return true; // we need the above line, because two non recurring events may // differ in the other settings, because one (or both) // may be not initialized properly if ( recurs != r2.recurs || rFreq != r2.rFreq || rDuration != r2.rDuration || !rDuration && rEndDateTime != r2.rEndDateTime || mRecurStart != r2.mRecurStart || mFloats != r2.mFloats || mRecurReadOnly != r2.mRecurReadOnly || mRecurExDatesCount != r2.mRecurExDatesCount ) return false; // no need to compare mCompat* and mParent // OK to compare the pointers switch ( recurs ) { case rWeekly: return rDays == r2.rDays && rWeekStart == r2.rWeekStart; case rMonthlyPos: { QPtrList<rMonthPos> MonthPositions = rMonthPositions; QPtrList<rMonthPos> MonthPositions2 = r2.rMonthPositions; if ( !MonthPositions.count() ) return false; if ( !MonthPositions2.count() ) return false; return MonthPositions.first()->rPos == MonthPositions2.first()->rPos; } case rMonthlyDay: { QPtrList<int> MonthDays = rMonthDays ; QPtrList<int> MonthDays2 = r2.rMonthDays ; if ( !MonthDays.count() ) return false; if ( !MonthDays2.count() ) return false; return *MonthDays.first() == *MonthDays2.first() ; } case rYearlyPos: { QPtrList<int> YearNums = rYearNums; QPtrList<int> YearNums2 = r2.rYearNums; if ( *YearNums.first() != *YearNums2.first() ) return false; QPtrList<rMonthPos> MonthPositions = rMonthPositions; QPtrList<rMonthPos> MonthPositions2 = r2.rMonthPositions; if ( !MonthPositions.count() ) return false; if ( !MonthPositions2.count() ) return false; return MonthPositions.first()->rPos == MonthPositions2.first()->rPos; } case rYearlyMonth: { QPtrList<int> YearNums = rYearNums; QPtrList<int> YearNums2 = r2.rYearNums; return ( *YearNums.first() == *YearNums2.first() && mFeb29YearlyType == r2.mFeb29YearlyType); } case rYearlyDay: { QPtrList<int> YearNums = rYearNums; QPtrList<int> YearNums2 = r2.rYearNums; return ( *YearNums.first() == *YearNums2.first() ); } case rNone: case rMinutely: case rHourly: case rDaily: default: return true; } } /* bool Recurrence::compareLists( const QPtrList<int> &l1 ,const QPtrList<int> &l2) { if ( l1.count() != l2.count() ) return false; int count = l1.count(); int i; for ( i = 0; i < count ; ++i ) { // if ( l1.at(i) != l2.at(i) ) return false; qDebug("compüare "); } return true; } */ QString Recurrence::recurrenceText() const { QString recurText = i18n("No"); if ( recurs == Recurrence::rMinutely ) recurText = i18n("minutely"); else if ( recurs == Recurrence::rHourly ) recurText = i18n("hourly"); else if ( recurs == Recurrence::rDaily ) recurText = i18n("daily"); else if ( recurs == Recurrence::rWeekly ) recurText = i18n("weekly"); else if ( recurs == Recurrence::rMonthlyPos ) recurText = i18n("monthly"); else if ( recurs == Recurrence::rMonthlyDay ) recurText = i18n("day-monthly"); else if ( recurs == Recurrence::rYearlyMonth ) recurText = i18n("month-yearly"); else if ( recurs == Recurrence::rYearlyDay ) recurText = i18n("day-yearly"); else if ( recurs == Recurrence::rYearlyPos ) recurText = i18n("position-yearly"); return recurText; } void Recurrence::setCompatVersion(int version) { mCompatVersion = version ? version : INT_MAX; } ushort Recurrence::doesRecur() const { return recurs; } bool Recurrence::recursOnPure(const QDate &qd) const { switch(recurs) { case rMinutely: return recursSecondly(qd, rFreq*60); case rHourly: return recursSecondly(qd, rFreq*3600); case rDaily: return recursDaily(qd); case rWeekly: return recursWeekly(qd); case rMonthlyPos: case rMonthlyDay: return recursMonthly(qd); case rYearlyMonth: return recursYearlyByMonth(qd); case rYearlyDay: return recursYearlyByDay(qd); case rYearlyPos: return recursYearlyByPos(qd); default: return false; case rNone: return false; } // case return false; } bool Recurrence::recursAtPure(const QDateTime &dt) const { switch(recurs) { case rMinutely: return recursMinutelyAt(dt, rFreq); case rHourly: return recursMinutelyAt(dt, rFreq*60); default: if (dt.time() != mRecurStart.time()) return false; switch(recurs) { case rDaily: return recursDaily(dt.date()); case rWeekly: return recursWeekly(dt.date()); case rMonthlyPos: case rMonthlyDay: return recursMonthly(dt.date()); case rYearlyMonth: return recursYearlyByMonth(dt.date()); case rYearlyDay: return recursYearlyByDay(dt.date()); case rYearlyPos: return recursYearlyByPos(dt.date()); default: return false; case rNone: return false; } } // case return false; } QDate Recurrence::endDate() const { int count = 0; QDate end; if (recurs != rNone) { if (rDuration < 0) return QDate(); // infinite recurrence if (rDuration == 0) return rEndDateTime.date(); // The end date is determined by the recurrence count QDate dStart = mRecurStart.date(); switch (recurs) { case rMinutely: return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60).date(); case rHourly: return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600).date(); case rDaily: return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq); case rWeekly: count = weeklyCalc(END_DATE_AND_COUNT, end); break; case rMonthlyPos: case rMonthlyDay: count = monthlyCalc(END_DATE_AND_COUNT, end); break; case rYearlyMonth: count = yearlyMonthCalc(END_DATE_AND_COUNT, end); break; case rYearlyDay: count = yearlyDayCalc(END_DATE_AND_COUNT, end); break; case rYearlyPos: count = yearlyPosCalc(END_DATE_AND_COUNT, end); break; default: // catch-all. Should never get here. kdDebug(5800) << "Control should never reach here in endDate()!" << endl; break; } } if (!count) return QDate(); // error - there is no recurrence return end; } QDateTime Recurrence::endDateTime() const { int count = 0; QDate end; if (recurs != rNone) { if (rDuration < 0) return QDateTime(); // infinite recurrence if (rDuration == 0) return rEndDateTime; // The end date is determined by the recurrence count QDate dStart = mRecurStart.date(); switch (recurs) { case rMinutely: return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60); case rHourly: return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600); case rDaily: return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq); case rWeekly: count = weeklyCalc(END_DATE_AND_COUNT, end); break; case rMonthlyPos: case rMonthlyDay: count = monthlyCalc(END_DATE_AND_COUNT, end); break; case rYearlyMonth: count = yearlyMonthCalc(END_DATE_AND_COUNT, end); break; case rYearlyDay: count = yearlyDayCalc(END_DATE_AND_COUNT, end); break; case rYearlyPos: count = yearlyPosCalc(END_DATE_AND_COUNT, end); break; default: // catch-all. Should never get here. kdDebug(5800) << "Control should never reach here in endDate()!" << endl; break; } } if (!count) return QDateTime(); // error - there is no recurrence return QDateTime(end, mRecurStart.time()); } int Recurrence::durationTo(const QDate &date) const { QDate d = date; return recurCalc(COUNT_TO_DATE, d); } int Recurrence::durationTo(const QDateTime &datetime) const { QDateTime dt = datetime; return recurCalc(COUNT_TO_DATE, dt); } void Recurrence::unsetRecurs() { if (mRecurReadOnly) return; recurs = rNone; rMonthPositions.clear(); rMonthDays.clear(); rYearNums.clear(); } void Recurrence::setRecurStart(const QDateTime &start) { mRecurStart = start; mFloats = false; switch (recurs) { case rMinutely: case rHourly: break; case rDaily: case rWeekly: case rMonthlyPos: case rMonthlyDay: case rYearlyMonth: case rYearlyDay: case rYearlyPos: default: rEndDateTime.setTime(start.time()); break; } } void Recurrence::setRecurStart(const QDate &start) { mRecurStart.setDate(start); mRecurStart.setTime(QTime(0,0,0)); switch (recurs) { case rMinutely: case rHourly: break; case rDaily: case rWeekly: case rMonthlyPos: case rMonthlyDay: case rYearlyMonth: case rYearlyDay: case rYearlyPos: default: mFloats = true; break; } } void Recurrence::setFloats(bool f) { switch (recurs) { case rDaily: case rWeekly: case rMonthlyPos: case rMonthlyDay: case rYearlyMonth: case rYearlyDay: case rYearlyPos: break; case rMinutely: case rHourly: default: return; // can't set sub-daily to floating } mFloats = f; if (f) { mRecurStart.setTime(QTime(0,0,0)); rEndDateTime.setTime(QTime(0,0,0)); } } int Recurrence::frequency() const { return rFreq; } int Recurrence::duration() const { return rDuration; } void Recurrence::setDuration(int _rDuration) { if (mRecurReadOnly) return; if (_rDuration > 0) { rDuration = _rDuration; // Compatibility mode is only needed when reading the calendar in ICalFormatImpl, // so explicitly setting the duration means no backwards compatibility is needed. mCompatDuration = 0; } } QString Recurrence::endDateStr(bool shortfmt) const { return KGlobal::locale()->formatDate(rEndDateTime.date(),shortfmt); } const QBitArray &Recurrence::days() const { return rDays; } const QPtrList<Recurrence::rMonthPos> &Recurrence::monthPositions() const { return rMonthPositions; } const QPtrList<Recurrence::rMonthPos> &Recurrence::yearMonthPositions() const { return rMonthPositions; } const QPtrList<int> &Recurrence::monthDays() const { return rMonthDays; } void Recurrence::setMinutely(int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; setDailySub(rMinutely, _rFreq, _rDuration); } void Recurrence::setMinutely(int _rFreq, const QDateTime &_rEndDateTime) { if (mRecurReadOnly) return; rEndDateTime = _rEndDateTime; setDailySub(rMinutely, _rFreq, 0); } void Recurrence::setHourly(int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; setDailySub(rHourly, _rFreq, _rDuration); } void Recurrence::setHourly(int _rFreq, const QDateTime &_rEndDateTime) { if (mRecurReadOnly) return; rEndDateTime = _rEndDateTime; setDailySub(rHourly, _rFreq, 0); } void Recurrence::setDaily(int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; setDailySub(rDaily, _rFreq, _rDuration); } void Recurrence::setDaily(int _rFreq, const QDate &_rEndDate) { if (mRecurReadOnly) return; rEndDateTime.setDate(_rEndDate); rEndDateTime.setTime(mRecurStart.time()); setDailySub(rDaily, _rFreq, 0); } void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays, int _rDuration, int _rWeekStart) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; recurs = rWeekly; rFreq = _rFreq; rDays = _rDays; rWeekStart = _rWeekStart; rDuration = _rDuration; if (mCompatVersion < 310 && _rDuration > 0) { // Backwards compatibility for KDE < 3.1. // rDuration was set to the number of time periods to recur, // with week start always on a Monday. // Convert this to the number of occurrences. mCompatDuration = _rDuration; int weeks = ((mCompatDuration-1+mRecurExDatesCount)*7) + (7 - mRecurStart.date().dayOfWeek()); QDate end(mRecurStart.date().addDays(weeks * rFreq)); rDuration = INT_MAX; // ensure that weeklyCalc() does its job correctly rDuration = weeklyCalc(COUNT_TO_DATE, end); } else { mCompatDuration = 0; } rMonthPositions.clear(); rMonthDays.clear(); if (mParent) mParent->updated(); } void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays, const QDate &_rEndDate, int _rWeekStart) { if (mRecurReadOnly) return; recurs = rWeekly; rFreq = _rFreq; rDays = _rDays; rWeekStart = _rWeekStart; rEndDateTime.setDate(_rEndDate); rEndDateTime.setTime(mRecurStart.time()); rDuration = 0; // set to 0 because there is an end date mCompatDuration = 0; rMonthPositions.clear(); rMonthDays.clear(); rYearNums.clear(); if (mParent) mParent->updated(); } void Recurrence::setMonthly(short type, int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; recurs = type; rFreq = _rFreq; rDuration = _rDuration; if (mCompatVersion < 310) mCompatDuration = (_rDuration > 0) ? _rDuration : 0; rYearNums.clear(); if (mParent) mParent->updated(); } void Recurrence::setMonthly(short type, int _rFreq, const QDate &_rEndDate) { if (mRecurReadOnly) return; recurs = type; rFreq = _rFreq; rEndDateTime.setDate(_rEndDate); rEndDateTime.setTime(mRecurStart.time()); rDuration = 0; // set to 0 because there is an end date mCompatDuration = 0; rYearNums.clear(); if (mParent) mParent->updated(); } void Recurrence::addMonthlyPos(short _rPos, const QBitArray &_rDays) { if (recurs == rMonthlyPos) addMonthlyPos_(_rPos, _rDays); } void Recurrence::addMonthlyPos_(short _rPos, const QBitArray &_rDays) { if (mRecurReadOnly || _rPos == 0 || _rPos > 5 || _rPos < -5) // invalid week number return; for (rMonthPos* it = rMonthPositions.first(); it; it = rMonthPositions.next()) { int itPos = it->negative ? -it->rPos : it->rPos; if (_rPos == itPos) { // This week is already in the list. // Combine the specified days with those in the list. it->rDays |= _rDays; if (mParent) mParent->updated(); return; } } // Add the new position to the list rMonthPos *tmpPos = new rMonthPos; if (_rPos > 0) { tmpPos->rPos = _rPos; tmpPos->negative = false; } else { tmpPos->rPos = -_rPos; // take abs() tmpPos->negative = true; } tmpPos->rDays = _rDays; tmpPos->rDays.detach(); rMonthPositions.append(tmpPos); if (mCompatVersion < 310 && mCompatDuration > 0) { // Backwards compatibility for KDE < 3.1. // rDuration was set to the number of time periods to recur. // Convert this to the number of occurrences. int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq; int month = mRecurStart.date().month() - 1 + monthsAhead; QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31); rDuration = INT_MAX; // ensure that recurCalc() does its job correctly rDuration = recurCalc(COUNT_TO_DATE, end); } if (mParent) mParent->updated(); } void Recurrence::addMonthlyDay(short _rDay) { if (mRecurReadOnly || (recurs != rMonthlyDay && recurs != rYearlyMonth) || _rDay == 0 || _rDay > 31 || _rDay < -31) // invalid day number return; for (int* it = rMonthDays.first(); it; it = rMonthDays.next()) { if (_rDay == *it) return; // this day is already in the list - avoid duplication } int *tmpDay = new int; *tmpDay = _rDay; rMonthDays.append(tmpDay); if (mCompatVersion < 310 && mCompatDuration > 0) { // Backwards compatibility for KDE < 3.1. // rDuration was set to the number of time periods to recur. // Convert this to the number of occurrences. int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq; int month = mRecurStart.date().month() - 1 + monthsAhead; QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31); rDuration = INT_MAX; // ensure that recurCalc() does its job correctly rDuration = recurCalc(COUNT_TO_DATE, end); } if (mParent) mParent->updated(); } void Recurrence::setYearly(int type, int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; if (mCompatVersion < 310) mCompatDuration = (_rDuration > 0) ? _rDuration : 0; setYearly_(type, mFeb29YearlyDefaultType, _rFreq, _rDuration); } void Recurrence::setYearly(int type, int _rFreq, const QDate &_rEndDate) { if (mRecurReadOnly) return; rEndDateTime.setDate(_rEndDate); rEndDateTime.setTime(mRecurStart.time()); mCompatDuration = 0; setYearly_(type, mFeb29YearlyDefaultType, _rFreq, 0); } void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; if (mCompatVersion < 310) mCompatDuration = (_rDuration > 0) ? _rDuration : 0; setYearly_(rYearlyMonth, type, _rFreq, _rDuration); } void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, const QDate &_rEndDate) { if (mRecurReadOnly) return; rEndDateTime.setDate(_rEndDate); rEndDateTime.setTime(mRecurStart.time()); mCompatDuration = 0; setYearly_(rYearlyMonth, type, _rFreq, 0); } void Recurrence::addYearlyMonthPos(short _rPos, const QBitArray &_rDays) { if (recurs == rYearlyPos) addMonthlyPos_(_rPos, _rDays); } const QPtrList<int> &Recurrence::yearNums() const { return rYearNums; } void Recurrence::addYearlyMonth(short _rPos ) { if (mRecurReadOnly || recurs != rYearlyMonth) // invalid day/month number return; rMonthPos *tmpPos = new rMonthPos; if ( _rPos > 0) { tmpPos->rPos = _rPos; tmpPos->negative = false; } else { tmpPos->rPos = -_rPos; // take abs() tmpPos->negative = true; } rMonthPositions.append(tmpPos); } void Recurrence::addYearlyNum(short _rNum) { if (mRecurReadOnly || (recurs != rYearlyMonth && recurs != rYearlyDay && recurs != rYearlyPos) || _rNum <= 0) // invalid day/month number return; if (mCompatVersion < 310 && mCompatRecurs == rYearlyDay) { // Backwards compatibility for KDE < 3.1. // Dates were stored as day numbers, with a fiddle to take account of leap years. // Convert the day number to a month. if (_rNum <= 0 || _rNum > 366 || (_rNum == 366 && mRecurStart.date().daysInYear() < 366)) return; // invalid day number _rNum = QDate(mRecurStart.date().year(), 1, 1).addDays(_rNum - 1).month(); } else if ((recurs == rYearlyMonth || recurs == rYearlyPos) && _rNum > 12 || recurs == rYearlyDay && _rNum > 366) return; // invalid day number uint i = 0; for (int* it = rYearNums.first(); it && _rNum >= *it; it = rYearNums.next()) { if (_rNum == *it) return; // this day/month is already in the list - avoid duplication ++i; } int *tmpNum = new int; *tmpNum = _rNum; rYearNums.insert(i, tmpNum); // insert the day/month in a sorted position if (mCompatVersion < 310 && mCompatDuration > 0) { // Backwards compatibility for KDE < 3.1. // rDuration was set to the number of time periods to recur. // Convert this to the number of occurrences. QDate end(mRecurStart.date().year() + (mCompatDuration-1+mRecurExDatesCount)*rFreq, 12, 31); rDuration = INT_MAX; // ensure that recurCalc() does its job correctly rDuration = recurCalc(COUNT_TO_DATE, end); } if (mParent) mParent->updated(); } QDateTime Recurrence::getNextDateTime(const QDateTime &preDateTime, bool *last) const { if (last) *last = false; int freq; switch (recurs) { case rMinutely: freq = rFreq * 60; break; case rHourly: freq = rFreq * 3600; break; case rDaily: case rWeekly: case rMonthlyPos: case rMonthlyDay: case rYearlyMonth: case rYearlyDay: case rYearlyPos: { QDate preDate = preDateTime.date(); if (!mFloats && mRecurStart.time() > preDateTime.time()) preDate = preDate.addDays(-1); return QDateTime(getNextDateNoTime(preDate, last), mRecurStart.time()); } default: return QDateTime(); } // It's a sub-daily recurrence if (preDateTime < mRecurStart) return mRecurStart; int count = mRecurStart.secsTo(preDateTime) / freq + 2; if (rDuration > 0) { if (count > rDuration) return QDateTime(); if (last && count == rDuration) *last = true; } QDateTime endtime = mRecurStart.addSecs((count - 1)*freq); if (rDuration == 0) { if (endtime > rEndDateTime) return QDateTime(); if (last && endtime == rEndDateTime) *last = true; } return endtime; } QDate Recurrence::getNextDate(const QDate &preDate, bool *last) const { if (last) *last = false; switch (recurs) { case rMinutely: case rHourly: return getNextDateTime(QDateTime(preDate, QTime(23,59,59)), last).date(); case rDaily: case rWeekly: case rMonthlyPos: case rMonthlyDay: case rYearlyMonth: case rYearlyDay: case rYearlyPos: + qDebug("Recurrence::getNextDate: MAY BE BROKEN "); return getNextDateNoTime(preDate, last); default: return QDate(); } } QDateTime Recurrence::getPreviousDateTime(const QDateTime &afterDateTime, bool *last) const { if (last) *last = false; int freq; switch (recurs) { case rMinutely: freq = rFreq * 60; break; case rHourly: freq = rFreq * 3600; break; case rDaily: case rWeekly: case rMonthlyPos: case rMonthlyDay: case rYearlyMonth: case rYearlyDay: case rYearlyPos: { QDate afterDate = afterDateTime.date(); if (!mFloats && mRecurStart.time() < afterDateTime.time()) afterDate = afterDate.addDays(1); return QDateTime(getPreviousDateNoTime(afterDate, last), mRecurStart.time()); } default: return QDateTime(); } // It's a sub-daily recurrence if (afterDateTime <= mRecurStart) return QDateTime(); int count = (mRecurStart.secsTo(afterDateTime) - 1) / freq + 1; if (rDuration > 0) { if (count > rDuration) count = rDuration; if (last && count == rDuration) *last = true; } QDateTime endtime = mRecurStart.addSecs((count - 1)*freq); if (rDuration == 0) { if (endtime > rEndDateTime) endtime = rEndDateTime; if (last && endtime == rEndDateTime) *last = true; } return endtime; } QDate Recurrence::getPreviousDate(const QDate &afterDate, bool *last) const { if (last) *last = false; switch (recurs) { case rMinutely: case rHourly: return getPreviousDateTime(QDateTime(afterDate, QTime(0,0,0)), last).date(); case rDaily: case rWeekly: case rMonthlyPos: case rMonthlyDay: case rYearlyMonth: case rYearlyDay: case rYearlyPos: return getPreviousDateNoTime(afterDate, last); default: return QDate(); } } /***************************** PROTECTED FUNCTIONS ***************************/ bool Recurrence::recursSecondly(const QDate &qd, int secondFreq) const { if ((qd >= mRecurStart.date()) && ((rDuration > 0) && (qd <= endDate()) || ((rDuration == 0) && (qd <= rEndDateTime.date())) || (rDuration == -1))) { // The date queried falls within the range of the event. if (secondFreq < 24*3600) return true; // the event recurs at least once each day int after = mRecurStart.secsTo(QDateTime(qd)); if (after / secondFreq != (after + 24*3600) / secondFreq) return true; } return false; } bool Recurrence::recursMinutelyAt(const QDateTime &dt, int minuteFreq) const { if ((dt >= mRecurStart) && ((rDuration > 0) && (dt <= endDateTime()) || ((rDuration == 0) && (dt <= rEndDateTime)) || (rDuration == -1))) { // The time queried falls within the range of the event. if (((mRecurStart.secsTo(dt) / 60) % minuteFreq) == 0) return true; } return false; } bool Recurrence::recursDaily(const QDate &qd) const { QDate dStart = mRecurStart.date(); if ((dStart.daysTo(qd) % rFreq) == 0) { // The date is a day which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. return true; } } return false; } bool Recurrence::recursWeekly(const QDate &qd) const { QDate dStart = mRecurStart.date(); if ((dStart.daysTo(qd)/7) % rFreq == 0) { // The date is in a week which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. // check if the bits set match today. int i = qd.dayOfWeek()-1; if (rDays.testBit((uint) i)) return true; } } return false; } bool Recurrence::recursMonthly(const QDate &qd) const { QDate dStart = mRecurStart.date(); int year = qd.year(); int month = qd.month(); int day = qd.day(); // calculate how many months ahead this date is from the original // event's date int monthsAhead = (year - dStart.year()) * 12 + (month - dStart.month()); if ((monthsAhead % rFreq) == 0) { // The date is in a month which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. QValueList<int> days; int daysInMonth = qd.daysInMonth(); if (recurs == rMonthlyDay) getMonthlyDayDays(days, daysInMonth); else if (recurs == rMonthlyPos) getMonthlyPosDays(days, daysInMonth, QDate(year, month, 1).dayOfWeek()); for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) { if (*it == day) return true; } // no dates matched } } return false; } bool Recurrence::recursYearlyByMonth(const QDate &qd) const { QDate dStart = mRecurStart.date(); int startDay = dStart.day(); int qday = qd.day(); int qmonth = qd.month(); int qyear = qd.year(); bool match = (qday == startDay); if (!match && startDay == 29 && dStart.month() == 2) { // It's a recurrence on February 29th switch (mFeb29YearlyType) { case rFeb28: if (qday == 28 && qmonth == 2 && !QDate::leapYear(qyear)) match = true; break; case rMar1: if (qday == 1 && qmonth == 3 && !QDate::leapYear(qyear)) { qmonth = 2; match = true; } break; case rFeb29: break; } } if (match) { // The day of the month matches. Calculate how many years ahead // this date is from the original event's date. int yearsAhead = (qyear - dStart.year()); if (yearsAhead % rFreq == 0) { // The date is in a year which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. int i = qmonth; for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { if (i == *qlin.current()) return true; } } } } return false; } bool Recurrence::recursYearlyByPos(const QDate &qd) const { QDate dStart = mRecurStart.date(); int year = qd.year(); int month = qd.month(); int day = qd.day(); // calculate how many years ahead this date is from the original // event's date int yearsAhead = (year - dStart.year()); if (yearsAhead % rFreq == 0) { // The date is in a year which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { if (month == *qlin.current()) { // The month recurs QValueList<int> days; getMonthlyPosDays(days, qd.daysInMonth(), QDate(year, month, 1).dayOfWeek()); for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) { if (*it == day) return true; } } } } } return false; } bool Recurrence::recursYearlyByDay(const QDate &qd) const { QDate dStart = mRecurStart.date(); // calculate how many years ahead this date is from the original // event's date int yearsAhead = (qd.year() - dStart.year()); if (yearsAhead % rFreq == 0) { // The date is in a year which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. int i = qd.dayOfYear(); for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { if (i == *qlin.current()) return true; } } } return false; } /* Get the date of the next recurrence, after the specified date. * If 'last' is non-null, '*last' is set to true if the next recurrence is the * last recurrence, else false. * Reply = date of next recurrence, or invalid date if none. */ QDate Recurrence::getNextDateNoTime(const QDate &preDate, bool *last) const { + if (last) *last = false; QDate dStart = mRecurStart.date(); if (preDate < dStart) return dStart; QDate earliestDate = preDate.addDays(1); QDate nextDate; switch (recurs) { case rDaily: nextDate = dStart.addDays((dStart.daysTo(preDate)/rFreq + 1) * rFreq); break; case rWeekly: { QDate start = dStart.addDays(1 - dStart.dayOfWeek()); // start of week for dStart int earliestDayOfWeek = earliestDate.dayOfWeek(); int weeksAhead = start.daysTo(earliestDate) / 7; int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week weeksAhead -= notThisWeek; // latest week which recurred int weekday = 0; // First check for any remaining day this week, if this week is a recurring week if (!notThisWeek) weekday = getFirstDayInWeek(earliestDayOfWeek); // Check for a day in the next scheduled week if (!weekday && earliestDayOfWeek > 1) weekday = getFirstDayInWeek(rWeekStart) + rFreq*7; if (weekday) nextDate = start.addDays(weeksAhead*7 + weekday - 1); break; } case rMonthlyDay: case rMonthlyPos: { int startYear = dStart.year(); int startMonth = dStart.month(); // 1..12 int earliestYear = earliestDate.year(); int monthsAhead = (earliestYear - startYear)*12 + earliestDate.month() - startMonth; int notThisMonth = monthsAhead % rFreq; // zero if this month is a recurring month monthsAhead -= notThisMonth; // latest month which recurred // Check for the first later day in the current month if (!notThisMonth) nextDate = getFirstDateInMonth(earliestDate); if (!nextDate.isValid() && earliestDate.day() > 1) { // Check for a day in the next scheduled month int months = startMonth - 1 + monthsAhead + rFreq; nextDate = getFirstDateInMonth(QDate(startYear + months/12, months%12 + 1, 1)); } break; } case rYearlyMonth: case rYearlyPos: case rYearlyDay: { int startYear = dStart.year(); int yearsAhead = earliestDate.year() - startYear; int notThisYear = yearsAhead % rFreq; // zero if this year is a recurring year yearsAhead -= notThisYear; // latest year which recurred // Check for the first later date in the current year if (!notThisYear) nextDate = getFirstDateInYear(earliestDate); // Check for a date in the next scheduled year if (!nextDate.isValid() && earliestDate.dayOfYear() > 1) nextDate = getFirstDateInYear(QDate(startYear + yearsAhead + rFreq, 1, 1)); break; } case rNone: default: return QDate(); } if (rDuration >= 0 && nextDate.isValid()) { // Check that the date found is within the range of the recurrence QDate end = endDate(); if (nextDate > end) return QDate(); if (last && nextDate == end) *last = true; } return nextDate; } /* Get the date of the last previous recurrence, before the specified date. * Reply = date of previous recurrence, or invalid date if none. */ QDate Recurrence::getPreviousDateNoTime(const QDate &afterDate, bool *last) const { if (last) *last = false; QDate dStart = mRecurStart.date(); QDate latestDate = afterDate.addDays(-1); if (latestDate < dStart) return QDate(); QDate prevDate; switch (recurs) { case rDaily: prevDate = dStart.addDays((dStart.daysTo(latestDate) / rFreq) * rFreq); break; case rWeekly: { QDate start = dStart.addDays(1 - dStart.dayOfWeek()); // start of week for dStart int latestDayOfWeek = latestDate.dayOfWeek(); int weeksAhead = start.daysTo(latestDate) / 7; int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week weeksAhead -= notThisWeek; // latest week which recurred int weekday = 0; // First check for any previous day this week, if this week is a recurring week if (!notThisWeek) weekday = getLastDayInWeek(latestDayOfWeek); // Check for a day in the previous scheduled week if (!weekday) { int weekEnd = (rWeekStart + 5)%7 + 1; if (latestDayOfWeek < weekEnd) { if (!notThisWeek) weeksAhead -= rFreq; weekday = getLastDayInWeek(weekEnd); } } if (weekday) prevDate = start.addDays(weeksAhead*7 + weekday - 1); break; } case rMonthlyDay: case rMonthlyPos: { int startYear = dStart.year(); int startMonth = dStart.month(); // 1..12 int latestYear = latestDate.year(); int monthsAhead = (latestYear - startYear)*12 + latestDate.month() - startMonth; int notThisMonth = monthsAhead % rFreq; // zero if this month is a recurring month monthsAhead -= notThisMonth; // latest month which recurred // Check for the last earlier day in the current month if (!notThisMonth) prevDate = getLastDateInMonth(latestDate); if (!prevDate.isValid() && latestDate.day() < latestDate.daysInMonth()) { // Check for a day in the previous scheduled month if (!notThisMonth) monthsAhead -= rFreq; int months = startMonth + monthsAhead; // get the month after the one that recurs prevDate = getLastDateInMonth(QDate(startYear + months/12, months%12 + 1, 1).addDays(-1)); } break; } case rYearlyMonth: case rYearlyPos: case rYearlyDay: { int startYear = dStart.year(); int yearsAhead = latestDate.year() - startYear; int notThisYear = yearsAhead % rFreq; // zero if this year is a recurring year yearsAhead -= notThisYear; // latest year which recurred // Check for the first later date in the current year if (!notThisYear) prevDate = getLastDateInYear(latestDate); if (!prevDate.isValid() && latestDate.dayOfYear() < latestDate.daysInYear()) { // Check for a date in the next scheduled year if (!notThisYear) yearsAhead -= rFreq; prevDate = getLastDateInYear(QDate(startYear + yearsAhead, 12, 31)); } break; } case rNone: default: return QDate(); } if (prevDate.isValid()) { // Check that the date found is within the range of the recurrence if (prevDate < dStart) return QDate(); if (rDuration >= 0) { QDate end = endDate(); if (prevDate >= end) { if (last) *last = true; return end; } } } return prevDate; } void Recurrence::setDailySub(short type, int freq, int duration) { recurs = type; rFreq = freq; rDuration = duration; rMonthPositions.clear(); rMonthDays.clear(); rYearNums.clear(); if (type != rDaily) mFloats = false; // sub-daily types can't be floating if (mParent) mParent->updated(); } void Recurrence::setYearly_(short type, Feb29Type feb29type, int freq, int duration) { recurs = type; if (mCompatVersion < 310 && type == rYearlyDay) { mCompatRecurs = rYearlyDay; recurs = rYearlyMonth; // convert old yearly-by-day to yearly-by-month feb29type = rMar1; // retain the same day number in the year } mFeb29YearlyType = feb29type; rFreq = freq; rDuration = duration; if (type != rYearlyPos) rMonthPositions.clear(); rMonthDays.clear(); if (mParent) mParent->updated(); } int Recurrence::recurCalc(PeriodFunc func, QDateTime &endtime) const { QDate enddate = endtime.date(); switch (func) { case END_DATE_AND_COUNT: if (rDuration < 0) { endtime = QDateTime(); return 0; // infinite recurrence } if (rDuration == 0) { endtime = rEndDateTime; func = COUNT_TO_DATE; } break; case COUNT_TO_DATE: // Count recurrences up to and including the specified date/time. if (endtime < mRecurStart) return 0; if (rDuration == 0 && endtime > rEndDateTime) enddate = rEndDateTime.date(); else if (!mFloats && mRecurStart.time() > endtime.time()) enddate = enddate.addDays(-1); break; case NEXT_AFTER_DATE: // Find next recurrence AFTER endtime if (endtime < mRecurStart) { endtime = mRecurStart; return 1; } if (rDuration == 0 && endtime >= rEndDateTime) { endtime = QDateTime(); return 0; } if (!mFloats && mRecurStart.time() > endtime.time()) enddate = enddate.addDays(-1); break; default: endtime = QDateTime(); return 0; } int count = 0; // default = error bool timed = false; switch (recurs) { case rMinutely: timed = true; count = secondlyCalc(func, endtime, rFreq*60); break; case rHourly: timed = true; count = secondlyCalc(func, endtime, rFreq*3600); break; case rDaily: count = dailyCalc(func, enddate); break; case rWeekly: count = weeklyCalc(func, enddate); break; case rMonthlyPos: case rMonthlyDay: count = monthlyCalc(func, enddate); break; case rYearlyMonth: count = yearlyMonthCalc(func, enddate); break; case rYearlyPos: count = yearlyPosCalc(func, enddate); break; case rYearlyDay: count = yearlyDayCalc(func, enddate); break; default: break; } switch (func) { case END_DATE_AND_COUNT: case NEXT_AFTER_DATE: if (count == 0) endtime = QDateTime(); else if (!timed) { endtime.setDate(enddate); endtime.setTime(mRecurStart.time()); } break; case COUNT_TO_DATE: break; } return count; } int Recurrence::recurCalc(PeriodFunc func, QDate &enddate) const { QDateTime endtime(enddate, QTime(23,59,59)); switch (func) { case END_DATE_AND_COUNT: if (rDuration < 0) { enddate = QDate(); return 0; // infinite recurrence } if (rDuration == 0) { enddate = rEndDateTime.date(); func = COUNT_TO_DATE; } break; case COUNT_TO_DATE: // Count recurrences up to and including the specified date. if (enddate < mRecurStart.date()) return 0; if (rDuration == 0 && enddate > rEndDateTime.date()) { enddate = rEndDateTime.date(); endtime.setDate(enddate); } break; case NEXT_AFTER_DATE: if (enddate < mRecurStart.date()) { enddate = mRecurStart.date(); return 1; } if (rDuration == 0 && enddate >= rEndDateTime.date()) { enddate = QDate(); return 0; } break; default: enddate = QDate(); return 0; } int count = 0; // default = error bool timed = false; switch (recurs) { case rMinutely: timed = true; count = secondlyCalc(func, endtime, rFreq*60); break; case rHourly: timed = true; count = secondlyCalc(func, endtime, rFreq*3600); break; case rDaily: count = dailyCalc(func, enddate); break; case rWeekly: count = weeklyCalc(func, enddate); break; case rMonthlyPos: case rMonthlyDay: count = monthlyCalc(func, enddate); break; case rYearlyMonth: count = yearlyMonthCalc(func, enddate); break; case rYearlyPos: count = yearlyPosCalc(func, enddate); break; case rYearlyDay: count = yearlyDayCalc(func, enddate); break; default: break; } switch (func) { case END_DATE_AND_COUNT: case NEXT_AFTER_DATE: if (count == 0) endtime = QDate(); else if (timed) enddate = endtime.date(); break; case COUNT_TO_DATE: break; } return count; } /* Find count and, depending on 'func', the end date/time of a secondly recurrence. * Reply = total number of occurrences up to 'endtime', or 0 if error. * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'endtime' is updated to the * recurrence end date/time. */ int Recurrence::secondlyCalc(PeriodFunc func, QDateTime &endtime, int freq) const { switch (func) { case END_DATE_AND_COUNT: endtime = mRecurStart.addSecs((rDuration + mRecurExDatesCount - 1) * freq); return rDuration + mRecurExDatesCount; case COUNT_TO_DATE: { int n = mRecurStart.secsTo(endtime)/freq + 1; if (rDuration > 0 && n > rDuration + mRecurExDatesCount) return rDuration + mRecurExDatesCount; return n; } case NEXT_AFTER_DATE: { int count = mRecurStart.secsTo(endtime) / freq + 2; if (rDuration > 0 && count > rDuration) return 0; endtime = mRecurStart.addSecs((count - 1)*freq); return count; } } return 0; } /* Find count and, depending on 'func', the end date of a daily recurrence. * Reply = total number of occurrences up to 'enddate', or 0 if error. * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the * recurrence end date. */ int Recurrence::dailyCalc(PeriodFunc func, QDate &enddate) const { QDate dStart = mRecurStart.date(); switch (func) { case END_DATE_AND_COUNT: enddate = dStart.addDays((rDuration + mRecurExDatesCount - 1) * rFreq); return rDuration + mRecurExDatesCount; case COUNT_TO_DATE: { int n = dStart.daysTo(enddate)/rFreq + 1; if (rDuration > 0 && n > rDuration + mRecurExDatesCount) return rDuration + mRecurExDatesCount; return n; } case NEXT_AFTER_DATE: { int count = dStart.daysTo(enddate) / rFreq + 2; if (rDuration > 0 && count > rDuration) return 0; enddate = dStart.addDays((count - 1)*rFreq); return count; } } return 0; } /* Find count and, depending on 'func', the end date of a weekly recurrence. * Reply = total number of occurrences up to 'enddate', or 0 if error. * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the * recurrence end date. */ int Recurrence::weeklyCalc(PeriodFunc func, QDate &enddate) const { int daysPerWeek = 0; for (int i = 0; i < 7; ++i) { if (rDays.testBit((uint)i)) ++daysPerWeek; } if (!daysPerWeek) return 0; // there are no days to recur on switch (func) { case END_DATE_AND_COUNT: return weeklyCalcEndDate(enddate, daysPerWeek); case COUNT_TO_DATE: return weeklyCalcToDate(enddate, daysPerWeek); case NEXT_AFTER_DATE: return weeklyCalcNextAfter(enddate, daysPerWeek); } return 0; } int Recurrence::weeklyCalcEndDate(QDate &enddate, int daysPerWeek) const { int startDayOfWeek = mRecurStart.date().dayOfWeek(); // 1..7 int countGone = 0; int daysGone = 0; uint countTogo = rDuration + mRecurExDatesCount; if (startDayOfWeek != rWeekStart) { // Check what remains of the start week for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) { ++daysGone; if (rDays.testBit((uint)i)) { ++countGone; if (--countTogo == 0) break; } } daysGone += 7 * (rFreq - 1); } if (countTogo) { // Skip the remaining whole weeks // Leave at least 1 recurrence remaining, in order to get its date int wholeWeeks = (countTogo - 1) / daysPerWeek; daysGone += wholeWeeks * 7 * rFreq; countGone += wholeWeeks * daysPerWeek; countTogo -= wholeWeeks * daysPerWeek; // Check the last week in the recurrence for (int i = rWeekStart - 1; ; i = (i + 1) % 7) { ++daysGone; if (rDays.testBit((uint)i)) { ++countGone; if (--countTogo == 0) break; } } } enddate = mRecurStart.date().addDays(daysGone); return countGone; } int Recurrence::weeklyCalcToDate(const QDate &enddate, int daysPerWeek) const { QDate dStart = mRecurStart.date(); int startDayOfWeek = dStart.dayOfWeek(); // 1..7 int countGone = 0; int daysGone = 0; int totalDays = dStart.daysTo(enddate) + 1; int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; if (startDayOfWeek != rWeekStart) { // Check what remains of the start week for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) { if (rDays.testBit((uint)i)) { if (++countGone >= countMax) return countMax; } if (++daysGone == totalDays) return countGone; } daysGone += 7 * (rFreq - 1); if (daysGone >= totalDays) return countGone; } // Skip the remaining whole weeks int wholeWeeks = (totalDays - daysGone) / 7; countGone += (wholeWeeks / rFreq) * daysPerWeek; if (countGone >= countMax) return countMax; daysGone += wholeWeeks * 7; if (daysGone >= totalDays // have we reached the end date? || wholeWeeks % rFreq) // is end week a recurrence week? return countGone; // Check the last week in the recurrence for (int i = rWeekStart - 1; ; i = (i + 1) % 7) { if (rDays.testBit((uint)i)) { if (++countGone >= countMax) return countMax; } if (++daysGone == totalDays) return countGone; } return countGone; } int Recurrence::weeklyCalcNextAfter(QDate &enddate, int daysPerWeek) const { QDate dStart = mRecurStart.date(); int startDayOfWeek = dStart.dayOfWeek(); // 1..7 int totalDays = dStart.daysTo(enddate) + 1; uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; int countGone = 0; int daysGone = 0; int recurWeeks; if (startDayOfWeek != rWeekStart) { // Check what remains of the start week for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) { ++daysGone; if (rDays.testBit((uint)i)) { ++countGone; if (daysGone > totalDays) goto ex; if (--countTogo == 0) return 0; } } daysGone += 7 * (rFreq - 1); } // Skip the remaining whole weeks recurWeeks = (totalDays - daysGone) / (7 * rFreq); if (recurWeeks) { int n = recurWeeks * daysPerWeek; if (static_cast<uint>(n) > countTogo) return 0; // reached end of recurrence countGone += n; countTogo -= n; daysGone += recurWeeks * 7 * rFreq; } // Check the last week or two in the recurrence for ( ; ; ) { for (int i = rWeekStart - 1; ; i = (i + 1) % 7) { ++daysGone; if (rDays.testBit((uint)i)) { ++countGone; if (daysGone > totalDays) goto ex; if (--countTogo == 0) return 0; } } daysGone += 7 * (rFreq - 1); } ex: enddate = dStart.addDays(daysGone); return countGone; } /* Find count and, depending on 'func', the end date of a monthly recurrence. * Reply = total number of occurrences up to 'enddate', or 0 if error. * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the * recurrence end date. */ struct Recurrence::MonthlyData { const Recurrence *recurrence; int year; // current year int month; // current month 0..11 int day; // current day of month 1..31 bool varies; // true if recurring days vary between different months private: QValueList<int> days28, days29, days30, days31; // recurring days in months of each length QValueList<int> *recurDays[4]; public: MonthlyData(const Recurrence* r, const QDate &date) : recurrence(r), year(date.year()), month(date.month()-1), day(date.day()) { recurDays[0] = &days28; recurDays[1] = &days29; recurDays[2] = &days30; recurDays[3] = &days31; varies = (recurrence->recurs == rMonthlyPos) ? true : recurrence->getMonthlyDayDays(days31, 31); } const QValueList<int>* dayList() const { if (!varies) return &days31; QDate startOfMonth(year, month + 1, 1); int daysInMonth = startOfMonth.daysInMonth(); QValueList<int>* days = recurDays[daysInMonth - 28]; if (recurrence->recurs == rMonthlyPos) recurrence->getMonthlyPosDays(*days, daysInMonth, startOfMonth.dayOfWeek()); else if (days->isEmpty()) recurrence->getMonthlyDayDays(*days, daysInMonth); return days; } int yearMonth() const { return year*12 + month; } void addMonths(int diff) { month += diff; year += month / 12; month %= 12; } QDate date() const { return QDate(year, month + 1, day); } }; int Recurrence::monthlyCalc(PeriodFunc func, QDate &enddate) const { if (recurs == rMonthlyPos && rMonthPositions.isEmpty() || recurs == rMonthlyDay && rMonthDays.isEmpty()) return 0; MonthlyData data(this, mRecurStart.date()); switch (func) { case END_DATE_AND_COUNT: return monthlyCalcEndDate(enddate, data); case COUNT_TO_DATE: return monthlyCalcToDate(enddate, data); case NEXT_AFTER_DATE: return monthlyCalcNextAfter(enddate, data); } return 0; } int Recurrence::monthlyCalcEndDate(QDate &enddate, MonthlyData &data) const { uint countTogo = rDuration + mRecurExDatesCount; int countGone = 0; QValueList<int>::ConstIterator it; const QValueList<int>* days = data.dayList(); if (data.day > 1) { // Check what remains of the start month for (it = days->begin(); it != days->end(); ++it) { if (*it >= data.day) { ++countGone; if (--countTogo == 0) { data.day = *it; break; } } } if (countTogo) { data.day = 1; data.addMonths(rFreq); } } if (countTogo) { if (data.varies) { // The number of recurrence days varies from month to month, // so we need to check month by month. for ( ; ; ) { days = data.dayList(); uint n = days->count(); // number of recurrence days in this month if (n >= countTogo) break; countTogo -= n; countGone += n; data.addMonths(rFreq); } } else { // The number of recurrences is the same every month, // so skip the month-by-month check. // Skip the remaining whole months, but leave at least // 1 recurrence remaining, in order to get its date. int daysPerMonth = days->count(); int wholeMonths = (countTogo - 1) / daysPerMonth; data.addMonths(wholeMonths * rFreq); countGone += wholeMonths * daysPerMonth; countTogo -= wholeMonths * daysPerMonth; } if (countTogo) { // Check the last month in the recurrence for (it = days->begin(); it != days->end(); ++it) { ++countGone; if (--countTogo == 0) { data.day = *it; break; } } } } enddate = data.date(); return countGone; } int Recurrence::monthlyCalcToDate(const QDate &enddate, MonthlyData &data) const { int countGone = 0; int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; int endYear = enddate.year(); int endMonth = enddate.month() - 1; // zero-based int endDay = enddate.day(); int endYearMonth = endYear*12 + endMonth; QValueList<int>::ConstIterator it; const QValueList<int>* days = data.dayList(); if (data.day > 1) { // Check what remains of the start month for (it = days->begin(); it != days->end(); ++it) { if (*it >= data.day) { if (data.yearMonth() == endYearMonth && *it > endDay) return countGone; if (++countGone >= countMax) return countMax; } } data.day = 1; data.addMonths(rFreq); } if (data.varies) { // The number of recurrence days varies from month to month, // so we need to check month by month. while (data.yearMonth() < endYearMonth) { countGone += data.dayList()->count(); if (countGone >= countMax) return countMax; data.addMonths(rFreq); } days = data.dayList(); } else { // The number of recurrences is the same every month, // so skip the month-by-month check. // Skip the remaining whole months. int daysPerMonth = days->count(); int wholeMonths = endYearMonth - data.yearMonth(); countGone += (wholeMonths / rFreq) * daysPerMonth; if (countGone >= countMax) return countMax; if (wholeMonths % rFreq) return countGone; // end year isn't a recurrence year data.year = endYear; data.month = endMonth; } // Check the last month in the recurrence for (it = days->begin(); it != days->end(); ++it) { if (*it > endDay) return countGone; if (++countGone >= countMax) return countMax; } return countGone; } int Recurrence::monthlyCalcNextAfter(QDate &enddate, MonthlyData &data) const { uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; int countGone = 0; int endYear = enddate.year(); int endDay = enddate.day(); int endYearMonth = endYear*12 + enddate.month() - 1; QValueList<int>::ConstIterator it; const QValueList<int>* days = data.dayList(); if (data.day > 1) { // Check what remains of the start month for (it = days->begin(); it != days->end(); ++it) { if (*it >= data.day) { ++countGone; if (data.yearMonth() == endYearMonth && *it > endDay) { data.day = *it; goto ex; } if (--countTogo == 0) return 0; } } data.day = 1; data.addMonths(rFreq); } if (data.varies) { // The number of recurrence days varies from month to month, // so we need to check month by month. while (data.yearMonth() <= endYearMonth) { days = data.dayList(); uint n = days->count(); // number of recurrence days in this month if (data.yearMonth() == endYearMonth && days->last() > endDay) break; if (n >= countTogo) return 0; countGone += n; countTogo -= n; data.addMonths(rFreq); } days = data.dayList(); } else { // The number of recurrences is the same every month, // so skip the month-by-month check. // Skip the remaining whole months to at least end year/month. int daysPerMonth = days->count(); int elapsed = endYearMonth - data.yearMonth(); int recurMonths = (elapsed + rFreq - 1) / rFreq; if (elapsed % rFreq == 0 && days->last() <= endDay) ++recurMonths; // required month is after endYearMonth if (recurMonths) { int n = recurMonths * daysPerMonth; if (static_cast<uint>(n) > countTogo) return 0; // reached end of recurrence countTogo -= n; countGone += n; data.addMonths(recurMonths * rFreq); } } // Check the last month in the recurrence for (it = days->begin(); it != days->end(); ++it) { ++countGone; if (data.yearMonth() > endYearMonth || *it > endDay) { data.day = *it; break; } if (--countTogo == 0) return 0; } ex: enddate = data.date(); return countGone; } /* Find count and, depending on 'func', the end date of an annual recurrence by date. * Reply = total number of occurrences up to 'enddate', or 0 if error. * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the * recurrence end date. */ struct Recurrence::YearlyMonthData { const Recurrence *recurrence; int year; // current year int month; // current month 1..12 int day; // current day of month 1..31 bool leapyear; // true if February 29th recurs and current year is a leap year bool feb29; // true if February 29th recurs private: QValueList<int> months; // recurring months in non-leap years 1..12 QValueList<int> leapMonths; // recurring months in leap years 1..12 public: YearlyMonthData(const Recurrence* r, const QDate &date) : recurrence(r), year(date.year()), month(date.month()), day(date.day()) { feb29 = recurrence->getYearlyMonthMonths(day, months, leapMonths); leapyear = feb29 && QDate::leapYear(year); } const QValueList<int>* monthList() const { return leapyear ? &leapMonths : &months; } const QValueList<int>* leapMonthList() const { return &leapMonths; } QDate date() const { return QDate(year, month, day); } }; int Recurrence::yearlyMonthCalc(PeriodFunc func, QDate &enddate) const { if (rYearNums.isEmpty()) return 0; YearlyMonthData data(this, mRecurStart.date()); switch (func) { case END_DATE_AND_COUNT: return yearlyMonthCalcEndDate(enddate, data); case COUNT_TO_DATE: return yearlyMonthCalcToDate(enddate, data); case NEXT_AFTER_DATE: return yearlyMonthCalcNextAfter(enddate, data); } return 0; } // Find total count and end date of an annual recurrence by date. // Reply = total number of occurrences. int Recurrence::yearlyMonthCalcEndDate(QDate &enddate, YearlyMonthData &data) const { uint countTogo = rDuration + mRecurExDatesCount; int countGone = 0; QValueList<int>::ConstIterator it; const QValueList<int>* mons = data.monthList(); // get recurring months for this year if (data.month > 1) { // Check what remains of the start year for (it = mons->begin(); it != mons->end(); ++it) { if (*it >= data.month) { ++countGone; if (--countTogo == 0) { data.month = *it; if (data.month == 2 && data.feb29 && !data.leapyear) { // The recurrence should end on February 29th, but it's a non-leap year switch (mFeb29YearlyType) { case rFeb28: data.day = 28; break; case rMar1: data.month = 3; data.day = 1; break; case rFeb29: break; } } break; } } } if (countTogo) { data.month = 1; data.year += rFreq; } } if (countTogo) { if (data.feb29 && mFeb29YearlyType == rFeb29) { // The number of recurrences is different on leap years, // so check year-by-year. for ( ; ; ) { mons = data.monthList(); uint n = mons->count(); if (n >= countTogo) break; countTogo -= n; countGone += n; data.year += rFreq; } } else { // The number of recurrences is the same every year, // so skip the year-by-year check. // Skip the remaining whole years, but leave at least // 1 recurrence remaining, in order to get its date. int monthsPerYear = mons->count(); int wholeYears = (countTogo - 1) / monthsPerYear; data.year += wholeYears * rFreq; countGone += wholeYears * monthsPerYear; countTogo -= wholeYears * monthsPerYear; } if (countTogo) { // Check the last year in the recurrence for (it = mons->begin(); it != mons->end(); ++it) { ++countGone; if (--countTogo == 0) { data.month = *it; if (data.month == 2 && data.feb29 && !QDate::leapYear(data.year)) { // The recurrence should end on February 29th, but it's a non-leap year switch (mFeb29YearlyType) { case rFeb28: data.day = 28; break; case rMar1: data.month = 3; data.day = 1; break; case rFeb29: break; } } break; } } } } enddate = data.date(); return countGone; } // Find count of an annual recurrence by date. // Reply = total number of occurrences up to 'enddate'. int Recurrence::yearlyMonthCalcToDate(const QDate &enddate, YearlyMonthData &data) const { int countGone = 0; int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; int endYear = enddate.year(); int endMonth = enddate.month(); int endDay = enddate.day(); if (endDay < data.day) { /* The end day of the month is earlier than the recurrence day of the month. * If Feb 29th recurs and: * 1) it recurs on Feb 28th in non-leap years, don't adjust the end month * if enddate is Feb 28th on a non-leap year. * 2) it recurs on Mar 1st in non-leap years, allow the end month to be * adjusted to February, to simplify calculations. */ if (data.feb29 && !QDate::leapYear(endYear) && mFeb29YearlyType == rFeb28 && endDay == 28 && endMonth == 2) { } else if (--endMonth == 0) { endMonth = 12; --endYear; } } QValueList<int>::ConstIterator it; const QValueList<int>* mons = data.monthList(); if (data.month > 1) { // Check what remains of the start year for (it = mons->begin(); it != mons->end(); ++it) { if (*it >= data.month) { if (data.year == endYear && *it > endMonth) return countGone; if (++countGone >= countMax) return countMax; } } data.month = 1; data.year += rFreq; } if (data.feb29 && mFeb29YearlyType == rFeb29) { // The number of recurrences is different on leap years, // so check year-by-year. while (data.year < endYear) { countGone += data.monthList()->count(); if (countGone >= countMax) return countMax; data.year += rFreq; } mons = data.monthList(); } else { // The number of recurrences is the same every year, // so skip the year-by-year check. // Skip the remaining whole years. int monthsPerYear = mons->count(); int wholeYears = endYear - data.year; countGone += (wholeYears / rFreq) * monthsPerYear; if (countGone >= countMax) return countMax; if (wholeYears % rFreq) return countGone; // end year isn't a recurrence year data.year = endYear; } // Check the last year in the recurrence for (it = mons->begin(); it != mons->end(); ++it) { if (*it > endMonth) return countGone; if (++countGone >= countMax) return countMax; } return countGone; } // Find count and date of first recurrence after 'enddate' of an annual recurrence by date. // Reply = total number of occurrences up to 'enddate'. int Recurrence::yearlyMonthCalcNextAfter(QDate &enddate, YearlyMonthData &data) const { uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; int countGone = 0; int endYear = enddate.year(); int endMonth = enddate.month(); int endDay = enddate.day(); bool mar1TooEarly = false; bool feb28ok = false; if (endDay < data.day) { if (data.feb29 && mFeb29YearlyType == rMar1 && endMonth == 3) mar1TooEarly = true; if (data.feb29 && mFeb29YearlyType == rFeb28 && endMonth == 2 && endDay == 28) feb28ok = true; else if (--endMonth == 0) { endMonth = 12; --endYear; } } QValueList<int>::ConstIterator it; const QValueList<int>* mons = data.monthList(); if (data.month > 1) { // Check what remains of the start year for (it = mons->begin(); it != mons->end(); ++it) { if (*it >= data.month) { ++countGone; if (data.year == endYear && ( *it > endMonth && (*it > 3 || !mar1TooEarly) || *it == 2 && feb28ok && data.leapyear)) { if (*it == 2 && data.feb29 && !data.leapyear) { // The next recurrence should be on February 29th, but it's a non-leap year switch (mFeb29YearlyType) { case rFeb28: data.month = 2; data.day = 28; break; case rMar1: data.month = 3; data.day = 1; break; case rFeb29: // impossible in this context! break; } } else data.month = *it; goto ex; } if (--countTogo == 0) return 0; } } data.month = 1; data.year += rFreq; } if (data.feb29 && mFeb29YearlyType == rFeb29) { // The number of recurrences is different on leap years, // so check year-by-year. while (data.year <= endYear) { mons = data.monthList(); if (data.year == endYear && mons->last() > endMonth) break; uint n = mons->count(); if (n >= countTogo) break; countTogo -= n; countGone += n; data.year += rFreq; } mons = data.monthList(); } else { // The number of recurrences is the same every year, // so skip the year-by-year check. // Skip the remaining whole years to at least endYear. int monthsPerYear = mons->count(); int recurYears = (endYear - data.year + rFreq - 1) / rFreq; if ((endYear - data.year)%rFreq == 0 && mons->last() <= endMonth) ++recurYears; // required year is after endYear if (recurYears) { int n = recurYears * monthsPerYear; if (static_cast<uint>(n) > countTogo) return 0; // reached end of recurrence countTogo -= n; countGone += n; data.year += recurYears * rFreq; } } // Check the last year in the recurrence for (it = mons->begin(); it != mons->end(); ++it) { ++countGone; if (data.year > endYear || ( *it > endMonth && (*it > 3 || !mar1TooEarly) || *it == 2 && feb28ok && QDate::leapYear(data.year))) { if (*it == 2 && data.feb29 && !QDate::leapYear(data.year)) { // The next recurrence should be on February 29th, but it's a non-leap year switch (mFeb29YearlyType) { case rFeb28: data.month = 2; data.day = 28; break; case rMar1: data.month = 3; data.day = 1; break; case rFeb29: // impossible in this context! break; } } else data.month = *it; break; } if (--countTogo == 0) return 0; } ex: enddate = data.date(); return countGone; } /* Find count and, depending on 'func', the end date of an annual recurrence by date. * Reply = total number of occurrences up to 'enddate', or 0 if error. * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the * recurrence end date. */ struct Recurrence::YearlyPosData { const Recurrence *recurrence; int year; // current year int month; // current month 1..12 int day; // current day of month 1..31 int daysPerMonth; // number of days which recur each month, or -1 if variable int count; // number of days which recur each year, or -1 if variable bool varies; // true if number of days varies from year to year private: mutable QValueList<int> days; public: YearlyPosData(const Recurrence* r, const QDate &date) : recurrence(r), year(date.year()), month(date.month()), day(date.day()), count(-1) { if ((daysPerMonth = r->countMonthlyPosDays()) > 0) count = daysPerMonth * r->rYearNums.count(); varies = (daysPerMonth < 0); } const QValueList<int>* dayList() const { QDate startOfMonth(year, month, 1); recurrence->getMonthlyPosDays(days, startOfMonth.daysInMonth(), startOfMonth.dayOfWeek()); return &days; } int yearMonth() const { return year*12 + month - 1; } void addMonths(int diff) { month += diff - 1; year += month / 12; month = month % 12 + 1; } QDate date() const { return QDate(year, month, day); } }; int Recurrence::yearlyPosCalc(PeriodFunc func, QDate &enddate) const { if (rYearNums.isEmpty() || rMonthPositions.isEmpty()) return 0; YearlyPosData data(this, mRecurStart.date()); switch (func) { case END_DATE_AND_COUNT: return yearlyPosCalcEndDate(enddate, data); case COUNT_TO_DATE: return yearlyPosCalcToDate(enddate, data); case NEXT_AFTER_DATE: return yearlyPosCalcNextAfter(enddate, data); } return 0; } int Recurrence::yearlyPosCalcEndDate(QDate &enddate, YearlyPosData &data) const { uint countTogo = rDuration + mRecurExDatesCount; int countGone = 0; QValueList<int>::ConstIterator id; const QValueList<int>* days; if (data.month > 1 || data.day > 1) { // Check what remains of the start year for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { if (*im.current() >= data.month) { // Check what remains of the start month if (data.day > 1 || data.varies || static_cast<uint>(data.daysPerMonth) >= countTogo) { data.month = *im.current(); days = data.dayList(); for (id = days->begin(); id != days->end(); ++id) { if (*id >= data.day) { ++countGone; if (--countTogo == 0) { data.month = *im.current(); data.day = *id; goto ex; } } } data.day = 1; } else { // The number of days per month is constant, so skip // the whole month. countTogo -= data.daysPerMonth; countGone += data.daysPerMonth; } } } data.month = 1; data.year += rFreq; } if (data.varies) { // The number of recurrences varies from year to year. for ( ; ; ) { for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { data.month = *im.current(); days = data.dayList(); int n = days->count(); if (static_cast<uint>(n) >= countTogo) { // Check the last month in the recurrence for (id = days->begin(); id != days->end(); ++id) { ++countGone; if (--countTogo == 0) { data.day = *id; goto ex; } } } countTogo -= n; countGone += n; } data.year += rFreq; } } else { // The number of recurrences is the same every year, // so skip the year-by-year check. // Skip the remaining whole years, but leave at least // 1 recurrence remaining, in order to get its date. int wholeYears = (countTogo - 1) / data.count; data.year += wholeYears * rFreq; countGone += wholeYears * data.count; countTogo -= wholeYears * data.count; // Check the last year in the recurrence. for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { if (static_cast<uint>(data.daysPerMonth) >= countTogo) { // Check the last month in the recurrence data.month = *im.current(); days = data.dayList(); for (id = days->begin(); id != days->end(); ++id) { ++countGone; if (--countTogo == 0) { data.day = *id; goto ex; } } } countTogo -= data.daysPerMonth; countGone += data.daysPerMonth; } data.year += rFreq; } ex: enddate = data.date(); return countGone; } int Recurrence::yearlyPosCalcToDate(const QDate &enddate, YearlyPosData &data) const { int countGone = 0; int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; int endYear = enddate.year(); int endMonth = enddate.month(); int endDay = enddate.day(); if (endDay < data.day && --endMonth == 0) { endMonth = 12; --endYear; } int endYearMonth = endYear*12 + endMonth; QValueList<int>::ConstIterator id; const QValueList<int>* days; if (data.month > 1 || data.day > 1) { // Check what remains of the start year for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { if (*im.current() >= data.month) { data.month = *im.current(); if (data.yearMonth() > endYearMonth) return countGone; // Check what remains of the start month bool lastMonth = (data.yearMonth() == endYearMonth); if (lastMonth || data.day > 1 || data.varies) { days = data.dayList(); if (lastMonth || data.day > 1) { for (id = days->begin(); id != days->end(); ++id) { if (*id >= data.day) { if (lastMonth && *id > endDay) return countGone; if (++countGone >= countMax) return countMax; } } } else { countGone += days->count(); if (countGone >= countMax) return countMax; } data.day = 1; } else { // The number of days per month is constant, so skip // the whole month. countGone += data.daysPerMonth; if (countGone >= countMax) return countMax; } } } data.month = 1; data.year += rFreq; } if (data.varies) { // The number of recurrences varies from year to year. for ( ; ; ) { for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { data.month = *im.current(); days = data.dayList(); if (data.yearMonth() >= endYearMonth) { if (data.yearMonth() > endYearMonth) return countGone; // Check the last month in the recurrence for (id = days->begin(); id != days->end(); ++id) { if (*id > endDay) return countGone; if (++countGone >= countMax) return countMax; } } else { countGone += days->count(); if (countGone >= countMax) return countMax; } } data.year += rFreq; } } else { // The number of recurrences is the same every year, // so skip the year-by-year check. // Skip the remaining whole years, but leave at least // 1 recurrence remaining, in order to get its date. int wholeYears = endYear - data.year; countGone += (wholeYears / rFreq) * data.count; if (countGone >= countMax) return countMax; if (wholeYears % rFreq) return countGone; // end year isn't a recurrence year data.year = endYear; // Check the last year in the recurrence. for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { data.month = *im.current(); if (data.month >= endMonth) { if (data.month > endMonth) return countGone; // Check the last month in the recurrence days = data.dayList(); for (id = days->begin(); id != days->end(); ++id) { if (*id > endDay) return countGone; if (++countGone >= countMax) return countMax; } } else { countGone += data.daysPerMonth; if (countGone >= countMax) return countMax; } } } return countGone; } int Recurrence::yearlyPosCalcNextAfter(QDate &enddate, YearlyPosData &data) const { uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; int countGone = 0; int endYear = enddate.year(); int endMonth = enddate.month(); int endDay = enddate.day(); if (endDay < data.day && --endMonth == 0) { endMonth = 12; --endYear; } int endYearMonth = endYear*12 + endMonth; QValueList<int>::ConstIterator id; const QValueList<int>* days; if (data.varies) { // The number of recurrences varies from year to year. for ( ; ; ) { // Check the next year for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { if (*im.current() >= data.month) { // Check the next month data.month = *im.current(); int ended = data.yearMonth() - endYearMonth; days = data.dayList(); if (ended >= 0 || data.day > 1) { // This is the start or end month, so check each day for (id = days->begin(); id != days->end(); ++id) { if (*id >= data.day) { ++countGone; if (ended > 0 || (ended == 0 && *id > endDay)) { data.day = *id; goto ex; } if (--countTogo == 0) return 0; } } } else { // Skip the whole month uint n = days->count(); if (n >= countTogo) return 0; countGone += n; } data.day = 1; // we've checked the start month now } } data.month = 1; // we've checked the start year now data.year += rFreq; } } else { // The number of recurrences is the same every year. if (data.month > 1 || data.day > 1) { // Check what remains of the start year for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { if (*im.current() >= data.month) { // Check what remains of the start month data.month = *im.current(); int ended = data.yearMonth() - endYearMonth; if (ended >= 0 || data.day > 1) { // This is the start or end month, so check each day days = data.dayList(); for (id = days->begin(); id != days->end(); ++id) { if (*id >= data.day) { ++countGone; if (ended > 0 || (ended == 0 && *id > endDay)) { data.day = *id; goto ex; } if (--countTogo == 0) return 0; } } data.day = 1; // we've checked the start month now } else { // Skip the whole month. if (static_cast<uint>(data.daysPerMonth) >= countTogo) return 0; countGone += data.daysPerMonth; } } } data.year += rFreq; } // Skip the remaining whole years to at least endYear. int recurYears = (endYear - data.year + rFreq - 1) / rFreq; if ((endYear - data.year)%rFreq == 0 && *rYearNums.getLast() <= endMonth) ++recurYears; // required year is after endYear if (recurYears) { int n = recurYears * data.count; if (static_cast<uint>(n) > countTogo) return 0; // reached end of recurrence countTogo -= n; countGone += n; data.year += recurYears * rFreq; } // Check the last year in the recurrence for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { data.month = *im.current(); int ended = data.yearMonth() - endYearMonth; if (ended >= 0) { // This is the end month, so check each day days = data.dayList(); for (id = days->begin(); id != days->end(); ++id) { ++countGone; if (ended > 0 || (ended == 0 && *id > endDay)) { data.day = *id; goto ex; } if (--countTogo == 0) return 0; } } else { // Skip the whole month. if (static_cast<uint>(data.daysPerMonth) >= countTogo) return 0; countGone += data.daysPerMonth; } } } ex: enddate = data.date(); return countGone; } /* Find count and, depending on 'func', the end date of an annual recurrence by day. * Reply = total number of occurrences up to 'enddate', or 0 if error. * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the * recurrence end date. */ struct Recurrence::YearlyDayData { int year; // current year int day; // current day of year 1..366 bool varies; // true if day 366 recurs private: int daycount; public: YearlyDayData(const Recurrence* r, const QDate &date) : year(date.year()), day(date.dayOfYear()), varies(*r->rYearNums.getLast() == 366), daycount(r->rYearNums.count()) { } bool leapYear() const { return QDate::leapYear(year); } int dayCount() const { return daycount - (varies && !QDate::leapYear(year) ? 1 : 0); } bool isMaxDayCount() const { return !varies || QDate::leapYear(year); } QDate date() const { return QDate(year, 1, 1).addDays(day - 1); } }; int Recurrence::yearlyDayCalc(PeriodFunc func, QDate &enddate) const { if (rYearNums.isEmpty()) return 0; YearlyDayData data(this, mRecurStart.date()); switch (func) { case END_DATE_AND_COUNT: return yearlyDayCalcEndDate(enddate, data); case COUNT_TO_DATE: return yearlyDayCalcToDate(enddate, data); case NEXT_AFTER_DATE: return yearlyDayCalcNextAfter(enddate, data); } return 0; } int Recurrence::yearlyDayCalcEndDate(QDate &enddate, YearlyDayData &data) const { uint countTogo = rDuration + mRecurExDatesCount; int countGone = 0; if (data.day > 1) { // Check what remains of the start year bool leapOK = data.isMaxDayCount(); for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { int d = *it.current(); if (d >= data.day && (leapOK || d < 366)) { ++countGone; if (--countTogo == 0) { data.day = d; goto ex; } } } data.day = 1; data.year += rFreq; } if (data.varies) { // The number of recurrences is different in leap years, // so check year-by-year. for ( ; ; ) { uint n = data.dayCount(); if (n >= countTogo) break; countTogo -= n; countGone += n; data.year += rFreq; } } else { // The number of recurrences is the same every year, // so skip the year-by-year check. // Skip the remaining whole years, but leave at least // 1 recurrence remaining, in order to get its date. int daysPerYear = rYearNums.count(); int wholeYears = (countTogo - 1) / daysPerYear; data.year += wholeYears * rFreq; countGone += wholeYears * daysPerYear; countTogo -= wholeYears * daysPerYear; } if (countTogo) { // Check the last year in the recurrence for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { ++countGone; if (--countTogo == 0) { data.day = *it.current(); break; } } } ex: enddate = data.date(); return countGone; } int Recurrence::yearlyDayCalcToDate(const QDate &enddate, YearlyDayData &data) const { int countGone = 0; int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; int endYear = enddate.year(); int endDay = enddate.dayOfYear(); if (data.day > 1) { // Check what remains of the start year bool leapOK = data.isMaxDayCount(); for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { int d = *it.current(); if (d >= data.day && (leapOK || d < 366)) { if (data.year == endYear && d > endDay) return countGone; if (++countGone >= countMax) return countMax; } } data.day = 1; data.year += rFreq; } if (data.varies) { // The number of recurrences is different in leap years, // so check year-by-year. while (data.year < endYear) { uint n = data.dayCount(); countGone += n; if (countGone >= countMax) return countMax; data.year += rFreq; } if (data.year > endYear) return countGone; } else { // The number of recurrences is the same every year. // Skip the remaining whole years. int wholeYears = endYear - data.year; countGone += (wholeYears / rFreq) * rYearNums.count(); if (countGone >= countMax) return countMax; if (wholeYears % rFreq) return countGone; // end year isn't a recurrence year data.year = endYear; } if (data.year <= endYear) { // Check the last year in the recurrence for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { if (*it.current() > endDay) return countGone; if (++countGone >= countMax) return countMax; } } return countGone; } int Recurrence::yearlyDayCalcNextAfter(QDate &enddate, YearlyDayData &data) const { uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; int countGone = 0; int endYear = enddate.year(); int endDay = enddate.dayOfYear(); if (data.day > 1) { // Check what remains of the start year bool leapOK = data.isMaxDayCount(); for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { int d = *it.current(); if (d >= data.day && (leapOK || d < 366)) { ++countGone; if (data.year == endYear && d > endDay) { data.day = d; goto ex; } if (--countTogo == 0) return 0; } } data.day = 1; data.year += rFreq; } if (data.varies) { // The number of recurrences is different in leap years, // so check year-by-year. while (data.year <= endYear) { uint n = data.dayCount(); if (data.year == endYear && *rYearNums.getLast() > endDay) break; if (n >= countTogo) break; countTogo -= n; countGone += n; data.year += rFreq; } } else { // The number of recurrences is the same every year, // so skip the year-by-year check. // Skip the remaining whole years to at least endYear. int daysPerYear = rYearNums.count(); int recurYears = (endYear - data.year + rFreq - 1) / rFreq; if ((endYear - data.year)%rFreq == 0 && *rYearNums.getLast() <= endDay) ++recurYears; // required year is after endYear if (recurYears) { int n = recurYears * daysPerYear; if (static_cast<uint>(n) > countTogo) return 0; // reached end of recurrence countTogo -= n; countGone += n; data.year += recurYears * rFreq; } } // Check the last year in the recurrence for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { ++countGone; int d = *it.current(); if (data.year > endYear || d > endDay) { data.day = d; break; } if (--countTogo == 0) return 0; } ex: enddate = data.date(); return countGone; } // Get the days in this month which recur, in numerical order. // Parameters: daysInMonth = number of days in this month // startDayOfWeek = day of week for first day of month. void Recurrence::getMonthlyPosDays(QValueList<int> &list, int daysInMonth, int startDayOfWeek) const { list.clear(); int endDayOfWeek = (startDayOfWeek + daysInMonth - 2) % 7 + 1; // Go through the list, compiling a bit list of actual day numbers Q_UINT32 days = 0; for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) { int weeknum = pos.current()->rPos - 1; // get 0-based week number QBitArray &rdays = pos.current()->rDays; if (pos.current()->negative) { // nth days before the end of the month for (uint i = 1; i <= 7; ++i) { if (rdays.testBit(i - 1)) { int day = daysInMonth - weeknum*7 - (endDayOfWeek - i + 7) % 7; if (day > 0) days |= 1 << (day - 1); } } } else { // nth days after the start of the month for (uint i = 1; i <= 7; ++i) { if (rdays.testBit(i - 1)) { int day = 1 + weeknum*7 + (i - startDayOfWeek + 7) % 7; if (day <= daysInMonth) days |= 1 << (day - 1); } } } } // Compile the ordered list Q_UINT32 mask = 1; for (int i = 0; i < daysInMonth; mask <<= 1, ++i) { if (days & mask) list.append(i + 1); } } // Get the number of days in the month which recur. // Reply = -1 if the number varies from month to month. int Recurrence::countMonthlyPosDays() const { int count = 0; Q_UINT8 positive[5] = { 0, 0, 0, 0, 0 }; Q_UINT8 negative[4] = { 0, 0, 0, 0 }; for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) { int weeknum = pos.current()->rPos; Q_UINT8* wk; if (pos.current()->negative) { // nth days before the end of the month if (weeknum > 4) return -1; // days in 5th week are often missing wk = &negative[4 - weeknum]; } else { // nth days after the start of the month if (weeknum > 4) return -1; // days in 5th week are often missing wk = &positive[weeknum - 1]; } QBitArray &rdays = pos.current()->rDays; for (uint i = 0; i < 7; ++i) { if (rdays.testBit(i)) { ++count; *wk |= (1 << i); } } } // Check for any possible days which could be duplicated by // a positive and a negative position. for (int i = 0; i < 4; ++i) { if (negative[i] & (positive[i] | positive[i+1])) return -1; } return count; } // Get the days in this month which recur, in numerical order. // Reply = true if day numbers varies from month to month. bool Recurrence::getMonthlyDayDays(QValueList<int> &list, int daysInMonth) const { list.clear(); bool variable = false; Q_UINT32 days = 0; for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) { int day = *it.current(); if (day > 0) { // date in the month if (day <= daysInMonth) days |= 1 << (day - 1); if (day > 28 && day <= 31) variable = true; // this date does not appear in some months } else if (day < 0) { // days before the end of the month variable = true; // this date varies depending on the month length day = daysInMonth + day; // zero-based day of month if (day >= 0) days |= 1 << day; } } // Compile the ordered list Q_UINT32 mask = 1; for (int i = 0; i < daysInMonth; mask <<= 1, ++i) { if (days & mask) list.append(i + 1); } return variable; } // Get the months which recur, in numerical order, for both leap years and non-leap years. // N.B. If February 29th recurs on March 1st in non-leap years, February (not March) is // included in the non-leap year month list. // Reply = true if February 29th also recurs. bool Recurrence::getYearlyMonthMonths(int day, QValueList<int> &list, QValueList<int> &leaplist) const { list.clear(); leaplist.clear(); bool feb29 = false; for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { int month = *it.current(); if (month == 2) { if (day <= 28) { list.append(month); // date appears in February leaplist.append(month); } else if (day == 29) { // February 29th leaplist.append(month); switch (mFeb29YearlyType) { case rFeb28: case rMar1: list.append(2); break; case rFeb29: break; } feb29 = true; } } else if (day <= 30 || QDate(2000, month, 1).daysInMonth() == 31) { list.append(month); // date appears in every month leaplist.append(month); } } return feb29; } /* From the recurrence day of the week list, get the earliest day in the * specified week which is >= the startDay. * Parameters: startDay = 1..7 (Monday..Sunday) * useWeekStart = true to end search at day before next rWeekStart * = false to search for a full 7 days * Reply = day of the week (1..7), or 0 if none found. */ int Recurrence::getFirstDayInWeek(int startDay, bool useWeekStart) const { int last = ((useWeekStart ? rWeekStart : startDay) + 5)%7; for (int i = startDay - 1; ; i = (i + 1)%7) { if (rDays.testBit(i)) return i + 1; if (i == last) return 0; } } /* From the recurrence day of the week list, get the latest day in the * specified week which is <= the endDay. * Parameters: endDay = 1..7 (Monday..Sunday) * useWeekStart = true to end search at rWeekStart * = false to search for a full 7 days * Reply = day of the week (1..7), or 0 if none found. */ int Recurrence::getLastDayInWeek(int endDay, bool useWeekStart) const { int last = useWeekStart ? rWeekStart - 1 : endDay%7; for (int i = endDay - 1; ; i = (i + 6)%7) { if (rDays.testBit(i)) return i + 1; if (i == last) return 0; } } /* From the recurrence monthly day number list or monthly day of week/week of * month list, get the earliest day in the specified month which is >= the * earliestDate. */ QDate Recurrence::getFirstDateInMonth(const QDate &earliestDate) const { int earliestDay = earliestDate.day(); int daysInMonth = earliestDate.daysInMonth(); switch (recurs) { case rMonthlyDay: { int minday = daysInMonth + 1; for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) { int day = *it.current(); if (day < 0) day = daysInMonth + day + 1; if (day >= earliestDay && day < minday) minday = day; } if (minday <= daysInMonth) return earliestDate.addDays(minday - earliestDay); break; } case rMonthlyPos: case rYearlyPos: { QDate monthBegin(earliestDate.addDays(1 - earliestDay)); QValueList<int> dayList; getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek()); for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) { if (*id >= earliestDay) return monthBegin.addDays(*id - 1); } break; } } return QDate(); } /* From the recurrence monthly day number list or monthly day of week/week of * month list, get the latest day in the specified month which is <= the * latestDate. */ QDate Recurrence::getLastDateInMonth(const QDate &latestDate) const { diff --git a/microkde/kdeui/ktoolbar.cpp b/microkde/kdeui/ktoolbar.cpp index 09ad0c8..35d4916 100644 --- a/microkde/kdeui/ktoolbar.cpp +++ b/microkde/kdeui/ktoolbar.cpp @@ -1,2266 +1,2266 @@ /* This file is part of the KDE libraries Copyright (C) 2000 Reginald Stadlbauer (reggie@kde.org) (C) 1997, 1998 Stephan Kulow (coolo@kde.org) (C) 1997, 1998 Mark Donohoe (donohoe@kde.org) (C) 1997, 1998 Sven Radej (radej@kde.org) (C) 1997, 1998 Matthias Ettrich (ettrich@kde.org) (C) 1999 Chris Schlaeger (cs@kde.org) (C) 1999 Kurt Granroth (granroth@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef KDE_USE_FINAL #undef Always #include <qdockwindow.h> #endif #include "ktoolbar.h" #include "kmainwindow.h" #include <string.h> #include <qpainter.h> #include <qtooltip.h> #include <qdrawutil.h> #include <qstring.h> #include <qrect.h> #include <qobjectlist.h> #include <qtimer.h> #include <qstyle.h> #include <qapplication.h> //US #include <config.h> #include "klineedit.h" #include "kseparator.h" #include <klocale.h> #include <kapplication.h> #include <kaction.h> #include <kstdaction.h> #include <kglobal.h> #include <kconfig.h> #include <kiconloader.h> #include <kcombobox.h> //US #include <kpopupmenu.h> //US #include <kanimwidget.h> //US #include <kipc.h> //US #include <kwin.h> #include <kdebug.h> #include <qlayout.h> #include "ktoolbarbutton.h" //US #include "kconfigbase.h" #include <qpopupmenu.h> #include <qmainwindow.h> enum { CONTEXT_TOP = 0, CONTEXT_LEFT = 1, CONTEXT_RIGHT = 2, CONTEXT_BOTTOM = 3, CONTEXT_FLOAT = 4, CONTEXT_FLAT = 5, CONTEXT_ICONS = 6, CONTEXT_TEXT = 7, CONTEXT_TEXTRIGHT = 8, CONTEXT_TEXTUNDER = 9, CONTEXT_ICONSIZES = 50 // starting point for the icon size list, put everything else before }; class KToolBarPrivate { public: KToolBarPrivate() { m_iconSize = 0; m_iconText = KToolBar::IconOnly; m_highlight = true; m_transparent = true; m_honorStyle = false; m_enableContext = true; m_xmlguiClient = 0; m_configurePlugged = false; //US oldPos = Qt::DockUnmanaged; oldPos = QMainWindow::Unmanaged; modified = m_isHorizontal = positioned = FALSE; HiddenDefault = false; IconSizeDefault = 0; IconTextDefault = "IconOnly"; IndexDefault = -1; NewLineDefault = false; OffsetDefault = -1; PositionDefault = "Top"; idleButtons.setAutoDelete(true); } int m_iconSize; KToolBar::IconText m_iconText; bool m_highlight : 1; bool m_transparent : 1; bool m_honorStyle : 1; bool m_isHorizontal : 1; bool m_enableContext : 1; bool m_configurePlugged : 1; bool modified : 1; bool positioned : 1; QWidget *m_parent; QMainWindow::ToolBarDock oldPos; KXMLGUIClient *m_xmlguiClient; struct ToolBarInfo { //US ToolBarInfo() : index( 0 ), offset( -1 ), newline( FALSE ), dock( Qt::DockTop ) {} ToolBarInfo() : index( 0 ), offset( -1 ), newline( FALSE ), dock( QMainWindow::Top ) {} //US ToolBarInfo( Qt::Dock d, int i, bool n, int o ) : index( i ), offset( o ), newline( n ), dock( d ) {} ToolBarInfo( QMainWindow::ToolBarDock d, int i, bool n, int o ) : index( i ), offset( o ), newline( n ), dock( d ) {} int index, offset; bool newline; //US Qt::Dock dock; QMainWindow::ToolBarDock dock; }; ToolBarInfo toolBarInfo; QValueList<int> iconSizes; QTimer repaintTimer; // Default Values. bool HiddenDefault; int IconSizeDefault; QString IconTextDefault; int IndexDefault; bool NewLineDefault; int OffsetDefault; QString PositionDefault; QPtrList<QWidget> idleButtons; }; KToolBarSeparator::KToolBarSeparator(Orientation o , bool l, QToolBar *parent, const char* name ) :QFrame( parent, name ), line( l ) { connect( parent, SIGNAL(orientationChanged(Orientation)), this, SLOT(setOrientation(Orientation)) ); setOrientation( o ); setBackgroundMode( parent->backgroundMode() ); setBackgroundOrigin( ParentOrigin ); } void KToolBarSeparator::setOrientation( Orientation o ) { orient = o; if ( line ) { if ( orientation() == Vertical ) setFrameStyle( HLine + Sunken ); else setFrameStyle( VLine + Sunken ); } else { setFrameStyle( NoFrame ); } } void KToolBarSeparator::styleChange( QStyle& ) { setOrientation( orient ); } QSize KToolBarSeparator::sizeHint() const { return orientation() == Vertical ? QSize( 0, 6 ) : QSize( 6, 0 ); } QSizePolicy KToolBarSeparator::sizePolicy() const { return QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); } KToolBar::KToolBar( QWidget *parent, const char *name, bool honorStyle, bool readConfig ) #ifdef DESKTOP_VERSION : QToolBar( QString::fromLatin1( name ), parent && parent->inherits( "QMainWindow" ) ? static_cast<QMainWindow*>(parent) : 0, parent, FALSE, name ? name : "mainToolBar") #else : QPEToolBar( parent && parent->inherits( "QMainWindow" ) ? static_cast<QMainWindow*>(parent) : 0, QString::fromLatin1( name )) #endif { init( readConfig, honorStyle ); } KToolBar::KToolBar( QMainWindow *parentWindow, QMainWindow::ToolBarDock dock, bool newLine, const char *name, bool honorStyle, bool readConfig ) #ifdef DESKTOP_VERSION : QToolBar( QString::fromLatin1( name ), parentWindow, dock, newLine, name ? name : "mainToolBar") #else : QPEToolBar( parentWindow,QString::fromLatin1( name )) #endif { init( readConfig, honorStyle ); } KToolBar::KToolBar( QMainWindow *parentWindow, QWidget *dock, bool newLine, const char *name, bool honorStyle, bool readConfig ) #ifdef DESKTOP_VERSION : QToolBar( QString::fromLatin1( name ), parentWindow, dock, newLine, name ? name : "mainToolBar") #else : QPEToolBar( parentWindow,QString::fromLatin1( name )) #endif { init( readConfig, honorStyle ); } KToolBar::~KToolBar() { inshutdownprocess = true; emit toolbarDestroyed(); delete d; } void KToolBar::init( bool readConfig, bool honorStyle ) { inshutdownprocess = false; d = new KToolBarPrivate; setFullSize( TRUE ); d->m_honorStyle = honorStyle; context = 0; layoutTimer = new QTimer( this ); connect( layoutTimer, SIGNAL( timeout() ), this, SLOT( rebuildLayout() ) ); connect( &(d->repaintTimer), SIGNAL( timeout() ), this, SLOT( slotRepaint() ) ); /*US if ( kapp ) { // may be null when started inside designer connect(kapp, SIGNAL(toolbarAppearanceChanged(int)), this, SLOT(slotAppearanceChanged())); // request notification of changes in icon style kapp->addKipcEventMask(KIPC::IconChanged); connect(kapp, SIGNAL(iconChanged(int)), this, SLOT(slotIconChanged(int))); } */ // finally, read in our configurable settings if ( readConfig ) slotReadConfig(); if ( mainWindow() ) connect( mainWindow(), SIGNAL( toolBarPositionChanged( QToolBar * ) ), this, SLOT( toolBarPosChanged( QToolBar * ) ) ); // Hack to make sure we recalculate our size when we dock. //US connect( this, SIGNAL(placeChanged(QDockWindow::Place)), SLOT(rebuildLayout()) ); } int KToolBar::insertButton(const QString& icon, int id, bool enabled, const QString& text, int index/*US, KInstance *_instance*/ ) { KToolBarButton *button = new KToolBarButton( icon, id, this, 0, text/*US, _instance*/ ); insertWidgetInternal( button, index, id ); button->setEnabled( enabled ); doConnections( button ); return index; } int KToolBar::insertButton(const QString& icon, int id, const char *signal, const QObject *receiver, const char *slot, bool enabled, const QString& text, int index/*US, KInstance *_instance*/ ) { KToolBarButton *button = new KToolBarButton( icon, id, this, 0, text/*US, _instance*/); insertWidgetInternal( button, index, id ); button->setEnabled( enabled ); connect( button, signal, receiver, slot ); doConnections( button ); return index; } int KToolBar::insertButton(const QPixmap& pixmap, int id, bool enabled, const QString& text, int index ) { KToolBarButton *button = new KToolBarButton( pixmap, id, this, 0, text); insertWidgetInternal( button, index, id ); button->setEnabled( enabled ); doConnections( button ); return index; } #if 0 bar->insertButton( icon, id_, SIGNAL( clicked() ), this, SLOT( slotActivated() ), d->isEnabled(), d->plainText(), index/*US, instance*/ ); #endif int KToolBar::insertButton(const QPixmap& pixmap, int id, const char *signal, const QObject *receiver, const char *slot, bool enabled, const QString& text, int index ) { KToolBarButton *button = new KToolBarButton( pixmap, id, this, 0, text); insertWidgetInternal( button, index, id ); button->setEnabled( enabled ); connect( button, signal, receiver, slot ); doConnections( button ); return index; } int KToolBar::insertButton(const QString& icon, int id, QPopupMenu *popup, bool enabled, const QString &text, int index ) { KToolBarButton *button = new KToolBarButton( icon, id, this, 0, text ); insertWidgetInternal( button, index, id ); button->setEnabled( enabled ); button->setPopup( popup ); doConnections( button ); return index; } int KToolBar::insertButton(const QPixmap& pixmap, int id, QPopupMenu *popup, bool enabled, const QString &text, int index ) { KToolBarButton *button = new KToolBarButton( pixmap, id, this, 0, text ); insertWidgetInternal( button, index, id ); button->setEnabled( enabled ); button->setPopup( popup ); doConnections( button ); return index; } int KToolBar::insertLined (const QString& text, int id, const char *signal, const QObject *receiver, const char *slot, bool enabled , const QString& toolTipText, int size, int index ) { KLineEdit *lined = new KLineEdit ( this, 0 ); if ( !toolTipText.isEmpty() ) QToolTip::add( lined, toolTipText ); if ( size > 0 ) lined->setMinimumWidth( size ); insertWidgetInternal( lined, index, id ); connect( lined, signal, receiver, slot ); lined->setText(text); lined->setEnabled( enabled ); return index; } int KToolBar::insertCombo (const QStringList &list, int id, bool writable, const char *signal, const QObject *receiver, const char *slot, bool enabled, const QString& tooltiptext, int size, int index, QComboBox::Policy policy ) { //US KComboBox *combo = new KComboBox ( writable, this ); KComboBox *combo = new KComboBox ( this ); combo->setEditable(writable); insertWidgetInternal( combo, index, id ); combo->insertStringList (list); combo->setInsertionPolicy(policy); combo->setEnabled( enabled ); if ( !tooltiptext.isEmpty() ) QToolTip::add( combo, tooltiptext ); if ( size > 0 ) combo->setMinimumWidth( size ); if (!tooltiptext.isNull()) QToolTip::add( combo, tooltiptext ); if ( signal && receiver && slot ) connect ( combo, signal, receiver, slot ); return index; } int KToolBar::insertCombo (const QString& text, int id, bool writable, const char *signal, QObject *receiver, const char *slot, bool enabled, const QString& tooltiptext, int size, int index, QComboBox::Policy policy ) { //US KComboBox *combo = new KComboBox ( writable, this ); KComboBox *combo = new KComboBox ( this ); combo->setEditable(writable); insertWidgetInternal( combo, index, id ); combo->insertItem (text); combo->setInsertionPolicy(policy); combo->setEnabled( enabled ); if ( !tooltiptext.isEmpty() ) QToolTip::add( combo, tooltiptext ); if ( size > 0 ) combo->setMinimumWidth( size ); if (!tooltiptext.isNull()) QToolTip::add( combo, tooltiptext ); connect (combo, signal, receiver, slot); return index; } int KToolBar::insertSeparator(int index, int id) { QWidget *w = new KToolBarSeparator( orientation(), FALSE, this, "tool bar separator" ); insertWidgetInternal( w, index, id ); return index; } int KToolBar::insertLineSeparator(int index, int id) { QWidget *w = new KToolBarSeparator( orientation(), TRUE, this, "tool bar separator" ); insertWidgetInternal( w, index, id ); return index; } int KToolBar::insertWidget(int id, int /*width*/, QWidget *widget, int index) { // removeWidgetInternal( widget ); // in case we already have it ? insertWidgetInternal( widget, index, id ); return index; } /*US int KToolBar::insertAnimatedWidget(int id, QObject *receiver, const char *slot, const QString& icons, int index ) { KAnimWidget *anim = new KAnimWidget( icons, d->m_iconSize, this ); insertWidgetInternal( anim, index, id ); if ( receiver ) connect( anim, SIGNAL(clicked()), receiver, slot); return index; } KAnimWidget *KToolBar::animatedWidget( int id ) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return 0; if ( (*it) && (*it)->inherits( "KAnimWidget" ) ) return (KAnimWidget*)(*it); QObjectList *l = queryList( "KAnimWidget" ); if ( !l || !l->first() ) { delete l; return 0; } for ( QObject *o = l->first(); o; o = l->next() ) { if ( o->inherits( "KAnimWidget" ) ) { delete l; return (KAnimWidget*)o; } } delete l; return 0; } */ void KToolBar::addConnection (int id, const char *signal, const QObject *receiver, const char *slot) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; if ( (*it) ) connect( (*it), signal, receiver, slot ); } void KToolBar::setItemEnabled( int id, bool enabled ) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; if ( (*it) ) (*it)->setEnabled( enabled ); } void KToolBar::setButtonPixmap( int id, const QPixmap& _pixmap ) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US KToolBarButton * button = dynamic_cast<KToolBarButton *>( *it ); KToolBarButton * button = (KToolBarButton *)( *it ); if ( button ) button->setPixmap( _pixmap ); } void KToolBar::setButtonIcon( int id, const QString& _icon ) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US KToolBarButton * button = dynamic_cast<KToolBarButton *>( *it ); KToolBarButton * button = (KToolBarButton *)( *it ); if ( button ) button->setIcon( _icon ); } void KToolBar::setButtonIconSet( int id, const QIconSet& iconset ) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US KToolBarButton * button = dynamic_cast<KToolBarButton *>( *it ); KToolBarButton * button = (KToolBarButton *)( *it ); if ( button ) button->setIconSet( iconset ); } void KToolBar::setDelayedPopup (int id , QPopupMenu *_popup, bool toggle ) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US KToolBarButton * button = dynamic_cast<KToolBarButton *>( *it ); KToolBarButton * button = (KToolBarButton *)( *it ); if ( button ) button->setDelayedPopup( _popup, toggle ); } void KToolBar::setAutoRepeat (int id, bool flag) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US KToolBarButton * button = dynamic_cast<KToolBarButton *>( *it ); KToolBarButton * button = (KToolBarButton *)( *it ); if ( button ) button->setAutoRepeat( flag ); } void KToolBar::setToggle (int id, bool flag ) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US KToolBarButton * button = dynamic_cast<KToolBarButton *>( *it ); KToolBarButton * button = (KToolBarButton *)( *it ); if ( button ) button->setToggle( flag ); } void KToolBar::toggleButton (int id) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US KToolBarButton * button = dynamic_cast<KToolBarButton *>( *it ); KToolBarButton * button = (KToolBarButton *)( *it ); if ( button ) button->toggle(); } void KToolBar::setButton (int id, bool flag) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US KToolBarButton * button = dynamic_cast<KToolBarButton *>( *it ); KToolBarButton * button = (KToolBarButton *)( *it ); if ( button ) button->on( flag ); } bool KToolBar::isButtonOn (int id) const { Id2WidgetMap::ConstIterator it = id2widget.find( id ); if ( it == id2widget.end() ) return false; //US KToolBarButton * button = dynamic_cast<KToolBarButton *>( *it ); KToolBarButton * button = (KToolBarButton *)( *it ); return button ? button->isOn() : false; } void KToolBar::setLinedText (int id, const QString& text) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US QLineEdit * lineEdit = dynamic_cast<QLineEdit *>( *it ); QLineEdit * lineEdit = (QLineEdit *)( *it ); if ( lineEdit ) lineEdit->setText( text ); } QString KToolBar::getLinedText (int id) const { Id2WidgetMap::ConstIterator it = id2widget.find( id ); if ( it == id2widget.end() ) return QString::null; //US QLineEdit * lineEdit = dynamic_cast<QLineEdit *>( *it ); QLineEdit * lineEdit = (QLineEdit *)( *it ); return lineEdit ? lineEdit->text() : QString::null; } void KToolBar::insertComboItem (int id, const QString& text, int index) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US QComboBox * comboBox = dynamic_cast<QComboBox *>( *it ); QComboBox * comboBox = (QComboBox *)( *it ); if (comboBox) comboBox->insertItem( text, index ); } void KToolBar::insertComboList (int id, const QStringList &list, int index) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US QComboBox * comboBox = dynamic_cast<QComboBox *>( *it ); QComboBox * comboBox = (QComboBox *)( *it ); if (comboBox) comboBox->insertStringList( list, index ); } void KToolBar::removeComboItem (int id, int index) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US QComboBox * comboBox = dynamic_cast<QComboBox *>( *it ); QComboBox * comboBox = (QComboBox *)( *it ); if (comboBox) comboBox->removeItem( index ); } void KToolBar::setCurrentComboItem (int id, int index) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US QComboBox * comboBox = dynamic_cast<QComboBox *>( *it ); QComboBox * comboBox = (QComboBox *)( *it ); if (comboBox) comboBox->setCurrentItem( index ); } void KToolBar::changeComboItem (int id, const QString& text, int index) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US QComboBox * comboBox = dynamic_cast<QComboBox *>( *it ); QComboBox * comboBox = (QComboBox *)( *it ); if (comboBox) comboBox->changeItem( text, index ); } void KToolBar::clearCombo (int id) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US QComboBox * comboBox = dynamic_cast<QComboBox *>( *it ); QComboBox * comboBox = (QComboBox *)( *it ); if (comboBox) comboBox->clear(); } QString KToolBar::getComboItem (int id, int index) const { Id2WidgetMap::ConstIterator it = id2widget.find( id ); if ( it == id2widget.end() ) return QString::null; //US QComboBox * comboBox = dynamic_cast<QComboBox *>( *it ); QComboBox * comboBox = (QComboBox *)( *it ); return comboBox ? comboBox->text( index ) : QString::null; } KComboBox * KToolBar::getCombo(int id) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return 0; //US return dynamic_cast<KComboBox *>( *it ); return (KComboBox *)( *it ); } KLineEdit * KToolBar::getLined (int id) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return 0; //US return dynamic_cast<KLineEdit *>( *it ); return (KLineEdit *)( *it ); } KToolBarButton * KToolBar::getButton (int id) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return 0; //US return dynamic_cast<KToolBarButton *>( *it ); return (KToolBarButton *)( *it ); } void KToolBar::alignItemRight (int id, bool right ) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; if ( rightAligned && !right && (*it) == rightAligned ) rightAligned = 0; if ( (*it) && right ) rightAligned = (*it); } QWidget *KToolBar::getWidget (int id) { Id2WidgetMap::Iterator it = id2widget.find( id ); return ( it == id2widget.end() ) ? 0 : (*it); } void KToolBar::setItemAutoSized (int id, bool yes ) { QWidget *w = getWidget(id); if ( w && yes ) setStretchableWidget( w ); } void KToolBar::clear () { QToolBar::clear(); widget2id.clear(); id2widget.clear(); } void KToolBar::removeItem(int id) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) { kdDebug(220) << "KToolBar::removeItem item " << id << " not found" << endl; return; } QWidget * w = (*it); id2widget.remove( id ); widget2id.remove( w ); widgets.removeRef( w ); delete w; } void KToolBar::removeItemDelayed(int id) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) { kdDebug(220) << "KToolBar::removeItem item " << id << " not found" << endl; return; } QWidget * w = (*it); id2widget.remove( id ); widget2id.remove( w ); widgets.removeRef( w ); w->blockSignals(true); d->idleButtons.append(w); layoutTimer->start( 50, TRUE ); } void KToolBar::hideItem (int id) { QWidget *w = getWidget(id); if ( w ) w->hide(); } void KToolBar::showItem (int id) { QWidget *w = getWidget(id); if ( w ) w->show(); } int KToolBar::itemIndex (int id) { QWidget *w = getWidget(id); return w ? widgets.findRef(w) : -1; } void KToolBar::setFullSize(bool flag ) { setHorizontalStretchable( flag ); setVerticalStretchable( flag ); } bool KToolBar::fullSize() const { return isHorizontalStretchable() || isVerticalStretchable(); } void KToolBar::enableMoving(bool flag ) { //US setMovingEnabled(flag); this->mainWindow()->setToolBarsMovable(flag); } void KToolBar::setBarPos (BarPosition bpos) { if ( !mainWindow() ) return; //US mainWindow()->moveDockWindow( this, (Dock)bpos ); mainWindow()->moveToolBar( this, (QMainWindow::ToolBarDock)bpos ); } -KToolBar::BarPosition KToolBar::barPos() const +const KToolBar::BarPosition KToolBar::barPos() { if ( !(QMainWindow*)mainWindow() ) return KToolBar::Top; //US Dock dock; QMainWindow::ToolBarDock dock; int dm1, dm2; bool dm3; ((QMainWindow*)mainWindow())->getLocation( (QToolBar*)this, dock, dm1, dm3, dm2 ); //US if ( dock == DockUnmanaged ) { if ( dock == QMainWindow::Unmanaged ) { return (KToolBar::BarPosition)Top; } return (BarPosition)dock; } bool KToolBar::enable(BarStatus stat) { bool mystat = isVisible(); if ( (stat == Toggle && mystat) || stat == Hide ) hide(); else show(); return isVisible() == mystat; } void KToolBar::setMaxHeight ( int h ) { setMaximumHeight( h ); } int KToolBar::maxHeight() { return maximumHeight(); } void KToolBar::setMaxWidth (int dw) { setMaximumWidth( dw ); } int KToolBar::maxWidth() { return maximumWidth(); } void KToolBar::setTitle (const QString& _title) { setLabel( _title ); } void KToolBar::enableFloating (bool ) { } void KToolBar::setIconText(IconText it) { setIconText( it, true ); } void KToolBar::setIconText(IconText icontext, bool update) { bool doUpdate=false; if (icontext != d->m_iconText) { d->m_iconText = icontext; doUpdate=true; } if (update == false) return; if (doUpdate) emit modechange(); // tell buttons what happened // ugly hack to force a QMainWindow::triggerLayout( TRUE ) if ( mainWindow() ) { QMainWindow *mw = mainWindow(); mw->setUpdatesEnabled( FALSE ); mw->setToolBarsMovable( !mw->toolBarsMovable() ); mw->setToolBarsMovable( !mw->toolBarsMovable() ); mw->setUpdatesEnabled( TRUE ); } } KToolBar::IconText KToolBar::iconText() const { return d->m_iconText; } void KToolBar::setIconSize(int size) { setIconSize( size, true ); } void KToolBar::setIconSize(int size, bool update) { bool doUpdate=false; if ( size != d->m_iconSize ) { d->m_iconSize = size; doUpdate=true; } if (update == false) return; if (doUpdate) emit modechange(); // tell buttons what happened // ugly hack to force a QMainWindow::triggerLayout( TRUE ) if ( mainWindow() ) { QMainWindow *mw = mainWindow(); mw->setUpdatesEnabled( FALSE ); mw->setToolBarsMovable( !mw->toolBarsMovable() ); mw->setToolBarsMovable( !mw->toolBarsMovable() ); mw->setUpdatesEnabled( TRUE ); } } int KToolBar::iconSize() const { /*US if ( !d->m_iconSize ) // default value? { if (!::qstrcmp(QObject::name(), "mainToolBar")) return KGlobal::iconLoader()->currentSize(KIcon::MainToolbar); else return KGlobal::iconLoader()->currentSize(KIcon::Toolbar); } return d->m_iconSize; */ int ret = 18; if ( QApplication::desktop()->width() > 320 ) ret = 30; return ret; } void KToolBar::setEnableContextMenu(bool enable ) { d->m_enableContext = enable; } bool KToolBar::contextMenuEnabled() const { return d->m_enableContext; } void KToolBar::setItemNoStyle(int id, bool no_style ) { Id2WidgetMap::Iterator it = id2widget.find( id ); if ( it == id2widget.end() ) return; //US KToolBarButton * button = dynamic_cast<KToolBarButton *>( *it ); KToolBarButton * button = (KToolBarButton *)( *it ); if (button) button->setNoStyle( no_style ); } void KToolBar::setFlat (bool flag) { if ( !mainWindow() ) return; if ( flag ) //US mainWindow()->moveDockWindow( this, DockMinimized ); mainWindow()->moveToolBar( this, QMainWindow::Minimized ); else //US mainWindow()->moveDockWindow( this, DockTop ); mainWindow()->moveToolBar( this, QMainWindow::Top ); // And remember to save the new look later /*US if ( mainWindow()->inherits( "KMainWindow" ) ) static_cast<KMainWindow *>(mainWindow())->setSettingsDirty(); */ } int KToolBar::count() const { return id2widget.count(); } void KToolBar::saveState() { /*US // first, try to save to the xml file if ( d->m_xmlguiClient && !d->m_xmlguiClient->xmlFile().isEmpty() ) { // go down one level to get to the right tags QDomElement elem = d->m_xmlguiClient->domDocument().documentElement().toElement(); elem = elem.firstChild().toElement(); QString barname(!::qstrcmp(name(), "unnamed") ? "mainToolBar" : name()); QDomElement current; // now try to find our toolbar d->modified = false; for( ; !elem.isNull(); elem = elem.nextSibling().toElement() ) { current = elem; if ( current.tagName().lower() != "toolbar" ) continue; QString curname(current.attribute( "name" )); if ( curname == barname ) { saveState( current ); break; } } // if we didn't make changes, then just return if ( !d->modified ) return; // now we load in the (non-merged) local file QString local_xml(KXMLGUIFactory::readConfigFile(d->m_xmlguiClient->xmlFile(), true, d->m_xmlguiClient->instance())); QDomDocument local; local.setContent(local_xml); // make sure we don't append if this toolbar already exists locally bool just_append = true; elem = local.documentElement().toElement(); KXMLGUIFactory::removeDOMComments( elem ); elem = elem.firstChild().toElement(); for( ; !elem.isNull(); elem = elem.nextSibling().toElement() ) { if ( elem.tagName().lower() != "toolbar" ) continue; QString curname(elem.attribute( "name" )); if ( curname == barname ) { just_append = false; local.documentElement().replaceChild( current, elem ); break; } } if (just_append) local.documentElement().appendChild( current ); KXMLGUIFactory::saveConfigFile(local, d->m_xmlguiClient->localXMLFile(), d->m_xmlguiClient->instance() ); return; } */ // if that didn't work, we save to the config file KConfig *config = KGlobal::config(); saveSettings(config, QString::null); config->sync(); } QString KToolBar::settingsGroup() { QString configGroup; if (!::qstrcmp(name(), "unnamed") || !::qstrcmp(name(), "mainToolBar")) configGroup = "Toolbar style"; else configGroup = QString(name()) + " Toolbar style"; if ( this->mainWindow() ) { configGroup.prepend(" "); configGroup.prepend( this->mainWindow()->name() ); } return configGroup; } void KToolBar::saveSettings(KConfig *config, const QString &_configGroup) { QString configGroup = _configGroup; if (configGroup.isEmpty()) configGroup = settingsGroup(); //kdDebug(220) << "KToolBar::saveSettings group=" << _configGroup << " -> " << configGroup << endl; QString position, icontext; int index; getAttributes( position, icontext, index ); //kdDebug(220) << "KToolBar::saveSettings " << name() << " newLine=" << newLine << endl; KConfigGroupSaver saver(config, configGroup); if ( position != d->PositionDefault ) config->writeEntry("Position", position); else config->deleteEntry("Position"); if ( icontext != d->IconTextDefault ) config->writeEntry("IconText", icontext); else config->deleteEntry("IconText"); if ( iconSize() != d->IconSizeDefault ) config->writeEntry("IconSize", iconSize()); else config->deleteEntry("IconSize"); if ( isHidden() != d->HiddenDefault ) config->writeEntry("Hidden", isHidden()); else config->deleteEntry("Hidden"); if ( index != d->IndexDefault ) config->writeEntry( "Index", index ); else config->deleteEntry("Index"); //US the older version of KDE (used on the Zaurus) has no Offset property /* if ( offset() != d->OffsetDefault ) config->writeEntry( "Offset", offset() ); else */ config->deleteEntry("Offset"); //US the older version of KDE (used on the Zaurus) has no NewLine property /* if ( newLine() != d->NewLineDefault ) config->writeEntry( "NewLine", newLine() ); else */ config->deleteEntry("NewLine"); } void KToolBar::setXMLGUIClient( KXMLGUIClient *client ) { d->m_xmlguiClient = client; } void KToolBar::setText( const QString & txt ) { //US setLabel( txt + " ( " + kapp->caption() + " ) " ); setLabel( txt + " ( " + KGlobal::getAppName() + " ) " ); } QString KToolBar::text() const { return label(); } void KToolBar::doConnections( KToolBarButton *button ) { connect(button, SIGNAL(clicked(int)), this, SIGNAL( clicked( int ) ) ); connect(button, SIGNAL(doubleClicked(int)), this, SIGNAL( doubleClicked( int ) ) ); connect(button, SIGNAL(released(int)), this, SIGNAL( released( int ) ) ); connect(button, SIGNAL(pressed(int)), this, SIGNAL( pressed( int ) ) ); connect(button, SIGNAL(toggled(int)), this, SIGNAL( toggled( int ) ) ); connect(button, SIGNAL(highlighted(int, bool)), this, SIGNAL( highlighted( int, bool ) ) ); } void KToolBar::mousePressEvent ( QMouseEvent *m ) { if ( !mainWindow() ) return; QMainWindow *mw = mainWindow(); if ( mw->toolBarsMovable() && d->m_enableContext ) { if ( m->button() == RightButton ) { int i = contextMenu()->exec( m->globalPos(), 0 ); switch ( i ) { case -1: return; // popup cancelled case CONTEXT_LEFT: //US mw->moveDockWindow( this, DockLeft ); mw->moveToolBar( this, QMainWindow::Left ); break; case CONTEXT_RIGHT: //US mw->moveDockWindow( this, DockRight ); mw->moveToolBar( this, QMainWindow::Right ); break; case CONTEXT_TOP: //US mw->moveDockWindow( this, DockTop ); mw->moveToolBar( this, QMainWindow::Top ); break; case CONTEXT_BOTTOM: //US mw->moveDockWindow( this, DockBottom ); mw->moveToolBar( this, QMainWindow::Bottom ); break; case CONTEXT_FLOAT: break; case CONTEXT_FLAT: //US mw->moveDockWindow( this, DockMinimized ); mw->moveToolBar( this, QMainWindow::Minimized ); break; case CONTEXT_ICONS: setIconText( IconOnly ); break; case CONTEXT_TEXTRIGHT: setIconText( IconTextRight ); break; case CONTEXT_TEXT: setIconText( TextOnly ); break; case CONTEXT_TEXTUNDER: setIconText( IconTextBottom ); break; default: if ( i >= CONTEXT_ICONSIZES ) setIconSize( i - CONTEXT_ICONSIZES ); else return; // assume this was an action handled elsewhere, no need for setSettingsDirty() } /*US if ( mw->inherits("KMainWindow") ) static_cast<KMainWindow *>(mw)->setSettingsDirty(); */ } } } void KToolBar::rebuildLayout() { for(QWidget *w=d->idleButtons.first(); w; w=d->idleButtons.next()) w->blockSignals(false); d->idleButtons.clear(); layoutTimer->stop(); QApplication::sendPostedEvents( this, QEvent::ChildInserted ); QBoxLayout *l = boxLayout(); l->setMargin( 1 ); // clear the old layout QLayoutIterator it = l->iterator(); while ( it.current() ) { it.deleteCurrent(); } for ( QWidget *w = widgets.first(); w; w = widgets.next() ) { if ( w == rightAligned ) { continue; } if ( w->inherits( "KToolBarSeparator" ) && !( (KToolBarSeparator*)w )->showLine() ) { l->addSpacing( 6 ); w->hide(); continue; } if ( w->inherits( "QPopupMenu" ) ) continue; l->addWidget( w ); w->show(); } if ( rightAligned ) { l->addStretch(); l->addWidget( rightAligned ); rightAligned->show(); } if ( fullSize() ) { // This code sucks. It makes the last combo in a toolbar VERY big (e.g. zoom combo in kword). //if ( !stretchableWidget && widgets.last() && // !widgets.last()->inherits( "QButton" ) && !widgets.last()->inherits( "KAnimWidget" ) ) // setStretchableWidget( widgets.last() ); if ( !rightAligned ) l->addStretch(); if ( stretchableWidget ) l->setStretchFactor( stretchableWidget, 10 ); } l->invalidate(); QApplication::postEvent( this, new QEvent( QEvent::LayoutHint ) ); //#endif //DESKTOP_VERSION } void KToolBar::childEvent( QChildEvent *e ) { if ( e->child()->isWidgetType() ) { QWidget * w = (QWidget*)e->child(); if ( e->type() == QEvent::ChildInserted ) { if ( !e->child()->inherits( "QPopupMenu" ) && ::qstrcmp( "qt_dockwidget_internal", e->child()->name() ) != 0 ) { // prevent items that have been explicitly inserted by insert*() from // being inserted again if ( !widget2id.contains( w ) ) { int dummy = -1; insertWidgetInternal( w, dummy, -1 ); } } } else { removeWidgetInternal( w ); } if ( isVisibleTo( 0 ) ) { QBoxLayout *l = boxLayout(); // QLayout *l = layout(); // clear the old layout so that we don't get unnecassery layout // changes till we have rebuild the thing QLayoutIterator it = l->iterator(); while ( it.current() ) { it.deleteCurrent(); } layoutTimer->start( 50, TRUE ); } } QToolBar::childEvent( e ); } void KToolBar::insertWidgetInternal( QWidget *w, int &index, int id ) { // we can't have it in widgets, or something is really wrong //widgets.removeRef( w ); connect( w, SIGNAL( destroyed() ), this, SLOT( widgetDestroyed() ) ); if ( index == -1 || index > (int)widgets.count() ) { widgets.append( w ); index = (int)widgets.count(); } else widgets.insert( index, w ); if ( id == -1 ) id = id2widget.count(); id2widget.insert( id, w ); widget2id.insert( w, id ); } void KToolBar::repaintMe() { setUpdatesEnabled( true ); QToolBar::repaint( true ); //qDebug(" KToolBar::repaintMe() "); } void KToolBar::showEvent( QShowEvent *e ) { QToolBar::showEvent( e ); rebuildLayout(); } void KToolBar::setStretchableWidget( QWidget *w ) { QToolBar::setStretchableWidget( w ); stretchableWidget = w; } QSizePolicy KToolBar::sizePolicy() const { if ( orientation() == Horizontal ) return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); else return QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding ); } QSize KToolBar::sizeHint() const { return QToolBar::sizeHint(); #if 0 QWidget::polish(); static int iii = 0; ++iii; qDebug("++++++++ KToolBar::sizeHint() %d ", iii ); int margin = static_cast<QWidget*>(ncThis)->layout()->margin(); switch( barPos() ) { case KToolBar::Top: case KToolBar::Bottom: for ( QWidget *w = widgets.first(); w; w =widgets.next() ) { if ( w->inherits( "KToolBarSeparator" ) && !( static_cast<KToolBarSeparator*>(w)->showLine() ) ) { minSize += QSize(6, 0); } else { QSize sh = w->sizeHint(); if (!sh.isValid()) sh = w->minimumSize(); minSize = minSize.expandedTo(QSize(0, sh.height())); minSize += QSize(sh.width()+1, 0); } } /*US minSize += QSize(QApplication::style().pixelMetric( QStyle::PM_DockWindowHandleExtent ), 0); */ minSize += QSize(margin*2, margin*2); break; case KToolBar::Left: case KToolBar::Right: for ( QWidget *w = widgets.first(); w; w = widgets.next() ) { if ( w->inherits( "KToolBarSeparator" ) && !( static_cast<KToolBarSeparator*>(w)->showLine() ) ) { minSize += QSize(0, 6); } else { QSize sh = w->sizeHint(); if (!sh.isValid()) sh = w->minimumSize(); minSize = minSize.expandedTo(QSize(sh.width(), 0)); minSize += QSize(0, sh.height()+1); } } /*US minSize += QSize(0, QApplication::style().pixelMetric( QStyle::PM_DockWindowHandleExtent )); */ minSize += QSize(margin*2, margin*2); break; default: minSize = QToolBar::sizeHint(); break; } return minSize; #endif } QSize KToolBar::minimumSize() const { return minimumSizeHint(); } QSize KToolBar::minimumSizeHint() const { return sizeHint(); } bool KToolBar::highlight() const { return d->m_highlight; } void KToolBar::hide() { QToolBar::hide(); } void KToolBar::show() { QToolBar::show(); } void KToolBar::resizeEvent( QResizeEvent *e ) { bool b = isUpdatesEnabled(); setUpdatesEnabled( FALSE ); QToolBar::resizeEvent( e ); if (b) d->repaintTimer.start( 100, true ); } void KToolBar::slotIconChanged(int group) { if ((group != KIcon::Toolbar) && (group != KIcon::MainToolbar)) return; if ((group == KIcon::MainToolbar) != !::qstrcmp(name(), "mainToolBar")) return; emit modechange(); if (isVisible()) updateGeometry(); } void KToolBar::slotReadConfig() { //kdDebug(220) << "KToolBar::slotReadConfig" << endl; // Read appearance settings (hmm, we used to do both here, // but a well behaved application will call applyMainWindowSettings // anyway, right ?) applyAppearanceSettings(KGlobal::config(), QString::null ); } void KToolBar::slotAppearanceChanged() { // Read appearance settings from global file. applyAppearanceSettings(KGlobal::config(), QString::null, true /* lose local settings */ ); // And remember to save the new look later /*US if ( mainWindow() && mainWindow()->inherits( "KMainWindow" ) ) static_cast<KMainWindow *>(mainWindow())->setSettingsDirty(); */ } //static bool KToolBar::highlightSetting() { QString grpToolbar(QString::fromLatin1("Toolbar style")); KConfigGroupSaver saver(KGlobal::config(), grpToolbar); return KGlobal::config()->readBoolEntry(QString::fromLatin1("Highlighting"),true); } //static bool KToolBar::transparentSetting() { QString grpToolbar(QString::fromLatin1("Toolbar style")); KConfigGroupSaver saver(KGlobal::config(), grpToolbar); return KGlobal::config()->readBoolEntry(QString::fromLatin1("TransparentMoving"),true); } //static KToolBar::IconText KToolBar::iconTextSetting() { QString grpToolbar(QString::fromLatin1("Toolbar style")); KConfigGroupSaver saver(KGlobal::config(), grpToolbar); QString icontext = KGlobal::config()->readEntry(QString::fromLatin1("IconText"),QString::fromLatin1("IconOnly")); if ( icontext == "IconTextRight" ) return IconTextRight; else if ( icontext == "IconTextBottom" ) return IconTextBottom; else if ( icontext == "TextOnly" ) return TextOnly; else return IconOnly; } void KToolBar::applyAppearanceSettings(KConfig *config, const QString &_configGroup, bool forceGlobal) { QString configGroup = _configGroup.isEmpty() ? settingsGroup() : _configGroup; //kdDebug(220) << "KToolBar::applyAppearanceSettings: configGroup=" << configGroup << endl; // We have application-specific settings in the XML file, // and nothing in the application's config file // -> don't apply the global defaults, the XML ones are preferred // See applySettings for a full explanation /*US :we do not support xml files if ( d->m_xmlguiClient && !d->m_xmlguiClient->xmlFile().isEmpty() && !config->hasGroup(configGroup) ) { //kdDebug(220) << "skipping global defaults, using XML ones instead" << endl; return; } */ if ( !config->hasGroup(configGroup) ) { //kdDebug(220) << "skipping global defaults, using XML ones instead" << endl; return; } KConfig *gconfig = KGlobal::config(); /*US static const QString &attrIconText = KGlobal::staticQString("IconText"); static const QString &attrHighlight = KGlobal::staticQString("Highlighting"); static const QString &attrTrans = KGlobal::staticQString("TransparentMoving"); static const QString &attrSize = KGlobal::staticQString("IconSize"); */ // we actually do this in two steps. // First, we read in the global styles [Toolbar style] (from the KControl module). // Then, if the toolbar is NOT 'mainToolBar', we will also try to read in [barname Toolbar style] bool highlight; int transparent; QString icontext; int iconsize = 0; // this is the first iteration QString grpToolbar(QString::fromLatin1("Toolbar style")); { // start block for KConfigGroupSaver KConfigGroupSaver saver(gconfig, grpToolbar); // first, get the generic settings //US highlight = gconfig->readBoolEntry(attrHighlight, true); highlight = gconfig->readBoolEntry("Highlighting", true); //US transparent = gconfig->readBoolEntry(attrTrans, true); transparent = gconfig->readBoolEntry("TransparentMoving", true); // we read in the IconText property *only* if we intend on actually // honoring it if (d->m_honorStyle) //US d->IconTextDefault = gconfig->readEntry(attrIconText, d->IconTextDefault); d->IconTextDefault = gconfig->readEntry("IconText", d->IconTextDefault); else d->IconTextDefault = "IconOnly"; // Use the default icon size for toolbar icons. //US d->IconSizeDefault = gconfig->readNumEntry(attrSize, d->IconSizeDefault); d->IconSizeDefault = gconfig->readNumEntry("IconSize", d->IconSizeDefault); if ( !forceGlobal && config->hasGroup(configGroup) ) { config->setGroup(configGroup); // first, get the generic settings //US highlight = config->readBoolEntry(attrHighlight, highlight); highlight = config->readBoolEntry("Highlighting", highlight); //US transparent = config->readBoolEntry(attrTrans, transparent); transparent = config->readBoolEntry("TransparentMoving", transparent); // now we always read in the IconText property //US icontext = config->readEntry(attrIconText, d->IconTextDefault); icontext = config->readEntry("IconText", d->IconTextDefault); // now get the size //US iconsize = config->readNumEntry(attrSize, d->IconSizeDefault); iconsize = config->readNumEntry("IconSize", d->IconSizeDefault); } else { iconsize = d->IconSizeDefault; icontext = d->IconTextDefault; } // revert back to the old group } // end block for KConfigGroupSaver bool doUpdate = false; IconText icon_text; if ( icontext == "IconTextRight" ) icon_text = IconTextRight; else if ( icontext == "IconTextBottom" ) icon_text = IconTextBottom; else if ( icontext == "TextOnly" ) icon_text = TextOnly; else icon_text = IconOnly; // check if the icon/text has changed if (icon_text != d->m_iconText) { //kdDebug(220) << "KToolBar::applyAppearanceSettings setIconText " << icon_text << endl; setIconText(icon_text, false); doUpdate = true; } // ...and check if the icon size has changed if (iconsize != d->m_iconSize) { setIconSize(iconsize, false); doUpdate = true; } QMainWindow *mw = mainWindow(); // ...and if we should highlight if ( highlight != d->m_highlight ) { d->m_highlight = highlight; doUpdate = true; } // ...and if we should move transparently if ( mw && transparent != (!mw->opaqueMoving()) ) { mw->setOpaqueMoving( !transparent ); } if (doUpdate) emit modechange(); // tell buttons what happened if (isVisible ()) updateGeometry(); } void KToolBar::applySettings(KConfig *config, const QString &_configGroup) { //kdDebug(220) << "KToolBar::applySettings group=" << _configGroup << endl; QString configGroup = _configGroup.isEmpty() ? settingsGroup() : _configGroup; /* Let's explain this a bit more in details. The order in which we apply settings is : Global config / <appnamerc> user settings if no XMLGUI is used Global config / App-XML attributes / <appnamerc> user settings if XMLGUI is used So in the first case, we simply read everything from KConfig as below, but in the second case we don't do anything here if there is no app-specific config, and the XMLGUI uses the static methods of this class to get the global defaults. Global config doesn't include position (index, offset, newline and hidden/shown). */ // First the appearance stuff - the one which has a global config applyAppearanceSettings( config, _configGroup ); // ...and now the position stuff if ( config->hasGroup(configGroup) ) { KConfigGroupSaver cgs(config, configGroup); /*US static const QString &attrPosition = KGlobal::staticQString("Position"); static const QString &attrIndex = KGlobal::staticQString("Index"); static const QString &attrOffset = KGlobal::staticQString("Offset"); static const QString &attrNewLine = KGlobal::staticQString("NewLine"); static const QString &attrHidden = KGlobal::staticQString("Hidden"); QString position = config->readEntry(attrPosition, d->PositionDefault); int index = config->readNumEntry(attrIndex, d->IndexDefault); int offset = config->readNumEntry(attrOffset, d->OffsetDefault); bool newLine = config->readBoolEntry(attrNewLine, d->NewLineDefault); bool hidden = config->readBoolEntry(attrHidden, d->HiddenDefault); */ QString position = config->readEntry("Position", d->PositionDefault); int index = config->readNumEntry("Index", d->IndexDefault); int offset = config->readNumEntry("Offset", d->OffsetDefault); bool newLine = config->readBoolEntry("NewLine", d->NewLineDefault); bool hidden = config->readBoolEntry("Hidden", d->HiddenDefault); /*US Dock pos(DockTop); if ( position == "Top" ) pos = DockTop; else if ( position == "Bottom" ) pos = DockBottom; else if ( position == "Left" ) pos = DockLeft; else if ( position == "Right" ) pos = DockRight; else if ( position == "Floating" ) pos = DockTornOff; else if ( position == "Flat" ) pos = DockMinimized; */ QMainWindow::ToolBarDock pos(QMainWindow::Top); if ( position == "Top" ) pos = QMainWindow::Top; else if ( position == "Bottom" ) pos = QMainWindow::Bottom; else if ( position == "Left" ) pos = QMainWindow::Left; else if ( position == "Right" ) pos = QMainWindow::Right; else if ( position == "Floating" ) pos = QMainWindow::TornOff; else if ( position == "Flat" ) pos = QMainWindow::Minimized; //kdDebug(220) << "KToolBar::applySettings hidden=" << hidden << endl; if (hidden) hide(); else show(); if ( mainWindow() ) { QMainWindow *mw = mainWindow(); //kdDebug(220) << "KToolBar::applySettings updating ToolbarInfo" << endl; d->toolBarInfo = KToolBarPrivate::ToolBarInfo( pos, index, newLine, offset ); // moveDockWindow calls QDockArea which does a reparent() on us with // showIt = true, so we loose our visibility status bool doHide = isHidden(); //US mw->moveDockWindow( this, pos, newLine, index, offset ); mw->moveToolBar( this, pos, newLine, index, offset ); //kdDebug(220) << "KToolBar::applySettings " << name() << " moveDockWindow with pos=" << pos << " newLine=" << newLine << " idx=" << index << " offs=" << offset << endl; if ( doHide ) hide(); } if (isVisible ()) updateGeometry(); } } bool KToolBar::event( QEvent *e ) { if ( (e->type() == QEvent::LayoutHint) && isUpdatesEnabled() ) d->repaintTimer.start( 100, true ); if (e->type() == QEvent::ChildInserted ) { // By pass QToolBar::event, // it will show() the inserted child and we don't want to // do that until we have rebuild the layout. childEvent((QChildEvent *)e); return true; } return QToolBar::event( e ); } void KToolBar::slotRepaint() { setUpdatesEnabled( FALSE ); // Send a resizeEvent to update the "toolbar extension arrow" // (The button you get when your toolbar-items don't fit in // the available space) QResizeEvent ev(size(), size()); resizeEvent(&ev); //#ifdef DESKTOP_VERSION QApplication::sendPostedEvents( this, QEvent::LayoutHint ); //#endif //DESKTOP_VERSION setUpdatesEnabled( TRUE ); repaint( TRUE ); } void KToolBar::toolBarPosChanged( QToolBar *tb ) { if ( tb != this ) return; //US if ( d->oldPos == DockMinimized ) if ( d->oldPos == QMainWindow::Minimized ) rebuildLayout(); d->oldPos = (QMainWindow::ToolBarDock)barPos(); /*US if ( mainWindow() && mainWindow()->inherits( "KMainWindow" ) ) static_cast<KMainWindow *>(mainWindow())->setSettingsDirty(); */ } /*US void KToolBar::loadState( const QDomElement &element ) { //kdDebug(220) << "KToolBar::loadState " << this << endl; if ( !mainWindow() ) return; { QCString text = element.namedItem( "text" ).toElement().text().utf8(); if ( text.isEmpty() ) text = element.namedItem( "Text" ).toElement().text().utf8(); if ( !text.isEmpty() ) setText( i18n( text ) ); } { QCString attrFullWidth = element.attribute( "fullWidth" ).lower().latin1(); if ( !attrFullWidth.isEmpty() ) setFullSize( attrFullWidth == "true" ); } Dock dock = DockTop; { QCString attrPosition = element.attribute( "position" ).lower().latin1(); //kdDebug(220) << "KToolBar::loadState attrPosition=" << attrPosition << endl; if ( !attrPosition.isEmpty() ) { if ( attrPosition == "top" ) dock = DockTop; else if ( attrPosition == "left" ) dock = DockLeft; else if ( attrPosition == "right" ) dock = DockRight; else if ( attrPosition == "bottom" ) dock = DockBottom; else if ( attrPosition == "floating" ) dock = DockTornOff; else if ( attrPosition == "flat" ) dock = DockMinimized; } } { QCString attrIconText = element.attribute( "iconText" ).lower().latin1(); if ( !attrIconText.isEmpty() ) { //kdDebug(220) << "KToolBar::loadState attrIconText=" << attrIconText << endl; if ( attrIconText == "icontextright" ) setIconText( KToolBar::IconTextRight ); else if ( attrIconText == "textonly" ) setIconText( KToolBar::TextOnly ); else if ( attrIconText == "icontextbottom" ) setIconText( KToolBar::IconTextBottom ); else if ( attrIconText == "icononly" ) setIconText( KToolBar::IconOnly ); } else // Use global setting setIconText( iconTextSetting() ); } { QString attrIconSize = element.attribute( "iconSize" ).lower(); if ( !attrIconSize.isEmpty() ) d->IconSizeDefault = attrIconSize.toInt(); setIconSize( d->IconSizeDefault ); } { QString attrIndex = element.attribute( "index" ).lower(); if ( !attrIndex.isEmpty() ) d->IndexDefault = attrIndex.toInt(); } { QString attrOffset = element.attribute( "offset" ).lower(); if ( !attrOffset.isEmpty() ) d->OffsetDefault = attrOffset.toInt(); } { QString attrNewLine = element.attribute( "newline" ).lower(); if ( !attrNewLine.isEmpty() ) d->NewLineDefault = attrNewLine == "true"; } { QString attrHidden = element.attribute( "hidden" ).lower(); if ( !attrHidden.isEmpty() ) d->HiddenDefault = attrHidden == "true"; } d->toolBarInfo = KToolBarPrivate::ToolBarInfo( dock, d->IndexDefault, d->NewLineDefault, d->OffsetDefault ); mainWindow()->addDockWindow( this, dock, d->NewLineDefault ); //US mainWindow()->moveDockWindow( this, dock, d->NewLineDefault, d->IndexDefault, d->OffsetDefault ); mainWindow()->moveToolBar( this, dock, d->NewLineDefault, d->IndexDefault, d->OffsetDefault ); // Apply the highlight button setting d->m_highlight = highlightSetting(); // Apply transparent-toolbar-moving setting (ok, this is global to the mainwindow, // but we do it only if there are toolbars...) if ( transparentSetting() != !mainWindow()->opaqueMoving() ) mainWindow()->setOpaqueMoving( !transparentSetting() ); if ( d->HiddenDefault ) hide(); else show(); getAttributes( d->PositionDefault, d->IconTextDefault, d->IndexDefault ); } */ void KToolBar::getAttributes( QString &position, QString &icontext, int &index ) { // get all of the stuff to save switch ( barPos() ) { case KToolBar::Flat: position = "Flat"; break; case KToolBar::Bottom: position = "Bottom"; break; case KToolBar::Left: position = "Left"; break; case KToolBar::Right: position = "Right"; break; case KToolBar::Floating: position = "Floating"; break; case KToolBar::Top: default: position = "Top"; break; } if ( mainWindow() ) { QMainWindow::ToolBarDock dock; bool newLine; int offset; mainWindow()->getLocation( this, dock, index, newLine, offset ); } switch (d->m_iconText) { case KToolBar::IconTextRight: icontext = "IconTextRight"; break; case KToolBar::IconTextBottom: icontext = "IconTextBottom"; break; case KToolBar::TextOnly: icontext = "TextOnly"; break; case KToolBar::IconOnly: default: icontext = "IconOnly"; break; } } /*US void KToolBar::saveState( QDomElement ¤t ) { QString position, icontext; int index = -1; getAttributes( position, icontext, index ); current.setAttribute( "noMerge", "1" ); current.setAttribute( "position", position ); current.setAttribute( "iconText", icontext ); current.setAttribute( "index", index ); current.setAttribute( "offset", offset() ); current.setAttribute( "newline", newLine() ); if ( isHidden() ) current.setAttribute( "hidden", "true" ); d->modified = true; } */ void KToolBar::positionYourself( bool force ) { if (force) d->positioned = false; if ( d->positioned || !mainWindow() ) { //kdDebug(220) << "KToolBar::positionYourself d->positioned=true ALREADY DONE" << endl; return; } // we can't test for ForceHide after moveDockWindow because QDockArea // does a reparent() with showIt == true bool doHide = isHidden(); //kdDebug(220) << "positionYourself " << name() << " dock=" << d->toolBarInfo.dock << " newLine=" << d->toolBarInfo.newline << " offset=" << d->toolBarInfo.offset << endl; /*US mainWindow()->moveDockWindow( this, d->toolBarInfo.dock, d->toolBarInfo.newline, d->toolBarInfo.index, d->toolBarInfo.offset ); */ mainWindow()->moveToolBar( this, d->toolBarInfo.dock, d->NewLineDefault, d->IndexDefault, d->OffsetDefault ); if ( doHide ) hide(); // This method can only have an effect once - unless force is set d->positioned = TRUE; } //US KPopupMenu *KToolBar::contextMenu() QPopupMenu *KToolBar::contextMenu() { if ( context ) return context; // Construct our context popup menu. Name it qt_dockwidget_internal so it // won't be deleted by QToolBar::clear(). //US context = new KPopupMenu( this, "qt_dockwidget_internal" ); context = new QPopupMenu( this, "qt_dockwidget_internal" ); //US context->insertTitle(i18n("Toolbar Menu")); //US KPopupMenu *orient = new KPopupMenu( context, "orient" ); QPopupMenu *orient = new QPopupMenu( context, "orient" ); orient->insertItem( i18n("toolbar position string","Top"), CONTEXT_TOP ); orient->insertItem( i18n("toolbar position string","Left"), CONTEXT_LEFT ); orient->insertItem( i18n("toolbar position string","Right"), CONTEXT_RIGHT ); orient->insertItem( i18n("toolbar position string","Bottom"), CONTEXT_BOTTOM ); orient->insertSeparator(-1); //orient->insertItem( i18n("toolbar position string","Floating"), CONTEXT_FLOAT ); orient->insertItem( i18n("min toolbar", "Flat"), CONTEXT_FLAT ); //US KPopupMenu *mode = new KPopupMenu( context, "mode" ); QPopupMenu *mode = new QPopupMenu( context, "mode" ); mode->insertItem( i18n("Icons Only"), CONTEXT_ICONS ); mode->insertItem( i18n("Text Only"), CONTEXT_TEXT ); mode->insertItem( i18n("Text Alongside Icons"), CONTEXT_TEXTRIGHT ); mode->insertItem( i18n("Text Under Icons"), CONTEXT_TEXTUNDER ); //US KPopupMenu *size = new KPopupMenu( context, "size" ); QPopupMenu *size = new QPopupMenu( context, "size" ); size->insertItem( i18n("Default"), CONTEXT_ICONSIZES ); // Query the current theme for available sizes QValueList<int> avSizes; /*US KIconTheme *theme = KGlobal::instance()->iconLoader()->theme(); if (!::qstrcmp(QObject::name(), "mainToolBar")) avSizes = theme->querySizes( KIcon::MainToolbar); else avSizes = theme->querySizes( KIcon::Toolbar); */ avSizes << 16; avSizes << 32; d->iconSizes = avSizes; QValueList<int>::Iterator it; for (it=avSizes.begin(); it!=avSizes.end(); it++) { QString text; if ( *it < 19 ) text = i18n("Small (%1x%2)").arg(*it).arg(*it); else if (*it < 25) text = i18n("Medium (%1x%2)").arg(*it).arg(*it); else text = i18n("Large (%1x%2)").arg(*it).arg(*it); //we use the size as an id, with an offset size->insertItem( text, CONTEXT_ICONSIZES + *it ); } context->insertItem( i18n("Orientation"), orient ); orient->setItemChecked(CONTEXT_TOP, true); context->insertItem( i18n("Text Position"), mode ); context->setItemChecked(CONTEXT_ICONS, true); context->insertItem( i18n("Icon Size"), size ); /*US if (mainWindow()->inherits("KMainWindow")) { if ( (static_cast<KMainWindow*>(mainWindow())->toolBarMenuAction()) && (static_cast<KMainWindow*>(mainWindow())->hasMenuBar()) ) (static_cast<KMainWindow*>(mainWindow()))->toolBarMenuAction()->plug(context); } */ connect( context, SIGNAL( aboutToShow() ), this, SLOT( slotContextAboutToShow() ) ); return context; } void KToolBar::slotContextAboutToShow() { if (!d->m_configurePlugged) { // try to find "configure toolbars" action KXMLGUIClient *xmlGuiClient = d->m_xmlguiClient; if ( !xmlGuiClient && mainWindow() && mainWindow()->inherits( "KMainWindow" ) ) xmlGuiClient = (KXMLGUIClient *)mainWindow(); if ( xmlGuiClient ) { KAction *configureAction = xmlGuiClient->actionCollection()->action(KStdAction::stdName(KStdAction::ConfigureToolbars)); if ( configureAction ) { configureAction->plug(context); d->m_configurePlugged = true; } } } for(int i = CONTEXT_ICONS; i <= CONTEXT_TEXTUNDER; ++i) context->setItemChecked(i, false); switch( d->m_iconText ) { case IconOnly: default: context->setItemChecked(CONTEXT_ICONS, true); break; case IconTextRight: context->setItemChecked(CONTEXT_TEXTRIGHT, true); break; case TextOnly: context->setItemChecked(CONTEXT_TEXT, true); break; case IconTextBottom: context->setItemChecked(CONTEXT_TEXTUNDER, true); break; } QValueList<int>::ConstIterator iIt = d->iconSizes.begin(); QValueList<int>::ConstIterator iEnd = d->iconSizes.end(); for (; iIt != iEnd; ++iIt ) context->setItemChecked( CONTEXT_ICONSIZES + *iIt, false ); context->setItemChecked( CONTEXT_ICONSIZES, false ); context->setItemChecked( CONTEXT_ICONSIZES + d->m_iconSize, true ); for ( int i = CONTEXT_TOP; i <= CONTEXT_FLAT; ++i ) context->setItemChecked( i, false ); switch ( barPos() ) { case KToolBar::Flat: context->setItemChecked( CONTEXT_FLAT, true ); break; case KToolBar::Bottom: context->setItemChecked( CONTEXT_BOTTOM, true ); break; case KToolBar::Left: context->setItemChecked( CONTEXT_LEFT, true ); break; case KToolBar::Right: context->setItemChecked( CONTEXT_RIGHT, true ); break; case KToolBar::Floating: context->setItemChecked( CONTEXT_FLOAT, true ); break; case KToolBar::Top: context->setItemChecked( CONTEXT_TOP, true ); break; default: break; } } void KToolBar::widgetDestroyed() { removeWidgetInternal( (QWidget*)sender() ); } void KToolBar::removeWidgetInternal( QWidget * w ) { if ( inshutdownprocess ) return; widgets.removeRef( w ); QMap< QWidget*, int >::Iterator it = widget2id.find( w ); if ( it == widget2id.end() ) return; id2widget.remove( *it ); widget2id.remove( it ); } void KToolBar::virtual_hook( int, void* ) { /*BASE::virtual_hook( id, data );*/ } //US #include "ktoolbar.moc" diff --git a/microkde/kdeui/ktoolbar.h b/microkde/kdeui/ktoolbar.h index 49ff856..7a5c114 100644 --- a/microkde/kdeui/ktoolbar.h +++ b/microkde/kdeui/ktoolbar.h @@ -1,1108 +1,1108 @@ /* This file is part of the KDE libraries Copyright (C) 2000 Reginald Stadlbauer (reggie@kde.org) (C) 1997, 1998 Stephan Kulow (coolo@kde.org) (C) 1997, 1998 Sven Radej (radej@kde.org) (C) 1997, 1998 Mark Donohoe (donohoe@kde.org) (C) 1997, 1998 Matthias Ettrich (ettrich@kde.org) (C) 1999, 2000 Kurt Granroth (granroth@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef KTOOLBAR_H #define KTOOLBAR_H #ifndef DESKTOP_VERSION #define private public #include <qtoolbar.h> #undef private #include <qpe/qpetoolbar.h> #else #include <qtoolbar.h> #endif #include <qmainwindow.h> #include <qcombobox.h> #include <qmap.h> #include <qptrlist.h> #include <kglobal.h> #include <qguardedptr.h> #include <qframe.h> #include <qiconset.h> class QDomElement; class QSize; class QPixmap; class QPopupMenu; class QStringList; class QDomDocument; class QTimer; class KLineEdit; class KToolBar; class KToolBarButton; class KToolBoxManager; //US class KAnimWidget; //US class KPopupMenu; //US class KInstance; class KComboBox; class KXMLGUIClient; class KToolBarPrivate; class KToolBarSeparator : public QFrame { Q_OBJECT public: KToolBarSeparator( Orientation, bool l, QToolBar *parent, const char* name=0 ); QSize sizeHint() const; Orientation orientation() const { return orient; } QSizePolicy sizePolicy() const; bool showLine() const { return line; } public slots: void setOrientation( Orientation ); protected: void styleChange( QStyle& ); private: Orientation orient; bool line; }; /** * A KDE-style toolbar. * * KToolBar can be dragged around in and between different docks. * * A KToolBar can contain all sorts of widgets. * * KToolBar can be used as a standalone widget, but @ref KMainWindow * provides easy factories and management of one or more toolbars. * Once you have a KToolBar object, you can insert items into it with the * insert... methods, or remove them with the @ref removeItem() method. This * can be done at any time; the toolbar will be automatically updated. * There are also many methods to set per-child properties like alignment * and toggle behaviour. * * KToolBar uses a global config group to load toolbar settings on * construction. It will reread this config group on a * @ref KApplication::appearanceChanged() signal. * * @short Floatable toolbar with auto resize. * @version $Id$ * @author Reginald Stadlbauer <reggie@kde.org>, Stephan Kulow <coolo@kde.org>, Sven Radej <radej@kde.org>. */ // strange things are happening ... so I have to use strange define methods ... // porting KToolBar back to Qt2 really needs some strange hacks #ifndef DESKTOP_VERSION #define QToolBar QPEToolBar #endif class KToolBar : public QToolBar { Q_OBJECT Q_ENUMS( IconText BarPosition ) Q_PROPERTY( IconText iconText READ iconText WRITE setIconText ) Q_PROPERTY( BarPosition barPos READ barPos WRITE setBarPos ) Q_PROPERTY( bool fullSize READ fullSize WRITE setFullSize ) Q_PROPERTY( int iconSize READ iconSize WRITE setIconSize ) Q_PROPERTY( QString text READ text WRITE setText ) #ifndef DESKTOP_VERSION #undef QToolBar #endif public: enum IconText{IconOnly = 0, IconTextRight, TextOnly, IconTextBottom}; /** * The state of the status bar. * @deprecated **/ enum BarStatus{Toggle, Show, Hide}; /** * Possible bar positions. **/ enum BarPosition{ Unmanaged, Floating, Top, Bottom, Right, Left, Flat}; /** * Constructor. * This constructor is used by the XML-GUI. If you use it, you need * to call QMainWindow::addToolBar to specify the position of the toolbar. * So it's simpler to use the other constructor. * * The toolbar will read in various global config settings for * things like icon size and text position, etc. However, some of * the settings will be honored only if @ref #_honor_mode is set to * true. All other toolbars will be IconOnly and use Medium icons. * * @param parent The standard toolbar parent (usually a * @ref KMainWindow) * @param name The standard internal name * @param honor_style If true, then global settings for IconSize and IconText will be honored * @param readConfig whether to apply the configuration (global and application-specific) */ KToolBar( QWidget *parent, const char *name = 0, bool honor_style = FALSE, bool readConfig = TRUE ); /** * Constructor for non-XML-GUI applications. * * The toolbar will read in various global config settings for * things like icon size and text position, etc. However, some of * the settings will be honored only if @ref #_honor_mode is set to * true. All other toolbars will be IconOnly and use Medium icons. * * @param parentWindow The window that should be the parent of this toolbar * @param dock The position of the toolbar. Usually QMainWindow::Top. * @param newLine If true, start a new line in the dock for this toolbar. * @param name The standard internal name * @param honor_style If true, then global settings for IconSize and IconText will be honored * @param readConfig whether to apply the configuration (global and application-specific) */ KToolBar( QMainWindow *parentWindow, QMainWindow::ToolBarDock dock /*= QMainWindow::Top*/, bool newLine = false, const char *name = 0, bool honor_style = FALSE, bool readConfig = TRUE ); /** * Constructor for non-XML-GUI applications. * * The toolbar will read in various global config settings for * things like icon size and text position, etc. However, some of * the settings will be honored only if @ref #_honor_mode is set to * true. All other toolbars will be IconOnly and use Medium icons. * * @param parentWindow The window that should be the parent of this toolbar * @param dock Another widget than the mainwindow to dock toolbar to. * @param newLine If true, start a new line in the dock for this toolbar. * @param name The standard internal name * @param honor_style If true, then global settings for IconSize and IconText will be honored * @param readConfig whether to apply the configuration (global and application-specific) */ KToolBar( QMainWindow *parentWindow, QWidget *dock, bool newLine = false, const char *name = 0, bool honor_style = FALSE, bool readConfig = TRUE ); virtual ~KToolBar(); /** * Insert a button (a @ref KToolBarButton) with a pixmap. The * pixmap is loaded by the button itself based on the global icon * settings. * * You should connect to one or more signals in KToolBar: * @ref clicked() , @ref pressed() , @ref released() , or * @ref highlighted() and if the button is a toggle button * (@ref setToggle() ) @ref toggled() . Those signals have @p id * of a button that caused the signal. If you want to bind a popup * to button, see @ref setButton(). * * @param icon The name of the icon to use as the active pixmap * @param id The id of this button * @param enabled Enable or disable the button at startup * @param text The tooltip or toolbar text (depending on state) * @param index The position of the button. (-1 = at end). * * @return The item index. */ int insertButton(const QString& icon, int id, bool enabled = true, const QString& text = QString::null, int index=-1/*US , KInstance *_instance = KGlobal::instance()*/); /** * This is the same as above, but with specified signals and * slots to which this button will be connected. * * You can add more signals with @ref addConnection(). * * @param icon The name of the icon to use as the active pixmap * @param id The id of this button * @param signal The signal to connect to * @param receiver The slot's parent * @param enabled Enable or disable the button at startup * @param text The tooltip or toolbar text (depending on state) * @param index The position of the button. (-1 = at end). * * @return The item index. */ int insertButton(const QString& icon, int id, const char *signal, const QObject *receiver, const char *slot, bool enabled = true, const QString& text = QString::null, int index=-1/*US, KInstance *_instance = KGlobal::instance()*/ ); /** * Inserts a button (a @ref KToolBarButton) with the specified * pixmap. This pixmap will be used as the "active" one and the * disabled and default ones will be autogenerated. * * It is recommended that you use the insertButton function that * allows you to specify the icon name rather then the pixmap * itself. Specifying the icon name is much more flexible. * * You should connect to one or more signals in KToolBar: * @ref clicked() , @ref pressed() , @ref released() , or * @ref highlighted() and if the button is a toggle button * (@ref setToggle() ) @ref toggled() . Those signals have @p id * of a button that caused the signal. If you want to bind a popup * to button, see @ref setButton(). * * @param pixmap The active pixmap * @param id The id of this button * @param enabled Enable or disable the button at startup * @param text The tooltip or toolbar text (depending on state) * @param index The position of the button. (-1 = at end). * * @return The item index. */ int insertButton(const QPixmap& pixmap, int id, bool enabled = true, const QString& text = QString::null, int index=-1 ); /** * This is the same as above, but with specified signals and * slots to which this button will be connected. * * You can add more signals with @ref addConnection(). * * @param icon The name of the icon to use as the active pixmap * @param id The id of this button * @param signal The signal to connect to * @param receiver The slot's parent * @param enabled Enable or disable the button at startup * @param text The tooltip or toolbar text (depending on state) * @param index The position of the button. (-1 = at end). * * @return The item index. */ int insertButton(const QPixmap& pixmap, int id, const char *signal, const QObject *receiver, const char *slot, bool enabled = true, const QString& text = QString::null, int index=-1 ); /** * Inserts a button with popupmenu. * * Button will have small * triangle. You have to connect to popup's signals. The * signals @ref KButton::pressed(), @ref KButton::released(), * @ref KButton::clicked() or @ref KButton::doubleClicked() are @p not * emmited by * this button (see @ref setDelayedPopup() for that). * You can add custom popups which inherit @ref QPopupMenu to get popups * with tables, drawings etc. Just don't fiddle with events there. */ int insertButton(const QString& icon, int id, QPopupMenu *popup, bool enabled, const QString&_text, int index=-1); /** * Inserts a button with popupmenu. * * Button will have small * triangle. You have to connect to popup's signals. The * signals @ref KButton::pressed(), @ref KButton::released(), * @ref KButton::clicked() or @ref KButton::doubleClicked() are @p not * emmited by * this button (see @ref setDelayedPopup() for that). * You can add custom popups which inherit @ref QPopupMenu to get popups * with tables, drawings etc. Just don't fiddle with events there. */ int insertButton(const QPixmap& pixmap, int id, QPopupMenu *popup, bool enabled, const QString&_text, int index=-1); /** * Inserts a @ref KLineEdit. You have to specify signals and slots to * which KLineEdit will be connected. KLineEdit has all slots QLineEdit * has, plus signals @ref KLineEdit::completion and @ref KLineEdit::textRotation * KLineEdit can be set to autoresize itself to full free width * in toolbar, that is to last right aligned item. For that, * toolbar must be set to full width (which it is by default). * @see setFullWidth() * @see setItemAutoSized() * @see KLineEdit * @return Item index. */ int insertLined (const QString& text, int id, const char *signal, const QObject *receiver, const char *slot, bool enabled = true, const QString& toolTipText = QString::null, int size = 70, int index =-1); /** * Inserts a @ref KComboBox with list. * * Can be writable, but cannot contain * pixmaps. By default inserting policy is AtBottom, i.e. typed items * are placed at the bottom of the list. Can be autosized. If the size * argument is specified as -1, the width of the combobox is automatically * computed. * * @see setFullWidth() * @see setItemAutoSized() * @see KComboBox * @return Item index. */ int insertCombo (const QStringList &list, int id, bool writable, const char *signal, const QObject *receiver, const char *slot, bool enabled=true, const QString& tooltiptext=QString::null, int size=70, int index=-1, QComboBox::Policy policy = QComboBox::AtBottom); /** * Insert a @ref KComboBox with text. * * The rest is the same as above. * @see setItemAutoSized() * * @see KComboBox * @return Item index. */ int insertCombo (const QString& text, int id, bool writable, const char *signal, QObject *recevier, const char *slot, bool enabled=true, const QString& tooltiptext=QString::null, int size=70, int index=-1, QComboBox::Policy policy = QComboBox::AtBottom); /** * Inserts a separator into the toolbar with the given id. * Returns the separator's index */ int insertSeparator( int index = -1, int id = -1 ); /** * Inserts a line separator into the toolbar with the given id. * Returns the separator's index */ int insertLineSeparator( int index = -1, int id = -1 ); /** * Inserts a user-defined widget. The widget @p must have this * toolbar as its parent. * * Widget must have a QWidget for base class. Widget can be * autosized to full width. If you forget about it, you can get a * pointer to this widget with @ref getWidget(). * @see setItemAutoSized() * @return Item index. */ int insertWidget(int id, int width, QWidget *_widget, int index=-1); /** * Inserts an animated widget. A @ref KAnimWidget will be created * internally using the icon name you provide. * This will emit a signal (clicked()) whenever the * animation widget is clicked. * * @see animatedWidget() * * @param id The id for this toolbar item * @param receiver The parent of your slot * @param slot The slot to receive the clicked() signal * @param icons The name of the animation icon group to use * @param index The item index * * @return The item index */ /*US int insertAnimatedWidget(int id, QObject *receiver, const char *slot, const QString& icons, int index = -1); */ /** * This will return a pointer to the given animated widget, if it * exists. * * @see insertAnimatedWidget * * @param id The id for the widget you want to get a pointer to * * @return A pointer to the current animated widget or 0L */ //US KAnimWidget *animatedWidget( int id ); /** * Adds connections to items. * * It is important that you * know the @p id of particular item. Nothing happens if you forget @p id. */ void addConnection (int id, const char *signal, const QObject *receiver, const char *slot); /** * Enables/disables item. */ void setItemEnabled( int id, bool enabled ); /** * Sets the icon for a button. * * Can be used while button is visible. */ void setButtonIcon( int id, const QString& _icon ); /** * Sets button pixmap. * * Can be used while button is visible. */ void setButtonPixmap( int id, const QPixmap& _pixmap ); /** * Sets a button icon from a QIconSet. * * Can be used while button is visible. */ void setButtonIconSet( int id, const QIconSet& iconset ); /** * Sets a delayed popup for a button. * * Delayed popup is what you see in * Netscape Navigator's Previous and Next buttons: If you click them you * go back * or forth. If you press them long enough, you get a history-menu. * This is exactly what we do here. * * You will insert normal a button with connection (or use signals from * toolbar): * <pre> * bar->insertButton(icon, id, SIGNAL(clicked ()), this, * SLOT (slotClick()), true, "click or wait for popup"); * </pre> And then add a delayed popup: * <pre> * bar->setDelayedPopup (id, historyPopup); </pre> * * Don't add delayed popups to buttons which have normal popups. * * You may add popups which are derived from @ref QPopupMenu. You may * add popups that are already in the menu bar or are submenus of * other popups. */ void setDelayedPopup (int id , QPopupMenu *_popup, bool toggle = false); /** * Turns a button into an autorepeat button. * * Toggle buttons, buttons with menus, or * buttons with delayed menus cannot be made into autorepeat buttons. * Moreover, you can and will receive * only the signal clicked(), but not pressed() or released(). * When the user presses this button, you will receive the signal clicked(), * and if the button is still pressed after some time, * you will receive more clicked() signals separated by regular * intervals. Since this uses @ref QButton::setAutoRepeat() , * I can't quantify 'some'. */ void setAutoRepeat (int id, bool flag=true); /** * Turns button into a toggle button if @p flag is true. */ void setToggle (int id, bool flag = true); /** * Toggles a togglebutton. * * If the button is a toggle button (see @ref setToggle()) * the button state will be toggled. This will also cause the toolbar to * emit the signal @ref KButton::toggled() with parameter @p id. You must connect to * this signal, or use @ref addConnection() to connect directly to the * button signal @ref KButton::toggled(). */ void toggleButton (int id); /** * Sets a toggle button state. * * If the button is a toggle button (see @ref setToggle()) * this will set its state flag. This will also emit the signal * @ref KButton::toggled(). * * @see setToggle() */ void setButton (int id, bool flag); /** * @return @p true if button is on, @p false if button is off or if the * button is not a toggle button. * @see setToggle() */ bool isButtonOn (int id) const; /** * Sets the text of a line editor. * * Cursor is set at end of text. */ void setLinedText (int id, const QString& text); /** * Returns a line editor text. */ QString getLinedText (int id) const; /** * Inserts @p text in combobox @p id at position @p index. */ void insertComboItem (int id, const QString& text, int index); /** * Inserts @p list in combobox @p id at position @p index. */ void insertComboList (int id, const QStringList &list, int index); /** * Removes item @p index from combobox @p id. */ void removeComboItem (int id, int index); /** * Sets item @p index to be current item in combobox @p id. */ void setCurrentComboItem (int id, int index); /** * Changes item @p index in combobox @p id to text. * * @p index = -1 refers current item (one displayed in the button). */ void changeComboItem (int id, const QString& text, int index=-1); /** * Clears the combobox @p id. * * Does not delete it or hide it. */ void clearCombo (int id); /** * Returns text of item @p index from combobox @p id. * * @p index = -1 refers to current item. */ QString getComboItem (int id, int index=-1) const; /** * Returns a pointer to the combobox. * * Example: * <pre> * KComboBox *combo = toolbar->getCombo(combo_id); * </pre> * That way you can get access to other public methods * that @ref KComboBox provides. */ KComboBox * getCombo(int id); /** * Returns a pointer to KToolBarLined. * * Example: * <pre> * KLineEdit * lined = toolbar->getKToolBarLined(lined_id); * </pre> * That way you can get access to other public methods * that @ref KLineEdit provides. @ref KLineEdit is the same thing * as @ref QLineEdit plus completion signals. */ KLineEdit * getLined (int id); /** * Returns a pointer to KToolBarButton. * * Example: * <pre> * KToolBarButton * button = toolbar->getButton(button_id); * </pre> * That way you can get access to other public methods * that @ref KToolBarButton provides. * * Using this method is not recommended. */ KToolBarButton * getButton (int id); /** * Align item to the right. * * This works only if toolbar is set to full width. * @see setFullWidth() */ void alignItemRight (int id, bool right = true); /** * Returns a pointer to an inserted widget. * * Wrong ids are not tested. * You can do with this whatever you want, * except change its height (hardcoded). If you change its width * you will probably have to call QToolBar::updateRects(true) * @see QWidget * @see updateRects() * * KDE4: make this const! */ QWidget *getWidget (int id); /** * Set item autosized. * * This works only if the toolbar is set to full width. * Only @p one item can be autosized, and it has to be * the last left-aligned item. Items that come after this must be right * aligned. Items that can be right aligned are Lineds, Frames, Widgets and * Combos. An autosized item will resize itself whenever the toolbar geometry * changes to the last right-aligned item (or to end of toolbar if there * are no right-aligned items.) * @see setFullWidth() * @see alignItemRight() */ void setItemAutoSized (int id, bool yes = true); /** * Remove all items. * * The toolbar is redrawn after it. */ void clear (); /** * Remove item @p id. * * Item is deleted. Toolbar is redrawn after it. */ void removeItem (int id); /** * Remove item @p id. * * Item is deleted when toolbar is redrawn. */ void removeItemDelayed (int id); /** * Hide item. */ void hideItem (int id); /** * Show item. */ void showItem (int id); /** * Returns the index of the given item. * * KDE4: make this const! */ int itemIndex (int id); /** * Set toolbar to full parent size (default). * * In full size mode the bar * extends over the parent's full width or height. If the mode is disabled * the toolbar tries to take as much space as it needs without wrapping, but * it does not exceed the parent box. You can force a certain width or * height with @ref setMaxWidth() or @ref setMaxHeight(). * * If you want to use right-aligned items or auto-sized items you must use * full size mode. */ void setFullSize(bool flag = true); /** * @return @p true if the full-size mode is enabled. Otherwise * it returns @false. */ bool fullSize() const; /** * @deprecated use setMovingEnabled(bool) instead. * Enable or disable moving of toolbar. */ void enableMoving(bool flag = true); /** * Set position of toolbar. * @see BarPosition() */ void setBarPos (BarPosition bpos); /** * Returns position of toolbar. */ - BarPosition barPos() const; + const BarPosition barPos(); /** * @deprecated * Show, hide, or toggle toolbar. * * This method is provided for compatibility only, * please use show() and/or hide() instead. * @see BarStatus */ bool enable(BarStatus stat); /** * @deprecated * Use setMaximumHeight() instead. */ void setMaxHeight (int h); // Set max height for vertical toolbars /** * @deprecated * Use maximumHeight() instead. * Returns the value that was set with @ref setMaxHeight(). */ int maxHeight(); /** * @deprecated * Use setMaximumWidth() instead. * Set maximal width of horizontal (top or bottom) toolbar. */ void setMaxWidth (int dw); /** * @deprecated * Use maximumWidth() instead. * Returns the value that was set with @ref setMaxWidth(). */ int maxWidth(); /** * Set title for toolbar when it floats. * * Titles are however not (yet) * visible. You can't change toolbar's title while it's floating. */ void setTitle (const QString& _title); /** * @deprecated * Use enableMoving() instead. */ void enableFloating (bool arrrrrrgh); /** * Set the kind of painting for buttons. * * Choose from: * @li IconOnly (only icons), * @li IconTextRight (icon and text, text is left from icons), * @li TextOnly (only text), * @li IconTextBottom (icons and text, text is under icons). * @see IconText * */ void setIconText(IconText it); // Note: don't merge with the next one, it breaks Qt properties /** * Similar to @ref setIconText(IconText it) but allows you to * disable or enable updating. If @p update is false, then the * buttons will not be updated. This is useful only if you know * that you will be forcing an update later. */ void setIconText(IconText it, bool update); /** * @return The current text style for buttons. */ IconText iconText() const; /** * Set the icon size to load. Usually you should not call * this, the icon size is taken care of by KIconLoader * and globally configured. * By default, the toolbar will load icons of size 32 for main * toolbars and 22 for other toolbars * @see KIconLoader. * * @param size The size to use */ void setIconSize(int size); // Note: don't merge with the next one, it breaks Qt properties /** * Same as @ref setIconText(int size) but allows you * to disable the toolbar update. * * @param size The size to use * @param update If true, then the toolbar will be updated after * this */ void setIconSize(int size, bool update); /** * @return The current icon size for buttons. */ int iconSize() const; /** * This allows you to enable or disable the context menu. * * @param enable If false, then the context menu will be disabled */ void setEnableContextMenu(bool enable = true); /** * Returns whether or not the context menu is disabled * * @return The context menu state */ bool contextMenuEnabled() const; /** * This will inform a toolbar button to ignore certain style * changes. Specifically, it will ignore IconText (always IconOnly) * and will not allow image effects to apply. * * @param id The button to exclude from styles * @param no_style If true, then it is excluded (default: true). */ void setItemNoStyle(int id, bool no_style = true); void setFlat (bool flag); /** * @return the number of items in the toolbar */ int count() const; /** * Instruct the toolbar to save it's current state to either the app * config file or to the XML-GUI resource file (whichever has * precedence). */ void saveState(); /** * Save the toolbar settings to group @p configGroup in @p config. */ void saveSettings(KConfig *config, const QString &configGroup); /** * Read the toolbar settings from group @p configGroup in @p config * and apply them. */ void applySettings(KConfig *config, const QString &configGroup); /** * Tell the toolbar what XML-GUI resource file it should use to save * it's state. The state of the toolbar (position, size, etc) is * saved in KConfig files if the application does not use XML-GUI.. * but if the app does, then it's saved the XML file. This function * allows this to happen. * * @param xmlfile The XML-GUI resource file to write to * @param xml The DOM document for the XML-GUI building */ // void setXML(const QString& xmlfile, const QDomDocument& xml); /* @internal */ void setXMLGUIClient( KXMLGUIClient *client ); /** * Assign a (translated) text to this toolbar. This is used * for the tooltip on the handle, and when listing the toolbars. */ void setText( const QString & txt ); /** * @return the toolbar's text. */ QString text() const; void setStretchableWidget( QWidget *w ); QSizePolicy sizePolicy() const; bool highlight() const; QSize sizeHint() const; QSize minimumSizeHint() const; QSize minimumSize() const; void hide(); void show(); void updateRects( bool = FALSE ) {} //US void loadState( const QDomElement &e ); //US void saveState( QDomElement &e ); /** * @internal */ void positionYourself( bool force = false); signals: /** * Emitted when button @p id is clicked. */ void clicked(int id); /** * Emitted when button @p id is double-clicked. * * Note: you will always * recive two @ref clicked() , @ref pressed() and @ref released() signals. * There is no way to avoid it - at least no easy way. * If you need to resolve this all you can do is set up timers * which wait for @ref QApplication::doubleClickInterval() to expire. * If in that time you don't get this signal, you may belive that * button was only clicked and not double-clicked. * And please note that butons with popup menus do not emit this signal, * but those with delayed popup do. */ void doubleClicked (int id); /** * Emitted when button @p id is pressed. */ void pressed(int); /** * Emits when button @p id is released. */ void released(int); /** * Emitted when a toggle button changes state. * * Emitted also if you change state * with @ref setButton() or @ref toggleButton() * If you make a button normal again, with * setToggle(false), this signal won't * be emitted. */ void toggled(int); /** * This signal is emitted when item id gets highlighted/unhighlighted * (i.e when mouse enters/exits). * * Note that this signal is emitted from * all buttons (normal, disabled and toggle) even when there is no visible * change in buttons (i.e., buttons do not raise when mouse enters). * The parameter @p isHighlighted is @p true when mouse enters and @p false when * mouse exits. */ void highlighted(int id, bool isHighlighted); /** * This signal is emitted when item id gets highlighted/unhighlighted * (i.e when mouse enters/exits). * * Note that this signal is emitted from * all buttons (normal, disabled and toggle) even when there is no visible * change in buttons (i.e., buttons do not raise when mouse enters). */ void highlighted(int id ); /** * Emitted when toolbar changes position, or when * an item is removed from toolbar. * * If you subclass @ref KMainWindow and reimplement * @ref KMainWindow::resizeEvent() be sure to connect to * this signal. Note: You can connect this signal to a slot that * doesn't take parameter. */ void moved( BarPosition ); /** * @internal * This signal is emitted when toolbar detects changing of * following parameters: * highlighting, button-size, button-mode. This signal is * internal, aimed to buttons. */ void modechange (); /** * This signal is emitted when the toolbar is getting deleted, * and before ~KToolbar finishes (so it's still time to remove * widgets from the toolbar). * Used by KWidgetAction. * @since 3.2 */ void toolbarDestroyed(); public: /** * @return global setting for "Highlight buttons under mouse" */ void repaintMe(); static bool highlightSetting(); /** * @return global setting for "Toolbars transparent when moving" */ static bool transparentSetting(); /** * @return global setting for "Icon Text" */ static IconText iconTextSetting(); public slots: virtual void setIconText( const QString &txt ) { QToolBar::setIconText( txt ); } void slotRepaint(); protected: void mousePressEvent( QMouseEvent * ); void childEvent( QChildEvent *e ); void showEvent( QShowEvent *e ); void resizeEvent( QResizeEvent *e ); bool event( QEvent *e ); void applyAppearanceSettings(KConfig *config, const QString &_configGroup, bool forceGlobal = false); QString settingsGroup(); private slots: void rebuildLayout(); void slotReadConfig (); void slotAppearanceChanged(); void slotIconChanged(int); void toolBarPosChanged( QToolBar *tb ); void slotContextAboutToShow(); void widgetDestroyed(); private: void init( bool readConfig = true, bool honorStyle = false ); void doConnections( KToolBarButton *button ); void insertWidgetInternal( QWidget *w, int &index, int id ); void removeWidgetInternal( QWidget *w ); void getAttributes( QString &position, QString &icontext, int &index ); //US KPopupMenu *contextMenu(); QPopupMenu *contextMenu(); QMap<QWidget*, int > widget2id; typedef QMap<int, QWidget* > Id2WidgetMap; Id2WidgetMap id2widget; //US KPopupMenu *context; QPopupMenu *context; QPtrList<QWidget> widgets; QTimer *layoutTimer; QGuardedPtr<QWidget> stretchableWidget, rightAligned; protected: virtual void virtual_hook( int id, void* data ); private: KToolBarPrivate *d; bool inshutdownprocess; }; #endif |