1 /* 2 * Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ApplicationTypeWindow.h" 8 #include "FileTypes.h" 9 #include "IconView.h" 10 #include "PreferredAppMenu.h" 11 #include "StringView.h" 12 #include "TypeListWindow.h" 13 14 #include <AppFileInfo.h> 15 #include <Application.h> 16 #include <Bitmap.h> 17 #include <Box.h> 18 #include <Button.h> 19 #include <CheckBox.h> 20 #include <File.h> 21 #include <ListView.h> 22 #include <MenuBar.h> 23 #include <MenuField.h> 24 #include <MenuItem.h> 25 #include <Mime.h> 26 #include <NodeInfo.h> 27 #include <PopUpMenu.h> 28 #include <RadioButton.h> 29 #include <Roster.h> 30 #include <ScrollView.h> 31 #include <TextControl.h> 32 33 #include <ctype.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 38 39 const uint32 kMsgSave = 'save'; 40 const uint32 kMsgFlagsChanged = 'flgc'; 41 42 const uint32 kMsgTypeSelected = 'tpsl'; 43 const uint32 kMsgAddType = 'adtp'; 44 const uint32 kMsgTypeAdded = 'tpad'; 45 const uint32 kMsgRemoveType = 'rmtp'; 46 47 48 class SupportedTypeItem : public BStringItem { 49 public: 50 SupportedTypeItem(const char* type); 51 ~SupportedTypeItem(); 52 53 const char* Type() const { return fType.String(); } 54 55 static int Compare(const void* _a, const void* _b); 56 57 private: 58 BString fType; 59 }; 60 61 62 SupportedTypeItem::SupportedTypeItem(const char* type) 63 : BStringItem(type), 64 fType(type) 65 { 66 BMimeType mimeType(type); 67 68 char description[B_MIME_TYPE_LENGTH]; 69 if (mimeType.GetShortDescription(description) == B_OK && description[0]) 70 SetText(description); 71 } 72 73 74 SupportedTypeItem::~SupportedTypeItem() 75 { 76 } 77 78 79 /*static*/ 80 int 81 SupportedTypeItem::Compare(const void* _a, const void* _b) 82 { 83 const SupportedTypeItem* a = *(const SupportedTypeItem**)_a; 84 const SupportedTypeItem* b = *(const SupportedTypeItem**)_b; 85 86 return strcasecmp(a->Type(), b->Type()); 87 } 88 89 90 // #pragma mark - 91 92 93 ApplicationTypeWindow::ApplicationTypeWindow(BPoint position, const BEntry& entry) 94 : BWindow(BRect(0.0f, 0.0f, 250.0f, 340.0f).OffsetBySelf(position), 95 "Application Type", B_TITLED_WINDOW, 96 B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS) 97 { 98 // add the menu 99 100 BMenuBar* menuBar = new BMenuBar(BRect(0, 0, 0, 0), NULL); 101 AddChild(menuBar); 102 103 BMenu* menu = new BMenu("File"); 104 menu->AddItem(new BMenuItem("Save", new BMessage(kMsgSave), 'S', B_COMMAND_KEY)); 105 BMenuItem* item; 106 menu->AddItem(item = new BMenuItem("Save Into Resource File" B_UTF8_ELLIPSIS, 107 NULL)); 108 item->SetEnabled(false); 109 110 menu->AddSeparatorItem(); 111 menu->AddItem(new BMenuItem("Close", new BMessage(B_QUIT_REQUESTED), 112 'W', B_COMMAND_KEY)); 113 menuBar->AddItem(menu); 114 115 // Top view and signature 116 117 BRect rect = Bounds(); 118 rect.top = menuBar->Bounds().Height() + 1.0f; 119 BView* topView = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW); 120 topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 121 AddChild(topView); 122 123 rect = topView->Bounds().InsetByCopy(8.0f, 8.0f); 124 fSignatureControl = new BTextControl(rect, "signature", "Signature:", NULL, 125 NULL, B_FOLLOW_LEFT_RIGHT); 126 fSignatureControl->SetDivider(fSignatureControl->StringWidth( 127 fSignatureControl->Label()) + 4.0f); 128 float width, height; 129 fSignatureControl->GetPreferredSize(&width, &height); 130 fSignatureControl->ResizeTo(rect.Width(), height); 131 topView->AddChild(fSignatureControl); 132 133 // filter out invalid characters that can't be part of a MIME type name 134 BTextView* textView = fSignatureControl->TextView(); 135 textView->SetMaxBytes(B_MIME_TYPE_LENGTH); 136 const char* disallowedCharacters = "<>@,;:\"()[]?="; 137 for (int32 i = 0; disallowedCharacters[i]; i++) { 138 textView->DisallowChar(disallowedCharacters[i]); 139 } 140 141 // "Application Flags" group 142 143 BFont font(be_bold_font); 144 font_height fontHeight; 145 font.GetHeight(&fontHeight); 146 147 width = font.StringWidth("Icon") + 16.0f; 148 if (width < B_LARGE_ICON + 16.0f) 149 width = B_LARGE_ICON + 16.0f; 150 151 rect.top = fSignatureControl->Frame().bottom + 4.0f; 152 rect.bottom = rect.top + 100.0f; 153 rect.right -= width + 8.0f; 154 BBox* box = new BBox(rect, NULL, B_FOLLOW_LEFT_RIGHT); 155 topView->AddChild(box); 156 157 fFlagsCheckBox = new BCheckBox(rect, "flags", "Application Flags", 158 new BMessage(kMsgFlagsChanged)); 159 fFlagsCheckBox->SetValue(B_CONTROL_ON); 160 fFlagsCheckBox->ResizeToPreferred(); 161 box->SetLabel(fFlagsCheckBox); 162 163 rect.top = fFlagsCheckBox->Bounds().Height() + 4.0f; 164 fSingleLaunchButton = new BRadioButton(rect, "single", "Single Launch", NULL); 165 fSingleLaunchButton->ResizeToPreferred(); 166 box->AddChild(fSingleLaunchButton); 167 168 rect.OffsetBy(0.0f, fSingleLaunchButton->Bounds().Height() + 0.0f); 169 fMultipleLaunchButton = new BRadioButton(rect, "multiple", "Multiple Launch", NULL); 170 fMultipleLaunchButton->ResizeToPreferred(); 171 box->AddChild(fMultipleLaunchButton); 172 173 rect.OffsetBy(0.0f, fSingleLaunchButton->Bounds().Height() + 0.0f); 174 fExclusiveLaunchButton = new BRadioButton(rect, "exclusive", "Exclusive Launch", NULL); 175 fExclusiveLaunchButton->ResizeToPreferred(); 176 box->AddChild(fExclusiveLaunchButton); 177 178 rect.top = fSingleLaunchButton->Frame().top; 179 rect.left = fExclusiveLaunchButton->Frame().right + 4.0f; 180 fArgsOnlyCheckBox = new BCheckBox(rect, "args only", "Args Only", NULL); 181 fArgsOnlyCheckBox->ResizeToPreferred(); 182 box->AddChild(fArgsOnlyCheckBox); 183 184 rect.top += fArgsOnlyCheckBox->Bounds().Height(); 185 fBackgroundAppCheckBox = new BCheckBox(rect, "background", "Background App", NULL); 186 fBackgroundAppCheckBox->ResizeToPreferred(); 187 box->AddChild(fBackgroundAppCheckBox); 188 189 box->ResizeTo(box->Bounds().Width(), fExclusiveLaunchButton->Frame().bottom + 8.0f); 190 191 // "Icon" group 192 193 rect = box->Frame(); 194 #ifdef __HAIKU__ 195 rect.top += box->TopBorderOffset(); 196 #endif 197 rect.left = rect.right + 8.0f; 198 rect.right += width + 8.0f; 199 float iconBoxWidth = rect.Width(); 200 box = new BBox(rect, NULL, B_FOLLOW_RIGHT | B_FOLLOW_TOP); 201 box->SetLabel("Icon"); 202 #ifdef __HAIKU__ 203 box->MoveBy(0.0f, -box->TopBorderOffset()); 204 box->ResizeBy(0.0f, box->TopBorderOffset()); 205 #endif 206 topView->AddChild(box); 207 208 rect = BRect(8.0f, 0.0f, 7.0f + B_LARGE_ICON, B_LARGE_ICON - 1.0f); 209 #ifdef __HAIKU__ 210 rect.OffsetBy(0.0f, (box->Bounds().Height() + box->TopBorderOffset() 211 - rect.Height()) / 2.0f); 212 #else 213 rect.OffsetBy(0.0f, (box->Bounds().Height() - rect.Height()) / 2.0f); 214 #endif 215 if (rect.top < fontHeight.ascent + fontHeight.descent + 4.0f) 216 rect.top = fontHeight.ascent + fontHeight.descent + 4.0f; 217 fIconView = new IconView(rect, "icon"); 218 box->AddChild(fIconView); 219 220 // "Supported Types" group 221 222 rect.top = box->Frame().bottom + 8.0f; 223 rect.bottom = rect.top + box->Bounds().Height(); 224 rect.left = 8.0f; 225 rect.right = Bounds().Width() - 8.0f; 226 box = new BBox(rect, NULL, B_FOLLOW_LEFT_RIGHT); 227 box->SetLabel("Supported Types"); 228 topView->AddChild(box); 229 230 rect = box->Bounds().InsetByCopy(8.0f, 6.0f); 231 rect.top += ceilf(fontHeight.ascent); 232 fAddTypeButton = new BButton(rect, "add type", "Add" B_UTF8_ELLIPSIS, 233 new BMessage(kMsgAddType), B_FOLLOW_RIGHT); 234 fAddTypeButton->ResizeToPreferred(); 235 fAddTypeButton->MoveBy(rect.right - fAddTypeButton->Bounds().Width() 236 - B_LARGE_ICON - 16.0f, 0.0f); 237 box->AddChild(fAddTypeButton); 238 239 rect = fAddTypeButton->Frame(); 240 rect.OffsetBy(0, rect.Height() + 4.0f); 241 fRemoveTypeButton = new BButton(rect, "remove type", "Remove", 242 new BMessage(kMsgRemoveType), B_FOLLOW_RIGHT); 243 box->AddChild(fRemoveTypeButton); 244 245 rect.right = rect.left - 10.0f - B_V_SCROLL_BAR_WIDTH; 246 rect.left = 10.0f; 247 rect.top = 8.0f + ceilf(fontHeight.ascent); 248 rect.bottom -= 2.0f; 249 // take scrollview border into account 250 fTypeListView = new BListView(rect, "type listview", 251 B_SINGLE_SELECTION_LIST, B_FOLLOW_LEFT_RIGHT); 252 fTypeListView->SetSelectionMessage(new BMessage(kMsgTypeSelected)); 253 254 BScrollView* scrollView = new BScrollView("type scrollview", fTypeListView, 255 B_FOLLOW_LEFT_RIGHT, B_FRAME_EVENTS | B_WILL_DRAW, false, true); 256 box->AddChild(scrollView); 257 258 box->ResizeTo(box->Bounds().Width(), fRemoveTypeButton->Frame().bottom + 8.0f); 259 260 rect.left = fRemoveTypeButton->Frame().right + 8.0f; 261 #ifdef __HAIKU__ 262 rect.top = (box->Bounds().Height() + box->TopBorderOffset() - B_LARGE_ICON) / 2.0f; 263 #else 264 rect.top = (box->Bounds().Height() - B_LARGE_ICON) / 2.0f; 265 #endif 266 rect.right = rect.left + B_LARGE_ICON - 1.0f; 267 rect.bottom = rect.top + B_LARGE_ICON - 1.0f; 268 fTypeIconView = new IconView(rect, "type icon", B_FOLLOW_RIGHT | B_FOLLOW_TOP); 269 box->AddChild(fTypeIconView); 270 271 // "Version Info" group 272 273 rect.top = box->Frame().bottom + 8.0f; 274 rect.bottom = rect.top + box->Bounds().Height(); 275 rect.left = 8.0f; 276 rect.right = Bounds().Width() - 8.0f; 277 box = new BBox(rect, NULL, B_FOLLOW_LEFT_RIGHT); 278 // the resizing mode will later be set to B_FOLLOW_ALL 279 box->SetLabel("Version Info"); 280 topView->AddChild(box); 281 282 BMenuField* menuField; 283 #if 0 284 BPopUpMenu *popUpMenu = new BPopUpMenu("version info", true, true); 285 item = new BMenuItem("Version Info", NULL); 286 item->SetMarked(true); 287 popUpMenu->AddItem(item); 288 item = new BMenuItem("System Version Info", NULL); 289 popUpMenu->AddItem(item); 290 291 menuField = new BMenuField(BRect(0, 0, 100, 15), 292 "version kind", NULL, popUpMenu, true); 293 menuField->ResizeToPreferred(); 294 box->SetLabel(menuField); 295 #endif 296 297 rect.top = 4.0f + ceilf(fontHeight.ascent + fontHeight.descent); 298 fMajorVersionControl = new BTextControl(rect, "major", "Version:", NULL, 299 NULL); 300 fMajorVersionControl->SetDivider(fMajorVersionControl->StringWidth( 301 fMajorVersionControl->Label()) + 4.0f); 302 fMajorVersionControl->GetPreferredSize(&width, &height); 303 width = 12.0f + fMajorVersionControl->StringWidth("99"); 304 fMajorVersionControl->ResizeTo(fMajorVersionControl->Divider() + width, height); 305 _MakeNumberTextControl(fMajorVersionControl); 306 box->AddChild(fMajorVersionControl); 307 308 rect.left = fMajorVersionControl->Frame().right + 1.0f; 309 fMiddleVersionControl = new BTextControl(rect, "middle", ".", NULL, 310 NULL); 311 fMiddleVersionControl->SetDivider(fMiddleVersionControl->StringWidth( 312 fMiddleVersionControl->Label()) + 4.0f); 313 fMiddleVersionControl->ResizeTo(fMiddleVersionControl->Divider() + width, height); 314 _MakeNumberTextControl(fMiddleVersionControl); 315 box->AddChild(fMiddleVersionControl); 316 317 rect.left = fMiddleVersionControl->Frame().right + 1.0f; 318 fMinorVersionControl = new BTextControl(rect, "middle", ".", NULL, 319 NULL); 320 fMinorVersionControl->SetDivider(fMinorVersionControl->StringWidth( 321 fMinorVersionControl->Label()) + 4.0f); 322 fMinorVersionControl->ResizeTo(fMinorVersionControl->Divider() + width, height); 323 _MakeNumberTextControl(fMinorVersionControl); 324 box->AddChild(fMinorVersionControl); 325 326 fVarietyMenu = new BPopUpMenu("variety", true, true); 327 fVarietyMenu->AddItem(new BMenuItem("Development", NULL)); 328 fVarietyMenu->AddItem(new BMenuItem("Alpha", NULL)); 329 fVarietyMenu->AddItem(new BMenuItem("Beta", NULL)); 330 fVarietyMenu->AddItem(new BMenuItem("Gamma", NULL)); 331 fVarietyMenu->AddItem(item = new BMenuItem("Golden Master", NULL)); 332 item->SetMarked(true); 333 fVarietyMenu->AddItem(new BMenuItem("Final", NULL)); 334 335 rect.top--; 336 // BMenuField oddity 337 rect.left = fMinorVersionControl->Frame().right + 6.0f; 338 menuField = new BMenuField(rect, 339 "variety", NULL, fVarietyMenu, true); 340 menuField->ResizeToPreferred(); 341 box->AddChild(menuField); 342 343 rect.top++; 344 rect.left = menuField->Frame().right; 345 rect.right = rect.left + 30.0f; 346 fInternalVersionControl = new BTextControl(rect, "internal", "/", NULL, 347 NULL); 348 fInternalVersionControl->SetDivider(fInternalVersionControl->StringWidth( 349 fInternalVersionControl->Label()) + 4.0f); 350 fInternalVersionControl->ResizeTo(fInternalVersionControl->Divider() + width, height); 351 box->AddChild(fInternalVersionControl); 352 353 rect = box->Bounds().InsetByCopy(8.0f, 0.0f); 354 rect.top = fInternalVersionControl->Frame().bottom + 8.0f; 355 fShortDescriptionControl = new BTextControl(rect, "short desc", "Short Description:", 356 NULL, NULL, B_FOLLOW_LEFT_RIGHT); 357 float labelWidth = fShortDescriptionControl->StringWidth( 358 fShortDescriptionControl->Label()) + 4.0f; 359 fShortDescriptionControl->SetDivider(labelWidth); 360 fShortDescriptionControl->GetPreferredSize(&width, &height); 361 fShortDescriptionControl->ResizeTo(rect.Width(), height); 362 363 // TODO: workaround for a GCC 4.1.0 bug? Or is that really what the standard says? 364 version_info versionInfo; 365 fShortDescriptionControl->TextView()->SetMaxBytes(sizeof(versionInfo.short_info)); 366 box->AddChild(fShortDescriptionControl); 367 368 rect.OffsetBy(0.0f, fShortDescriptionControl->Bounds().Height() + 5.0f); 369 rect.right = rect.left + labelWidth; 370 StringView* label = new StringView(rect, NULL, "Long Description:", NULL); 371 label->SetDivider(labelWidth); 372 box->AddChild(label); 373 374 rect.left = rect.right + 3.0f; 375 rect.top += 1.0f; 376 rect.right = box->Bounds().Width() - 8.0f; 377 rect.bottom = rect.top + fShortDescriptionControl->Bounds().Height() * 3.0f - 1.0f; 378 fLongDescriptionView = new BTextView(rect, "long desc", 379 rect.OffsetToCopy(B_ORIGIN), B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS); 380 fLongDescriptionView->SetMaxBytes(sizeof(versionInfo.long_info)); 381 // box->AddChild(fLongDescriptionView); 382 383 scrollView = new BScrollView("desc scrollview", fLongDescriptionView, 384 B_FOLLOW_ALL, B_FRAME_EVENTS | B_WILL_DRAW, false, false); 385 box->ResizeTo(box->Bounds().Width(), scrollView->Frame().bottom + 8.0f); 386 box->AddChild(scrollView); 387 388 // Adjust window size and limits 389 390 width = fInternalVersionControl->Frame().right + 16.0f; 391 float minWidth = fBackgroundAppCheckBox->Frame().right + iconBoxWidth + 32.0f; 392 if (width > minWidth) 393 minWidth = width; 394 395 ResizeTo(Bounds().Width() > minWidth ? Bounds().Width() : minWidth, 396 box->Frame().bottom + topView->Frame().top + 8.0f); 397 SetSizeLimits(minWidth, 32767.0f, Bounds().Height(), 32767.0f); 398 box->SetResizingMode(B_FOLLOW_ALL); 399 400 fSignatureControl->MakeFocus(true); 401 402 BMimeType::StartWatching(this); 403 _SetTo(entry); 404 } 405 406 407 ApplicationTypeWindow::~ApplicationTypeWindow() 408 { 409 BMimeType::StopWatching(this); 410 } 411 412 413 BString 414 ApplicationTypeWindow::_Title(const BEntry& entry) 415 { 416 char name[B_FILE_NAME_LENGTH]; 417 if (entry.GetName(name) != B_OK) 418 strcpy(name, "\"-\""); 419 420 BString title(name); 421 title.Append(" Application Type"); 422 return title; 423 } 424 425 426 void 427 ApplicationTypeWindow::_SetTo(const BEntry& entry) 428 { 429 SetTitle(_Title(entry).String()); 430 fEntry = entry; 431 432 // Retrieve Info 433 434 BFile file(&entry, B_READ_ONLY); 435 if (file.InitCheck() != B_OK) 436 return; 437 438 BAppFileInfo info(&file); 439 if (info.InitCheck() != B_OK) 440 return; 441 442 char signature[B_MIME_TYPE_LENGTH]; 443 if (info.GetSignature(signature) != B_OK) 444 signature[0] = '\0'; 445 446 bool gotFlags = false; 447 uint32 flags; 448 if (info.GetAppFlags(&flags) == B_OK) 449 gotFlags = true; 450 else 451 flags = B_MULTIPLE_LAUNCH; 452 453 BMessage supportedTypes; 454 info.GetSupportedTypes(&supportedTypes); 455 456 version_info versionInfo; 457 if (info.GetVersionInfo(&versionInfo, B_APP_VERSION_KIND) != B_OK) 458 memset(&versionInfo, 0, sizeof(version_info)); 459 460 // Set Controls 461 462 fSignatureControl->SetText(signature); 463 464 // flags 465 466 switch (flags & (B_SINGLE_LAUNCH | B_MULTIPLE_LAUNCH | B_EXCLUSIVE_LAUNCH)) { 467 case B_SINGLE_LAUNCH: 468 fSingleLaunchButton->SetValue(B_CONTROL_ON); 469 break; 470 471 case B_EXCLUSIVE_LAUNCH: 472 fExclusiveLaunchButton->SetValue(B_CONTROL_ON); 473 break; 474 475 case B_MULTIPLE_LAUNCH: 476 default: 477 fMultipleLaunchButton->SetValue(B_CONTROL_ON); 478 break; 479 } 480 481 fArgsOnlyCheckBox->SetValue((flags & B_ARGV_ONLY) != 0); 482 fBackgroundAppCheckBox->SetValue((flags & B_BACKGROUND_APP) != 0); 483 fFlagsCheckBox->SetValue(gotFlags); 484 485 _UpdateAppFlagsEnabled(); 486 487 // icon 488 489 entry_ref ref; 490 if (entry.GetRef(&ref) == B_OK) 491 fIconView->SetTo(&ref); 492 493 // supported types 494 495 for (int32 i = fTypeListView->CountItems(); i-- > 0;) { 496 BListItem* item = fTypeListView->RemoveItem(i); 497 delete item; 498 } 499 500 const char* type; 501 for (int32 i = 0; supportedTypes.FindString("types", i, &type) == B_OK; i++) { 502 fTypeListView->AddItem(new SupportedTypeItem(type)); 503 } 504 fTypeListView->SortItems(&SupportedTypeItem::Compare); 505 fRemoveTypeButton->SetEnabled(false); 506 507 // version info 508 509 char text[256]; 510 snprintf(text, sizeof(text), "%ld", versionInfo.major); 511 fMajorVersionControl->SetText(text); 512 snprintf(text, sizeof(text), "%ld", versionInfo.middle); 513 fMiddleVersionControl->SetText(text); 514 snprintf(text, sizeof(text), "%ld", versionInfo.minor); 515 fMinorVersionControl->SetText(text); 516 517 if (versionInfo.variety >= (uint32)fVarietyMenu->CountItems()) 518 versionInfo.variety = 0; 519 BMenuItem* item = fVarietyMenu->ItemAt(versionInfo.variety); 520 if (item != NULL) 521 item->SetMarked(true); 522 523 snprintf(text, sizeof(text), "%ld", versionInfo.internal); 524 fInternalVersionControl->SetText(text); 525 526 fShortDescriptionControl->SetText(versionInfo.short_info); 527 fLongDescriptionView->SetText(versionInfo.long_info); 528 } 529 530 531 void 532 ApplicationTypeWindow::_UpdateAppFlagsEnabled() 533 { 534 bool enabled = fFlagsCheckBox->Value() != B_CONTROL_OFF; 535 536 fSingleLaunchButton->SetEnabled(enabled); 537 fMultipleLaunchButton->SetEnabled(enabled); 538 fExclusiveLaunchButton->SetEnabled(enabled); 539 fArgsOnlyCheckBox->SetEnabled(enabled); 540 fBackgroundAppCheckBox->SetEnabled(enabled); 541 } 542 543 544 void 545 ApplicationTypeWindow::_MakeNumberTextControl(BTextControl* control) 546 { 547 // filter out invalid characters that can't be part of a MIME type name 548 BTextView* textView = control->TextView(); 549 textView->SetMaxBytes(10); 550 551 for (int32 i = 0; i < 256; i++) { 552 if (!isdigit(i)) 553 textView->DisallowChar(i); 554 } 555 } 556 557 558 void 559 ApplicationTypeWindow::_Save() 560 { 561 BFile file; 562 status_t status = file.SetTo(&fEntry, B_READ_WRITE); 563 if (status != B_OK) 564 return; 565 566 BAppFileInfo info(&file); 567 status = info.InitCheck(); 568 if (status != B_OK) 569 return; 570 571 // Retrieve Info 572 573 uint32 flags = 0; 574 if (fFlagsCheckBox->Value() != B_CONTROL_OFF) { 575 if (fSingleLaunchButton->Value() != B_CONTROL_OFF) 576 flags |= B_SINGLE_LAUNCH; 577 else if (fMultipleLaunchButton->Value() != B_CONTROL_OFF) 578 flags |= B_MULTIPLE_LAUNCH; 579 else if (fExclusiveLaunchButton->Value() != B_CONTROL_OFF) 580 flags |= B_EXCLUSIVE_LAUNCH; 581 582 if (fArgsOnlyCheckBox->Value() != B_CONTROL_OFF) 583 flags |= B_ARGV_ONLY; 584 if (fBackgroundAppCheckBox->Value() != B_CONTROL_OFF) 585 flags |= B_BACKGROUND_APP; 586 } 587 588 BMessage supportedTypes; 589 for (int32 i = 0; i < fTypeListView->CountItems(); i++) { 590 SupportedTypeItem* item = dynamic_cast<SupportedTypeItem*>( 591 fTypeListView->ItemAt(i)); 592 if (item == NULL) 593 continue; 594 595 supportedTypes.AddString("types", item->Type()); 596 } 597 598 version_info versionInfo; 599 versionInfo.major = atol(fMajorVersionControl->Text()); 600 versionInfo.middle = atol(fMiddleVersionControl->Text()); 601 versionInfo.minor = atol(fMinorVersionControl->Text()); 602 versionInfo.variety = fVarietyMenu->IndexOf(fVarietyMenu->FindMarked()); 603 versionInfo.internal = atol(fInternalVersionControl->Text()); 604 strlcpy(versionInfo.short_info, fShortDescriptionControl->Text(), 605 sizeof(versionInfo.short_info)); 606 strlcpy(versionInfo.long_info, fLongDescriptionView->Text(), 607 sizeof(versionInfo.long_info)); 608 609 // Save 610 611 status = info.SetSignature(fSignatureControl->Text()); 612 if (status == B_OK) 613 status = info.SetAppFlags(flags); 614 if (status == B_OK) 615 status = info.SetVersionInfo(&versionInfo, B_APP_VERSION_KIND); 616 617 // TODO: icon & supported types icons 618 // if (status == B_OK) 619 // status = info.SetIcon(&icon); 620 621 if (status == B_OK) 622 status = info.SetSupportedTypes(&supportedTypes); 623 } 624 625 626 void 627 ApplicationTypeWindow::FrameResized(float width, float height) 628 { 629 // This works around a flaw of BTextView 630 fLongDescriptionView->SetTextRect(fLongDescriptionView->Bounds()); 631 } 632 633 634 void 635 ApplicationTypeWindow::MessageReceived(BMessage* message) 636 { 637 switch (message->what) { 638 case kMsgFlagsChanged: 639 _UpdateAppFlagsEnabled(); 640 break; 641 642 case kMsgSave: 643 _Save(); 644 break; 645 646 case kMsgTypeSelected: 647 { 648 int32 index; 649 if (message->FindInt32("index", &index) == B_OK) { 650 BStringItem* item = (BStringItem*)fTypeListView->ItemAt(index); 651 fRemoveTypeButton->SetEnabled(item != NULL); 652 } 653 break; 654 } 655 656 case kMsgAddType: 657 { 658 BWindow* window = new TypeListWindow(NULL, 659 kMsgTypeAdded, this); 660 window->Show(); 661 break; 662 } 663 664 case kMsgTypeAdded: 665 { 666 const char* type; 667 if (message->FindString("type", &type) != B_OK) 668 break; 669 670 // check if this type already exists 671 672 SupportedTypeItem* newItem = new SupportedTypeItem(type); 673 int32 insertAt = 0; 674 675 for (int32 i = fTypeListView->CountItems(); i-- > 0;) { 676 SupportedTypeItem* item = dynamic_cast<SupportedTypeItem*>( 677 fTypeListView->ItemAt(i)); 678 if (item == NULL) 679 continue; 680 681 int compare = strcasecmp(item->Type(), type); 682 if (!compare) { 683 // type does already exist, select it and bail out 684 delete newItem; 685 newItem = NULL; 686 fTypeListView->Select(i); 687 break; 688 } 689 if (compare < 0) 690 insertAt = i + 1; 691 } 692 693 if (newItem == NULL) 694 break; 695 696 fTypeListView->AddItem(newItem, insertAt); 697 fTypeListView->Select(insertAt); 698 break; 699 } 700 701 case kMsgRemoveType: 702 { 703 int32 index = fTypeListView->CurrentSelection(); 704 if (index < 0) 705 break; 706 707 delete fTypeListView->RemoveItem(index); 708 break; 709 } 710 711 case B_SIMPLE_DATA: 712 { 713 entry_ref ref; 714 if (message->FindRef("refs", &ref) != B_OK) 715 break; 716 717 // TODO: add to supported types 718 break; 719 } 720 721 case B_META_MIME_CHANGED: 722 const char* type; 723 int32 which; 724 if (message->FindString("be:type", &type) != B_OK 725 || message->FindInt32("be:which", &which) != B_OK) 726 break; 727 728 // TODO: update supported types names 729 // if (which == B_MIME_TYPE_DELETED) 730 break; 731 732 default: 733 BWindow::MessageReceived(message); 734 } 735 } 736 737 738 bool 739 ApplicationTypeWindow::QuitRequested() 740 { 741 be_app->PostMessage(kMsgTypeWindowClosed); 742 return true; 743 } 744 745