add more spacing
[personal-kdebase.git] / workspace / plasma / applets / battery / battery.cpp
blob8ac524ecd09a522916995905ebd99c86e0adeb5f
1 /***************************************************************************
2 * Copyright 2007-2008 by Riccardo Iaconelli <riccardo@kde.org> *
3 * Copyright 2007-2008 by Sebastian Kuegler <sebas@kde.org> *
4 * Copyright 2007 by Luka Renko <lure@kubuntu.org> *
5 * *
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. *
10 * *
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. *
15 * *
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 ***************************************************************************/
22 #include "battery.h"
24 #include <QApplication>
25 #include <QDBusConnection>
26 #include <QDBusInterface>
27 #include <QPainter>
28 #include <QStyleOptionGraphicsItem>
29 #include <QFont>
30 #include <QGraphicsSceneHoverEvent>
31 #include <QGraphicsGridLayout>
32 #include <QGraphicsLinearLayout>
34 #include <KDebug>
35 #include <KIcon>
36 #include <KLocalizedString>
37 #include <KSharedConfig>
38 #include <KToolInvocation>
39 #include <KDialog>
40 #include <KColorScheme>
41 #include <KConfigDialog>
42 #include <KGlobalSettings>
43 #include <KPushButton>
45 #include <kworkspace/kworkspace.h>
47 #include <solid/control/powermanager.h>
48 #include <solid/powermanagement.h>
50 #include <Plasma/Svg>
51 #include <Plasma/Theme>
52 #include <Plasma/Animator>
53 #include <Plasma/Extender>
54 #include <Plasma/ExtenderItem>
55 #include <Plasma/PopupApplet>
56 #include <Plasma/Label>
57 #include <Plasma/Slider>
58 #include <Plasma/PushButton>
59 #include <Plasma/CheckBox>
60 #include <Plasma/ComboBox>
61 #include <Plasma/IconWidget>
64 Battery::Battery(QObject *parent, const QVariantList &args)
65 : Plasma::PopupApplet(parent, args),
66 m_isEmbedded(false),
67 m_extenderVisible(false),
68 m_controlsLayout(0),
69 m_batteryLayout(0),
70 m_statusLabel(0),
71 m_batteryLabel(0),
72 m_profileLabel(0),
73 m_profileCombo(0),
74 m_brightnessSlider(0),
75 m_theme(0),
76 m_availableProfiles(QStringList()),
77 m_currentProfile(0),
78 m_animId(-1),
79 m_alpha(1),
80 m_fadeIn(false),
81 m_acAnimId(-1),
82 m_acAlpha(1),
83 m_acFadeIn(false),
84 m_batteryAnimId(-1),
85 m_batteryAlpha(1),
86 m_batteryFadeIn(true),
87 m_isHovered(false),
88 m_firstRun(true),
89 m_numOfBattery(0),
90 m_acadapter_plugged(false),
91 m_remainingMSecs(0)
93 kDebug() << "Loading applet battery";
94 setAcceptsHoverEvents(true);
95 setHasConfigurationInterface(true);
96 setPopupIcon(QIcon());
97 resize(128, 128);
98 setAspectRatioMode(Plasma::ConstrainedSquare );
99 m_textRect = QRectF();
100 m_remainingMSecs = 0;
101 m_extenderApplet = 0;
102 m_theme = new Plasma::Svg(this);
103 m_theme->setImagePath("widgets/battery-oxygen");
104 m_theme->setContainsMultipleImages(false);
107 void Battery::init()
109 KConfigGroup cg = config();
110 m_showBatteryString = cg.readEntry("showBatteryString", false);
111 m_showMultipleBatteries = cg.readEntry("showMultipleBatteries", !m_isEmbedded);
113 showBattery(false);
114 m_theme->resize(contentsRect().size());
115 if (m_acadapter_plugged) {
116 showAcAdapter(true);
118 showBattery(true);
120 m_theme->resize(contentsRect().size());
121 m_font = QApplication::font();
122 m_font.setWeight(QFont::Bold);
124 m_boxAlpha = 128;
125 m_boxHoverAlpha = 192;
127 readColors();
128 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(readColors()));
129 connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), SLOT(readColors()));
131 const QStringList& battery_sources = dataEngine("powermanagement")->query("Battery")["sources"].toStringList();
133 //connect sources
134 connectSources();
136 foreach (const QString &battery_source, battery_sources) {
137 //kDebug() << "BatterySource:" << battery_source;
138 dataUpdated(battery_source, dataEngine("powermanagement")->query(battery_source));
140 m_numOfBattery = battery_sources.size();
142 dataUpdated("AC Adapter", dataEngine("powermanagement")->query("AC Adapter"));
144 if (!m_isEmbedded) {
145 Plasma::ExtenderItem *eItem = new Plasma::ExtenderItem(extender());
146 eItem->setName("powermanagement");
147 initBatteryExtender(eItem);
148 extender()->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
152 void Battery::constraintsEvent(Plasma::Constraints constraints)
154 //kDebug() << "ConstraintsEvent, Dude." << contentsRect();
155 if (!m_showMultipleBatteries || m_numOfBattery < 2) {
156 setAspectRatioMode(Plasma::Square);
157 } else {
158 setAspectRatioMode(Plasma::KeepAspectRatio);
161 if (constraints & (Plasma::FormFactorConstraint | Plasma::SizeConstraint)) {
162 if (formFactor() == Plasma::Vertical) {
163 if (!m_showMultipleBatteries) {
164 setMinimumHeight(qMax(m_textRect.height(), size().width()));
165 } else {
166 setMinimumHeight(qMax(m_textRect.height(), size().width()*m_numOfBattery));
168 setMinimumWidth(0);
169 //kDebug() << "Vertical FormFactor";
170 } else if (formFactor() == Plasma::Horizontal) {
171 if (!m_showMultipleBatteries) {
172 setMinimumWidth(qMax(m_textRect.width(), size().height()));
173 } else {
174 setMinimumWidth(qMax(m_textRect.width(), size().height()*m_numOfBattery));
176 setMinimumHeight(0);
177 //kDebug() << "Horizontal FormFactor" << m_textRect.width() << contentsRect().height();
178 } else {
179 setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
180 setMinimumSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
183 m_theme->resize(contentsRect().size().toSize());
184 m_font.setPointSize(qMax(KGlobalSettings::smallestReadableFont().pointSize(),
185 qRound(contentsRect().height() / 10)));
186 update();
190 void Battery::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data)
192 if (source.startsWith("Battery")) {
193 m_batteries_data[source] = data;
194 } else if (source == "AC Adapter") {
195 m_acadapter_plugged = data["Plugged in"].toBool();
196 showAcAdapter(m_acadapter_plugged);
197 } else if (source == "PowerDevil") {
198 m_availableProfiles = data["availableProfiles"].toStringList();
199 m_currentProfile = data["currentProfile"].toString();
200 //kDebug() << "PowerDevil profiles:" << m_availableProfiles << "[" << m_currentProfile << "]";
201 } else {
202 kDebug() << "Applet::Dunno what to do with " << source;
204 if (source == "Battery0") {
205 m_remainingMSecs = data["Remaining msec"].toInt();
206 //kDebug() << "Remaining msecs on battery:" << m_remainingMSecs;
209 updateStatus();
210 update();
213 void Battery::createConfigurationInterface(KConfigDialog *parent)
215 QWidget *widget = new QWidget(parent);
216 ui.setupUi(widget);
217 parent->addPage(widget, i18n("General"), Applet::icon());
218 connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
219 connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
220 ui.showBatteryStringCheckBox->setChecked(m_showBatteryString ? Qt::Checked : Qt::Unchecked);
221 ui.showMultipleBatteriesCheckBox->setChecked(m_showMultipleBatteries ? Qt::Checked : Qt::Unchecked);
224 void Battery::configAccepted()
226 KConfigGroup cg = config();
228 if (m_showBatteryString != ui.showBatteryStringCheckBox->isChecked()) {
229 m_showBatteryString = !m_showBatteryString;
230 cg.writeEntry("showBatteryString", m_showBatteryString);
231 showLabel(m_showBatteryString);
234 if (m_showMultipleBatteries != ui.showMultipleBatteriesCheckBox->isChecked()) {
235 m_showMultipleBatteries = !m_showMultipleBatteries;
236 cg.writeEntry("showMultipleBatteries", m_showMultipleBatteries);
237 kDebug() << "Show multiple battery changed: " << m_showMultipleBatteries;
238 emit sizeHintChanged(Qt::PreferredSize);
241 //reconnect sources
242 disconnectSources();
243 connectSources();
245 emit configNeedsSaving();
248 void Battery::readColors()
250 m_textColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
251 m_boxColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor);
252 m_boxColor.setAlpha(m_boxAlpha);
255 void Battery::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
257 showLabel(true);
258 //showAcAdapter(false); // to test the animation without constant plugging
259 //showBattery(false); // to test the animation without constant plugging
260 m_isHovered = true;
261 Applet::hoverEnterEvent(event);
264 void Battery::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
266 if (!m_showBatteryString && !m_isEmbedded) {
267 showLabel(false);
269 //showAcAdapter(true); // to test the animation without constant plugging
270 //showBattery(true); // to test the animation without constant plugging
271 //m_isHovered = false;
272 Applet::hoverLeaveEvent(event);
275 Battery::~Battery()
279 void Battery::suspend()
281 QDBusConnection dbus( QDBusConnection::sessionBus() );
282 QDBusInterface iface( "org.kde.kded", "/modules/powerdevil", "org.kde.PowerDevil", dbus );
283 iface.call( "suspend", Solid::Control::PowerManager::ToRam );
286 void Battery::hibernate()
288 QDBusConnection dbus( QDBusConnection::sessionBus() );
289 QDBusInterface iface( "org.kde.kded", "/modules/powerdevil", "org.kde.PowerDevil", dbus );
290 iface.call( "suspend", Solid::Control::PowerManager::ToDisk );
293 void Battery::brightnessChanged(const int brightness)
295 Solid::Control::PowerManager::setBrightness(brightness);
298 void Battery::updateSlider(const float brightness)
300 if (m_brightnessSlider->value() != (int)brightness) {
301 m_brightnessSlider->setValue((int) brightness);
305 void Battery::setFullBrightness()
307 brightnessChanged(100);
308 updateSlider(100);
311 void Battery::setEmbedded(const bool embedded)
313 m_isEmbedded = embedded;
316 void Battery::initBatteryExtender(Plasma::ExtenderItem *item)
318 // We only show the extender for applets that are not embedded, as
319 // that would create infinitve loops, you really don't want an applet
320 // extender when the applet is embedded into another applet, such
321 // as the battery applet is also embedded into the battery's extender.
322 if (!m_isEmbedded) {
323 int row = 0;
324 int rowHeight = 20;
325 int columnWidth = 120;
327 QGraphicsWidget *controls = new QGraphicsWidget(item);
328 //controls->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
329 //controls->resize(500, 500);
330 m_controlsLayout = new QGraphicsGridLayout(controls);
331 m_controlsLayout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
333 m_controlsLayout->setColumnPreferredWidth(0, rowHeight);
334 m_controlsLayout->setColumnMinimumWidth(1, 2*columnWidth);
335 m_controlsLayout->setColumnPreferredWidth(2, rowHeight);
336 m_controlsLayout->setHorizontalSpacing(0);
338 m_batteryLayout = new QGraphicsGridLayout(m_controlsLayout);
340 //m_batteryLayout->setColumnPreferredWidth(0, 100);
341 m_batteryLayout->setColumnPreferredWidth(1, columnWidth);
342 //m_batteryLayout->setRowPreferredHeight(row, 60);
343 m_batteryLabel = new Plasma::Label(controls);
344 m_batteryLabel->setMinimumSize(200, 80);
345 m_batteryLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
347 //m_batteryLabel->nativeWidget()->setWordWrap(false);
348 m_batteryLabel->nativeWidget()->setAlignment(Qt::AlignTop);
349 // FIXME: larger fonts screw up this label
350 m_batteryLayout->addItem(m_batteryLabel, 0, 0, 1, 1, Qt::AlignLeft);
352 Battery *m_extenderApplet = static_cast<Battery*>(Plasma::Applet::load("battery"));
353 if (m_extenderApplet) {
354 m_extenderApplet->setParent(this);
355 m_extenderApplet->setAcceptsHoverEvents(false);
356 m_extenderApplet->setParentItem(controls);
357 m_extenderApplet->setEmbedded(true);
358 m_extenderApplet->setMinimumSize(80, 80); // TODO: Multiple batteries?
359 m_extenderApplet->resize(80, 80);
360 m_extenderApplet->setBackgroundHints(NoBackground);
361 m_extenderApplet->setFlag(QGraphicsItem::ItemIsMovable, false);
362 m_extenderApplet->init();
363 m_extenderApplet->showBatteryLabel(true);
364 m_batteryLayout->addItem(m_extenderApplet, 0, 1, 1, 1, Qt::AlignRight);
365 m_extenderApplet->updateConstraints(Plasma::StartupCompletedConstraint);
368 m_controlsLayout->addItem(m_batteryLayout, row, 0, 1, 3);
369 row++;
371 Plasma::Label *brightnessLabel = new Plasma::Label(controls);
372 brightnessLabel->setText(i18n("Screen Brightness"));
373 brightnessLabel->nativeWidget()->setWordWrap(false);
374 m_controlsLayout->addItem(brightnessLabel, row, 0, 1, 3);
375 brightnessLabel->nativeWidget()->setWordWrap(false);
376 row++;
378 m_brightnessSlider = new Plasma::Slider(controls);
379 m_brightnessSlider->setRange(0, 100);
380 m_brightnessSlider->setValue(Solid::Control::PowerManager::brightness());
381 m_brightnessSlider->nativeWidget()->setTickInterval(10);
382 m_brightnessSlider->setOrientation(Qt::Horizontal);
383 connect(m_brightnessSlider, SIGNAL(valueChanged(int)),
384 this, SLOT(brightnessChanged(int)));
386 Solid::Control::PowerManager::Notifier *notifier = Solid::Control::PowerManager::notifier();
388 connect(notifier, SIGNAL(brightnessChanged(float)),
389 this, SLOT(updateSlider(float)));
390 m_controlsLayout->addItem(m_brightnessSlider, row, 1, 1, 1);
392 Plasma::IconWidget *brightnessIcon = new Plasma::IconWidget(controls);
393 brightnessIcon->setIcon("ktip");
394 connect(brightnessIcon, SIGNAL(clicked()),
395 this, SLOT(setFullBrightness()));
396 brightnessIcon->setDrawBackground(true);
397 brightnessIcon->setMinimumSize(rowHeight, rowHeight);
398 m_controlsLayout->addItem(brightnessIcon, row, 2, 1, 1);
399 m_controlsLayout->setRowSpacing(row, 10);
400 row++;
402 m_profileLabel = new Plasma::Label(controls);
403 m_profileLabel->setText(i18n("Power Profile"));
404 m_controlsLayout->addItem(m_profileLabel, row, 0, 1, 3);
405 row++;
407 m_profileCombo = new Plasma::ComboBox(controls);
408 // This is necessary until Qt task #217874 is fixed
409 m_profileCombo->setZValue(100);
410 connect(m_profileCombo, SIGNAL(activated(QString)),
411 this, SLOT(setProfile(QString)));
413 m_controlsLayout->addItem(m_profileCombo, row, 1, 1, 2);
414 row++;
416 Plasma::Label *actionsLabel = new Plasma::Label(controls);
417 actionsLabel->setText(i18n("Actions"));
418 actionsLabel->nativeWidget()->setWordWrap(false);
419 m_controlsLayout->addItem(actionsLabel, row, 0, 1, 3);
420 row++;
422 QGraphicsGridLayout *actionsLayout = new QGraphicsGridLayout(m_controlsLayout);
423 actionsLayout->setColumnSpacing(0, 0);
424 actionsLayout->setColumnSpacing(1, 0);
426 // Sleep and Hibernate buttons
427 QSet<Solid::PowerManagement::SleepState> sleepstates = Solid::PowerManagement::supportedSleepStates();
428 foreach (const Solid::PowerManagement::SleepState &sleepstate, sleepstates) {
429 if (sleepstate == Solid::PowerManagement::StandbyState) {
430 // Not interesting at this point ...
432 } else if (sleepstate == Solid::PowerManagement::SuspendState) {
433 Plasma::IconWidget *suspendButton = new Plasma::IconWidget(controls);
434 suspendButton->setIcon("system-suspend");
435 suspendButton->setText(i18n("Sleep"));
436 suspendButton->setOrientation(Qt::Horizontal);
437 suspendButton->setMaximumHeight(36);
438 suspendButton->setDrawBackground(true);
439 actionsLayout->addItem(suspendButton, 0, 0);
440 connect(suspendButton, SIGNAL(clicked()), this, SLOT(suspend()));
441 actionsLayout->setColumnSpacing(0, 20);
442 } else if (sleepstate == Solid::PowerManagement::HibernateState) {
443 Plasma::IconWidget *hibernateButton = new Plasma::IconWidget(controls);
444 hibernateButton->setIcon("system-suspend-hibernate");
445 hibernateButton->setText(i18n("Hibernate"));
446 hibernateButton->setOrientation(Qt::Horizontal);
447 hibernateButton->setMaximumHeight(36);
448 hibernateButton->setDrawBackground(true);
449 actionsLayout->addItem(hibernateButton, 0, 1);
450 connect(hibernateButton, SIGNAL(clicked()), this, SLOT(hibernate()));
453 m_controlsLayout->addItem(actionsLayout, row, 1, 1, 2);
454 m_controlsLayout->setRowSpacing(row, 10);
455 row++;
457 // More settings button
458 Plasma::IconWidget *configButton = new Plasma::IconWidget(controls);
459 configButton->setText(i18n("More..."));
460 configButton->setOrientation(Qt::Horizontal);
461 configButton->setMaximumHeight(36);
462 configButton->setDrawBackground(true);
463 configButton->setIcon("preferences-system-power-management");
464 //configButton->nativeWidget()->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
465 connect(configButton, SIGNAL(clicked()), this, SLOT(openConfig()));
467 //QGraphicsGridLayout *moreLayout = new QGraphicsGridLayout(m_controlsLayout);
468 //moreLayout->setColumnPreferredWidth(0, columnWidth);
469 actionsLayout->addItem(configButton, 1, 1, Qt::AlignLeft);
471 //m_controlsLayout->addItem(moreLayout, row, 1, 1, 2);
473 controls->setLayout(m_controlsLayout);
474 item->setWidget(controls);
475 item->setTitle(i18n("Power Management"));
479 void Battery::popupEvent(bool show)
481 m_extenderVisible = show;
482 updateStatus();
485 void Battery::updateStatus()
487 if (!m_extenderVisible) {
488 return;
491 QString batteryLabelText = QString("<br />");
492 if (m_numOfBattery && m_batteryLabel) {
493 QHashIterator<QString, QHash<QString, QVariant > > battery_data(m_batteries_data);
494 int bnum = 0;
495 int hours = m_remainingMSecs/1000/3600;
496 int minutes = qRound(m_remainingMSecs/60000) % 60;
498 while (battery_data.hasNext()) {
499 bnum++;
500 battery_data.next();
501 QString state = battery_data.value()["State"].toString();
502 if (state == "Discharging" && m_remainingMSecs > 0) {
504 // FIXME: Somehow, m_extenderApplet is null here, so the label never becomes visible
505 if (m_extenderApplet) {
506 m_extenderApplet->showBatteryLabel(true);
509 // we don't have too much accuracy so only give hours and minutes
510 int msecs = hours * 1000 * 3600 + minutes * 60000;
511 batteryLabelText.append(i18n("Time remaining: <b>%1</b><br />", KGlobal::locale()->prettyFormatDuration(msecs)));
512 kDebug() << "hours:" << hours << "minutes:" << minutes;
513 /* might be useful for the tooltip
514 kDebug() << "hours:" << hours << "minutes:" << minutes;
515 QTime t = QTime(hours, minutes);
516 kDebug() << t;
517 KLocale tmpLocale(*KGlobal::locale());
518 tmpLocale.setTimeFormat("%k:h %Mm remaining");
519 kDebug() << tmpLocale.formatTime(t, false, true); // minutes, hours as duration
521 } else {
522 if (m_extenderApplet) {
523 m_extenderApplet->showBatteryLabel(false);
525 if (m_numOfBattery == 0) {
526 //kDebug() << "zero batteries ...";
527 } else if (m_numOfBattery == 1) {
528 if (battery_data.value()["Plugged in"].toBool()) {
529 if (state == "NoCharge") {
530 batteryLabelText.append(i18n("<b>Battery:</b> %1% (fully charged)<br />", battery_data.value()["Percent"].toString()));
531 } else if (state == "Discharging") {
532 batteryLabelText.append(i18nc("Shown when a time estimate is not available", "<b>Battery:</b> %1% (discharging)<br />", battery_data.value()["Percent"].toString()));
533 } else {
534 batteryLabelText.append(i18n("<b>Battery:</b> %1% (charging)<br />", battery_data.value()["Percent"].toString()));
536 } else {
537 batteryLabelText.append(i18nc("Battery is not plugged in", "<b>Battery:</b> not present<br />"));
539 } else {
540 //kDebug() << "More batteries ...";
541 if (state == "NoCharge") {
542 batteryLabelText.append(i18n("<b>Battery %1:</b> %2% (fully charged)<br />", bnum, battery_data.value()["Percent"].toString()));
543 } else if (state == "Discharging") {
544 batteryLabelText.append(i18n("<b>Battery %1:</b> %2% (discharging)<br />", bnum, battery_data.value()["Percent"].toString()));
545 } else {
546 batteryLabelText.append(i18n("<b>Battery %1:</b> %2% (charging)<br />", bnum, battery_data.value()["Percent"].toString()));
552 if (m_acadapter_plugged) {
553 batteryLabelText.append(i18n("<b>AC Adapter:</b> Plugged in"));
554 } else {
555 batteryLabelText.append(i18n("<b>AC Adapter:</b> Not plugged in"));
557 } else {
558 batteryLabelText.append(i18nc("Battery is not plugged in", "<b>Battery:</b> not present<br />"));
560 //kDebug() << batteryLabelText;
561 if (m_batteryLabel) {
562 m_batteryLabel->setText(batteryLabelText);
564 if (!m_availableProfiles.empty() && m_profileCombo) {
565 m_profileCombo->clear();
566 m_profileCombo->addItem(m_currentProfile);
567 foreach (const QString &p, m_availableProfiles) {
568 if (m_currentProfile != p) {
569 m_profileCombo->addItem(p);
574 if (m_profileLabel && m_profileCombo) {
575 if (m_availableProfiles.empty()) {
576 m_profileCombo->hide();
577 m_profileLabel->hide();
578 } else {
579 m_profileCombo->show();
580 m_profileLabel->show();
584 if (m_brightnessSlider) {
585 m_brightnessSlider->setValue(Solid::Control::PowerManager::brightness());
586 kDebug() << "Updating brightness:" << Solid::Control::PowerManager::brightness();
588 //kDebug() << "SIZE LABEL" << m_batteryLabel->size() << m_batteryLabel->preferredSize() << m_batteryLabel->preferredSize();
589 m_controlsLayout->setColumnMinimumWidth(1,280);
590 m_batteryLayout->setColumnMinimumWidth(0,200);
591 m_batteryLayout->invalidate();
592 m_controlsLayout->invalidate();
595 void Battery::openConfig()
597 kDebug() << "opening powermanagement configuration dialog";
598 QStringList args;
599 args << "powerdevilconfig";
600 KToolInvocation::kdeinitExec("kcmshell4", args);
603 void Battery::setProfile(const QString &profile)
605 if (m_currentProfile != profile) {
606 kDebug() << "Changing power profile to " << profile;
607 QDBusConnection dbus( QDBusConnection::sessionBus() );
608 QDBusInterface iface( "org.kde.kded", "/modules/powerdevil", "org.kde.PowerDevil", dbus );
609 iface.call( "refreshStatus" );
610 iface.call( "setProfile", profile );
614 void Battery::showLabel(bool show)
616 if (m_fadeIn == show) {
617 return;
619 m_fadeIn = show;
620 const int FadeInDuration = 150;
622 if (m_animId != -1) {
623 Plasma::Animator::self()->stopCustomAnimation(m_animId);
625 m_animId = Plasma::Animator::self()->customAnimation(40 / (1000 / FadeInDuration), FadeInDuration,
626 Plasma::Animator::EaseOutCurve, this,
627 "animationUpdate");
630 QRectF Battery::scaleRectF(const qreal progress, QRectF rect)
632 if (progress == 1) {
633 return rect;
635 // Scale
636 qreal w = rect.width()*progress;
637 qreal h = rect.width()*progress;
639 // Position centered
640 rect.setX((rect.width() - w)/2);
641 rect.setY((rect.height() - h)/2);
643 rect.setWidth(w);
644 rect.setHeight(h);
646 return rect;
649 void Battery::showAcAdapter(bool show)
651 if (m_acFadeIn == show) {
652 return;
654 m_acFadeIn = show;
655 const int FadeInDuration = 600;
656 // As long as the animation is running, we fake it's still plugged in so it gets
657 // painted in paintInterface()
658 m_acadapter_plugged = true;
660 if (m_acAnimId != -1) {
661 Plasma::Animator::self()->stopCustomAnimation(m_acAnimId);
663 m_acAnimId = Plasma::Animator::self()->customAnimation(40 / (1000 / FadeInDuration), FadeInDuration,
664 Plasma::Animator::EaseOutCurve, this,
665 "acAnimationUpdate");
668 void Battery::showBattery(bool show)
670 if (m_batteryFadeIn == show) {
671 return;
673 m_batteryFadeIn = show;
674 const int FadeInDuration = 300;
676 if (m_batteryAnimId != -1) {
677 Plasma::Animator::self()->stopCustomAnimation(m_batteryAnimId);
679 m_batteryAnimId = Plasma::Animator::self()->customAnimation(40 / (1000 / FadeInDuration), FadeInDuration,
680 Plasma::Animator::EaseOutCurve, this,
681 "batteryAnimationUpdate");
684 void Battery::animationUpdate(qreal progress)
686 if (progress == 1) {
687 m_animId = -1;
689 if (!m_fadeIn) {
690 qreal new_alpha = m_fadeIn ? progress : 1 - progress;
691 m_alpha = qMin(new_alpha, m_alpha);
692 } else {
693 m_alpha = m_fadeIn ? progress : 1 - progress;
695 m_alpha = qMax(qreal(0.0), m_alpha);
696 update();
699 void Battery::acAnimationUpdate(qreal progress)
701 if (progress == 1) {
702 m_acAnimId = -1;
704 m_acAlpha = m_acFadeIn ? progress : 1 - progress;
705 // During the fadeout animation, we had set it to true (and lie)
706 // now the animation has ended, we _really_ set it to not show the adapter
707 if (!m_acFadeIn && (progress == 1)) {
708 m_acadapter_plugged = false;
709 updateStatus();
711 update();
714 void Battery::batteryAnimationUpdate(qreal progress)
716 if (progress == 1) {
717 m_batteryAnimId = -1;
719 m_batteryAlpha = m_batteryFadeIn ? progress : 1 - progress;
720 update();
723 void Battery::paintLabel(QPainter *p, const QRect &contentsRect, const QString& labelText)
725 // Store font size, we want to restore it shortly
726 int original_font_size = m_font.pointSize();
728 // Fonts smaller than smallestReadableFont don't make sense.
729 m_font.setPointSize(qMax(KGlobalSettings::smallestReadableFont().pointSize(), m_font.pointSize()));
730 QFontMetrics fm(m_font);
731 qreal text_width = fm.width(labelText);
733 // Longer texts get smaller fonts
734 if (labelText.length() > 4) {
735 if (original_font_size/1.5 < KGlobalSettings::smallestReadableFont().pointSize()) {
736 m_font.setPointSize((KGlobalSettings::smallestReadableFont().pointSize()));
737 } else {
738 m_font.setPointSizeF(original_font_size/1.5);
740 fm = QFontMetrics(m_font);
741 text_width = (fm.width(labelText) * 1.2);
742 } else {
743 // Smaller texts get a wider box
744 text_width = (text_width * 1.4);
746 if (formFactor() == Plasma::Horizontal ||
747 formFactor() == Plasma::Vertical) {
748 m_font = KGlobalSettings::smallestReadableFont();
749 m_font.setWeight(QFont::Bold);
750 fm = QFontMetrics(m_font);
751 text_width = (fm.width(labelText)+8);
753 p->setFont(m_font);
755 // Let's find a good position for painting the percentage on top of the battery
756 m_textRect = QRectF(qMax(qreal(0.0), contentsRect.left() + (contentsRect.width() - text_width) / 2),
757 contentsRect.top() + ((contentsRect.height() - (int)fm.height()) / 2 * 0.9),
758 qMin(contentsRect.width(), (int)text_width),
759 fm.height() * 1.2 );
760 //kDebug() << contentsRect << m_textRect;
761 //p->setBrush(QColor("green"));
762 //p->drawRect(m_textRect);
764 if (m_firstRun) {
765 m_firstRun = false;
766 return;
768 // Poor man's highlighting
769 m_boxColor.setAlphaF(m_alpha);
770 p->setPen(m_boxColor);
771 m_boxColor.setAlphaF(m_alpha*0.5);
772 p->setBrush(m_boxColor);
774 // Find sensible proportions for the rounded corners
775 float round_prop = m_textRect.width() / m_textRect.height();
777 // Tweak the rounding edge a bit with the proportions of the textbox
778 qreal round_radius = 35.0;
779 p->drawRoundedRect(m_textRect, round_radius / round_prop, round_radius, Qt::RelativeSize);
781 m_textColor.setAlphaF(m_alpha);
782 p->setPen(m_textColor);
783 p->drawText(m_textRect, Qt::AlignCenter, labelText);
785 // Reset font and box
786 m_font.setPointSize(original_font_size);
787 m_boxColor.setAlpha(m_boxAlpha);
790 void Battery::paintBattery(QPainter *p, const QRect &contentsRect, const int batteryPercent, const bool plugState)
792 if (m_theme->hasElement("Battery")) {
793 m_theme->paint(p, scaleRectF(m_batteryAlpha, contentsRect), "Battery");
796 QString fill_element = QString();
797 if (plugState) {
798 if (batteryPercent > 95) {
799 fill_element = "Fill100";
800 } else if (batteryPercent > 80) {
801 fill_element = "Fill80";
802 } else if (batteryPercent > 50) {
803 fill_element = "Fill60";
804 } else if (batteryPercent > 20) {
805 fill_element = "Fill40";
806 } else if (batteryPercent > 10) {
807 fill_element = "Fill20";
808 } // Don't show a fillbar below 11% charged
809 } else {
810 fill_element = "Unavailable";
812 //kDebug() << "plugState:" << plugState;
814 // Now let's find out which fillstate to show
815 if (!fill_element.isEmpty()) {
816 if (m_theme->hasElement(fill_element)) {
817 m_theme->paint(p, scaleRectF(m_batteryAlpha, contentsRect), fill_element);
818 } else {
819 kDebug() << fill_element << " does not exist in svg";
823 if (m_acadapter_plugged) {
824 //QRectF ac_rect = QRectF(contentsRect.topLeft(), QSizeF(contentsRect.width()*m_acAlpha, contentsRect.height()*m_acAlpha));
825 m_theme->paint(p, scaleRectF(m_acAlpha, contentsRect), "AcAdapter");
828 // For small FormFactors, we're drawing a shadow
829 if (formFactor() == Plasma::Vertical ||
830 formFactor() == Plasma::Horizontal) {
831 if (plugState) {
832 m_theme->paint(p, contentsRect, "Shadow");
835 if (plugState && m_theme->hasElement("Overlay")) {
836 m_theme->paint(p, scaleRectF(m_batteryAlpha, contentsRect), "Overlay");
840 void Battery::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
842 Q_UNUSED( option );
844 p->setRenderHint(QPainter::SmoothPixmapTransform);
845 p->setRenderHint(QPainter::Antialiasing);
847 if (m_numOfBattery == 0) {
848 QRectF ac_contentsRect(contentsRect.topLeft(), QSizeF(qMax(qreal(0.0), contentsRect.width() * m_acAlpha), qMax(qreal(0.0), contentsRect.height() * m_acAlpha)));
849 if (m_acadapter_plugged) {
850 m_theme->paint(p, ac_contentsRect, "AcAdapter");
852 paintBattery(p, contentsRect, 0, false);
853 return;
856 if (m_isEmbedded || m_showMultipleBatteries || m_firstRun) {
857 // paint each battery with own charge level
858 int battery_num = 0;
859 int width = contentsRect.width()/m_numOfBattery;
860 QHashIterator<QString, QHash<QString, QVariant > > battery_data(m_batteries_data);
861 while (battery_data.hasNext()) {
862 battery_data.next();
863 QRect corect = QRect(contentsRect.left()+battery_num*width,
864 contentsRect.top(),
865 width, contentsRect.height());
867 // paint battery with appropriate charge level
868 paintBattery(p, corect, battery_data.value()["Percent"].toInt(), battery_data.value()["Plugged in"].toBool());
870 if (m_showBatteryString || m_isHovered || m_firstRun) {
871 // Show the charge percentage with a box on top of the battery
872 QString batteryLabel;
873 if (battery_data.value()["Plugged in"].toBool()) {
874 batteryLabel = battery_data.value()["Percent"].toString();
875 batteryLabel.append("%");
876 paintLabel(p, corect, batteryLabel);
879 ++battery_num;
881 } else {
882 // paint only one battery and show cumulative charge level
883 int battery_num = 0;
884 int battery_charge = 0;
885 bool has_battery = false;
886 QHashIterator<QString, QHash<QString, QVariant > > battery_data(m_batteries_data);
887 while (battery_data.hasNext()) {
888 battery_data.next();
889 if (battery_data.value()["Plugged in"].toBool()) {
890 battery_charge += battery_data.value()["Percent"].toInt();
891 has_battery = true;
892 ++battery_num;
895 if (battery_num > 0) {
896 battery_charge = battery_charge / battery_num;
898 // paint battery with appropriate charge level
899 paintBattery(p, contentsRect, battery_charge, has_battery);
900 if (m_showBatteryString || m_isHovered) {
901 // Show the charge percentage with a box on top of the battery
902 QString batteryLabel;
903 if (has_battery) {
904 batteryLabel = QString::number(battery_charge);
905 batteryLabel.append("%");
906 paintLabel(p, contentsRect, batteryLabel);
912 void Battery::showBatteryLabel(bool show)
914 kDebug() << show;
915 if (show != m_showBatteryString) {
916 showLabel(show);
917 m_showBatteryString = show;
921 void Battery::connectSources()
923 const QStringList& battery_sources = dataEngine("powermanagement")->query("Battery")["sources"].toStringList();
925 foreach (const QString &battery_source, battery_sources) {
926 dataEngine("powermanagement")->connectSource(battery_source, this);
929 dataEngine("powermanagement")->connectSource("AC Adapter", this);
930 dataEngine("powermanagement")->connectSource("PowerDevil", this);
932 connect(dataEngine("powermanagement"), SIGNAL(sourceAdded(QString)),
933 this, SLOT(sourceAdded(QString)));
934 connect(dataEngine("powermanagement"), SIGNAL(sourceRemoved(QString)),
935 this, SLOT(sourceRemoved(QString)));
938 void Battery::disconnectSources()
940 const QStringList& battery_sources = dataEngine("powermanagement")->query("Battery")["sources"].toStringList();
942 foreach (const QString &battery_source ,battery_sources) {
943 dataEngine("powermanagement")->disconnectSource(battery_source, this);
946 dataEngine("powermanagement")->disconnectSource("AC Adapter", this);
947 dataEngine("powermanagement")->disconnectSource("PowerDevil", this);
949 disconnect(SLOT(sourceAdded(QString)));
950 disconnect(SLOT(sourceRemoved(QString)));
953 void Battery::sourceAdded(const QString& source)
955 if (source.startsWith("Battery") && source != "Battery") {
956 dataEngine("powermanagement")->connectSource(source, this);
957 m_numOfBattery++;
958 constraintsEvent(Plasma::SizeConstraint);
959 update();
961 if (source == "PowerDevil") {
962 dataEngine("powermanagement")->connectSource(source, this);
966 void Battery::sourceRemoved(const QString& source)
968 if (m_batteries_data.remove(source)) {
969 m_numOfBattery--;
970 constraintsEvent(Plasma::SizeConstraint);
971 update();
973 if (source == "PowerDevil") {
974 dataEngine("powermanagement")->disconnectSource(source, this);
978 #include "battery.moc"