diff options
Diffstat (limited to 'kmymoney2/widgets/kmymoneycalendar.cpp')
-rw-r--r-- | kmymoney2/widgets/kmymoneycalendar.cpp | 661 |
1 files changed, 661 insertions, 0 deletions
diff --git a/kmymoney2/widgets/kmymoneycalendar.cpp b/kmymoney2/widgets/kmymoneycalendar.cpp new file mode 100644 index 0000000..8f5291f --- /dev/null +++ b/kmymoney2/widgets/kmymoneycalendar.cpp @@ -0,0 +1,661 @@ +/*************************************************************************** + kmymoneycalendar.cpp - description + ------------------- + begin : Wed Jul 2 2003 + copyright : (C) 2000-2003 by Michael Edwardes + email : [email protected] + Javier Campos Morales <[email protected]> + Felix Rodriguez <[email protected]> + John C <[email protected]> + Thomas Baumgart <[email protected]> + Kevin Tambascio <[email protected]> + ***************************************************************************/ + +/*************************************************************************** + * Contains code from KDatePicker in kdelibs-3.1.2. + * Original license message: + * + This file is part of the KDE libraries + Copyright (C) 1997 Tim D. Gilman ([email protected]) + (C) 1998-2001 Mirko Boehm ([email protected]) + 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. + ****************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +// ---------------------------------------------------------------------------- +// QT Includes +#include <qpainter.h> +#include <qdrawutil.h> +#include <qframe.h> +#include <qpainter.h> +#include <qdialog.h> +#include <qstyle.h> +#include <qtoolbutton.h> +#include <qtooltip.h> +#include <qfont.h> +#include <qvalidator.h> +#include <qpushbutton.h> + +// ---------------------------------------------------------------------------- +// KDE Includes +#include "kdecompat.h" +#include <kglobal.h> +#include <kapplication.h> +#include <klocale.h> +#include <kiconloader.h> +#include <klineedit.h> +#include <kdebug.h> +#include <knotifyclient.h> +#include <kdatetbl.h> // for maximum re-use +#include <kpopupmenu.h> + +#if KDE_IS_VERSION(3,2,0) +#include <kcalendarsystem.h> +#endif + +// ---------------------------------------------------------------------------- +// Project Includes +#include "kmymoneycalendar.h" +#include "kmymoneydatetbl.h" + +class kMyMoneyCalendar::kMyMoneyCalendarPrivate +{ +public: + kMyMoneyCalendarPrivate() + : closeButton(0L), selectWeek(0L), userButton1(0), userButton2(0) {} + + QToolButton *closeButton; + QToolButton *selectWeek; + QPushButton *userButton1; + QPushButton *userButton2; +}; + +kMyMoneyCalendar::kMyMoneyCalendar(QWidget *parent, const char *name ) : + QFrame(parent,name), + table(0), + d(new kMyMoneyCalendarPrivate) +{ +} + +kMyMoneyCalendar::~kMyMoneyCalendar() +{ + delete d; +} + +void kMyMoneyCalendar::init( const QDate &dt ) +{ + styleControl = new QPushButton(i18n("Select Style"), this); + yearForward = new QToolButton(this); + yearBackward = new QToolButton(this); + monthForward = new QToolButton(this); + monthBackward = new QToolButton(this); + selectMonth = new QToolButton(this); + selectYear = new QToolButton(this); + line = new KLineEdit(this); + val = new KDateValidator(this); + fontsize = 10; + + d->selectWeek = new QToolButton( this ); + +// KIconLoader *kiconloader = KGlobal::iconLoader(); + KPopupMenu* kpopupmenuNew = new KPopupMenu(this); + kpopupmenuNew->insertItem(i18n("Week"), this, SLOT(slotSetStyleWeekly())); + kpopupmenuNew->insertItem(i18n("Month"), this, SLOT(slotSetStyleMonthly())); +/* kpopupmenuNew->insertItem(i18n("3 Months"), this, SLOT(slotSetStyleQuarterly())); */ + styleControl->setPopup(kpopupmenuNew); + + QToolTip::add(styleControl, i18n("Choose Style")); + QToolTip::add(yearForward, i18n("Next year")); + QToolTip::add(yearBackward, i18n("Previous year")); + QToolTip::add(monthForward, i18n("Next month")); + QToolTip::add(monthBackward, i18n("Previous month")); + QToolTip::add(d->selectWeek, i18n("Select a week")); + QToolTip::add(selectMonth, i18n("Select a month")); + QToolTip::add(selectYear, i18n("Select a year")); + + // ----- + setFontSize(10); + line->setValidator(val); + line->installEventFilter( this ); + yearForward->setPixmap(BarIcon(QString::fromLatin1("2rightarrow"))); + yearBackward->setPixmap(BarIcon(QString::fromLatin1("2leftarrow"))); + monthForward->setPixmap(BarIcon(QString::fromLatin1("1rightarrow"))); + monthBackward->setPixmap(BarIcon(QString::fromLatin1("1leftarrow"))); + setDate(dt); // set button texts + connect(table, SIGNAL(dateChanged(QDate)), SLOT(dateChangedSlot(QDate))); + connect(table, SIGNAL(tableClicked()), SLOT(tableClickedSlot())); + connect(monthForward, SIGNAL(clicked()), SLOT(monthForwardClicked())); + connect(monthBackward, SIGNAL(clicked()), SLOT(monthBackwardClicked())); + connect(yearForward, SIGNAL(clicked()), SLOT(yearForwardClicked())); + connect(yearBackward, SIGNAL(clicked()), SLOT(yearBackwardClicked())); + connect(d->selectWeek, SIGNAL(clicked()), SLOT(selectWeekClicked())); + connect(selectMonth, SIGNAL(clicked()), SLOT(selectMonthClicked())); + connect(selectYear, SIGNAL(clicked()), SLOT(selectYearClicked())); + connect(line, SIGNAL(returnPressed()), SLOT(lineEnterPressed())); + if (table) + table->setFocus(); +} + +bool +kMyMoneyCalendar::eventFilter(QObject *o, QEvent *e ) +{ + if ( e->type() == QEvent::KeyPress ) { + QKeyEvent *k = (QKeyEvent *)e; + + if ( (k->key() == Qt::Key_Prior) || + (k->key() == Qt::Key_Next) || + (k->key() == Qt::Key_Up) || + (k->key() == Qt::Key_Down) ) + { + QApplication::sendEvent( table, e ); + table->setFocus(); + return TRUE; // eat event + } + } + return QFrame::eventFilter( o, e ); +} + +void +kMyMoneyCalendar::resizeEvent(QResizeEvent*) +{ + QWidget *buttons[] = { + styleControl, + d->userButton1, + d->userButton2, + yearBackward, + monthBackward, + selectMonth, + selectYear, + monthForward, + yearForward, + d->closeButton + }; + const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]); + QSize sizes[NoOfButtons]; + int buttonHeight=0; + int count; + int w; + int x=0; + // ----- calculate button row height: + for(count=0; count<NoOfButtons; ++count) { + if ( buttons[count] ) { // closeButton may be 0L + sizes[count]=buttons[count]->sizeHint(); + buttonHeight=QMAX(buttonHeight, sizes[count].height()); + } + else + sizes[count] = QSize(0,0); // closeButton + } + + // ----- calculate size of the month button: + for(count=0; count<NoOfButtons; ++count) { + if(buttons[count]==selectMonth) { + QSize metricBound = style().sizeFromContents(QStyle::CT_ToolButton, selectMonth, maxMonthRect); + sizes[count].setWidth(QMAX(metricBound.width(), maxMonthRect.width()+2*QApplication::style().pixelMetric(QStyle::PM_ButtonMargin))); + } + } + // ----- place the buttons: + // Put the style button and user buttons to the left and the rest to the right + x = 0; + int noUserButtons=2; + buttons[0]->setGeometry(x, 0, sizes[0].width(), buttonHeight); + x += sizes[0].width(); + for (count=1; count<=noUserButtons; ++count) + { + if (buttons[count]) + { + buttons[count]->setGeometry(x, 0, sizes[count].width(), buttonHeight); + x += sizes[count].width(); + } + } + + x = width(); + for(count=(1+noUserButtons); count<NoOfButtons; ++count) + { + w=sizes[count].width(); + x -= w; + } + + for(count=(1+noUserButtons); count<NoOfButtons; ++count) + { + w=sizes[count].width(); + if ( buttons[count] ) + buttons[count]->setGeometry(x, 0, w, buttonHeight); + x+=w; + } + + // ----- place the line edit for direct input: + sizes[0]=line->sizeHint(); + int week_width=d->selectWeek->fontMetrics().width(i18n("Week XX"))+((d->closeButton != 0L) ? 50 : 20); + line->setGeometry(0, height()-sizes[0].height(), width()-week_width, sizes[0].height()); + d->selectWeek->setGeometry(width()-week_width, height()-sizes[0].height(), week_width, sizes[0].height()); + // ----- adjust the table: + table->setGeometry(0, buttonHeight, width(), + height()-buttonHeight-sizes[0].height()); + + table->setFocus(); +} + +void +kMyMoneyCalendar::dateChangedSlot(QDate date) +{ + kdDebug() << "kMyMoneyCalendar::dateChangedSlot: date changed (" << date.year() << "/" << date.month() << "/" << date.day() << ")." << endl; + line->setText(KGlobal::locale()->formatDate(date, true)); + d->selectWeek->setText(i18n("Week %1").arg(weekOfYear(date))); + selectMonth->setText(MONTH_NAME(date.month(), date.year(), false)); + selectYear->setText(date.toString("yyyy")); + emit(dateChanged(date)); +} + +void +kMyMoneyCalendar::tableClickedSlot() +{ + kdDebug() << "kMyMoneyCalendar::tableClickedSlot: table clicked." << endl; + emit(dateSelected(table->getDate())); + emit(tableClicked()); +} + +const QDate& +kMyMoneyCalendar::getDate() const +{ + return table->getDate(); +} + +const QDate & +kMyMoneyCalendar::date() const +{ + return table->getDate(); +} + +bool +kMyMoneyCalendar::setDate(const QDate& date) +{ + if (!table) + return true; // hack + + if(date.isValid()) { + QString temp; + // ----- + table->setDate(date); + d->selectWeek->setText(i18n("Week %1").arg(weekOfYear(date))); + selectMonth->setText(MONTH_NAME(date.month(), date.year(), false)); + temp.setNum(date.year()); + selectYear->setText(temp); + line->setText(KGlobal::locale()->formatDate(date, true)); + return true; + } else { + kdDebug() << "kMyMoneyCalendar::setDate: refusing to set invalid date." << endl; + return false; + } +} + +void +kMyMoneyCalendar::monthForwardClicked() +{ + setDate( table->getDate().addMonths(1) ); +} + +void +kMyMoneyCalendar::monthBackwardClicked() +{ + setDate( table->getDate().addMonths(-1) ); +} + +void +kMyMoneyCalendar::yearForwardClicked() +{ + setDate( table->getDate().addYears(1) ); +} + +void +kMyMoneyCalendar::yearBackwardClicked() +{ + setDate( table->getDate().addYears(-1) ); +} + +void +kMyMoneyCalendar::selectWeekClicked() +{ +#if KDE_VERSION >= 310 && KDE_VERSION <= 314 + int week; + KPopupFrame* popup = new KPopupFrame(this); + KDateInternalWeekSelector* picker = new KDateInternalWeekSelector(/*fontsize, */popup); + // ----- + picker->resize(picker->sizeHint()); + popup->setMainWidget(picker); + connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int))); + picker->setFocus(); + if(popup->exec(d->selectWeek->mapToGlobal(QPoint(0, d->selectWeek->height())))) + { + QDate date; + int year; + // ----- + week=picker->getWeek(); + date=table->getDate(); + year=date.year(); + // ----- find the first selectable day in this week (hacky solution :) + date.setYMD(year, 1, 1); + while (weekOfYear(date)>50) + date=date.addDays(1); + while (weekOfYear(date)<week && (week!=53 || (week==53 && + (weekOfYear(date)!=52 || weekOfYear(date.addDays(1))!=1)))) + date=date.addDays(1); + if (week==53 && weekOfYear(date)==52) + while (weekOfYear(date.addDays(-1))==52) + date=date.addDays(-1); + // ----- set this date + setDate(date); + } else { + KNotifyClient::beep(); + } + delete popup; +#endif +} + +void +kMyMoneyCalendar::selectMonthClicked() +{ +#if KDE_VERSION >= 310 && KDE_VERSION <= 314 + int month; + KPopupFrame* popup = new KPopupFrame(this); + KDateInternalMonthPicker* picker = new KDateInternalMonthPicker(/*fontsize, */popup); + // ----- + picker->resize(picker->sizeHint()); + popup->setMainWidget(picker); + picker->setFocus(); + connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int))); + if(popup->exec(selectMonth->mapToGlobal(QPoint(0, selectMonth->height())))) + { + QDate date; + int day; + // ----- + month=picker->getResult(); + date=table->getDate(); + day=date.day(); + // ----- construct a valid date in this month: + date.setYMD(date.year(), month, 1); + date.setYMD(date.year(), month, QMIN(day, date.daysInMonth())); + // ----- set this month + setDate(date); + } else { + KNotifyClient::beep(); + } + delete popup; +#endif +} + +void +kMyMoneyCalendar::selectYearClicked() +{ +#if KDE_VERSION >= 310 && KDE_VERSION <= 314 + int year; + KPopupFrame* popup = new KPopupFrame(this); + KDateInternalYearSelector* picker = new KDateInternalYearSelector(fontsize, popup); + // ----- + picker->resize(picker->sizeHint()); + popup->setMainWidget(picker); + connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int))); + picker->setFocus(); + if(popup->exec(selectYear->mapToGlobal(QPoint(0, selectMonth->height())))) + { + QDate date; + int day; + // ----- + year=picker->getYear(); + date=table->getDate(); + day=date.day(); + // ----- construct a valid date in this month: + date.setYMD(year, date.month(), 1); + date.setYMD(year, date.month(), QMIN(day, date.daysInMonth())); + // ----- set this month + setDate(date); + } else { + KNotifyClient::beep(); + } + delete popup; +#endif +} + +void +kMyMoneyCalendar::setEnabled(bool enable) +{ + QWidget *widgets[]= { + styleControl, yearForward, yearBackward, monthForward, monthBackward, + selectMonth, selectYear, + line, table, d->selectWeek, d->userButton1, d->userButton2 }; + const int Size=sizeof(widgets)/sizeof(widgets[0]); + int count; + // ----- + for(count=0; count<Size; ++count) + { + if (widgets[count]) + widgets[count]->setEnabled(enable); + } +} + +void +kMyMoneyCalendar::lineEnterPressed() +{ + QDate temp; + // ----- + if(val->date(line->text(), temp)==QValidator::Acceptable) + { + kdDebug() << "kMyMoneyCalendar::lineEnterPressed: valid date entered." << endl; + emit(dateEntered(temp)); + setDate(temp); + } else { + KNotifyClient::beep(); + kdDebug() << "kMyMoneyCalendar::lineEnterPressed: invalid date entered." << endl; + } +} + +QSize +kMyMoneyCalendar::sizeHint() const +{ + QSize tableSize=table->sizeHint(); + QWidget *buttons[]={ + styleControl, + yearBackward, + monthBackward, + selectMonth, + selectYear, + monthForward, + yearForward, + d->closeButton, + d->userButton1, + d->userButton2 + }; + const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]); + QSize sizes[NoOfButtons]; + int cx=0, cy=0, count; + // ----- store the size hints: + for(count=0; count<NoOfButtons; ++count) + { + if ( buttons[count] ) + sizes[count]=buttons[count]->sizeHint(); + else + sizes[count] = QSize(0,0); + + if(buttons[count]==selectMonth) + { + QSize metricBound = style().sizeFromContents(QStyle::CT_ToolButton, selectMonth, maxMonthRect); + cx+=QMAX(metricBound.width(), maxMonthRect.width()+2*QApplication::style().pixelMetric(QStyle::PM_ButtonMargin)); + } else { + cx+=sizes[count].width(); + } + cy=QMAX(sizes[count].height(), cy); + } + // ----- calculate width hint: + cx=QMAX(cx, tableSize.width()); // line edit ignored + // ----- calculate height hint: + cy+=tableSize.height()+line->sizeHint().height(); + return QSize(cx, cy); +} + +void +kMyMoneyCalendar::setFontSize(int s) +{ + if (table) + { + QWidget *buttons[]= { + // styleControl + // yearBackward, + // monthBackward, + selectMonth, + selectYear, + // monthForward, + // yearForward + }; + const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]); + int count; + QFont font; + QRect r; + // ----- + fontsize=s; + for(count=0; count<NoOfButtons; ++count) + { + font=buttons[count]->font(); + font.setPointSize(s); + buttons[count]->setFont(font); + } + QFontMetrics metrics(selectMonth->fontMetrics()); + for(int i=1; i <= 12; ++i) + { // maxMonthRect is used by sizeHint() + r=metrics.boundingRect(MONTH_NAME(i, 2000, false)); + maxMonthRect.setWidth(QMAX(r.width(), maxMonthRect.width())); + maxMonthRect.setHeight(QMAX(r.height(), maxMonthRect.height())); + } + table->setFontSize(s); + } +} + +void +kMyMoneyCalendar::setCloseButton( bool enable ) +{ + if ( enable == (d->closeButton != 0L) ) + return; + + if ( enable ) { + d->closeButton = new QToolButton( this ); + QToolTip::add(d->closeButton, i18n("Close")); + d->closeButton->setPixmap( SmallIcon("remove") ); + connect( d->closeButton, SIGNAL( clicked() ), + topLevelWidget(), SLOT( close() ) ); + } + else { + delete d->closeButton; + d->closeButton = 0L; + } + + updateGeometry(); +} + +bool kMyMoneyCalendar::hasCloseButton() const +{ + return (d->closeButton != 0L); +} + +int kMyMoneyCalendar::weekOfYear(QDate date) +{ + // Calculate ISO 8601 week number (taken from glibc/Gnumeric) + int year, week, wday, jan1wday, nextjan1wday; + QDate jan1date, nextjan1date; + + year=date.year(); + wday=date.dayOfWeek(); + + jan1date=QDate(year,1,1); + jan1wday=jan1date.dayOfWeek(); + + week = (date.dayOfYear()-1 + jan1wday-1)/7 + ((jan1wday-1) == 0 ? 1 : 0); + + /* Does date belong to last week of previous year? */ + if ((week == 0) && (jan1wday > 4 /*THURSDAY*/)) { + QDate tmpdate=QDate(year-1,12,31); + return weekOfYear(tmpdate); + } + + if ((jan1wday <= 4 /*THURSDAY*/) && (jan1wday > 1 /*MONDAY*/)) + week++; + + if (week == 53) { + nextjan1date=QDate(year+1, 1, 1); + nextjan1wday = nextjan1date.dayOfWeek(); + if (nextjan1wday <= 4 /*THURSDAY*/) + week = 1; + } + + return week; +} + +void kMyMoneyCalendar::virtual_hook( int /*id*/, void* /*data*/ ) +{ /*BASE::virtual_hook( id, data );*/ } + +void kMyMoneyCalendar::slotSetStyleWeekly() +{ + setType(kMyMoneyDateTbl::WEEKLY); +} + +void kMyMoneyCalendar::slotSetStyleMonthly() +{ + setType(kMyMoneyDateTbl::MONTHLY); +} + +void kMyMoneyCalendar::slotSetStyleQuarterly() +{ + setType(kMyMoneyDateTbl::QUARTERLY); +} + +void kMyMoneyCalendar::setUserButton1(bool enable, QPushButton* pb) +{ + if ( enable == (d->userButton1 != 0L) ) + return; + + if ( enable ) { + d->userButton1 = pb; + } + else { + delete d->userButton1; + d->userButton1 = 0L; + } + + updateGeometry(); +} + +void kMyMoneyCalendar::setUserButton2(bool enable, QPushButton* pb) +{ + if ( enable == (d->userButton2 != 0L) ) + return; + + if ( enable ) { + d->userButton2 = pb; + } + else { + delete d->userButton2; + d->userButton2 = 0L; + } + + updateGeometry(); +} + +#include "kmymoneycalendar.moc" |