kde-workspace/libs/plasmaclock/calendar.cpp

490 lines
14 KiB
C++
Raw Normal View History

2014-11-13 19:30:51 +02:00
/*
* Copyright 2008,2010 Davide Bettio <davide.bettio@kdemail.net>
* Copyright 2009 John Layt <john@layt.net>
*
* This program 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, 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 Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "calendar.h"
//Qt
#include <QtCore/qdatetime.h>
2014-11-13 19:30:51 +02:00
#include <QtCore/QTimer>
#include <QtGui/QApplication>
#include <QtGui/qgraphicssceneevent.h>
2014-11-13 19:30:51 +02:00
#include <QtGui/QGraphicsGridLayout>
#include <QtGui/QGraphicsLinearLayout>
#include <QtGui/QGraphicsProxyWidget>
#include <QtGui/QGraphicsView>
#include <QtGui/QLabel>
#include <QtGui/QMenu>
#include <QtGui/QSpinBox>
#include <QtGui/QToolButton>
#include <QtGui/QDesktopWidget>
//KDECore
#include <KCalendarSystem>
#include <KDebug>
#include <KGlobal>
#include <KIcon>
#include <KLineEdit>
#include <KLocale>
#include <KIntSpinBox>
#include <KConfigDialog>
#include <KConfigGroup>
//Plasma
#include <Plasma/Label>
#include <Plasma/LineEdit>
#include <Plasma/Separator>
#include <Plasma/SpinBox>
#include <Plasma/TextBrowser>
#include <Plasma/ToolButton>
#include <Plasma/DataEngine>
#include "wheelytoolbutton.h"
namespace Plasma
{
static const int s_yearWidgetIndex = 3;
class CalendarPrivate
{
public:
CalendarPrivate(Calendar *calendar)
: q(calendar),
back(0),
spacer0(0),
month(0),
yearSpinBox(0),
year(0),
spacer1(0),
forward(0),
calendarTable(0),
dateText(0),
jumpToday(0),
monthMenu(0),
weekSpinBox(0),
separator(0)
{
}
void init(const QDate &date = QDate());
void refreshWidgets();
void popupMonthsMenu();
void updateSize();
Calendar *q;
ToolButton *back;
Plasma::Label *spacer0;
Plasma::ToolButton *month;
Plasma::SpinBox *yearSpinBox;
Plasma::ToolButton *year;
Plasma::Label *spacer1;
Plasma::ToolButton *forward;
Plasma::CalendarTable *calendarTable;
Plasma::LineEdit *dateText;
ToolButton *jumpToday;
QMenu *monthMenu;
Plasma::SpinBox *weekSpinBox;
Plasma::Separator *separator;
QGraphicsLinearLayout *layout;
};
Calendar::Calendar(const QDate &date, QGraphicsWidget *parent)
: QGraphicsWidget(parent),
d(new CalendarPrivate(this))
{
d->init(date);
}
Calendar::Calendar(QGraphicsWidget *parent)
: QGraphicsWidget(parent),
d(new CalendarPrivate(this))
{
d->init();
}
Calendar::~Calendar()
{
delete d->monthMenu;
delete d;
}
void CalendarPrivate::init(const QDate &initialDate)
{
q->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
layout = new QGraphicsLinearLayout(Qt::Horizontal, q);
QGraphicsLinearLayout *calendarLayout = new QGraphicsLinearLayout(Qt::Vertical, layout);
QGraphicsLinearLayout *hLayout = new QGraphicsLinearLayout(layout);
QGraphicsLinearLayout *layoutTools = new QGraphicsLinearLayout(layout);
calendarTable = new CalendarTable(q);
calendarTable->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QObject::connect(calendarTable, SIGNAL(dateChanged(QDate)), q, SLOT(dateUpdated()));
QObject::connect(calendarTable, SIGNAL(dateHovered(QDate)), q, SIGNAL(dateHovered(QDate)));
back = new Plasma::ToolButton(q);
back->setText("<");
back->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QObject::connect(back, SIGNAL(clicked()), q, SLOT(prevMonth()));
hLayout->addItem(back);
hLayout->addStretch();
month = new WheelyToolButton(q);
month->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
monthMenu = new QMenu();
QObject::connect(month, SIGNAL(clicked()), q, SLOT(popupMonthsMenu()));
QObject::connect(month, SIGNAL(pressed()), q, SLOT(popupMonthsMenu()));
QObject::connect(month, SIGNAL(wheelUp()), q, SLOT(prevMonth()));
QObject::connect(month, SIGNAL(wheelDown()), q, SLOT(nextMonth()));
hLayout->addItem(month);
year = new WheelyToolButton(q);
year->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QObject::connect(year, SIGNAL(wheelUp()), q, SLOT(prevYear()));
QObject::connect(year, SIGNAL(wheelDown()), q, SLOT(nextYear()));
QObject::connect(year, SIGNAL(clicked()), q, SLOT(showYearSpinBox()));
hLayout->addItem(year);
yearSpinBox = new Plasma::SpinBox(q);
yearSpinBox->setRange(calendarTable->calendar()->year(calendarTable->calendar()->earliestValidDate()),
calendarTable->calendar()->year(calendarTable->calendar()->latestValidDate()));
yearSpinBox->hide();
QObject::connect(yearSpinBox->nativeWidget(), SIGNAL(editingFinished()), q, SLOT(hideYearSpinBox()));
hLayout->addStretch();
forward = new Plasma::ToolButton(q);
forward->setText(">");
forward->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QObject::connect(forward, SIGNAL(clicked()), q, SLOT(nextMonth()));
hLayout->addItem(forward);
jumpToday = new Plasma::ToolButton(q);
jumpToday->nativeWidget()->setIcon(KIcon("go-jump-today"));
jumpToday->nativeWidget()->setToolTip(i18n("Select today"));
jumpToday->nativeWidget()->setMinimumWidth(25);
QObject::connect(jumpToday, SIGNAL(clicked()), q, SLOT(goToToday()));
layoutTools->addItem(jumpToday);
layoutTools->addStretch();
dateText = new Plasma::LineEdit(q);
QObject::connect(dateText->nativeWidget(), SIGNAL(returnPressed()), q, SLOT(manualDateChange()));
layoutTools->addItem(dateText);
layoutTools->addStretch();
weekSpinBox = new Plasma::SpinBox(q);
weekSpinBox->setMinimum(1);
QObject::connect(weekSpinBox, SIGNAL(valueChanged(int)), q, SLOT(goToWeek(int)));
layoutTools->addItem(weekSpinBox);
calendarLayout->addItem(hLayout);
calendarLayout->addItem(calendarTable);
calendarLayout->addItem(layoutTools);
layout->addItem(calendarLayout);
q->setDate(initialDate);
updateSize();
}
void Calendar::focusInEvent(QFocusEvent* event)
{
Q_UNUSED(event);
grabKeyboard();
}
void Calendar::focusOutEvent(QFocusEvent* event)
{
Q_UNUSED(event);
ungrabKeyboard();
}
void Calendar::keyPressEvent(QKeyEvent* event)
{
switch(event->key()) {
case Qt::Key_Right :
setDate(date().addDays(1));
break;
case Qt::Key_Left :
setDate(date().addDays(-1));
break;
case Qt::Key_Up :
setDate(date().addDays(-7));
break;
case Qt::Key_Down :
setDate(date().addDays(7));
break;
case Qt::Key_PageUp:
nextMonth();
break;
case Qt::Key_PageDown:
prevMonth();
break;
case Qt::Key_Home:
goToToday();
break;
default:
break;
}
}
CalendarTable *Calendar::calendarTable() const
{
return d->calendarTable;
}
void Calendar::setCalendar(int newCalendarType)
{
calendarTable()->setCalendar(newCalendarType);
d->refreshWidgets();
}
void Calendar::setCalendar(const KCalendarSystem *newCalendar)
{
calendarTable()->setCalendar(newCalendar);
d->refreshWidgets();
}
const KCalendarSystem *Calendar::calendar() const
{
return calendarTable()->calendar();
}
void Calendar::setDate(const QDate &toDate)
{
d->calendarTable->setDate(toDate);
//If set date failed force refresh of nav widgets to reset any user entry
//If set date successful refresh will be triggered through signal/slot
if (d->calendarTable->date() != toDate) {
d->refreshWidgets();
}
}
const QDate& Calendar::date() const
{
return calendarTable()->date();
}
void Calendar::setAutomaticUpdateEnabled(bool automatic)
{
calendarTable()->setAutomaticUpdateEnabled(automatic);
}
bool Calendar::isAutomaticUpdateEnabled() const
{
return calendarTable()->isAutomaticUpdateEnabled();
}
void Calendar::setCurrentDate(const QDate &date)
{
calendarTable()->setCurrentDate(date);
}
const QDate& Calendar::currentDate() const
{
return calendarTable()->currentDate();
}
void Calendar::writeConfiguration(KConfigGroup cg)
{
calendarTable()->writeConfiguration(cg);
}
void Calendar::createConfigurationInterface(KConfigDialog *parent)
{
calendarTable()->createConfigurationInterface(parent);
}
void Calendar::configAccepted(KConfigGroup cg)
{
calendarTable()->configAccepted(cg);
applyConfiguration(cg);
}
void CalendarPrivate::updateSize()
{
QSize minSize = QSize(200, 200);
QSize prefSize = calendarTable ? calendarTable->size().toSize() : QSize(250, 250);
q->setMinimumSize(minSize);
q->setPreferredSize(prefSize);
}
void Calendar::applyConfiguration(KConfigGroup cg)
{
calendarTable()->applyConfiguration(cg);
d->updateSize();
}
void Calendar::manualDateChange()
{
setDate(calendar()->readDate(((QLineEdit*)sender())->text()));
}
void Calendar::goToToday()
{
setDate(QDate::currentDate());
}
void Calendar::dateUpdated()
{
// Ignore the date passed in, only ever show the date to match the CalendarTable
d->refreshWidgets();
emit dateChanged(date());
}
// Update the nav widgets to show the current date in the CalendarTable
void CalendarPrivate::refreshWidgets()
{
const KCalendarSystem *calendar = calendarTable->calendar();
const QDate date = calendarTable->date();
month->setText(calendar->monthName(calendar->month(date), calendar->year(date)));
month->setMinimumSize(static_cast<QToolButton*>(month->widget())->sizeHint());
year->setText(calendar->formatDate(date, KLocale::Year, KLocale::LongNumber));
dateText->setText(calendar->formatDate(date, KLocale::ShortDate));
// Block the signals to prevent changing the date again
yearSpinBox->blockSignals(true);
yearSpinBox->setRange(calendar->year(calendar->earliestValidDate()),
calendar->year(calendar->latestValidDate()));
yearSpinBox->setValue(calendar->year(date));
yearSpinBox->blockSignals(false);
// Block the signals to prevent changing the date again
weekSpinBox->blockSignals(true);
weekSpinBox->setMaximum(calendar->weeksInYear(date));
weekSpinBox->setValue(calendar->week(date, KLocale::IsoWeekNumber));
weekSpinBox->blockSignals(false);
}
void Calendar::prevMonth()
{
setDate(calendar()->addMonths(date(), -1));
}
void Calendar::nextMonth()
{
setDate(calendar()->addMonths(date(), 1));
}
void Calendar::prevYear()
{
setDate(calendar()->addYears(date(), -1));
}
void Calendar::nextYear()
{
setDate(calendar()->addYears(date(), 1));
}
void CalendarPrivate::popupMonthsMenu()
{
monthMenu->clear();
const KCalendarSystem *calendar = calendarTable->calendar();
const QDate date = calendarTable->date();
const int year = calendar->year(date);
const int monthsInYear = calendar->monthsInYear(date);
for (int i = 1; i <= monthsInYear; i++){
QAction *tmpAction = new QAction(calendar->monthName(i, year), monthMenu);
tmpAction->setProperty("month", i);
QObject::connect(tmpAction, SIGNAL(triggered()), q, SLOT(monthTriggered()));
monthMenu->addAction(tmpAction);
}
QGraphicsView *view = Plasma::viewFor(month);
if (view) {
monthMenu->adjustSize();
const int x = month->sceneBoundingRect().center().x() - monthMenu->width() / 2;
QPoint pos(x, month->sceneBoundingRect().bottom());
pos = view->mapToGlobal(view->mapFromScene(pos));
QRect r = qApp->desktop()->screenGeometry(view->geometry().center());
if (pos.y() + monthMenu->height() > r.bottom()) {
pos = QPoint(x, month->sceneBoundingRect().top() - monthMenu->height());
pos = view->mapToGlobal(view->mapFromScene(pos));
}
monthMenu->popup(pos);
} else {
monthMenu->popup(QCursor::pos());
}
month->nativeWidget()->setDown(false);
}
void Calendar::monthTriggered()
{
QAction *action = qobject_cast<QAction*> (sender());
2014-11-13 19:30:51 +02:00
if (action && action->property("month").type() == QVariant::Int) {
int newMonth = action->property("month").toInt();
int currMonth = calendar()->month(date());
setDate(calendar()->addMonths(date(), newMonth - currMonth));
}
}
void Calendar::goToWeek(int newWeek)
{
int currWeek = calendar()->week(date(), KLocale::IsoWeekNumber);
int daysInWeek = calendar()->daysInWeek(date());
setDate(calendar()->addDays(date(), (newWeek - currWeek) * daysInWeek));
}
void Calendar::showYearSpinBox()
{
QGraphicsLinearLayout *hLayout = (QGraphicsLinearLayout*)d->year->parentLayoutItem();
if (!hLayout) {
// already hidden!
return;
}
d->year->hide();
hLayout->removeItem(d->year);
d->yearSpinBox->setValue(calendar()->year(date()));
d->yearSpinBox->setMinimumWidth(d->yearSpinBox->preferredSize().width());
hLayout->insertItem(s_yearWidgetIndex, d->yearSpinBox);
hLayout->activate();
d->yearSpinBox->show();
d->yearSpinBox->nativeWidget()->setFocus(Qt::MouseFocusReason);
}
void Calendar::hideYearSpinBox()
{
QGraphicsLinearLayout *hLayout = (QGraphicsLinearLayout*)d->yearSpinBox->parentLayoutItem();
if (!hLayout) {
// already hidden!
return;
}
hLayout->removeItem(d->yearSpinBox);
hLayout->insertItem(s_yearWidgetIndex, d->year);
d->yearSpinBox->hide();
int newYear = d->yearSpinBox->value();
int currYear = calendar()->year(date());
setDate(calendar()->addYears(date(), newYear - currYear));
d->year->show();
}
}
2015-02-27 09:28:46 +00:00
#include "moc_calendar.cpp"