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