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