00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00115
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
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
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
00171 newTimezone = tzs.at(0);
00172 }
00173
00174 setCurrentTimezone(newTimezone);
00175 cg.writeEntry("timezone", currentTimezone());
00176
00177 connectToEngine();
00178
00179 constraintsEvent(Plasma::AllConstraints);
00180 emit configNeedsSaving();
00181 }
00182
00183 void Clock::moveSecondHand()
00184 {
00185
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
00223 if (m_showTimeString) {
00224 QString time;
00225 QFontMetrics fm(QApplication::font());
00226 const int margin = 4;
00227
00228 if (m_showSecondHand) {
00229
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
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
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;
00272 static const double b = 1;
00273 static const double k = 1.5;
00274 static const double PI = 3.141592653589793;
00275 static const double gamma = b / (2 * m);
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"