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> *
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. *
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. *
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 ***************************************************************************/
24 #include <QApplication>
25 #include <QDBusConnection>
26 #include <QDBusInterface>
28 #include <QStyleOptionGraphicsItem>
30 #include <QGraphicsSceneHoverEvent>
31 #include <QGraphicsGridLayout>
32 #include <QGraphicsLinearLayout>
36 #include <KLocalizedString>
37 #include <KSharedConfig>
38 #include <KToolInvocation>
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>
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
),
67 m_extenderVisible(false),
74 m_brightnessSlider(0),
76 m_availableProfiles(QStringList()),
86 m_batteryFadeIn(true),
90 m_acadapter_plugged(false),
93 kDebug() << "Loading applet battery";
94 setAcceptsHoverEvents(true);
95 setHasConfigurationInterface(true);
96 setPopupIcon(QIcon());
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);
109 KConfigGroup cg
= config();
110 m_showBatteryString
= cg
.readEntry("showBatteryString", false);
111 m_showMultipleBatteries
= cg
.readEntry("showMultipleBatteries", !m_isEmbedded
);
114 m_theme
->resize(contentsRect().size());
115 if (m_acadapter_plugged
) {
120 m_theme
->resize(contentsRect().size());
121 m_font
= QApplication::font();
122 m_font
.setWeight(QFont::Bold
);
125 m_boxHoverAlpha
= 192;
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();
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"));
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
);
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()));
166 setMinimumHeight(qMax(m_textRect
.height(), size().width()*m_numOfBattery
));
169 //kDebug() << "Vertical FormFactor";
170 } else if (formFactor() == Plasma::Horizontal
) {
171 if (!m_showMultipleBatteries
) {
172 setMinimumWidth(qMax(m_textRect
.width(), size().height()));
174 setMinimumWidth(qMax(m_textRect
.width(), size().height()*m_numOfBattery
));
177 //kDebug() << "Horizontal FormFactor" << m_textRect.width() << contentsRect().height();
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)));
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 << "]";
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;
213 void Battery::createConfigurationInterface(KConfigDialog
*parent
)
215 QWidget
*widget
= new QWidget(parent
);
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
);
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
)
258 //showAcAdapter(false); // to test the animation without constant plugging
259 //showBattery(false); // to test the animation without constant plugging
261 Applet::hoverEnterEvent(event
);
264 void Battery::hoverLeaveEvent(QGraphicsSceneHoverEvent
*event
)
266 if (!m_showBatteryString
&& !m_isEmbedded
) {
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
);
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);
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.
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);
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);
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);
402 m_profileLabel
= new Plasma::Label(controls
);
403 m_profileLabel
->setText(i18n("Power Profile"));
404 m_controlsLayout
->addItem(m_profileLabel
, row
, 0, 1, 3);
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);
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);
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);
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
;
485 void Battery::updateStatus()
487 if (!m_extenderVisible
) {
491 QString batteryLabelText
= QString("<br />");
492 if (m_numOfBattery
&& m_batteryLabel
) {
493 QHashIterator
<QString
, QHash
<QString
, QVariant
> > battery_data(m_batteries_data
);
495 int hours
= m_remainingMSecs
/1000/3600;
496 int minutes
= qRound(m_remainingMSecs
/60000) % 60;
498 while (battery_data
.hasNext()) {
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);
517 KLocale tmpLocale(*KGlobal::locale());
518 tmpLocale.setTimeFormat("%k:h %Mm remaining");
519 kDebug() << tmpLocale.formatTime(t, false, true); // minutes, hours as duration
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()));
534 batteryLabelText
.append(i18n("<b>Battery:</b> %1% (charging)<br />", battery_data
.value()["Percent"].toString()));
537 batteryLabelText
.append(i18nc("Battery is not plugged in", "<b>Battery:</b> not present<br />"));
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()));
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"));
555 batteryLabelText
.append(i18n("<b>AC Adapter:</b> Not plugged in"));
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();
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";
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
) {
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,
630 QRectF
Battery::scaleRectF(const qreal progress
, QRectF rect
)
636 qreal w
= rect
.width()*progress
;
637 qreal h
= rect
.width()*progress
;
640 rect
.setX((rect
.width() - w
)/2);
641 rect
.setY((rect
.height() - h
)/2);
649 void Battery::showAcAdapter(bool show
)
651 if (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
) {
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
)
690 qreal new_alpha
= m_fadeIn
? progress
: 1 - progress
;
691 m_alpha
= qMin(new_alpha
, m_alpha
);
693 m_alpha
= m_fadeIn
? progress
: 1 - progress
;
695 m_alpha
= qMax(qreal(0.0), m_alpha
);
699 void Battery::acAnimationUpdate(qreal progress
)
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;
714 void Battery::batteryAnimationUpdate(qreal progress
)
717 m_batteryAnimId
= -1;
719 m_batteryAlpha
= m_batteryFadeIn
? progress
: 1 - progress
;
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()));
738 m_font
.setPointSizeF(original_font_size
/1.5);
740 fm
= QFontMetrics(m_font
);
741 text_width
= (fm
.width(labelText
) * 1.2);
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);
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
),
760 //kDebug() << contentsRect << m_textRect;
761 //p->setBrush(QColor("green"));
762 //p->drawRect(m_textRect);
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();
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
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
);
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
) {
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
)
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);
856 if (m_isEmbedded
|| m_showMultipleBatteries
|| m_firstRun
) {
857 // paint each battery with own charge level
859 int width
= contentsRect
.width()/m_numOfBattery
;
860 QHashIterator
<QString
, QHash
<QString
, QVariant
> > battery_data(m_batteries_data
);
861 while (battery_data
.hasNext()) {
863 QRect corect
= QRect(contentsRect
.left()+battery_num
*width
,
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
);
882 // paint only one battery and show cumulative charge level
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()) {
889 if (battery_data
.value()["Plugged in"].toBool()) {
890 battery_charge
+= battery_data
.value()["Percent"].toInt();
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
;
904 batteryLabel
= QString::number(battery_charge
);
905 batteryLabel
.append("%");
906 paintLabel(p
, contentsRect
, batteryLabel
);
912 void Battery::showBatteryLabel(bool show
)
915 if (show
!= m_showBatteryString
) {
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);
958 constraintsEvent(Plasma::SizeConstraint
);
961 if (source
== "PowerDevil") {
962 dataEngine("powermanagement")->connectSource(source
, this);
966 void Battery::sourceRemoved(const QString
& source
)
968 if (m_batteries_data
.remove(source
)) {
970 constraintsEvent(Plasma::SizeConstraint
);
973 if (source
== "PowerDevil") {
974 dataEngine("powermanagement")->disconnectSource(source
, this);
978 #include "battery.moc"