2 // C++ Implementation: cpowermanager
4 // Author: Oliver Groß <z.o.gross@gmx.de>, (C) 2008
6 // Copyright: See COPYING file that comes with this distribution
9 #include "powermanager.h"
12 #include "batteryicon.h"
13 #include "qtimermessagebox.h"
18 CPowerManager::CPowerManager(QObject
* parent
) :
20 m_CriticalHandled(false),
21 m_SysfsDir(UI_PATH_SYSFS_DIR
),
22 m_SettingsFile(UI_FILE_CONFIG
, QSettings::IniFormat
, this),
23 m_DefaultTrayIcon(QIcon(UI_ICON_QBAT
), this)
26 m_ContextMenu
.addAction(tr("&Settings"), this, SLOT(showSettings()))->setEnabled(m_SysfsDir
.exists());
27 m_ContextMenu
.addAction(tr("&About"), this, SLOT(showAbout()));
28 m_ContextMenu
.addSeparator();
29 m_ContextMenu
.addAction(tr("&Quit"), qApp
, SLOT(quit()));
31 m_DefaultTrayIcon
.setContextMenu(&m_ContextMenu
);
34 if (m_SysfsDir
.exists()) {
35 m_Timer
= startTimer(m_Settings
.pollingRate
);
39 CPowerManager::~CPowerManager() {
44 inline void CPowerManager::readSettings() {
45 m_SettingsFile
.beginGroup("Main");
46 m_Settings
.pollingRate
= m_SettingsFile
.value("pollingRate", 3000).toUInt();
47 m_Settings
.showBalloon
= m_SettingsFile
.value("showBalloon", false).toBool();
48 m_SettingsFile
.endGroup();
50 m_SettingsFile
.beginGroup("TrayIcons");
51 m_Settings
.mergeBatterys
= m_SettingsFile
.value("mergeBatterys", true).toBool();
52 m_Settings
.colors
[UI_COLOR_PEN
] = m_SettingsFile
.value("textColor", 0).toUInt();
53 m_Settings
.colors
[UI_COLOR_PEN_FULL
] = m_SettingsFile
.value("textFullColor", 0).toUInt();
54 m_Settings
.colors
[UI_COLOR_BRUSH_CHARGED
] = m_SettingsFile
.value("mainChargedColor", qRgb( 0, 255, 0)).toUInt();
55 m_Settings
.colors
[UI_COLOR_BRUSH_EMPTY
] = m_SettingsFile
.value("mainEmptyColor", qRgb(255, 255, 255)).toUInt();
56 m_Settings
.colors
[UI_COLOR_BRUSH_FULL
] = m_SettingsFile
.value("mainFullColor", m_Settings
.colors
[UI_COLOR_BRUSH_CHARGED
]).toUInt();
57 m_Settings
.colors
[UI_COLOR_BRUSH_POLE
] = m_SettingsFile
.value("poleColor", qRgb(255, 255, 0)).toUInt();
58 m_Settings
.colors
[UI_COLOR_BRUSH_POLE_FULL
] = m_SettingsFile
.value("poleFullColor", m_Settings
.colors
[UI_COLOR_BRUSH_POLE
]).toUInt();
59 m_SettingsFile
.endGroup();
61 m_SettingsFile
.beginGroup("CriticalEvent");
62 m_Settings
.handleCritical
= m_SettingsFile
.value("handle", false).toBool();
63 m_Settings
.criticalCapacity
= m_SettingsFile
.value("criticalCapacity", 7).toUInt();
64 m_Settings
.executeCommand
= m_SettingsFile
.value("executeCommand", false).toBool();
65 m_Settings
.criticalCommand
= m_SettingsFile
.value("command", "").toString();
66 m_Settings
.confirmCommand
= m_SettingsFile
.value("confirmCommand", false).toBool();
67 m_Settings
.confirmWithTimeout
= m_SettingsFile
.value("confirmWithTimeout", false).toBool();
68 m_Settings
.timeoutValue
= m_SettingsFile
.value("timeoutValue", 5).toUInt();
69 m_SettingsFile
.endGroup();
72 inline void CPowerManager::writeSettings() {
73 m_SettingsFile
.beginGroup("Main");
74 m_SettingsFile
.setValue("pollingRate", m_Settings
.pollingRate
);
75 m_SettingsFile
.setValue("showBalloon", m_Settings
.showBalloon
);
76 m_SettingsFile
.endGroup();
78 m_SettingsFile
.beginGroup("TrayIcons");
79 m_SettingsFile
.setValue("mergeBatterys", m_Settings
.mergeBatterys
);
80 m_SettingsFile
.setValue("textColor", m_Settings
.colors
[UI_COLOR_PEN
]);
81 m_SettingsFile
.setValue("textFullColor", m_Settings
.colors
[UI_COLOR_PEN_FULL
]);
82 m_SettingsFile
.setValue("mainChargedColor", m_Settings
.colors
[UI_COLOR_BRUSH_CHARGED
]);
83 m_SettingsFile
.setValue("mainEmptyColor", m_Settings
.colors
[UI_COLOR_BRUSH_EMPTY
]);
84 m_SettingsFile
.setValue("mainFullColor", m_Settings
.colors
[UI_COLOR_BRUSH_FULL
]);
85 m_SettingsFile
.setValue("poleColor", m_Settings
.colors
[UI_COLOR_BRUSH_POLE
]);
86 m_SettingsFile
.setValue("poleFullColor", m_Settings
.colors
[UI_COLOR_BRUSH_POLE_FULL
]);
87 m_SettingsFile
.endGroup();
89 m_SettingsFile
.beginGroup("CriticalEvent");
90 m_SettingsFile
.setValue("handle", m_Settings
.handleCritical
);
91 m_SettingsFile
.setValue("criticalCapacity", m_Settings
.criticalCapacity
);
92 m_SettingsFile
.setValue("executeCommand", m_Settings
.executeCommand
);
93 m_SettingsFile
.setValue("command", m_Settings
.criticalCommand
);
94 m_SettingsFile
.setValue("confirmCommand", m_Settings
.confirmCommand
);
95 m_SettingsFile
.setValue("confirmWithTimeout", m_Settings
.confirmWithTimeout
);
96 m_SettingsFile
.setValue("timeoutValue", m_Settings
.timeoutValue
);
97 m_SettingsFile
.endGroup();
100 void CPowerManager::timerEvent(QTimerEvent
*) {
104 void CPowerManager::updateData() {
105 if (m_SysfsDir
.exists()) {
107 QStringList powerSupplies
= m_SysfsDir
.entryList(QDir::Dirs
| QDir::NoDotAndDotDot
);
110 int chargeFullDesign
= 0;
115 bool energyUnits
= false;
117 int relativeCapacity
= 100;
119 if (m_Settings
.mergeBatterys
) {
120 int batteryCount
= 0;
121 foreach(QString i
, powerSupplies
) {
122 string buffer
= readStringSysFile(m_SysfsDir
.filePath(i
+ "/type").toAscii().constData());
124 if ((!acPlug
) && (buffer
== "Mains")) {
125 if (1 == readIntSysFile(m_SysfsDir
.filePath(i
+ "/online").toAscii().constData()))
128 else if (buffer
== "Battery") {
129 energyUnits
= m_SysfsDir
.exists(i
+ UI_CAPTION_NOW(UI_CAPTION_ENERGY
));
132 double voltage
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_NOW(UI_CAPTION_VOLTAGE
)).toAscii().constData()) / 1000000.0;
134 chargeFull
+= qRound(readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_FULL(UI_CAPTION_ENERGY
)).toAscii().constData()) / voltage
);
135 chargeFullDesign
+= qRound(readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_DESIGN(UI_CAPTION_ENERGY
)).toAscii().constData()) / voltage
);
136 chargeNow
+= qRound(readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_NOW(UI_CAPTION_ENERGY
)).toAscii().constData()) / voltage
);
137 currentNow
+= qRound(readIntSysFile(m_SysfsDir
.filePath(i
+ "/current_now").toAscii().constData()) / voltage
);
140 chargeFull
+= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_FULL(UI_CAPTION_CHARGE
)).toAscii().constData());
141 chargeFullDesign
+= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_DESIGN(UI_CAPTION_CHARGE
)).toAscii().constData());
142 chargeNow
+= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_NOW(UI_CAPTION_CHARGE
)).toAscii().constData());
143 currentNow
+= readIntSysFile(m_SysfsDir
.filePath(i
+ "/current_now").toAscii().constData());
146 int statusBuffer
= toStatusInt(readStringSysFile(m_SysfsDir
.filePath(i
+ "/status").toAscii().constData()));
148 if ((!status
) || (statusBuffer
!= UI_BATTERY_FULL
))
149 status
= statusBuffer
;
156 if (m_Settings
.handleCritical
)
157 relativeCapacity
= (int)(100.0 * chargeNow
/ chargeFull
);
159 chargeFull
/= batteryCount
;
160 chargeFullDesign
/= batteryCount
;
161 chargeNow
/= batteryCount
;
162 currentNow
/= batteryCount
;
164 if (!m_BatteryIcons
.contains("merged")) {
165 if (!m_BatteryIcons
.isEmpty()) {
166 foreach(CBatteryIcon
* i
, m_BatteryIcons
) {
170 m_BatteryIcons
.clear();
173 CBatteryIcon
* currentBatteryIcon
= new CBatteryIcon("average", &m_Settings
, &m_ContextMenu
, this);
174 currentBatteryIcon
->updateData(chargeFull
, chargeFullDesign
, chargeNow
, currentNow
, status
, false);
175 m_BatteryIcons
.insert("merged", currentBatteryIcon
);
178 m_BatteryIcons
["merged"]->updateData(chargeFull
, chargeFullDesign
, chargeNow
, currentNow
, status
, false);
181 delete m_BatteryIcons
.take("merged");
185 QList
<CBatteryIcon
*> newBatteryIcons
;
186 CBatteryIcon
* currentBatteryIcon
;
188 int chargeNowMid
= 0;
189 int chargeFullMid
= 0;
191 foreach(QString i
, powerSupplies
) {
192 string buffer
= readStringSysFile(m_SysfsDir
.filePath(i
+ "/type").toAscii().constData());
194 if (buffer
== "Mains") {
195 if (1 == readIntSysFile(m_SysfsDir
.filePath(i
+ "/online").toAscii().constData()))
198 else if (buffer
== "Battery") {
199 energyUnits
= m_SysfsDir
.exists(i
+ UI_CAPTION_NOW(UI_CAPTION_ENERGY
));
202 chargeFull
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_FULL(UI_CAPTION_ENERGY
)).toAscii().constData());
203 chargeFullDesign
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_DESIGN(UI_CAPTION_ENERGY
)).toAscii().constData());
204 chargeNow
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_NOW(UI_CAPTION_ENERGY
)).toAscii().constData());
207 chargeFull
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_FULL(UI_CAPTION_CHARGE
)).toAscii().constData());
208 chargeFullDesign
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_DESIGN(UI_CAPTION_CHARGE
)).toAscii().constData());
209 chargeNow
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_NOW(UI_CAPTION_CHARGE
)).toAscii().constData());
211 currentNow
= readIntSysFile(m_SysfsDir
.filePath(i
+ "/current_now").toAscii().constData());
212 status
= toStatusInt(readStringSysFile(m_SysfsDir
.filePath(i
+ "/status").toAscii().constData()));
214 chargeFullMid
+= chargeFull
;
215 chargeNowMid
+= chargeNow
;
217 if (!m_BatteryIcons
.contains(i
)) {
218 currentBatteryIcon
= new CBatteryIcon(i
, &m_Settings
, &m_ContextMenu
, this);
219 currentBatteryIcon
->updateData(chargeFull
, chargeFullDesign
, chargeNow
, currentNow
, status
, energyUnits
);
222 currentBatteryIcon
= m_BatteryIcons
.take(i
);
223 currentBatteryIcon
->updateData(chargeFull
, chargeFullDesign
, chargeNow
, currentNow
, status
, energyUnits
);
225 newBatteryIcons
<< currentBatteryIcon
;
229 foreach(CBatteryIcon
* i
, m_BatteryIcons
) {
233 m_BatteryIcons
.clear();
235 foreach(CBatteryIcon
* i
, newBatteryIcons
)
236 m_BatteryIcons
.insert(i
->batteryName(), i
);
238 if (!m_BatteryIcons
.isEmpty())
239 relativeCapacity
= (int)(100.0 * chargeNowMid
/ chargeFullMid
);
244 m_DefaultTrayIcon
.setToolTip("QBat - " + tr("AC adapter plugged in"));
246 if (m_Settings
.handleCritical
) {
247 if ((relativeCapacity
<= m_Settings
.criticalCapacity
) && (!m_CriticalHandled
)) {
248 QString msgTitle
= (m_Settings
.executeCommand
&& m_Settings
.confirmWithTimeout
) ?
249 tr("QBat - critical battery capacity (will automatically choose ok on timeout)"):
250 tr("QBat - critical battery capacity");
251 QString msgText
= (m_Settings
.executeCommand
&& m_Settings
.confirmCommand
) ?
252 tr("WARNING: The attached battery(s) reached the critical mark.\nClick cancel and please make sure to save and shut down soon or provide another source of power\nor:\nClick ok to execute:\n%1").arg(m_Settings
.criticalCommand
) :
253 tr("WARNING: The attached battery(s) reached the critical mark.\nPlease make sure to save and shut down soon or provide another source of power.");
254 if (m_Settings
.executeCommand
&& (!m_Settings
.confirmCommand
|| ((m_Settings
.confirmWithTimeout
) ? QTimerMessageBox::warning(NULL
, msgTitle
, msgText
, m_Settings
.timeoutValue
, QMessageBox::Ok
| QMessageBox::Cancel
) : QMessageBox::warning(NULL
, msgTitle
, msgText
, QMessageBox::Ok
| QMessageBox::Cancel
))))
255 QProcess::startDetached(m_Settings
.criticalCommand
);
257 if (m_Settings
.showBalloon
)
258 m_BatteryIcons
.begin().value()->showMessage(msgTitle
, msgText
, QSystemTrayIcon::Warning
, 7000);
260 QMessageBox::warning(NULL
, msgTitle
, msgText
);
262 m_CriticalHandled
= true;
265 m_CriticalHandled
= false;
267 m_DefaultTrayIcon
.setToolTip("QBat - " + tr("AC adapter unplugged"));
271 m_DefaultTrayIcon
.setToolTip("QBat - " + tr("no information available"));
273 m_DefaultTrayIcon
.setVisible(m_BatteryIcons
.isEmpty());
276 void CPowerManager::restartTimer() {
278 m_Timer
= startTimer(m_Settings
.pollingRate
);
281 void CPowerManager::showSettings() {
283 connect(&dialog
, SIGNAL(settingsChanged()), this, SLOT(updateData()));
284 connect(&dialog
, SIGNAL(settingsChanged()), this, SLOT(restartTimer()));
286 dialog
.execute(&m_Settings
);
289 void CPowerManager::showAbout() {
290 if (m_Settings
.showBalloon
) {
291 if (m_DefaultTrayIcon
.isVisible())
292 m_DefaultTrayIcon
.showMessage(tr("About QBat"), UI_NAME
+ "\nv" + QString(UI_VERSION
),
293 QSystemTrayIcon::Information
, 4000);
295 m_BatteryIcons
.begin().value()->showMessage(tr("About QBat"), UI_NAME
+ "\nv" + QString(UI_VERSION
),
296 QSystemTrayIcon::Information
, 4000);
299 QMessageBox aboutBox
;
301 aboutBox
.setWindowIcon(QIcon(UI_ICON_QBAT
));
302 aboutBox
.setIconPixmap(QPixmap(UI_ICON_QBAT
));
303 aboutBox
.setWindowTitle(tr("About QBat"));
304 aboutBox
.setText(UI_NAME
+ "\nv" + QString(UI_VERSION
));
305 aboutBox
.setStandardButtons(QMessageBox::Ok
);