bool ShortcutsSpec::_AttemptTabCompletion() { bool ret = false; int32 argc; char** argv = ParseArgvFromString(fCommand, argc); if (argc > 0) { // Try to complete the path partially expressed in the last argument! char* arg = argv[argc - 1]; char* fileFragment = strrchr(arg, '/'); if (fileFragment) { const char* directoryName = (fileFragment == arg) ? "/" : arg; *fileFragment = '\0'; fileFragment++; int fragLen = strlen(fileFragment); BDirectory dir(directoryName); if (dir.InitCheck() == B_NO_ERROR) { BEntry nextEnt; BPath nextPath; BList matchList; int maxEntryLen = 0; // Read in all the files in the directory whose names start // with our fragment. while (dir.GetNextEntry(&nextEnt) == B_NO_ERROR) { if (nextEnt.GetPath(&nextPath) == B_NO_ERROR) { char* filePath = strrchr(nextPath.Path(), '/') + 1; if (strncmp(filePath, fileFragment, fragLen) == 0) { int len = strlen(filePath); if (len > maxEntryLen) maxEntryLen = len; char* newStr = new char[len + 1]; strcpy(newStr, filePath); matchList.AddItem(newStr); } } } // Now slowly extend our keyword to its full length, counting // numbers of matches at each step. If the match list length // is 1, we can use that whole entry. If it's greater than one // , we can use just the match length. int matchLen = matchList.CountItems(); if (matchLen > 0) { int i; BString result(fileFragment); for (i = fragLen; i < maxEntryLen; i++) { // See if all the matching entries have the same letter // in the next position... if so, we can go farther. char commonLetter = '\0'; for (int j = 0; j < matchLen; j++) { char nextLetter = GetLetterAt( (char*)matchList.ItemAt(j), i); if (commonLetter == '\0') commonLetter = nextLetter; if ((commonLetter != '\0') && (commonLetter != nextLetter)) { commonLetter = '\0';// failed; beep(); break; } } if (commonLetter == '\0') break; else result.Append(commonLetter, 1); } // Free all the strings we allocated for (int k = 0; k < matchLen; k++) delete [] ((char*)matchList.ItemAt(k)); DoStandardEscapes(result); BString wholeLine; for (int l = 0; l < argc - 1; l++) { wholeLine += argv[l]; wholeLine += " "; } BString file(directoryName); DoStandardEscapes(file); if (directoryName[strlen(directoryName) - 1] != '/') file += "/"; file += result; // Remove any trailing slash... const char* fileStr = file.String(); if (fileStr[strlen(fileStr)-1] == '/') file.RemoveLast("/"); // And re-append it iff the file is a dir. BDirectory testFileAsDir(file.String()); if ((strcmp(file.String(), "/") != 0) && (testFileAsDir.InitCheck() == B_NO_ERROR)) file.Append("/"); wholeLine += file; SetCommand(wholeLine.String()); ret = true; } } *(fileFragment - 1) = '/'; } } FreeArgv(argv); return ret; }
void ShortcutsWindow::MessageReceived(BMessage* msg) { switch(msg->what) { case OPEN_KEYSET: case APPEND_KEYSET: fLastOpenWasAppend = (msg->what == APPEND_KEYSET); if (fOpenPanel) fOpenPanel->Show(); else { BMessenger m(this); fOpenPanel = new BFilePanel(B_OPEN_PANEL, &m, NULL, 0, false); fOpenPanel->Show(); } fOpenPanel->SetButtonLabel(B_DEFAULT_BUTTON, fLastOpenWasAppend ? "Append" : "Open"); break; case REVERT_KEYSET: { // Send a message to myself, to get me to reload the settings file fLastOpenWasAppend = false; BMessage reload(B_REFS_RECEIVED); entry_ref eref; _GetSettingsFile(&eref); reload.AddRef("refs", &eref); reload.AddString("startupRef", "yeah"); PostMessage(&reload); } break; // Respond to drag-and-drop messages here case B_SIMPLE_DATA: { int i = 0; entry_ref ref; while (msg->FindRef("refs", i++, &ref) == B_NO_ERROR) { BEntry entry(&ref); if (entry.InitCheck() == B_NO_ERROR) { BPath path(&entry); if (path.InitCheck() == B_NO_ERROR) { // Add a new item with the given path. BString str(path.Path()); DoStandardEscapes(str); _AddNewSpec(str.String()); } } } } break; // Respond to FileRequester's messages here case B_REFS_RECEIVED: { // Find file ref entry_ref ref; bool isStartMsg = msg->HasString("startupRef"); if (msg->FindRef("refs", &ref) == B_NO_ERROR) { // load the file into (fileMsg) BMessage fileMsg; { BFile file(&ref, B_READ_ONLY); if ((file.InitCheck() != B_NO_ERROR) || (fileMsg.Unflatten(&file) != B_NO_ERROR)) { if (isStartMsg) { // use this to save to anyway fLastSaved = BEntry(&ref); break; } else { (new BAlert(ERROR, "Shortcuts was couldn't open your KeySet file!" , "Okay"))->Go(NULL); break; } } } if (fLastOpenWasAppend == false) { // Clear the menu... ShortcutsSpec * item; do { delete (item = ((ShortcutsSpec*) fColumnListView->RemoveItem(int32(0)))); } while (item); } if (_LoadKeySet(fileMsg)) { if (isStartMsg) fLastSaved = BEntry(&ref); fSaveButton->SetEnabled(isStartMsg == false); // If we just loaded in the Shortcuts settings file, then // no need to tell the user to save on exit. entry_ref eref; _GetSettingsFile(&eref); if (ref == eref) fKeySetModified = false; } else { (new BAlert(ERROR, "Shortcuts was unable to parse your KeySet file!", "Okay"))->Go(NULL); break; } } } break; // These messages come from the pop-up menu of the Applications column case SELECT_APPLICATION: { int csel = fColumnListView->CurrentSelection(); if (csel >= 0) { entry_ref aref; if (msg->FindRef("refs", &aref) == B_NO_ERROR) { BEntry ent(&aref); if (ent.InitCheck() == B_NO_ERROR) { BPath path; if ((ent.GetPath(&path) == B_NO_ERROR) && (((ShortcutsSpec *) fColumnListView->ItemAt(csel))-> ProcessColumnTextString(ShortcutsSpec:: STRING_COLUMN_INDEX, path.Path()))) { fColumnListView->InvalidateItem(csel); _MarkKeySetModified(); } } } } } break; case SAVE_KEYSET: { bool showSaveError = false; const char * name; entry_ref entry; if ((msg->FindString("name", &name) == B_NO_ERROR) && (msg->FindRef("directory", &entry) == B_NO_ERROR)) { BDirectory dir(&entry); BEntry saveTo(&dir, name, true); showSaveError = ((saveTo.InitCheck() != B_NO_ERROR) || (_SaveKeySet(saveTo) == false)); } else if (fLastSaved.InitCheck() == B_NO_ERROR) { // We've saved this before, save over previous file. showSaveError = (_SaveKeySet(fLastSaved) == false); } else PostMessage(SAVE_KEYSET_AS); // open the save requester... if (showSaveError) { (new BAlert(ERROR, "Shortcuts wasn't able to save your keyset." , "Okay"))->Go(NULL); } } break; case SAVE_KEYSET_AS: { if (fSavePanel) fSavePanel->Show(); else { BMessage msg(SAVE_KEYSET); BMessenger messenger(this); fSavePanel = new BFilePanel(B_SAVE_PANEL, &messenger, NULL, 0, false, &msg); fSavePanel->Show(); } } break; case B_ABOUT_REQUESTED: be_app_messenger.SendMessage(B_ABOUT_REQUESTED); break; case ADD_HOTKEY_ITEM: _AddNewSpec(NULL); break; case REMOVE_HOTKEY_ITEM: { int index = fColumnListView->CurrentSelection(); if (index >= 0) { CLVListItem* item = (CLVListItem*) fColumnListView->ItemAt(index); fColumnListView->RemoveItem(index); delete item; _MarkKeySetModified(); // Rules for new selection: If there is an item at (index), // select it. Otherwise, if there is an item at (index-1), // select it. Otherwise, select nothing. int num = fColumnListView->CountItems(); if (num > 0) { if (index < num) fColumnListView->Select(index); else { if (index > 0) index--; if (index < num) fColumnListView->Select(index); } } } } break; // Received when the user clicks on the ColumnListView case HOTKEY_ITEM_SELECTED: { int32 index = -1; msg->FindInt32("index", &index); bool validItem = (index >= 0); fRemoveButton->SetEnabled(validItem); } break; // Received when an entry is to be modified in response to GUI activity case HOTKEY_ITEM_MODIFIED: { int32 row, column; if ((msg->FindInt32("row", &row) == B_NO_ERROR) && (msg->FindInt32("column", &column) == B_NO_ERROR)) { int32 key; const char* bytes; if (row >= 0) { ShortcutsSpec* item = (ShortcutsSpec*) fColumnListView->ItemAt(row); bool repaintNeeded = false; // default if (msg->HasInt32("mouseClick")) { repaintNeeded = item->ProcessColumnMouseClick(column); } else if ((msg->FindString("bytes", &bytes) == B_NO_ERROR) && (msg->FindInt32("key", &key) == B_NO_ERROR)) { repaintNeeded = item->ProcessColumnKeyStroke(column, bytes, key); } else if (msg->FindInt32("unmappedkey", &key) == B_NO_ERROR) { repaintNeeded = ((column == item->KEY_COLUMN_INDEX) && ((key > 0xFF) || (GetKeyName(key) != NULL)) && (item->ProcessColumnKeyStroke(column, NULL, key))); } else if (msg->FindString("text", &bytes) == B_NO_ERROR) { if ((bytes[0] == '(')&&(bytes[1] == 'C')) { if (fSelectPanel) fSelectPanel->Show(); else { BMessage msg(SELECT_APPLICATION); BMessenger m(this); fSelectPanel = new BFilePanel(B_OPEN_PANEL, &m, NULL, 0, false, &msg); fSelectPanel->Show(); } fSelectPanel->SetButtonLabel(B_DEFAULT_BUTTON, "Select"); } else repaintNeeded = item->ProcessColumnTextString( column, bytes); } if (repaintNeeded) { fColumnListView->InvalidateItem(row); _MarkKeySetModified(); } } } } break; default: BWindow::MessageReceived(msg); break; } }