1 /* 2 * Copyright 1999-2010 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jeremy Friesner 7 * Fredrik Modéen 8 */ 9 10 11 #include "ShortcutsWindow.h" 12 13 #include <math.h> 14 #include <stdio.h> 15 16 #include <Alert.h> 17 #include <Application.h> 18 #include <Catalog.h> 19 #include <Clipboard.h> 20 #include <File.h> 21 #include <FindDirectory.h> 22 #include <Input.h> 23 #include <Locale.h> 24 #include <Menu.h> 25 #include <MenuBar.h> 26 #include <MenuItem.h> 27 #include <MessageFilter.h> 28 #include <Path.h> 29 #include <PopUpMenu.h> 30 #include <ScrollBar.h> 31 #include <ScrollView.h> 32 #include <String.h> 33 34 #include "ColumnListView.h" 35 36 #include "KeyInfos.h" 37 #include "MetaKeyStateMap.h" 38 #include "ParseCommandLine.h" 39 #include "ShortcutsFilterConstants.h" 40 #include "ShortcutsSpec.h" 41 42 43 // Window sizing constraints 44 #define MIN_WIDTH 600 45 #define MIN_HEIGHT 130 46 #define MAX_WIDTH 65535 47 #define MAX_HEIGHT 65535 48 49 // Default window position 50 #define WINDOW_START_X 30 51 #define WINDOW_START_Y 100 52 53 #undef B_TRANSLATE_CONTEXT 54 #define B_TRANSLATE_CONTEXT "ShortcutsWindow" 55 56 #define ERROR "Shortcuts error" 57 #define WARNING "Shortcuts warning" 58 59 // Global constants for Shortcuts 60 #define V_SPACING 5 // vertical spacing between GUI components 61 62 63 // Creates a pop-up-menu that reflects the possible states of the specified 64 // meta-key. 65 static BPopUpMenu* 66 CreateMetaPopUp(int col) 67 { 68 MetaKeyStateMap& map = GetNthKeyMap(col); 69 BPopUpMenu * popup = new BPopUpMenu(NULL, false); 70 int numStates = map.GetNumStates(); 71 72 for (int i = 0; i < numStates; i++) 73 popup->AddItem(new BMenuItem(map.GetNthStateDesc(i), NULL)); 74 75 return popup; 76 } 77 78 79 // Creates a pop-up that allows the user to choose a key-cap visually 80 static BPopUpMenu* 81 CreateKeysPopUp() 82 { 83 BPopUpMenu* popup = new BPopUpMenu(NULL, false); 84 int numKeys = GetNumKeyIndices(); 85 for (int i = 0; i < numKeys; i++) { 86 const char* next = GetKeyName(i); 87 88 if (next) 89 popup->AddItem(new BMenuItem(next, NULL)); 90 } 91 return popup; 92 } 93 94 95 ShortcutsWindow::ShortcutsWindow() 96 : 97 BWindow(BRect(WINDOW_START_X, WINDOW_START_Y, WINDOW_START_X + MIN_WIDTH, 98 WINDOW_START_Y + MIN_HEIGHT * 2), B_TRANSLATE("Shortcuts"), 99 B_DOCUMENT_WINDOW, 0L), 100 fSavePanel(NULL), 101 fOpenPanel(NULL), 102 fSelectPanel(NULL), 103 fKeySetModified(false), 104 fLastOpenWasAppend(false) 105 { 106 ShortcutsSpec::InitializeMetaMaps(); 107 108 SetSizeLimits(MIN_WIDTH, MAX_WIDTH, MIN_HEIGHT, MAX_HEIGHT); 109 BMenuBar* menuBar = new BMenuBar(BRect(0, 0, 0, 0), "Menu Bar"); 110 111 BMenu* fileMenu = new BMenu(B_TRANSLATE("File")); 112 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Open KeySet" B_UTF8_ELLIPSIS), 113 new BMessage(OPEN_KEYSET), 'O')); 114 fileMenu->AddItem(new BMenuItem( 115 B_TRANSLATE("Append KeySet" B_UTF8_ELLIPSIS), 116 new BMessage(APPEND_KEYSET), 'A')); 117 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Revert to saved"), 118 new BMessage(REVERT_KEYSET), 'A')); 119 fileMenu->AddItem(new BSeparatorItem); 120 fileMenu->AddItem(new BMenuItem( 121 B_TRANSLATE("Save KeySet as" B_UTF8_ELLIPSIS), 122 new BMessage(SAVE_KEYSET_AS), 'S')); 123 fileMenu->AddItem(new BSeparatorItem); 124 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("About Shortcuts"), 125 new BMessage(B_ABOUT_REQUESTED))); 126 fileMenu->AddItem(new BSeparatorItem); 127 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Quit"), 128 new BMessage(B_QUIT_REQUESTED), 'Q')); 129 menuBar->AddItem(fileMenu); 130 131 AddChild(menuBar); 132 133 font_height fh; 134 be_plain_font->GetHeight(&fh); 135 float vButtonHeight = ceil(fh.ascent) + ceil(fh.descent) + 5.0f; 136 137 BRect tableBounds = Bounds(); 138 tableBounds.top = menuBar->Bounds().bottom + 1; 139 tableBounds.right -= B_V_SCROLL_BAR_WIDTH; 140 tableBounds.bottom -= (B_H_SCROLL_BAR_HEIGHT + V_SPACING + vButtonHeight + 141 V_SPACING * 2); 142 143 BScrollView* containerView; 144 fColumnListView = new ColumnListView(tableBounds, &containerView, NULL, 145 B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE, 146 B_SINGLE_SELECTION_LIST, true, true, true, B_NO_BORDER); 147 148 fColumnListView->SetEditMessage(new BMessage(HOTKEY_ITEM_MODIFIED), 149 BMessenger(this)); 150 151 const float metaWidth = 50.0f; 152 153 for (int i = 0; i < ShortcutsSpec::NUM_META_COLUMNS; i++) { 154 fColumnListView->AddColumn( 155 new CLVColumn(ShortcutsSpec::GetColumnName(i), CreateMetaPopUp(i), 156 metaWidth, CLV_SORT_KEYABLE)); 157 } 158 159 fColumnListView->AddColumn(new CLVColumn(B_TRANSLATE("Key"), 160 CreateKeysPopUp(), 60, CLV_SORT_KEYABLE)); 161 162 BPopUpMenu* popup = new BPopUpMenu(NULL, false); 163 popup->AddItem(new BMenuItem( 164 B_TRANSLATE("(Choose application with file requester)"), NULL)); 165 popup->AddItem(new BMenuItem( 166 B_TRANSLATE("*InsertString \"Your Text Here\""), NULL)); 167 popup->AddItem(new BMenuItem( 168 B_TRANSLATE("*MoveMouse +20 +0"), NULL)); 169 popup->AddItem(new BMenuItem(B_TRANSLATE("*MoveMouseTo 50% 50%"), NULL)); 170 popup->AddItem(new BMenuItem(B_TRANSLATE("*MouseButton 1"), NULL)); 171 popup->AddItem(new BMenuItem( 172 B_TRANSLATE("*LaunchHandler text/html"), NULL)); 173 popup->AddItem(new BMenuItem( 174 B_TRANSLATE("*Multi \"*MoveMouseTo 100% 0\" \"*MouseButton 1\""), 175 NULL)); 176 popup->AddItem(new BMenuItem(B_TRANSLATE("*MouseDown"), NULL)); 177 popup->AddItem(new BMenuItem(B_TRANSLATE("*MouseUp"), NULL)); 178 popup->AddItem(new BMenuItem( 179 B_TRANSLATE("*SendMessage application/x-vnd.Be-TRAK 'Tfnd'"), NULL)); 180 popup->AddItem(new BMenuItem(B_TRANSLATE("*Beep"), NULL)); 181 fColumnListView->AddColumn(new CLVColumn(B_TRANSLATE("Application"), popup, 182 323.0, CLV_SORT_KEYABLE)); 183 184 fColumnListView->SetSortFunction(ShortcutsSpec::MyCompare); 185 AddChild(containerView); 186 187 fColumnListView->SetSelectionMessage(new BMessage(HOTKEY_ITEM_SELECTED)); 188 fColumnListView->SetTarget(this); 189 190 BRect buttonBounds = Bounds(); 191 buttonBounds.left += V_SPACING; 192 buttonBounds.right = ((buttonBounds.right - buttonBounds.left) / 2.0f) 193 + buttonBounds.left; 194 buttonBounds.bottom -= V_SPACING * 2; 195 buttonBounds.top = buttonBounds.bottom - vButtonHeight; 196 buttonBounds.right -= B_V_SCROLL_BAR_WIDTH; 197 float origRight = buttonBounds.right; 198 buttonBounds.right = (buttonBounds.left + origRight) * 0.40f - 199 (V_SPACING / 2); 200 AddChild(fAddButton = new ResizableButton(Bounds(), buttonBounds, "add", 201 B_TRANSLATE("Add new shortcut"), new BMessage(ADD_HOTKEY_ITEM))); 202 buttonBounds.left = buttonBounds.right + V_SPACING; 203 buttonBounds.right = origRight; 204 AddChild(fRemoveButton = new ResizableButton(Bounds(), buttonBounds, 205 "remove", B_TRANSLATE("Remove selected shortcut"), 206 new BMessage(REMOVE_HOTKEY_ITEM))); 207 208 fRemoveButton->SetEnabled(false); 209 210 float offset = (buttonBounds.right - buttonBounds.left) / 2.0f; 211 BRect saveButtonBounds = buttonBounds; 212 saveButtonBounds.right = Bounds().right - B_V_SCROLL_BAR_WIDTH - offset; 213 saveButtonBounds.left = buttonBounds.right + V_SPACING + offset; 214 AddChild(fSaveButton = new ResizableButton(Bounds(), saveButtonBounds, 215 "save", B_TRANSLATE("Save & apply"), new BMessage(SAVE_KEYSET))); 216 217 fSaveButton->SetEnabled(false); 218 219 entry_ref ref; 220 if (_GetSettingsFile(&ref)) { 221 BMessage msg(B_REFS_RECEIVED); 222 msg.AddRef("refs", &ref); 223 msg.AddString("startupRef", "please"); 224 PostMessage(&msg); // Tell ourself to load this file if it exists. 225 } 226 Show(); 227 } 228 229 230 ShortcutsWindow::~ShortcutsWindow() 231 { 232 delete fSavePanel; 233 delete fOpenPanel; 234 delete fSelectPanel; 235 be_app->PostMessage(B_QUIT_REQUESTED); 236 } 237 238 239 bool 240 ShortcutsWindow::QuitRequested() 241 { 242 bool ret = true; 243 244 if (fKeySetModified) { 245 BAlert* alert = new BAlert(WARNING, 246 B_TRANSLATE("Really quit without saving your changes?"), 247 B_TRANSLATE("Don't save"), B_TRANSLATE("Cancel"), 248 B_TRANSLATE("Save")); 249 switch(alert->Go()) { 250 case 1: 251 ret = false; 252 break; 253 254 case 2: 255 // Save: automatically if possible, otherwise go back and open 256 // up the file requester 257 if (fLastSaved.InitCheck() == B_OK) { 258 if (_SaveKeySet(fLastSaved) == false) { 259 (new BAlert(ERROR, 260 B_TRANSLATE("Shortcuts was unable to save your " 261 "KeySet file!"), 262 B_TRANSLATE("Oh no")))->Go(); 263 ret = true; //quit anyway 264 } 265 } else { 266 PostMessage(SAVE_KEYSET); 267 ret = false; 268 } 269 break; 270 default: 271 ret = true; 272 break; 273 } 274 } 275 276 if (ret) 277 fColumnListView->DeselectAll(); 278 return ret; 279 } 280 281 282 bool 283 ShortcutsWindow::_GetSettingsFile(entry_ref* eref) 284 { 285 BPath path; 286 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 287 return false; 288 else 289 path.Append(SHORTCUTS_SETTING_FILE_NAME); 290 291 if (BEntry(path.Path(), true).GetRef(eref) == B_OK) 292 return true; 293 else 294 return false; 295 } 296 297 298 // Saves a settings file to (saveEntry). Returns true iff successful. 299 bool 300 ShortcutsWindow::_SaveKeySet(BEntry& saveEntry) 301 { 302 BFile saveTo(&saveEntry, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 303 if (saveTo.InitCheck() != B_OK) 304 return false; 305 306 BMessage saveMsg; 307 for (int i = 0; i < fColumnListView->CountItems(); i++) { 308 BMessage next; 309 if (((ShortcutsSpec*)fColumnListView->ItemAt(i))->Archive(&next) 310 == B_OK) 311 saveMsg.AddMessage("spec", &next); 312 else 313 printf("Error archiving ShortcutsSpec #%i!\n", i); 314 } 315 316 bool ret = (saveMsg.Flatten(&saveTo) == B_OK); 317 318 if (ret) { 319 fKeySetModified = false; 320 fSaveButton->SetEnabled(false); 321 } 322 323 return ret; 324 } 325 326 327 // Appends new entries from the file specified in the "spec" entry of 328 // (loadMsg). Returns true iff successful. 329 bool 330 ShortcutsWindow::_LoadKeySet(const BMessage& loadMsg) 331 { 332 int i = 0; 333 BMessage msg; 334 while (loadMsg.FindMessage("spec", i++, &msg) == B_OK) { 335 ShortcutsSpec* spec = (ShortcutsSpec*)ShortcutsSpec::Instantiate(&msg); 336 if (spec != NULL) 337 fColumnListView->AddItem(spec); 338 else 339 printf("_LoadKeySet: Error parsing spec!\n"); 340 } 341 return true; 342 } 343 344 345 // Creates a new entry and adds it to the GUI. (defaultCommand) will be the 346 // text in the entry, or NULL if no text is desired. 347 void 348 ShortcutsWindow::_AddNewSpec(const char* defaultCommand) 349 { 350 _MarkKeySetModified(); 351 352 ShortcutsSpec* spec; 353 int curSel = fColumnListView->CurrentSelection(); 354 if (curSel >= 0) { 355 spec = new ShortcutsSpec(*((ShortcutsSpec*) 356 fColumnListView->ItemAt(curSel))); 357 358 if (defaultCommand) 359 spec->SetCommand(defaultCommand); 360 } else 361 spec = new ShortcutsSpec(defaultCommand ? defaultCommand : ""); 362 363 fColumnListView->AddItem(spec); 364 fColumnListView->Select(fColumnListView->CountItems() - 1); 365 fColumnListView->ScrollToSelection(); 366 } 367 368 369 void 370 ShortcutsWindow::MessageReceived(BMessage* msg) 371 { 372 switch(msg->what) { 373 case OPEN_KEYSET: 374 case APPEND_KEYSET: 375 fLastOpenWasAppend = (msg->what == APPEND_KEYSET); 376 if (fOpenPanel) 377 fOpenPanel->Show(); 378 else { 379 BMessenger m(this); 380 fOpenPanel = new BFilePanel(B_OPEN_PANEL, &m, NULL, 0, false); 381 fOpenPanel->Show(); 382 } 383 fOpenPanel->SetButtonLabel(B_DEFAULT_BUTTON, fLastOpenWasAppend ? 384 B_TRANSLATE("Append") : B_TRANSLATE("Open")); 385 break; 386 387 case REVERT_KEYSET: 388 { 389 // Send a message to myself, to get me to reload the settings file 390 fLastOpenWasAppend = false; 391 BMessage reload(B_REFS_RECEIVED); 392 entry_ref eref; 393 _GetSettingsFile(&eref); 394 reload.AddRef("refs", &eref); 395 reload.AddString("startupRef", "yeah"); 396 PostMessage(&reload); 397 break; 398 } 399 400 // Respond to drag-and-drop messages here 401 case B_SIMPLE_DATA: 402 { 403 int i = 0; 404 405 entry_ref ref; 406 while (msg->FindRef("refs", i++, &ref) == B_OK) { 407 BEntry entry(&ref); 408 if (entry.InitCheck() == B_OK) { 409 BPath path(&entry); 410 411 if (path.InitCheck() == B_OK) { 412 // Add a new item with the given path. 413 BString str(path.Path()); 414 DoStandardEscapes(str); 415 _AddNewSpec(str.String()); 416 } 417 } 418 } 419 break; 420 } 421 422 // Respond to FileRequester's messages here 423 case B_REFS_RECEIVED: 424 { 425 // Find file ref 426 entry_ref ref; 427 bool isStartMsg = msg->HasString("startupRef"); 428 if (msg->FindRef("refs", &ref) == B_OK) { 429 // load the file into (fileMsg) 430 BMessage fileMsg; 431 { 432 BFile file(&ref, B_READ_ONLY); 433 if ((file.InitCheck() != B_OK) 434 || (fileMsg.Unflatten(&file) != B_OK)) { 435 if (isStartMsg) { 436 // use this to save to anyway 437 fLastSaved = BEntry(&ref); 438 break; 439 } else { 440 (new BAlert(ERROR, 441 B_TRANSLATE("Shortcuts was couldn't open your " 442 "KeySet file!"), B_TRANSLATE("OK")))->Go(NULL); 443 break; 444 } 445 } 446 } 447 448 if (fLastOpenWasAppend == false) { 449 // Clear the menu... 450 while (ShortcutsSpec* item 451 = ((ShortcutsSpec*)fColumnListView->RemoveItem(0L))) { 452 delete item; 453 } 454 } 455 456 if (_LoadKeySet(fileMsg)) { 457 if (isStartMsg) fLastSaved = BEntry(&ref); 458 fSaveButton->SetEnabled(isStartMsg == false); 459 460 // If we just loaded in the Shortcuts settings file, then 461 // no need to tell the user to save on exit. 462 entry_ref eref; 463 _GetSettingsFile(&eref); 464 if (ref == eref) fKeySetModified = false; 465 } else { 466 (new BAlert(ERROR, 467 B_TRANSLATE("Shortcuts was unable to parse your " 468 "KeySet file!"), 469 B_TRANSLATE("OK")))->Go(NULL); 470 break; 471 } 472 } 473 break; 474 } 475 476 // These messages come from the pop-up menu of the Applications column 477 case SELECT_APPLICATION: 478 { 479 int csel = fColumnListView->CurrentSelection(); 480 if (csel >= 0) { 481 entry_ref aref; 482 if (msg->FindRef("refs", &aref) == B_OK) { 483 BEntry ent(&aref); 484 if (ent.InitCheck() == B_OK) { 485 BPath path; 486 if ((ent.GetPath(&path) == B_OK) 487 && (((ShortcutsSpec *) 488 fColumnListView->ItemAt(csel))-> 489 ProcessColumnTextString(ShortcutsSpec:: 490 STRING_COLUMN_INDEX, path.Path()))) { 491 492 fColumnListView->InvalidateItem(csel); 493 _MarkKeySetModified(); 494 } 495 } 496 } 497 } 498 break; 499 } 500 501 case SAVE_KEYSET: 502 { 503 bool showSaveError = false; 504 505 const char * name; 506 entry_ref entry; 507 if ((msg->FindString("name", &name) == B_OK) 508 && (msg->FindRef("directory", &entry) == B_OK)) { 509 BDirectory dir(&entry); 510 BEntry saveTo(&dir, name, true); 511 showSaveError = ((saveTo.InitCheck() != B_OK) 512 || (_SaveKeySet(saveTo) == false)); 513 } else if (fLastSaved.InitCheck() == B_OK) { 514 // We've saved this before, save over previous file. 515 showSaveError = (_SaveKeySet(fLastSaved) == false); 516 } else PostMessage(SAVE_KEYSET_AS); // open the save requester... 517 518 if (showSaveError) { 519 (new BAlert(ERROR, 520 B_TRANSLATE("Shortcuts wasn't able to save your keyset."), 521 B_TRANSLATE("OK")))->Go(NULL); 522 } 523 break; 524 } 525 526 case SAVE_KEYSET_AS: 527 { 528 if (fSavePanel) 529 fSavePanel->Show(); 530 else { 531 BMessage msg(SAVE_KEYSET); 532 BMessenger messenger(this); 533 fSavePanel = new BFilePanel(B_SAVE_PANEL, &messenger, NULL, 0, 534 false, &msg); 535 fSavePanel->Show(); 536 } 537 break; 538 } 539 540 case B_ABOUT_REQUESTED: 541 be_app_messenger.SendMessage(B_ABOUT_REQUESTED); 542 break; 543 544 case ADD_HOTKEY_ITEM: 545 _AddNewSpec(NULL); 546 break; 547 548 case REMOVE_HOTKEY_ITEM: 549 { 550 int index = fColumnListView->CurrentSelection(); 551 if (index >= 0) { 552 CLVListItem* item = (CLVListItem*) 553 fColumnListView->ItemAt(index); 554 fColumnListView->RemoveItem(index); 555 delete item; 556 _MarkKeySetModified(); 557 558 // Rules for new selection: If there is an item at (index), 559 // select it. Otherwise, if there is an item at (index-1), 560 // select it. Otherwise, select nothing. 561 int num = fColumnListView->CountItems(); 562 if (num > 0) { 563 if (index < num) 564 fColumnListView->Select(index); 565 else { 566 if (index > 0) 567 index--; 568 if (index < num) 569 fColumnListView->Select(index); 570 } 571 } 572 } 573 break; 574 } 575 576 // Received when the user clicks on the ColumnListView 577 case HOTKEY_ITEM_SELECTED: 578 { 579 int32 index = -1; 580 msg->FindInt32("index", &index); 581 bool validItem = (index >= 0); 582 fRemoveButton->SetEnabled(validItem); 583 break; 584 } 585 586 // Received when an entry is to be modified in response to GUI activity 587 case HOTKEY_ITEM_MODIFIED: 588 { 589 int32 row, column; 590 591 if ((msg->FindInt32("row", &row) == B_OK) 592 && (msg->FindInt32("column", &column) == B_OK)) { 593 int32 key; 594 const char* bytes; 595 596 if (row >= 0) { 597 ShortcutsSpec* item = (ShortcutsSpec*) 598 fColumnListView->ItemAt(row); 599 bool repaintNeeded = false; // default 600 601 if (msg->HasInt32("mouseClick")) { 602 repaintNeeded = item->ProcessColumnMouseClick(column); 603 } else if ((msg->FindString("bytes", &bytes) == B_OK) 604 && (msg->FindInt32("key", &key) == B_OK)) { 605 repaintNeeded = item->ProcessColumnKeyStroke(column, 606 bytes, key); 607 } else if (msg->FindInt32("unmappedkey", &key) == 608 B_OK) { 609 repaintNeeded = ((column == item->KEY_COLUMN_INDEX) 610 && ((key > 0xFF) || (GetKeyName(key) != NULL)) 611 && (item->ProcessColumnKeyStroke(column, NULL, 612 key))); 613 } else if (msg->FindString("text", &bytes) == B_OK) { 614 if ((bytes[0] == '(')&&(bytes[1] == 'C')) { 615 if (fSelectPanel) 616 fSelectPanel->Show(); 617 else { 618 BMessage msg(SELECT_APPLICATION); 619 BMessenger m(this); 620 fSelectPanel = new BFilePanel(B_OPEN_PANEL, &m, 621 NULL, 0, false, &msg); 622 fSelectPanel->Show(); 623 } 624 fSelectPanel->SetButtonLabel(B_DEFAULT_BUTTON, 625 B_TRANSLATE("Select")); 626 } else { 627 repaintNeeded = item->ProcessColumnTextString( 628 column, bytes); 629 } 630 } 631 632 if (repaintNeeded) { 633 fColumnListView->InvalidateItem(row); 634 _MarkKeySetModified(); 635 } 636 } 637 } 638 break; 639 } 640 641 default: 642 BWindow::MessageReceived(msg); 643 break; 644 } 645 } 646 647 648 void 649 ShortcutsWindow::_MarkKeySetModified() 650 { 651 if (fKeySetModified == false) { 652 fKeySetModified = true; 653 fSaveButton->SetEnabled(true); 654 } 655 } 656 657 658 void 659 ShortcutsWindow::Quit() 660 { 661 for (int i = fColumnListView->CountItems() - 1; i >= 0; i--) 662 delete (ShortcutsSpec*)fColumnListView->ItemAt(i); 663 664 fColumnListView->MakeEmpty(); 665 BWindow::Quit(); 666 } 667 668 669 void 670 ShortcutsWindow::FrameResized(float w, float h) 671 { 672 fAddButton->ChangeToNewSize(w, h); 673 fRemoveButton->ChangeToNewSize(w, h); 674 fSaveButton->ChangeToNewSize(w, h); 675 } 676 677 678 void 679 ShortcutsWindow::DispatchMessage(BMessage* msg, BHandler* handler) 680 { 681 switch(msg->what) { 682 case B_COPY: 683 case B_CUT: 684 if (be_clipboard->Lock()) { 685 int32 row = fColumnListView->CurrentSelection(); 686 int32 column = fColumnListView->GetSelectedColumn(); 687 if ((row >= 0) 688 && (column == ShortcutsSpec::STRING_COLUMN_INDEX)) { 689 ShortcutsSpec* spec = (ShortcutsSpec*) 690 fColumnListView->ItemAt(row); 691 if (spec) { 692 BMessage* data = be_clipboard->Data(); 693 data->RemoveName("text/plain"); 694 data->AddData("text/plain", B_MIME_TYPE, 695 spec->GetCellText(column), 696 strlen(spec->GetCellText(column))); 697 be_clipboard->Commit(); 698 699 if (msg->what == B_CUT) { 700 spec->ProcessColumnTextString(column, ""); 701 _MarkKeySetModified(); 702 fColumnListView->InvalidateItem(row); 703 } 704 } 705 } 706 be_clipboard->Unlock(); 707 } 708 break; 709 710 case B_PASTE: 711 if (be_clipboard->Lock()) { 712 BMessage* data = be_clipboard->Data(); 713 const char* text; 714 ssize_t textLen; 715 if (data->FindData("text/plain", B_MIME_TYPE, (const void**) 716 &text, &textLen) == B_OK) { 717 int32 row = fColumnListView->CurrentSelection(); 718 int32 column = fColumnListView->GetSelectedColumn(); 719 if ((row >= 0) 720 && (column == ShortcutsSpec::STRING_COLUMN_INDEX)) { 721 ShortcutsSpec* spec = (ShortcutsSpec*) 722 fColumnListView->ItemAt(row); 723 if (spec) { 724 for (ssize_t i = 0; i < textLen; i++) { 725 char buf[2] = {text[i], 0x00}; 726 spec->ProcessColumnKeyStroke(column, buf, 0); 727 } 728 } 729 fColumnListView->InvalidateItem(row); 730 _MarkKeySetModified(); 731 } 732 } 733 be_clipboard->Unlock(); 734 } 735 break; 736 737 default: 738 BWindow::DispatchMessage(msg, handler); 739 break; 740 } 741 } 742 743