xref: /haiku/src/preferences/notifications/NotificationsView.cpp (revision 529cd177b573aaba391c8adc9c9f5ad76a14bf81)
1 /*
2  * Copyright 2010, Haiku, Inc. All Rights Reserved.
3  * Copyright 2009, Pier Luigi Fiorini.
4  * Distributed under the terms of the MIT License.
5  *
6  * Authors:
7  *		Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
8  */
9 
10 #include <Alert.h>
11 #include <Catalog.h>
12 #include <Directory.h>
13 #include <FindDirectory.h>
14 #include <GroupLayout.h>
15 #include <GroupLayoutBuilder.h>
16 #include <Window.h>
17 #include <CheckBox.h>
18 #include <TextControl.h>
19 #include <Path.h>
20 #include <Notification.h>
21 #include <notification/Notifications.h>
22 #include <notification/NotificationReceived.h>
23 
24 #include <ColumnListView.h>
25 #include <ColumnTypes.h>
26 
27 #include "NotificationsView.h"
28 
29 #undef B_TRANSLATION_CONTEXT
30 #define B_TRANSLATION_CONTEXT "NotificationView"
31 
32 const float kEdgePadding = 5.0;
33 const float kCLVTitlePadding = 8.0;
34 
35 const int32 kApplicationSelected = '_ASL';
36 const int32 kNotificationSelected = '_NSL';
37 
38 const int32 kCLVDeleteRow = 'av02';
39 
40 // Applications column indexes
41 const int32 kAppIndex = 0;
42 const int32 kAppEnabledIndex = 1;
43 
44 // Notifications column indexes
45 const int32 kTitleIndex = 0;
46 const int32 kDateIndex = 1;
47 const int32 kTypeIndex = 2;
48 const int32 kAllowIndex = 3;
49 
50 
51 NotificationsView::NotificationsView(SettingsHost* host)
52 	:
53 	SettingsPane("apps", host)
54 {
55 	BRect rect(0, 0, 100, 100);
56 
57 	// Search application field
58 	fSearch = new BTextControl(B_TRANSLATE("Search:"), NULL,
59 		new BMessage(kSettingChanged));
60 
61 	// Applications list
62 	fApplications = new BColumnListView(rect, B_TRANSLATE("Applications"),
63 		0, B_WILL_DRAW, B_FANCY_BORDER, true);
64 	fApplications->SetSelectionMode(B_SINGLE_SELECTION_LIST);
65 
66 	fAppCol = new BStringColumn(B_TRANSLATE("Application"), 200,
67 		be_plain_font->StringWidth(B_TRANSLATE("Application")) +
68 		(kCLVTitlePadding * 2), rect.Width(), B_TRUNCATE_END, B_ALIGN_LEFT);
69 	fApplications->AddColumn(fAppCol, kAppIndex);
70 
71 	fAppEnabledCol = new BStringColumn(B_TRANSLATE("Enabled"), 10,
72 		be_plain_font->StringWidth(B_TRANSLATE("Enabled")) +
73 		(kCLVTitlePadding * 2), rect.Width(), B_TRUNCATE_END, B_ALIGN_LEFT);
74 	fApplications->AddColumn(fAppEnabledCol, kAppEnabledIndex);
75 
76 	// Notifications list
77 	fNotifications = new BColumnListView(rect, B_TRANSLATE("Notifications"),
78 		0, B_WILL_DRAW, B_FANCY_BORDER, true);
79 	fNotifications->SetSelectionMode(B_SINGLE_SELECTION_LIST);
80 
81 	fTitleCol = new BStringColumn(B_TRANSLATE("Title"), 100,
82 		be_plain_font->StringWidth(B_TRANSLATE("Title")) +
83 		(kCLVTitlePadding * 2), rect.Width(), B_TRUNCATE_END, B_ALIGN_LEFT);
84 	fNotifications->AddColumn(fTitleCol, kTitleIndex);
85 
86 	fDateCol = new BDateColumn(B_TRANSLATE("Last Received"), 100,
87 		be_plain_font->StringWidth(B_TRANSLATE("Last Received")) +
88 		(kCLVTitlePadding * 2), rect.Width(), B_ALIGN_LEFT);
89 	fNotifications->AddColumn(fDateCol, kDateIndex);
90 
91 	fTypeCol = new BStringColumn(B_TRANSLATE("Type"), 100,
92 		be_plain_font->StringWidth(B_TRANSLATE("Type")) +
93 		(kCLVTitlePadding * 2), rect.Width(), B_TRUNCATE_END, B_ALIGN_LEFT);
94 	fNotifications->AddColumn(fTypeCol, kTypeIndex);
95 
96 	fAllowCol = new BStringColumn(B_TRANSLATE("Allowed"), 100,
97 		be_plain_font->StringWidth(B_TRANSLATE("Allowed")) +
98 		(kCLVTitlePadding * 2), rect.Width(), B_TRUNCATE_END, B_ALIGN_LEFT);
99 	fNotifications->AddColumn(fAllowCol, kAllowIndex);
100 
101 	// Calculate inset
102 	float inset = ceilf(be_plain_font->Size() * 0.7f);
103 
104 	// Set layout
105 	SetLayout(new BGroupLayout(B_VERTICAL));
106 
107 	// Add views
108 	AddChild(BGroupLayoutBuilder(B_VERTICAL, inset)
109 		.AddGroup(B_HORIZONTAL)
110 			.AddGlue()
111 			.Add(fSearch)
112 		.End()
113 		.Add(fApplications)
114 		.Add(fNotifications)
115 		.SetInsets(inset, inset, inset, inset)
116 	);
117 }
118 
119 
120 void
121 NotificationsView::AttachedToWindow()
122 {
123 	fApplications->SetTarget(this);
124 	fApplications->SetInvocationMessage(new BMessage(kApplicationSelected));
125 
126 	fNotifications->SetTarget(this);
127 	fNotifications->SetInvocationMessage(new BMessage(kNotificationSelected));
128 
129 #if 0
130 	fNotifications->AddFilter(new BMessageFilter(B_ANY_DELIVERY,
131 		B_ANY_SOURCE, B_KEY_DOWN, CatchDelete));
132 #endif
133 }
134 
135 
136 void
137 NotificationsView::MessageReceived(BMessage* msg)
138 {
139 	switch (msg->what) {
140 		case kApplicationSelected:
141 		{
142 			BRow* row = fApplications->CurrentSelection();
143 			if (row == NULL)
144 				return;
145 			BStringField* appName
146 				= dynamic_cast<BStringField*>(row->GetField(kAppIndex));
147 			if (appName == NULL)
148 				break;
149 
150 			appusage_t::iterator it = fAppFilters.find(appName->String());
151 			if (it != fAppFilters.end())
152 				_Populate(it->second);
153 
154 			break;
155 		}
156 		case kNotificationSelected:
157 			break;
158 		default:
159 			BView::MessageReceived(msg);
160 			break;
161 	}
162 }
163 
164 
165 status_t
166 NotificationsView::Load(BMessage& settings)
167 {
168 	type_code type;
169 	int32 count = 0;
170 
171 	if (settings.GetInfo("app_usage", &type, &count) != B_OK)
172 		return B_ERROR;
173 
174 	// Clean filters
175 	appusage_t::iterator auIt;
176 	for (auIt = fAppFilters.begin(); auIt != fAppFilters.end(); auIt++)
177 		delete auIt->second;
178 	fAppFilters.clear();
179 
180 	// Add new filters
181 	for (int32 i = 0; i < count; i++) {
182 		AppUsage* app = new AppUsage();
183 		settings.FindFlat("app_usage", i, app);
184 		fAppFilters[app->Name()] = app;
185 	}
186 
187 	// Load the applications list
188 	_PopulateApplications();
189 
190 	return B_OK;
191 }
192 
193 
194 status_t
195 NotificationsView::Save(BMessage& storage)
196 {
197 	appusage_t::iterator fIt;
198 	for (fIt = fAppFilters.begin(); fIt != fAppFilters.end(); fIt++)
199 		storage.AddFlat("app_usage", fIt->second);
200 
201 	return B_OK;
202 }
203 
204 
205 void
206 NotificationsView::_PopulateApplications()
207 {
208 	appusage_t::iterator it;
209 
210 	fApplications->Clear();
211 
212 	for (it = fAppFilters.begin(); it != fAppFilters.end(); ++it) {
213 		BRow* row = new BRow();
214 		row->SetField(new BStringField(it->first.String()), kAppIndex);
215 		fApplications->AddRow(row);
216 	}
217 }
218 
219 
220 void
221 NotificationsView::_Populate(AppUsage* usage)
222 {
223 	// Sanity check
224 	if (!usage)
225 		return;
226 
227 	int32 size = usage->Notifications();
228 
229 	if (usage->Allowed() == false)
230 		fBlockAll->SetValue(B_CONTROL_ON);
231 
232 	fNotifications->Clear();
233 
234 	for (int32 i = 0; i < size; i++) {
235 		NotificationReceived* notification = usage->NotificationAt(i);
236 		time_t updated = notification->LastReceived();
237 		const char* allow = notification->Allowed() ? B_TRANSLATE("Yes")
238 			: B_TRANSLATE("No");
239 		const char* type = "";
240 
241 		switch (notification->Type()) {
242 			case B_INFORMATION_NOTIFICATION:
243 				type = B_TRANSLATE("Information");
244 				break;
245 			case B_IMPORTANT_NOTIFICATION:
246 				type = B_TRANSLATE("Important");
247 				break;
248 			case B_ERROR_NOTIFICATION:
249 				type = B_TRANSLATE("Error");
250 				break;
251 			case B_PROGRESS_NOTIFICATION:
252 				type = B_TRANSLATE("Progress");
253 				break;
254 			default:
255 				type = B_TRANSLATE("Unknown");
256 		}
257 
258 		BRow* row = new BRow();
259 		row->SetField(new BStringField(notification->Title()), kTitleIndex);
260 		row->SetField(new BDateField(&updated), kDateIndex);
261 		row->SetField(new BStringField(type), kTypeIndex);
262 		row->SetField(new BStringField(allow), kAllowIndex);
263 
264 		fNotifications->AddRow(row);
265 	}
266 }
267