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