libroot/posix/stdio: Remove unused portions.
[haiku.git] / src / preferences / shortcuts / ShortcutsWindow.cpp
blob556db5a1683d5170423395d2ee60d1cb84c6a0bf
1 /*
2 * Copyright 1999-2009 Jeremy Friesner
3 * Copyright 2009-2010 Haiku, Inc. All rights reserved.
4 * Distributed under the terms of the MIT License.
6 * Authors:
7 * Jeremy Friesner
8 * Fredrik Modéen
9 */
12 #include "ShortcutsWindow.h"
14 #include <math.h>
15 #include <stdio.h>
17 #include <Alert.h>
18 #include <Application.h>
19 #include <Button.h>
20 #include <Catalog.h>
21 #include <Clipboard.h>
22 #include <ColumnListView.h>
23 #include <ColumnTypes.h>
24 #include <ControlLook.h>
25 #include <File.h>
26 #include <FilePanel.h>
27 #include <FindDirectory.h>
28 #include <Input.h>
29 #include <LayoutBuilder.h>
30 #include <Locale.h>
31 #include <Message.h>
32 #include <Menu.h>
33 #include <MenuBar.h>
34 #include <MenuItem.h>
35 #include <MessageFilter.h>
36 #include <Path.h>
37 #include <PopUpMenu.h>
38 #include <Screen.h>
39 #include <ScrollBar.h>
40 #include <ScrollView.h>
41 #include <String.h>
42 #include <SupportDefs.h>
44 #include "EditWindow.h"
45 #include "KeyInfos.h"
46 #include "MetaKeyStateMap.h"
47 #include "ParseCommandLine.h"
48 #include "PopUpColumn.h"
49 #include "ShortcutsFilterConstants.h"
50 #include "ShortcutsSpec.h"
53 // Window sizing constraints
54 #define MAX_WIDTH 10000
55 #define MAX_HEIGHT 10000
56 // SetSizeLimits does not provide a mechanism for specifying an
57 // unrestricted maximum. 10,000 seems to be the most common value used
58 // in other Haiku system applications.
60 #define WINDOW_SETTINGS_FILE_NAME "Shortcuts_window_settings"
61 // Because the "shortcuts_settings" file (SHORTCUTS_SETTING_FILE_NAME) is
62 // already used as a communications method between this configurator and
63 // the "shortcut_catcher" input_server filter, it should not be overloaded
64 // with window position information, instead, a separate file is used.
66 #undef B_TRANSLATION_CONTEXT
67 #define B_TRANSLATION_CONTEXT "ShortcutsWindow"
69 #define ERROR "Shortcuts error"
70 #define WARNING "Shortcuts warning"
73 // Creates a pop-up-menu that reflects the possible states of the specified
74 // meta-key.
75 static BPopUpMenu*
76 CreateMetaPopUp(int column)
78 MetaKeyStateMap& map = GetNthKeyMap(column);
79 BPopUpMenu* popup = new BPopUpMenu(NULL, false);
80 int stateCount = map.GetNumStates();
82 for (int i = 0; i < stateCount; i++)
83 popup->AddItem(new BMenuItem(map.GetNthStateDesc(i), NULL));
85 return popup;
89 // Creates a pop-up that allows the user to choose a key-cap visually
90 static BPopUpMenu*
91 CreateKeysPopUp()
93 BPopUpMenu* popup = new BPopUpMenu(NULL, false);
94 int numKeys = GetNumKeyIndices();
95 for (int i = 0; i < numKeys; i++) {
96 const char* next = GetKeyName(i);
97 if (next != NULL)
98 popup->AddItem(new BMenuItem(next, NULL));
101 return popup;
105 ShortcutsWindow::ShortcutsWindow()
107 BWindow(BRect(0, 0, 0, 0), B_TRANSLATE_SYSTEM_NAME("Shortcuts"),
108 B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS),
109 fSavePanel(NULL),
110 fOpenPanel(NULL),
111 fSelectPanel(NULL),
112 fKeySetModified(false),
113 fLastOpenWasAppend(false)
115 ShortcutsSpec::InitializeMetaMaps();
117 BMenuBar* menuBar = new BMenuBar("Menu Bar");
119 BMenu* fileMenu = new BMenu(B_TRANSLATE("File"));
120 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Open KeySet" B_UTF8_ELLIPSIS),
121 new BMessage(OPEN_KEYSET), 'O'));
122 fileMenu->AddItem(new BMenuItem(
123 B_TRANSLATE("Append KeySet" B_UTF8_ELLIPSIS),
124 new BMessage(APPEND_KEYSET), 'A'));
125 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Revert to saved"),
126 new BMessage(REVERT_KEYSET), 'A'));
127 fileMenu->AddItem(new BSeparatorItem);
128 fileMenu->AddItem(new BMenuItem(
129 B_TRANSLATE("Save KeySet as" B_UTF8_ELLIPSIS),
130 new BMessage(SAVE_KEYSET_AS), 'S'));
131 fileMenu->AddItem(new BSeparatorItem);
132 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
133 new BMessage(B_QUIT_REQUESTED), 'Q'));
134 menuBar->AddItem(fileMenu);
136 BRect tableBounds = Bounds();
137 tableBounds.top = menuBar->Bounds().bottom + 1;
138 tableBounds.right -= B_V_SCROLL_BAR_WIDTH;
139 tableBounds.bottom -= B_H_SCROLL_BAR_HEIGHT;
141 fColumnListView = new BColumnListView(NULL,
142 B_WILL_DRAW | B_FRAME_EVENTS, B_FANCY_BORDER);
144 float cellWidth = be_plain_font->StringWidth("Either") + 20;
145 // ShortcutsSpec does not seem to translate the string "Either".
147 for (int i = 0; i < ShortcutsSpec::NUM_META_COLUMNS; i++) {
148 const char* name = ShortcutsSpec::GetColumnName(i);
149 float headerWidth = be_plain_font->StringWidth(name) + 20;
150 float width = max_c(headerWidth, cellWidth);
152 fColumnListView->AddColumn(new PopUpColumn(CreateMetaPopUp(i), name,
153 width, width - 1, width * 1.5, B_TRUNCATE_END, false, true, 1),
154 fColumnListView->CountColumns());
157 float keyCellWidth = be_plain_font->StringWidth("Caps Lock") + 20;
158 fColumnListView->AddColumn(new PopUpColumn(CreateKeysPopUp(),
159 B_TRANSLATE("Key"), keyCellWidth, keyCellWidth - 10,
160 keyCellWidth + 30, B_TRUNCATE_END),
161 fColumnListView->CountColumns());
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 PopUpColumn(popup, B_TRANSLATE("Application"),
182 300.0, 223.0, 324.0, B_TRUNCATE_END, true),
183 fColumnListView->CountColumns());
185 fColumnListView->SetSelectionMessage(new BMessage(HOTKEY_ITEM_SELECTED));
186 fColumnListView->SetSelectionMode(B_SINGLE_SELECTION_LIST);
187 fColumnListView->SetTarget(this);
189 fAddButton = new BButton("add", B_TRANSLATE("Add new shortcut"),
190 new BMessage(ADD_HOTKEY_ITEM), B_FOLLOW_BOTTOM);
192 fRemoveButton = new BButton("remove",
193 B_TRANSLATE("Remove selected shortcut"),
194 new BMessage(REMOVE_HOTKEY_ITEM), B_FOLLOW_BOTTOM);
195 fRemoveButton->SetEnabled(false);
197 fSaveButton = new BButton("save", B_TRANSLATE("Save & apply"),
198 new BMessage(SAVE_KEYSET), B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT);
199 fSaveButton->SetEnabled(false);
201 CenterOnScreen();
203 entry_ref windowSettingsRef;
204 if (_GetWindowSettingsFile(&windowSettingsRef)) {
205 // The window settings file is not accepted via B_REFS_RECEIVED; this
206 // is a behind-the-scenes file that the user will never see or
207 // interact with.
208 BFile windowSettingsFile(&windowSettingsRef, B_READ_ONLY);
209 BMessage loadMessage;
210 if (loadMessage.Unflatten(&windowSettingsFile) == B_OK)
211 _LoadWindowSettings(loadMessage);
214 entry_ref keySetRef;
215 if (_GetSettingsFile(&keySetRef)) {
216 BMessage message(B_REFS_RECEIVED);
217 message.AddRef("refs", &keySetRef);
218 message.AddString("startupRef", "please");
219 PostMessage(&message);
220 // tell ourselves to load this file if it exists
223 fColumnListView->ResizeAllColumnsToPreferred();
225 BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
226 .Add(menuBar)
227 .AddGroup(B_VERTICAL)
228 .SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET))
229 .SetInsets(B_USE_WINDOW_SPACING)
230 .Add(fColumnListView)
231 .AddGroup(B_HORIZONTAL)
232 .AddGroup(B_HORIZONTAL)
233 .SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP))
234 .Add(fAddButton)
235 .Add(fRemoveButton)
236 .End()
237 .AddGroup(B_HORIZONTAL)
238 .SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT, B_ALIGN_TOP))
239 .Add(fSaveButton)
240 .End()
241 .End()
242 .End();
244 Show();
248 ShortcutsWindow::~ShortcutsWindow()
250 delete fSavePanel;
251 delete fOpenPanel;
252 delete fSelectPanel;
253 be_app->PostMessage(B_QUIT_REQUESTED);
257 bool
258 ShortcutsWindow::QuitRequested()
260 bool result = true;
262 if (fKeySetModified) {
263 BAlert* alert = new BAlert(WARNING,
264 B_TRANSLATE("Save changes before closing?"),
265 B_TRANSLATE("Cancel"), B_TRANSLATE("Don't save"),
266 B_TRANSLATE("Save"));
267 alert->SetShortcut(0, B_ESCAPE);
268 alert->SetShortcut(1, 'd');
269 alert->SetShortcut(2, 's');
270 switch (alert->Go()) {
271 case 0:
272 result = false;
273 break;
275 case 1:
276 result = true;
277 break;
279 case 2:
280 // Save: automatically if possible, otherwise go back and open
281 // up the file requester
282 if (fLastSaved.InitCheck() == B_OK) {
283 if (_SaveKeySet(fLastSaved) == false) {
284 BAlert* alert = new BAlert(ERROR,
285 B_TRANSLATE("Shortcuts was unable to save your "
286 "KeySet file!"),
287 B_TRANSLATE("Oh no"));
288 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
289 alert->Go();
290 result = true; // quit anyway
292 } else {
293 PostMessage(SAVE_KEYSET);
294 result = false;
296 break;
300 if (result) {
301 fColumnListView->DeselectAll();
303 // Save the window position.
304 entry_ref ref;
305 if (_GetWindowSettingsFile(&ref)) {
306 BEntry entry(&ref);
307 _SaveWindowSettings(entry);
311 return result;
315 bool
316 ShortcutsWindow::_GetSettingsFile(entry_ref* eref)
318 BPath path;
319 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
320 return false;
321 else
322 path.Append(SHORTCUTS_SETTING_FILE_NAME);
324 if (BEntry(path.Path(), true).GetRef(eref) == B_OK)
325 return true;
326 else
327 return false;
331 // Saves a settings file to (saveEntry). Returns true iff successful.
332 bool
333 ShortcutsWindow::_SaveKeySet(BEntry& saveEntry)
335 BFile saveTo(&saveEntry, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
336 if (saveTo.InitCheck() != B_OK)
337 return false;
339 BMessage saveMessage;
340 for (int i = 0; i < fColumnListView->CountRows(); i++) {
341 BMessage next;
342 if (((ShortcutsSpec*)fColumnListView->RowAt(i))->Archive(&next)
343 == B_OK) {
344 saveMessage.AddMessage("spec", &next);
345 } else
346 printf("Error archiving ShortcutsSpec #%i!\n", i);
349 bool result = (saveMessage.Flatten(&saveTo) == B_OK);
351 if (result) {
352 fKeySetModified = false;
353 fSaveButton->SetEnabled(false);
356 return result;
360 // Appends new entries from the file specified in the "spec" entry of
361 // (loadMessage). Returns true iff successful.
362 bool
363 ShortcutsWindow::_LoadKeySet(const BMessage& loadMessage)
365 int i = 0;
366 BMessage message;
367 while (loadMessage.FindMessage("spec", i++, &message) == B_OK) {
368 ShortcutsSpec* spec
369 = (ShortcutsSpec*)ShortcutsSpec::Instantiate(&message);
370 if (spec != NULL)
371 fColumnListView->AddRow(spec);
372 else
373 printf("_LoadKeySet: Error parsing spec!\n");
376 return true;
380 // Gets the filesystem location of the "Shortcuts_window_settings" file.
381 bool
382 ShortcutsWindow::_GetWindowSettingsFile(entry_ref* eref)
384 BPath path;
385 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
386 return false;
387 else
388 path.Append(WINDOW_SETTINGS_FILE_NAME);
390 return BEntry(path.Path(), true).GetRef(eref) == B_OK;
394 // Saves the application settings file to (saveEntry). Because this is a
395 // non-essential file, errors are ignored when writing the settings.
396 void
397 ShortcutsWindow::_SaveWindowSettings(BEntry& saveEntry)
399 BFile saveTo(&saveEntry, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
400 if (saveTo.InitCheck() != B_OK)
401 return;
403 BMessage saveMsg;
404 saveMsg.AddRect("window frame", Frame());
406 for (int i = 0; i < fColumnListView->CountColumns(); i++) {
407 BColumn* column = fColumnListView->ColumnAt(i);
408 saveMsg.AddFloat("column width", column->Width());
411 saveMsg.Flatten(&saveTo);
415 // Loads the application settings file from (loadMessage) and resizes
416 // the interface to match the previously saved settings. Because this
417 // is a non-essential file, errors are ignored when loading the settings.
418 void
419 ShortcutsWindow::_LoadWindowSettings(const BMessage& loadMessage)
421 BRect frame;
422 if (loadMessage.FindRect("window frame", &frame) == B_OK) {
423 // ensure the frame does not resize below the computed minimum.
424 float width = max_c(Bounds().right, frame.right - frame.left);
425 float height = max_c(Bounds().bottom, frame.bottom - frame.top);
426 ResizeTo(width, height);
428 // ensure the frame is not placed outside of the screen.
429 BScreen screen(this);
430 float left = min_c(screen.Frame().right - width, frame.left);
431 float top = min_c(screen.Frame().bottom - height, frame.top);
432 MoveTo(left, top);
435 for (int i = 0; i < fColumnListView->CountColumns(); i++) {
436 BColumn* column = fColumnListView->ColumnAt(i);
437 float columnWidth;
438 if (loadMessage.FindFloat("column width", i, &columnWidth) == B_OK)
439 column->SetWidth(max_c(column->Width(), columnWidth));
444 // Creates a new entry and adds it to the GUI. (defaultCommand) will be the
445 // text in the entry, or NULL if no text is desired.
446 void
447 ShortcutsWindow::_AddNewSpec(const char* defaultCommand)
449 _MarkKeySetModified();
451 ShortcutsSpec* spec;
452 BRow* curSel = fColumnListView->CurrentSelection();
453 if (curSel)
454 spec = new ShortcutsSpec(*((ShortcutsSpec*)curSel));
455 else {
456 spec = new ShortcutsSpec("");
457 for (int i = 0; i < fColumnListView->CountColumns(); i++)
458 spec->SetField(new BStringField(""), i);
461 fColumnListView->AddRow(spec);
462 fColumnListView->AddToSelection(spec);
463 fColumnListView->ScrollTo(spec);
464 if (defaultCommand)
465 spec->SetCommand(defaultCommand);
469 void
470 ShortcutsWindow::MessageReceived(BMessage* message)
472 switch (message->what) {
473 case OPEN_KEYSET:
474 case APPEND_KEYSET:
475 fLastOpenWasAppend = (message->what == APPEND_KEYSET);
476 if (fOpenPanel)
477 fOpenPanel->Show();
478 else {
479 BMessenger messenger(this);
480 fOpenPanel = new BFilePanel(B_OPEN_PANEL, &messenger, NULL,
481 0, false);
482 fOpenPanel->Show();
484 fOpenPanel->SetButtonLabel(B_DEFAULT_BUTTON, fLastOpenWasAppend ?
485 B_TRANSLATE("Append") : B_TRANSLATE("Open"));
486 break;
488 // send a message to myself, to get me to reload the settings file
489 case REVERT_KEYSET:
491 fLastOpenWasAppend = false;
492 BMessage reload(B_REFS_RECEIVED);
493 entry_ref eref;
494 _GetSettingsFile(&eref);
495 reload.AddRef("refs", &eref);
496 reload.AddString("startupRef", "yeah");
497 PostMessage(&reload);
498 break;
501 // respond to drag-and-drop messages here
502 case B_SIMPLE_DATA:
504 int i = 0;
506 entry_ref ref;
507 while (message->FindRef("refs", i++, &ref) == B_OK) {
508 BEntry entry(&ref);
509 if (entry.InitCheck() == B_OK) {
510 BPath path(&entry);
512 if (path.InitCheck() == B_OK) {
513 // Add a new item with the given path.
514 BString str(path.Path());
515 DoStandardEscapes(str);
516 _AddNewSpec(str.String());
520 break;
523 // respond to FileRequester's messages here
524 case B_REFS_RECEIVED:
526 // Find file ref
527 entry_ref ref;
528 bool isStartMsg = message->HasString("startupRef");
529 if (message->FindRef("refs", &ref) == B_OK) {
530 // load the file into (fileMsg)
531 BMessage fileMsg;
533 BFile file(&ref, B_READ_ONLY);
534 if ((file.InitCheck() != B_OK)
535 || (fileMsg.Unflatten(&file) != B_OK)) {
536 if (isStartMsg) {
537 // use this to save to anyway
538 fLastSaved = BEntry(&ref);
539 break;
540 } else {
541 BAlert* alert = new BAlert(ERROR,
542 B_TRANSLATE("Shortcuts was couldn't open your "
543 "KeySet file!"), B_TRANSLATE("OK"));
544 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
545 alert->Go(NULL);
546 break;
551 if (fLastOpenWasAppend == false) {
552 // Clear the menu...
553 while (fColumnListView->CountRows()) {
554 ShortcutsSpec* row =
555 static_cast<ShortcutsSpec*>(fColumnListView->RowAt(0));
556 fColumnListView->RemoveRow(row);
557 delete row;
561 if (_LoadKeySet(fileMsg)) {
562 if (isStartMsg) fLastSaved = BEntry(&ref);
563 fSaveButton->SetEnabled(isStartMsg == false);
565 // If we just loaded in the Shortcuts settings file, then
566 // no need to tell the user to save on exit.
567 entry_ref eref;
568 _GetSettingsFile(&eref);
569 if (ref == eref) fKeySetModified = false;
570 } else {
571 BAlert* alert = new BAlert(ERROR,
572 B_TRANSLATE("Shortcuts was unable to parse your "
573 "KeySet file!"), B_TRANSLATE("OK"));
574 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
575 alert->Go(NULL);
576 break;
579 break;
582 // these messages come from the pop-up menu of the Applications column
583 case SELECT_APPLICATION:
585 ShortcutsSpec* row =
586 static_cast<ShortcutsSpec*>(fColumnListView->CurrentSelection());
587 if (row != NULL) {
588 entry_ref aref;
589 if (message->FindRef("refs", &aref) == B_OK) {
590 BEntry ent(&aref);
591 if (ent.InitCheck() == B_OK) {
592 BPath path;
593 if ((ent.GetPath(&path) == B_OK)
594 && (row->
595 ProcessColumnTextString(ShortcutsSpec::STRING_COLUMN_INDEX,
596 path.Path()))) {
597 _MarkKeySetModified();
602 break;
605 case SAVE_KEYSET:
607 bool showSaveError = false;
609 const char* name;
610 entry_ref entry;
611 if ((message->FindString("name", &name) == B_OK)
612 && (message->FindRef("directory", &entry) == B_OK)) {
613 BDirectory dir(&entry);
614 BEntry saveTo(&dir, name, true);
615 showSaveError = ((saveTo.InitCheck() != B_OK)
616 || (_SaveKeySet(saveTo) == false));
617 } else if (fLastSaved.InitCheck() == B_OK) {
618 // We've saved this before, save over previous file.
619 showSaveError = (_SaveKeySet(fLastSaved) == false);
620 } else
621 PostMessage(SAVE_KEYSET_AS);
622 // open the save requester...
624 if (showSaveError) {
625 BAlert* alert = new BAlert(ERROR,
626 B_TRANSLATE("Shortcuts wasn't able to save your keyset."),
627 B_TRANSLATE("OK"));
628 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
629 alert->Go(NULL);
631 break;
634 case SAVE_KEYSET_AS:
636 if (fSavePanel)
637 fSavePanel->Show();
638 else {
639 BMessage message(SAVE_KEYSET);
640 BMessenger messenger(this);
641 fSavePanel = new BFilePanel(B_SAVE_PANEL, &messenger, NULL, 0,
642 false, &message);
643 fSavePanel->Show();
645 break;
648 case ADD_HOTKEY_ITEM:
649 _AddNewSpec(NULL);
650 break;
652 case REMOVE_HOTKEY_ITEM:
654 BRow* item = fColumnListView->CurrentSelection();
655 if (item) {
656 int index = fColumnListView->IndexOf(item);
657 fColumnListView->RemoveRow(item);
658 delete item;
659 _MarkKeySetModified();
661 // Rules for new selection: If there is an item at (index),
662 // select it. Otherwise, if there is an item at (index-1),
663 // select it. Otherwise, select nothing.
664 int num = fColumnListView->CountRows();
665 if (num > 0) {
666 if (index < num)
667 fColumnListView->AddToSelection(
668 fColumnListView->RowAt(index));
669 else {
670 if (index > 0)
671 index--;
672 if (index < num)
673 fColumnListView->AddToSelection(
674 fColumnListView->RowAt(index));
678 break;
681 // Received when the user clicks on the ColumnListView
682 case HOTKEY_ITEM_SELECTED:
684 if (fColumnListView->CountRows() > 0)
685 fRemoveButton->SetEnabled(true);
686 else
687 fRemoveButton->SetEnabled(false);
688 break;
691 // Received when an entry is to be modified in response to GUI activity
692 case HOTKEY_ITEM_MODIFIED:
694 int32 row, column;
696 if ((message->FindInt32("row", &row) == B_OK)
697 && (message->FindInt32("column", &column) == B_OK)) {
698 int32 key;
699 const char* bytes;
701 if (row >= 0) {
702 ShortcutsSpec* item = (ShortcutsSpec*)
703 fColumnListView->RowAt(row);
704 bool repaintNeeded = false; // default
706 if (message->HasInt32("mouseClick")) {
707 repaintNeeded = item->ProcessColumnMouseClick(column);
708 } else if ((message->FindString("bytes", &bytes) == B_OK)
709 && (message->FindInt32("key", &key) == B_OK)) {
710 repaintNeeded = item->ProcessColumnKeyStroke(column,
711 bytes, key);
712 } else if (message->FindInt32("unmappedkey", &key) ==
713 B_OK) {
714 repaintNeeded = ((column == item->KEY_COLUMN_INDEX)
715 && ((key > 0xFF) || (GetKeyName(key) != NULL))
716 && (item->ProcessColumnKeyStroke(column, NULL,
717 key)));
718 } else if (message->FindString("text", &bytes) == B_OK) {
719 if ((bytes[0] == '(')&&(bytes[1] == 'C')) {
720 if (fSelectPanel)
721 fSelectPanel->Show();
722 else {
723 BMessage message(SELECT_APPLICATION);
724 BMessenger m(this);
725 fSelectPanel = new BFilePanel(B_OPEN_PANEL, &m,
726 NULL, 0, false, &message);
727 fSelectPanel->Show();
729 fSelectPanel->SetButtonLabel(B_DEFAULT_BUTTON,
730 B_TRANSLATE("Select"));
731 } else
732 repaintNeeded = item->ProcessColumnTextString(
733 column, bytes);
736 if (repaintNeeded) {
737 fColumnListView->Invalidate(row);
738 _MarkKeySetModified();
742 break;
745 default:
746 BWindow::MessageReceived(message);
747 break;
752 void
753 ShortcutsWindow::_MarkKeySetModified()
755 if (fKeySetModified == false) {
756 fKeySetModified = true;
757 fSaveButton->SetEnabled(true);
762 void
763 ShortcutsWindow::Quit()
765 BWindow::Quit();
769 void
770 ShortcutsWindow::DispatchMessage(BMessage* message, BHandler* handler)
772 switch (message->what) {
773 case B_SIMPLE_DATA:
774 MessageReceived(message);
775 break;
777 case B_COPY:
778 case B_CUT:
779 if (be_clipboard->Lock()) {
780 ShortcutsSpec* row =
781 static_cast<ShortcutsSpec*>(fColumnListView->CurrentSelection());
782 if (row) {
783 BMessage* data = be_clipboard->Data();
784 data->RemoveName("text/plain");
785 data->AddData("text/plain", B_MIME_TYPE,
786 row->GetCellText(ShortcutsSpec::STRING_COLUMN_INDEX),
787 strlen(row->GetCellText(ShortcutsSpec::STRING_COLUMN_INDEX)));
788 be_clipboard->Commit();
790 if (message->what == B_CUT) {
791 row->ProcessColumnTextString(
792 ShortcutsSpec::STRING_COLUMN_INDEX, "");
793 _MarkKeySetModified();
796 be_clipboard->Unlock();
798 break;
800 case B_PASTE:
801 if (be_clipboard->Lock()) {
802 BMessage* data = be_clipboard->Data();
803 const char* text;
804 ssize_t textLen;
805 if (data->FindData("text/plain", B_MIME_TYPE, (const void**)
806 &text, &textLen) == B_OK) {
807 ShortcutsSpec* row =
808 static_cast<ShortcutsSpec*>(fColumnListView->CurrentSelection());
809 if (row) {
810 for (ssize_t i = 0; i < textLen; i++) {
811 char buf[2] = {text[i], 0x00};
812 row->ProcessColumnKeyStroke(
813 ShortcutsSpec::STRING_COLUMN_INDEX, buf, 0);
816 _MarkKeySetModified();
818 be_clipboard->Unlock();
820 break;
822 case B_KEY_DOWN:
823 ShortcutsSpec* selected;
824 if (message->GetInt32("modifiers", 0) != 0)
825 BWindow::DispatchMessage(message, handler);
826 else if (handler == fColumnListView
827 && (selected =
828 static_cast<ShortcutsSpec*>(fColumnListView->CurrentSelection()))) {
829 selected->ProcessColumnTextString(
830 ShortcutsSpec::KEY_COLUMN_INDEX,
831 GetKeyName(message->GetInt32("key", 0)));
832 _MarkKeySetModified();
834 break;
836 default:
837 BWindow::DispatchMessage(message, handler);
838 break;