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