1/*
2 * Copyright 2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Clemens Zeidler, haiku@Clemens-Zeidler.de
7 */
8
9
10#include "ExtendedInfoWindow.h"
11
12#include <Box.h>
13#include <Catalog.h>
14#include <GroupView.h>
15#include <SpaceLayoutItem.h>
16
17
18#undef B_TRANSLATION_CONTEXT
19#define B_TRANSLATION_CONTEXT "PowerStatus"
20
21
22const int kLineSpacing = 5;
23
24
25FontString::FontString()
26{
27	font = be_plain_font;
28}
29
30
31//	#pragma mark -
32
33
34BatteryInfoView::BatteryInfoView()
35	:
36	BView("battery info view", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
37	fPreferredSize(200, 200),
38	fMaxStringSize(0, 0)
39{
40	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
41}
42
43
44BatteryInfoView::~BatteryInfoView()
45{
46	_ClearStringList();
47}
48
49
50void
51BatteryInfoView::Update(battery_info& info, acpi_extended_battery_info& extInfo)
52{
53	fBatteryInfo = info;
54	fBatteryExtendedInfo = extInfo;
55
56	_FillStringList();
57}
58
59
60void
61BatteryInfoView::Draw(BRect updateRect)
62{
63	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
64
65	BPoint point(10, 10);
66
67	float space = _MeasureString("").height + kLineSpacing;
68
69	for (int i = 0; i < fStringList.CountItems(); i++) {
70		FontString* fontString = fStringList.ItemAt(i);
71		SetFont(fontString->font);
72		DrawString(fontString->string.String(), point);
73		point.y += space;
74	}
75}
76
77
78void
79BatteryInfoView::GetPreferredSize(float* width, float* height)
80{
81	*width = fPreferredSize.width;
82	*height = fPreferredSize.height;
83}
84
85
86void
87BatteryInfoView::AttachedToWindow()
88{
89	Window()->CenterOnScreen();
90}
91
92
93BSize
94BatteryInfoView::_MeasureString(const BString& string)
95{
96	BFont font;
97	GetFont(&font);
98	BSize size;
99
100	size.width = font.StringWidth(string);
101
102	font_height height;
103	font.GetHeight(&height);
104	size.height = height.ascent + height.descent;
105
106	return size;
107}
108
109
110void
111BatteryInfoView::_FillStringList()
112{
113	_ClearStringList();
114
115	BString powerUnit;
116	BString rateUnit;
117	switch (fBatteryExtendedInfo.power_unit) {
118		case 0:
119			powerUnit = B_TRANSLATE(" mWh");
120			rateUnit = B_TRANSLATE(" mW");
121			break;
122
123		case 1:
124			powerUnit = B_TRANSLATE(" mAh");
125			rateUnit = B_TRANSLATE(" mA");
126			break;
127	}
128
129	FontString* fontString;
130
131	fontString = new FontString;
132	fStringList.AddItem(fontString);
133	fontString->font = be_bold_font;
134
135	if ((fBatteryInfo.state & BATTERY_CHARGING) != 0)
136		fontString->string = B_TRANSLATE("Battery charging");
137	else if ((fBatteryInfo.state & BATTERY_DISCHARGING) != 0)
138		fontString->string = B_TRANSLATE("Battery discharging");
139	else if ((fBatteryInfo.state & BATTERY_CRITICAL_STATE) != 0
140		&& fBatteryExtendedInfo.model_number[0] == '\0'
141		&& fBatteryExtendedInfo.serial_number[0] == '\0'
142		&& fBatteryExtendedInfo.type[0] == '\0'
143		&& fBatteryExtendedInfo.oem_info[0] == '\0')
144		fontString->string = B_TRANSLATE("Empty battery slot");
145	else if ((fBatteryInfo.state & BATTERY_CRITICAL_STATE) != 0)
146		fontString->string = B_TRANSLATE("Damaged battery");
147	else
148		fontString->string = B_TRANSLATE("Battery unused");
149
150	fontString = new FontString;
151	fontString->string = B_TRANSLATE("Capacity: ");
152	fontString->string << fBatteryInfo.capacity;
153	fontString->string << powerUnit;
154	_AddToStringList(fontString);
155
156	fontString = new FontString;
157	fontString->string = B_TRANSLATE("Last full charge: ");
158	fontString->string << fBatteryInfo.full_capacity;
159	fontString->string << powerUnit;
160	_AddToStringList(fontString);
161
162	fontString = new FontString;
163	fontString->string = B_TRANSLATE("Current rate: ");
164	fontString->string << fBatteryInfo.current_rate;
165	fontString->string << rateUnit;
166	_AddToStringList(fontString);
167
168	// empty line
169	fontString = new FontString;
170	_AddToStringList(fontString);
171
172	fontString = new FontString;
173	fontString->string = B_TRANSLATE("Design capacity: ");
174	fontString->string << fBatteryExtendedInfo.design_capacity;
175	fontString->string << powerUnit;
176	_AddToStringList(fontString);
177
178	fontString = new FontString;
179	fontString->string = B_TRANSLATE("Technology: ");
180	if (fBatteryExtendedInfo.technology == 0)
181		fontString->string << B_TRANSLATE("non-rechargeable");
182	else if (fBatteryExtendedInfo.technology == 1)
183		fontString->string << B_TRANSLATE("rechargeable");
184	else
185		fontString->string << "?";
186	_AddToStringList(fontString);
187
188	fontString = new FontString;
189	fontString->string = B_TRANSLATE("Design voltage: ");
190	fontString->string << fBatteryExtendedInfo.design_voltage;
191	fontString->string << B_TRANSLATE(" mV");
192	_AddToStringList(fontString);
193
194	fontString = new FontString;
195	fontString->string = B_TRANSLATE("Design capacity warning: ");
196	fontString->string << fBatteryExtendedInfo.design_capacity_warning;
197	fontString->string << powerUnit;
198	_AddToStringList(fontString);
199
200	fontString = new FontString;
201	fontString->string = B_TRANSLATE("Design capacity low warning: ");
202	fontString->string << fBatteryExtendedInfo.design_capacity_low;
203	fontString->string << powerUnit;
204	_AddToStringList(fontString);
205
206	fontString = new FontString;
207	fontString->string = B_TRANSLATE("Capacity granularity 1: ");
208	fontString->string << fBatteryExtendedInfo.capacity_granularity_1;
209	fontString->string << powerUnit;
210	_AddToStringList(fontString);
211
212	fontString = new FontString;
213	fontString->string = B_TRANSLATE("Capacity granularity 2: ");
214	fontString->string << fBatteryExtendedInfo.capacity_granularity_2;
215	fontString->string << powerUnit;
216	_AddToStringList(fontString);
217
218	fontString = new FontString;
219	fontString->string = B_TRANSLATE("Model number: ");
220	fontString->string << fBatteryExtendedInfo.model_number;
221	_AddToStringList(fontString);
222
223	fontString = new FontString;
224	fontString->string = B_TRANSLATE("Serial number: ");
225	fontString->string << fBatteryExtendedInfo.serial_number;
226	_AddToStringList(fontString);
227
228	fontString = new FontString;
229	fontString->string = B_TRANSLATE("Type: ");
230	fontString->string += fBatteryExtendedInfo.type;
231	_AddToStringList(fontString);
232
233	fontString = new FontString;
234	fontString->string = B_TRANSLATE("OEM info: ");
235	fontString->string += fBatteryExtendedInfo.oem_info;
236	_AddToStringList(fontString);
237
238	fPreferredSize.width = fMaxStringSize.width + 10;
239	fPreferredSize.height = (fMaxStringSize.height + kLineSpacing) *
240		fStringList.CountItems();
241}
242
243
244void
245BatteryInfoView::_AddToStringList(FontString* fontString)
246{
247	fStringList.AddItem(fontString);
248	BSize stringSize = _MeasureString(fontString->string);
249	if (fMaxStringSize.width < stringSize.width)
250		fMaxStringSize = stringSize;
251}
252
253
254void
255BatteryInfoView::_ClearStringList()
256{
257	for (int i = 0; i < fStringList.CountItems(); i ++)
258		delete fStringList.ItemAt(i);
259	fStringList.MakeEmpty();
260	fMaxStringSize = BSize(0, 0);
261}
262
263
264//	#pragma mark -
265
266
267ExtPowerStatusView::ExtPowerStatusView(PowerStatusDriverInterface* interface,
268		BRect frame, int32 resizingMode, int batteryID,
269		ExtendedInfoWindow* window)
270	:
271	PowerStatusView(interface, frame, resizingMode, batteryID),
272	fExtendedInfoWindow(window),
273	fBatteryInfoView(window->GetExtendedBatteryInfoView()),
274	fSelected(false)
275{
276}
277
278
279void
280ExtPowerStatusView::Draw(BRect updateRect)
281{
282	if (fSelected)
283		SetLowColor(102, 152, 203);
284	else
285		SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
286
287	PowerStatusView::Draw(updateRect);
288}
289
290
291void
292ExtPowerStatusView::MouseDown(BPoint where)
293{
294	if (!fSelected) {
295		fSelected = true;
296		Update(true);
297		if (ExtendedInfoWindow* window
298				= dynamic_cast<ExtendedInfoWindow*>(Window()))
299			window->BatterySelected(this);
300	}
301}
302
303
304void
305ExtPowerStatusView::Select(bool select)
306{
307	fSelected = select;
308	Update(true);
309}
310
311
312bool
313ExtPowerStatusView::IsCritical()
314{
315	return (fBatteryInfo.state & BATTERY_CRITICAL_STATE) != 0;
316}
317
318
319void
320ExtPowerStatusView::Update(bool force)
321{
322	PowerStatusView::Update(force);
323	if (!fSelected)
324		return;
325
326	acpi_extended_battery_info extInfo;
327	fDriverInterface->GetExtendedBatteryInfo(&extInfo, fBatteryID);
328
329	fBatteryInfoView->Update(fBatteryInfo, extInfo);
330	fBatteryInfoView->Invalidate();
331}
332
333
334//	#pragma mark -
335
336
337ExtendedInfoWindow::ExtendedInfoWindow(PowerStatusDriverInterface* interface)
338	:
339	BWindow(BRect(100, 150, 500, 500), B_TRANSLATE("Extended battery info"),
340		B_TITLED_WINDOW,
341		B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AVOID_FRONT |
342		B_ASYNCHRONOUS_CONTROLS),
343	fDriverInterface(interface),
344	fSelectedView(NULL)
345{
346	fDriverInterface->AcquireReference();
347
348	BView *view = new BView(Bounds(), "view", B_FOLLOW_ALL, 0);
349	view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
350	AddChild(view);
351
352	BGroupLayout* mainLayout = new BGroupLayout(B_VERTICAL);
353	mainLayout->SetSpacing(10);
354	mainLayout->SetInsets(10, 10, 10, 10);
355	view->SetLayout(mainLayout);
356
357	BRect rect = Bounds();
358	rect.InsetBy(5, 5);
359	BBox *infoBox = new BBox(rect, B_TRANSLATE("Power status box"));
360	infoBox->SetLabel(B_TRANSLATE("Battery info"));
361	BGroupLayout* infoLayout = new BGroupLayout(B_HORIZONTAL);
362	infoLayout->SetInsets(10, infoBox->TopBorderOffset() * 2 + 10, 10, 10);
363	infoLayout->SetSpacing(10);
364	infoBox->SetLayout(infoLayout);
365	mainLayout->AddView(infoBox);
366
367	BGroupView* batteryView = new BGroupView(B_VERTICAL);
368	batteryView->GroupLayout()->SetSpacing(10);
369	infoLayout->AddView(batteryView);
370
371	// create before the battery views
372	fBatteryInfoView = new BatteryInfoView();
373
374	BGroupLayout* batteryLayout = batteryView->GroupLayout();
375	BRect batteryRect(0, 0, 50, 30);
376	for (int i = 0; i < interface->GetBatteryCount(); i++) {
377		ExtPowerStatusView* view = new ExtPowerStatusView(interface,
378			batteryRect, B_FOLLOW_NONE, i, this);
379		view->SetExplicitMaxSize(BSize(70, 80));
380		view->SetExplicitMinSize(BSize(70, 80));
381
382		batteryLayout->AddView(view);
383		fBatteryViewList.AddItem(view);
384		fDriverInterface->StartWatching(view);
385		if (!view->IsCritical())
386			fSelectedView = view;
387	}
388
389	batteryLayout->AddItem(BSpaceLayoutItem::CreateGlue());
390
391	infoLayout->AddView(fBatteryInfoView);
392
393	if (!fSelectedView && fBatteryViewList.CountItems() > 0)
394		fSelectedView = fBatteryViewList.ItemAt(0);
395	fSelectedView->Select();
396
397	BSize size = mainLayout->PreferredSize();
398	ResizeTo(size.width, size.height);
399}
400
401
402ExtendedInfoWindow::~ExtendedInfoWindow()
403{
404	for (int i = 0; i < fBatteryViewList.CountItems(); i++)
405		fDriverInterface->StopWatching(fBatteryViewList.ItemAt(i));
406
407	fDriverInterface->ReleaseReference();
408}
409
410
411BatteryInfoView*
412ExtendedInfoWindow::GetExtendedBatteryInfoView()
413{
414	return fBatteryInfoView;
415}
416
417
418void
419ExtendedInfoWindow::BatterySelected(ExtPowerStatusView* view)
420{
421	if (fSelectedView) {
422		fSelectedView->Select(false);
423		fSelectedView->Invalidate();
424	}
425
426	fSelectedView = view;
427}
428