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> *
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. *
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. *
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 ***************************************************************************/
26 #include <QtGui/QPainter>
27 #include <QtGui/QStyleOptionGraphicsItem>
28 #include <QtGui/QSpinBox>
29 #include <QtCore/QTimeLine>
30 #include <QtGui/QGraphicsView>
31 #include <QtGui/QGraphicsSceneMouseEvent>
36 #include <KSharedConfig>
37 #include <KTimeZoneWidget>
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()),
51 m_plainClockFontBold(false),
52 m_plainClockFontItalic(false),
57 m_showTimezone(false),
62 setHasConfigurationInterface(true);
63 setContentSize(70, 22);
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
) {
102 return Qt::Horizontal
;
106 void Clock::dataUpdated(const QString
& source
, const Plasma::DataEngine::Data
&data
)
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
;
121 void Clock::mousePressEvent(QGraphicsSceneMouseEvent
*event
)
123 if (event
->buttons() == Qt::LeftButton
&& contentRect().contains(event
->pos())) {
130 void Clock::showCalendar(QGraphicsSceneMouseEvent
*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()) {
151 m_calendar
->move(popupPosition(m_calendar
->sizeHint()));
156 void Clock::showConfigurationInterface()
159 m_dialog
= new KDialog
;
161 m_dialog
->setCaption(i18n("Configure Clock"));
163 QWidget
*widget
= new QWidget
;
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");
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
);
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
);
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
);
252 emit
configNeedsSaving();
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.
265 void Clock::paintInterface(QPainter
*p
, const QStyleOptionGraphicsItem
*option
, const QRect
&contentsRect
)
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
);
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
) {
284 QString day
= m_date
.toString("d");
285 QString month
= m_date
.toString("MMM");
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
);
293 dateString
= i18nc("@label Short date: "
294 "%1 day in the month, %2 short month name",
295 "%1 %2", day
, month
);
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("_", " ");
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()) ,
326 QTextOption(Qt::AlignHCenter
)
329 // Now find out how much space is left for painting the time
330 timeRect
= QRect( contentsRect
.left(),
332 (contentsRect
.width()),
333 (contentsRect
.height()-subtitleHeight
));
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
,
352 QTextOption(Qt::AlignCenter
)
357 QRect
Clock::preparePainter(QPainter
*p
, const QRect
&rect
, const QFont
&font
, const QString
&text
)
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
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()));
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
;