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