xref: /haiku/src/preferences/notifications/GeneralView.cpp (revision fae7ea18b62865f5e1159e1678c851d3aa1ddce0)
1 /*
2  * Copyright 2010-2013, 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 <stdio.h>
11 #include <stdlib.h>
12 
13 #include <vector>
14 
15 #include <Roster.h>
16 #include <GroupLayout.h>
17 #include <GroupLayoutBuilder.h>
18 #include <Alert.h>
19 #include <Font.h>
20 #include <Button.h>
21 #include <Catalog.h>
22 #include <StringView.h>
23 #include <TextControl.h>
24 #include <CheckBox.h>
25 #include <String.h>
26 #include <FindDirectory.h>
27 #include <Node.h>
28 #include <notification/Notifications.h>
29 #include <Path.h>
30 #include <File.h>
31 #include <Directory.h>
32 #include <VolumeRoster.h>
33 #include <Volume.h>
34 #include <Query.h>
35 #include <SymLink.h>
36 
37 #include "GeneralView.h"
38 #include "SettingsHost.h"
39 
40 #undef B_TRANSLATION_CONTEXT
41 #define B_TRANSLATION_CONTEXT "GeneralView"
42 const int32 kToggleNotifications = '_TSR';
43 
44 GeneralView::GeneralView(SettingsHost* host)
45 	:
46 	SettingsPane("general", host)
47 {
48 	// Notifications
49 	fNotificationBox = new BCheckBox("server",
50 		B_TRANSLATE("Enable notifications"),
51 		new BMessage(kToggleNotifications));
52 
53 	// Autostart
54 	fAutoStart = new BCheckBox("autostart",
55 		B_TRANSLATE("Enable notifications at startup"),
56 		new BMessage(kSettingChanged));
57 
58 	// Display time
59 	fTimeout = new BTextControl(B_TRANSLATE("Hide notifications from screen"
60 		" after"), NULL, new BMessage(kSettingChanged));
61 	BStringView* displayTimeLabel = new BStringView("dt_label",
62 		B_TRANSLATE("seconds of inactivity"));
63 
64 	// Default position
65 	// TODO: Here will come a screen representation with the four corners
66 	// clickable
67 
68 	// Calculate inset
69 	float inset = ceilf(be_plain_font->Size() * 0.7f);
70 
71 	SetLayout(new BGroupLayout(B_VERTICAL));
72 	AddChild(BGroupLayoutBuilder(B_VERTICAL, inset)
73 		.AddGroup(B_HORIZONTAL, inset)
74 			.Add(fNotificationBox)
75 			.AddGlue()
76 		.End()
77 
78 		.AddGroup(B_VERTICAL, inset)
79 			.Add(fAutoStart)
80 			.AddGroup(B_HORIZONTAL)
81 				.AddGroup(B_HORIZONTAL, 2)
82 					.Add(fTimeout)
83 					.Add(displayTimeLabel)
84 				.End()
85 			.End()
86 		.End()
87 		.SetInsets(inset, inset, inset, inset)
88 		.AddGlue()
89 	);
90 }
91 
92 
93 void
94 GeneralView::AttachedToWindow()
95 {
96 	fNotificationBox->SetTarget(this);
97 	fAutoStart->SetTarget(this);
98 	fTimeout->SetTarget(this);
99 }
100 
101 
102 void
103 GeneralView::MessageReceived(BMessage* msg)
104 {
105 	switch (msg->what) {
106 		case kToggleNotifications:
107 		{
108 			entry_ref ref;
109 
110 			// Check if server is available
111 			if (!_CanFindServer(&ref)) {
112 				BAlert* alert = new BAlert(B_TRANSLATE("Notifications"),
113 					B_TRANSLATE("The notifications server cannot be"
114 					" found, this means your InfoPopper installation was"
115 					" not successfully completed."), B_TRANSLATE("OK"),
116 					NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
117 				alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
118 				(void)alert->Go();
119 				return;
120 			}
121 
122 			if (fNotificationBox->Value() == B_CONTROL_OFF) {
123 				// Server team
124 				team_id team = be_roster->TeamFor(kNotificationServerSignature);
125 
126 				// Establish a connection to infopopper_server
127 				status_t ret = B_ERROR;
128 				BMessenger messenger(kNotificationServerSignature, team, &ret);
129 				if (ret != B_OK) {
130 					BAlert* alert = new BAlert(B_TRANSLATE(
131 						"Notifications"), B_TRANSLATE("Notifications "
132 						"cannot be stopped, because the server can't be"
133 						" reached."), B_TRANSLATE("OK"), NULL, NULL,
134 						B_WIDTH_AS_USUAL, B_STOP_ALERT);
135 					alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
136 					(void)alert->Go();
137 					return;
138 				}
139 
140 				// Send quit message
141 				if (messenger.SendMessage(B_QUIT_REQUESTED) != B_OK) {
142 					BAlert* alert = new BAlert(B_TRANSLATE(
143 						"Notifications"), B_TRANSLATE("Cannot disable"
144 						" notifications because the server can't be "
145 						"reached."), B_TRANSLATE("OK"),
146 						NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
147 					alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
148 					(void)alert->Go();
149 					return;
150 				}
151 			} else if (!_IsServerRunning()) {
152 				// Start server
153 				status_t err = be_roster->Launch(kNotificationServerSignature);
154 				if (err != B_OK) {
155 					BAlert* alert = new BAlert(B_TRANSLATE(
156 						"Notifications"), B_TRANSLATE("Cannot enable"
157 						" notifications because the server cannot be "
158 						"found.\nThis means your InfoPopper installation"
159 						" was not successfully completed."),
160 						B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL,
161 						B_STOP_ALERT);
162 					alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
163 					(void)alert->Go();
164 					return;
165 				}
166 			}
167 			break;
168 		}
169 		case kSettingChanged:
170 			SettingsPane::MessageReceived(msg);
171 			break;
172 		default:
173 			BView::MessageReceived(msg);
174 			break;
175 	}
176 }
177 
178 
179 status_t
180 GeneralView::Load(BMessage& settings)
181 {
182 	char buffer[255];
183 
184 	fNotificationBox->SetValue(_IsServerRunning() ? B_CONTROL_ON : B_CONTROL_OFF);
185 
186 	bool autoStart;
187 	if (settings.FindBool(kAutoStartName, &autoStart) != B_OK)
188 		autoStart = kDefaultAutoStart;
189 	fAutoStart->SetValue(autoStart ? B_CONTROL_ON : B_CONTROL_OFF);
190 
191 	int32 timeout;
192 	if (settings.FindInt32(kTimeoutName, &timeout) != B_OK)
193 		timeout = kDefaultTimeout;
194 	(void)sprintf(buffer, "%" B_PRId32, timeout);
195 	fTimeout->SetText(buffer);
196 
197 	return B_OK;
198 }
199 
200 
201 status_t
202 GeneralView::Save(BMessage& settings)
203 {
204 	bool autoStart = (fAutoStart->Value() == B_CONTROL_ON);
205 	settings.AddBool(kAutoStartName, autoStart);
206 
207 	int32 timeout = atol(fTimeout->Text());
208 	settings.AddInt32(kTimeoutName, timeout);
209 
210 	return B_OK;
211 }
212 
213 
214 status_t
215 GeneralView::Revert()
216 {
217 	return B_ERROR;
218 }
219 
220 
221 bool
222 GeneralView::_CanFindServer(entry_ref* ref)
223 {
224 	// Try searching with be_roster
225 	if (be_roster->FindApp(kNotificationServerSignature, ref) == B_OK)
226 		return true;
227 
228 	// Try with a query and take the first result
229 	BVolumeRoster vroster;
230 	BVolume volume;
231 	char volName[B_FILE_NAME_LENGTH];
232 
233 	vroster.Rewind();
234 
235 	while (vroster.GetNextVolume(&volume) == B_OK) {
236 		if ((volume.InitCheck() != B_OK) || !volume.KnowsQuery())
237 			continue;
238 
239 		volume.GetName(volName);
240 
241 		BQuery *query = new BQuery();
242 		query->SetPredicate("(BEOS:APP_SIG==\""kNotificationServerSignature"\")");
243 		query->SetVolume(&volume);
244 		query->Fetch();
245 
246 		if (query->GetNextRef(ref) == B_OK)
247 			return true;
248 	}
249 
250 	return false;
251 }
252 
253 
254 bool
255 GeneralView::_IsServerRunning()
256 {
257 	return be_roster->IsRunning(kNotificationServerSignature);
258 }
259