1 /* 2 * Copyright 2006-2010, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "AttributeListView.h" 8 #include "AttributeWindow.h" 9 #include "DropTargetListView.h" 10 #include "ExtensionWindow.h" 11 #include "FileTypes.h" 12 #include "FileTypesWindow.h" 13 #include "IconView.h" 14 #include "MimeTypeListView.h" 15 #include "NewFileTypeWindow.h" 16 #include "PreferredAppMenu.h" 17 #include "StringView.h" 18 19 #include <Alignment.h> 20 #include <AppFileInfo.h> 21 #include <Application.h> 22 #include <Bitmap.h> 23 #include <Box.h> 24 #include <Button.h> 25 #include <Catalog.h> 26 #include <ControlLook.h> 27 #include <GridLayoutBuilder.h> 28 #include <GroupLayoutBuilder.h> 29 #include <ListView.h> 30 #include <Locale.h> 31 #include <MenuBar.h> 32 #include <MenuField.h> 33 #include <MenuItem.h> 34 #include <Mime.h> 35 #include <NodeInfo.h> 36 #include <OutlineListView.h> 37 #include <PopUpMenu.h> 38 #include <ScrollView.h> 39 #include <SpaceLayoutItem.h> 40 #include <SplitView.h> 41 #include <TextControl.h> 42 43 #include <OverrideAlert.h> 44 #include <be_apps/Tracker/RecentItems.h> 45 46 #include <stdio.h> 47 #include <stdlib.h> 48 49 50 #undef B_TRANSLATE_CONTEXT 51 #define B_TRANSLATE_CONTEXT "FileTypes Window" 52 53 54 const uint32 kMsgTypeSelected = 'typs'; 55 const uint32 kMsgAddType = 'atyp'; 56 const uint32 kMsgRemoveType = 'rtyp'; 57 58 const uint32 kMsgExtensionSelected = 'exts'; 59 const uint32 kMsgExtensionInvoked = 'exti'; 60 const uint32 kMsgAddExtension = 'aext'; 61 const uint32 kMsgRemoveExtension = 'rext'; 62 const uint32 kMsgRuleEntered = 'rule'; 63 64 const uint32 kMsgAttributeSelected = 'atrs'; 65 const uint32 kMsgAttributeInvoked = 'atri'; 66 const uint32 kMsgAddAttribute = 'aatr'; 67 const uint32 kMsgRemoveAttribute = 'ratr'; 68 69 const uint32 kMsgPreferredAppChosen = 'papc'; 70 const uint32 kMsgSelectPreferredApp = 'slpa'; 71 const uint32 kMsgSamePreferredAppAs = 'spaa'; 72 73 const uint32 kMsgPreferredAppOpened = 'paOp'; 74 const uint32 kMsgSamePreferredAppAsOpened = 'spaO'; 75 76 const uint32 kMsgTypeEntered = 'type'; 77 const uint32 kMsgDescriptionEntered = 'dsce'; 78 79 const uint32 kMsgToggleIcons = 'tgic'; 80 const uint32 kMsgToggleRule = 'tgrl'; 81 82 83 class TypeIconView : public IconView { 84 public: 85 TypeIconView(const char* name); 86 virtual ~TypeIconView(); 87 88 virtual void Draw(BRect updateRect); 89 virtual void GetPreferredSize(float* _width, float* _height); 90 91 protected: 92 virtual BRect BitmapRect() const; 93 }; 94 95 96 class ExtensionListView : public DropTargetListView { 97 public: 98 ExtensionListView(const char* name, 99 list_view_type type = B_SINGLE_SELECTION_LIST, 100 uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE); 101 virtual ~ExtensionListView(); 102 103 virtual void MessageReceived(BMessage* message); 104 virtual bool AcceptsDrag(const BMessage* message); 105 106 void SetType(BMimeType* type); 107 108 private: 109 BMimeType fType; 110 }; 111 112 113 // #pragma mark - 114 115 116 TypeIconView::TypeIconView(const char* name) 117 : IconView(name) 118 { 119 ShowEmptyFrame(false); 120 SetIconSize(48); 121 } 122 123 124 TypeIconView::~TypeIconView() 125 { 126 } 127 128 129 void 130 TypeIconView::Draw(BRect updateRect) 131 { 132 if (!IsEnabled()) 133 return; 134 135 IconView::Draw(updateRect); 136 137 const char* text = NULL; 138 139 switch (IconSource()) { 140 case kNoIcon: 141 text = B_TRANSLATE("no icon"); 142 break; 143 case kApplicationIcon: 144 text = B_TRANSLATE("(from application)"); 145 break; 146 case kSupertypeIcon: 147 text = B_TRANSLATE("(from super type)"); 148 break; 149 150 default: 151 return; 152 } 153 154 SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 155 B_DISABLED_LABEL_TINT)); 156 SetLowColor(ViewColor()); 157 158 font_height fontHeight; 159 GetFontHeight(&fontHeight); 160 161 float y = fontHeight.ascent; 162 if (IconSource() == kNoIcon) { 163 // center text in the middle of the icon 164 y += (IconSize() - fontHeight.ascent - fontHeight.descent) / 2.0f; 165 } else 166 y += IconSize() + 3.0f; 167 168 DrawString(text, BPoint(ceilf((Bounds().Width() - StringWidth(text)) / 2.0f), 169 ceilf(y))); 170 } 171 172 173 void 174 TypeIconView::GetPreferredSize(float* _width, float* _height) 175 { 176 if (_width) { 177 float a = StringWidth(B_TRANSLATE("(from application)")); 178 float b = StringWidth(B_TRANSLATE("(from super type)")); 179 float width = max_c(a, b); 180 if (width < IconSize()) 181 width = IconSize(); 182 183 *_width = ceilf(width); 184 } 185 186 if (_height) { 187 font_height fontHeight; 188 GetFontHeight(&fontHeight); 189 190 *_height = IconSize() + 3.0f + ceilf(fontHeight.ascent 191 + fontHeight.descent); 192 } 193 } 194 195 196 BRect 197 TypeIconView::BitmapRect() const 198 { 199 if (IconSource() == kNoIcon) { 200 // this also defines the drop target area 201 font_height fontHeight; 202 GetFontHeight(&fontHeight); 203 204 float width = StringWidth(B_TRANSLATE("no icon")) + 8.0f; 205 float height = ceilf(fontHeight.ascent + fontHeight.descent) + 6.0f; 206 float x = (Bounds().Width() - width) / 2.0f; 207 float y = ceilf((IconSize() - fontHeight.ascent - fontHeight.descent) 208 / 2.0f) - 3.0f; 209 210 return BRect(x, y, x + width, y + height); 211 } 212 213 float x = (Bounds().Width() - IconSize()) / 2.0f; 214 return BRect(x, 0.0f, x + IconSize() - 1, IconSize() - 1); 215 } 216 217 218 // #pragma mark - 219 220 221 ExtensionListView::ExtensionListView(const char* name, 222 list_view_type type, uint32 flags) 223 : 224 DropTargetListView(name, type, flags) 225 { 226 } 227 228 229 ExtensionListView::~ExtensionListView() 230 { 231 } 232 233 234 void 235 ExtensionListView::MessageReceived(BMessage* message) 236 { 237 if (message->WasDropped() && AcceptsDrag(message)) { 238 // create extension list 239 BList list; 240 entry_ref ref; 241 for (int32 index = 0; message->FindRef("refs", index, &ref) == B_OK; 242 index++) { 243 const char* point = strchr(ref.name, '.'); 244 if (point != NULL && point[1]) 245 list.AddItem(strdup(++point)); 246 } 247 248 merge_extensions(fType, list); 249 250 // delete extension list 251 for (int32 index = list.CountItems(); index-- > 0;) { 252 free(list.ItemAt(index)); 253 } 254 } else 255 DropTargetListView::MessageReceived(message); 256 } 257 258 259 bool 260 ExtensionListView::AcceptsDrag(const BMessage* message) 261 { 262 if (fType.Type() == NULL) 263 return false; 264 265 int32 count = 0; 266 entry_ref ref; 267 268 for (int32 index = 0; message->FindRef("refs", index, &ref) == B_OK; 269 index++) { 270 const char* point = strchr(ref.name, '.'); 271 if (point != NULL && point[1]) 272 count++; 273 } 274 275 return count > 0; 276 } 277 278 279 void 280 ExtensionListView::SetType(BMimeType* type) 281 { 282 if (type != NULL) 283 fType.SetTo(type->Type()); 284 else 285 fType.Unset(); 286 } 287 288 289 // #pragma mark - 290 291 292 FileTypesWindow::FileTypesWindow(const BMessage& settings) 293 : 294 BWindow(_Frame(settings), B_TRANSLATE("FileTypes"), B_TITLED_WINDOW, 295 B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 296 fNewTypeWindow(NULL) 297 { 298 bool showIcons; 299 bool showRule; 300 if (settings.FindBool("show_icons", &showIcons) != B_OK) 301 showIcons = true; 302 if (settings.FindBool("show_rule", &showRule) != B_OK) 303 showRule = false; 304 305 SetLayout(new BGroupLayout(B_VERTICAL)); 306 307 float padding = be_control_look->DefaultItemSpacing(); 308 BAlignment labelAlignment = be_control_look->DefaultLabelAlignment(); 309 BAlignment fullAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); 310 311 // add the menu 312 BMenuBar* menuBar = new BMenuBar(""); 313 314 BMenu* menu = new BMenu(B_TRANSLATE("File")); 315 BMenuItem* item = new BMenuItem( 316 B_TRANSLATE("New resource file" B_UTF8_ELLIPSIS), NULL, 'N', 317 B_COMMAND_KEY); 318 item->SetEnabled(false); 319 menu->AddItem(item); 320 321 BMenu* recentsMenu = BRecentFilesList::NewFileListMenu( 322 B_TRANSLATE("Open" B_UTF8_ELLIPSIS), NULL, NULL, 323 be_app, 10, false, NULL, kSignature); 324 item = new BMenuItem(recentsMenu, new BMessage(kMsgOpenFilePanel)); 325 item->SetShortcut('O', B_COMMAND_KEY); 326 menu->AddItem(item); 327 328 menu->AddItem(new BMenuItem( 329 B_TRANSLATE("Application types" B_UTF8_ELLIPSIS), 330 new BMessage(kMsgOpenApplicationTypesWindow))); 331 menu->AddSeparatorItem(); 332 333 menu->AddItem(new BMenuItem(B_TRANSLATE("About FileTypes" B_UTF8_ELLIPSIS), 334 new BMessage(B_ABOUT_REQUESTED))); 335 menu->AddSeparatorItem(); 336 337 menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"), 338 new BMessage(B_QUIT_REQUESTED), 'Q', B_COMMAND_KEY)); 339 menu->SetTargetForItems(be_app); 340 menuBar->AddItem(menu); 341 342 menu = new BMenu(B_TRANSLATE("Settings")); 343 item = new BMenuItem(B_TRANSLATE("Show icons in list"), 344 new BMessage(kMsgToggleIcons)); 345 item->SetMarked(showIcons); 346 item->SetTarget(this); 347 menu->AddItem(item); 348 349 item = new BMenuItem(B_TRANSLATE("Show recognition rule"), 350 new BMessage(kMsgToggleRule)); 351 item->SetMarked(showRule); 352 item->SetTarget(this); 353 menu->AddItem(item); 354 menuBar->AddItem(menu); 355 356 AddChild(menuBar); 357 menuBar->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP)); 358 359 // MIME Types list 360 BButton* addTypeButton = new BButton("add", 361 B_TRANSLATE("Add" B_UTF8_ELLIPSIS), new BMessage(kMsgAddType)); 362 363 fRemoveTypeButton = new BButton("remove", B_TRANSLATE("Remove"), 364 new BMessage(kMsgRemoveType) ); 365 366 fTypeListView = new MimeTypeListView("typeview", NULL, showIcons, false); 367 fTypeListView->SetSelectionMessage(new BMessage(kMsgTypeSelected)); 368 fTypeListView->SetExplicitMinSize(BSize(200, B_SIZE_UNSET)); 369 370 BScrollView* typeListScrollView = new BScrollView("scrollview", 371 fTypeListView, B_FRAME_EVENTS | B_WILL_DRAW, false, true); 372 373 // "Icon" group 374 375 fIconView = new TypeIconView("icon"); 376 fIconBox = new BBox("Icon BBox"); 377 fIconBox->SetLabel(B_TRANSLATE("Icon")); 378 fIconBox->AddChild(BGroupLayoutBuilder(B_VERTICAL, padding) 379 .Add(BSpaceLayoutItem::CreateGlue(), 1) 380 .Add(fIconView, 3) 381 .Add(BSpaceLayoutItem::CreateGlue(), 1) 382 .SetInsets(padding, padding, padding, padding)); 383 384 // "File Recognition" group 385 386 fRecognitionBox = new BBox("Recognition Box"); 387 fRecognitionBox->SetLabel(B_TRANSLATE("File recognition")); 388 fRecognitionBox->SetExplicitAlignment(fullAlignment); 389 390 fExtensionLabel = new StringView(B_TRANSLATE("Extensions:"), NULL); 391 fExtensionLabel->LabelView()->SetExplicitAlignment(labelAlignment); 392 393 fAddExtensionButton = new BButton("add ext", 394 B_TRANSLATE("Add" B_UTF8_ELLIPSIS), new BMessage(kMsgAddExtension)); 395 fAddExtensionButton->SetExplicitMaxSize( 396 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 397 398 fRemoveExtensionButton = new BButton("remove ext", B_TRANSLATE("Remove"), 399 new BMessage(kMsgRemoveExtension)); 400 401 fExtensionListView = new ExtensionListView("listview ext", 402 B_SINGLE_SELECTION_LIST); 403 fExtensionListView->SetSelectionMessage( 404 new BMessage(kMsgExtensionSelected)); 405 fExtensionListView->SetInvocationMessage( 406 new BMessage(kMsgExtensionInvoked)); 407 408 BScrollView* scrollView = new BScrollView("scrollview ext", 409 fExtensionListView, B_FRAME_EVENTS | B_WILL_DRAW, false, true); 410 411 fRuleControl = new BTextControl("rule", B_TRANSLATE("Rule:"), "", 412 new BMessage(kMsgRuleEntered)); 413 fRuleControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT); 414 fRuleControl->Hide(); 415 416 BView* recognitionBoxGrid = BGridLayoutBuilder(padding, padding / 2) 417 .Add(fExtensionLabel->LabelView(), 0, 0) 418 .Add(scrollView, 0, 1, 2, 3) 419 .Add(fAddExtensionButton, 2, 1) 420 .Add(fRemoveExtensionButton, 2, 2) 421 .Add(fRuleControl, 0, 4, 3, 1) 422 .SetInsets(padding, padding, padding, padding); 423 424 recognitionBoxGrid->SetExplicitAlignment(fullAlignment); 425 fRecognitionBox->AddChild(recognitionBoxGrid); 426 427 // "Description" group 428 429 fDescriptionBox = new BBox("description BBox"); 430 fDescriptionBox->SetLabel(B_TRANSLATE("Description")); 431 fDescriptionBox->SetExplicitAlignment(fullAlignment); 432 433 fInternalNameView = new StringView(B_TRANSLATE("Internal name:"), NULL); 434 fInternalNameView->SetEnabled(false); 435 fTypeNameControl = new BTextControl("type", B_TRANSLATE("Type name:"), "", 436 new BMessage(kMsgTypeEntered)); 437 fDescriptionControl = new BTextControl("description", 438 B_TRANSLATE("Description:"), "", new BMessage(kMsgDescriptionEntered)); 439 440 fDescriptionBox->AddChild(BGridLayoutBuilder(padding / 2, padding / 2) 441 .Add(fInternalNameView->LabelView(), 0, 0) 442 .Add(fInternalNameView->TextView(), 1, 0) 443 .Add(fTypeNameControl->CreateLabelLayoutItem(), 0, 1) 444 .Add(fTypeNameControl->CreateTextViewLayoutItem(), 1, 1, 2) 445 .Add(fDescriptionControl->CreateLabelLayoutItem(), 0, 2) 446 .Add(fDescriptionControl->CreateTextViewLayoutItem(), 1, 2, 2) 447 .SetInsets(padding, padding, padding, padding)); 448 449 // "Preferred Application" group 450 451 fPreferredBox = new BBox("preferred BBox"); 452 fPreferredBox->SetLabel(B_TRANSLATE("Preferred application")); 453 454 menu = new BPopUpMenu("preferred"); 455 menu->AddItem(item = new BMenuItem(B_TRANSLATE("None"), 456 new BMessage(kMsgPreferredAppChosen))); 457 item->SetMarked(true); 458 fPreferredField = new BMenuField("preferred", (char*)NULL, menu); 459 460 fSelectButton = new BButton("select", 461 B_TRANSLATE("Select" B_UTF8_ELLIPSIS), 462 new BMessage(kMsgSelectPreferredApp)); 463 464 fSameAsButton = new BButton("same as", 465 B_TRANSLATE("Same as" B_UTF8_ELLIPSIS), 466 new BMessage(kMsgSamePreferredAppAs)); 467 468 fPreferredBox->AddChild(BGroupLayoutBuilder(B_HORIZONTAL, padding) 469 .Add(fPreferredField) 470 .Add(fSelectButton) 471 .Add(fSameAsButton) 472 .SetInsets(padding, padding, padding, padding)); 473 474 // "Extra Attributes" group 475 476 fAttributeBox = new BBox("Attribute Box"); 477 fAttributeBox->SetLabel(B_TRANSLATE("Extra attributes")); 478 479 fAddAttributeButton = new BButton("add attr", 480 "Add" B_UTF8_ELLIPSIS, new BMessage(kMsgAddAttribute)); 481 fAddAttributeButton->SetExplicitMaxSize( 482 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 483 484 fRemoveAttributeButton = new BButton("remove attr", B_TRANSLATE("Remove"), 485 new BMessage(kMsgRemoveAttribute)); 486 487 fAttributeListView = new AttributeListView("listview attr"); 488 fAttributeListView->SetSelectionMessage( 489 new BMessage(kMsgAttributeSelected)); 490 fAttributeListView->SetInvocationMessage( 491 new BMessage(kMsgAttributeInvoked)); 492 493 BScrollView* attributesScroller = new BScrollView("scrollview attr", 494 fAttributeListView, B_FRAME_EVENTS | B_WILL_DRAW, false, true); 495 496 fAttributeBox->AddChild(BGridLayoutBuilder(padding, padding / 2) 497 .Add(attributesScroller, 0, 0, 2, 3) 498 .Add(fAddAttributeButton, 2, 0) 499 .Add(fRemoveAttributeButton, 2, 1) 500 .SetInsets(padding, padding, padding, padding)); 501 502 BView* topView = BGroupLayoutBuilder(B_HORIZONTAL, padding) 503 .SetInsets(padding, padding, padding, padding) 504 .Add(BGroupLayoutBuilder(B_VERTICAL, padding) 505 .Add(typeListScrollView) 506 .Add(BGroupLayoutBuilder(B_HORIZONTAL, padding) 507 .Add(addTypeButton) 508 .Add(fRemoveTypeButton) 509 .AddGlue())) 510 // Right side 511 .Add(BGroupLayoutBuilder(B_VERTICAL, padding) 512 .Add(BGroupLayoutBuilder(B_HORIZONTAL, padding) 513 .Add(fIconBox, 1).Add(fRecognitionBox, 3)) 514 .Add(fDescriptionBox) 515 .Add(fPreferredBox) 516 .Add(fAttributeBox, 5)); 517 518 //topView->SetExplicitAlignment(fullAlignment); 519 //topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 520 AddChild(topView); 521 522 _SetType(NULL); 523 _ShowSnifferRule(showRule); 524 525 BMimeType::StartWatching(this); 526 } 527 528 529 FileTypesWindow::~FileTypesWindow() 530 { 531 BMimeType::StopWatching(this); 532 } 533 534 535 BRect 536 FileTypesWindow::_Frame(const BMessage& settings) const 537 { 538 BRect rect; 539 if (settings.FindRect("file_types_frame", &rect) == B_OK) 540 return rect; 541 542 return BRect(80.0f, 80.0f, 0.0f, 0.0f); 543 } 544 545 546 void 547 FileTypesWindow::_ShowSnifferRule(bool show) 548 { 549 if (fRuleControl->IsHidden() == !show) 550 return; 551 552 if (!show) 553 fRuleControl->Hide(); 554 else 555 fRuleControl->Show(); 556 } 557 558 559 void 560 FileTypesWindow::_UpdateExtensions(BMimeType* type) 561 { 562 // clear list 563 564 for (int32 i = fExtensionListView->CountItems(); i-- > 0;) { 565 delete fExtensionListView->ItemAt(i); 566 } 567 fExtensionListView->MakeEmpty(); 568 569 // fill it again 570 571 if (type == NULL) 572 return; 573 574 BMessage extensions; 575 if (type->GetFileExtensions(&extensions) != B_OK) 576 return; 577 578 const char* extension; 579 int32 i = 0; 580 while (extensions.FindString("extensions", i++, &extension) == B_OK) { 581 char dotExtension[B_FILE_NAME_LENGTH]; 582 snprintf(dotExtension, B_FILE_NAME_LENGTH, ".%s", extension); 583 584 fExtensionListView->AddItem(new BStringItem(dotExtension)); 585 } 586 } 587 588 589 void 590 FileTypesWindow::_AdoptPreferredApplication(BMessage* message, bool sameAs) 591 { 592 if (fCurrentType.Type() == NULL) 593 return; 594 595 BString preferred; 596 if (retrieve_preferred_app(message, sameAs, fCurrentType.Type(), preferred) 597 != B_OK) { 598 return; 599 } 600 601 status_t status = fCurrentType.SetPreferredApp(preferred.String()); 602 if (status != B_OK) 603 error_alert(B_TRANSLATE("Could not set preferred application"), 604 status); 605 } 606 607 608 void 609 FileTypesWindow::_UpdatePreferredApps(BMimeType* type) 610 { 611 update_preferred_app_menu(fPreferredField->Menu(), type, 612 kMsgPreferredAppChosen); 613 } 614 615 616 void 617 FileTypesWindow::_UpdateIcon(BMimeType* type) 618 { 619 if (type != NULL) 620 fIconView->SetTo(*type); 621 else 622 fIconView->Unset(); 623 } 624 625 626 void 627 FileTypesWindow::_SetType(BMimeType* type, int32 forceUpdate) 628 { 629 bool enabled = type != NULL; 630 631 // update controls 632 633 if (type != NULL) { 634 if (fCurrentType == *type) { 635 if (!forceUpdate) 636 return; 637 } else 638 forceUpdate = B_EVERYTHING_CHANGED; 639 640 if (&fCurrentType != type) 641 fCurrentType.SetTo(type->Type()); 642 643 fInternalNameView->SetText(type->Type()); 644 645 char description[B_MIME_TYPE_LENGTH]; 646 647 if ((forceUpdate & B_SHORT_DESCRIPTION_CHANGED) != 0) { 648 if (type->GetShortDescription(description) != B_OK) 649 description[0] = '\0'; 650 fTypeNameControl->SetText(description); 651 } 652 653 if ((forceUpdate & B_LONG_DESCRIPTION_CHANGED) != 0) { 654 if (type->GetLongDescription(description) != B_OK) 655 description[0] = '\0'; 656 fDescriptionControl->SetText(description); 657 } 658 659 if ((forceUpdate & B_SNIFFER_RULE_CHANGED) != 0) { 660 BString rule; 661 if (type->GetSnifferRule(&rule) != B_OK) 662 rule = ""; 663 fRuleControl->SetText(rule.String()); 664 } 665 666 fExtensionListView->SetType(&fCurrentType); 667 } else { 668 fCurrentType.Unset(); 669 fInternalNameView->SetText(NULL); 670 fTypeNameControl->SetText(NULL); 671 fDescriptionControl->SetText(NULL); 672 fRuleControl->SetText(NULL); 673 fPreferredField->Menu()->ItemAt(0)->SetMarked(true); 674 fExtensionListView->SetType(NULL); 675 fAttributeListView->SetTo(NULL); 676 } 677 678 if ((forceUpdate & B_FILE_EXTENSIONS_CHANGED) != 0) 679 _UpdateExtensions(type); 680 681 if ((forceUpdate & B_PREFERRED_APP_CHANGED) != 0) 682 _UpdatePreferredApps(type); 683 684 if ((forceUpdate & (B_ICON_CHANGED | B_PREFERRED_APP_CHANGED)) != 0) 685 _UpdateIcon(type); 686 687 if ((forceUpdate & B_ATTR_INFO_CHANGED) != 0) 688 fAttributeListView->SetTo(type); 689 690 // enable/disable controls 691 692 fIconView->SetEnabled(enabled); 693 694 fInternalNameView->SetEnabled(enabled); 695 fTypeNameControl->SetEnabled(enabled); 696 fDescriptionControl->SetEnabled(enabled); 697 fPreferredField->SetEnabled(enabled); 698 699 fRemoveTypeButton->SetEnabled(enabled); 700 701 fSelectButton->SetEnabled(enabled); 702 fSameAsButton->SetEnabled(enabled); 703 704 fExtensionLabel->SetEnabled(enabled); 705 fAddExtensionButton->SetEnabled(enabled); 706 fRemoveExtensionButton->SetEnabled(false); 707 fRuleControl->SetEnabled(enabled); 708 709 fAddAttributeButton->SetEnabled(enabled); 710 fRemoveAttributeButton->SetEnabled(false); 711 } 712 713 714 void 715 FileTypesWindow::PlaceSubWindow(BWindow* window) 716 { 717 window->MoveTo(Frame().left + (Frame().Width() - window->Frame().Width()) 718 / 2.0f, Frame().top + (Frame().Height() - window->Frame().Height()) 719 / 2.0f); 720 } 721 722 723 void 724 FileTypesWindow::MessageReceived(BMessage* message) 725 { 726 switch (message->what) { 727 case B_SIMPLE_DATA: 728 { 729 type_code type; 730 if (message->GetInfo("refs", &type) == B_OK 731 && type == B_REF_TYPE) { 732 be_app->PostMessage(message); 733 } 734 break; 735 } 736 737 case kMsgToggleIcons: 738 { 739 BMenuItem* item; 740 if (message->FindPointer("source", (void **)&item) != B_OK) 741 break; 742 743 item->SetMarked(!fTypeListView->IsShowingIcons()); 744 fTypeListView->ShowIcons(item->IsMarked()); 745 746 // update settings 747 BMessage update(kMsgSettingsChanged); 748 update.AddBool("show_icons", item->IsMarked()); 749 be_app_messenger.SendMessage(&update); 750 break; 751 } 752 753 case kMsgToggleRule: 754 { 755 BMenuItem* item; 756 if (message->FindPointer("source", (void **)&item) != B_OK) 757 break; 758 759 item->SetMarked(fRuleControl->IsHidden()); 760 _ShowSnifferRule(item->IsMarked()); 761 762 // update settings 763 BMessage update(kMsgSettingsChanged); 764 update.AddBool("show_rule", item->IsMarked()); 765 be_app_messenger.SendMessage(&update); 766 break; 767 } 768 769 case kMsgTypeSelected: 770 { 771 int32 index; 772 if (message->FindInt32("index", &index) == B_OK) { 773 MimeTypeItem* item 774 = (MimeTypeItem*)fTypeListView->ItemAt(index); 775 if (item != NULL) { 776 BMimeType type(item->Type()); 777 _SetType(&type); 778 } else 779 _SetType(NULL); 780 } 781 break; 782 } 783 784 case kMsgAddType: 785 if (fNewTypeWindow == NULL) { 786 fNewTypeWindow 787 = new NewFileTypeWindow(this, fCurrentType.Type()); 788 fNewTypeWindow->Show(); 789 } else 790 fNewTypeWindow->Activate(); 791 break; 792 793 case kMsgNewTypeWindowClosed: 794 fNewTypeWindow = NULL; 795 break; 796 797 case kMsgRemoveType: 798 { 799 if (fCurrentType.Type() == NULL) 800 break; 801 802 BAlert* alert; 803 if (fCurrentType.IsSupertypeOnly()) { 804 alert = new BPrivate::OverrideAlert( 805 B_TRANSLATE("FileTypes request"), 806 B_TRANSLATE("Removing a super type cannot be reverted.\n" 807 "All file types that belong to this super type " 808 "will be lost!\n\n" 809 "Are you sure you want to do this? To remove the whole " 810 "group, hold down the Shift key and press \"Remove\"."), 811 B_TRANSLATE("Remove"), B_SHIFT_KEY, B_TRANSLATE("Cancel"), 812 0, NULL, 0, B_WIDTH_AS_USUAL, B_STOP_ALERT); 813 } else { 814 alert = new BAlert(B_TRANSLATE("FileTypes request"), 815 B_TRANSLATE("Removing a file type cannot be reverted.\n" 816 "Are you sure you want to remove it?"), 817 B_TRANSLATE("Remove"), B_TRANSLATE("Cancel"), 818 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 819 } 820 if (alert->Go()) 821 break; 822 823 status_t status = fCurrentType.Delete(); 824 if (status != B_OK) { 825 fprintf(stderr, B_TRANSLATE( 826 "Could not remove file type: %s\n"), strerror(status)); 827 } 828 break; 829 } 830 831 case kMsgSelectNewType: 832 { 833 const char* type; 834 if (message->FindString("type", &type) == B_OK) 835 fTypeListView->SelectNewType(type); 836 break; 837 } 838 839 // File Recognition group 840 841 case kMsgExtensionSelected: 842 { 843 int32 index; 844 if (message->FindInt32("index", &index) == B_OK) { 845 BStringItem* item 846 = (BStringItem*)fExtensionListView->ItemAt(index); 847 fRemoveExtensionButton->SetEnabled(item != NULL); 848 } 849 break; 850 } 851 852 case kMsgExtensionInvoked: 853 { 854 if (fCurrentType.Type() == NULL) 855 break; 856 857 int32 index; 858 if (message->FindInt32("index", &index) == B_OK) { 859 BStringItem* item 860 = (BStringItem*)fExtensionListView->ItemAt(index); 861 if (item == NULL) 862 break; 863 864 BWindow* window 865 = new ExtensionWindow(this, fCurrentType, item->Text()); 866 window->Show(); 867 } 868 break; 869 } 870 871 case kMsgAddExtension: 872 { 873 if (fCurrentType.Type() == NULL) 874 break; 875 876 BWindow* window = new ExtensionWindow(this, fCurrentType, NULL); 877 window->Show(); 878 break; 879 } 880 881 case kMsgRemoveExtension: 882 { 883 int32 index = fExtensionListView->CurrentSelection(); 884 if (index < 0 || fCurrentType.Type() == NULL) 885 break; 886 887 BMessage extensions; 888 if (fCurrentType.GetFileExtensions(&extensions) == B_OK) { 889 extensions.RemoveData("extensions", index); 890 fCurrentType.SetFileExtensions(&extensions); 891 } 892 break; 893 } 894 895 case kMsgRuleEntered: 896 { 897 // check rule 898 BString parseError; 899 if (BMimeType::CheckSnifferRule(fRuleControl->Text(), 900 &parseError) != B_OK) { 901 parseError.Prepend( 902 B_TRANSLATE("Recognition rule is not valid:\n\n")); 903 error_alert(parseError.String()); 904 } else 905 fCurrentType.SetSnifferRule(fRuleControl->Text()); 906 break; 907 } 908 909 // Description group 910 911 case kMsgTypeEntered: 912 { 913 fCurrentType.SetShortDescription(fTypeNameControl->Text()); 914 break; 915 } 916 917 case kMsgDescriptionEntered: 918 { 919 fCurrentType.SetLongDescription(fDescriptionControl->Text()); 920 break; 921 } 922 923 // Preferred Application group 924 925 case kMsgPreferredAppChosen: 926 { 927 const char* signature; 928 if (message->FindString("signature", &signature) != B_OK) 929 signature = NULL; 930 931 fCurrentType.SetPreferredApp(signature); 932 break; 933 } 934 935 case kMsgSelectPreferredApp: 936 { 937 BMessage panel(kMsgOpenFilePanel); 938 panel.AddString("title", 939 B_TRANSLATE("Select preferred application")); 940 panel.AddInt32("message", kMsgPreferredAppOpened); 941 panel.AddMessenger("target", this); 942 943 be_app_messenger.SendMessage(&panel); 944 break; 945 } 946 case kMsgPreferredAppOpened: 947 _AdoptPreferredApplication(message, false); 948 break; 949 950 case kMsgSamePreferredAppAs: 951 { 952 BMessage panel(kMsgOpenFilePanel); 953 panel.AddString("title", 954 B_TRANSLATE("Select same preferred application as")); 955 panel.AddInt32("message", kMsgSamePreferredAppAsOpened); 956 panel.AddMessenger("target", this); 957 958 be_app_messenger.SendMessage(&panel); 959 break; 960 } 961 case kMsgSamePreferredAppAsOpened: 962 _AdoptPreferredApplication(message, true); 963 break; 964 965 // Extra Attributes group 966 967 case kMsgAttributeSelected: 968 { 969 int32 index; 970 if (message->FindInt32("index", &index) == B_OK) { 971 AttributeItem* item 972 = (AttributeItem*)fAttributeListView->ItemAt(index); 973 fRemoveAttributeButton->SetEnabled(item != NULL); 974 } 975 break; 976 } 977 978 case kMsgAttributeInvoked: 979 { 980 if (fCurrentType.Type() == NULL) 981 break; 982 983 int32 index; 984 if (message->FindInt32("index", &index) == B_OK) { 985 AttributeItem* item 986 = (AttributeItem*)fAttributeListView->ItemAt(index); 987 if (item == NULL) 988 break; 989 990 BWindow* window = new AttributeWindow(this, fCurrentType, 991 item); 992 window->Show(); 993 } 994 break; 995 } 996 997 case kMsgAddAttribute: 998 { 999 if (fCurrentType.Type() == NULL) 1000 break; 1001 1002 BWindow* window = new AttributeWindow(this, fCurrentType, NULL); 1003 window->Show(); 1004 break; 1005 } 1006 1007 case kMsgRemoveAttribute: 1008 { 1009 int32 index = fAttributeListView->CurrentSelection(); 1010 if (index < 0 || fCurrentType.Type() == NULL) 1011 break; 1012 1013 BMessage attributes; 1014 if (fCurrentType.GetAttrInfo(&attributes) == B_OK) { 1015 const char* kAttributeNames[] = { 1016 "attr:public_name", "attr:name", "attr:type", 1017 "attr:editable", "attr:viewable", "attr:extra", 1018 "attr:alignment", "attr:width", "attr:display_as" 1019 }; 1020 1021 for (uint32 i = 0; i < 1022 sizeof(kAttributeNames) / sizeof(kAttributeNames[0]); 1023 i++) { 1024 attributes.RemoveData(kAttributeNames[i], index); 1025 } 1026 1027 fCurrentType.SetAttrInfo(&attributes); 1028 } 1029 break; 1030 } 1031 1032 case B_META_MIME_CHANGED: 1033 { 1034 const char* type; 1035 int32 which; 1036 if (message->FindString("be:type", &type) != B_OK 1037 || message->FindInt32("be:which", &which) != B_OK) 1038 break; 1039 1040 if (fCurrentType.Type() == NULL) 1041 break; 1042 1043 if (!strcasecmp(fCurrentType.Type(), type)) { 1044 if (which != B_MIME_TYPE_DELETED) 1045 _SetType(&fCurrentType, which); 1046 else 1047 _SetType(NULL); 1048 } else { 1049 // this change could still affect our current type 1050 1051 if (which == B_MIME_TYPE_DELETED 1052 || which == B_SUPPORTED_TYPES_CHANGED 1053 || which == B_PREFERRED_APP_CHANGED) 1054 _UpdatePreferredApps(&fCurrentType); 1055 } 1056 break; 1057 } 1058 1059 default: 1060 BWindow::MessageReceived(message); 1061 } 1062 } 1063 1064 1065 bool 1066 FileTypesWindow::QuitRequested() 1067 { 1068 BMessage update(kMsgSettingsChanged); 1069 update.AddRect("file_types_frame", Frame()); 1070 be_app_messenger.SendMessage(&update); 1071 1072 be_app->PostMessage(kMsgTypesWindowClosed); 1073 return true; 1074 } 1075 1076 1077