/* * Copyright 2006-2010, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #include "FileTypes.h" #include "FileTypeWindow.h" #include "IconView.h" #include "PreferredAppMenu.h" #include "TypeListWindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "FileType Window" const uint32 kMsgTypeEntered = 'type'; const uint32 kMsgSelectType = 'sltp'; const uint32 kMsgTypeSelected = 'tpsd'; const uint32 kMsgSameTypeAs = 'stpa'; const uint32 kMsgSameTypeAsOpened = 'stpO'; const uint32 kMsgPreferredAppChosen = 'papc'; const uint32 kMsgSelectPreferredApp = 'slpa'; const uint32 kMsgSamePreferredAppAs = 'spaa'; const uint32 kMsgPreferredAppOpened = 'paOp'; const uint32 kMsgSamePreferredAppAsOpened = 'spaO'; FileTypeWindow::FileTypeWindow(BPoint position, const BMessage& refs) : BWindow(BRect(0.0f, 0.0f, 300.0f, 200.0f).OffsetBySelf(position), B_TRANSLATE("File type"), B_TITLED_WINDOW, B_NOT_V_RESIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS) { float padding = be_control_look->DefaultItemSpacing(); // "File Type" group BBox* fileTypeBox = new BBox("file type BBox"); fileTypeBox->SetLabel(B_TRANSLATE("File type")); fTypeControl = new BTextControl("type", NULL, "Type Control", new BMessage(kMsgTypeEntered)); // filter out invalid characters that can't be part of a MIME type name BTextView* textView = fTypeControl->TextView(); const char* disallowedCharacters = "<>@,;:\"()[]?="; for (int32 i = 0; disallowedCharacters[i]; i++) { textView->DisallowChar(disallowedCharacters[i]); } fSelectTypeButton = new BButton("select type", B_TRANSLATE("Select" B_UTF8_ELLIPSIS), new BMessage(kMsgSelectType)); fSameTypeAsButton = new BButton("same type as", B_TRANSLATE_COMMENT("Same as" B_UTF8_ELLIPSIS, "The same TYPE as ..."), new BMessage(kMsgSameTypeAs)); BLayoutBuilder::Grid<>(fileTypeBox, padding, padding / 2) .SetInsets(padding, padding * 2, padding, padding) .Add(fTypeControl, 0, 0, 3, 1) .Add(fSelectTypeButton, 0, 1) .Add(fSameTypeAsButton, 1, 1); // "Icon" group BBox* iconBox = new BBox("icon BBox"); iconBox->SetLabel(B_TRANSLATE("Icon")); fIconView = new IconView("icon"); BLayoutBuilder::Group<>(iconBox, B_HORIZONTAL) .SetInsets(padding, padding * 2, padding, padding) .Add(fIconView); // "Preferred Application" group BBox* preferredBox = new BBox("preferred BBox"); preferredBox->SetLabel(B_TRANSLATE("Preferred application")); BMenu* menu = new BPopUpMenu("preferred"); BMenuItem* item; menu->AddItem(item = new BMenuItem(B_TRANSLATE("Default application"), new BMessage(kMsgPreferredAppChosen))); item->SetMarked(true); fPreferredField = new BMenuField("preferred", NULL, menu); fSelectAppButton = new BButton("select app", B_TRANSLATE("Select" B_UTF8_ELLIPSIS), new BMessage(kMsgSelectPreferredApp)); fSameAppAsButton = new BButton("same app as", B_TRANSLATE_COMMENT("Same as" B_UTF8_ELLIPSIS, "The same APPLICATION as ..."), new BMessage(kMsgSamePreferredAppAs)); BLayoutBuilder::Grid<>(preferredBox, padding, padding / 2) .SetInsets(padding, padding * 2, padding, padding) .Add(fPreferredField, 0, 0, 2, 1) .Add(fSelectAppButton, 0, 1) .Add(fSameAppAsButton, 1, 1); BLayoutBuilder::Grid<>(this) .SetInsets(padding) .Add(fileTypeBox, 0, 0, 2, 1) .Add(preferredBox, 0, 1, 1, 1) .Add(iconBox, 1, 1, 1, 1); fTypeControl->MakeFocus(true); BMimeType::StartWatching(this); _SetTo(refs); } FileTypeWindow::~FileTypeWindow() { BMimeType::StopWatching(this); } BString FileTypeWindow::_Title(const BMessage& refs) { BString title; entry_ref ref; if (refs.FindRef("refs", 1, &ref) == B_OK) { bool same = false; BEntry entry, parent; if (entry.SetTo(&ref) == B_OK && entry.GetParent(&parent) == B_OK) { same = true; // Check if all entries have the same parent directory for (int32 i = 0; refs.FindRef("refs", i, &ref) == B_OK; i++) { BEntry directory; if (entry.SetTo(&ref) == B_OK && entry.GetParent(&directory) == B_OK) { if (directory != parent) { same = false; break; } } } } char name[B_FILE_NAME_LENGTH]; if (same && parent.GetName(name) == B_OK) { char buffer[512]; snprintf(buffer, sizeof(buffer), B_TRANSLATE("Multiple files from \"%s\" file type"), name); title = buffer; } else title = B_TRANSLATE("[Multiple files] file types"); } else if (refs.FindRef("refs", 0, &ref) == B_OK) { char buffer[512]; snprintf(buffer, sizeof(buffer), B_TRANSLATE("%s file type"), ref.name); title = buffer; } return title; } void FileTypeWindow::_SetTo(const BMessage& refs) { SetTitle(_Title(refs).String()); // get common info and icons fCommonPreferredApp = ""; fCommonType = ""; entry_ref ref; for (int32 i = 0; refs.FindRef("refs", i, &ref) == B_OK; i++) { BNode node(&ref); if (node.InitCheck() != B_OK) continue; BNodeInfo info(&node); if (info.InitCheck() != B_OK) continue; // TODO: watch entries? entry_ref* copiedRef = new entry_ref(ref); fEntries.AddItem(copiedRef); char type[B_MIME_TYPE_LENGTH]; if (info.GetType(type) != B_OK) type[0] = '\0'; if (i > 0) { if (fCommonType != type) fCommonType = ""; } else fCommonType = type; char preferredApp[B_MIME_TYPE_LENGTH]; if (info.GetPreferredApp(preferredApp) != B_OK) preferredApp[0] = '\0'; if (i > 0) { if (fCommonPreferredApp != preferredApp) fCommonPreferredApp = ""; } else fCommonPreferredApp = preferredApp; if (i == 0) fIconView->SetTo(ref); } fTypeControl->SetText(fCommonType.String()); _UpdatePreferredApps(); fIconView->ShowIconHeap(fEntries.CountItems() != 1); } void FileTypeWindow::_AdoptType(BMessage* message) { entry_ref ref; if (message == NULL || message->FindRef("refs", &ref) != B_OK) return; BNode node(&ref); status_t status = node.InitCheck(); char type[B_MIME_TYPE_LENGTH]; if (status == B_OK) { // get type from file BNodeInfo nodeInfo(&node); status = nodeInfo.InitCheck(); if (status == B_OK) { if (nodeInfo.GetType(type) != B_OK) type[0] = '\0'; } } if (status != B_OK) { error_alert(B_TRANSLATE("Could not open file"), status); return; } fCommonType = type; fTypeControl->SetText(type); _AdoptType(); } void FileTypeWindow::_AdoptType() { for (int32 i = 0; i < fEntries.CountItems(); i++) { BNode node(fEntries.ItemAt(i)); BNodeInfo info(&node); if (node.InitCheck() != B_OK || info.InitCheck() != B_OK) continue; info.SetType(fCommonType.String()); } } void FileTypeWindow::_AdoptPreferredApp(BMessage* message, bool sameAs) { if (retrieve_preferred_app(message, sameAs, fCommonType.String(), fCommonPreferredApp) == B_OK) { _AdoptPreferredApp(); _UpdatePreferredApps(); } } void FileTypeWindow::_AdoptPreferredApp() { for (int32 i = 0; i < fEntries.CountItems(); i++) { BNode node(fEntries.ItemAt(i)); if (fCommonPreferredApp.Length() == 0) { node.RemoveAttr("BEOS:PREF_APP"); continue; } BNodeInfo info(&node); if (node.InitCheck() != B_OK || info.InitCheck() != B_OK) continue; info.SetPreferredApp(fCommonPreferredApp.String()); } } void FileTypeWindow::_UpdatePreferredApps() { BMimeType type(fCommonType.String()); update_preferred_app_menu(fPreferredField->Menu(), &type, kMsgPreferredAppChosen, fCommonPreferredApp.String()); } void FileTypeWindow::MessageReceived(BMessage* message) { switch (message->what) { // File Type group case kMsgTypeEntered: fCommonType = fTypeControl->Text(); _AdoptType(); break; case kMsgSelectType: { BWindow* window = new TypeListWindow(fCommonType.String(), kMsgTypeSelected, this); window->Show(); break; } case kMsgTypeSelected: { const char* type; if (message->FindString("type", &type) == B_OK) { fCommonType = type; fTypeControl->SetText(type); _AdoptType(); } break; } case kMsgSameTypeAs: { BMessage panel(kMsgOpenFilePanel); panel.AddString("title", B_TRANSLATE("Select same type as")); panel.AddInt32("message", kMsgSameTypeAsOpened); panel.AddMessenger("target", this); panel.AddBool("allowDirs", true); be_app_messenger.SendMessage(&panel); break; } case kMsgSameTypeAsOpened: _AdoptType(message); break; // Preferred Application group case kMsgPreferredAppChosen: { const char* signature; if (message->FindString("signature", &signature) == B_OK) fCommonPreferredApp = signature; else fCommonPreferredApp = ""; _AdoptPreferredApp(); break; } case kMsgSelectPreferredApp: { BMessage panel(kMsgOpenFilePanel); panel.AddString("title", B_TRANSLATE("Select preferred application")); panel.AddInt32("message", kMsgPreferredAppOpened); panel.AddMessenger("target", this); be_app_messenger.SendMessage(&panel); break; } case kMsgPreferredAppOpened: _AdoptPreferredApp(message, false); break; case kMsgSamePreferredAppAs: { BMessage panel(kMsgOpenFilePanel); panel.AddString("title", B_TRANSLATE("Select same preferred application as")); panel.AddInt32("message", kMsgSamePreferredAppAsOpened); panel.AddMessenger("target", this); panel.AddBool("allowDirs", true); be_app_messenger.SendMessage(&panel); break; } case kMsgSamePreferredAppAsOpened: _AdoptPreferredApp(message, true); break; // Other case B_SIMPLE_DATA: { entry_ref ref; if (message->FindRef("refs", &ref) != B_OK) break; BFile file(&ref, B_READ_ONLY); if (is_application(file)) _AdoptPreferredApp(message, false); else _AdoptType(message); break; } case B_META_MIME_CHANGED: const char* type; int32 which; if (message->FindString("be:type", &type) != B_OK || message->FindInt32("be:which", &which) != B_OK) break; if (which == B_MIME_TYPE_DELETED || which == B_SUPPORTED_TYPES_CHANGED) { _UpdatePreferredApps(); } break; default: BWindow::MessageReceived(message); } } bool FileTypeWindow::QuitRequested() { be_app->PostMessage(kMsgTypeWindowClosed); return true; }