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