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/kmymoneydateinput.cpp

349 lines
10 KiB

/***************************************************************************
kmymoneydateinput.cpp
-------------------
copyright : (C) 2000 by Michael Edwardes
email : mte@users.sourceforge.net
ipwizard@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* *
* 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 <tqpoint.h>
#include <tqvalidator.h>
#include <tqtimer.h>
#include <tqstyle.h>
#include <tqlayout.h>
#include <tqapplication.h>
#include <tqdesktopwidget.h>
#include <tqpixmap.h>
#include <tqtimer.h>
#include <tqlabel.h>
// ----------------------------------------------------------------------------
// KDE Includes
#include "kdecompat.h"
#include <kglobal.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kpushbutton.h>
#include <kshortcut.h>
#include <kpassivepopup.h>
// ----------------------------------------------------------------------------
// Project Includes
#include "kmymoneydateinput.h"
namespace {
const int DATE_POPUP_TIMEOUT = 1500;
}
bool KMyMoneyDateEdit::event(TQEvent* e)
{
// make sure that we keep the current date setting of a kMyMoneyDateInput object
// across the TQDateEdit::event(FocusOutEvent)
bool rc;
kMyMoneyDateInput* p = dynamic_cast<kMyMoneyDateInput*>(parentWidget());
if(e->type() == TQEvent::FocusOut && p) {
TQDate d = p->date();
rc = TQDateEdit::event(e);
if(d.isValid())
d = p->date();
p->loadDate(d);
} else {
rc = TQDateEdit::event(e);
}
return rc;
}
kMyMoneyDateInput::kMyMoneyDateInput(TQWidget *parent, const char *name, TQt::AlignmentFlags flags)
: TQHBox(parent,name)
{
m_qtalignment = flags;
m_date = TQDate::currentDate();
dateEdit = new KMyMoneyDateEdit(m_date, this, "dateEdit");
setFocusProxy(dateEdit);
focusWidget()->installEventFilter(this); // To get dateEdit's FocusIn/Out and some KeyPress events
dateEdit->installEventFilter(this); // To get dateEdit's FocusIn/Out and some KeyPress events
m_datePopup = new KPassivePopup(dateEdit, "datePopup");
m_datePopup->setTimeout(DATE_POPUP_TIMEOUT);
m_datePopup->setView(new TQLabel(KGlobal::locale()->formatDate(m_date), m_datePopup, "datePopupLabel"));
m_dateFrame = new TQVBox(this, 0, WType_Popup);
m_dateFrame->setFrameStyle(TQFrame::PopupPanel | TQFrame::Raised);
m_dateFrame->setLineWidth(3);
m_dateFrame->hide();
TQString dateFormat = KGlobal::locale()->dateFormatShort().lower();
TQString order, separator;
for(unsigned i = 0; i < dateFormat.length(); ++i) {
// DD.MM.YYYY is %d.%m.%y
// dD.mM.YYYY is %e.%n.%y
// SHORTWEEKDAY, dD SHORTMONTH YYYY is %a, %e %b %Y
if(dateFormat[i] == 'y' || dateFormat[i] == 'm' || dateFormat[i] == 'n' || dateFormat[i] == 'd' || dateFormat[i] == 'e') {
if(dateFormat[i] == 'n')
dateFormat[i] = 'm';
if(dateFormat[i] == 'e')
dateFormat[i] = 'd';
order += dateFormat[i];
} else if(dateFormat[i] != '%' && separator.isEmpty())
separator = dateFormat[i];
if(order.length() == 3)
break;
}
// see if we find a known format. If it's unknown, then we use YMD (international)
// set m_focusDatePart to the day position (0-2)
if(order == "mdy") {
dateEdit->setOrder(TQDateEdit::MDY);
m_focusDatePart = 1;
} else if(order == "dmy") {
dateEdit->setOrder(TQDateEdit::DMY);
m_focusDatePart = 0;
} else if(order == "ydm") {
dateEdit->setOrder(TQDateEdit::YDM);
m_focusDatePart = 1;
} else {
dateEdit->setOrder(TQDateEdit::YMD);
m_focusDatePart = 2;
separator = '-';
}
dateEdit->setSeparator(separator);
m_datePicker = new KDatePicker(m_dateFrame, m_date);
#if KDE_IS_VERSION(3,1,0)
// Let the date picker have a close button (Added in 3.1)
m_datePicker->setCloseButton(true);
#endif
// the next line is a try to add an icon to the button
m_dateButton = new KPushButton(TQIconSet(TQPixmap(KGlobal::iconLoader()->iconPath("date", -KIcon::SizeSmall))), TQString(""), this);
m_dateButton->setMinimumWidth(30);
connect(m_dateButton,TQT_SIGNAL(clicked()),TQT_SLOT(toggleDatePicker()));
connect(dateEdit, TQT_SIGNAL(valueChanged(const TQDate&)), this, TQT_SLOT(slotDateChosenRef(const TQDate&)));
connect(m_datePicker, TQT_SIGNAL(dateSelected(TQDate)), this, TQT_SLOT(slotDateChosen(TQDate)));
connect(m_datePicker, TQT_SIGNAL(dateEntered(TQDate)), this, TQT_SLOT(slotDateChosen(TQDate)));
connect(m_datePicker, TQT_SIGNAL(dateSelected(TQDate)), m_dateFrame, TQT_SLOT(hide()));
}
void kMyMoneyDateInput::markAsBadDate(bool bad, const TQColor& color)
{
if(dateEdit->focusProxy()) {
TQT_TQWIDGET(dateEdit->focusProxy())->setPaletteForegroundColor(paletteForegroundColor());
if(bad)
TQT_TQWIDGET(dateEdit->focusProxy())->setPaletteForegroundColor(color);
}
}
void kMyMoneyDateInput::show(void)
{
// don't forget the standard behaviour ;-)
TQHBox::show();
// If the widget is shown, the size must be fixed a little later
// to be appropriate. I saw this in some other places and the only
// way to solve this problem is to postpone the setup of the size
// to the time when the widget is on the screen.
TQTimer::singleShot(50, this, TQT_SLOT(fixSize()));
}
void kMyMoneyDateInput::fixSize(void)
{
// According to a hint in the documentation of KDatePicker::sizeHint()
// 28 pixels should be added in each direction to obtain a better
// display of the month button. I decided, (22,14) is good
// enough and save some space on the screen (ipwizard)
m_dateFrame->setFixedSize(m_datePicker->sizeHint() + TQSize(22, 14));
dateEdit->setMinimumWidth(dateEdit->minimumSizeHint().width() + 6);
}
kMyMoneyDateInput::~kMyMoneyDateInput()
{
delete m_dateFrame;
delete m_datePopup;
}
void kMyMoneyDateInput::toggleDatePicker()
{
int w = m_dateFrame->width();
int h = m_dateFrame->height();
if(m_dateFrame->isVisible())
{
m_dateFrame->hide();
}
else
{
TQPoint tmpPoint = mapToGlobal(m_dateButton->geometry().bottomRight());
// usually, the datepicker widget is shown underneath the dateEdit widget
// if it does not fit on the screen, we show it above this widget
if(tmpPoint.y() + h > TQApplication::desktop()->height()) {
tmpPoint.setY(tmpPoint.y() - h - m_dateButton->height());
}
if((m_qtalignment == TQt::AlignRight && tmpPoint.x()+w <= TQApplication::desktop()->width())
|| (tmpPoint.x()-w < 0) )
{
m_dateFrame->setGeometry(tmpPoint.x()-width(), tmpPoint.y(), w, h);
}
else
{
tmpPoint.setX(tmpPoint.x() - w);
m_dateFrame->setGeometry(tmpPoint.x(), tmpPoint.y(), w, h);
}
if(m_date.isValid())
{
m_datePicker->setDate(m_date);
}
else
{
m_datePicker->setDate(TQDate::currentDate());
}
m_dateFrame->show();
}
}
void kMyMoneyDateInput::resizeEvent(TQResizeEvent* ev)
{
m_dateButton->setMaximumHeight(ev->size().height());
m_dateButton->setMaximumWidth(ev->size().height());
dateEdit->setMaximumHeight(ev->size().height());
// tqDebug("Received resize-event %d,%d", ev->size().width(), ev->size().height());
}
/** Overriding TQWidget::keyPressEvent
*
* increments/decrements the date upon +/- or Up/Down key input
* sets the date to current date when the 'T' key is pressed
*/
void kMyMoneyDateInput::keyPressEvent(TQKeyEvent * k)
{
KShortcut today(i18n("Enter todays date into date input widget", "T"));
switch(k->key()) {
case Key_Equal:
case Key_Plus:
slotDateChosen(m_date.addDays(1));
break;
case Key_Minus:
slotDateChosen(m_date.addDays(-1));
break;
default:
if(today.contains(KKey(k)) || k->key() == Key_T) {
slotDateChosen(TQDate::currentDate());
}
break;
}
}
/**
* This function receives all events that are sent to focusWidget().
* Some KeyPress events are intercepted and passed to keyPressEvent.
* Otherwise they would be consumed by TQDateEdit.
*/
bool kMyMoneyDateInput::eventFilter(TQObject *, TQEvent *e)
{
if (e->type() == TQEvent::FocusIn) {
m_datePopup->show();
// The cast to the base class is needed since setFocusSection
// is protected in TQDateEdit. This causes some logic in
// TQDateEdit::setFocusSection not to be executed but this does
// not hurt here, because the widget just receives focus.
static_cast<TQDateTimeEditBase *>(dateEdit)->setFocusSection(m_focusDatePart);
}
else if (e->type() == TQEvent::FocusOut)
m_datePopup->hide();
else if (e->type() == TQEvent::KeyPress) {
if (TQKeyEvent *k = dynamic_cast<TQKeyEvent*>(e)) {
if (k->key() == Key_Minus) {
keyPressEvent(k);
return true;
}
}
}
return false; // Don't filter the event
}
void kMyMoneyDateInput::slotDateChosenRef(const TQDate& date)
{
if(date.isValid()) {
emit dateChanged(date);
m_date = date;
TQLabel *lbl = static_cast<TQLabel*>(m_datePopup->view());
lbl->setText(KGlobal::locale()->formatDate(date));
lbl->adjustSize();
if(m_datePopup->isVisible() || hasFocus())
m_datePopup->show(); // Repaint
}
}
void kMyMoneyDateInput::slotDateChosen(TQDate date)
{
if(date.isValid()) {
// the next line implies a call to slotDateChosenRef() above
dateEdit->setDate(date);
}
}
TQDate kMyMoneyDateInput::date(void) const
{
return dateEdit->date();
}
void kMyMoneyDateInput::setDate(TQDate date)
{
slotDateChosen(date);
}
void kMyMoneyDateInput::loadDate(const TQDate& date)
{
m_date = m_prevDate = date;
blockSignals(true);
dateEdit->setDate(date);
m_date = date;
blockSignals(false);
}
void kMyMoneyDateInput::resetDate(void)
{
setDate(m_prevDate);
}
TQWidget* kMyMoneyDateInput::focusWidget(void) const
{
TQWidget* w = dateEdit;
while(w->focusProxy())
w = TQT_TQWIDGET(w->focusProxy());
return w;
}
#include "kmymoneydateinput.moc"