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

Applets

clock.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright 2007 by Aaron Seigo <aseigo@kde.org>                        *
00003  *   Copyright 2007 by Riccardo Iaconelli <riccardo@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 #include "clock.h"
00022 
00023 #include <math.h>
00024 
00025 #include <QApplication>
00026 #include <QBitmap>
00027 #include <QGraphicsScene>
00028 #include <QMatrix>
00029 #include <QPaintEvent>
00030 #include <QPainter>
00031 #include <QPainterPath>
00032 #include <QPixmap>
00033 #include <QStyleOptionGraphicsItem>
00034 #include <QVBoxLayout>
00035 #include <QHBoxLayout>
00036 #include <QCheckBox>
00037 #include <QPushButton>
00038 #include <QSpinBox>
00039 
00040 #include <KConfigDialog>
00041 #include <KDebug>
00042 #include <KLocale>
00043 #include <KIcon>
00044 #include <KSharedConfig>
00045 #include <KTimeZoneWidget>
00046 #include <KDialog>
00047 
00048 #include <plasma/dialog.h>
00049 #include <plasma/paintutils.h>
00050 #include <plasma/svg.h>
00051 #include <plasma/theme.h>
00052 
00053 Clock::Clock(QObject *parent, const QVariantList &args)
00054     : ClockApplet(parent, args),
00055       m_showTimeString(false),
00056       m_showSecondHand(false),
00057       m_secondHandUpdateTimer(0)
00058 {
00059     KGlobal::locale()->insertCatalog("libplasmaclock");
00060 
00061     setHasConfigurationInterface(true);
00062     resize(125, 125);
00063     setAspectRatioMode(Plasma::Square);
00064 
00065     m_theme = new Plasma::Svg(this);
00066     m_theme->setImagePath("widgets/clock");
00067     m_theme->setContainsMultipleImages(false);
00068     m_theme->resize(size());
00069 }
00070 
00071 Clock::~Clock()
00072 {
00073 }
00074 
00075 void Clock::init()
00076 {
00077     KConfigGroup cg = config();
00078     m_showTimeString = cg.readEntry("showTimeString", false);
00079     m_showSecondHand = cg.readEntry("showSecondHand", false);
00080     m_fancyHands = cg.readEntry("fancyHands", false);
00081     setCurrentTimezone(cg.readEntry("timezone", localTimezone()));
00082 
00083     connectToEngine();
00084 }
00085 
00086 void Clock::connectToEngine()
00087 {
00088     Plasma::DataEngine* timeEngine = dataEngine("time");
00089     if (m_showSecondHand) {
00090         timeEngine->connectSource(currentTimezone(), this, 500);
00091     } else {
00092         timeEngine->connectSource(currentTimezone(), this, 6000, Plasma::AlignToMinute);
00093     }
00094 }
00095 
00096 void Clock::constraintsEvent(Plasma::Constraints constraints)
00097 {
00098     if (constraints & Plasma::FormFactorConstraint) {
00099         setBackgroundHints(NoBackground);
00100     }
00101 
00102     if (constraints & Plasma::SizeConstraint) {
00103         m_theme->resize(size());
00104     }
00105 }
00106 
00107 QPainterPath Clock::shape() const
00108 {
00109     if (m_theme->hasElement("hint-square-clock")) {
00110         return Applet::shape();
00111     }
00112 
00113     QPainterPath path;
00114     // we adjust by 2px all around to allow for smoothing the jaggies
00115     // if the ellipse is too small, we'll get a nastily jagged edge around the clock
00116     path.addEllipse(boundingRect().adjusted(-2, -2, 2, 2));
00117     return path;
00118 }
00119 
00120 void Clock::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data)
00121 {
00122     Q_UNUSED(source);
00123     m_time = data["Time"].toTime();
00124 
00125     if (m_time.minute() == m_lastTimeSeen.minute() &&
00126         m_time.second() == m_lastTimeSeen.second()) {
00127         // avoid unnecessary repaints
00128         return;
00129     }
00130 
00131     if (m_secondHandUpdateTimer) {
00132         m_secondHandUpdateTimer->stop();
00133     }
00134 
00135     m_lastTimeSeen = m_time;
00136     update();
00137 }
00138 
00139 void Clock::createConfigurationInterface(KConfigDialog *parent)
00140 {
00141     //TODO: Make the size settable
00142     QWidget *widget = new QWidget();
00143     ui.setupUi(widget);
00144     parent->setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply );
00145     connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
00146     connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
00147     parent->addPage(widget, parent->windowTitle(), icon());
00148 
00149     ui.localTimeZone->setChecked(isLocalTimezone());
00150     ui.timeZones->setSelected(currentTimezone(), true);
00151     ui.timeZones->setEnabled(!isLocalTimezone());
00152     ui.showTimeStringCheckBox->setChecked(m_showTimeString);
00153     ui.showSecondHandCheckBox->setChecked(m_showSecondHand);
00154 }
00155 
00156 void Clock::configAccepted()
00157 {
00158     KConfigGroup cg = config();
00159     m_showTimeString = ui.showTimeStringCheckBox->isChecked();
00160     m_showSecondHand = ui.showSecondHandCheckBox->isChecked();
00161 
00162     cg.writeEntry("showTimeString", m_showTimeString);
00163     cg.writeEntry("showSecondHand", m_showSecondHand);
00164     update();
00165     QStringList tzs = ui.timeZones->selection();
00166 
00167     dataEngine("time")->disconnectSource(currentTimezone(), this);
00168     QString newTimezone = localTimezone();
00169     if (!ui.localTimeZone->isChecked() && !tzs.isEmpty()) {
00170         //TODO: support multiple timezones
00171         newTimezone = tzs.at(0);
00172     }
00173 
00174     setCurrentTimezone(newTimezone);
00175     cg.writeEntry("timezone", currentTimezone());
00176 
00177     connectToEngine();
00178     //TODO: why we don't call updateConstraints()?
00179     constraintsEvent(Plasma::AllConstraints);
00180     emit configNeedsSaving();
00181 }
00182 
00183 void Clock::moveSecondHand()
00184 {
00185     //kDebug() << "moving second hand";
00186     update();
00187 }
00188 
00189 void Clock::drawHand(QPainter *p, qreal rotation, const QString &handName)
00190 {
00191     p->save();
00192     const QSizeF boundSize = boundingRect().size();
00193     const QRectF elementRect = m_theme->elementRect(handName);
00194 
00195     p->translate(boundSize.width() / 2, boundSize.height() / 2);
00196     p->rotate(rotation);
00197     p->translate(-elementRect.width() / 2, -(m_theme->elementRect("clockFace").center().y() - elementRect.top()) );
00198     m_theme->paint(p, QRectF(QPointF(0, 0), elementRect.size()), handName);
00199    
00200     p->restore();
00201 }
00202 
00203 void Clock::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &rect)
00204 {
00205     Q_UNUSED(option)
00206     Q_UNUSED(rect)
00207 
00208     QRectF tempRect(0, 0, 0, 0);
00209 
00210     QSizeF boundSize = geometry().size();
00211     QSize elementSize;
00212 
00213     p->setRenderHint(QPainter::SmoothPixmapTransform);
00214 
00215     const qreal minutes = 6.0 * m_time.minute() - 180;
00216     const qreal hours = 30.0 * m_time.hour() - 180 +
00217                         ((m_time.minute() / 59.0) * 30.0);
00218 
00219     m_theme->paint(p, rect, "ClockFace");
00220 
00221     
00222     //optionally paint the time string
00223     if (m_showTimeString) {
00224         QString time;
00225         QFontMetrics fm(QApplication::font());
00226         const int margin = 4;
00227 
00228         if (m_showSecondHand) {
00229             //FIXME: temporary time output
00230             time = m_time.toString();
00231         } else {
00232             time = m_time.toString("hh:mm");
00233         }
00234 
00235         QRect textRect((rect.width()/2 - fm.width(time) / 2),((rect.height()/2) - fm.xHeight()*4),
00236               fm.width(time), fm.xHeight());
00237 
00238         p->setPen(Qt::NoPen);
00239         QColor background = Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor);
00240         background.setAlphaF(0.5);
00241         p->setBrush(background);
00242 
00243         p->setRenderHint(QPainter::Antialiasing, true);
00244         p->drawPath(Plasma::PaintUtils::roundedRectangle(textRect.adjusted(-margin, -margin, margin, margin), margin));
00245         p->setRenderHint(QPainter::Antialiasing, false);
00246 
00247         p->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
00248         
00249         p->drawText(textRect.bottomLeft(), time);
00250     }
00251 
00252 
00253     //Make sure we paint the second hand on top of the others
00254     qreal seconds = 0;
00255     if (m_showSecondHand) {
00256         static const double anglePerSec = 6;
00257         seconds = anglePerSec * m_time.second() - 180;
00258 
00259         if (m_fancyHands) {
00260             if (!m_secondHandUpdateTimer) {
00261                 m_secondHandUpdateTimer = new QTimer(this);
00262                 connect(m_secondHandUpdateTimer, SIGNAL(timeout()), this, SLOT(moveSecondHand()));
00263             }
00264 
00265             if (!m_secondHandUpdateTimer->isActive()) {
00266                 //kDebug() << "starting second hand movement";
00267                 m_secondHandUpdateTimer->start(50);
00268                 m_animationStart = QTime::currentTime().msec();
00269             } else {
00270                 static const int runTime = 500;
00271                 static const double m = 1; // Mass
00272                 static const double b = 1; // Drag coefficient
00273                 static const double k = 1.5; // Spring constant
00274                 static const double PI = 3.141592653589793; // the universe is irrational
00275                 static const double gamma = b / (2 * m); // Dampening constant
00276                 static const double omega0 = sqrt(k / m);
00277                 static const double omega1 = sqrt(omega0 * omega0 - gamma * gamma);
00278                 const double elapsed = QTime::currentTime().msec() - m_animationStart;
00279                 const double t = (4 * PI) * (elapsed / runTime);
00280                 const double val = 1 + exp(-gamma * t) * -cos(omega1 * t);
00281 
00282                 if (elapsed > runTime) {
00283                     m_secondHandUpdateTimer->stop();
00284                 } else {
00285                     seconds += -anglePerSec + (anglePerSec * val);
00286                 }
00287             }
00288         }
00289     }
00290 
00291     if (m_theme->hasElement("HourHandShadow")) {
00292         p->translate(1,3);
00293 
00294         drawHand(p, hours, "HourHandShadow");
00295         drawHand(p, minutes, "MinuteHandShadow");
00296 
00297         if (m_showSecondHand) {
00298             drawHand(p, seconds, "SecondHandShadow");
00299         }
00300 
00301         p->translate(-1,-3);
00302     }
00303     
00304     drawHand(p, hours, "HourHand");
00305     drawHand(p, minutes, "MinuteHand");
00306     if (m_showSecondHand) {
00307         drawHand(p, seconds, "SecondHand");
00308     }
00309 
00310     p->save();
00311     elementSize = m_theme->elementSize("HandCenterScrew");
00312     tempRect.setSize(elementSize);
00313     p->translate(boundSize.width() / 2 - elementSize.width() / 2, boundSize.height() / 2 - elementSize.height() / 2);
00314     m_theme->paint(p, tempRect, "HandCenterScrew");
00315     p->restore();
00316 
00317     m_theme->paint(p, rect, "Glass");
00318 }
00319 
00320 #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
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
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