00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "battery.h"
00023
00024 #include <QApplication>
00025 #include <QPainter>
00026 #include <QStyleOptionGraphicsItem>
00027 #include <QFont>
00028 #include <QGraphicsSceneHoverEvent>
00029
00030 #include <KDebug>
00031 #include <KIcon>
00032 #include <KLocalizedString>
00033 #include <KSharedConfig>
00034 #include <KDialog>
00035 #include <KColorScheme>
00036 #include <KConfigDialog>
00037 #include <KGlobalSettings>
00038
00039 #include <plasma/svg.h>
00040 #include <plasma/theme.h>
00041 #include <plasma/animator.h>
00042
00043 Battery::Battery(QObject *parent, const QVariantList &args)
00044 : Plasma::Applet(parent, args),
00045 m_batteryStyle(0),
00046 m_theme(0),
00047 m_animId(-1),
00048 m_alpha(1),
00049 m_fadeIn(true),
00050 m_acAnimId(-1),
00051 m_acAlpha(1),
00052 m_acFadeIn(false),
00053 m_batteryAnimId(-1),
00054 m_batteryAlpha(1),
00055 m_batteryFadeIn(true),
00056 m_isHovered(false),
00057 m_numOfBattery(0)
00058 {
00059 kDebug() << "Loading applet battery";
00060 setAcceptsHoverEvents(true);
00061 setHasConfigurationInterface(true);
00062 resize(128, 128);
00063
00064 m_textRect = QRect();
00065 }
00066
00067 void Battery::init()
00068 {
00069 KConfigGroup cg = config();
00070 m_showBatteryString = cg.readEntry("showBatteryString", false);
00071 m_showMultipleBatteries = cg.readEntry("showMultipleBatteries", true);
00072
00073 QString svgFile = QString();
00074 if (cg.readEntry("style", 0) == 0) {
00075 m_batteryStyle = OxygenBattery;
00076 svgFile = "widgets/battery-oxygen";
00077 } else {
00078 m_batteryStyle = ClassicBattery;
00079 svgFile = "widgets/battery";
00080 }
00081 m_theme = new Plasma::Svg(this);
00082 m_theme->setImagePath(svgFile);
00083 m_theme->setContainsMultipleImages(false);
00084
00085 m_theme->resize(contentsRect().size());
00086 m_font = QApplication::font();
00087 m_font.setWeight(QFont::Bold);
00088
00089 m_boxAlpha = 128;
00090 m_boxHoverAlpha = 192;
00091
00092 readColors();
00093 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(readColors()));
00094
00095 const QStringList& battery_sources = dataEngine("powermanagement")->query(I18N_NOOP("Battery"))[I18N_NOOP("sources")].toStringList();
00096
00097
00098 connectSources();
00099
00100 foreach (const QString &battery_source, battery_sources) {
00101 kDebug() << "BatterySource:" << battery_source;
00102 dataUpdated(battery_source, dataEngine("powermanagement")->query(battery_source));
00103 }
00104 dataUpdated(I18N_NOOP("AC Adapter"), dataEngine("powermanagement")->query(I18N_NOOP("AC Adapter")));
00105 m_numOfBattery = battery_sources.size();
00106 kDebug() << battery_sources.size();
00107 }
00108
00109 void Battery::constraintsEvent(Plasma::Constraints constraints)
00110 {
00111 if (constraints & (Plasma::FormFactorConstraint | Plasma::SizeConstraint)) {
00112 if (formFactor() == Plasma::Vertical) {
00113 setMaximumSize(QWIDGETSIZE_MAX, qMax(m_textRect.height(), contentsRect().width()));
00114
00115 } else if (formFactor() == Plasma::Horizontal) {
00116 setMaximumSize(qMax(m_textRect.width(), contentsRect().height()), QWIDGETSIZE_MAX);
00117
00118 }
00119 }
00120
00121 if (constraints & (Plasma::SizeConstraint | Plasma::FormFactorConstraint) && m_theme) {
00122 m_theme->resize(contentsRect().size().toSize());
00123 m_font.setPointSize(qMax(KGlobalSettings::smallestReadableFont().pointSize(),
00124 qRound(contentsRect().height() / 10)));
00125 }
00126 }
00127
00128 void Battery::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data)
00129 {
00130 if (source.startsWith(I18N_NOOP("Battery"))) {
00131 m_batteries_data[source] = data;
00132 } else if (source == I18N_NOOP("AC Adapter")) {
00133 m_acadapter_plugged = data[I18N_NOOP("Plugged in")].toBool();
00134 showAcAdapter(m_acadapter_plugged);
00135 } else {
00136 kDebug() << "Applet::Dunno what to do with " << source;
00137 }
00138 update();
00139 }
00140
00141 void Battery::createConfigurationInterface(KConfigDialog *parent)
00142 {
00143 QWidget *widget = new QWidget();
00144 ui.setupUi(widget);
00145 parent->setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply );
00146 parent->addPage(widget, parent->windowTitle(), icon());
00147 connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
00148 connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
00149 ui.styleGroup->setSelected(m_batteryStyle);
00150 ui.showBatteryStringCheckBox->setChecked(m_showBatteryString ? Qt::Checked : Qt::Unchecked);
00151 ui.showMultipleBatteriesCheckBox->setChecked(m_showMultipleBatteries ? Qt::Checked : Qt::Unchecked);
00152 }
00153
00154 void Battery::configAccepted()
00155 {
00156 KConfigGroup cg = config();
00157
00158 if (m_showBatteryString != ui.showBatteryStringCheckBox->isChecked()) {
00159 m_showBatteryString = !m_showBatteryString;
00160 cg.writeEntry("showBatteryString", m_showBatteryString);
00161 showLabel(m_showBatteryString);
00162 }
00163
00164 if (m_showMultipleBatteries != ui.showMultipleBatteriesCheckBox->isChecked()) {
00165 m_showMultipleBatteries = !m_showMultipleBatteries;
00166 cg.writeEntry("showMultipleBatteries", m_showMultipleBatteries);
00167 kDebug() << "Show multiple battery changed: " << m_showMultipleBatteries;
00168 }
00169
00170 if (ui.styleGroup->selected() != m_batteryStyle) {
00171 QString svgFile = QString();
00172 if (ui.styleGroup->selected() == OxygenBattery) {
00173 svgFile = "widgets/battery-oxygen";
00174 } else {
00175 svgFile = "widgets/battery";
00176 }
00177 if (m_acadapter_plugged) {
00178 showAcAdapter(false);
00179 }
00180 showBattery(false);
00181 m_batteryStyle = ui.styleGroup->selected();
00182 delete m_theme;
00183 m_theme = new Plasma::Svg(this);
00184 m_theme->setImagePath(svgFile);
00185 kDebug() << "Changing theme to " << svgFile;
00186 cg.writeEntry("style", m_batteryStyle);
00187 m_theme->resize(contentsRect().size());
00188 if (m_acadapter_plugged) {
00189 showAcAdapter(true);
00190 }
00191 showBattery(true);
00192 }
00193
00194
00195 disconnectSources();
00196 connectSources();
00197
00198 emit configNeedsSaving();
00199 }
00200
00201 void Battery::readColors()
00202 {
00203 m_textColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
00204 m_boxColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor);
00205 m_boxColor.setAlpha(m_boxAlpha);
00206 }
00207
00208 void Battery::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00209 {
00210 showLabel(true);
00211
00212
00213 m_isHovered = true;
00214 Applet::hoverEnterEvent(event);
00215 }
00216
00217 void Battery::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00218 {
00219 if (!m_showBatteryString) {
00220 showLabel(false);
00221 }
00222
00223
00224
00225 Applet::hoverLeaveEvent(event);
00226 }
00227
00228 Battery::~Battery()
00229 {
00230 }
00231
00232 void Battery::showLabel(bool show)
00233 {
00234 if (m_fadeIn == show) {
00235 return;
00236 }
00237 m_fadeIn = show;
00238 const int FadeInDuration = 150;
00239
00240 if (m_animId != -1) {
00241 Plasma::Animator::self()->stopCustomAnimation(m_animId);
00242 }
00243 m_animId = Plasma::Animator::self()->customAnimation(40 / (1000 / FadeInDuration), FadeInDuration,
00244 Plasma::Animator::EaseOutCurve, this,
00245 "animationUpdate");
00246 }
00247
00248 QRectF Battery::scaleRectF(const qreal progress, QRectF rect) {
00249 if (progress == 1) {
00250 return rect;
00251 }
00252
00253 qreal w = rect.width()*progress;
00254 qreal h = rect.width()*progress;
00255
00256
00257 rect.setX((rect.width() - w)/2);
00258 rect.setY((rect.height() - h)/2);
00259
00260 rect.setWidth(w);
00261 rect.setHeight(h);
00262
00263 return rect;
00264 }
00265
00266 void Battery::showAcAdapter(bool show)
00267 {
00268 if (m_acFadeIn == show) {
00269 return;
00270 }
00271 m_acFadeIn = show;
00272 const int FadeInDuration = 300;
00273
00274
00275 m_acadapter_plugged = true;
00276
00277 if (m_acAnimId != -1) {
00278 Plasma::Animator::self()->stopCustomAnimation(m_acAnimId);
00279 }
00280 m_acAnimId = Plasma::Animator::self()->customAnimation(40 / (1000 / FadeInDuration), FadeInDuration,
00281 Plasma::Animator::EaseOutCurve, this,
00282 "acAnimationUpdate");
00283 }
00284
00285 void Battery::showBattery(bool show)
00286 {
00287 if (m_batteryFadeIn == show) {
00288 return;
00289 }
00290 m_batteryFadeIn = show;
00291 const int FadeInDuration = 300;
00292
00293 if (m_batteryAnimId != -1) {
00294 Plasma::Animator::self()->stopCustomAnimation(m_batteryAnimId);
00295 }
00296 m_batteryAnimId = Plasma::Animator::self()->customAnimation(40 / (1000 / FadeInDuration), FadeInDuration,
00297 Plasma::Animator::EaseOutCurve, this,
00298 "batteryAnimationUpdate");
00299 }
00300
00301 void Battery::animationUpdate(qreal progress)
00302 {
00303 if (progress == 1) {
00304 m_animId = -1;
00305 }
00306 if (!m_fadeIn) {
00307 qreal new_alpha = m_fadeIn ? progress : 1 - progress;
00308 m_alpha = qMin(new_alpha, m_alpha);
00309 } else {
00310 m_alpha = m_fadeIn ? progress : 1 - progress;
00311 }
00312 m_alpha = qMax(qreal(0.0), m_alpha);
00313 update();
00314 }
00315
00316 void Battery::acAnimationUpdate(qreal progress)
00317 {
00318 if (progress == 1) {
00319 m_acAnimId = -1;
00320 }
00321 m_acAlpha = m_acFadeIn ? progress : 1 - progress;
00322
00323
00324 if (!m_acFadeIn && (progress == 1)) {
00325 m_acadapter_plugged = false;
00326 }
00327 update();
00328 }
00329
00330 void Battery::batteryAnimationUpdate(qreal progress)
00331 {
00332 if (progress == 1) {
00333 m_batteryAnimId = -1;
00334 }
00335 m_batteryAlpha = m_batteryFadeIn ? progress : 1 - progress;
00336 update();
00337 }
00338
00339 void Battery::paintLabel(QPainter *p, const QRect &contentsRect, const QString& labelText)
00340 {
00341
00342 int original_font_size = m_font.pointSize();
00343
00344
00345 m_font.setPointSize(qMax(KGlobalSettings::smallestReadableFont().pointSize(), m_font.pointSize()));
00346 QFontMetrics fm(m_font);
00347 qreal text_width = fm.width(labelText);
00348
00349
00350 if (labelText.length() > 4) {
00351 if (original_font_size/1.5 < KGlobalSettings::smallestReadableFont().pointSize()) {
00352 m_font.setPointSize((KGlobalSettings::smallestReadableFont().pointSize()));
00353 } else {
00354 m_font.setPointSizeF(original_font_size/1.5);
00355 }
00356 fm = QFontMetrics(m_font);
00357 text_width = (fm.width(labelText) * 1.2);
00358 } else {
00359
00360 text_width = (text_width * 1.4);
00361 }
00362 if (formFactor() == Plasma::Horizontal ||
00363 formFactor() == Plasma::Vertical) {
00364 m_font = KGlobalSettings::smallestReadableFont();
00365 m_font.setWeight(QFont::Bold);
00366 fm = QFontMetrics(m_font);
00367 text_width = (fm.width(labelText)+8);
00368 }
00369 p->setFont(m_font);
00370
00371
00372 m_textRect = QRectF(qMax(qreal(0.0), contentsRect.left() + (contentsRect.width() - text_width) / 2),
00373 contentsRect.top() + ((contentsRect.height() - (int)fm.height()) / 2 * 0.9),
00374 qMin(contentsRect.width(), (int)text_width),
00375 fm.height() * 1.2 );
00376
00377
00378 m_boxColor.setAlphaF(m_alpha);
00379 p->setPen(m_boxColor);
00380 m_boxColor.setAlphaF(m_alpha*0.5);
00381 p->setBrush(m_boxColor);
00382
00383
00384 float round_prop = m_textRect.width() / m_textRect.height();
00385
00386
00387 qreal round_radius = 35.0;
00388 p->drawRoundedRect(m_textRect, round_radius / round_prop, round_radius, Qt::RelativeSize);
00389
00390 m_textColor.setAlphaF(m_alpha);
00391 p->setPen(m_textColor);
00392 p->drawText(m_textRect, Qt::AlignCenter, labelText);
00393
00394
00395 m_font.setPointSize(original_font_size);
00396 m_boxColor.setAlpha(m_boxAlpha);
00397 }
00398
00399 void Battery::paintBattery(QPainter *p, const QRect &contentsRect, const int batteryPercent, const bool plugState)
00400 {
00401 QString fill_element = QString();
00402 if (plugState && m_theme->hasElement("Battery")) {
00403 m_theme->paint(p, scaleRectF(m_batteryAlpha, contentsRect), "Battery");
00404
00405 if (m_batteryStyle == OxygenBattery) {
00406 if (batteryPercent > 95) {
00407 fill_element = "Fill100";
00408 } else if (batteryPercent > 80) {
00409 fill_element = "Fill80";
00410 } else if (batteryPercent > 50) {
00411 fill_element = "Fill60";
00412 } else if (batteryPercent > 20) {
00413 fill_element = "Fill40";
00414 } else if (batteryPercent > 10) {
00415 fill_element = "Fill20";
00416 }
00417 } else {
00418 if (batteryPercent > 95) {
00419 fill_element = "Fill100";
00420 } else if (batteryPercent > 90) {
00421 fill_element = "Fill90";
00422 } else if (batteryPercent > 80) {
00423 fill_element = "Fill80";
00424 } else if (batteryPercent > 70) {
00425 fill_element = "Fill70";
00426 } else if (batteryPercent > 55) {
00427 fill_element = "Fill60";
00428 } else if (batteryPercent > 40) {
00429 fill_element = "Fill50";
00430 } else if (batteryPercent > 30) {
00431 fill_element = "Fill40";
00432 } else if (batteryPercent > 20) {
00433 fill_element = "Fill30";
00434 } else if (batteryPercent > 10) {
00435 fill_element = "Fill20";
00436 } else if (batteryPercent >= 5) {
00437 fill_element = "Fill10";
00438 }
00439 }
00440 }
00441
00442
00443
00444 if (plugState && !fill_element.isEmpty()) {
00445 if (m_theme->hasElement(fill_element)) {
00446 m_theme->paint(p, scaleRectF(m_batteryAlpha, contentsRect), fill_element);
00447 } else {
00448 kDebug() << fill_element << " does not exist in svg";
00449 }
00450 }
00451
00452 if (m_acadapter_plugged) {
00453
00454 m_theme->paint(p, scaleRectF(m_acAlpha, contentsRect), "AcAdapter");
00455 }
00456
00457
00458 if (formFactor() == Plasma::Vertical ||
00459 formFactor() == Plasma::Horizontal) {
00460 if (plugState) {
00461 m_theme->paint(p, contentsRect, "Shadow");
00462 }
00463 }
00464 if (plugState && m_theme->hasElement("Overlay")) {
00465 m_theme->paint(p, scaleRectF(m_batteryAlpha, contentsRect), "Overlay");
00466 }
00467 }
00468
00469 void Battery::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
00470 {
00471 Q_UNUSED( option );
00472
00473 p->setRenderHint(QPainter::SmoothPixmapTransform);
00474 p->setRenderHint(QPainter::Antialiasing);
00475
00476 if (m_numOfBattery == 0) {
00477 QRectF ac_contentsRect(contentsRect.topLeft(), QSizeF(qMax(qreal(0.0), contentsRect.width() * m_acAlpha), qMax(qreal(0.0), contentsRect.height() * m_acAlpha)));
00478 if (m_acadapter_plugged) {
00479 m_theme->paint(p, ac_contentsRect, "AcAdapter");
00480 }
00481
00482 paintLabel(p, contentsRect, I18N_NOOP("n/a"));
00483 return;
00484 }
00485
00486 if (m_showMultipleBatteries) {
00487
00488 int battery_num = 0;
00489 int width = contentsRect.width()/m_numOfBattery;
00490 QHashIterator<QString, QHash<QString, QVariant > > battery_data(m_batteries_data);
00491 while (battery_data.hasNext()) {
00492 battery_data.next();
00493 QRect corect = QRect(contentsRect.left()+battery_num*width,
00494 contentsRect.top(),
00495 width, contentsRect.height());
00496
00497
00498 paintBattery(p, corect, battery_data.value()[I18N_NOOP("Percent")].toInt(), battery_data.value()[I18N_NOOP("Plugged in")].toBool());
00499
00500 if (m_showBatteryString || m_isHovered) {
00501
00502 QString batteryLabel;
00503 if (battery_data.value()[I18N_NOOP("Plugged in")].toBool()) {
00504 batteryLabel = battery_data.value()[I18N_NOOP("Percent")].toString();
00505 batteryLabel.append("%");
00506 } else {
00507 batteryLabel = I18N_NOOP("n/a");
00508 }
00509 paintLabel(p, corect, batteryLabel);
00510 }
00511 ++battery_num;
00512 }
00513 } else {
00514
00515 int battery_num = 0;
00516 int battery_charge = 0;
00517 bool has_battery = false;
00518 QHashIterator<QString, QHash<QString, QVariant > > battery_data(m_batteries_data);
00519 while (battery_data.hasNext()) {
00520 battery_data.next();
00521 if (battery_data.value()[I18N_NOOP("Plugged in")].toBool()) {
00522 battery_charge += battery_data.value()[I18N_NOOP("Percent")].toInt();
00523 has_battery = true;
00524 ++battery_num;
00525 }
00526 }
00527 if (battery_num > 0) {
00528 battery_charge = battery_charge / battery_num;
00529 }
00530
00531 paintBattery(p, contentsRect, battery_charge, has_battery);
00532 if (m_showBatteryString || m_isHovered) {
00533
00534 QString batteryLabel;
00535 if(has_battery) {
00536 batteryLabel = QString::number(battery_charge);
00537 batteryLabel.append("%");
00538 } else {
00539 batteryLabel = I18N_NOOP("n/a");
00540 }
00541 paintLabel(p, contentsRect, batteryLabel);
00542 }
00543 }
00544 }
00545
00546 void Battery::connectSources() {
00547 const QStringList& battery_sources = dataEngine("powermanagement")->query(I18N_NOOP("Battery"))[I18N_NOOP("sources")].toStringList();
00548
00549 foreach (const QString &battery_source, battery_sources) {
00550 dataEngine("powermanagement")->connectSource(battery_source, this);
00551 }
00552
00553 dataEngine("powermanagement")->connectSource(I18N_NOOP("AC Adapter"), this);
00554 }
00555
00556 void Battery::disconnectSources()
00557 {
00558 const QStringList& battery_sources = dataEngine("powermanagement")->query(I18N_NOOP("Battery"))[I18N_NOOP("sources")].toStringList();
00559
00560 foreach (const QString &battery_source ,battery_sources) {
00561 dataEngine("powermanagement")->disconnectSource(battery_source, this);
00562 }
00563
00564 dataEngine("powermanagement")->disconnectSource(I18N_NOOP("AC Adapter"), this);
00565 }
00566
00567 #include "battery.moc"