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