1/*
2 * Copyright 2009, Stephan A��mus <superstippi@gmx.de>
3 * Copyright 2005, J��r��me DUVAL.
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
6
7#include "PackageViews.h"
8
9#include <stdio.h>
10
11#include <Catalog.h>
12#include <ControlLook.h>
13#include <Directory.h>
14#include <Entry.h>
15#include <fs_attr.h>
16#include <GroupLayout.h>
17#include <LayoutUtils.h>
18#include <Locale.h>
19#include <Messenger.h>
20#include <package/PackageInfo.h>
21#include <Path.h>
22#include <ScrollBar.h>
23#include <String.h>
24#include <View.h>
25#include <Window.h>
26
27#include "InstallerDefs.h"
28#include "StringForSize.h"
29
30
31#undef B_TRANSLATION_CONTEXT
32#define B_TRANSLATION_CONTEXT "PackagesView"
33
34#define ICON_ATTRIBUTE "INSTALLER PACKAGE: ICON"
35
36
37Package::Package(const BPath &path)
38	:
39	Group(),
40	fSize(0),
41	fIcon(NULL)
42{
43	SetPath(path);
44}
45
46
47Package::~Package()
48{
49	delete fIcon;
50}
51
52
53Package *
54Package::PackageFromEntry(BEntry &entry)
55{
56	BPath path;
57	entry.GetPath(&path);
58
59	BPackageKit::BPackageInfo info;
60	info.ReadFromPackageFile(path.Path());
61
62	if (info.InitCheck() != B_OK)
63		return NULL;
64
65	Package *package = new Package(path);
66	package->fName = info.Name();
67	package->fDescription = info.Summary();
68
69	bool alwaysOn = false;
70	bool onByDefault = true;
71	off_t size = 0;
72	entry.GetSize(&size);
73	char group[64];
74	memset(group, 0, 64);
75
76	BNode node(&entry);
77	// FIXME enable these when the attributes on the packages are actually
78	// populated by the buildsystem. For now, assume everything is
79	// on-by-default and optional, and have no groups.
80#if 0
81	if (node.ReadAttr("INSTALLER PACKAGE: GROUP", B_STRING_TYPE, 0,
82		group, 64) < 0) {
83		goto err;
84	}
85	if (node.ReadAttr("INSTALLER PACKAGE: ON_BY_DEFAULT", B_BOOL_TYPE, 0,
86		&onByDefault, sizeof(onByDefault)) < 0) {
87		goto err;
88	}
89	if (node.ReadAttr("INSTALLER PACKAGE: ALWAYS_ON", B_BOOL_TYPE, 0,
90		&alwaysOn, sizeof(alwaysOn)) < 0) {
91		goto err;
92	}
93#endif
94	package->SetGroupName(group);
95	package->SetSize(size);
96	package->SetAlwaysOn(alwaysOn);
97	package->SetOnByDefault(onByDefault);
98
99	attr_info attributes;
100	if (node.GetAttrInfo(ICON_ATTRIBUTE, &attributes) == B_OK) {
101		char buffer[attributes.size];
102		BMessage msg;
103		if ((node.ReadAttr(ICON_ATTRIBUTE, attributes.type, 0, buffer,
104				attributes.size) == attributes.size)
105			&& (msg.Unflatten(buffer) == B_OK)) {
106			package->SetIcon(new BBitmap(&msg));
107		}
108	}
109	return package;
110#if 0
111err:
112#endif
113	delete package;
114	return NULL;
115}
116
117
118void
119Package::GetSizeAsString(char* string, size_t stringSize)
120{
121	string_for_size(fSize, string, stringSize);
122}
123
124
125Group::Group()
126{
127
128}
129
130Group::~Group()
131{
132}
133
134
135PackageCheckBox::PackageCheckBox(Package *item)
136	:
137	BCheckBox("pack_cb", item->Name(), NULL),
138	fPackage(item)
139{
140	SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
141	SetFlags(Flags() | B_FULL_UPDATE_ON_RESIZE);
142	SetIcon(fPackage->Icon());
143}
144
145
146PackageCheckBox::~PackageCheckBox()
147{
148	delete fPackage;
149}
150
151
152void
153PackageCheckBox::Draw(BRect update)
154{
155	BCheckBox::Draw(update);
156
157	// Draw the label
158	char string[15];
159	fPackage->GetSizeAsString(string, sizeof(string));
160	float width = StringWidth(string);
161	BRect sizeRect = Bounds();
162	sizeRect.left = sizeRect.right - width;
163	be_control_look->DrawLabel(this, string, NULL, sizeRect, update,
164		ui_color(B_DOCUMENT_BACKGROUND_COLOR), be_control_look->Flags(this));
165}
166
167
168void
169PackageCheckBox::MouseMoved(BPoint point, uint32 transit,
170	const BMessage* dragMessage)
171{
172	if (transit == B_ENTERED_VIEW) {
173		BMessage msg(MSG_STATUS_MESSAGE);
174		msg.AddString("status", fPackage->Description());
175		BMessenger(NULL, Window()).SendMessage(&msg);
176	} else if (transit == B_EXITED_VIEW) {
177		BMessage msg(MSG_STATUS_MESSAGE);
178		BMessenger(NULL, Window()).SendMessage(&msg);
179	}
180}
181
182
183GroupView::GroupView(Group *group)
184	:
185	BStringView("group", group->GroupName()),
186	fGroup(group)
187{
188	SetFont(be_bold_font);
189}
190
191
192GroupView::~GroupView()
193{
194	delete fGroup;
195}
196
197
198// #pragma mark -
199
200
201PackagesView::PackagesView(const char* name)
202	:
203	BView(name, B_WILL_DRAW)
204{
205	BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
206	layout->SetSpacing(0);
207	layout->SetInsets(B_USE_SMALL_SPACING, 0);
208	SetLayout(layout);
209
210	SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
211	SetExplicitMinSize(BSize(B_SIZE_UNSET, 80));
212}
213
214
215PackagesView::~PackagesView()
216{
217
218}
219
220
221void
222PackagesView::Clean()
223{
224	BView* view;
225	while ((view = ChildAt(0))) {
226		if (dynamic_cast<GroupView*>(view)
227			|| dynamic_cast<PackageCheckBox*>(view)) {
228			RemoveChild(view);
229			delete view;
230		}
231	}
232	ScrollTo(0, 0);
233
234	BView* parent = Parent();
235	BRect r = parent->Bounds();
236	parent->FrameResized(r.Width(), r.Height());
237}
238
239
240void
241PackagesView::AddPackages(BList& packages, BMessage* msg)
242{
243	int32 count = packages.CountItems();
244	BString lastGroup = "";
245	for (int32 i = 0; i < count; i++) {
246		void* item = packages.ItemAt(i);
247		Package* package = static_cast<Package*>(item);
248		if (lastGroup != BString(package->GroupName())) {
249			lastGroup = package->GroupName();
250			Group* group = new Group();
251			group->SetGroupName(package->GroupName());
252			GroupView *view = new GroupView(group);
253			AddChild(view);
254		}
255		PackageCheckBox* checkBox = new PackageCheckBox(package);
256		checkBox->SetValue(package->OnByDefault()
257			? B_CONTROL_ON : B_CONTROL_OFF);
258		checkBox->SetEnabled(!package->AlwaysOn());
259		checkBox->SetMessage(new BMessage(*msg));
260		AddChild(checkBox);
261	}
262	Invalidate();
263
264	// Force scrollbars to update
265	BView* parent = Parent();
266	BRect r = parent->Bounds();
267	parent->FrameResized(r.Width(), r.Height());
268}
269
270
271void
272PackagesView::GetTotalSizeAsString(char* string, size_t stringSize)
273{
274	int32 count = CountChildren();
275	int32 size = 0;
276	for (int32 i = 0; i < count; i++) {
277		PackageCheckBox* cb = dynamic_cast<PackageCheckBox*>(ChildAt(i));
278		if (cb && cb->Value())
279			size += cb->GetPackage()->Size();
280	}
281	string_for_size(size, string, stringSize);
282}
283
284
285void
286PackagesView::GetPackagesToInstall(BList* list, int32* size)
287{
288	int32 count = CountChildren();
289	*size = 0;
290	for (int32 i = 0; i < count; i++) {
291		PackageCheckBox* cb = dynamic_cast<PackageCheckBox*>(ChildAt(i));
292		if (cb && cb->Value()) {
293			list->AddItem(cb->GetPackage());
294			*size += cb->GetPackage()->Size();
295		}
296	}
297}
298
299
300void
301PackagesView::Draw(BRect updateRect)
302{
303	if (CountChildren() > 0)
304		return;
305
306	be_control_look->DrawLabel(this,
307		B_TRANSLATE("No optional packages available."),
308		Bounds(), updateRect, ViewColor(), BControlLook::B_DISABLED,
309		BAlignment(B_ALIGN_CENTER, B_ALIGN_MIDDLE));
310}
311