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