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