vfs: check userland buffers before reading them.
[haiku.git] / src / apps / haikudepot / ui / FeaturedPackagesView.cpp
blobfd6cc9d23420fb693abaf9b00f83e9fd1dec0322
1 /*
2 * Copyright 2013-214, Stephan Aßmus <superstippi@gmx.de>.
3 * Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
7 #include "FeaturedPackagesView.h"
9 #include <stdio.h>
11 #include <Catalog.h>
12 #include <Font.h>
13 #include <LayoutBuilder.h>
14 #include <Message.h>
15 #include <ScrollView.h>
16 #include <StringView.h>
17 #include <SpaceLayoutItem.h>
19 #include "BitmapView.h"
20 #include "MainWindow.h"
21 #include "MarkupTextView.h"
22 #include "MessagePackageListener.h"
23 #include "RatingView.h"
24 #include "ScrollableGroupView.h"
27 #undef B_TRANSLATION_CONTEXT
28 #define B_TRANSLATION_CONTEXT "FeaturedPackagesView"
31 static const rgb_color kLightBlack = (rgb_color){ 60, 60, 60, 255 };
33 static BitmapRef sInstalledIcon(new(std::nothrow) SharedBitmap(504), true);
36 // #pragma mark - PackageView
39 class PackageView : public BGroupView {
40 public:
41 PackageView()
43 BGroupView("package view", B_HORIZONTAL),
44 fPackageListener(
45 new(std::nothrow) OnePackageMessagePackageListener(this)),
46 fSelected(false)
48 SetViewUIColor(B_LIST_BACKGROUND_COLOR);
49 SetHighUIColor(B_LIST_ITEM_TEXT_COLOR);
50 SetEventMask(B_POINTER_EVENTS);
52 fIconView = new BitmapView("package icon view");
53 fInstalledIconView = new BitmapView("installed icon view");
54 fTitleView = new BStringView("package title view", "");
55 fPublisherView = new BStringView("package publisher view", "");
57 // Title font
58 BFont font;
59 GetFont(&font);
60 font_family family;
61 font_style style;
62 font.SetSize(ceilf(font.Size() * 1.8f));
63 font.GetFamilyAndStyle(&family, &style);
64 font.SetFamilyAndStyle(family, "Bold");
65 fTitleView->SetFont(&font);
67 // Publisher font
68 GetFont(&font);
69 font.SetSize(std::max(9.0f, floorf(font.Size() * 0.92f)));
70 font.SetFamilyAndStyle(family, "Italic");
71 fPublisherView->SetFont(&font);
73 // Summary text view
74 fSummaryView = new BTextView("package summary");
75 fSummaryView->MakeSelectable(false);
76 fSummaryView->MakeEditable(false);
77 font = BFont(be_plain_font);
78 rgb_color color = HighColor();
79 fSummaryView->SetFontAndColor(&font, B_FONT_ALL, &color);
81 // Rating view
82 fRatingView = new RatingView("package rating view");
84 fAvgRating = new BStringView("package average rating", "");
85 fAvgRating->SetFont(&font);
87 fVoteInfo = new BStringView("package vote info", "");
88 // small font
89 GetFont(&font);
90 font.SetSize(std::max(9.0f, floorf(font.Size() * 0.85f)));
91 fVoteInfo->SetFont(&font);
92 fVoteInfo->SetHighUIColor(HighUIColor());
94 BLayoutBuilder::Group<>(this)
95 .Add(fIconView)
96 .AddGroup(B_VERTICAL, 1.0f, 2.2f)
97 .AddGroup(B_HORIZONTAL)
98 .Add(fTitleView)
99 .Add(fInstalledIconView)
100 .AddGlue()
101 .End()
102 .Add(fPublisherView)
103 .SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET))
104 .End()
105 .AddGlue(0.1f)
106 .AddGroup(B_HORIZONTAL, 0.8f)
107 .Add(fRatingView)
108 .Add(fAvgRating)
109 .Add(fVoteInfo)
110 .End()
111 .AddGlue(0.2f)
112 .Add(fSummaryView, 2.0f)
114 .SetInsets(B_USE_WINDOW_INSETS)
117 Clear();
120 virtual ~PackageView()
122 fPackageListener->SetPackage(PackageInfoRef(NULL));
123 delete fPackageListener;
126 virtual void AllAttached()
128 for (int32 index = 0; index < CountChildren(); ++index) {
129 ChildAt(index)->SetViewUIColor(ViewUIColor());
130 ChildAt(index)->SetLowUIColor(ViewUIColor());
131 ChildAt(index)->SetHighUIColor(HighUIColor());
135 virtual void MessageReceived(BMessage* message)
137 switch (message->what) {
138 case B_MOUSE_WHEEL_CHANGED:
139 Window()->PostMessage(message, Parent());
140 break;
142 case MSG_UPDATE_PACKAGE:
144 uint32 changes = 0;
145 if (message->FindUInt32("changes", &changes) != B_OK)
146 break;
147 UpdatePackage(changes, fPackageListener->Package());
148 break;
151 case B_COLORS_UPDATED:
153 if (message->HasColor(ui_color_name(B_LIST_ITEM_TEXT_COLOR)))
154 _UpdateColors();
155 break;
160 virtual void MouseDown(BPoint where)
162 BRect bounds = Bounds();
163 BRect parentBounds = Parent()->Bounds();
164 ConvertFromParent(&parentBounds);
165 bounds = bounds & parentBounds;
167 if (bounds.Contains(where) && Window()->IsActive()) {
168 BMessage message(MSG_PACKAGE_SELECTED);
169 message.AddString("name", PackageName());
170 Window()->PostMessage(&message);
174 void SetPackage(const PackageInfoRef& package)
176 fPackageListener->SetPackage(package);
178 _SetIcon(package->Icon());
179 _SetInstalled(package->State() == ACTIVATED);
181 fTitleView->SetText(package->Title());
183 BString publisher = package->Publisher().Name();
184 fPublisherView->SetText(publisher);
186 BString summary = package->ShortDescription();
187 fSummaryView->SetText(summary);
189 _SetRating(package->CalculateRatingSummary());
191 InvalidateLayout();
192 Invalidate();
195 void UpdatePackage(uint32 changeMask, const PackageInfoRef& package)
197 if ((changeMask & PKG_CHANGED_TITLE) != 0)
198 fTitleView->SetText(package->Title());
199 if ((changeMask & PKG_CHANGED_SUMMARY) != 0)
200 fSummaryView->SetText(package->ShortDescription());
201 if ((changeMask & PKG_CHANGED_RATINGS) != 0)
202 _SetRating(package->CalculateRatingSummary());
203 if ((changeMask & PKG_CHANGED_STATE) != 0)
204 _SetInstalled(package->State() == ACTIVATED);
205 if ((changeMask & PKG_CHANGED_ICON) != 0)
206 _SetIcon(package->Icon());
209 void Clear()
211 fPackageListener->SetPackage(PackageInfoRef(NULL));
213 fIconView->UnsetBitmap();
214 fInstalledIconView->UnsetBitmap();
215 fTitleView->SetText("");
216 fPublisherView->SetText("");
217 fSummaryView->SetText("");
218 fRatingView->SetRating(-1.0f);
219 fAvgRating->SetText("");
220 fVoteInfo->SetText("");
223 const char* PackageTitle() const
225 return fTitleView->Text();
228 const char* PackageName() const
230 if (fPackageListener->Package().Get() != NULL)
231 return fPackageListener->Package()->Name();
232 else
233 return "";
236 void SetSelected(bool selected)
238 if (fSelected == selected)
239 return;
240 fSelected = selected;
242 _UpdateColors();
245 void _UpdateColors()
247 color_which bgColor = B_LIST_BACKGROUND_COLOR;
248 color_which textColor = B_LIST_ITEM_TEXT_COLOR;
250 if (fSelected) {
251 bgColor = B_LIST_SELECTED_BACKGROUND_COLOR;
252 textColor = B_LIST_SELECTED_ITEM_TEXT_COLOR;
255 List<BView*, true> views;
257 views.Add(this);
258 views.Add(fIconView);
259 views.Add(fInstalledIconView);
260 views.Add(fTitleView);
261 views.Add(fPublisherView);
262 views.Add(fSummaryView);
263 views.Add(fRatingView);
264 views.Add(fAvgRating);
265 views.Add(fVoteInfo);
267 for (int32 i = 0; i < views.CountItems(); i++) {
268 BView* view = views.ItemAtFast(i);
270 view->SetViewUIColor(bgColor);
271 view->SetLowUIColor(bgColor);
272 view->SetHighUIColor(textColor);
273 view->Invalidate();
276 BFont font(be_plain_font);
277 rgb_color color = HighColor();
278 fSummaryView->SetFontAndColor(&font, B_FONT_ALL, &color);
281 void _SetRating(const RatingSummary& ratingSummary)
283 fRatingView->SetRating(ratingSummary.averageRating);
285 if (ratingSummary.ratingCount > 0) {
286 BString avgRating;
287 avgRating.SetToFormat("%.1f", ratingSummary.averageRating);
288 fAvgRating->SetText(avgRating);
290 BString votes;
291 votes.SetToFormat("%d", ratingSummary.ratingCount);
293 BString voteInfo(B_TRANSLATE("(%Votes%)"));
294 voteInfo.ReplaceAll("%Votes%", votes);
296 fVoteInfo->SetText(voteInfo);
297 } else {
298 fAvgRating->SetText("");
299 fVoteInfo->SetText("");
303 void _SetInstalled(bool installed)
305 if (installed) {
306 fInstalledIconView->SetBitmap(sInstalledIcon,
307 SharedBitmap::SIZE_16);
308 } else
309 fInstalledIconView->UnsetBitmap();
312 void _SetIcon(const BitmapRef& icon)
314 if (icon.Get() != NULL) {
315 fIconView->SetBitmap(icon, SharedBitmap::SIZE_64);
316 } else
317 fIconView->UnsetBitmap();
320 private:
321 OnePackageMessagePackageListener* fPackageListener;
323 BitmapView* fIconView;
324 BitmapView* fInstalledIconView;
326 BStringView* fTitleView;
327 BStringView* fPublisherView;
329 BTextView* fSummaryView;
331 RatingView* fRatingView;
332 BStringView* fAvgRating;
333 BStringView* fVoteInfo;
335 bool fSelected;
337 BString fPackageName;
341 // #pragma mark - FeaturedPackagesView
344 FeaturedPackagesView::FeaturedPackagesView()
346 BView("featured package view", 0)
348 BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
349 SetLayout(layout);
351 fContainerView = new ScrollableGroupView();
352 fContainerView->SetViewUIColor(B_LIST_BACKGROUND_COLOR);
353 fPackageListLayout = fContainerView->GroupLayout();
355 BScrollView* scrollView = new BScrollView(
356 "featured packages scroll view", fContainerView,
357 0, false, true, B_FANCY_BORDER);
359 BScrollBar* scrollBar = scrollView->ScrollBar(B_VERTICAL);
360 if (scrollBar != NULL)
361 scrollBar->SetSteps(10.0f, 20.0f);
363 BLayoutBuilder::Group<>(this)
364 .Add(scrollView, 1.0f)
369 FeaturedPackagesView::~FeaturedPackagesView()
374 void
375 FeaturedPackagesView::AddPackage(const PackageInfoRef& package)
377 // Find insertion index (alphabetical)
378 int32 index = 0;
379 for (int32 i = 0; BLayoutItem* item = fPackageListLayout->ItemAt(i); i++) {
380 PackageView* view = dynamic_cast<PackageView*>(item->View());
381 if (view == NULL)
382 break;
384 BString name = view->PackageName();
385 if (name == package->Name()) {
386 // Don't add packages more than once
387 return;
390 BString title = view->PackageTitle();
391 if (title.Compare(package->Title()) < 0)
392 index++;
395 PackageView* view = new PackageView();
396 view->SetPackage(package);
398 fPackageListLayout->AddView(index, view);
402 void
403 FeaturedPackagesView::RemovePackage(const PackageInfoRef& package)
405 // Find the package
406 for (int32 i = 0; BLayoutItem* item = fPackageListLayout->ItemAt(i); i++) {
407 PackageView* view = dynamic_cast<PackageView*>(item->View());
408 if (view == NULL)
409 break;
411 BString name = view->PackageName();
412 if (name == package->Name()) {
413 view->RemoveSelf();
414 delete view;
415 break;
421 void
422 FeaturedPackagesView::Clear()
424 for (int32 i = fPackageListLayout->CountItems() - 1;
425 BLayoutItem* item = fPackageListLayout->ItemAt(i); i--) {
426 BView* view = dynamic_cast<PackageView*>(item->View());
427 if (view != NULL) {
428 view->RemoveSelf();
429 delete view;
435 void
436 FeaturedPackagesView::SelectPackage(const PackageInfoRef& package,
437 bool scrollToEntry)
439 BString selectedName;
440 if (package.Get() != NULL)
441 selectedName = package->Name();
443 for (int32 i = 0; BLayoutItem* item = fPackageListLayout->ItemAt(i); i++) {
444 PackageView* view = dynamic_cast<PackageView*>(item->View());
445 if (view == NULL)
446 break;
448 BString name = view->PackageName();
449 bool match = (name == selectedName);
450 view->SetSelected(match);
452 if (match && scrollToEntry) {
453 // Scroll the view so that the package entry shows up in the middle
454 fContainerView->ScrollTo(0,
455 view->Frame().top
456 - fContainerView->Bounds().Height() / 2
457 + view->Bounds().Height() / 2);
463 void
464 FeaturedPackagesView::CleanupIcons()
466 sInstalledIcon.Unset();