xref: /haiku/src/preferences/shortcuts/ShortcutsSpec.cpp (revision 0bbc331f6b5a56c98243fcf9c1f2dadff4450b9f)
16c333678SFredrik Modeen /*
23672a07eSStephan Aßmus  * Copyright 1999-2010 Haiku Inc. All rights reserved.
36c333678SFredrik Modeen  * Distributed under the terms of the MIT License.
46c333678SFredrik Modeen  *
56c333678SFredrik Modeen  * Authors:
66c333678SFredrik Modeen  *		Jeremy Friesner
76c333678SFredrik Modeen  */
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>
17fa1ee6d4SJonas Sundström #include <Directory.h>
183672a07eSStephan Aßmus #include <Locale.h>
19fa1ee6d4SJonas Sundström #include <NodeInfo.h>
20fa1ee6d4SJonas Sundström #include <Path.h>
216c333678SFredrik Modeen #include <Region.h>
226c333678SFredrik Modeen #include <Window.h>
236c333678SFredrik Modeen 
246c333678SFredrik Modeen #include "ColumnListView.h"
256c333678SFredrik Modeen 
266c333678SFredrik Modeen #include "BitFieldTesters.h"
27fa1ee6d4SJonas Sundström #include "Colors.h"
286c333678SFredrik Modeen #include "CommandActuators.h"
29fa1ee6d4SJonas Sundström #include "MetaKeyStateMap.h"
306c333678SFredrik Modeen #include "ParseCommandLine.h"
316c333678SFredrik Modeen 
32fa1ee6d4SJonas Sundström 
336c333678SFredrik Modeen #define CLASS "ShortcutsSpec : "
346c333678SFredrik Modeen 
35546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
36546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "ShortcutsSpec"
37fa1ee6d4SJonas Sundström 
386c333678SFredrik Modeen const float _height = 20.0f;
396c333678SFredrik Modeen 
403672a07eSStephan Aßmus static MetaKeyStateMap sMetaMaps[ShortcutsSpec::NUM_META_COLUMNS];
416c333678SFredrik Modeen 
423672a07eSStephan Aßmus static bool sFontCached = false;
433672a07eSStephan Aßmus static BFont sViewFont;
443672a07eSStephan Aßmus static float sFontHeight;
453672a07eSStephan Aßmus static BBitmap* sActuatorBitmaps[2];
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
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
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.
786c333678SFredrik Modeen 	map.AddState("(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)
826c333678SFredrik Modeen 	map.AddState("Either", new HasBitsFieldTester(both));
836c333678SFredrik Modeen 
846c333678SFredrik Modeen 	// Here, only the left may be pressed
856c333678SFredrik Modeen 	map.AddState("Left", new HasBitsFieldTester(left, right));
866c333678SFredrik Modeen 
876c333678SFredrik Modeen 	// Here, only the right may be pressed
886c333678SFredrik Modeen 	map.AddState("Right", new HasBitsFieldTester(right, left));
896c333678SFredrik Modeen 
906c333678SFredrik Modeen 	// Here, both must be pressed.
916c333678SFredrik Modeen 	map.AddState("Both", new HasBitsFieldTester(left | right));
926c333678SFredrik Modeen }
936c333678SFredrik Modeen 
946c333678SFredrik Modeen 
953672a07eSStephan Aßmus MetaKeyStateMap&
963672a07eSStephan Aßmus GetNthKeyMap(int which)
976c333678SFredrik Modeen {
983672a07eSStephan Aßmus 	return sMetaMaps[which];
996c333678SFredrik Modeen }
1006c333678SFredrik Modeen 
1016c333678SFredrik Modeen 
1026c333678SFredrik Modeen static BBitmap*
1036c333678SFredrik Modeen MakeActuatorBitmap(bool lit)
1046c333678SFredrik Modeen {
1056c333678SFredrik Modeen 	BBitmap* map = new BBitmap(ICON_BITMAP_RECT, ICON_BITMAP_SPACE, true);
1066c333678SFredrik Modeen 	const rgb_color yellow = {255, 255, 0};
1076c333678SFredrik Modeen 	const rgb_color red = {200, 200, 200};
1086c333678SFredrik Modeen 	const rgb_color black = {0, 0, 0};
1096c333678SFredrik Modeen 	const BPoint points[10] = {
1106c333678SFredrik Modeen 		BPoint(8, 0), BPoint(9.8, 5.8), BPoint(16, 5.8),
1116c333678SFredrik Modeen 		BPoint(11, 9.0), BPoint(13, 16), BPoint(8, 11),
1126c333678SFredrik Modeen 		BPoint(3, 16), BPoint(5, 9.0), BPoint(0, 5.8),
1136c333678SFredrik Modeen 		BPoint(6.2, 5.8) };
1146c333678SFredrik Modeen 
1156c333678SFredrik Modeen 	BView* view = new BView(BRect(0, 0, 16, 16), NULL, B_FOLLOW_ALL_SIDES, 0L);
1166c333678SFredrik Modeen 	map->AddChild(view);
1176c333678SFredrik Modeen 	map->Lock();
1186c333678SFredrik Modeen 	view->SetHighColor(B_TRANSPARENT_32_BIT);
1196c333678SFredrik Modeen 	view->FillRect(ICON_BITMAP_RECT);
1206c333678SFredrik Modeen 	view->SetHighColor(lit ? yellow : red);
1216c333678SFredrik Modeen 	view->FillPolygon(points, 10);
1226c333678SFredrik Modeen 	view->SetHighColor(black);
1236c333678SFredrik Modeen 	view->StrokePolygon(points, 10);
1246c333678SFredrik Modeen 	map->Unlock();
1256c333678SFredrik Modeen 	map->RemoveChild(view);
1266c333678SFredrik Modeen 	delete view;
1276c333678SFredrik Modeen 	return map;
1286c333678SFredrik Modeen }
1296c333678SFredrik Modeen 
1306c333678SFredrik Modeen 
1313672a07eSStephan Aßmus /*static*/ void
1323672a07eSStephan Aßmus ShortcutsSpec::InitializeMetaMaps()
1336c333678SFredrik Modeen {
1343672a07eSStephan Aßmus 	static bool metaMapsInitialized = false;
1353672a07eSStephan Aßmus 	if (metaMapsInitialized)
1363672a07eSStephan Aßmus 		return;
1373672a07eSStephan Aßmus 	metaMapsInitialized = true;
1383672a07eSStephan Aßmus 
1393672a07eSStephan Aßmus 	_InitModifierNames();
1403672a07eSStephan Aßmus 
1413672a07eSStephan Aßmus 	SetupStandardMap(sMetaMaps[ShortcutsSpec::SHIFT_COLUMN_INDEX], sShiftName,
1426c333678SFredrik Modeen 		B_SHIFT_KEY, B_LEFT_SHIFT_KEY, B_RIGHT_SHIFT_KEY);
1436c333678SFredrik Modeen 
1443672a07eSStephan Aßmus 	SetupStandardMap(sMetaMaps[ShortcutsSpec::CONTROL_COLUMN_INDEX],
1453672a07eSStephan Aßmus 		sControlName, B_CONTROL_KEY, B_LEFT_CONTROL_KEY, B_RIGHT_CONTROL_KEY);
1466c333678SFredrik Modeen 
1473672a07eSStephan Aßmus 	SetupStandardMap(sMetaMaps[ShortcutsSpec::COMMAND_COLUMN_INDEX],
1483672a07eSStephan Aßmus 		sCommandName, B_COMMAND_KEY, B_LEFT_COMMAND_KEY, B_RIGHT_COMMAND_KEY);
1496c333678SFredrik Modeen 
1503672a07eSStephan Aßmus 	SetupStandardMap(sMetaMaps[ShortcutsSpec::OPTION_COLUMN_INDEX], sOptionName
1516c333678SFredrik Modeen 		, B_OPTION_KEY, B_LEFT_OPTION_KEY, B_RIGHT_OPTION_KEY);
1526c333678SFredrik Modeen 
1533672a07eSStephan Aßmus 	sActuatorBitmaps[0] = MakeActuatorBitmap(false);
1543672a07eSStephan Aßmus 	sActuatorBitmaps[1] = MakeActuatorBitmap(true);
1556c333678SFredrik Modeen }
1566c333678SFredrik Modeen 
1576c333678SFredrik Modeen 
1586c333678SFredrik Modeen ShortcutsSpec::ShortcutsSpec(const char* cmd)
1596c333678SFredrik Modeen 	:
1606c333678SFredrik Modeen 	CLVListItem(0, false, false, _height),
1616c333678SFredrik Modeen 	fCommand(NULL),
1626c333678SFredrik Modeen 	fTextOffset(0),
1636c333678SFredrik Modeen 	fBitmap(ICON_BITMAP_RECT, ICON_BITMAP_SPACE),
1646c333678SFredrik Modeen 	fLastBitmapName(NULL),
1656c333678SFredrik Modeen 	fBitmapValid(false),
1666c333678SFredrik Modeen 	fKey(0),
1676c333678SFredrik Modeen 	fCursorPtsValid(false)
1686c333678SFredrik Modeen {
1696c333678SFredrik Modeen 	for (int i = 0; i < NUM_META_COLUMNS; i++)
1706c333678SFredrik Modeen 		fMetaCellStateIndex[i] = 0;
1716c333678SFredrik Modeen 	SetCommand(cmd);
1726c333678SFredrik Modeen }
1736c333678SFredrik Modeen 
1746c333678SFredrik Modeen 
1756c333678SFredrik Modeen ShortcutsSpec::ShortcutsSpec(const ShortcutsSpec& from)
1766c333678SFredrik Modeen 	:
1776c333678SFredrik Modeen 	CLVListItem(0, false, false, _height),
1786c333678SFredrik Modeen 	fCommand(NULL),
1796c333678SFredrik Modeen 	fTextOffset(from.fTextOffset),
1806c333678SFredrik Modeen 	fBitmap(ICON_BITMAP_RECT, ICON_BITMAP_SPACE),
1816c333678SFredrik Modeen 	fLastBitmapName(NULL),
1826c333678SFredrik Modeen 	fBitmapValid(false),
1836c333678SFredrik Modeen 	fKey(from.fKey),
1846c333678SFredrik Modeen 	fCursorPtsValid(false)
1856c333678SFredrik Modeen {
1866c333678SFredrik Modeen 	for (int i = 0; i < NUM_META_COLUMNS; i++)
1876c333678SFredrik Modeen 		fMetaCellStateIndex[i] = from.fMetaCellStateIndex[i];
1886c333678SFredrik Modeen 
1896c333678SFredrik Modeen 	SetCommand(from.fCommand);
1906c333678SFredrik Modeen 	SetSelectedColumn(from.GetSelectedColumn());
1916c333678SFredrik Modeen }
1926c333678SFredrik Modeen 
1936c333678SFredrik Modeen 
1946c333678SFredrik Modeen ShortcutsSpec::ShortcutsSpec(BMessage* from)
1956c333678SFredrik Modeen 	:
1966c333678SFredrik Modeen 	CLVListItem(0, false, false, _height),
1976c333678SFredrik Modeen 	fCommand(NULL),
1986c333678SFredrik Modeen 	fTextOffset(0),
1996c333678SFredrik Modeen 	fBitmap(ICON_BITMAP_RECT, ICON_BITMAP_SPACE),
2006c333678SFredrik Modeen 	fLastBitmapName(NULL),
2016c333678SFredrik Modeen 	fBitmapValid(false),
2026c333678SFredrik Modeen 	fCursorPtsValid(false)
2036c333678SFredrik Modeen {
2046c333678SFredrik Modeen 	const char* temp;
2056c333678SFredrik Modeen 	if (from->FindString("command", &temp) != B_NO_ERROR) {
2063672a07eSStephan Aßmus 		printf(CLASS);
2073672a07eSStephan Aßmus 		printf(" Error, no command string in archive BMessage!\n");
2086c333678SFredrik Modeen 		temp = "";
2096c333678SFredrik Modeen 	}
2106c333678SFredrik Modeen 
2116c333678SFredrik Modeen 	SetCommand(temp);
2126c333678SFredrik Modeen 
2133672a07eSStephan Aßmus 	if (from->FindInt32("key", (int32*) &fKey) != B_NO_ERROR) {
2143672a07eSStephan Aßmus 		printf(CLASS);
2153672a07eSStephan Aßmus 		printf(" Error, no key int32 in archive BMessage!\n");
2163672a07eSStephan Aßmus 	}
2176c333678SFredrik Modeen 
2186c333678SFredrik Modeen 	for (int i = 0; i < NUM_META_COLUMNS; i++)
2196c333678SFredrik Modeen 		if (from->FindInt32("mcidx", i, (int32*)&fMetaCellStateIndex[i])
2203672a07eSStephan Aßmus 			!= B_NO_ERROR) {
2213672a07eSStephan Aßmus 			printf(CLASS);
2223672a07eSStephan Aßmus 			printf(" Error, no modifiers int32 in archive BMessage!\n");
2233672a07eSStephan Aßmus 		}
2246c333678SFredrik Modeen }
2256c333678SFredrik Modeen 
2266c333678SFredrik Modeen 
2276c333678SFredrik Modeen void
2286c333678SFredrik Modeen ShortcutsSpec::SetCommand(const char* command)
2296c333678SFredrik Modeen {
2306c333678SFredrik Modeen 	delete[] fCommand;	// out with the old (if any)...
2316c333678SFredrik Modeen 	fCommandLen = strlen(command) + 1;
2326c333678SFredrik Modeen 	fCommandNul = fCommandLen - 1;
2336c333678SFredrik Modeen 	fCommand = new char[fCommandLen];
2346c333678SFredrik Modeen 	strcpy(fCommand, command);
2356c333678SFredrik Modeen 	_UpdateIconBitmap();
2366c333678SFredrik Modeen }
2376c333678SFredrik Modeen 
2386c333678SFredrik Modeen 
2396c333678SFredrik Modeen const char*
2406c333678SFredrik Modeen ShortcutsSpec::GetColumnName(int i)
2416c333678SFredrik Modeen {
2423672a07eSStephan Aßmus 	return sMetaMaps[i].GetName();
2436c333678SFredrik Modeen }
2446c333678SFredrik Modeen 
2456c333678SFredrik Modeen 
2466c333678SFredrik Modeen status_t
2476c333678SFredrik Modeen ShortcutsSpec::Archive(BMessage* into, bool deep) const
2486c333678SFredrik Modeen {
2496c333678SFredrik Modeen 	status_t ret = BArchivable::Archive(into, deep);
2506c333678SFredrik Modeen 	if (ret != B_NO_ERROR)
2516c333678SFredrik Modeen 		return ret;
2526c333678SFredrik Modeen 
2536c333678SFredrik Modeen 	into->AddString("class", "ShortcutsSpec");
2546c333678SFredrik Modeen 
2556c333678SFredrik Modeen 	// These fields are for our prefs panel's benefit only
2566c333678SFredrik Modeen 	into->AddString("command", fCommand);
2576c333678SFredrik Modeen 	into->AddInt32("key", fKey);
2586c333678SFredrik Modeen 
2596c333678SFredrik Modeen 	// Assemble a BitFieldTester for the input_server add-on to use...
2606c333678SFredrik Modeen 	MinMatchFieldTester test(NUM_META_COLUMNS, false);
2616c333678SFredrik Modeen 	for (int i = 0; i < NUM_META_COLUMNS; i++) {
2626c333678SFredrik Modeen 		// for easy parsing by prefs applet on load-in
2636c333678SFredrik Modeen 		into->AddInt32("mcidx", fMetaCellStateIndex[i]);
2643672a07eSStephan Aßmus 		test.AddSlave(sMetaMaps[i].GetNthStateTester(fMetaCellStateIndex[i]));
2656c333678SFredrik Modeen 	}
2666c333678SFredrik Modeen 
2676c333678SFredrik Modeen 	BMessage testerMsg;
2686c333678SFredrik Modeen 	ret = test.Archive(&testerMsg);
2696c333678SFredrik Modeen 	if (ret != B_NO_ERROR)
2706c333678SFredrik Modeen 		return ret;
2716c333678SFredrik Modeen 
2726c333678SFredrik Modeen 	into->AddMessage("modtester", &testerMsg);
2736c333678SFredrik Modeen 
2746c333678SFredrik Modeen 	// And also create a CommandActuator for the input_server add-on to execute
2756c333678SFredrik Modeen 	CommandActuator* act = CreateCommandActuator(fCommand);
2766c333678SFredrik Modeen 	BMessage actMsg;
2776c333678SFredrik Modeen 	ret = act->Archive(&actMsg);
2786c333678SFredrik Modeen 	if (ret != B_NO_ERROR)
2796c333678SFredrik Modeen 		return ret;
2806c333678SFredrik Modeen 	delete act;
2816c333678SFredrik Modeen 
2826c333678SFredrik Modeen 	into->AddMessage("act", &actMsg);
2836c333678SFredrik Modeen 	return ret;
2846c333678SFredrik Modeen }
2856c333678SFredrik Modeen 
2866c333678SFredrik Modeen 
2876c333678SFredrik Modeen static bool IsValidActuatorName(const char* c);
2886c333678SFredrik Modeen static bool
2896c333678SFredrik Modeen IsValidActuatorName(const char* c)
2906c333678SFredrik Modeen {
2913672a07eSStephan Aßmus 	return (strcmp(c, B_TRANSLATE("InsertString")) == 0
2923672a07eSStephan Aßmus 		|| strcmp(c, B_TRANSLATE("MoveMouse")) == 0
2933672a07eSStephan Aßmus 		|| strcmp(c, B_TRANSLATE("MoveMouseTo")) == 0
2943672a07eSStephan Aßmus 		|| strcmp(c, B_TRANSLATE("MouseButton")) == 0
2953672a07eSStephan Aßmus 		|| strcmp(c, B_TRANSLATE("LaunchHandler")) == 0
2963672a07eSStephan Aßmus 		|| strcmp(c, B_TRANSLATE("Multi")) == 0
2973672a07eSStephan Aßmus 		|| strcmp(c, B_TRANSLATE("MouseDown")) == 0
2983672a07eSStephan Aßmus 		|| strcmp(c, B_TRANSLATE("MouseUp")) == 0
2993672a07eSStephan Aßmus 		|| strcmp(c, B_TRANSLATE("SendMessage")) == 0
3003672a07eSStephan Aßmus 		|| strcmp(c, B_TRANSLATE("Beep")) == 0);
3016c333678SFredrik Modeen }
3026c333678SFredrik Modeen 
3036c333678SFredrik Modeen 
3046c333678SFredrik Modeen BArchivable*
3056c333678SFredrik Modeen ShortcutsSpec::Instantiate(BMessage* from)
3066c333678SFredrik Modeen {
3076c333678SFredrik Modeen 	bool validateOK = false;
3086c333678SFredrik Modeen 	if (validate_instantiation(from, "ShortcutsSpec"))
3096c333678SFredrik Modeen 		validateOK = true;
3106c333678SFredrik Modeen 	else // test the old one.
3116c333678SFredrik Modeen 		if (validate_instantiation(from, "SpicyKeysSpec"))
3126c333678SFredrik Modeen 			validateOK = true;
3136c333678SFredrik Modeen 
3146c333678SFredrik Modeen 	if (!validateOK)
3156c333678SFredrik Modeen 		return NULL;
3166c333678SFredrik Modeen 
3176c333678SFredrik Modeen 	return new ShortcutsSpec(from);
3186c333678SFredrik Modeen }
3196c333678SFredrik Modeen 
3206c333678SFredrik Modeen 
3216c333678SFredrik Modeen ShortcutsSpec::~ShortcutsSpec()
3226c333678SFredrik Modeen {
3236c333678SFredrik Modeen 	delete[] fCommand;
3246c333678SFredrik Modeen 	delete[] fLastBitmapName;
3256c333678SFredrik Modeen }
3266c333678SFredrik Modeen 
3276c333678SFredrik Modeen 
3286c333678SFredrik Modeen void
3296c333678SFredrik Modeen ShortcutsSpec::_CacheViewFont(BView* owner)
3306c333678SFredrik Modeen {
3313672a07eSStephan Aßmus 	if (sFontCached == false) {
3323672a07eSStephan Aßmus 		sFontCached = true;
3333672a07eSStephan Aßmus 		owner->GetFont(&sViewFont);
3346c333678SFredrik Modeen 		font_height fh;
3353672a07eSStephan Aßmus 		sViewFont.GetHeight(&fh);
3363672a07eSStephan Aßmus 		sFontHeight = fh.ascent - fh.descent;
3376c333678SFredrik Modeen 	}
3386c333678SFredrik Modeen }
3396c333678SFredrik Modeen 
3406c333678SFredrik Modeen 
3416c333678SFredrik Modeen void
3426c333678SFredrik Modeen ShortcutsSpec::DrawItemColumn(BView* owner, BRect item_column_rect,
3436c333678SFredrik Modeen 	int32 column_index, bool columnSelected, bool complete)
3446c333678SFredrik Modeen {
3456c333678SFredrik Modeen 	const float STRING_COLUMN_LEFT_MARGIN = 25.0f; // 16 for the icon,+9 empty
3466c333678SFredrik Modeen 
3476c333678SFredrik Modeen 	rgb_color color;
3486c333678SFredrik Modeen 	bool selected = IsSelected();
3496c333678SFredrik Modeen 	if (selected)
3506c333678SFredrik Modeen 		color = columnSelected ? BeBackgroundGrey : BeListSelectGrey;
3516c333678SFredrik Modeen 	else
3526c333678SFredrik Modeen 		color = BeInactiveControlGrey;
3536c333678SFredrik Modeen 	owner->SetLowColor(color);
3546c333678SFredrik Modeen 	owner->SetDrawingMode(B_OP_COPY);
3556c333678SFredrik Modeen 	owner->SetHighColor(color);
3566c333678SFredrik Modeen 	owner->FillRect(item_column_rect);
3576c333678SFredrik Modeen 
3586c333678SFredrik Modeen 	const char* text = GetCellText(column_index);
3596c333678SFredrik Modeen 
3606c333678SFredrik Modeen 	if (text == NULL)
3616c333678SFredrik Modeen 		return;
3626c333678SFredrik Modeen 
363ce59b51cSRene Gollent 	_CacheViewFont(owner);
364ce59b51cSRene Gollent 		// Ensure that sViewFont is configured before using it to calculate
365ce59b51cSRene Gollent 		// widths.  The lack of this call was causing the initial display of
366ce59b51cSRene Gollent 		// columns to be incorrect, with a "jump" as all the columns correct
367ce59b51cSRene Gollent 		// themselves upon the first column resize.
368ce59b51cSRene Gollent 
3693672a07eSStephan Aßmus 	float textWidth = sViewFont.StringWidth(text);
3706c333678SFredrik Modeen 	BPoint point;
3716c333678SFredrik Modeen 	rgb_color lowColor = color;
3726c333678SFredrik Modeen 
3736c333678SFredrik Modeen 	if (column_index == STRING_COLUMN_INDEX) {
3746c333678SFredrik Modeen 		// left justified
3756c333678SFredrik Modeen 		point.Set(item_column_rect.left + STRING_COLUMN_LEFT_MARGIN,
3766c333678SFredrik Modeen 			item_column_rect.top + fTextOffset);
3776c333678SFredrik Modeen 
378fa1ee6d4SJonas Sundström 		item_column_rect.left = point.x;
379fa1ee6d4SJonas Sundström 			// keep text from drawing into icon area
3806c333678SFredrik Modeen 
3816c333678SFredrik Modeen 		// scroll if too wide
3826c333678SFredrik Modeen 		float rectWidth = item_column_rect.Width() - STRING_COLUMN_LEFT_MARGIN;
3836c333678SFredrik Modeen 		float extra = textWidth - rectWidth;
3846c333678SFredrik Modeen 		if (extra > 0.0f)
3856c333678SFredrik Modeen 			point.x -= extra;
3866c333678SFredrik Modeen 	} else {
3876c333678SFredrik Modeen 		if ((column_index < NUM_META_COLUMNS) && (text[0] == '('))
3886c333678SFredrik Modeen 			return; // don't draw for this ...
3896c333678SFredrik Modeen 
3906c333678SFredrik Modeen 		if ((column_index <= NUM_META_COLUMNS) && (text[0] == '\0'))
3916c333678SFredrik Modeen 			return; // don't draw for this ...
3926c333678SFredrik Modeen 
3936c333678SFredrik Modeen 		// centered
3946c333678SFredrik Modeen 		point.Set((item_column_rect.left + item_column_rect.right) / 2.0,
3956c333678SFredrik Modeen 			item_column_rect.top + fTextOffset);
3966c333678SFredrik Modeen 		_CacheViewFont(owner);
3976c333678SFredrik Modeen 		point.x -= textWidth / 2.0f;
3986c333678SFredrik Modeen 	}
3996c333678SFredrik Modeen 
4006c333678SFredrik Modeen 	BRegion Region;
4016c333678SFredrik Modeen 	Region.Include(item_column_rect);
4026c333678SFredrik Modeen 	owner->ConstrainClippingRegion(&Region);
4036c333678SFredrik Modeen 	if (column_index != STRING_COLUMN_INDEX) {
4046c333678SFredrik Modeen 		const float KEY_MARGIN = 3.0f;
4056c333678SFredrik Modeen 		const float CORNER_RADIUS = 3.0f;
4066c333678SFredrik Modeen 		_CacheViewFont(owner);
4076c333678SFredrik Modeen 
4086c333678SFredrik Modeen 		// How about I draw a nice "key" background for this one?
4093672a07eSStephan Aßmus 		BRect textRect(point.x - KEY_MARGIN, (point.y-sFontHeight) - KEY_MARGIN
4106c333678SFredrik Modeen 			, point.x + textWidth + KEY_MARGIN - 2.0f, point.y + KEY_MARGIN);
4116c333678SFredrik Modeen 
4126c333678SFredrik Modeen 		if (column_index == KEY_COLUMN_INDEX)
4136c333678SFredrik Modeen 			lowColor = ReallyLightPurple;
4146c333678SFredrik Modeen 		else
4156c333678SFredrik Modeen 			lowColor = LightYellow;
4166c333678SFredrik Modeen 
4176c333678SFredrik Modeen 		owner->SetHighColor(lowColor);
4186c333678SFredrik Modeen 		owner->FillRoundRect(textRect, CORNER_RADIUS, CORNER_RADIUS);
4196c333678SFredrik Modeen 		owner->SetHighColor(Black);
4206c333678SFredrik Modeen 		owner->StrokeRoundRect(textRect, CORNER_RADIUS, CORNER_RADIUS);
4216c333678SFredrik Modeen 	}
4226c333678SFredrik Modeen 
4236c333678SFredrik Modeen 	owner->SetHighColor(Black);
4246c333678SFredrik Modeen 	owner->SetLowColor(lowColor);
4256c333678SFredrik Modeen 	owner->DrawString(text, point);
4266c333678SFredrik Modeen 	// with a cursor at the end if highlighted
4276c333678SFredrik Modeen 	if (column_index == STRING_COLUMN_INDEX) {
4286c333678SFredrik Modeen 		// Draw cursor
4296c333678SFredrik Modeen 		if ((columnSelected) && (selected)) {
4306c333678SFredrik Modeen 			point.x += textWidth;
4316c333678SFredrik Modeen 			point.y += (fTextOffset / 4.0f);
4326c333678SFredrik Modeen 
4336c333678SFredrik Modeen 			BPoint pt2 = point;
4346c333678SFredrik Modeen 			pt2.y -= fTextOffset;
4356c333678SFredrik Modeen 			owner->StrokeLine(point, pt2);
4366c333678SFredrik Modeen 
4376c333678SFredrik Modeen 			fCursorPt1 = point;
4386c333678SFredrik Modeen 			fCursorPt2 = pt2;
4396c333678SFredrik Modeen 			fCursorPtsValid = true;
4406c333678SFredrik Modeen 		}
4416c333678SFredrik Modeen 
4426c333678SFredrik Modeen 		BRegion bitmapRegion;
4436c333678SFredrik Modeen 		item_column_rect.left	-= (STRING_COLUMN_LEFT_MARGIN - 4.0f);
4446c333678SFredrik Modeen 		item_column_rect.right	= item_column_rect.left + 16.0f;
4456c333678SFredrik Modeen 		item_column_rect.top	+= 3.0f;
4466c333678SFredrik Modeen 		item_column_rect.bottom	= item_column_rect.top + 16.0f;
4476c333678SFredrik Modeen 
4486c333678SFredrik Modeen 		bitmapRegion.Include(item_column_rect);
4496c333678SFredrik Modeen 		owner->ConstrainClippingRegion(&bitmapRegion);
4505788aadfSJérôme Duval 		owner->SetDrawingMode(B_OP_ALPHA);
4516c333678SFredrik Modeen 
4526c333678SFredrik Modeen 		if ((fCommand != NULL) && (fCommand[0] == '*'))
4533672a07eSStephan Aßmus 			owner->DrawBitmap(sActuatorBitmaps[fBitmapValid ? 1 : 0],
4546c333678SFredrik Modeen 				ICON_BITMAP_RECT, item_column_rect);
4556c333678SFredrik Modeen 		else
4566c333678SFredrik Modeen 			// Draw icon, if any
4576c333678SFredrik Modeen 			if (fBitmapValid)
4586c333678SFredrik Modeen 				owner->DrawBitmap(&fBitmap, ICON_BITMAP_RECT,
4596c333678SFredrik Modeen 					item_column_rect);
4606c333678SFredrik Modeen 	}
4616c333678SFredrik Modeen 
4626c333678SFredrik Modeen 	owner->SetDrawingMode(B_OP_COPY);
4636c333678SFredrik Modeen 	owner->ConstrainClippingRegion(NULL);
4646c333678SFredrik Modeen }
4656c333678SFredrik Modeen 
4666c333678SFredrik Modeen 
4676c333678SFredrik Modeen void
4686c333678SFredrik Modeen ShortcutsSpec::Update(BView* owner, const BFont* font)
4696c333678SFredrik Modeen {
4706c333678SFredrik Modeen 	CLVListItem::Update(owner, font);
4716c333678SFredrik Modeen 	font_height FontAttributes;
4726c333678SFredrik Modeen 	be_plain_font->GetHeight(&FontAttributes);
4736c333678SFredrik Modeen 	float fontHeight = ceil(FontAttributes.ascent) +
4746c333678SFredrik Modeen 		ceil(FontAttributes.descent);
4756c333678SFredrik Modeen 	fTextOffset = ceil(FontAttributes.ascent) + (Height() - fontHeight) / 2.0;
4766c333678SFredrik Modeen }
4776c333678SFredrik Modeen 
4786c333678SFredrik Modeen 
4796c333678SFredrik Modeen const char*
4806c333678SFredrik Modeen ShortcutsSpec::GetCellText(int whichColumn) const
4816c333678SFredrik Modeen {
4826c333678SFredrik Modeen 	const char* temp = ""; // default
4833672a07eSStephan Aßmus 	switch(whichColumn) {
4846c333678SFredrik Modeen 		case KEY_COLUMN_INDEX:
4856c333678SFredrik Modeen 		{
4866c333678SFredrik Modeen 			if ((fKey > 0) && (fKey <= 0xFF)) {
4876c333678SFredrik Modeen 				temp = GetKeyName(fKey);
4886c333678SFredrik Modeen 				if (temp == NULL)
4896c333678SFredrik Modeen 					temp = "";
4906c333678SFredrik Modeen 			} else if (fKey > 0xFF) {
491*0bbc331fSJérôme Duval 				sprintf(fScratch, "#%" B_PRIx32, fKey);
4926c333678SFredrik Modeen 				return fScratch;
4936c333678SFredrik Modeen 			}
4946c333678SFredrik Modeen 			break;
4953672a07eSStephan Aßmus 		}
4966c333678SFredrik Modeen 
4976c333678SFredrik Modeen 		case STRING_COLUMN_INDEX:
4986c333678SFredrik Modeen 			temp = fCommand;
4996c333678SFredrik Modeen 			break;
5006c333678SFredrik Modeen 
5016c333678SFredrik Modeen 		default:
5026c333678SFredrik Modeen 			if ((whichColumn >= 0) && (whichColumn < NUM_META_COLUMNS))
5033672a07eSStephan Aßmus 				temp = sMetaMaps[whichColumn].GetNthStateDesc(
5046c333678SFredrik Modeen 							fMetaCellStateIndex[whichColumn]);
5056c333678SFredrik Modeen 			break;
5066c333678SFredrik Modeen 	}
5076c333678SFredrik Modeen 	return temp;
5086c333678SFredrik Modeen }
5096c333678SFredrik Modeen 
5106c333678SFredrik Modeen 
5116c333678SFredrik Modeen bool
5126c333678SFredrik Modeen ShortcutsSpec::ProcessColumnMouseClick(int whichColumn)
5136c333678SFredrik Modeen {
5146c333678SFredrik Modeen 	if ((whichColumn >= 0) && (whichColumn < NUM_META_COLUMNS)) {
5156c333678SFredrik Modeen 		// same as hitting space for these columns: cycle entry
5166c333678SFredrik Modeen 		const char temp = B_SPACE;
5176c333678SFredrik Modeen 
5186c333678SFredrik Modeen 		// 3rd arg isn't correct but it isn't read for this case anyway
5196c333678SFredrik Modeen 		return ProcessColumnKeyStroke(whichColumn, &temp, 0);
5206c333678SFredrik Modeen 	}
5216c333678SFredrik Modeen 	return false;
5226c333678SFredrik Modeen }
5236c333678SFredrik Modeen 
5246c333678SFredrik Modeen 
5256c333678SFredrik Modeen bool
5266c333678SFredrik Modeen ShortcutsSpec::ProcessColumnTextString(int whichColumn, const char* string)
5276c333678SFredrik Modeen {
5286c333678SFredrik Modeen 	switch(whichColumn) {
5296c333678SFredrik Modeen 		case STRING_COLUMN_INDEX:
5306c333678SFredrik Modeen 			SetCommand(string);
5316c333678SFredrik Modeen 			return true;
5326c333678SFredrik Modeen 			break;
5336c333678SFredrik Modeen 
5346c333678SFredrik Modeen 		case KEY_COLUMN_INDEX:
5356c333678SFredrik Modeen 		{
5366c333678SFredrik Modeen 			fKey = FindKeyCode(string);
5376c333678SFredrik Modeen 			return true;
5386c333678SFredrik Modeen 			break;
5396c333678SFredrik Modeen 		}
5406c333678SFredrik Modeen 
5416c333678SFredrik Modeen 		default:
5426c333678SFredrik Modeen 			return ProcessColumnKeyStroke(whichColumn, string, 0);
5436c333678SFredrik Modeen 	}
5446c333678SFredrik Modeen }
5456c333678SFredrik Modeen 
5466c333678SFredrik Modeen 
5476c333678SFredrik Modeen bool
5486c333678SFredrik Modeen ShortcutsSpec::_AttemptTabCompletion()
5496c333678SFredrik Modeen {
5506c333678SFredrik Modeen 	bool ret = false;
5516c333678SFredrik Modeen 
5526c333678SFredrik Modeen 	int32 argc;
5536c333678SFredrik Modeen 	char** argv = ParseArgvFromString(fCommand, argc);
5546c333678SFredrik Modeen 	if (argc > 0) {
5556c333678SFredrik Modeen 		// Try to complete the path partially expressed in the last argument!
5566c333678SFredrik Modeen 		char* arg = argv[argc - 1];
5576c333678SFredrik Modeen 		char* fileFragment = strrchr(arg, '/');
5586c333678SFredrik Modeen 		if (fileFragment) {
5596c333678SFredrik Modeen 			const char* directoryName = (fileFragment == arg) ? "/" : arg;
5606c333678SFredrik Modeen 			*fileFragment = '\0';
5616c333678SFredrik Modeen 			fileFragment++;
5626c333678SFredrik Modeen 			int fragLen = strlen(fileFragment);
5636c333678SFredrik Modeen 
5646c333678SFredrik Modeen 			BDirectory dir(directoryName);
5656c333678SFredrik Modeen 			if (dir.InitCheck() == B_NO_ERROR) {
5666c333678SFredrik Modeen 				BEntry nextEnt;
5676c333678SFredrik Modeen 				BPath nextPath;
5686c333678SFredrik Modeen 				BList matchList;
5696c333678SFredrik Modeen 				int maxEntryLen = 0;
5706c333678SFredrik Modeen 
5716c333678SFredrik Modeen 				// Read in all the files in the directory whose names start
5726c333678SFredrik Modeen 				// with our fragment.
5736c333678SFredrik Modeen 				while (dir.GetNextEntry(&nextEnt) == B_NO_ERROR) {
5746c333678SFredrik Modeen 					if (nextEnt.GetPath(&nextPath) == B_NO_ERROR) {
5756c333678SFredrik Modeen 						char* filePath = strrchr(nextPath.Path(), '/') + 1;
5766c333678SFredrik Modeen 						if (strncmp(filePath, fileFragment, fragLen) == 0) {
5776c333678SFredrik Modeen 							int len = strlen(filePath);
5786c333678SFredrik Modeen 							if (len > maxEntryLen)
5796c333678SFredrik Modeen 								maxEntryLen = len;
5806c333678SFredrik Modeen 							char* newStr = new char[len + 1];
5816c333678SFredrik Modeen 							strcpy(newStr, filePath);
5826c333678SFredrik Modeen 							matchList.AddItem(newStr);
5836c333678SFredrik Modeen 						}
5846c333678SFredrik Modeen 					}
5856c333678SFredrik Modeen 				}
5866c333678SFredrik Modeen 
5876c333678SFredrik Modeen 				// Now slowly extend our keyword to its full length, counting
5886c333678SFredrik Modeen 				// numbers of matches at each step. If the match list length
5896c333678SFredrik Modeen 				// is 1, we can use that whole entry. If it's greater than one
5906c333678SFredrik Modeen 				// , we can use just the match length.
5916c333678SFredrik Modeen 				int matchLen = matchList.CountItems();
5926c333678SFredrik Modeen 				if (matchLen > 0) {
5936c333678SFredrik Modeen 					int i;
5946c333678SFredrik Modeen 					BString result(fileFragment);
5956c333678SFredrik Modeen 					for (i = fragLen; i < maxEntryLen; i++) {
5966c333678SFredrik Modeen 						// See if all the matching entries have the same letter
5976c333678SFredrik Modeen 						// in the next position... if so, we can go farther.
5986c333678SFredrik Modeen 						char commonLetter = '\0';
5996c333678SFredrik Modeen 						for (int j = 0; j < matchLen; j++) {
6006c333678SFredrik Modeen 							char nextLetter = GetLetterAt(
6016c333678SFredrik Modeen 								(char*)matchList.ItemAt(j), i);
6026c333678SFredrik Modeen 							if (commonLetter == '\0')
6036c333678SFredrik Modeen 								commonLetter = nextLetter;
6046c333678SFredrik Modeen 
6056c333678SFredrik Modeen 							if ((commonLetter != '\0')
6066c333678SFredrik Modeen 								&& (commonLetter != nextLetter)) {
6076c333678SFredrik Modeen 								commonLetter = '\0';// failed;
6086c333678SFredrik Modeen 								beep();
6096c333678SFredrik Modeen 								break;
6106c333678SFredrik Modeen 							}
6116c333678SFredrik Modeen 						}
6126c333678SFredrik Modeen 						if (commonLetter == '\0')
6136c333678SFredrik Modeen 							break;
6146c333678SFredrik Modeen 						else
6156c333678SFredrik Modeen 							result.Append(commonLetter, 1);
6166c333678SFredrik Modeen 					}
6176c333678SFredrik Modeen 
6186c333678SFredrik Modeen 					// Free all the strings we allocated
6196c333678SFredrik Modeen 					for (int k = 0; k < matchLen; k++)
6206c333678SFredrik Modeen 						delete [] ((char*)matchList.ItemAt(k));
6216c333678SFredrik Modeen 
6226c333678SFredrik Modeen 					DoStandardEscapes(result);
6236c333678SFredrik Modeen 
6246c333678SFredrik Modeen 					BString wholeLine;
6256c333678SFredrik Modeen 					for (int l = 0; l < argc - 1; l++) {
6266c333678SFredrik Modeen 						wholeLine += argv[l];
6276c333678SFredrik Modeen 						wholeLine += " ";
6286c333678SFredrik Modeen 					}
6296c333678SFredrik Modeen 
6306c333678SFredrik Modeen 					BString file(directoryName);
6316c333678SFredrik Modeen 					DoStandardEscapes(file);
6326c333678SFredrik Modeen 
6336c333678SFredrik Modeen 					if (directoryName[strlen(directoryName) - 1] != '/')
6346c333678SFredrik Modeen 						file += "/";
6356c333678SFredrik Modeen 
6366c333678SFredrik Modeen 					file += result;
6376c333678SFredrik Modeen 
6386c333678SFredrik Modeen 					// Remove any trailing slash...
6396c333678SFredrik Modeen 					const char* fileStr = file.String();
6406c333678SFredrik Modeen 					if (fileStr[strlen(fileStr)-1] == '/')
6416c333678SFredrik Modeen 						file.RemoveLast("/");
6426c333678SFredrik Modeen 
6436c333678SFredrik Modeen 					// And re-append it iff the file is a dir.
6446c333678SFredrik Modeen 					BDirectory testFileAsDir(file.String());
6456c333678SFredrik Modeen 					if ((strcmp(file.String(), "/") != 0)
6466c333678SFredrik Modeen 						&& (testFileAsDir.InitCheck() == B_NO_ERROR))
6476c333678SFredrik Modeen 						file.Append("/");
6486c333678SFredrik Modeen 
6496c333678SFredrik Modeen 					wholeLine += file;
6506c333678SFredrik Modeen 
6516c333678SFredrik Modeen 					SetCommand(wholeLine.String());
6526c333678SFredrik Modeen 					ret = true;
6536c333678SFredrik Modeen 				}
6546c333678SFredrik Modeen 			}
6556c333678SFredrik Modeen 			*(fileFragment - 1) = '/';
6566c333678SFredrik Modeen 		}
6576c333678SFredrik Modeen 	}
6586c333678SFredrik Modeen 	FreeArgv(argv);
6596c333678SFredrik Modeen 	return ret;
6606c333678SFredrik Modeen }
6616c333678SFredrik Modeen 
6626c333678SFredrik Modeen 
6636c333678SFredrik Modeen bool
6646c333678SFredrik Modeen ShortcutsSpec::ProcessColumnKeyStroke(int whichColumn, const char* bytes,
6656c333678SFredrik Modeen 	int32 key)
6666c333678SFredrik Modeen {
6676c333678SFredrik Modeen 	bool ret = false;
6686c333678SFredrik Modeen 	switch(whichColumn) {
6696c333678SFredrik Modeen 		case KEY_COLUMN_INDEX:
6703672a07eSStephan Aßmus 			if (key > -1) {
6713672a07eSStephan Aßmus 				if ((int32)fKey != key) {
6726c333678SFredrik Modeen 					fKey = key;
6736c333678SFredrik Modeen 					ret = true;
6746c333678SFredrik Modeen 				}
6756c333678SFredrik Modeen 			}
6766c333678SFredrik Modeen 			break;
6776c333678SFredrik Modeen 
6786c333678SFredrik Modeen 		case STRING_COLUMN_INDEX:
6796c333678SFredrik Modeen 		{
6806c333678SFredrik Modeen 			switch(bytes[0]) {
6816c333678SFredrik Modeen 				case B_BACKSPACE:
6826c333678SFredrik Modeen 				case B_DELETE:
6836c333678SFredrik Modeen 					if (fCommandNul > 0) {
6846c333678SFredrik Modeen 						// trim a char off the string
6856c333678SFredrik Modeen 						fCommand[fCommandNul - 1] = '\0';
6866c333678SFredrik Modeen 						fCommandNul--;	// note new nul position
6876c333678SFredrik Modeen 						ret = true;
6886c333678SFredrik Modeen 						_UpdateIconBitmap();
6896c333678SFredrik Modeen 					}
6906c333678SFredrik Modeen 				break;
6916c333678SFredrik Modeen 
6926c333678SFredrik Modeen 				case B_TAB:
6936c333678SFredrik Modeen 					if (_AttemptTabCompletion()) {
6946c333678SFredrik Modeen 						_UpdateIconBitmap();
6956c333678SFredrik Modeen 						ret = true;
6966c333678SFredrik Modeen 					} else
6976c333678SFredrik Modeen 						beep();
6986c333678SFredrik Modeen 				break;
6996c333678SFredrik Modeen 
7006c333678SFredrik Modeen 				default:
7016c333678SFredrik Modeen 				{
702529fd9afSOliver Tappe 					uint32 newCharLen = strlen(bytes);
7036c333678SFredrik Modeen 					if ((newCharLen > 0) && (bytes[0] >= ' ')) {
7046c333678SFredrik Modeen 						bool reAllocString = false;
7056c333678SFredrik Modeen 						// Make sure we have enough room in our command string
7066c333678SFredrik Modeen 						// to add these chars...
707529fd9afSOliver Tappe 						while (fCommandLen - fCommandNul <= newCharLen) {
7086c333678SFredrik Modeen 							reAllocString = true;
7096c333678SFredrik Modeen 							// enough for a while...
7106c333678SFredrik Modeen 							fCommandLen = (fCommandLen + 10) * 2;
7116c333678SFredrik Modeen 						}
7126c333678SFredrik Modeen 
7136c333678SFredrik Modeen 						if (reAllocString) {
7146c333678SFredrik Modeen 							char* temp = new char[fCommandLen];
7156c333678SFredrik Modeen 							strcpy(temp, fCommand);
7166c333678SFredrik Modeen 							delete [] fCommand;
7176c333678SFredrik Modeen 							fCommand = temp;
7186c333678SFredrik Modeen 							// fCommandNul is still valid since it's an offset
7196c333678SFredrik Modeen 							// and the string length is the same for now
7206c333678SFredrik Modeen 						}
7216c333678SFredrik Modeen 
7226c333678SFredrik Modeen 						// Here we should be guaranteed enough room.
7236c333678SFredrik Modeen 						strncat(fCommand, bytes, fCommandLen);
7246c333678SFredrik Modeen 						fCommandNul += newCharLen;
7256c333678SFredrik Modeen 						ret = true;
7266c333678SFredrik Modeen 						_UpdateIconBitmap();
7276c333678SFredrik Modeen 					}
7286c333678SFredrik Modeen 				}
7296c333678SFredrik Modeen 			}
7306c333678SFredrik Modeen 			break;
7313672a07eSStephan Aßmus 		}
7326c333678SFredrik Modeen 
7336c333678SFredrik Modeen 		default:
7346c333678SFredrik Modeen 			if ((whichColumn >= 0) && (whichColumn < NUM_META_COLUMNS)) {
7353672a07eSStephan Aßmus 				MetaKeyStateMap * map = &sMetaMaps[whichColumn];
7366c333678SFredrik Modeen 				int curState = fMetaCellStateIndex[whichColumn];
7376c333678SFredrik Modeen 				int origState = curState;
7386c333678SFredrik Modeen 				int numStates = map->GetNumStates();
7396c333678SFredrik Modeen 
7406c333678SFredrik Modeen 				switch(bytes[0])
7416c333678SFredrik Modeen 				{
7426c333678SFredrik Modeen 					case B_RETURN:
7436c333678SFredrik Modeen 						// cycle to the previous state
7446c333678SFredrik Modeen 						curState = (curState + numStates - 1) % numStates;
7456c333678SFredrik Modeen 						break;
7466c333678SFredrik Modeen 
7476c333678SFredrik Modeen 					case B_SPACE:
7486c333678SFredrik Modeen 						// cycle to the next state
7496c333678SFredrik Modeen 						curState = (curState + 1) % numStates;
7506c333678SFredrik Modeen 						break;
7516c333678SFredrik Modeen 
7526c333678SFredrik Modeen 					default:
7536c333678SFredrik Modeen 					{
7546c333678SFredrik Modeen 						// Go to the state starting with the given letter, if
7556c333678SFredrik Modeen 						// any
7566c333678SFredrik Modeen 						char letter = bytes[0];
7576c333678SFredrik Modeen 						if (islower(letter))
7586c333678SFredrik Modeen 							letter = toupper(letter); // convert to upper case
7596c333678SFredrik Modeen 
7606c333678SFredrik Modeen 						if ((letter == B_BACKSPACE) || (letter == B_DELETE))
761fa1ee6d4SJonas Sundström 							letter = '(';
762fa1ee6d4SJonas Sundström 								// so space bar will blank out an entry
7636c333678SFredrik Modeen 
7646c333678SFredrik Modeen 						for (int i = 0; i < numStates; i++) {
7656c333678SFredrik Modeen 							const char* desc = map->GetNthStateDesc(i);
7666c333678SFredrik Modeen 
7676c333678SFredrik Modeen 							if (desc) {
7686c333678SFredrik Modeen 								if (desc[0] == letter) {
7696c333678SFredrik Modeen 									curState = i;
7706c333678SFredrik Modeen 									break;
7716c333678SFredrik Modeen 								}
7726c333678SFredrik Modeen 							} else
7733672a07eSStephan Aßmus 								printf(B_TRANSLATE("Error, NULL state description?\n"));
7746c333678SFredrik Modeen 						}
7756c333678SFredrik Modeen 						break;
7766c333678SFredrik Modeen 					}
7773672a07eSStephan Aßmus 				}
7786c333678SFredrik Modeen 				fMetaCellStateIndex[whichColumn] = curState;
7796c333678SFredrik Modeen 
7806c333678SFredrik Modeen 				if (curState != origState)
7816c333678SFredrik Modeen 					ret = true;
7826c333678SFredrik Modeen 			}
7836c333678SFredrik Modeen 			break;
7846c333678SFredrik Modeen 	}
7856c333678SFredrik Modeen 
7866c333678SFredrik Modeen 	return ret;
7876c333678SFredrik Modeen }
7886c333678SFredrik Modeen 
7896c333678SFredrik Modeen 
7906c333678SFredrik Modeen int
791fa1ee6d4SJonas Sundström ShortcutsSpec::MyCompare(const CLVListItem* a_Item1, const CLVListItem* a_Item2,
792fa1ee6d4SJonas Sundström 	int32 KeyColumn)
7936c333678SFredrik Modeen {
7946c333678SFredrik Modeen 	ShortcutsSpec* left = (ShortcutsSpec*) a_Item1;
7956c333678SFredrik Modeen 	ShortcutsSpec* right = (ShortcutsSpec*) a_Item2;
7966c333678SFredrik Modeen 
7976c333678SFredrik Modeen 	int ret = strcmp(left->GetCellText(KeyColumn),
7986c333678SFredrik Modeen 		right->GetCellText(KeyColumn));
7996c333678SFredrik Modeen 	return (ret > 0) ? 1 : ((ret == 0) ? 0 : -1);
8006c333678SFredrik Modeen }
8016c333678SFredrik Modeen 
8026c333678SFredrik Modeen 
8036c333678SFredrik Modeen void
8046c333678SFredrik Modeen ShortcutsSpec::Pulse(BView* owner)
8056c333678SFredrik Modeen {
8066c333678SFredrik Modeen 	if ((fCursorPtsValid)&&(owner->Window()->IsActive())) {
8076c333678SFredrik Modeen 		rgb_color prevColor = owner->HighColor();
8086c333678SFredrik Modeen 		rgb_color backgroundColor = (GetSelectedColumn() ==
8096c333678SFredrik Modeen 			STRING_COLUMN_INDEX) ? BeBackgroundGrey : BeListSelectGrey;
8106c333678SFredrik Modeen 		rgb_color barColor = ((GetSelectedColumn() == STRING_COLUMN_INDEX)
8116c333678SFredrik Modeen 			&& ((system_time() % 1000000) > 500000)) ? Black : backgroundColor;
8126c333678SFredrik Modeen 		owner->SetHighColor(barColor);
8136c333678SFredrik Modeen 		owner->StrokeLine(fCursorPt1, fCursorPt2);
8146c333678SFredrik Modeen 		owner->SetHighColor(prevColor);
8156c333678SFredrik Modeen 	}
8166c333678SFredrik Modeen }
8176c333678SFredrik Modeen 
8186c333678SFredrik Modeen 
8196c333678SFredrik Modeen void
8206c333678SFredrik Modeen ShortcutsSpec::_UpdateIconBitmap()
8216c333678SFredrik Modeen {
8226c333678SFredrik Modeen 	BString firstWord = ParseArgvZeroFromString(fCommand);
8236c333678SFredrik Modeen 
8246c333678SFredrik Modeen 	// Only need to change if the first word has changed...
8253672a07eSStephan Aßmus 	if (fLastBitmapName == NULL || firstWord.Length() == 0
8263672a07eSStephan Aßmus 		|| firstWord.Compare(fLastBitmapName)) {
8276c333678SFredrik Modeen 		if (firstWord.ByteAt(0) == '*')
8286c333678SFredrik Modeen 			fBitmapValid = IsValidActuatorName(&firstWord.String()[1]);
8296c333678SFredrik Modeen 		else {
8306c333678SFredrik Modeen 			fBitmapValid = false; // default till we prove otherwise!
8316c333678SFredrik Modeen 
8326c333678SFredrik Modeen 			if (firstWord.Length() > 0) {
8336c333678SFredrik Modeen 				delete [] fLastBitmapName;
8346c333678SFredrik Modeen 				fLastBitmapName = new char[firstWord.Length() + 1];
8356c333678SFredrik Modeen 				strcpy(fLastBitmapName, firstWord.String());
8366c333678SFredrik Modeen 
8376c333678SFredrik Modeen 				BEntry progEntry(fLastBitmapName, true);
8386c333678SFredrik Modeen 				if ((progEntry.InitCheck() == B_NO_ERROR)
8396c333678SFredrik Modeen 					&& (progEntry.Exists())) {
8406c333678SFredrik Modeen 					BNode progNode(&progEntry);
8416c333678SFredrik Modeen 					if (progNode.InitCheck() == B_NO_ERROR) {
8426c333678SFredrik Modeen 						BNodeInfo progNodeInfo(&progNode);
8436c333678SFredrik Modeen 						if ((progNodeInfo.InitCheck() == B_NO_ERROR)
8446c333678SFredrik Modeen 						&& (progNodeInfo.GetTrackerIcon(&fBitmap, B_MINI_ICON)
8453672a07eSStephan Aßmus 							== B_NO_ERROR)) {
8466c333678SFredrik Modeen 							fBitmapValid = fBitmap.IsValid();
8476c333678SFredrik Modeen 						}
8486c333678SFredrik Modeen 					}
8496c333678SFredrik Modeen 				}
8506c333678SFredrik Modeen 			}
8516c333678SFredrik Modeen 		}
8526c333678SFredrik Modeen 	}
8533672a07eSStephan Aßmus }
8543672a07eSStephan Aßmus 
8553672a07eSStephan Aßmus 
8563672a07eSStephan Aßmus /*static*/ void
8573672a07eSStephan Aßmus ShortcutsSpec::_InitModifierNames()
8583672a07eSStephan Aßmus {
8593672a07eSStephan Aßmus 	sShiftName = B_TRANSLATE_COMMENT("Shift",
8603672a07eSStephan Aßmus 		"Name for modifier on keyboard");
8613672a07eSStephan Aßmus 	sControlName = B_TRANSLATE_COMMENT("Control",
8623672a07eSStephan Aßmus 		"Name for modifier on keyboard");
8633672a07eSStephan Aßmus // TODO: Wrapping in __INTEL__ define probably won't work to extract catkeys?
8643672a07eSStephan Aßmus #if __INTEL__
86576f3378cSHumdinger 	sOptionName = B_TRANSLATE_COMMENT("Option",
8663672a07eSStephan Aßmus 		"Name for modifier on keyboard");
8673672a07eSStephan Aßmus 	sCommandName = B_TRANSLATE_COMMENT("Alt",
8683672a07eSStephan Aßmus 		"Name for modifier on keyboard");
8693672a07eSStephan Aßmus #else
8703672a07eSStephan Aßmus 	sOptionName = B_TRANSLATE_COMMENT("Option",
8713672a07eSStephan Aßmus 		"Name for modifier on keyboard");
8723672a07eSStephan Aßmus 	sCommandName = B_TRANSLATE_COMMENT("Command",
8733672a07eSStephan Aßmus 		"Name for modifier on keyboard");
8743672a07eSStephan Aßmus #endif
8753672a07eSStephan Aßmus }
876fa1ee6d4SJonas Sundström 
877