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