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