diff --git a/src/preferences/filetypes/ApplicationTypesWindow.cpp b/src/preferences/filetypes/ApplicationTypesWindow.cpp index e666de0194..5cd1bf83de 100644 --- a/src/preferences/filetypes/ApplicationTypesWindow.cpp +++ b/src/preferences/filetypes/ApplicationTypesWindow.cpp @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -33,7 +35,21 @@ #include +class ProgressWindow : public BWindow { + public: + ProgressWindow(const char* message, int32 max, volatile bool* signalQuit); + virtual ~ProgressWindow(); + + virtual void MessageReceived(BMessage* message); + + private: + BStatusBar* fStatusBar; + BButton* fAbortButton; + volatile bool* fQuitListener; +}; + const uint32 kMsgTypeSelected = 'typs'; +const uint32 kMsgTypeInvoked = 'typi'; const uint32 kMsgRemoveUninstalled = 'runs'; @@ -71,6 +87,77 @@ variety_to_text(uint32 variety) // #pragma mark - +ProgressWindow::ProgressWindow(const char* message, int32 max, volatile bool* signalQuit) + : BWindow(BRect(0, 0, 300, 200), "Progress", B_MODAL_WINDOW_LOOK, + B_MODAL_SUBSET_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS | B_NOT_V_RESIZABLE), + fQuitListener(signalQuit) +{ + BView* topView = new BView(Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW); + topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + AddChild(topView); + + char count[100]; + snprintf(count, sizeof(count), "/%ld", max); + + BRect rect = Bounds().InsetByCopy(8, 8); + fStatusBar = new BStatusBar(rect, "status", message, count); + fStatusBar->SetMaxValue(max); + fStatusBar->SetResizingMode(B_FOLLOW_LEFT_RIGHT); + float width, height; + fStatusBar->GetPreferredSize(&width, &height); + fStatusBar->ResizeTo(rect.Width(), height); + topView->AddChild(fStatusBar); + + fAbortButton = new BButton(rect, "abort", "Abort", new BMessage(B_CANCEL), + B_FOLLOW_H_CENTER | B_FOLLOW_TOP); + fAbortButton->ResizeToPreferred(); + fAbortButton->MoveTo((Bounds().Width() - fAbortButton->Bounds().Width()) / 2, + fStatusBar->Frame().bottom + 10.0f); + topView->AddChild(fAbortButton); + + ResizeTo(width * 1.4f, fAbortButton->Frame().bottom + 8.0f); + SetSizeLimits(width + 42.0f, 32767.0f, + Bounds().Height(), Bounds().Height()); + + // center on screen + BScreen screen(this); + MoveTo(screen.Frame().left + (screen.Frame().Width() - Bounds().Width()) / 2.0f, + screen.Frame().top + (screen.Frame().Height() - Bounds().Height()) / 2.0f); +} + + +ProgressWindow::~ProgressWindow() +{ +} + + +void +ProgressWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + case B_UPDATE_STATUS_BAR: + char count[100]; + snprintf(count, sizeof(count), "%ld", (int32)fStatusBar->CurrentValue() + 1); + + fStatusBar->Update(1, NULL, count); + break; + + case B_CANCEL: + fAbortButton->SetEnabled(false); + if (fQuitListener != NULL) + *fQuitListener = true; + break; + + default: + BWindow::MessageReceived(message); + break; + } +} + + +// #pragma mark - + + ApplicationTypesWindow::ApplicationTypesWindow(BRect frame) : BWindow(frame, "Application Types", B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS) @@ -96,6 +183,7 @@ ApplicationTypesWindow::ApplicationTypesWindow(BRect frame) fTypeListView = new MimeTypeListView(rect, "listview", "application", true, true, B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM); fTypeListView->SetSelectionMessage(new BMessage(kMsgTypeSelected)); + fTypeListView->SetInvocationMessage(new BMessage(kMsgTypeInvoked)); BScrollView* scrollView = new BScrollView("scrollview", fTypeListView, B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM, B_FRAME_EVENTS | B_WILL_DRAW, false, true); @@ -213,9 +301,17 @@ ApplicationTypesWindow::_RemoveUninstalled() // Note: this runs in the looper's thread, which isn't that nice int32 removed = 0; + volatile bool quit = false; - for (int32 i = fTypeListView->FullListCountItems(); i-- > 0;) { + BWindow* progressWindow = new ProgressWindow("Removing uninstalled application types", + fTypeListView->FullListCountItems(), &quit); + progressWindow->AddToSubset(this); + progressWindow->Show(); + + for (int32 i = fTypeListView->FullListCountItems(); i-- > 0 && !quit;) { MimeTypeItem* item = dynamic_cast(fTypeListView->FullListItemAt(i)); + progressWindow->PostMessage(B_UPDATE_STATUS_BAR); + if (item == NULL) continue; @@ -257,6 +353,8 @@ ApplicationTypesWindow::_RemoveUninstalled() } } + progressWindow->PostMessage(B_QUIT_REQUESTED); + char message[512]; snprintf(message, sizeof(message), "%ld Application Type%s could be removed.", removed, removed == 1 ? "" : "s"); @@ -366,7 +464,6 @@ ApplicationTypesWindow::_SetType(BMimeType* type, int32 forceUpdate) } - void ApplicationTypesWindow::FrameResized(float width, float height) { @@ -393,6 +490,25 @@ ApplicationTypesWindow::MessageReceived(BMessage* message) break; } + case kMsgTypeInvoked: + { + int32 index; + if (message->FindInt32("index", &index) == B_OK) { + MimeTypeItem* item = (MimeTypeItem*)fTypeListView->ItemAt(index); + if (item != NULL) { + BMimeType type(item->Type()); + entry_ref ref; + if (type.GetAppHint(&ref) == B_OK) { + BMessage refs(B_REFS_RECEIVED); + refs.AddRef("refs", &ref); + + be_app->PostMessage(&refs); + } + } + } + break; + } + case kMsgRemoveUninstalled: _RemoveUninstalled(); break; diff --git a/src/preferences/filetypes/MimeTypeListView.cpp b/src/preferences/filetypes/MimeTypeListView.cpp index 87a6b6d420..006ea828e2 100644 --- a/src/preferences/filetypes/MimeTypeListView.cpp +++ b/src/preferences/filetypes/MimeTypeListView.cpp @@ -7,11 +7,15 @@ #include "MimeTypeListView.h" #include +#include // TODO: lazy type collecting (super types only at startup) +const uint32 kMsgAddType = 'adtp'; + + status_t icon_for_type(BMimeType& type, BBitmap& bitmap, icon_size size, icon_source* _source) @@ -430,6 +434,51 @@ MimeTypeListView::_MakeTypesUnique(MimeTypeItem* underItem) } +void +MimeTypeListView::_AddNewType(const char* type) +{ + MimeTypeItem* item = FindItem(type); + + BMimeType mimeType(type); + bool isApp = mimetype_is_application_signature(mimeType); + if (fApplicationMode ^ isApp || !mimeType.IsInstalled()) { + if (item != NULL) { + // type doesn't belong here + RemoveItem(item); + delete item; + } + return; + } + + if (item != NULL) { + // for some reason, the type already exists + return; + } + + BMimeType superType; + MimeTypeItem* superItem = NULL; + if (mimeType.GetSupertype(&superType) == B_OK) + superItem = FindItem(superType.Type()); + + item = new MimeTypeItem(mimeType, fShowIcons, fSupertype.Type() != NULL); + item->SetApplicationMode(isApp); + + if (superItem != NULL) { + AddUnder(item, superItem); + InvalidateItem(IndexOf(superItem)); + // the super item is not picked up from the class (ie. bug) + } else + AddItem(item); + + UpdateItem(item); + + if (!fSelectNewType.ICompare(mimeType.Type())) { + SelectItem(item); + fSelectNewType = ""; + } +} + + void MimeTypeListView::AttachedToWindow() { @@ -470,7 +519,7 @@ MimeTypeListView::MessageReceived(BMessage* message) case B_SHORT_DESCRIPTION_CHANGED: { // update label - + MimeTypeItem* item = FindItem(type); if (item != NULL) UpdateItem(item); @@ -478,33 +527,17 @@ MimeTypeListView::MessageReceived(BMessage* message) } case B_MIME_TYPE_CREATED: { - // create new item - BMimeType created(type); - bool isApp = mimetype_is_application_signature(created); - if (fApplicationMode ^ isApp) - break; + // delay creation of new item a bit, until the type is fully installed - BMimeType superType; - MimeTypeItem* superItem = NULL; - if (created.GetSupertype(&superType) == B_OK) - superItem = FindItem(superType.Type()); + BMessage addType(kMsgAddType); + addType.AddString("type", type); - MimeTypeItem* item = new MimeTypeItem(created, fShowIcons, - fSupertype.Type() != NULL); - item->SetApplicationMode(isApp); - - if (superItem != NULL) { - AddUnder(item, superItem); - InvalidateItem(IndexOf(superItem)); - // the super item is not picked up from the class (ie. bug) - } else - AddItem(item); - - UpdateItem(item); - - if (!fSelectNewType.ICompare(type)) { - SelectItem(item); - fSelectNewType = ""; + // TODO: free runner again! + BMessageRunner* runner = new BMessageRunner(this, &addType, + 200000ULL, 1); + if (runner->InitCheck() != B_OK) { + delete runner; + _AddNewType(type); } break; } @@ -519,15 +552,23 @@ MimeTypeListView::MessageReceived(BMessage* message) break; } case B_PREFERRED_APP_CHANGED: + { + // try to add or remove this type (changing the preferred app + // might change visibility in our list) + _AddNewType(type); + + // supposed to fall through + } case B_ICON_CHANGED: // TODO: take B_ICON_FOR_TYPE_CHANGED into account, too - if (fShowIcons) { + { + MimeTypeItem* item = FindItem(type); + if (item != NULL && fShowIcons) { // refresh item - MimeTypeItem* item = FindItem(type); - if (item != NULL) - InvalidateItem(IndexOf(item)); + InvalidateItem(IndexOf(item)); } break; + } default: break; @@ -535,6 +576,14 @@ MimeTypeListView::MessageReceived(BMessage* message) break; } + case kMsgAddType: + { + const char* type; + if (message->FindString("type", &type) == B_OK) + _AddNewType(type); + break; + } + default: BOutlineListView::MessageReceived(message); } diff --git a/src/preferences/filetypes/MimeTypeListView.h b/src/preferences/filetypes/MimeTypeListView.h index 598bb56aef..9ada6a7770 100644 --- a/src/preferences/filetypes/MimeTypeListView.h +++ b/src/preferences/filetypes/MimeTypeListView.h @@ -79,6 +79,7 @@ class MimeTypeListView : public BOutlineListView { void _CollectSubtypes(const char* supertype, MimeTypeItem* supertypeItem); void _CollectTypes(); void _MakeTypesUnique(MimeTypeItem* underItem = NULL); + void _AddNewType(const char* type); BMimeType fSupertype; BString fSelectNewType;