/* * Copyright 2010-2017, Haiku, Inc. All Rights Reserved. * Copyright 2009, Pier Luigi Fiorini. * Distributed under the terms of the MIT License. * * Authors: * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com * Brian Hill, supernova@tycho.email */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "NotificationsConstants.h" #include "NotificationsView.h" #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "NotificationView" // Applications column indexes const int32 kAppNameIndex = 0; const int32 kAppEnabledIndex = 1; AppRow::AppRow(const char* name, const char* signature, bool allowed) : BRow(), fName(name), fSignature(signature), fAllowed(allowed) { SetField(new BStringField(fName.String()), kAppNameIndex); BString text = fAllowed ? B_TRANSLATE("Allowed") : B_TRANSLATE("Muted"); SetField(new BStringField(text.String()), kAppEnabledIndex); } void AppRow::SetAllowed(bool allowed) { fAllowed = allowed; RefreshEnabledField(); } void AppRow::RefreshEnabledField() { BStringField* field = (BStringField*)GetField(kAppEnabledIndex); BString text = fAllowed ? B_TRANSLATE("Allowed") : B_TRANSLATE("Muted"); field->SetString(text.String()); Invalidate(); } NotificationsView::NotificationsView(SettingsHost* host) : SettingsPane("apps", host), fSelectedRow(NULL) { // Applications list fApplications = new BColumnListView(B_TRANSLATE("Applications"), 0, B_FANCY_BORDER, false); fApplications->SetSelectionMode(B_SINGLE_SELECTION_LIST); fApplications->SetSelectionMessage(new BMessage(kApplicationSelected)); float colWidth = be_plain_font->StringWidth(B_TRANSLATE("Application")) + (kCLVTitlePadding * 2); fAppCol = new BStringColumn(B_TRANSLATE("Application"), colWidth * 2, colWidth, colWidth * 4, B_TRUNCATE_END, B_ALIGN_LEFT); fApplications->AddColumn(fAppCol, kAppNameIndex); colWidth = be_plain_font->StringWidth(B_TRANSLATE("Status")) + (kCLVTitlePadding * 2); fAppEnabledCol = new BStringColumn(B_TRANSLATE("Status"), colWidth * 1.5, colWidth, colWidth * 3, B_TRUNCATE_END, B_ALIGN_LEFT); fApplications->AddColumn(fAppEnabledCol, kAppEnabledIndex); fApplications->SetSortColumn(fAppCol, true, true); fAddButton = new BButton("add_app", B_TRANSLATE("Add" B_UTF8_ELLIPSIS), new BMessage(kAddApplication)); fRemoveButton = new BButton("add_app", B_TRANSLATE("Remove"), new BMessage(kRemoveApplication)); fRemoveButton->SetEnabled(false); fMuteAll = new BCheckBox("block", B_TRANSLATE("Mute notifications from " "this application"), new BMessage(kMuteChanged)); // Add views BLayoutBuilder::Group<>(this, B_VERTICAL) .AddGroup(B_HORIZONTAL) .Add(fApplications) .AddGroup(B_VERTICAL) .Add(fAddButton) .Add(fRemoveButton) .AddGlue() .End() .End() .Add(fMuteAll) .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING); // Set button sizes float maxButtonWidth = std::max(fAddButton->PreferredSize().Width(), fRemoveButton->PreferredSize().Width()); fAddButton->SetExplicitMaxSize(BSize(maxButtonWidth, B_SIZE_UNSET)); fRemoveButton->SetExplicitMaxSize(BSize(maxButtonWidth, B_SIZE_UNSET)); // File Panel fPanelFilter = new AppRefFilter(); fAddAppPanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL, B_FILE_NODE, false, NULL, fPanelFilter); } NotificationsView::~NotificationsView() { delete fAddAppPanel; delete fPanelFilter; } void NotificationsView::AttachedToWindow() { fApplications->SetTarget(this); fApplications->SetInvocationMessage(new BMessage(kApplicationSelected)); fAddButton->SetTarget(this); fRemoveButton->SetTarget(this); fMuteAll->SetTarget(this); fAddAppPanel->SetTarget(this); _RecallItemSettings(); } void NotificationsView::MessageReceived(BMessage* msg) { switch (msg->what) { case kApplicationSelected: { Window()->Lock(); _ClearItemSettings(); _UpdateSelectedItem(); _RecallItemSettings(); Window()->Unlock(); break; } case kMuteChanged: { bool allowed = fMuteAll->Value() == B_CONTROL_OFF; fSelectedRow->SetAllowed(allowed); appusage_t::iterator it = fAppFilters.find(fSelectedRow->Signature()); if (it != fAppFilters.end()) it->second->SetAllowed(allowed); Window()->PostMessage(kApply); break; } case kAddApplication: { BMessage addmsg(kAddApplicationRef); fAddAppPanel->SetMessage(&addmsg); fAddAppPanel->Show(); break; } case kAddApplicationRef: { entry_ref srcRef; msg->FindRef("refs", &srcRef); BEntry srcEntry(&srcRef, true); BPath path(&srcEntry); BNode node(&srcEntry); char *buf = new char[B_ATTR_NAME_LENGTH]; ssize_t size; if ( (size = node.ReadAttr("BEOS:APP_SIG", 0, 0, buf, B_ATTR_NAME_LENGTH)) > 0 ) { // Search for already existing app appusage_t::iterator it = fAppFilters.find(buf); if (it != fAppFilters.end()) { BString text(path.Leaf()); text.Append(B_TRANSLATE_COMMENT(" is already listed", "Alert message")); BAlert* alert = new BAlert("", text.String(), B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); alert->Go(NULL); } else { AppUsage* appUsage = new AppUsage(path.Leaf(), buf, true); fAppFilters[appUsage->Signature()] = appUsage; AppRow* row = new AppRow(appUsage->AppName(), appUsage->Signature(), appUsage->Allowed()); fApplications->AddRow(row); fApplications->DeselectAll(); fApplications->AddToSelection(row); fApplications->ScrollTo(row); _UpdateSelectedItem(); _RecallItemSettings(); //row->Invalidate(); //fApplications->InvalidateRow(row); // TODO redraw row properly Window()->PostMessage(kApply); } } else { BAlert* alert = new BAlert("", B_TRANSLATE_COMMENT("Application does not have " "a valid signature", "Alert message"), B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); alert->Go(NULL); } delete[] buf; break; } case kRemoveApplication: { if (fSelectedRow) { appusage_t::iterator it = fAppFilters.find(fSelectedRow->Signature()); if (it != fAppFilters.end()) { delete it->second; fAppFilters.erase(it); } fApplications->RemoveRow(fSelectedRow); delete fSelectedRow; fSelectedRow = NULL; _ClearItemSettings(); _UpdateSelectedItem(); _RecallItemSettings(); Window()->PostMessage(kApply); } break; } default: BView::MessageReceived(msg); break; } } status_t NotificationsView::Load(BMessage& settings) { type_code type; int32 count = 0; if (settings.GetInfo("app_usage", &type, &count) != B_OK) return B_ERROR; // Clean filters appusage_t::iterator auIt; for (auIt = fAppFilters.begin(); auIt != fAppFilters.end(); auIt++) delete auIt->second; fAppFilters.clear(); // Add new filters for (int32 i = 0; i < count; i++) { AppUsage* app = new AppUsage(); settings.FindFlat("app_usage", i, app); fAppFilters[app->Signature()] = app; } // Load the applications list _PopulateApplications(); return B_OK; } status_t NotificationsView::Save(BMessage& storage) { appusage_t::iterator fIt; for (fIt = fAppFilters.begin(); fIt != fAppFilters.end(); fIt++) storage.AddFlat("app_usage", fIt->second); return B_OK; } void NotificationsView::_ClearItemSettings() { fMuteAll->SetValue(B_CONTROL_OFF); } void NotificationsView::_UpdateSelectedItem() { fSelectedRow = dynamic_cast(fApplications->CurrentSelection()); } void NotificationsView::_RecallItemSettings() { // No selected item if(fSelectedRow == NULL) { fMuteAll->SetValue(B_CONTROL_OFF); fMuteAll->SetEnabled(false); fRemoveButton->SetEnabled(false); } else { fMuteAll->SetEnabled(true); fRemoveButton->SetEnabled(true); appusage_t::iterator it = fAppFilters.find(fSelectedRow->Signature()); if (it != fAppFilters.end()) fMuteAll->SetValue(!(it->second->Allowed())); } } status_t NotificationsView::Revert() { return B_OK; } bool NotificationsView::RevertPossible() { return false; } status_t NotificationsView::Defaults() { return B_OK; } bool NotificationsView::DefaultsPossible() { return false; } bool NotificationsView::UseDefaultRevertButtons() { return false; } void NotificationsView::_PopulateApplications() { fApplications->Clear(); appusage_t::iterator it; for (it = fAppFilters.begin(); it != fAppFilters.end(); ++it) { AppUsage* appUsage = it->second; AppRow* row = new AppRow(appUsage->AppName(), appUsage->Signature(), appUsage->Allowed()); fApplications->AddRow(row); } }