• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Applets

clock.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2007-2008 by Riccardo Iaconelli <riccardo@kde.org>      *
00003  *   Copyright (C) 2007-2008 by Sebastian Kuegler <sebas@kde.org>          *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
00019  ***************************************************************************/
00020 
00021 
00022 #include "clock.h"
00023 
00024 #include <math.h>
00025 
00026 #include <QtGui/QPainter>
00027 #include <QtGui/QStyleOptionGraphicsItem>
00028 #include <QtGui/QSpinBox>
00029 #include <QtCore/QTimeLine>
00030 #include <QtGui/QGraphicsView>
00031 #include <QtGui/QGraphicsSceneMouseEvent>
00032 #include <QtCore/QDate>
00033 
00034 #include <KDebug>
00035 #include <KLocale>
00036 #include <KIcon>
00037 #include <KSharedConfig>
00038 #include <KTimeZoneWidget>
00039 #include <KDialog>
00040 #include <KColorScheme>
00041 #include <KGlobalSettings>
00042 #include <KConfigDialog>
00043 #include <KDatePicker>
00044 #include <Plasma/Theme>
00045 #include <Plasma/Dialog>
00046 #include <Plasma/ToolTipManager>
00047 
00048 
00049 Clock::Clock(QObject *parent, const QVariantList &args)
00050     : ClockApplet(parent, args),
00051       m_plainClockFont(KGlobalSettings::generalFont()),
00052       m_useCustomColor(false),
00053       m_plainClockColor(),
00054       m_showDate(false),
00055       m_showYear(false),
00056       m_showDay(false),
00057       m_showSeconds(false),
00058       m_showTimezone(false),
00059       m_dateTimezoneBesides(false),
00060       m_dateString(0),
00061       m_layout(0)
00062 {
00063     KGlobal::locale()->insertCatalog("libplasmaclock");
00064     setHasConfigurationInterface(true);
00065     resize(150, 75);
00066 }
00067 
00068 Clock::~Clock()
00069 {
00070 }
00071 
00072 void Clock::init()
00073 {
00074     ClockApplet::init();
00075 
00076     KConfigGroup cg = config();
00077 
00078     m_showTimezone = cg.readEntry("showTimezone", !isLocalTimezone());
00079 
00080     kDebug() << "showTimezone:" << m_showTimezone;
00081 
00082     m_showDate = cg.readEntry("showDate", false);
00083     m_showYear = cg.readEntry("showYear", false);
00084     m_showDay = cg.readEntry("showDay", true);
00085 
00086     m_showSeconds = cg.readEntry("showSeconds", false);
00087     m_plainClockFont = cg.readEntry("plainClockFont", m_plainClockFont);
00088     m_useCustomColor = cg.readEntry("useCustomColor", false);
00089     if (m_useCustomColor) {
00090         m_plainClockColor = cg.readEntry("plainClockColor", m_plainClockColor);
00091     } else {
00092         m_plainClockColor = KColorScheme(QPalette::Active, KColorScheme::View, Plasma::Theme::defaultTheme()->colorScheme()).foreground().color();
00093     }
00094 
00095     QFontMetricsF metrics(KGlobalSettings::smallestReadableFont());
00096     QString timeString = KGlobal::locale()->formatTime(QTime(23, 59), m_showSeconds);
00097     setMinimumSize(metrics.size(Qt::TextSingleLine, timeString));
00098 
00099     dataEngine("time")->connectSource(currentTimezone(), this, updateInterval(), intervalAlignment());
00100     connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(updateColors()));
00101 }
00102 
00103 void Clock::constraintsEvent(Plasma::Constraints constraints)
00104 {
00105     ClockApplet::constraintsEvent(constraints);
00106 
00107     if (constraints & Plasma::SizeConstraint) {
00108         updateSize();
00109     }
00110 }
00111 
00112 void Clock::updateSize()
00113 {
00114     Plasma::FormFactor f = formFactor();
00115 
00116     if (f != Plasma::Vertical && f != Plasma::Horizontal) {
00117         QFontMetricsF metrics(KGlobalSettings::smallestReadableFont());
00118         // calculates based on size of "23:59"!
00119         QString timeString = KGlobal::locale()->formatTime(QTime(23, 59), m_showSeconds);
00120         setMinimumSize(metrics.size(Qt::TextSingleLine, timeString));
00121     }
00122 
00123     // more magic numbers
00124     int aspect = 2;
00125     if (m_showSeconds) {
00126         aspect = 3;
00127     }
00128 
00129     int w, h;
00130     if (m_showDate || showTimezone()) {
00131         QFont f(KGlobalSettings::smallestReadableFont());
00132         QFontMetrics metrics(f);
00133         // if there's enough vertical space, wrap the words
00134         if (contentsRect().height() < f.pointSize() * 6) {
00135             QSize s = metrics.size(Qt::TextSingleLine, m_dateString);
00136             w = s.width() + metrics.width(" ");
00137             h = s.height();
00138             //kDebug(96669) << "uS: singleline" << w;
00139         } else {
00140             QSize s = metrics.size(Qt::TextWordWrap, m_dateString);
00141             w = s.width();
00142             h = s.height();
00143             //kDebug(96669) << "uS: wordwrap" << w;
00144         }
00145 
00146         if (!m_dateTimezoneBesides) {
00147             w = qMax(w, (int)(contentsRect().height() * aspect));
00148             h = h+(int)(contentsRect().width() / aspect);
00149         } else {
00150             w = w+(int)(contentsRect().height() * aspect);
00151             h = qMax(h, (int)(contentsRect().width() / aspect));
00152         }
00153     } else {
00154         w = (int)(contentsRect().height() * aspect);
00155         h = (int)(contentsRect().width() / aspect);
00156     }
00157 
00158     if (f == Plasma::Horizontal) {
00159         // We have a fixed height, set some sensible width
00160         setMinimumWidth(w);
00161         setMinimumHeight(0);
00162         //kDebug() << "DR" << m_dateRect.width() << "CR" << contentsRect().height() * aspect;
00163         // kDebug(96669) << contentsRect();
00164     } else {
00165         // We have a fixed width, set some sensible height
00166         setMinimumHeight(h);
00167         setMinimumWidth(0);
00168     }
00169     // kDebug(96669) << "minZize: " << minimumSize();
00170 }
00171 
00172 bool Clock::showTimezone() const
00173 {
00174     return m_showTimezone || shouldDisplayTimezone();
00175 }
00176 
00177 void Clock::dataUpdated(const QString &source, const Plasma::DataEngine::Data &data)
00178 {
00179     Q_UNUSED(source);
00180     m_time = data["Time"].toTime();
00181     m_date = data["Date"].toDate();
00182 
00183     if (Plasma::ToolTipManager::self()->isVisible(this)) {
00184         updateTipContent();
00185     }
00186 
00187     // avoid unnecessary repaints
00188     if ((m_showSeconds && m_time.second() != m_lastTimeSeen.second()) ||
00189         m_time.minute() != m_lastTimeSeen.minute()) {
00190         m_lastTimeSeen = m_time;
00191         update();
00192     }
00193 }
00194 
00195 void Clock::createClockConfigurationInterface(KConfigDialog *parent)
00196 {
00197     //TODO: Make the size settable
00198     QWidget *widget = new QWidget();
00199     ui.setupUi(widget);
00200     parent->addPage(widget, i18n("General"), icon());
00201 
00202     ui.showDate->setChecked(m_showDate);
00203     ui.showYear->setChecked(m_showYear);
00204     ui.showDay->setChecked(m_showDay);
00205     ui.secondsCheckbox->setChecked(m_showSeconds);
00206     ui.showTimeZone->setChecked(m_showTimezone);
00207     ui.plainClockFontBold->setChecked(m_plainClockFont.bold());
00208     ui.plainClockFontItalic->setChecked(m_plainClockFont.italic());
00209     ui.plainClockFont->setCurrentFont(m_plainClockFont);
00210     ui.useCustomColor->setChecked(m_useCustomColor);
00211     ui.plainClockColor->setColor(m_plainClockColor);
00212 }
00213 
00214 void Clock::clockConfigAccepted()
00215 {
00216     KConfigGroup cg = config();
00217 
00218     m_showTimezone = ui.showTimeZone->isChecked();
00219     cg.writeEntry("showTimezone", m_showTimezone);
00220 
00221     m_plainClockFont = ui.plainClockFont->currentFont();
00222     //We need this to happen before we disconnect/reconnect sources to ensure
00223     //that the update interval is set properly.
00224     if (m_showSeconds != ui.secondsCheckbox->isChecked()) {
00225         m_showSeconds = !m_showSeconds;
00226         cg.writeEntry("showSeconds", m_showSeconds);
00227 
00228         dataEngine("time")->disconnectSource(currentTimezone(), this);
00229         dataEngine("time")->connectSource(currentTimezone(), this, updateInterval(), intervalAlignment());
00230     }
00231 
00232     m_showDate = ui.showDate->checkState() == Qt::Checked;
00233     cg.writeEntry("showDate", m_showDate);
00234     m_showYear = ui.showYear->checkState() == Qt::Checked;
00235     cg.writeEntry("showYear", m_showYear);
00236     m_showDay = ui.showDay->checkState() == Qt::Checked;
00237     cg.writeEntry("showDay", m_showDay);
00238     m_showSeconds = ui.secondsCheckbox->checkState() == Qt::Checked;
00239     cg.writeEntry("showSeconds", m_showSeconds);
00240 
00241     m_useCustomColor = ui.useCustomColor->isChecked();
00242     if (m_useCustomColor) {
00243         m_plainClockColor = ui.plainClockColor->color();
00244     } else {
00245         m_plainClockColor = KColorScheme(QPalette::Active, KColorScheme::View, Plasma::Theme::defaultTheme()->colorScheme()).foreground().color();
00246     }
00247 
00248     m_plainClockFont.setBold(ui.plainClockFontBold->checkState() == Qt::Checked);
00249     m_plainClockFont.setItalic(ui.plainClockFontItalic->checkState() == Qt::Checked);
00250 
00251     cg.writeEntry("plainClockFont", m_plainClockFont);
00252     cg.writeEntry("useCustomColor", m_useCustomColor);
00253     cg.writeEntry("plainClockColor", m_plainClockColor);
00254 
00255     constraintsEvent(Plasma::SizeConstraint);
00256     update();
00257     emit sizeHintChanged(Qt::PreferredSize);
00258     emit configNeedsSaving();
00259 }
00260 
00261 void Clock::changeEngineTimezone(const QString &oldTimezone, const QString &newTimezone)
00262 {
00263     dataEngine("time")->disconnectSource(oldTimezone, this);
00264     dataEngine("time")->connectSource(newTimezone, this, updateInterval(), intervalAlignment());
00265 }
00266 
00267 QRectF Clock::normalLayout(int subtitleWidth, int subtitleHeight, const QRect &contentsRect)
00268 {
00269     Q_UNUSED(subtitleWidth);
00270 
00271     QRectF myRect = QRectF(contentsRect.left(),
00272                     contentsRect.bottom() - subtitleHeight,
00273                     contentsRect.width(),
00274                     contentsRect.bottom());
00275 
00276     //p->fillRect(myRect, QBrush(QColor("green")));
00277 
00278     // Now find out how much space is left for painting the time
00279     m_timeRect = QRect(contentsRect.left(),
00280                        contentsRect.top(),
00281                        contentsRect.width(),
00282                        contentsRect.height() - subtitleHeight);
00283 
00284     return myRect;
00285 }
00286 
00287 QRectF Clock::sideBySideLayout(int subtitleWidth, int subtitleHeight, const QRect &contentsRect)
00288 {
00289     QRectF myRect = QRectF(contentsRect.right()-subtitleWidth,
00290                            (contentsRect.bottom()-subtitleHeight)/2,
00291                            subtitleWidth,
00292                            subtitleHeight);
00293     // kDebug(96669) << "myRect: " << myRect;
00294     // p->fillRect(myRect, QBrush(QColor("grey")));
00295 
00296     // Now find out how much space is left for painting the time
00297     m_timeRect = QRect(contentsRect.left(),
00298                        contentsRect.top(),
00299                        contentsRect.right() - subtitleWidth,
00300                        contentsRect.bottom());
00301 
00302     return myRect;
00303 }
00304 
00305 void Clock::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
00306 {
00307     Q_UNUSED(option);
00308 
00309     if (!m_time.isValid() || !m_date.isValid()) {
00310         return;
00311     }
00312 
00313     p->setPen(QPen(m_plainClockColor));
00314     p->setRenderHint(QPainter::SmoothPixmapTransform);
00315     p->setRenderHint(QPainter::Antialiasing);
00316 
00317     /* ... helps debugging contentsRect and sizing ... 
00318        QColor c = QColor(Qt::blue);
00319        c.setAlphaF(.5);
00320        p->setBrush(c);
00321        p->drawRect(contentsRect);
00322      */
00323 
00324     // Paint the date, conditionally, and let us know afterwards how much
00325     // space is left for painting the time on top of it.
00326     QRectF dateRect;
00327     QString timeString = KGlobal::locale()->formatTime(m_time, m_showSeconds);
00328     QFont smallFont = KGlobalSettings::smallestReadableFont();
00329 
00330     if (m_showDate || showTimezone()) {
00331         QString dateString;
00332         if (m_showDate) {
00333             KLocale tmpLocale(*KGlobal::locale());
00334             tmpLocale.setDateFormat("%e"); // day number of the month
00335             QString day = tmpLocale.formatDate(m_date);
00336             tmpLocale.setDateFormat("%b"); // short form of the month
00337             QString month = tmpLocale.formatDate(m_date);
00338 
00339             if (m_showYear) {
00340                 tmpLocale.setDateFormat("%Y"); // whole year
00341                 QString year = tmpLocale.formatDate(m_date);
00342                 dateString = i18nc("@label Short date: "
00343                         "%1 day in the month, %2 short month name, %3 year",
00344                         "%1 %2 %3", day, month, year);
00345             } else {
00346                 dateString = i18nc("@label Short date: "
00347                         "%1 day in the month, %2 short month name",
00348                         "%1 %2", day, month);
00349             }
00350 
00351             if (m_showDay) {
00352                 tmpLocale.setDateFormat("%a"); // short weekday
00353                 QString weekday = tmpLocale.formatDate(m_date);
00354                 dateString = i18nc("@label Day of the week with date: "
00355                         "%1 short day name, %2 short date",
00356                         "%1, %2", weekday, dateString);
00357             }
00358 
00359             if (showTimezone()) {
00360                 QString currentTimezone = prettyTimezone();
00361                 dateString = i18nc("@label Date with currentTimezone: "
00362                         "%1 day of the week with date, %2 currentTimezone",
00363                         "%1 %2", dateString, currentTimezone);
00364             }
00365         } else if (showTimezone()) {
00366             dateString = prettyTimezone();
00367         }
00368 
00369         dateString = dateString.trimmed();
00370 
00371         if (m_dateString != dateString) {
00372             // If this string has changed (for example due to changes in the config
00373             // we have to reset the sizing of the applet
00374             m_dateString = dateString;
00375             updateSize();
00376         }
00377 
00378         // Check sizes
00379         // magic 10 is for very big spaces,
00380         // where there's enough space to grow without harming time space
00381         QFontMetrics fm(smallFont);
00382         smallFont.setPixelSize(qMax(contentsRect.height()/10, fm.ascent()));
00383         // kDebug(96669) << "=========";
00384         // kDebug(96669) << "contentsRect: " << contentsRect;
00385 
00386         m_dateRect = preparePainter(p, contentsRect, smallFont, dateString);
00387         // kDebug(96669) << "m_dateRect: " << m_dateRect;
00388 
00389         int subtitleHeight = m_dateRect.height();
00390         int subtitleWidth = m_dateRect.width();
00391         // kDebug(96669) << "subtitleWitdh: " << subtitleWitdh;
00392         // kDebug(96669) << "subtitleHeight: " << subtitleHeight;
00393 
00394         if (m_dateTimezoneBesides) {
00395             //kDebug(96669) << contentsRect.height() << subtitleHeight << smallFont.pixelSize();
00396             if (contentsRect.height() - subtitleHeight >= smallFont.pixelSize() || formFactor() != Plasma::Horizontal) {
00397                 // to small to display the time on top of the date/timezone
00398                 // put them side by side
00399                 // kDebug(96669) << "switching to normal";
00400                 m_dateTimezoneBesides = false;
00401                 dateRect = normalLayout(subtitleWidth, subtitleHeight, contentsRect);
00402             } else {
00403                 dateRect = sideBySideLayout(subtitleWidth, subtitleHeight, contentsRect);
00404             }
00405         } else {
00406             /* kDebug(96669) << "checking timezone placement"
00407                           << contentsRect.height() << dateRect.height() << subtitleHeight
00408                           << smallFont.pixelSize() << smallFont.pointSize();*/
00409             if (contentsRect.height() - subtitleHeight < smallFont.pixelSize() && formFactor() == Plasma::Horizontal) {
00410                 // to small to display the time on top of the date/timezone
00411                 // put them side by side
00412                 // kDebug(96669) << "switching to s-b-s";
00413                 m_dateTimezoneBesides = true;
00414                 dateRect = sideBySideLayout(subtitleWidth, subtitleHeight, contentsRect);
00415             } else {
00416                 dateRect = normalLayout(subtitleWidth, subtitleHeight, contentsRect);
00417             }
00418         }
00419     } else {
00420         m_timeRect = contentsRect;
00421     }
00422     // kDebug(96669) << "timeRect: " << m_timeRect;
00423     // p->fillRect(timeRect, QBrush(QColor("red")));
00424 
00425     // kDebug(96669) << m_time;
00426     // Choose a relatively big font size to start with
00427     m_plainClockFont.setPointSizeF(qMax(m_timeRect.height(), KGlobalSettings::smallestReadableFont().pointSize()));
00428     preparePainter(p, m_timeRect, m_plainClockFont, timeString, true);
00429 
00430     if (!m_dateString.isEmpty()) {
00431         if (m_dateTimezoneBesides) {
00432             QFontMetrics fm(m_plainClockFont);
00433             //kDebug() << dateRect << m_timeRect << fm.boundingRect(m_timeRect, Qt::AlignCenter, timeString);
00434             QRect br = fm.boundingRect(m_timeRect, Qt::AlignCenter, timeString);
00435 
00436             QFontMetrics smallfm(smallFont);
00437             dateRect.moveLeft(br.right() + qMin(0, br.left()) + smallfm.width(" "));
00438         }
00439 
00440         // When we're relatively low, force everything into a single line
00441         QFont f = p->font();
00442         p->setFont(smallFont);
00443 
00444         if (formFactor() == Plasma::Horizontal && (contentsRect.height() < smallFont.pointSize()*6)) {
00445             p->drawText(dateRect, Qt::TextSingleLine | Qt::AlignHCenter, m_dateString);
00446         } else {
00447             p->drawText(dateRect, Qt::TextWordWrap | Qt::AlignHCenter, m_dateString);
00448         }
00449 
00450         p->setFont(f);
00451     }
00452 
00453     QTextOption textOption(m_dateTimezoneBesides ? Qt::AlignCenter | Qt::AlignVCenter : Qt::AlignCenter);
00454     textOption.setWrapMode(QTextOption::NoWrap);
00455     p->drawText(m_timeRect, timeString, textOption);
00456 }
00457 
00458 QRect Clock::preparePainter(QPainter *p, const QRect &rect, const QFont &font, const QString &text, bool singleline)
00459 {
00460     QRect tmpRect;
00461     QFont tmpFont = font;
00462     bool first = true;
00463 
00464     // Starting with the given font, decrease its size until it'll fit in the
00465     // given rect allowing wrapping where possible
00466     do {
00467         if (first) {
00468             first = false;
00469         } else  {
00470             tmpFont.setPointSize(qMax(KGlobalSettings::smallestReadableFont().pointSize(), tmpFont.pointSize() - 1));
00471         }
00472 
00473         QFontMetrics fm(tmpFont);
00474         int flags = (singleline || ((formFactor() == Plasma::Horizontal) &&
00475                                     (contentsRect().height() < tmpFont.pointSize()*6))) ?
00476                     Qt::TextSingleLine : Qt::TextWordWrap;
00477 
00478         tmpRect = fm.boundingRect(rect, flags, text);
00479     } while (tmpFont.pointSize() > KGlobalSettings::smallestReadableFont().pointSize() &&
00480              (tmpRect.width() > rect.width() || tmpRect.height() > rect.height()));
00481 
00482     p->setFont(tmpFont);
00483     return tmpRect;
00484 }
00485 
00486 int Clock::updateInterval() const
00487 {
00488     return m_showSeconds ? 1000 : 60000;
00489 }
00490 
00491 Plasma::IntervalAlignment Clock::intervalAlignment() const
00492 {
00493     return m_showSeconds ? Plasma::NoAlignment : Plasma::AlignToMinute;
00494 }
00495 
00496 void Clock::updateColors()
00497 {
00498     if (!m_useCustomColor) {
00499         m_plainClockColor = KColorScheme(QPalette::Active, KColorScheme::View, Plasma::Theme::defaultTheme()->colorScheme()).foreground().color();
00500         update();
00501     }
00502 }
00503 #include "clock.moc"

Applets

Skip menu "Applets"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal