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