16c333678SFredrik Modeen /*
2b42302c5SJohn Scipione * Copyright 1999-2009 Jeremy Friesner
3b42302c5SJohn Scipione * Copyright 2009-2010 Haiku, Inc. All rights reserved.
46c333678SFredrik Modeen * Distributed under the terms of the MIT License.
56c333678SFredrik Modeen *
66c333678SFredrik Modeen * Authors:
76c333678SFredrik Modeen * Jeremy Friesner
86c333678SFredrik Modeen */
96c333678SFredrik Modeen
106c333678SFredrik Modeen #include "ShortcutsSpec.h"
116c333678SFredrik Modeen
126c333678SFredrik Modeen #include <ctype.h>
136c333678SFredrik Modeen #include <stdio.h>
146c333678SFredrik Modeen
15fa1ee6d4SJonas Sundström #include <Beep.h>
163672a07eSStephan Aßmus #include <Catalog.h>
17149ce46dSAdrien Destugues #include <ColumnTypes.h>
18fa1ee6d4SJonas Sundström #include <Directory.h>
193672a07eSStephan Aßmus #include <Locale.h>
20fa1ee6d4SJonas Sundström #include <NodeInfo.h>
21fa1ee6d4SJonas Sundström #include <Path.h>
226c333678SFredrik Modeen #include <Region.h>
236c333678SFredrik Modeen #include <Window.h>
246c333678SFredrik Modeen
256c333678SFredrik Modeen #include "ColumnListView.h"
266c333678SFredrik Modeen
276c333678SFredrik Modeen #include "BitFieldTesters.h"
286c333678SFredrik Modeen #include "CommandActuators.h"
29149ce46dSAdrien Destugues #include "KeyInfos.h"
30fa1ee6d4SJonas Sundström #include "MetaKeyStateMap.h"
316c333678SFredrik Modeen #include "ParseCommandLine.h"
326c333678SFredrik Modeen
33fa1ee6d4SJonas Sundström
346c333678SFredrik Modeen #define CLASS "ShortcutsSpec : "
356c333678SFredrik Modeen
36546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
37546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "ShortcutsSpec"
38fa1ee6d4SJonas Sundström
396c333678SFredrik Modeen const float _height = 20.0f;
406c333678SFredrik Modeen
413672a07eSStephan Aßmus static MetaKeyStateMap sMetaMaps[ShortcutsSpec::NUM_META_COLUMNS];
426c333678SFredrik Modeen
433672a07eSStephan Aßmus static bool sFontCached = false;
443672a07eSStephan Aßmus static BFont sViewFont;
453672a07eSStephan Aßmus static float sFontHeight;
466c333678SFredrik Modeen
473672a07eSStephan Aßmus const char* ShortcutsSpec::sShiftName;
483672a07eSStephan Aßmus const char* ShortcutsSpec::sControlName;
493672a07eSStephan Aßmus const char* ShortcutsSpec::sOptionName;
503672a07eSStephan Aßmus const char* ShortcutsSpec::sCommandName;
51fa1ee6d4SJonas Sundström
526c333678SFredrik Modeen
536c333678SFredrik Modeen #define ICON_BITMAP_RECT BRect(0.0f, 0.0f, 15.0f, 15.0f)
545788aadfSJérôme Duval #define ICON_BITMAP_SPACE B_RGBA32
556c333678SFredrik Modeen
56fa1ee6d4SJonas Sundström
576c333678SFredrik Modeen // Returns the (pos)'th char in the string, or '\0' if (pos) if off the end of
586c333678SFredrik Modeen // the string
596c333678SFredrik Modeen static char
GetLetterAt(const char * str,int pos)606c333678SFredrik Modeen GetLetterAt(const char* str, int pos)
616c333678SFredrik Modeen {
623672a07eSStephan Aßmus for (int i = 0; i < pos; i++) {
636c333678SFredrik Modeen if (str[i] == '\0')
646c333678SFredrik Modeen return '\0';
653672a07eSStephan Aßmus }
666c333678SFredrik Modeen return str[pos];
676c333678SFredrik Modeen }
686c333678SFredrik Modeen
696c333678SFredrik Modeen
706c333678SFredrik Modeen // Setup the states in a standard manner for a pair of meta-keys.
716c333678SFredrik Modeen static void
SetupStandardMap(MetaKeyStateMap & map,const char * name,uint32 both,uint32 left,uint32 right)726c333678SFredrik Modeen SetupStandardMap(MetaKeyStateMap& map, const char* name, uint32 both,
736c333678SFredrik Modeen uint32 left, uint32 right)
746c333678SFredrik Modeen {
756c333678SFredrik Modeen map.SetInfo(name);
766c333678SFredrik Modeen
776c333678SFredrik Modeen // In this state, neither key may be pressed.
78*bc622f6bSHumdinger map.AddState(B_TRANSLATE("(None)"), new HasBitsFieldTester(0, both));
796c333678SFredrik Modeen
806c333678SFredrik Modeen // Here, either may be pressed. (Remember both is NOT a 2-bit chord, it's
816c333678SFredrik Modeen // another bit entirely)
82*bc622f6bSHumdinger map.AddState(B_TRANSLATE("Either"), new HasBitsFieldTester(both));
836c333678SFredrik Modeen
846c333678SFredrik Modeen // Here, only the left may be pressed
85*bc622f6bSHumdinger map.AddState(B_TRANSLATE("Left"), new HasBitsFieldTester(left, right));
866c333678SFredrik Modeen
876c333678SFredrik Modeen // Here, only the right may be pressed
88*bc622f6bSHumdinger map.AddState(B_TRANSLATE("Right"), new HasBitsFieldTester(right, left));
896c333678SFredrik Modeen
906c333678SFredrik Modeen // Here, both must be pressed.
91*bc622f6bSHumdinger map.AddState(B_TRANSLATE("Both"), new HasBitsFieldTester(left | right));
926c333678SFredrik Modeen }
936c333678SFredrik Modeen
946c333678SFredrik Modeen
953672a07eSStephan Aßmus MetaKeyStateMap&
GetNthKeyMap(int which)963672a07eSStephan Aßmus GetNthKeyMap(int which)
976c333678SFredrik Modeen {
983672a07eSStephan Aßmus return sMetaMaps[which];
996c333678SFredrik Modeen }
1006c333678SFredrik Modeen
1016c333678SFredrik Modeen
1023672a07eSStephan Aßmus /*static*/ void
InitializeMetaMaps()1033672a07eSStephan Aßmus ShortcutsSpec::InitializeMetaMaps()
1046c333678SFredrik Modeen {
1053672a07eSStephan Aßmus static bool metaMapsInitialized = false;
1063672a07eSStephan Aßmus if (metaMapsInitialized)
1073672a07eSStephan Aßmus return;
1083672a07eSStephan Aßmus metaMapsInitialized = true;
1093672a07eSStephan Aßmus
1103672a07eSStephan Aßmus _InitModifierNames();
1113672a07eSStephan Aßmus
1123672a07eSStephan Aßmus SetupStandardMap(sMetaMaps[ShortcutsSpec::SHIFT_COLUMN_INDEX], sShiftName,
1136c333678SFredrik Modeen B_SHIFT_KEY, B_LEFT_SHIFT_KEY, B_RIGHT_SHIFT_KEY);
1146c333678SFredrik Modeen
1153672a07eSStephan Aßmus SetupStandardMap(sMetaMaps[ShortcutsSpec::CONTROL_COLUMN_INDEX],
1163672a07eSStephan Aßmus sControlName, B_CONTROL_KEY, B_LEFT_CONTROL_KEY, B_RIGHT_CONTROL_KEY);
1176c333678SFredrik Modeen
1183672a07eSStephan Aßmus SetupStandardMap(sMetaMaps[ShortcutsSpec::COMMAND_COLUMN_INDEX],
1193672a07eSStephan Aßmus sCommandName, B_COMMAND_KEY, B_LEFT_COMMAND_KEY, B_RIGHT_COMMAND_KEY);
1206c333678SFredrik Modeen
1213672a07eSStephan Aßmus SetupStandardMap(sMetaMaps[ShortcutsSpec::OPTION_COLUMN_INDEX], sOptionName
1226c333678SFredrik Modeen , B_OPTION_KEY, B_LEFT_OPTION_KEY, B_RIGHT_OPTION_KEY);
1236c333678SFredrik Modeen }
1246c333678SFredrik Modeen
1256c333678SFredrik Modeen
ShortcutsSpec(const char * cmd)1266c333678SFredrik Modeen ShortcutsSpec::ShortcutsSpec(const char* cmd)
1276c333678SFredrik Modeen :
128149ce46dSAdrien Destugues BRow(),
1296c333678SFredrik Modeen fCommand(NULL),
1306c333678SFredrik Modeen fBitmap(ICON_BITMAP_RECT, ICON_BITMAP_SPACE),
1316c333678SFredrik Modeen fLastBitmapName(NULL),
1326c333678SFredrik Modeen fBitmapValid(false),
1336c333678SFredrik Modeen fKey(0),
1346c333678SFredrik Modeen fCursorPtsValid(false)
1356c333678SFredrik Modeen {
1366c333678SFredrik Modeen for (int i = 0; i < NUM_META_COLUMNS; i++)
1376c333678SFredrik Modeen fMetaCellStateIndex[i] = 0;
1386c333678SFredrik Modeen SetCommand(cmd);
1396c333678SFredrik Modeen }
1406c333678SFredrik Modeen
1416c333678SFredrik Modeen
ShortcutsSpec(const ShortcutsSpec & from)1426c333678SFredrik Modeen ShortcutsSpec::ShortcutsSpec(const ShortcutsSpec& from)
1436c333678SFredrik Modeen :
144149ce46dSAdrien Destugues BRow(),
1456c333678SFredrik Modeen fCommand(NULL),
1466c333678SFredrik Modeen fBitmap(ICON_BITMAP_RECT, ICON_BITMAP_SPACE),
1476c333678SFredrik Modeen fLastBitmapName(NULL),
1486c333678SFredrik Modeen fBitmapValid(false),
1496c333678SFredrik Modeen fKey(from.fKey),
1506c333678SFredrik Modeen fCursorPtsValid(false)
1516c333678SFredrik Modeen {
1526c333678SFredrik Modeen for (int i = 0; i < NUM_META_COLUMNS; i++)
1536c333678SFredrik Modeen fMetaCellStateIndex[i] = from.fMetaCellStateIndex[i];
1546c333678SFredrik Modeen
1556c333678SFredrik Modeen SetCommand(from.fCommand);
1566c333678SFredrik Modeen SetSelectedColumn(from.GetSelectedColumn());
157149ce46dSAdrien Destugues
158149ce46dSAdrien Destugues for (int i = 0; i < from.CountFields(); i++)
159149ce46dSAdrien Destugues SetField(new BStringField(
160149ce46dSAdrien Destugues static_cast<const BStringField*>(from.GetField(i))->String()), i);
1616c333678SFredrik Modeen }
1626c333678SFredrik Modeen
1636c333678SFredrik Modeen
ShortcutsSpec(BMessage * from)1646c333678SFredrik Modeen ShortcutsSpec::ShortcutsSpec(BMessage* from)
1656c333678SFredrik Modeen :
166149ce46dSAdrien Destugues BRow(),
1676c333678SFredrik Modeen fCommand(NULL),
1686c333678SFredrik Modeen fBitmap(ICON_BITMAP_RECT, ICON_BITMAP_SPACE),
1696c333678SFredrik Modeen fLastBitmapName(NULL),
1706c333678SFredrik Modeen fBitmapValid(false),
1716c333678SFredrik Modeen fCursorPtsValid(false)
1726c333678SFredrik Modeen {
1736c333678SFredrik Modeen const char* temp;
1746c333678SFredrik Modeen if (from->FindString("command", &temp) != B_NO_ERROR) {
1753672a07eSStephan Aßmus printf(CLASS);
1763672a07eSStephan Aßmus printf(" Error, no command string in archive BMessage!\n");
1776c333678SFredrik Modeen temp = "";
1786c333678SFredrik Modeen }
1796c333678SFredrik Modeen
1806c333678SFredrik Modeen SetCommand(temp);
1816c333678SFredrik Modeen
1823672a07eSStephan Aßmus if (from->FindInt32("key", (int32*) &fKey) != B_NO_ERROR) {
1833672a07eSStephan Aßmus printf(CLASS);
1843672a07eSStephan Aßmus printf(" Error, no key int32 in archive BMessage!\n");
1853672a07eSStephan Aßmus }
1866c333678SFredrik Modeen
1876c333678SFredrik Modeen for (int i = 0; i < NUM_META_COLUMNS; i++)
1886c333678SFredrik Modeen if (from->FindInt32("mcidx", i, (int32*)&fMetaCellStateIndex[i])
1893672a07eSStephan Aßmus != B_NO_ERROR) {
1903672a07eSStephan Aßmus printf(CLASS);
1913672a07eSStephan Aßmus printf(" Error, no modifiers int32 in archive BMessage!\n");
1923672a07eSStephan Aßmus }
193149ce46dSAdrien Destugues
194617096a4SJosef Gajdusek for (int i = 0; i <= STRING_COLUMN_INDEX; i++)
195617096a4SJosef Gajdusek SetField(new BStringField(GetCellText(i)), i);
1966c333678SFredrik Modeen }
1976c333678SFredrik Modeen
1986c333678SFredrik Modeen
1996c333678SFredrik Modeen void
SetCommand(const char * command)2006c333678SFredrik Modeen ShortcutsSpec::SetCommand(const char* command)
2016c333678SFredrik Modeen {
202b42302c5SJohn Scipione delete[] fCommand;
203b42302c5SJohn Scipione // out with the old (if any)...
2046c333678SFredrik Modeen fCommandLen = strlen(command) + 1;
2056c333678SFredrik Modeen fCommandNul = fCommandLen - 1;
2066c333678SFredrik Modeen fCommand = new char[fCommandLen];
2076c333678SFredrik Modeen strcpy(fCommand, command);
208149ce46dSAdrien Destugues SetField(new BStringField(command), STRING_COLUMN_INDEX);
2096c333678SFredrik Modeen }
2106c333678SFredrik Modeen
2116c333678SFredrik Modeen
2126c333678SFredrik Modeen const char*
GetColumnName(int i)2136c333678SFredrik Modeen ShortcutsSpec::GetColumnName(int i)
2146c333678SFredrik Modeen {
2153672a07eSStephan Aßmus return sMetaMaps[i].GetName();
2166c333678SFredrik Modeen }
2176c333678SFredrik Modeen
2186c333678SFredrik Modeen
2196c333678SFredrik Modeen status_t
Archive(BMessage * into,bool deep) const2206c333678SFredrik Modeen ShortcutsSpec::Archive(BMessage* into, bool deep) const
2216c333678SFredrik Modeen {
2226c333678SFredrik Modeen status_t ret = BArchivable::Archive(into, deep);
2236c333678SFredrik Modeen if (ret != B_NO_ERROR)
2246c333678SFredrik Modeen return ret;
2256c333678SFredrik Modeen
2266c333678SFredrik Modeen into->AddString("class", "ShortcutsSpec");
2276c333678SFredrik Modeen
2286c333678SFredrik Modeen // These fields are for our prefs panel's benefit only
2296c333678SFredrik Modeen into->AddString("command", fCommand);
2306c333678SFredrik Modeen into->AddInt32("key", fKey);
2316c333678SFredrik Modeen
2326c333678SFredrik Modeen // Assemble a BitFieldTester for the input_server add-on to use...
2336c333678SFredrik Modeen MinMatchFieldTester test(NUM_META_COLUMNS, false);
2346c333678SFredrik Modeen for (int i = 0; i < NUM_META_COLUMNS; i++) {
2356c333678SFredrik Modeen // for easy parsing by prefs applet on load-in
2366c333678SFredrik Modeen into->AddInt32("mcidx", fMetaCellStateIndex[i]);
2373672a07eSStephan Aßmus test.AddSlave(sMetaMaps[i].GetNthStateTester(fMetaCellStateIndex[i]));
2386c333678SFredrik Modeen }
2396c333678SFredrik Modeen
2406c333678SFredrik Modeen BMessage testerMsg;
2416c333678SFredrik Modeen ret = test.Archive(&testerMsg);
2426c333678SFredrik Modeen if (ret != B_NO_ERROR)
2436c333678SFredrik Modeen return ret;
2446c333678SFredrik Modeen
2456c333678SFredrik Modeen into->AddMessage("modtester", &testerMsg);
2466c333678SFredrik Modeen
2476c333678SFredrik Modeen // And also create a CommandActuator for the input_server add-on to execute
2486c333678SFredrik Modeen CommandActuator* act = CreateCommandActuator(fCommand);
2496c333678SFredrik Modeen BMessage actMsg;
2506c333678SFredrik Modeen ret = act->Archive(&actMsg);
2516c333678SFredrik Modeen if (ret != B_NO_ERROR)
2526c333678SFredrik Modeen return ret;
2536c333678SFredrik Modeen delete act;
2546c333678SFredrik Modeen
2556c333678SFredrik Modeen into->AddMessage("act", &actMsg);
256149ce46dSAdrien Destugues
2576c333678SFredrik Modeen return ret;
2586c333678SFredrik Modeen }
2596c333678SFredrik Modeen
2606c333678SFredrik Modeen
2616c333678SFredrik Modeen BArchivable*
Instantiate(BMessage * from)2626c333678SFredrik Modeen ShortcutsSpec::Instantiate(BMessage* from)
2636c333678SFredrik Modeen {
2646c333678SFredrik Modeen bool validateOK = false;
2656c333678SFredrik Modeen if (validate_instantiation(from, "ShortcutsSpec"))
2666c333678SFredrik Modeen validateOK = true;
2676c333678SFredrik Modeen else // test the old one.
2686c333678SFredrik Modeen if (validate_instantiation(from, "SpicyKeysSpec"))
2696c333678SFredrik Modeen validateOK = true;
2706c333678SFredrik Modeen
2716c333678SFredrik Modeen if (!validateOK)
2726c333678SFredrik Modeen return NULL;
2736c333678SFredrik Modeen
2746c333678SFredrik Modeen return new ShortcutsSpec(from);
2756c333678SFredrik Modeen }
2766c333678SFredrik Modeen
2776c333678SFredrik Modeen
~ShortcutsSpec()2786c333678SFredrik Modeen ShortcutsSpec::~ShortcutsSpec()
2796c333678SFredrik Modeen {
2806c333678SFredrik Modeen delete[] fCommand;
2816c333678SFredrik Modeen delete[] fLastBitmapName;
2826c333678SFredrik Modeen }
2836c333678SFredrik Modeen
2846c333678SFredrik Modeen
2856c333678SFredrik Modeen void
_CacheViewFont(BView * owner)2866c333678SFredrik Modeen ShortcutsSpec::_CacheViewFont(BView* owner)
2876c333678SFredrik Modeen {
2883672a07eSStephan Aßmus if (sFontCached == false) {
2893672a07eSStephan Aßmus sFontCached = true;
2903672a07eSStephan Aßmus owner->GetFont(&sViewFont);
2916c333678SFredrik Modeen font_height fh;
2923672a07eSStephan Aßmus sViewFont.GetHeight(&fh);
2933672a07eSStephan Aßmus sFontHeight = fh.ascent - fh.descent;
2946c333678SFredrik Modeen }
2956c333678SFredrik Modeen }
2966c333678SFredrik Modeen
2976c333678SFredrik Modeen
2986c333678SFredrik Modeen const char*
GetCellText(int whichColumn) const2996c333678SFredrik Modeen ShortcutsSpec::GetCellText(int whichColumn) const
3006c333678SFredrik Modeen {
3016c333678SFredrik Modeen const char* temp = ""; // default
3023672a07eSStephan Aßmus switch (whichColumn) {
3036c333678SFredrik Modeen case KEY_COLUMN_INDEX:
3046c333678SFredrik Modeen {
3056c333678SFredrik Modeen if ((fKey > 0) && (fKey <= 0xFF)) {
3066c333678SFredrik Modeen temp = GetKeyName(fKey);
3076c333678SFredrik Modeen if (temp == NULL)
3086c333678SFredrik Modeen temp = "";
3096c333678SFredrik Modeen } else if (fKey > 0xFF) {
3100bbc331fSJérôme Duval sprintf(fScratch, "#%" B_PRIx32, fKey);
3116c333678SFredrik Modeen return fScratch;
3126c333678SFredrik Modeen }
3136c333678SFredrik Modeen break;
3143672a07eSStephan Aßmus }
3156c333678SFredrik Modeen
3166c333678SFredrik Modeen case STRING_COLUMN_INDEX:
3176c333678SFredrik Modeen temp = fCommand;
3186c333678SFredrik Modeen break;
3196c333678SFredrik Modeen
3206c333678SFredrik Modeen default:
3216c333678SFredrik Modeen if ((whichColumn >= 0) && (whichColumn < NUM_META_COLUMNS))
3223672a07eSStephan Aßmus temp = sMetaMaps[whichColumn].GetNthStateDesc(
3236c333678SFredrik Modeen fMetaCellStateIndex[whichColumn]);
324149ce46dSAdrien Destugues if (temp[0] == '(')
325149ce46dSAdrien Destugues temp = "";
3266c333678SFredrik Modeen break;
3276c333678SFredrik Modeen }
3286c333678SFredrik Modeen return temp;
3296c333678SFredrik Modeen }
3306c333678SFredrik Modeen
3316c333678SFredrik Modeen
3326c333678SFredrik Modeen bool
ProcessColumnMouseClick(int whichColumn)3336c333678SFredrik Modeen ShortcutsSpec::ProcessColumnMouseClick(int whichColumn)
3346c333678SFredrik Modeen {
3356c333678SFredrik Modeen if ((whichColumn >= 0) && (whichColumn < NUM_META_COLUMNS)) {
3366c333678SFredrik Modeen // same as hitting space for these columns: cycle entry
3376c333678SFredrik Modeen const char temp = B_SPACE;
3386c333678SFredrik Modeen
3396c333678SFredrik Modeen // 3rd arg isn't correct but it isn't read for this case anyway
3406c333678SFredrik Modeen return ProcessColumnKeyStroke(whichColumn, &temp, 0);
3416c333678SFredrik Modeen }
3426c333678SFredrik Modeen return false;
3436c333678SFredrik Modeen }
3446c333678SFredrik Modeen
3456c333678SFredrik Modeen
3466c333678SFredrik Modeen bool
ProcessColumnTextString(int whichColumn,const char * string)3476c333678SFredrik Modeen ShortcutsSpec::ProcessColumnTextString(int whichColumn, const char* string)
3486c333678SFredrik Modeen {
3496c333678SFredrik Modeen switch (whichColumn) {
3506c333678SFredrik Modeen case STRING_COLUMN_INDEX:
3516c333678SFredrik Modeen SetCommand(string);
3526c333678SFredrik Modeen return true;
3536c333678SFredrik Modeen break;
3546c333678SFredrik Modeen
3556c333678SFredrik Modeen case KEY_COLUMN_INDEX:
3566c333678SFredrik Modeen {
3576c333678SFredrik Modeen fKey = FindKeyCode(string);
358149ce46dSAdrien Destugues SetField(new BStringField(GetCellText(whichColumn)),
359149ce46dSAdrien Destugues KEY_COLUMN_INDEX);
3606c333678SFredrik Modeen return true;
3616c333678SFredrik Modeen break;
3626c333678SFredrik Modeen }
3636c333678SFredrik Modeen
3646c333678SFredrik Modeen default:
3656c333678SFredrik Modeen return ProcessColumnKeyStroke(whichColumn, string, 0);
3666c333678SFredrik Modeen }
3676c333678SFredrik Modeen }
3686c333678SFredrik Modeen
3696c333678SFredrik Modeen
3706c333678SFredrik Modeen bool
_AttemptTabCompletion()3716c333678SFredrik Modeen ShortcutsSpec::_AttemptTabCompletion()
3726c333678SFredrik Modeen {
373b42302c5SJohn Scipione bool result = false;
3746c333678SFredrik Modeen
3756c333678SFredrik Modeen int32 argc;
3766c333678SFredrik Modeen char** argv = ParseArgvFromString(fCommand, argc);
3776c333678SFredrik Modeen if (argc > 0) {
3786c333678SFredrik Modeen // Try to complete the path partially expressed in the last argument!
3796c333678SFredrik Modeen char* arg = argv[argc - 1];
3806c333678SFredrik Modeen char* fileFragment = strrchr(arg, '/');
381b42302c5SJohn Scipione if (fileFragment != NULL) {
3826c333678SFredrik Modeen const char* directoryName = (fileFragment == arg) ? "/" : arg;
3836c333678SFredrik Modeen *fileFragment = '\0';
3846c333678SFredrik Modeen fileFragment++;
385b42302c5SJohn Scipione int fragmentLength = strlen(fileFragment);
3866c333678SFredrik Modeen
3876c333678SFredrik Modeen BDirectory dir(directoryName);
3886c333678SFredrik Modeen if (dir.InitCheck() == B_NO_ERROR) {
3896c333678SFredrik Modeen BEntry nextEnt;
3906c333678SFredrik Modeen BPath nextPath;
3916c333678SFredrik Modeen BList matchList;
3926c333678SFredrik Modeen int maxEntryLen = 0;
3936c333678SFredrik Modeen
3946c333678SFredrik Modeen // Read in all the files in the directory whose names start
3956c333678SFredrik Modeen // with our fragment.
3966c333678SFredrik Modeen while (dir.GetNextEntry(&nextEnt) == B_NO_ERROR) {
3976c333678SFredrik Modeen if (nextEnt.GetPath(&nextPath) == B_NO_ERROR) {
3986c333678SFredrik Modeen char* filePath = strrchr(nextPath.Path(), '/') + 1;
399b42302c5SJohn Scipione if (strncmp(filePath, fileFragment, fragmentLength) == 0) {
4006c333678SFredrik Modeen int len = strlen(filePath);
4016c333678SFredrik Modeen if (len > maxEntryLen)
4026c333678SFredrik Modeen maxEntryLen = len;
4036c333678SFredrik Modeen char* newStr = new char[len + 1];
4046c333678SFredrik Modeen strcpy(newStr, filePath);
4056c333678SFredrik Modeen matchList.AddItem(newStr);
4066c333678SFredrik Modeen }
4076c333678SFredrik Modeen }
4086c333678SFredrik Modeen }
4096c333678SFredrik Modeen
4106c333678SFredrik Modeen // Now slowly extend our keyword to its full length, counting
4116c333678SFredrik Modeen // numbers of matches at each step. If the match list length
412b42302c5SJohn Scipione // is 1, we can use that whole entry. If it's greater than one,
413b42302c5SJohn Scipione // we can use just the match length.
4146c333678SFredrik Modeen int matchLen = matchList.CountItems();
4156c333678SFredrik Modeen if (matchLen > 0) {
4166c333678SFredrik Modeen int i;
4176c333678SFredrik Modeen BString result(fileFragment);
418b42302c5SJohn Scipione for (i = fragmentLength; i < maxEntryLen; i++) {
4196c333678SFredrik Modeen // See if all the matching entries have the same letter
4206c333678SFredrik Modeen // in the next position... if so, we can go farther.
4216c333678SFredrik Modeen char commonLetter = '\0';
4226c333678SFredrik Modeen for (int j = 0; j < matchLen; j++) {
4236c333678SFredrik Modeen char nextLetter = GetLetterAt(
4246c333678SFredrik Modeen (char*)matchList.ItemAt(j), i);
4256c333678SFredrik Modeen if (commonLetter == '\0')
4266c333678SFredrik Modeen commonLetter = nextLetter;
4276c333678SFredrik Modeen
4286c333678SFredrik Modeen if ((commonLetter != '\0')
4296c333678SFredrik Modeen && (commonLetter != nextLetter)) {
4306c333678SFredrik Modeen commonLetter = '\0';// failed;
4316c333678SFredrik Modeen beep();
4326c333678SFredrik Modeen break;
4336c333678SFredrik Modeen }
4346c333678SFredrik Modeen }
4356c333678SFredrik Modeen if (commonLetter == '\0')
4366c333678SFredrik Modeen break;
4376c333678SFredrik Modeen else
4386c333678SFredrik Modeen result.Append(commonLetter, 1);
4396c333678SFredrik Modeen }
4406c333678SFredrik Modeen
441b42302c5SJohn Scipione // free all the strings we allocated
4426c333678SFredrik Modeen for (int k = 0; k < matchLen; k++)
4436c333678SFredrik Modeen delete [] ((char*)matchList.ItemAt(k));
4446c333678SFredrik Modeen
4456c333678SFredrik Modeen DoStandardEscapes(result);
4466c333678SFredrik Modeen
4476c333678SFredrik Modeen BString wholeLine;
4486c333678SFredrik Modeen for (int l = 0; l < argc - 1; l++) {
4496c333678SFredrik Modeen wholeLine += argv[l];
4506c333678SFredrik Modeen wholeLine += " ";
4516c333678SFredrik Modeen }
4526c333678SFredrik Modeen
4536c333678SFredrik Modeen BString file(directoryName);
4546c333678SFredrik Modeen DoStandardEscapes(file);
4556c333678SFredrik Modeen
4566c333678SFredrik Modeen if (directoryName[strlen(directoryName) - 1] != '/')
4576c333678SFredrik Modeen file += "/";
4586c333678SFredrik Modeen
4596c333678SFredrik Modeen file += result;
4606c333678SFredrik Modeen
4616c333678SFredrik Modeen // Remove any trailing slash...
4626c333678SFredrik Modeen const char* fileStr = file.String();
4636c333678SFredrik Modeen if (fileStr[strlen(fileStr) - 1] == '/')
4646c333678SFredrik Modeen file.RemoveLast("/");
4656c333678SFredrik Modeen
466b42302c5SJohn Scipione // and re-append it iff the file is a dir.
4676c333678SFredrik Modeen BDirectory testFileAsDir(file.String());
4686c333678SFredrik Modeen if ((strcmp(file.String(), "/") != 0)
4696c333678SFredrik Modeen && (testFileAsDir.InitCheck() == B_NO_ERROR))
4706c333678SFredrik Modeen file.Append("/");
4716c333678SFredrik Modeen
4726c333678SFredrik Modeen wholeLine += file;
4736c333678SFredrik Modeen
4746c333678SFredrik Modeen SetCommand(wholeLine.String());
475b42302c5SJohn Scipione result = true;
4766c333678SFredrik Modeen }
4776c333678SFredrik Modeen }
4786c333678SFredrik Modeen *(fileFragment - 1) = '/';
4796c333678SFredrik Modeen }
4806c333678SFredrik Modeen }
4816c333678SFredrik Modeen FreeArgv(argv);
482b42302c5SJohn Scipione
483b42302c5SJohn Scipione return result;
4846c333678SFredrik Modeen }
4856c333678SFredrik Modeen
4866c333678SFredrik Modeen
4876c333678SFredrik Modeen bool
ProcessColumnKeyStroke(int whichColumn,const char * bytes,int32 key)4886c333678SFredrik Modeen ShortcutsSpec::ProcessColumnKeyStroke(int whichColumn, const char* bytes,
4896c333678SFredrik Modeen int32 key)
4906c333678SFredrik Modeen {
491b42302c5SJohn Scipione bool result = false;
492b42302c5SJohn Scipione
4936c333678SFredrik Modeen switch (whichColumn) {
4946c333678SFredrik Modeen case KEY_COLUMN_INDEX:
4953672a07eSStephan Aßmus if (key > -1) {
4963672a07eSStephan Aßmus if ((int32)fKey != key) {
4976c333678SFredrik Modeen fKey = key;
498b42302c5SJohn Scipione result = true;
4996c333678SFredrik Modeen }
5006c333678SFredrik Modeen }
5016c333678SFredrik Modeen break;
5026c333678SFredrik Modeen
5036c333678SFredrik Modeen case STRING_COLUMN_INDEX:
5046c333678SFredrik Modeen {
5056c333678SFredrik Modeen switch (bytes[0]) {
5066c333678SFredrik Modeen case B_BACKSPACE:
5076c333678SFredrik Modeen case B_DELETE:
5086c333678SFredrik Modeen if (fCommandNul > 0) {
5096c333678SFredrik Modeen // trim a char off the string
5106c333678SFredrik Modeen fCommand[fCommandNul - 1] = '\0';
5116c333678SFredrik Modeen fCommandNul--; // note new nul position
512b42302c5SJohn Scipione result = true;
5136c333678SFredrik Modeen }
5146c333678SFredrik Modeen break;
5156c333678SFredrik Modeen
5166c333678SFredrik Modeen case B_TAB:
5176c333678SFredrik Modeen if (_AttemptTabCompletion()) {
518b42302c5SJohn Scipione result = true;
5196c333678SFredrik Modeen } else
5206c333678SFredrik Modeen beep();
5216c333678SFredrik Modeen break;
5226c333678SFredrik Modeen
5236c333678SFredrik Modeen default:
5246c333678SFredrik Modeen {
525529fd9afSOliver Tappe uint32 newCharLen = strlen(bytes);
5266c333678SFredrik Modeen if ((newCharLen > 0) && (bytes[0] >= ' ')) {
5276c333678SFredrik Modeen bool reAllocString = false;
5286c333678SFredrik Modeen // Make sure we have enough room in our command string
5296c333678SFredrik Modeen // to add these chars...
530529fd9afSOliver Tappe while (fCommandLen - fCommandNul <= newCharLen) {
5316c333678SFredrik Modeen reAllocString = true;
5326c333678SFredrik Modeen // enough for a while...
5336c333678SFredrik Modeen fCommandLen = (fCommandLen + 10) * 2;
5346c333678SFredrik Modeen }
5356c333678SFredrik Modeen
5366c333678SFredrik Modeen if (reAllocString) {
5376c333678SFredrik Modeen char* temp = new char[fCommandLen];
5386c333678SFredrik Modeen strcpy(temp, fCommand);
5396c333678SFredrik Modeen delete [] fCommand;
5406c333678SFredrik Modeen fCommand = temp;
5416c333678SFredrik Modeen // fCommandNul is still valid since it's an offset
5426c333678SFredrik Modeen // and the string length is the same for now
5436c333678SFredrik Modeen }
5446c333678SFredrik Modeen
5456c333678SFredrik Modeen // Here we should be guaranteed enough room.
5466c333678SFredrik Modeen strncat(fCommand, bytes, fCommandLen);
5476c333678SFredrik Modeen fCommandNul += newCharLen;
548b42302c5SJohn Scipione result = true;
5496c333678SFredrik Modeen }
5506c333678SFredrik Modeen }
5516c333678SFredrik Modeen }
5526c333678SFredrik Modeen break;
5533672a07eSStephan Aßmus }
5546c333678SFredrik Modeen
5556c333678SFredrik Modeen default:
556b42302c5SJohn Scipione if (whichColumn < 0 || whichColumn >= NUM_META_COLUMNS)
557b42302c5SJohn Scipione break;
558b42302c5SJohn Scipione
5593672a07eSStephan Aßmus MetaKeyStateMap * map = &sMetaMaps[whichColumn];
5606c333678SFredrik Modeen int curState = fMetaCellStateIndex[whichColumn];
5616c333678SFredrik Modeen int origState = curState;
5626c333678SFredrik Modeen int numStates = map->GetNumStates();
5636c333678SFredrik Modeen
564b42302c5SJohn Scipione switch(bytes[0]) {
5656c333678SFredrik Modeen case B_RETURN:
5666c333678SFredrik Modeen // cycle to the previous state
5676c333678SFredrik Modeen curState = (curState + numStates - 1) % numStates;
5686c333678SFredrik Modeen break;
5696c333678SFredrik Modeen
5706c333678SFredrik Modeen case B_SPACE:
5716c333678SFredrik Modeen // cycle to the next state
5726c333678SFredrik Modeen curState = (curState + 1) % numStates;
5736c333678SFredrik Modeen break;
5746c333678SFredrik Modeen
5756c333678SFredrik Modeen default:
5766c333678SFredrik Modeen {
5776c333678SFredrik Modeen // Go to the state starting with the given letter, if
5786c333678SFredrik Modeen // any
5796c333678SFredrik Modeen char letter = bytes[0];
5806c333678SFredrik Modeen if (islower(letter))
5816c333678SFredrik Modeen letter = toupper(letter); // convert to upper case
5826c333678SFredrik Modeen
5836c333678SFredrik Modeen if ((letter == B_BACKSPACE) || (letter == B_DELETE))
584fa1ee6d4SJonas Sundström letter = '(';
585fa1ee6d4SJonas Sundström // so space bar will blank out an entry
5866c333678SFredrik Modeen
5876c333678SFredrik Modeen for (int i = 0; i < numStates; i++) {
5886c333678SFredrik Modeen const char* desc = map->GetNthStateDesc(i);
5896c333678SFredrik Modeen
5906c333678SFredrik Modeen if (desc) {
5916c333678SFredrik Modeen if (desc[0] == letter) {
5926c333678SFredrik Modeen curState = i;
5936c333678SFredrik Modeen break;
5946c333678SFredrik Modeen }
595b42302c5SJohn Scipione } else {
596b42302c5SJohn Scipione puts(B_TRANSLATE(
597b42302c5SJohn Scipione "Error, NULL state description?"));
5986c333678SFredrik Modeen }
599b42302c5SJohn Scipione }
6006c333678SFredrik Modeen }
6013672a07eSStephan Aßmus }
6026c333678SFredrik Modeen fMetaCellStateIndex[whichColumn] = curState;
6036c333678SFredrik Modeen
6046c333678SFredrik Modeen if (curState != origState)
605b42302c5SJohn Scipione result = true;
6066c333678SFredrik Modeen }
6076c333678SFredrik Modeen
608149ce46dSAdrien Destugues SetField(new BStringField(GetCellText(whichColumn)), whichColumn);
609149ce46dSAdrien Destugues
610b42302c5SJohn Scipione return result;
6116c333678SFredrik Modeen }
6126c333678SFredrik Modeen
6136c333678SFredrik Modeen
6143672a07eSStephan Aßmus /*static*/ void
_InitModifierNames()6153672a07eSStephan Aßmus ShortcutsSpec::_InitModifierNames()
6163672a07eSStephan Aßmus {
6173672a07eSStephan Aßmus sShiftName = B_TRANSLATE_COMMENT("Shift",
6183672a07eSStephan Aßmus "Name for modifier on keyboard");
6193672a07eSStephan Aßmus sControlName = B_TRANSLATE_COMMENT("Control",
6203672a07eSStephan Aßmus "Name for modifier on keyboard");
62176f3378cSHumdinger sOptionName = B_TRANSLATE_COMMENT("Option",
6223672a07eSStephan Aßmus "Name for modifier on keyboard");
6233672a07eSStephan Aßmus sCommandName = B_TRANSLATE_COMMENT("Alt",
6243672a07eSStephan Aßmus "Name for modifier on keyboard");
6253672a07eSStephan Aßmus }
626