xref: /haiku/src/apps/installer/PackageViews.cpp (revision e6eaad8615c4734498b9b800847d18bbe62782fa)
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 <LayoutUtils.h>
17 #include <Locale.h>
18 #include <Messenger.h>
19 #include <ScrollBar.h>
20 #include <String.h>
21 #include <View.h>
22 #include <Window.h>
23 
24 #include "InstallerDefs.h"
25 #include "StringForSize.h"
26 
27 
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "PackagesView"
30 
31 #define ICON_ATTRIBUTE "INSTALLER PACKAGE: ICON"
32 
33 
34 Package::Package(const char *folder)
35 	:
36 	Group(),
37 	fSize(0),
38 	fIcon(NULL)
39 {
40 	SetFolder(folder);
41 }
42 
43 
44 Package::~Package()
45 {
46 	delete fIcon;
47 }
48 
49 
50 Package *
51 Package::PackageFromEntry(BEntry &entry)
52 {
53 	char folder[B_FILE_NAME_LENGTH];
54 	entry.GetName(folder);
55 	BDirectory directory(&entry);
56 	if (directory.InitCheck() != B_OK)
57 		return NULL;
58 	Package *package = new Package(folder);
59 	bool alwaysOn;
60 	bool onByDefault;
61 	int32 size;
62 	char group[64];
63 	memset(group, 0, 64);
64 	if (directory.ReadAttr("INSTALLER PACKAGE: NAME", B_STRING_TYPE, 0,
65 		package->fName, 64) < 0) {
66 		goto err;
67 	}
68 	if (directory.ReadAttr("INSTALLER PACKAGE: GROUP", B_STRING_TYPE, 0,
69 		group, 64) < 0) {
70 		goto err;
71 	}
72 	if (directory.ReadAttr("INSTALLER PACKAGE: DESCRIPTION", B_STRING_TYPE, 0,
73 		package->fDescription, 64) < 0) {
74 		goto err;
75 	}
76 	if (directory.ReadAttr("INSTALLER PACKAGE: ON_BY_DEFAULT", B_BOOL_TYPE, 0,
77 		&onByDefault, sizeof(onByDefault)) < 0) {
78 		goto err;
79 	}
80 	if (directory.ReadAttr("INSTALLER PACKAGE: ALWAYS_ON", B_BOOL_TYPE, 0,
81 		&alwaysOn, sizeof(alwaysOn)) < 0) {
82 		goto err;
83 	}
84 	if (directory.ReadAttr("INSTALLER PACKAGE: SIZE", B_INT32_TYPE, 0,
85 		&size, sizeof(size)) < 0) {
86 		goto err;
87 	}
88 	package->SetGroupName(group);
89 	package->SetSize(size);
90 	package->SetAlwaysOn(alwaysOn);
91 	package->SetOnByDefault(onByDefault);
92 
93 	attr_info info;
94 	if (directory.GetAttrInfo(ICON_ATTRIBUTE, &info) == B_OK) {
95 		char buffer[info.size];
96 		BMessage msg;
97 		if ((directory.ReadAttr(ICON_ATTRIBUTE, info.type, 0, buffer,
98 				info.size) == info.size)
99 			&& (msg.Unflatten(buffer) == B_OK)) {
100 			package->SetIcon(new BBitmap(&msg));
101 		}
102 	}
103 	return package;
104 err:
105 	delete package;
106 	return NULL;
107 }
108 
109 
110 void
111 Package::GetSizeAsString(char* string, size_t stringSize)
112 {
113 	string_for_size(fSize, string, stringSize);
114 }
115 
116 
117 Group::Group()
118 {
119 
120 }
121 
122 Group::~Group()
123 {
124 }
125 
126 
127 PackageCheckBox::PackageCheckBox(BRect rect, Package *item)
128 	:
129 	BCheckBox(rect.OffsetBySelf(7, 0), "pack_cb", item->Name(), NULL),
130 	fPackage(item)
131 {
132 }
133 
134 
135 PackageCheckBox::~PackageCheckBox()
136 {
137 	delete fPackage;
138 }
139 
140 
141 void
142 PackageCheckBox::Draw(BRect update)
143 {
144 	BCheckBox::Draw(update);
145 	char string[15];
146 	fPackage->GetSizeAsString(string, sizeof(string));
147 	float width = StringWidth(string);
148 	DrawString(string, BPoint(Bounds().right - width - 8, 11));
149 
150 	const BBitmap *icon = fPackage->Icon();
151 	if (icon)
152 		DrawBitmap(icon, BPoint(Bounds().right - 92, 0));
153 }
154 
155 
156 void
157 PackageCheckBox::MouseMoved(BPoint point, uint32 transit,
158 	const BMessage* dragMessage)
159 {
160 	printf("%s called\n", __PRETTY_FUNCTION__);
161 	if (transit == B_ENTERED_VIEW) {
162 		BMessage msg(MSG_STATUS_MESSAGE);
163 		msg.AddString("status", fPackage->Description());
164 		BMessenger(NULL, Window()).SendMessage(&msg);
165 	} else if (transit == B_EXITED_VIEW) {
166 		BMessage msg(MSG_STATUS_MESSAGE);
167 		BMessenger(NULL, Window()).SendMessage(&msg);
168 	}
169 }
170 
171 
172 GroupView::GroupView(BRect rect, Group *group)
173 	:
174 	BStringView(rect, "group", group->GroupName()),
175 	fGroup(group)
176 {
177 	SetFont(be_bold_font);
178 }
179 
180 
181 GroupView::~GroupView()
182 {
183 	delete fGroup;
184 }
185 
186 
187 // #pragma mark -
188 
189 
190 PackagesView::PackagesView(BRect rect, const char* name)
191 	:
192 	BView(rect, name, B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS)
193 {
194 }
195 
196 
197 PackagesView::PackagesView(const char* name)
198 	:
199 	BView(name, B_WILL_DRAW | B_FRAME_EVENTS)
200 {
201 }
202 
203 
204 PackagesView::~PackagesView()
205 {
206 
207 }
208 
209 
210 void
211 PackagesView::Clean()
212 {
213 	BView* view;
214 	while ((view = ChildAt(0))) {
215 		if (dynamic_cast<GroupView*>(view)
216 			|| dynamic_cast<PackageCheckBox*>(view)) {
217 			RemoveChild(view);
218 			delete view;
219 		}
220 	}
221 	ScrollTo(0, 0);
222 }
223 
224 
225 void
226 PackagesView::AddPackages(BList& packages, BMessage* msg)
227 {
228 	int32 count = packages.CountItems();
229 	BRect rect = Bounds();
230 	BRect bounds = rect;
231 	rect.left = 1;
232 	rect.bottom = 15;
233 	rect.top = 0;
234 	BString lastGroup = "";
235 	for (int32 i = 0; i < count; i++) {
236 		void* item = packages.ItemAt(i);
237 		Package* package = static_cast<Package*>(item);
238 		if (lastGroup != BString(package->GroupName())) {
239 			rect.OffsetBy(0, 1);
240 			lastGroup = package->GroupName();
241 			Group* group = new Group();
242 			group->SetGroupName(package->GroupName());
243 			GroupView *view = new GroupView(rect, group);
244 			AddChild(view);
245 			rect.OffsetBy(0, 17);
246 		}
247 		PackageCheckBox* checkBox = new PackageCheckBox(rect, package);
248 		checkBox->SetValue(package->OnByDefault()
249 			? B_CONTROL_ON : B_CONTROL_OFF);
250 		checkBox->SetEnabled(!package->AlwaysOn());
251 		checkBox->SetMessage(new BMessage(*msg));
252 		AddChild(checkBox);
253 		rect.OffsetBy(0, 20);
254 	}
255 	ResizeTo(bounds.Width(), rect.top);
256 	Invalidate();
257 }
258 
259 
260 void
261 PackagesView::GetTotalSizeAsString(char* string, size_t stringSize)
262 {
263 	int32 count = CountChildren();
264 	int32 size = 0;
265 	for (int32 i = 0; i < count; i++) {
266 		PackageCheckBox* cb = dynamic_cast<PackageCheckBox*>(ChildAt(i));
267 		if (cb && cb->Value())
268 			size += cb->GetPackage()->Size();
269 	}
270 	string_for_size(size, string, stringSize);
271 }
272 
273 
274 void
275 PackagesView::GetPackagesToInstall(BList* list, int32* size)
276 {
277 	int32 count = CountChildren();
278 	*size = 0;
279 	for (int32 i = 0; i < count; i++) {
280 		PackageCheckBox* cb = dynamic_cast<PackageCheckBox*>(ChildAt(i));
281 		if (cb && cb->Value()) {
282 			list->AddItem(cb->GetPackage());
283 			*size += cb->GetPackage()->Size();
284 		}
285 	}
286 }
287 
288 
289 void
290 PackagesView::FrameResized(float width, float height)
291 {
292 	if (CountChildren() == 0)
293 		Invalidate();
294 
295 	BScrollBar* scrollBar = ScrollBar(B_VERTICAL);
296 	if (scrollBar == NULL)
297 		return;
298 
299 	float virtualHeight = 0.0;
300 
301 	int32 count = CountChildren();
302 	if (count > 0) {
303 		BView* child = ChildAt(count - 1);
304 		virtualHeight = child->Frame().bottom;
305 	}
306 
307 	if (height > virtualHeight) {
308 		scrollBar->SetRange(0.0f, 0.0f);
309 		scrollBar->SetValue(0.0f);
310 	} else {
311 		scrollBar->SetRange(0.0f, virtualHeight - height);
312 		scrollBar->SetProportion(height / virtualHeight);
313 	}
314 
315 	scrollBar->SetSteps(15, height);
316 }
317 
318 
319 void
320 PackagesView::Draw(BRect updateRect)
321 {
322 	if (CountChildren() > 0)
323 		return;
324 
325 	be_control_look->DrawLabel(this,
326 		B_TRANSLATE("No optional packages available."),
327 		Bounds(), updateRect, ViewColor(), BControlLook::B_DISABLED,
328 		BAlignment(B_ALIGN_CENTER, B_ALIGN_MIDDLE));
329 }
330 
331 
332 void
333 PackagesView::GetPreferredSize(float* _width, float* _height)
334 {
335 	// TODO: Something more nice as default? I need to see how this looks
336 	// when there are actually any packages...
337 	if (_width != NULL)
338 		*_width = 400.0;
339 
340 	if (_height != NULL)
341 		*_height = 80.0;
342 }
343 
344 
345 BSize
346 PackagesView::MaxSize()
347 {
348 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
349 		BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
350 }
351 
352