/*
* 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 <Alert.h>
#include <Button.h>
#include <Catalog.h>
#include <CheckBox.h>
#include <ColumnListView.h>
#include <ColumnTypes.h>
#include <Directory.h>
#include <FindDirectory.h>
#include <LayoutBuilder.h>
#include <Notification.h>
#include <Path.h>
#include <TextControl.h>
#include <Window.h>
#include <notification/Notifications.h>
#include <notification/NotificationReceived.h>
#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<AppRow*>(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);
}
}
↑ V773 Visibility scope of the 'alert' pointer was exited without releasing the memory. A memory leak is possible.
↑ V773 Visibility scope of the 'alert' pointer was exited without releasing the memory. A memory leak is possible.