xref: /haiku/src/preferences/shortcuts/ShortcutsSpec.cpp (revision 387609c3be3a7b9072024bf2ffb62078ca2cd176)
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