2 // C++ Implementation: powermanager
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;
117 bool energyUnits
= false;
119 int relativeCapacity
= 100;
121 if (m_Settings
.mergeBatterys
) {
122 int batteryCount
= 0;
124 foreach(QString i
, powerSupplies
) {
125 string buffer
= readStringSysFile(m_SysfsDir
.filePath(i
+ "/type").toAscii().constData());
127 if ((!acPlug
) && (buffer
== "Mains")) {
128 if (1 == readIntSysFile(m_SysfsDir
.filePath(i
+ "/online").toAscii().constData()))
131 else if (buffer
== "Battery") {
132 energyUnits
= m_SysfsDir
.exists(i
+ UI_CAPTION_NOW(UI_CAPTION_ENERGY
));
134 voltageBuffer
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_NOW(UI_CAPTION_VOLTAGE
)).toAscii().constData()) / 10000;
136 double voltageNorm
= voltageBuffer
/ 100.0;
138 chargeFull
+= qRound(readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_FULL(UI_CAPTION_ENERGY
)).toAscii().constData()) / voltageNorm
);
139 chargeFullDesign
+= qRound(readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_DESIGN(UI_CAPTION_ENERGY
)).toAscii().constData()) / voltageNorm
);
140 chargeNow
+= qRound(readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_NOW(UI_CAPTION_ENERGY
)).toAscii().constData()) / voltageNorm
);
141 currentNow
+= qRound(readIntSysFile(m_SysfsDir
.filePath(i
+ "/current_now").toAscii().constData()) / voltageNorm
);
144 chargeFull
+= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_FULL(UI_CAPTION_CHARGE
)).toAscii().constData());
145 chargeFullDesign
+= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_DESIGN(UI_CAPTION_CHARGE
)).toAscii().constData());
146 chargeNow
+= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_NOW(UI_CAPTION_CHARGE
)).toAscii().constData());
147 currentNow
+= readIntSysFile(m_SysfsDir
.filePath(i
+ "/current_now").toAscii().constData());
149 voltage
+= voltageBuffer
;
151 int statusBuffer
= toStatusInt(readStringSysFile(m_SysfsDir
.filePath(i
+ "/status").toAscii().constData()));
153 if ((!status
) || (statusBuffer
!= UI_BATTERY_FULL
))
154 status
= statusBuffer
;
161 if (m_Settings
.handleCritical
)
162 relativeCapacity
= (int)(100.0 * chargeNow
/ chargeFull
);
164 chargeFull
/= batteryCount
;
165 chargeFullDesign
/= batteryCount
;
166 chargeNow
/= batteryCount
;
167 currentNow
/= batteryCount
;
168 voltage
/= batteryCount
;
170 if (!m_BatteryIcons
.contains("merged")) {
171 if (!m_BatteryIcons
.isEmpty()) {
172 foreach(CBatteryIcon
* i
, m_BatteryIcons
)
175 m_BatteryIcons
.clear();
178 CBatteryIcon
* currentBatteryIcon
= new CBatteryIcon("average", &m_Settings
, &m_ContextMenu
, this);
179 currentBatteryIcon
->updateData(chargeFull
, chargeFullDesign
, chargeNow
, currentNow
, voltage
, status
, false);
180 m_BatteryIcons
.insert("merged", currentBatteryIcon
);
183 m_BatteryIcons
["merged"]->updateData(chargeFull
, chargeFullDesign
, chargeNow
, currentNow
, voltage
, status
, false);
186 delete m_BatteryIcons
.take("merged");
190 QList
<CBatteryIcon
*> newBatteryIcons
;
191 CBatteryIcon
* currentBatteryIcon
;
193 int chargeNowMid
= 0;
194 int chargeFullMid
= 0;
196 foreach(QString i
, powerSupplies
) {
197 string buffer
= readStringSysFile(m_SysfsDir
.filePath(i
+ "/type").toAscii().constData());
199 if (buffer
== "Mains") {
200 if (1 == readIntSysFile(m_SysfsDir
.filePath(i
+ "/online").toAscii().constData()))
203 else if (buffer
== "Battery") {
204 energyUnits
= m_SysfsDir
.exists(i
+ UI_CAPTION_NOW(UI_CAPTION_ENERGY
));
207 chargeFull
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_FULL(UI_CAPTION_ENERGY
)).toAscii().constData());
208 chargeFullDesign
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_DESIGN(UI_CAPTION_ENERGY
)).toAscii().constData());
209 chargeNow
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_NOW(UI_CAPTION_ENERGY
)).toAscii().constData());
212 chargeFull
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_FULL(UI_CAPTION_CHARGE
)).toAscii().constData());
213 chargeFullDesign
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_DESIGN(UI_CAPTION_CHARGE
)).toAscii().constData());
214 chargeNow
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_NOW(UI_CAPTION_CHARGE
)).toAscii().constData());
216 currentNow
= readIntSysFile(m_SysfsDir
.filePath(i
+ "/current_now").toAscii().constData());
217 voltage
= readIntSysFile(m_SysfsDir
.filePath(i
+ UI_CAPTION_NOW(UI_CAPTION_VOLTAGE
)).toAscii().constData()) / 10000;
218 status
= toStatusInt(readStringSysFile(m_SysfsDir
.filePath(i
+ "/status").toAscii().constData()));
220 chargeFullMid
+= chargeFull
;
221 chargeNowMid
+= chargeNow
;
223 if (m_BatteryIcons
.contains(i
)) {
224 currentBatteryIcon
= m_BatteryIcons
.take(i
);
225 currentBatteryIcon
->updateData(chargeFull
, chargeFullDesign
, chargeNow
, currentNow
, voltage
, status
, energyUnits
);
228 currentBatteryIcon
= new CBatteryIcon(i
, &m_Settings
, &m_ContextMenu
, this);
229 currentBatteryIcon
->updateData(chargeFull
, chargeFullDesign
, chargeNow
, currentNow
, voltage
, status
, energyUnits
);
230 m_CriticalHandled
= false;
232 newBatteryIcons
<< currentBatteryIcon
;
236 foreach(CBatteryIcon
* i
, m_BatteryIcons
) {
240 m_BatteryIcons
.clear();
242 foreach(CBatteryIcon
* i
, newBatteryIcons
)
243 m_BatteryIcons
.insert(i
->batteryName(), i
);
245 if (!m_BatteryIcons
.isEmpty())
246 relativeCapacity
= (int)(100.0 * chargeNowMid
/ chargeFullMid
);
250 m_DefaultTrayIcon
.setToolTip("QBat - " + tr("AC adapter plugged in"));
251 m_CriticalHandled
= false;
254 if (m_Settings
.handleCritical
) {
255 if ((relativeCapacity
<= m_Settings
.criticalCapacity
) && (!m_CriticalHandled
)) {
256 QString msgTitle
= (m_Settings
.executeCommand
&& m_Settings
.confirmWithTimeout
) ?
257 tr("QBat - critical battery capacity (will automatically choose ok on timeout)"):
258 tr("QBat - critical battery capacity");
259 QString msgText
= (m_Settings
.executeCommand
&& m_Settings
.confirmCommand
) ?
260 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
) :
261 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.");
262 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
))))
263 QProcess::startDetached(m_Settings
.criticalCommand
);
265 if (m_Settings
.showBalloon
)
266 m_BatteryIcons
.begin().value()->showMessage(msgTitle
, msgText
, QSystemTrayIcon::Warning
, 7000);
268 QMessageBox::warning(NULL
, msgTitle
, msgText
);
270 m_CriticalHandled
= true;
273 m_CriticalHandled
= false;
275 m_DefaultTrayIcon
.setToolTip("QBat - " + tr("AC adapter unplugged"));
279 m_DefaultTrayIcon
.setToolTip("QBat - " + tr("no information available"));
281 m_DefaultTrayIcon
.setVisible(m_BatteryIcons
.isEmpty());
284 void CPowerManager::restartTimer() {
286 m_Timer
= startTimer(m_Settings
.pollingRate
);
289 void CPowerManager::showSettings() {
292 if (dialog
.execute(&m_Settings
)) {
293 foreach(CBatteryIcon
* i
, m_BatteryIcons
) {
297 m_BatteryIcons
.clear();
304 void CPowerManager::showAbout() {
305 if (m_Settings
.showBalloon
) {
306 if (m_DefaultTrayIcon
.isVisible())
307 m_DefaultTrayIcon
.showMessage(tr("About QBat"), UI_NAME
+ "\nv" + QString(UI_VERSION
),
308 QSystemTrayIcon::Information
, 4000);
310 m_BatteryIcons
.begin().value()->showMessage(tr("About QBat"), UI_NAME
+ "\nv" + QString(UI_VERSION
),
311 QSystemTrayIcon::Information
, 4000);
314 QMessageBox aboutBox
;
316 aboutBox
.setWindowIcon(QIcon(UI_ICON_QBAT
));
317 aboutBox
.setIconPixmap(QPixmap(UI_ICON_QBAT
));
318 aboutBox
.setWindowTitle(tr("About QBat"));
319 aboutBox
.setText(UI_NAME
+ "\nv" + QString(UI_VERSION
));
320 aboutBox
.setStandardButtons(QMessageBox::Ok
);