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