You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kmymoney/kmymoney2/widgets/kmymoneycalendar.cpp

662 lines
19 KiB

/***************************************************************************
kmymoneycalendar.cpp - description
-------------------
begin : Wed Jul 2 2003
copyright : (C) 2000-2003 by Michael Edwardes
email : mte@users.sourceforge.net
Javier Campos Morales <javi_c@users.sourceforge.net>
Felix Rodriguez <frodriguez@users.sourceforge.net>
John C <thetacoturtle@users.sourceforge.net>
Thomas Baumgart <ipwizard@users.sourceforge.net>
Kevin Tambascio <ktambascio@users.sourceforge.net>
***************************************************************************/
/***************************************************************************
* 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 (tdgilman@best.org)
(C) 1998-2001 Mirko Boehm (mirko@kde.org)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
****************************************************************************/
/***************************************************************************
* *
* 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 <tqpainter.h>
#include <tqdrawutil.h>
#include <tqframe.h>
#include <tqpainter.h>
#include <tqdialog.h>
#include <tqstyle.h>
#include <tqtoolbutton.h>
#include <tqtooltip.h>
#include <tqfont.h>
#include <tqvalidator.h>
#include <tqpushbutton.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) {}
TQToolButton *closeButton;
TQToolButton *selectWeek;
TQPushButton *userButton1;
TQPushButton *userButton2;
};
kMyMoneyCalendar::kMyMoneyCalendar(TQWidget *parent, const char *name ) :
TQFrame(parent,name),
table(0),
d(new kMyMoneyCalendarPrivate)
{
}
kMyMoneyCalendar::~kMyMoneyCalendar()
{
delete d;
}
void kMyMoneyCalendar::init( const TQDate &dt )
{
styleControl = new TQPushButton(i18n("Select Style"), this);
yearForward = new TQToolButton(this);
yearBackward = new TQToolButton(this);
monthForward = new TQToolButton(this);
monthBackward = new TQToolButton(this);
selectMonth = new TQToolButton(this);
selectYear = new TQToolButton(this);
line = new KLineEdit(this);
val = new KDateValidator(this);
fontsize = 10;
d->selectWeek = new TQToolButton( this );
// KIconLoader *kiconloader = KGlobal::iconLoader();
KPopupMenu* kpopupmenuNew = new KPopupMenu(this);
kpopupmenuNew->insertItem(i18n("Week"), this, TQT_SLOT(slotSetStyleWeekly()));
kpopupmenuNew->insertItem(i18n("Month"), this, TQT_SLOT(slotSetStyleMonthly()));
/* kpopupmenuNew->insertItem(i18n("3 Months"), this, TQT_SLOT(slotSetStyleQuarterly())); */
styleControl->setPopup(kpopupmenuNew);
TQToolTip::add(styleControl, i18n("Choose Style"));
TQToolTip::add(yearForward, i18n("Next year"));
TQToolTip::add(yearBackward, i18n("Previous year"));
TQToolTip::add(monthForward, i18n("Next month"));
TQToolTip::add(monthBackward, i18n("Previous month"));
TQToolTip::add(d->selectWeek, i18n("Select a week"));
TQToolTip::add(selectMonth, i18n("Select a month"));
TQToolTip::add(selectYear, i18n("Select a year"));
// -----
setFontSize(10);
line->setValidator(val);
line->installEventFilter( this );
yearForward->setPixmap(BarIcon(TQString::fromLatin1("2rightarrow")));
yearBackward->setPixmap(BarIcon(TQString::fromLatin1("2leftarrow")));
monthForward->setPixmap(BarIcon(TQString::fromLatin1("1rightarrow")));
monthBackward->setPixmap(BarIcon(TQString::fromLatin1("1leftarrow")));
setDate(dt); // set button texts
connect(table, TQT_SIGNAL(dateChanged(TQDate)), TQT_SLOT(dateChangedSlot(TQDate)));
connect(table, TQT_SIGNAL(tableClicked()), TQT_SLOT(tableClickedSlot()));
connect(monthForward, TQT_SIGNAL(clicked()), TQT_SLOT(monthForwardClicked()));
connect(monthBackward, TQT_SIGNAL(clicked()), TQT_SLOT(monthBackwardClicked()));
connect(yearForward, TQT_SIGNAL(clicked()), TQT_SLOT(yearForwardClicked()));
connect(yearBackward, TQT_SIGNAL(clicked()), TQT_SLOT(yearBackwardClicked()));
connect(d->selectWeek, TQT_SIGNAL(clicked()), TQT_SLOT(selectWeekClicked()));
connect(selectMonth, TQT_SIGNAL(clicked()), TQT_SLOT(selectMonthClicked()));
connect(selectYear, TQT_SIGNAL(clicked()), TQT_SLOT(selectYearClicked()));
connect(line, TQT_SIGNAL(returnPressed()), TQT_SLOT(lineEnterPressed()));
if (table)
table->setFocus();
}
bool
kMyMoneyCalendar::eventFilter(TQObject *o, TQEvent *e )
{
if ( e->type() == TQEvent::KeyPress ) {
TQKeyEvent *k = (TQKeyEvent *)e;
if ( (k->key() == TQt::Key_Prior) ||
(k->key() == TQt::Key_Next) ||
(k->key() == TQt::Key_Up) ||
(k->key() == TQt::Key_Down) )
{
TQApplication::sendEvent( table, e );
table->setFocus();
return TRUE; // eat event
}
}
return TQFrame::eventFilter( o, e );
}
void
kMyMoneyCalendar::resizeEvent(TQResizeEvent*)
{
TQWidget *buttons[] = {
styleControl,
d->userButton1,
d->userButton2,
yearBackward,
monthBackward,
selectMonth,
selectYear,
monthForward,
yearForward,
d->closeButton
};
const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
TQSize 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=TQMAX(buttonHeight, sizes[count].height());
}
else
sizes[count] = TQSize(0,0); // closeButton
}
// ----- calculate size of the month button:
for(count=0; count<NoOfButtons; ++count) {
if(buttons[count]==selectMonth) {
TQSize metricBound = style().tqsizeFromContents(TQStyle::CT_ToolButton, selectMonth, maxMonthRect);
sizes[count].setWidth(TQMAX(metricBound.width(), maxMonthRect.width()+2*TQApplication::style().pixelMetric(TQStyle::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(TQDate 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 TQDate&
kMyMoneyCalendar::getDate() const
{
return table->getDate();
}
const TQDate &
kMyMoneyCalendar::date() const
{
return table->getDate();
}
bool
kMyMoneyCalendar::setDate(const TQDate& date)
{
if (!table)
return true; // hack
if(date.isValid()) {
TQString 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, TQT_SIGNAL(closeMe(int)), popup, TQT_SLOT(close(int)));
picker->setFocus();
if(popup->exec(d->selectWeek->mapToGlobal(TQPoint(0, d->selectWeek->height()))))
{
TQDate 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, TQT_SIGNAL(closeMe(int)), popup, TQT_SLOT(close(int)));
if(popup->exec(selectMonth->mapToGlobal(TQPoint(0, selectMonth->height()))))
{
TQDate 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, TQMIN(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, TQT_SIGNAL(closeMe(int)), popup, TQT_SLOT(close(int)));
picker->setFocus();
if(popup->exec(selectYear->mapToGlobal(TQPoint(0, selectMonth->height()))))
{
TQDate 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(), TQMIN(day, date.daysInMonth()));
// ----- set this month
setDate(date);
} else {
KNotifyClient::beep();
}
delete popup;
#endif
}
void
kMyMoneyCalendar::setEnabled(bool enable)
{
TQWidget *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()
{
TQDate temp;
// -----
if(val->date(line->text(), temp)==TQValidator::Acceptable)
{
kdDebug() << "kMyMoneyCalendar::lineEnterPressed: valid date entered." << endl;
emit(dateEntered(temp));
setDate(temp);
} else {
KNotifyClient::beep();
kdDebug() << "kMyMoneyCalendar::lineEnterPressed: invalid date entered." << endl;
}
}
TQSize
kMyMoneyCalendar::sizeHint() const
{
TQSize tableSize=table->sizeHint();
TQWidget *buttons[]={
styleControl,
yearBackward,
monthBackward,
selectMonth,
selectYear,
monthForward,
yearForward,
d->closeButton,
d->userButton1,
d->userButton2
};
const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
TQSize 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] = TQSize(0,0);
if(buttons[count]==selectMonth)
{
TQSize metricBound = style().tqsizeFromContents(TQStyle::CT_ToolButton, selectMonth, maxMonthRect);
cx+=TQMAX(metricBound.width(), maxMonthRect.width()+2*TQApplication::style().pixelMetric(TQStyle::PM_ButtonMargin));
} else {
cx+=sizes[count].width();
}
cy=TQMAX(sizes[count].height(), cy);
}
// ----- calculate width hint:
cx=TQMAX(cx, tableSize.width()); // line edit ignored
// ----- calculate height hint:
cy+=tableSize.height()+line->sizeHint().height();
return TQSize(cx, cy);
}
void
kMyMoneyCalendar::setFontSize(int s)
{
if (table)
{
TQWidget *buttons[]= {
// styleControl
// yearBackward,
// monthBackward,
selectMonth,
selectYear,
// monthForward,
// yearForward
};
const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]);
int count;
TQFont font;
TQRect r;
// -----
fontsize=s;
for(count=0; count<NoOfButtons; ++count)
{
font=buttons[count]->font();
font.setPointSize(s);
buttons[count]->setFont(font);
}
TQFontMetrics 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(TQMAX(r.width(), maxMonthRect.width()));
maxMonthRect.setHeight(TQMAX(r.height(), maxMonthRect.height()));
}
table->setFontSize(s);
}
}
void
kMyMoneyCalendar::setCloseButton( bool enable )
{
if ( enable == (d->closeButton != 0L) )
return;
if ( enable ) {
d->closeButton = new TQToolButton( this );
TQToolTip::add(d->closeButton, i18n("Close"));
d->closeButton->setPixmap( SmallIcon("remove") );
connect( d->closeButton, TQT_SIGNAL( clicked() ),
topLevelWidget(), TQT_SLOT( close() ) );
}
else {
delete d->closeButton;
d->closeButton = 0L;
}
updateGeometry();
}
bool kMyMoneyCalendar::hasCloseButton() const
{
return (d->closeButton != 0L);
}
int kMyMoneyCalendar::weekOfYear(TQDate date)
{
// Calculate ISO 8601 week number (taken from glibc/Gnumeric)
int year, week, wday, jan1wday, nextjan1wday;
TQDate jan1date, nextjan1date;
year=date.year();
wday=date.dayOfWeek();
jan1date=TQDate(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*/)) {
TQDate tmpdate=TQDate(year-1,12,31);
return weekOfYear(tmpdate);
}
if ((jan1wday <= 4 /*THURSDAY*/) && (jan1wday > 1 /*MONDAY*/))
week++;
if (week == 53) {
nextjan1date=TQDate(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, TQPushButton* 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, TQPushButton* pb)
{
if ( enable == (d->userButton2 != 0L) )
return;
if ( enable ) {
d->userButton2 = pb;
}
else {
delete d->userButton2;
d->userButton2 = 0L;
}
updateGeometry();
}
#include "kmymoneycalendar.moc"