xref: /haiku/src/apps/deskbar/PreferencesWindow.cpp (revision 830f67ef991407f287dbc1238aa5f5906d90c991)
1 /*
2  * Copyright 2009-2011 Haiku, Inc.
3  * All Rights Reserved. Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		John Scipione, jscipione@gmail.com
7  *		Jonas Sundström, jonas@kirilla.com
8  */
9 
10 
11 #include "PreferencesWindow.h"
12 
13 #include <Box.h>
14 #include <Button.h>
15 #include <Catalog.h>
16 #include <CheckBox.h>
17 #include <ControlLook.h>
18 #include <File.h>
19 #include <FormattingConventions.h>
20 #include <GroupLayout.h>
21 #include <ListView.h>
22 #include <Locale.h>
23 #include <LayoutBuilder.h>
24 #include <OpenWithTracker.h>
25 #include <Path.h>
26 #include <RadioButton.h>
27 #include <Roster.h>
28 #include <SeparatorView.h>
29 #include <Screen.h>
30 #include <Slider.h>
31 #include <SpaceLayoutItem.h>
32 #include <Spinner.h>
33 #include <View.h>
34 
35 #include "BarApp.h"
36 #include "DeskbarUtils.h"
37 #include "StatusView.h"
38 
39 
40 static const char* kSettingsFileName = "prefs_window_settings";
41 
42 
43 #undef B_TRANSLATION_CONTEXT
44 #define B_TRANSLATION_CONTEXT "PreferencesWindow"
45 
46 
47 PreferencesWindow::PreferencesWindow(BRect frame)
48 	:
49 	BWindow(frame, B_TRANSLATE("Deskbar preferences"), B_TITLED_WINDOW,
50 		B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE)
51 {
52 	// Initial settings (used by revert button)
53 	fSettings = *static_cast<TBarApp*>(be_app)->Settings();
54 
55 	// Menu controls
56 	fMenuRecentDocuments = new BCheckBox(B_TRANSLATE("Recent documents:"),
57 		new BMessage(kUpdateRecentCounts));
58 	fMenuRecentApplications = new BCheckBox(B_TRANSLATE("Recent applications:"),
59 		new BMessage(kUpdateRecentCounts));
60 	fMenuRecentFolders = new BCheckBox(B_TRANSLATE("Recent folders:"),
61 		new BMessage(kUpdateRecentCounts));
62 
63 	fMenuRecentDocumentCount = new BSpinner("recent documents", NULL,
64 		new BMessage(kUpdateRecentCounts));
65 	fMenuRecentApplicationCount = new BSpinner("recent applications", NULL,
66 		new BMessage(kUpdateRecentCounts));
67 	fMenuRecentFolderCount = new BSpinner("recent folders", NULL,
68 		new BMessage(kUpdateRecentCounts));
69 
70 	// Applications controls
71 	fAppsSort = new BCheckBox(B_TRANSLATE("Sort applications by name"),
72 		new BMessage(kSortRunningApps));
73 	fAppsSortTrackerFirst = new BCheckBox(B_TRANSLATE("Tracker always first"),
74 		new BMessage(kTrackerFirst));
75 	fAppsShowExpanders = new BCheckBox(B_TRANSLATE("Show application expander"),
76 		new BMessage(kSuperExpando));
77 	fAppsExpandNew = new BCheckBox(B_TRANSLATE("Expand new applications"),
78 		new BMessage(kExpandNewTeams));
79 	fAppsHideLabels = new BCheckBox(B_TRANSLATE("Hide application names"),
80 		new BMessage(kHideLabels));
81 	fAppsIconSizeSlider = new BSlider("icon_size", B_TRANSLATE("Icon size"),
82 		new BMessage(kResizeTeamIcons), kMinimumIconSize / kIconSizeInterval,
83 		kMaximumIconSize / kIconSizeInterval, B_HORIZONTAL);
84 	fAppsIconSizeSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
85 	fAppsIconSizeSlider->SetHashMarkCount((kMaximumIconSize - kMinimumIconSize)
86 		/ kIconSizeInterval + 1);
87 	fAppsIconSizeSlider->SetLimitLabels(B_TRANSLATE("Small"),
88 		B_TRANSLATE("Large"));
89 	fAppsIconSizeSlider->SetModificationMessage(new BMessage(kResizeTeamIcons));
90 
91 	// Window controls
92 	fWindowAlwaysOnTop = new BCheckBox(B_TRANSLATE("Always on top"),
93 		new BMessage(kAlwaysTop));
94 	fWindowAutoRaise = new BCheckBox(B_TRANSLATE("Auto-raise"),
95 		new BMessage(kAutoRaise));
96 	fWindowAutoHide = new BCheckBox(B_TRANSLATE("Auto-hide"),
97 		new BMessage(kAutoHide));
98 
99 	// Menu settings
100 	fMenuRecentDocuments->SetValue(fSettings.recentDocsEnabled);
101 	fMenuRecentDocumentCount->SetEnabled(fSettings.recentDocsEnabled);
102 	fMenuRecentDocumentCount->SetRange(0, 50);
103 	fMenuRecentDocumentCount->SetValue(fSettings.recentDocsCount);
104 
105 	fMenuRecentApplications->SetValue(fSettings.recentAppsEnabled);
106 	fMenuRecentApplicationCount->SetEnabled(fSettings.recentAppsEnabled);
107 	fMenuRecentApplicationCount->SetRange(0, 50);
108 	fMenuRecentApplicationCount->SetValue(fSettings.recentAppsCount);
109 
110 	fMenuRecentFolders->SetValue(fSettings.recentFoldersEnabled);
111 	fMenuRecentFolderCount->SetEnabled(fSettings.recentFoldersEnabled);
112 	fMenuRecentFolderCount->SetRange(0, 50);
113 	fMenuRecentFolderCount->SetValue(fSettings.recentFoldersCount);
114 
115 	// Applications settings
116 	fAppsSort->SetValue(fSettings.sortRunningApps);
117 	fAppsSortTrackerFirst->SetValue(fSettings.trackerAlwaysFirst);
118 	fAppsShowExpanders->SetValue(fSettings.superExpando);
119 	fAppsExpandNew->SetValue(fSettings.expandNewTeams);
120 	fAppsHideLabels->SetValue(fSettings.hideLabels);
121 	fAppsIconSizeSlider->SetValue(fSettings.iconSize
122 		/ kIconSizeInterval);
123 
124 	// Window settings
125 	fWindowAlwaysOnTop->SetValue(fSettings.alwaysOnTop);
126 	fWindowAutoRaise->SetValue(fSettings.autoRaise);
127 	fWindowAutoHide->SetValue(fSettings.autoHide);
128 
129 	_EnableDisableDependentItems();
130 
131 	// Targets
132 	fAppsSort->SetTarget(be_app);
133 	fAppsSortTrackerFirst->SetTarget(be_app);
134 	fAppsShowExpanders->SetTarget(be_app);
135 	fAppsExpandNew->SetTarget(be_app);
136 	fAppsHideLabels->SetTarget(be_app);
137 	fAppsIconSizeSlider->SetTarget(be_app);
138 
139 	fWindowAlwaysOnTop->SetTarget(be_app);
140 	fWindowAutoRaise->SetTarget(be_app);
141 	fWindowAutoHide->SetTarget(be_app);
142 
143 	const float spacing = be_control_look->DefaultItemSpacing() * 2.3;
144 
145 	// Applications
146 	BBox* appsSettingsBox = new BBox("applications");
147 	appsSettingsBox->SetLabel(B_TRANSLATE("Applications"));
148 	appsSettingsBox->AddChild(BLayoutBuilder::Group<>()
149 		.AddGroup(B_VERTICAL, 0)
150 			.Add(fAppsSort)
151 			.Add(fAppsSortTrackerFirst)
152 			.Add(fAppsShowExpanders)
153 			.AddGroup(B_HORIZONTAL, 0)
154 				.Add(BSpaceLayoutItem::CreateHorizontalStrut(spacing))
155 				.Add(fAppsExpandNew)
156 				.End()
157 			.Add(fAppsHideLabels)
158 			.AddGlue()
159 			.Add(BSpaceLayoutItem::CreateVerticalStrut(B_USE_SMALL_SPACING))
160 			.Add(fAppsIconSizeSlider)
161 			.SetInsets(B_USE_DEFAULT_SPACING)
162 			.End()
163 		.View());
164 
165 	// Menu
166 	BBox* menuBox = new BBox("menu");
167 	menuBox->SetLabel(B_TRANSLATE("Menu"));
168 	menuBox->AddChild(BLayoutBuilder::Group<>()
169 		.AddGroup(B_VERTICAL, 0)
170 			.AddGroup(B_HORIZONTAL, 0)
171 				.AddGroup(B_VERTICAL, 0)
172 					.Add(fMenuRecentDocuments)
173 					.Add(fMenuRecentFolders)
174 					.Add(fMenuRecentApplications)
175 					.End()
176 				.AddGroup(B_VERTICAL, 0)
177 					.Add(fMenuRecentDocumentCount)
178 					.Add(fMenuRecentFolderCount)
179 					.Add(fMenuRecentApplicationCount)
180 					.End()
181 				.End()
182 				.Add(BSpaceLayoutItem::CreateVerticalStrut(
183 					B_USE_SMALL_SPACING))
184 				.Add(new BButton(B_TRANSLATE("Edit in Tracker"
185 					B_UTF8_ELLIPSIS), new BMessage(kEditInTracker)))
186 			.AddGlue()
187 			.SetInsets(B_USE_DEFAULT_SPACING)
188 			.End()
189 		.View());
190 
191 	// Window
192 	BBox* windowSettingsBox = new BBox("window");
193 	windowSettingsBox->SetLabel(B_TRANSLATE("Window"));
194 	windowSettingsBox->AddChild(BLayoutBuilder::Group<>()
195 		.SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET))
196 		.AddGroup(B_VERTICAL, 0)
197 			.Add(fWindowAlwaysOnTop)
198 			.Add(fWindowAutoRaise)
199 			.Add(fWindowAutoHide)
200 			.AddGlue()
201 			.SetInsets(B_USE_DEFAULT_SPACING)
202 			.End()
203 		.View());
204 
205 	// Action Buttons
206 	fDefaultsButton = new BButton(B_TRANSLATE("Defaults"),
207 		new BMessage(kDefaults));
208 	fRevertButton = new BButton(B_TRANSLATE("Revert"),
209 		new BMessage(kRevert));
210 
211 	// Layout
212 	BLayoutBuilder::Group<>(this)
213 		.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING)
214 			.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
215 				.Add(appsSettingsBox)
216 				.AddGroup(B_VERTICAL, B_USE_SMALL_SPACING)
217 					.Add(menuBox)
218 					.Add(windowSettingsBox)
219 				.End()
220 			.End()
221 			.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
222 				.Add(fDefaultsButton)
223 				.Add(fRevertButton)
224 				.AddGlue()
225 				.End()
226 			.SetInsets(B_USE_WINDOW_SPACING)
227 			.End();
228 
229 	BMessage windowSettings;
230 	BPoint where;
231 	if (_LoadSettings(&windowSettings) == B_OK
232 		&& windowSettings.FindPoint("window_position", &where) == B_OK
233 		&& BScreen(this).Frame().Contains(where)) {
234 		MoveTo(where);
235 	} else
236 		CenterOnScreen();
237 }
238 
239 
240 PreferencesWindow::~PreferencesWindow()
241 {
242 	_UpdateRecentCounts();
243 }
244 
245 
246 void
247 PreferencesWindow::MessageReceived(BMessage* message)
248 {
249 	switch (message->what) {
250 		case kEditInTracker:
251 			OpenWithTracker(B_USER_DESKBAR_DIRECTORY);
252 			break;
253 
254 		case kUpdatePreferences:
255 			_EnableDisableDependentItems();
256 			_UpdateButtons();
257 			break;
258 
259 		case kUpdateRecentCounts:
260 			_UpdateRecentCounts();
261 			_UpdateButtons();
262 			break;
263 
264 		case kStateChanged:
265 			_EnableDisableDependentItems();
266 			break;
267 
268 		case kRevert:
269 			_UpdatePreferences(&fSettings);
270 			break;
271 
272 		case kDefaults:
273 			_UpdatePreferences(
274 				static_cast<TBarApp*>(be_app)->DefaultSettings());
275 			break;
276 
277 		default:
278 			BWindow::MessageReceived(message);
279 			break;
280 	}
281 }
282 
283 
284 bool
285 PreferencesWindow::QuitRequested()
286 {
287 	BMessage windowSettings;
288 	windowSettings.AddPoint("window_position", Frame().LeftTop());
289 	_SaveSettings(&windowSettings);
290 
291 	be_app->PostMessage(kConfigQuit);
292 
293 	return false;
294 }
295 
296 
297 void
298 PreferencesWindow::Show()
299 {
300 	if (IsHidden())
301 		SetWorkspaces(B_CURRENT_WORKSPACE);
302 
303 	_UpdateButtons();
304 
305 	BWindow::Show();
306 }
307 
308 
309 //	#pragma mark - private methods
310 
311 
312 void
313 PreferencesWindow::_EnableDisableDependentItems()
314 {
315 	TBarApp* barApp = static_cast<TBarApp*>(be_app);
316 	if (barApp->BarView()->Vertical()
317 		&& barApp->BarView()->ExpandoState()) {
318 		fAppsShowExpanders->SetEnabled(true);
319 		fAppsExpandNew->SetEnabled(fAppsShowExpanders->Value());
320 	} else {
321 		fAppsShowExpanders->SetEnabled(false);
322 		fAppsExpandNew->SetEnabled(false);
323 	}
324 
325 	fMenuRecentDocumentCount->SetEnabled(
326 		fMenuRecentDocuments->Value() != B_CONTROL_OFF);
327 	fMenuRecentFolderCount->SetEnabled(
328 		fMenuRecentFolders->Value() != B_CONTROL_OFF);
329 	fMenuRecentApplicationCount->SetEnabled(
330 		fMenuRecentApplications->Value() != B_CONTROL_OFF);
331 
332 	fWindowAutoRaise->SetEnabled(
333 		fWindowAlwaysOnTop->Value() == B_CONTROL_OFF);
334 }
335 
336 
337 bool
338 PreferencesWindow::_IsDefaultable()
339 {
340 	desk_settings* settings = static_cast<TBarApp*>(be_app)->Settings();
341 	desk_settings* defaults = static_cast<TBarApp*>(be_app)->DefaultSettings();
342 
343 	return defaults->sortRunningApps != settings->sortRunningApps
344 		|| defaults->trackerAlwaysFirst != settings->trackerAlwaysFirst
345 		|| defaults->superExpando != settings->superExpando
346 		|| defaults->expandNewTeams != settings->expandNewTeams
347 		|| defaults->hideLabels != settings->hideLabels
348 		|| defaults->iconSize != settings->iconSize
349 		|| defaults->recentAppsEnabled != settings->recentAppsEnabled
350 		|| defaults->recentDocsEnabled != settings->recentDocsEnabled
351 		|| defaults->recentFoldersEnabled
352 			!= settings->recentFoldersEnabled
353 		|| defaults->recentAppsCount != settings->recentAppsCount
354 		|| defaults->recentDocsCount != settings->recentDocsCount
355 		|| defaults->recentFoldersCount != settings->recentFoldersCount
356 		|| defaults->alwaysOnTop != settings->alwaysOnTop
357 		|| defaults->autoRaise != settings->autoRaise
358 		|| defaults->autoHide != settings->autoHide;
359 }
360 
361 
362 bool
363 PreferencesWindow::_IsRevertable()
364 {
365 	desk_settings* settings = static_cast<TBarApp*>(be_app)->Settings();
366 
367 	return fSettings.sortRunningApps != settings->sortRunningApps
368 		|| fSettings.trackerAlwaysFirst != settings->trackerAlwaysFirst
369 		|| fSettings.superExpando != settings->superExpando
370 		|| fSettings.expandNewTeams != settings->expandNewTeams
371 		|| fSettings.hideLabels != settings->hideLabels
372 		|| fSettings.iconSize != settings->iconSize
373 		|| fSettings.recentAppsEnabled != settings->recentAppsEnabled
374 		|| fSettings.recentDocsEnabled != settings->recentDocsEnabled
375 		|| fSettings.recentFoldersEnabled
376 			!= settings->recentFoldersEnabled
377 		|| fSettings.recentAppsCount != settings->recentAppsCount
378 		|| fSettings.recentDocsCount != settings->recentDocsCount
379 		|| fSettings.recentFoldersCount != settings->recentFoldersCount
380 		|| fSettings.alwaysOnTop != settings->alwaysOnTop
381 		|| fSettings.autoRaise != settings->autoRaise
382 		|| fSettings.autoHide != settings->autoHide;
383 }
384 
385 
386 status_t
387 PreferencesWindow::_InitSettingsFile(BFile* file, bool write)
388 {
389 	BPath prefsPath;
390 	status_t status = GetDeskbarSettingsDirectory(prefsPath);
391 	if (status != B_OK)
392 		return status;
393 
394 	status = prefsPath.Append(kSettingsFileName);
395 	if (status != B_OK)
396 		return status;
397 
398 	if (write) {
399 		status = file->SetTo(prefsPath.Path(),
400 			B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
401 	} else
402 		status = file->SetTo(prefsPath.Path(), B_READ_ONLY);
403 
404 	return status;
405 }
406 
407 
408 status_t
409 PreferencesWindow::_LoadSettings(BMessage* settings)
410 {
411 	BFile prefsFile;
412 	status_t status = _InitSettingsFile(&prefsFile, false);
413 	if (status != B_OK)
414 		return status;
415 
416 	return settings->Unflatten(&prefsFile);
417 }
418 
419 
420 status_t
421 PreferencesWindow::_SaveSettings(BMessage* settings)
422 {
423 	BFile prefsFile;
424 	status_t status = _InitSettingsFile(&prefsFile, true);
425 	if (status != B_OK)
426 		return status;
427 
428 	return settings->Flatten(&prefsFile);
429 }
430 
431 
432 void
433 PreferencesWindow::_UpdateButtons()
434 {
435 	fDefaultsButton->SetEnabled(_IsDefaultable());
436 	fRevertButton->SetEnabled(_IsRevertable());
437 }
438 
439 
440 void
441 PreferencesWindow::_UpdatePreferences(desk_settings* settings)
442 {
443 	desk_settings* current = static_cast<TBarApp*>(be_app)->Settings();
444 	bool updateRecentCounts = false;
445 
446 	if (current->sortRunningApps != settings->sortRunningApps) {
447 		fAppsSort->SetValue(settings->sortRunningApps);
448 		fAppsSort->Invoke();
449 	}
450 	if (current->trackerAlwaysFirst != settings->trackerAlwaysFirst) {
451 		fAppsSortTrackerFirst->SetValue(settings->trackerAlwaysFirst);
452 		fAppsSortTrackerFirst->Invoke();
453 	}
454 	if (current->superExpando != settings->superExpando) {
455 		fAppsShowExpanders->SetValue(settings->superExpando);
456 		fAppsShowExpanders->Invoke();
457 	}
458 	if (current->expandNewTeams != settings->expandNewTeams) {
459 		fAppsExpandNew->SetValue(settings->expandNewTeams);
460 		fAppsExpandNew->Invoke();
461 	}
462 	if (current->hideLabels != settings->hideLabels) {
463 		fAppsHideLabels->SetValue(settings->hideLabels);
464 		fAppsHideLabels->Invoke();
465 	}
466 	if (current->iconSize != settings->iconSize) {
467 		fAppsIconSizeSlider->SetValue(settings->iconSize / kIconSizeInterval);
468 		fAppsIconSizeSlider->Invoke();
469 	}
470 	if (current->recentDocsEnabled != settings->recentDocsEnabled) {
471 		fMenuRecentDocuments->SetValue(settings->recentDocsEnabled
472 			? B_CONTROL_ON : B_CONTROL_OFF);
473 		updateRecentCounts = true;
474 	}
475 	if (current->recentFoldersEnabled != settings->recentFoldersEnabled) {
476 		fMenuRecentFolders->SetValue(settings->recentFoldersEnabled
477 			? B_CONTROL_ON : B_CONTROL_OFF);
478 		updateRecentCounts = true;
479 	}
480 	if (current->recentAppsEnabled != settings->recentAppsEnabled) {
481 		fMenuRecentApplications->SetValue(settings->recentAppsEnabled
482 			? B_CONTROL_ON : B_CONTROL_OFF);
483 		updateRecentCounts = true;
484 	}
485 	if (current->recentDocsCount != settings->recentDocsCount) {
486 		fMenuRecentDocumentCount->SetValue(settings->recentDocsCount);
487 		updateRecentCounts = true;
488 	}
489 	if (current->recentFoldersCount != settings->recentFoldersCount) {
490 		fMenuRecentFolderCount->SetValue(settings->recentFoldersCount);
491 		updateRecentCounts = true;
492 	}
493 	if (current->recentAppsCount != settings->recentAppsCount) {
494 		fMenuRecentApplicationCount->SetValue(settings->recentAppsCount);
495 		updateRecentCounts = true;
496 	}
497 	if (current->alwaysOnTop != settings->alwaysOnTop) {
498 		fWindowAlwaysOnTop->SetValue(settings->alwaysOnTop);
499 		fWindowAlwaysOnTop->Invoke();
500 	}
501 	if (current->autoRaise != settings->autoRaise) {
502 		fWindowAutoRaise->SetValue(settings->autoRaise);
503 		fWindowAutoRaise->Invoke();
504 	}
505 	if (current->autoHide != settings->autoHide) {
506 		fWindowAutoHide->SetValue(settings->autoHide);
507 		fWindowAutoHide->Invoke();
508 	}
509 
510 	if (updateRecentCounts)
511 		_UpdateRecentCounts();
512 }
513 
514 
515 void
516 PreferencesWindow::_UpdateRecentCounts()
517 {
518 	BMessage message(kUpdateRecentCounts);
519 
520 	message.AddInt32("documents", fMenuRecentDocumentCount->Value());
521 	message.AddInt32("applications", fMenuRecentApplicationCount->Value());
522 	message.AddInt32("folders", fMenuRecentFolderCount->Value());
523 
524 	message.AddBool("documentsEnabled", fMenuRecentDocuments->Value());
525 	message.AddBool("applicationsEnabled", fMenuRecentApplications->Value());
526 	message.AddBool("foldersEnabled", fMenuRecentFolders->Value());
527 
528 	be_app->PostMessage(&message);
529 
530 	_EnableDisableDependentItems();
531 }
532