Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / plasma / applets / digital-clock / clock.cpp
blob63e4764d26777e61de7541f434cda1267253fcd7
1 /***************************************************************************
2 * Copyright (C) 2005,2006,2007 by Siraj Razick <siraj@kdemail.net> *
3 * Copyright (C) 2007 by Riccardo Iaconelli <riccardo@kde.org> *
4 * Copyright (C) 2007 by Sebastian Kuegler <sebas@kde.org> *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
20 ***************************************************************************/
22 #include "clock.h"
24 #include <math.h>
26 #include <QtGui/QPainter>
27 #include <QtGui/QStyleOptionGraphicsItem>
28 #include <QtGui/QSpinBox>
29 #include <QtCore/QTimeLine>
30 #include <QtGui/QGraphicsView>
31 #include <QtGui/QGraphicsSceneMouseEvent>
33 #include <KDebug>
34 #include <KLocale>
35 #include <KIcon>
36 #include <KSharedConfig>
37 #include <KTimeZoneWidget>
38 #include <KDialog>
39 #include <KColorScheme>
40 #include <KGlobalSettings>
41 #include <KDatePicker>
42 #include <plasma/theme.h>
43 #include <plasma/dialog.h>
46 Clock::Clock(QObject *parent, const QVariantList &args)
47 : Plasma::Applet(parent, args),
48 m_clockStyle(PlainClock),
49 m_plainClockFont(KGlobalSettings::generalFont()),
50 m_plainClockColor(),
51 m_plainClockFontBold(false),
52 m_plainClockFontItalic(false),
53 m_showDate(false),
54 m_showYear(false),
55 m_showDay(false),
56 m_showSeconds(false),
57 m_showTimezone(false),
58 m_dialog(0),
59 m_calendar(0),
60 m_layout(0)
62 setHasConfigurationInterface(true);
63 setContentSize(70, 22);
66 void Clock::init()
68 KConfigGroup cg = config();
69 m_timezone = cg.readEntry("timezone", "Local");
71 m_showTimezone = cg.readEntry("showTimezone", (m_timezone != "Local"));
73 kDebug() << "showTimezone:" << m_showTimezone;
75 m_showDate = cg.readEntry("showDate", false);
76 m_showYear = cg.readEntry("showYear", false);
78 m_showDay = cg.readEntry("showDay", true);
80 m_showSeconds = cg.readEntry("showSeconds", false);
81 m_plainClockColor = KColorScheme(QPalette::Active, KColorScheme::View, Plasma::Theme::self()->colors()).foreground().color();
82 m_plainClockFont = cg.readEntry("plainClockFont", m_plainClockFont);
83 m_plainClockColor = cg.readEntry("plainClockColor", m_plainClockColor);
85 m_plainClockFontBold = cg.readEntry("plainClockFontBold", true);
86 m_plainClockFontItalic = cg.readEntry("plainClockFontItalic", false);
87 m_plainClockFont.setBold(m_plainClockFontBold);
88 m_plainClockFont.setItalic(m_plainClockFontItalic);
90 QFontMetricsF metrics(KGlobalSettings::smallestReadableFont());
91 QString timeString = KGlobal::locale()->formatTime(QTime(23, 59), m_showSeconds);
92 setMinimumContentSize(metrics.size(Qt::TextSingleLine, timeString));
94 dataEngine("time")->connectSource(m_timezone, this, updateInterval(), intervalAlignment());
97 Qt::Orientations Clock::expandingDirections() const
99 if (formFactor() == Plasma::Horizontal) {
100 return Qt::Vertical;
101 } else {
102 return Qt::Horizontal;
106 void Clock::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data)
108 Q_UNUSED(source);
109 m_time = data["Time"].toTime();
110 m_date = data["Date"].toDate();
111 m_prettyTimezone = data["Timezone City"].toString();
113 // avoid unnecessary repaints
114 if (m_showSeconds || m_time.minute() != m_lastTimeSeen.minute()) {
115 m_lastTimeSeen = m_time;
117 update();
121 void Clock::mousePressEvent(QGraphicsSceneMouseEvent *event)
123 if (event->buttons() == Qt::LeftButton && contentRect().contains(event->pos())) {
124 showCalendar(event);
125 } else {
126 event->ignore();
130 void Clock::showCalendar(QGraphicsSceneMouseEvent *event)
132 Q_UNUSED(event);
134 if (m_calendar == 0) {
135 m_calendar = new Plasma::Dialog();
136 //m_calendar->setStyleSheet("{ border : 0px }"); // FIXME: crashes
137 m_layout = new QVBoxLayout();
138 m_layout->setSpacing(0);
139 m_layout->setMargin(0);
141 m_calendarUi.setupUi(m_calendar);
142 m_calendar->setLayout(m_layout);
143 m_calendar->setWindowFlags(Qt::Popup);
144 m_calendar->adjustSize();
147 if (m_calendar->isVisible()) {
148 m_calendar->hide();
149 } else {
150 kDebug();
151 m_calendar->move(popupPosition(m_calendar->sizeHint()));
152 m_calendar->show();
156 void Clock::showConfigurationInterface()
158 if (m_dialog == 0) {
159 m_dialog = new KDialog;
161 m_dialog->setCaption(i18n("Configure Clock"));
163 QWidget *widget = new QWidget;
164 ui.setupUi(widget);
165 m_dialog->setMainWidget(widget);
166 m_dialog->setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply );
168 connect( m_dialog, SIGNAL(applyClicked()), this, SLOT(configAccepted()) );
169 connect( m_dialog, SIGNAL(okClicked()), this, SLOT(configAccepted()) );
171 ui.showDate->setChecked(m_showDate);
172 ui.showYear->setChecked(m_showYear);
173 ui.showDay->setChecked(m_showDay);
174 ui.secondsCheckbox->setChecked(m_showSeconds);
175 ui.showTimezone->setChecked(m_showTimezone);
176 ui.plainClockFontBold->setChecked(m_plainClockFontBold);
177 ui.plainClockFontItalic->setChecked(m_plainClockFontItalic);
178 ui.plainClockFont->setCurrentFont(m_plainClockFont);
179 ui.plainClockColor->setColor(m_plainClockColor);
180 ui.timeZones->setSelected(m_timezone, true);
181 ui.timeZones->setEnabled(m_timezone != "Local");
182 ui.localTimeZone->setChecked(m_timezone == "Local");
184 m_dialog->show();
187 void Clock::configAccepted()
189 KConfigGroup cg = config();
190 //We need this to happen before we disconnect/reconnect sources to ensure
191 //that the update interval is set properly.
192 m_showSeconds = ui.secondsCheckbox->checkState() == Qt::Checked;
193 cg.writeEntry("showSeconds", m_showSeconds);
194 //QGraphicsItem::update();
195 QStringList tzs = ui.timeZones->selection();
196 if (ui.localTimeZone->checkState() == Qt::Checked) {
197 dataEngine("time")->disconnectSource(m_timezone, this);
198 m_timezone = "Local";
199 dataEngine("time")->connectSource(m_timezone, this, updateInterval(), intervalAlignment());
200 cg.writeEntry("timezone", m_timezone);
201 } else if (tzs.count() > 0) {
202 //TODO: support multiple timezones
203 QString tz = tzs.at(0);
204 if (tz != m_timezone) {
205 dataEngine("time")->disconnectSource(m_timezone, this);
206 // We have changed the timezone, show that in the clock, but only if this
207 // setting hasn't been changed.
208 ui.showTimezone->setCheckState(Qt::Checked);
209 m_timezone = tz;
210 dataEngine("time")->connectSource(m_timezone, this, updateInterval(), intervalAlignment());
212 cg.writeEntry("timezone", m_timezone);
213 } else if (m_timezone != "Local") {
214 dataEngine("time")->disconnectSource(m_timezone, this);
215 m_timezone = "Local";
216 dataEngine("time")->connectSource(m_timezone, this, updateInterval(), intervalAlignment());
217 cg.writeEntry("timezone", m_timezone);
218 } else {
219 kDebug() << "Timezone unknown: " << tzs;
222 m_showDate = ui.showDate->checkState() == Qt::Checked;
223 cg.writeEntry("showDate", m_showDate);
224 m_showYear = ui.showYear->checkState() == Qt::Checked;
225 cg.writeEntry("showYear", m_showYear);
226 m_showDay = ui.showDay->checkState() == Qt::Checked;
227 cg.writeEntry("showDay", m_showDay);
228 m_showSeconds = ui.secondsCheckbox->checkState() == Qt::Checked;
229 cg.writeEntry("showSeconds", m_showSeconds);
231 if (m_showTimezone != (ui.showTimezone->checkState() == Qt::Checked)) {
232 m_showTimezone = ui.showTimezone->checkState() == Qt::Checked;
233 cg.writeEntry("showTimezone", m_showTimezone);
234 kDebug() << "Saving show timezone: " << m_showTimezone;
237 m_plainClockFont = ui.plainClockFont->currentFont();
238 m_plainClockColor = ui.plainClockColor->color();
239 m_plainClockFontBold = ui.plainClockFontBold->checkState() == Qt::Checked;
240 m_plainClockFontItalic = ui.plainClockFontItalic->checkState() == Qt::Checked;
242 m_plainClockFont.setBold(m_plainClockFontBold);
243 m_plainClockFont.setItalic(m_plainClockFontItalic);
245 cg.writeEntry("plainClock", m_clockStyle == PlainClock);
246 cg.writeEntry("plainClockFont", m_plainClockFont);
247 cg.writeEntry("plainClockColor", m_plainClockColor);
248 cg.writeEntry("plainClockFontBold", m_plainClockFontBold);
249 cg.writeEntry("plainClockFontItalic", m_plainClockFontItalic);
251 update();
252 emit configNeedsSaving();
255 Clock::~Clock()
257 delete m_calendar;
258 delete m_dialog;
259 //delete m_layout;
260 // deleting m_layout isn't necessary. it is owned by the dialog
261 // (setLayout transfers ownership) and so will be deleted when the dialog is.
262 // thnx aseigo
265 void Clock::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
267 Q_UNUSED(option);
269 if (m_time.isValid() && m_date.isValid()) {
271 p->setFont(KGlobalSettings::smallestReadableFont());
273 p->setPen(QPen(m_plainClockColor));
274 p->setRenderHint(QPainter::SmoothPixmapTransform);
275 p->setRenderHint(QPainter::Antialiasing);
277 QRect timeRect;
279 // Paint the date, conditionally, and let us know afterwards how much
280 // space is left for painting the time on top of it.
281 if (m_showDate || m_showTimezone) {
282 QString dateString;
283 if (m_showDate) {
284 QString day = m_date.toString("d");
285 QString month = m_date.toString("MMM");
287 if (m_showYear) {
288 QString year = m_date.toString("yyyy");
289 dateString = i18nc("@label Short date: "
290 "%1 day in the month, %2 short month name, %3 year",
291 "%1 %2 %3", day, month, year);
292 } else {
293 dateString = i18nc("@label Short date: "
294 "%1 day in the month, %2 short month name",
295 "%1 %2", day, month);
298 if (m_showDay) {
299 QString weekday = QDate::shortDayName(m_date.dayOfWeek());
300 dateString = i18nc("@label Day of the week with date: "
301 "%1 short day name, %2 short date",
302 "%1, %2", weekday, dateString);
305 if (m_showTimezone) {
306 QString timezone = m_prettyTimezone;
307 timezone.replace("_", " ");
308 dateString = i18nc("@label Date with timezone: "
309 "%1 day of the week with date, %2 timezone",
310 "%1 %2", dateString, timezone);
312 } else if (m_showTimezone) {
313 dateString = m_prettyTimezone;
314 dateString.replace("_", " ");
317 // Check sizes
318 QRect dateRect = preparePainter(p, contentsRect, KGlobalSettings::smallestReadableFont(), dateString);
319 int subtitleHeight = dateRect.height();
321 p->drawText(QRectF(0,
322 contentsRect.bottom()-subtitleHeight,
323 contentsRect.right(),
324 contentsRect.bottom()) ,
325 dateString,
326 QTextOption(Qt::AlignHCenter)
329 // Now find out how much space is left for painting the time
330 timeRect = QRect( contentsRect.left(),
331 contentsRect.top(),
332 (contentsRect.width()),
333 (contentsRect.height()-subtitleHeight));
334 } else {
335 timeRect = QRect( contentsRect.left(),
336 (contentsRect.top()),
337 (contentsRect.width()),
338 (contentsRect.height()));
341 QString timeString = KGlobal::locale()->formatTime(m_time, m_showSeconds);
343 m_plainClockFont.setBold(m_plainClockFontBold);
344 m_plainClockFont.setItalic(m_plainClockFontItalic);
346 // Choose a relatively big font size to start with
347 m_plainClockFont.setPointSizeF(qMax((contentsRect.height()/1.5), (qreal)KGlobalSettings::smallestReadableFont().pointSize()));
348 preparePainter(p, timeRect, m_plainClockFont, timeString);
350 p->drawText(timeRect,
351 timeString,
352 QTextOption(Qt::AlignCenter)
357 QRect Clock::preparePainter(QPainter *p, const QRect &rect, const QFont &font, const QString &text)
359 QRect tmpRect;
360 QFont tmpFont = font;
362 // Starting with the given font, decrease its size until it'll fit in the
363 // given rect allowing wrapping where possible
364 do {
365 p->setFont(tmpFont);
366 tmpFont.setPointSize(qMax(KGlobalSettings::smallestReadableFont().pointSize(), tmpFont.pointSize() - 1));
367 tmpRect = p->boundingRect(rect, Qt::TextWordWrap, text);
368 } while (tmpFont.pointSize() > KGlobalSettings::smallestReadableFont().pointSize() && (tmpRect.width() > rect.width() ||
369 tmpRect.height() > rect.height()));
371 return tmpRect;
374 int Clock::updateInterval() const
376 return m_showSeconds ? 1000 : 60000;
379 Plasma::IntervalAlignment Clock::intervalAlignment() const
381 return m_showSeconds ? Plasma::NoAlignment : Plasma::AlignToMinute;
384 #include "clock.moc"