xref: /haiku/src/preferences/keymap/ModifierKeysWindow.cpp (revision 90ae2e54f6ccaca73c011a2aa4cdd660417108ad)
1 /*
2  * Copyright 2011 Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		John Scipione, jscipione@gmail.com
7  */
8 
9 
10 #include "ModifierKeysWindow.h"
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include <Catalog.h>
17 #include <FindDirectory.h>
18 #include <GroupLayout.h>
19 #include <GridLayoutBuilder.h>
20 #include <GroupLayoutBuilder.h>
21 #include <IconUtils.h>
22 #include <Locale.h>
23 #include <LayoutBuilder.h>
24 #include <MenuItem.h>
25 #include <Message.h>
26 #include <Path.h>
27 #include <Resources.h>
28 #include <Size.h>
29 
30 #include "KeymapApplication.h"
31 
32 
33 #ifdef DEBUG_ALERT
34 #	define FTRACE(x) fprintf(x)
35 #else
36 #	define FTRACE(x) /* nothing */
37 #endif
38 
39 
40 const rgb_color disabledColor = (rgb_color){128, 128, 128, 255};
41 const rgb_color normalColor = (rgb_color){0, 0, 0, 255};
42 
43 enum {
44 	SHIFT_KEY = 0x00000001,
45 	CONTROL_KEY = 0x00000002,
46 	OPTION_KEY = 0x00000004,
47 	COMMAND_KEY = 0x00000008
48 };
49 
50 enum {
51 	MENU_ITEM_SHIFT = 0,
52 	MENU_ITEM_CONTROL,
53 	MENU_ITEM_OPTION,
54 	MENU_ITEM_COMMAND,
55 	MENU_ITEM_SEPERATOR,
56 	MENU_ITEM_DISABLED
57 };
58 
59 static const uint32 kMsgUpdateModifier		= 'upmd';
60 static const uint32 kMsgApplyModifiers 		= 'apmd';
61 static const uint32 kMsgRevertModifiers		= 'rvmd';
62 
63 
64 #undef B_TRANSLATION_CONTEXT
65 #define B_TRANSLATION_CONTEXT "Modifier keys window"
66 
67 
68 ModifierKeysWindow::ModifierKeysWindow()
69 	:
70 	BWindow(BRect(0, 0, 360, 220), B_TRANSLATE("Modifier keys"),
71 		B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE
72 		| B_AUTO_UPDATE_SIZE_LIMITS)
73 {
74 	get_key_map(&fCurrentMap, &fCurrentBuffer);
75 	get_key_map(&fSavedMap, &fSavedBuffer);
76 
77 	BStringView* keyRole = new BStringView("key role",
78 		B_TRANSLATE_COMMENT("Role", "As in the role of a modifier key"));
79 	keyRole->SetAlignment(B_ALIGN_RIGHT);
80 	keyRole->SetFont(be_bold_font);
81 
82 	BStringView* keyLabel = new BStringView("key label",
83 		B_TRANSLATE_COMMENT("Key", "As in a computer keyboard key"));
84 	keyLabel->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
85 	keyLabel->SetFont(be_bold_font);
86 
87 	fShiftStringView = new BStringView("shift",
88 		B_TRANSLATE_COMMENT("Shift:", "Shift key role name"));
89 	fShiftStringView->SetAlignment(B_ALIGN_RIGHT);
90 
91 	fControlStringView = new BStringView("control",
92 		B_TRANSLATE_COMMENT("Control:", "Control key role name"));
93 	fControlStringView->SetAlignment(B_ALIGN_RIGHT);
94 
95 	fOptionStringView = new BStringView("option",
96 		B_TRANSLATE_COMMENT("Option:", "Option key role name"));
97 	fOptionStringView->SetAlignment(B_ALIGN_RIGHT);
98 
99 	fCommandStringView = new BStringView("command",
100 		B_TRANSLATE_COMMENT("Command:", "Command key role name"));
101 	fCommandStringView->SetAlignment(B_ALIGN_RIGHT);
102 
103 	fShiftConflictView = new ConflictView("shift warning view");
104 	fShiftConflictView->SetExplicitMaxSize(BSize(15, 15));
105 
106 	fControlConflictView = new ConflictView("control warning view");
107 	fControlConflictView->SetExplicitMaxSize(BSize(15, 15));
108 
109 	fOptionConflictView = new ConflictView("option warning view");
110 	fOptionConflictView->SetExplicitMaxSize(BSize(15, 15));
111 
112 	fCommandConflictView = new ConflictView("command warning view");
113 	fCommandConflictView->SetExplicitMaxSize(BSize(15, 15));
114 
115 	fCancelButton = new BButton("cancelButton", B_TRANSLATE("Cancel"),
116 		new BMessage(B_QUIT_REQUESTED));
117 
118 	fRevertButton = new BButton("revertButton", B_TRANSLATE("Revert"),
119 		new BMessage(kMsgRevertModifiers));
120 	fRevertButton->SetEnabled(false);
121 
122 	fOkButton = new BButton("okButton", B_TRANSLATE("Set modifier keys"),
123 		new BMessage(kMsgApplyModifiers));
124 	fOkButton->MakeDefault(true);
125 
126 	// Build the layout
127 	SetLayout(new BGroupLayout(B_VERTICAL));
128 
129 	AddChild(BGroupLayoutBuilder(B_VERTICAL, 10)
130 		.Add(BGridLayoutBuilder(10, 10)
131 			.Add(keyRole, 0, 0)
132 			.Add(keyLabel, 1, 0)
133 
134 			.Add(fShiftStringView, 0, 1)
135 			.Add(_CreateShiftMenuField(), 1, 1)
136 			.Add(fShiftConflictView, 2, 1)
137 
138 			.Add(fControlStringView, 0, 2)
139 			.Add(_CreateControlMenuField(), 1, 2)
140 			.Add(fControlConflictView, 2, 2)
141 
142 			.Add(fOptionStringView, 0, 3)
143 			.Add(_CreateOptionMenuField(), 1, 3)
144 			.Add(fOptionConflictView, 2, 3)
145 
146 			.Add(fCommandStringView, 0, 4)
147 			.Add(_CreateCommandMenuField(), 1, 4)
148 			.Add(fCommandConflictView, 2, 4)
149 		)
150 		.AddGlue()
151 		.AddGroup(B_HORIZONTAL, 10)
152 			.Add(fCancelButton)
153 			.AddGlue()
154 			.Add(fRevertButton)
155 			.Add(fOkButton)
156 		.End()
157 		.SetInsets(10, 10, 10, 10)
158 	);
159 
160 	_MarkMenuItems();
161 	_ValidateDuplicateKeys();
162 
163 	CenterOnScreen();
164 }
165 
166 
167 ModifierKeysWindow::~ModifierKeysWindow()
168 {
169 	be_app->PostMessage(kMsgCloseModifierKeysWindow);
170 }
171 
172 
173 void
174 ModifierKeysWindow::MessageReceived(BMessage* message)
175 {
176 	switch (message->what) {
177 		case kMsgUpdateModifier:
178 		{
179 			int32 menuitem = MENU_ITEM_SHIFT;
180 			int32 key = -1;
181 
182 			for (; menuitem <= MENU_ITEM_COMMAND; menuitem++) {
183 				if (message->FindInt32(_KeyToString(menuitem), &key) == B_OK)
184 					break;
185 			}
186 
187 			if (key == -1)
188 				return;
189 
190 			// menuitem contains the item we want to set
191 			// key contains the item we want to set it to.
192 
193 			switch (menuitem) {
194 				case MENU_ITEM_SHIFT:
195 					fCurrentMap->left_shift_key = _KeyToKeyCode(key);
196 					fCurrentMap->right_shift_key = _KeyToKeyCode(key, true);
197 					break;
198 
199 				case MENU_ITEM_CONTROL:
200 					fCurrentMap->left_control_key = _KeyToKeyCode(key);
201 					fCurrentMap->right_control_key = _KeyToKeyCode(key, true);
202 					break;
203 
204 				case MENU_ITEM_OPTION:
205 					fCurrentMap->left_option_key = _KeyToKeyCode(key);
206 					fCurrentMap->right_option_key = _KeyToKeyCode(key, true);
207 					break;
208 
209 				case MENU_ITEM_COMMAND:
210 					fCurrentMap->left_command_key = _KeyToKeyCode(key);
211 					fCurrentMap->right_command_key = _KeyToKeyCode(key, true);
212 					break;
213 			}
214 
215 			_MarkMenuItems();
216 			_ValidateDuplicateKeys();
217 
218 			// enable/disable revert button
219 			fRevertButton->SetEnabled(
220 				memcmp(fCurrentMap, fSavedMap, sizeof(key_map)));
221 			break;
222 		}
223 
224 		// OK button
225 		case kMsgApplyModifiers:
226 		{
227 			// if duplicate modifiers are found, don't update
228 			if (_DuplicateKeys() != 0)
229 				break;
230 
231 			BMessage* updateModifiers = new BMessage(kMsgUpdateModifierKeys);
232 
233 			if (fCurrentMap->left_shift_key != fSavedMap->left_shift_key) {
234 				updateModifiers->AddUInt32("left_shift_key",
235 					fCurrentMap->left_shift_key);
236 			}
237 
238 			if (fCurrentMap->right_shift_key != fSavedMap->right_shift_key) {
239 				updateModifiers->AddUInt32("right_shift_key",
240 					fCurrentMap->right_shift_key);
241 			}
242 
243 			if (fCurrentMap->left_control_key != fSavedMap->left_control_key) {
244 				updateModifiers->AddUInt32("left_control_key",
245 					fCurrentMap->left_control_key);
246 			}
247 
248 			if (fCurrentMap->right_control_key
249 				!= fSavedMap->right_control_key) {
250 				updateModifiers->AddUInt32("right_control_key",
251 					fCurrentMap->right_control_key);
252 			}
253 
254 			if (fCurrentMap->left_option_key != fSavedMap->left_option_key) {
255 				updateModifiers->AddUInt32("left_option_key",
256 					fCurrentMap->left_option_key);
257 			}
258 
259 			if (fCurrentMap->right_option_key != fSavedMap->right_option_key) {
260 				updateModifiers->AddUInt32("right_option_key",
261 					fCurrentMap->right_option_key);
262 			}
263 
264 			if (fCurrentMap->left_command_key != fSavedMap->left_command_key) {
265 				updateModifiers->AddUInt32("left_command_key",
266 					fCurrentMap->left_command_key);
267 			}
268 
269 			if (fCurrentMap->right_command_key
270 				!= fSavedMap->right_command_key) {
271 				updateModifiers->AddUInt32("right_command_key",
272 					fCurrentMap->right_command_key);
273 			}
274 
275 			// KeymapWindow updates the modifiers
276 			be_app->PostMessage(updateModifiers);
277 
278 			// we are done here, close the window
279 			this->PostMessage(B_QUIT_REQUESTED);
280 			break;
281 		}
282 
283 		// Revert button
284 		case kMsgRevertModifiers:
285 			memcpy(fCurrentMap, fSavedMap, sizeof(key_map));
286 
287 			_MarkMenuItems();
288 			_ValidateDuplicateKeys();
289 
290 			fRevertButton->SetEnabled(false);
291 			break;
292 
293 		default:
294 			BWindow::MessageReceived(message);
295 	}
296 }
297 
298 
299 //	#pragma mark -
300 
301 
302 BMenuField*
303 ModifierKeysWindow::_CreateShiftMenuField()
304 {
305 	fShiftMenu = new BPopUpMenu(
306 		B_TRANSLATE_NOCOLLECT(_KeyToString(MENU_ITEM_SHIFT)), true, true);
307 
308 	for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_DISABLED; key++) {
309 		if (key == MENU_ITEM_SEPERATOR) {
310 			// add separator item
311 			BSeparatorItem* separator = new BSeparatorItem;
312 			fShiftMenu->AddItem(separator, MENU_ITEM_SEPERATOR);
313 			continue;
314 		}
315 
316 		BMessage* message = new BMessage(kMsgUpdateModifier);
317 		message->AddInt32(_KeyToString(MENU_ITEM_SHIFT), key);
318 		BMenuItem* item = new BMenuItem(
319 			B_TRANSLATE_NOCOLLECT(_KeyToString(key)), message);
320 
321 		fShiftMenu->AddItem(item, key);
322 	}
323 	fShiftMenu->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
324 		B_ALIGN_VERTICAL_UNSET));
325 
326 	return new BMenuField(NULL, fShiftMenu);
327 }
328 
329 
330 BMenuField*
331 ModifierKeysWindow::_CreateControlMenuField()
332 {
333 	fControlMenu = new BPopUpMenu(
334 		B_TRANSLATE_NOCOLLECT(_KeyToString(MENU_ITEM_CONTROL)), true, true);
335 
336 	for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_DISABLED; key++) {
337 		if (key == MENU_ITEM_SEPERATOR) {
338 			// add separator item
339 			BSeparatorItem* separator = new BSeparatorItem;
340 			fControlMenu->AddItem(separator, MENU_ITEM_SEPERATOR);
341 			continue;
342 		}
343 
344 		BMessage* message = new BMessage(kMsgUpdateModifier);
345 		message->AddInt32(_KeyToString(MENU_ITEM_CONTROL), key);
346 		BMenuItem* item = new BMenuItem(
347 			B_TRANSLATE_NOCOLLECT(_KeyToString(key)), message);
348 
349 		fControlMenu->AddItem(item, key);
350 	}
351 	fControlMenu->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
352 		B_ALIGN_VERTICAL_UNSET));
353 
354 	return new BMenuField(NULL, fControlMenu);
355 }
356 
357 
358 BMenuField*
359 ModifierKeysWindow::_CreateOptionMenuField()
360 {
361 	fOptionMenu = new BPopUpMenu(
362 		B_TRANSLATE_NOCOLLECT(_KeyToString(MENU_ITEM_OPTION)), true, true);
363 
364 	for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_DISABLED; key++) {
365 		if (key == MENU_ITEM_SEPERATOR) {
366 			// add separator item
367 			BSeparatorItem* separator = new BSeparatorItem;
368 			fOptionMenu->AddItem(separator, MENU_ITEM_SEPERATOR);
369 			continue;
370 		}
371 
372 		BMessage* message = new BMessage(kMsgUpdateModifier);
373 		message->AddInt32(_KeyToString(MENU_ITEM_OPTION), key);
374 		BMenuItem* item = new BMenuItem(
375 			B_TRANSLATE_NOCOLLECT(_KeyToString(key)), message);
376 
377 		fOptionMenu->AddItem(item, key);
378 	}
379 	fOptionMenu->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
380 		B_ALIGN_VERTICAL_UNSET));
381 
382 	return new BMenuField(NULL, fOptionMenu);
383 }
384 
385 
386 BMenuField*
387 ModifierKeysWindow::_CreateCommandMenuField()
388 {
389 	fCommandMenu = new BPopUpMenu(
390 		B_TRANSLATE_NOCOLLECT(_KeyToString(MENU_ITEM_COMMAND)), true, true);
391 
392 	for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_DISABLED; key++) {
393 		if (key == MENU_ITEM_SEPERATOR) {
394 			// add separator item
395 			BSeparatorItem* separator = new BSeparatorItem;
396 			fCommandMenu->AddItem(separator, MENU_ITEM_SEPERATOR);
397 			continue;
398 		}
399 
400 		BMessage* message = new BMessage(kMsgUpdateModifier);
401 		message->AddInt32(_KeyToString(MENU_ITEM_COMMAND), key);
402 		BMenuItem* item = new BMenuItem(
403 			B_TRANSLATE_NOCOLLECT(_KeyToString(key)), message);
404 		fCommandMenu->AddItem(item, key);
405 	}
406 	fCommandMenu->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
407 		B_ALIGN_VERTICAL_UNSET));
408 
409 	return new BMenuField(NULL, fCommandMenu);
410 }
411 
412 
413 void
414 ModifierKeysWindow::_MarkMenuItems()
415 {
416 	for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_DISABLED; key++) {
417 		if (key == MENU_ITEM_SEPERATOR)
418 			continue;
419 
420 		if (fCurrentMap->left_shift_key == _KeyToKeyCode(key)
421 			&& fCurrentMap->right_shift_key == _KeyToKeyCode(key, true)) {
422 			fShiftMenu->ItemAt(key)->SetMarked(true);
423 
424 			if (key == MENU_ITEM_DISABLED)
425 				fShiftStringView->SetHighColor(disabledColor);
426 			else
427 				fShiftStringView->SetHighColor(normalColor);
428 
429 			fShiftStringView->Invalidate();
430 		}
431 
432 		if (fCurrentMap->left_control_key == _KeyToKeyCode(key)
433 			&& fCurrentMap->right_control_key == _KeyToKeyCode(key, true)) {
434 			fControlMenu->ItemAt(key)->SetMarked(true);
435 
436 			if (key == MENU_ITEM_DISABLED)
437 				fControlStringView->SetHighColor(disabledColor);
438 			else
439 				fControlStringView->SetHighColor(normalColor);
440 
441 			fControlStringView->Invalidate();
442 		}
443 
444 		if (fCurrentMap->left_option_key == _KeyToKeyCode(key)
445 			&& fCurrentMap->right_option_key == _KeyToKeyCode(key, true)) {
446 			fOptionMenu->ItemAt(key)->SetMarked(true);
447 
448 			if (key == MENU_ITEM_DISABLED)
449 				fOptionStringView->SetHighColor(disabledColor);
450 			else
451 				fOptionStringView->SetHighColor(normalColor);
452 
453 			fOptionStringView->Invalidate();
454 		}
455 
456 		if (fCurrentMap->left_command_key == _KeyToKeyCode(key)
457 			&& fCurrentMap->right_command_key == _KeyToKeyCode(key, true)) {
458 			fCommandMenu->ItemAt(key)->SetMarked(true);
459 
460 			if (key == MENU_ITEM_DISABLED)
461 				fCommandStringView->SetHighColor(disabledColor);
462 			else
463 				fCommandStringView->SetHighColor(normalColor);
464 
465 			fCommandStringView->Invalidate();
466 		}
467 	}
468 }
469 
470 
471 // get the string for a modifier key
472 const char*
473 ModifierKeysWindow::_KeyToString(int32 key)
474 {
475 	switch (key) {
476 		case MENU_ITEM_SHIFT:
477 			return B_TRANSLATE_COMMENT("Shift key",
478 				"Label of key above Ctrl, usually Shift");
479 
480 		case MENU_ITEM_CONTROL:
481 			return B_TRANSLATE_COMMENT("Ctrl key",
482 				"Label of key farthest from the spacebar, usually Ctrl"
483 				"e.g. Strg for German keyboard");
484 
485 		case MENU_ITEM_OPTION:
486 			return B_TRANSLATE_COMMENT("Win/Cmd key",
487 				"Label of the \"Windows\" key (PC)/Command key (Mac)");
488 
489 		case MENU_ITEM_COMMAND:
490 			return B_TRANSLATE_COMMENT("Alt/Opt key",
491 				"Label of Alt key (PC)/Option key (Mac)");
492 
493 		case MENU_ITEM_DISABLED:
494 			return B_TRANSLATE_COMMENT("Disabled", "Do nothing");
495 	}
496 
497 	return "";
498 }
499 
500 
501 // get the keycode for a modifier key
502 uint32
503 ModifierKeysWindow::_KeyToKeyCode(int32 key, bool right)
504 {
505 	switch (key) {
506 		case MENU_ITEM_SHIFT:
507 			if (right)
508 				return 0x56;
509 			return 0x4b;
510 
511 		case MENU_ITEM_CONTROL:
512 			if (right)
513 				return 0x60;
514 			return 0x5c;
515 
516 		case MENU_ITEM_OPTION:
517 			if (right)
518 				return 0x67;
519 			return 0x66;
520 
521 		case MENU_ITEM_COMMAND:
522 			if (right)
523 				return 0x5f;
524 			return 0x5d;
525 
526 		case MENU_ITEM_DISABLED:
527 			return 0;
528 	}
529 
530 	return 0;
531 }
532 
533 
534 // validate duplicate keys
535 void
536 ModifierKeysWindow::_ValidateDuplicateKeys()
537 {
538 	uint32 dupMask = _DuplicateKeys();
539 
540 	BBitmap* shiftIcon = fShiftConflictView->Icon();
541 	BBitmap* controlIcon = fControlConflictView->Icon();
542 	BBitmap* optionIcon = fOptionConflictView->Icon();
543 	BBitmap* commandIcon = fCommandConflictView->Icon();
544 
545 	if (dupMask != 0) {
546 		fShiftConflictView->ShowIcon((dupMask & SHIFT_KEY) != 0);
547 		fControlConflictView->ShowIcon((dupMask & CONTROL_KEY) != 0);
548 		fOptionConflictView->ShowIcon((dupMask & OPTION_KEY) != 0);
549 		fCommandConflictView->ShowIcon((dupMask & COMMAND_KEY) != 0);
550 
551 		fOkButton->SetEnabled(false);
552 	} else {
553 		fShiftConflictView->ShowIcon(false);
554 		fControlConflictView->ShowIcon(false);
555 		fOptionConflictView->ShowIcon(false);
556 		fCommandConflictView->ShowIcon(false);
557 
558 		fOkButton->SetEnabled(true);
559 	}
560 
561 	// if there was a change invalidate the view
562 	if (shiftIcon != fShiftConflictView->Icon())
563 		fShiftConflictView->Invalidate();
564 
565 	if (controlIcon != fControlConflictView->Icon())
566 		fControlConflictView->Invalidate();
567 
568 	if (optionIcon != fOptionConflictView->Icon())
569 		fOptionConflictView->Invalidate();
570 
571 	if (commandIcon != fCommandConflictView->Icon())
572 		fCommandConflictView->Invalidate();
573 }
574 
575 
576 // return a mask marking which keys are duplicates of each other for
577 // validation. Control = 1, Option = 2, Command = 3
578 uint32
579 ModifierKeysWindow::_DuplicateKeys()
580 {
581 	uint32 duplicateMask = 0;
582 
583 	for (int32 testKey = MENU_ITEM_SHIFT; testKey <= MENU_ITEM_COMMAND;
584 		testKey++) {
585 		uint32 testLeft = 0;
586 		uint32 testRight = 0;
587 
588 		switch (testKey) {
589 			case MENU_ITEM_SHIFT:
590 				testLeft = fCurrentMap->left_shift_key;
591 				testRight = fCurrentMap->right_shift_key;
592 				break;
593 
594 			case MENU_ITEM_CONTROL:
595 				testLeft = fCurrentMap->left_control_key;
596 				testRight = fCurrentMap->right_control_key;
597 				break;
598 
599 			case MENU_ITEM_OPTION:
600 				testLeft = fCurrentMap->left_option_key;
601 				testRight = fCurrentMap->right_option_key;
602 				break;
603 
604 			case MENU_ITEM_COMMAND:
605 				testLeft = fCurrentMap->left_command_key;
606 				testRight = fCurrentMap->right_command_key;
607 				break;
608 		}
609 
610 		if (testLeft == 0 && testRight == 0)
611 			continue;
612 
613 		for (int32 key = MENU_ITEM_SHIFT; key <= MENU_ITEM_COMMAND; key++) {
614 			if (key == testKey) {
615 				// skip over yourself
616 				continue;
617 			}
618 
619 			uint32 left = 0;
620 			uint32 right = 0;
621 
622 			switch(key) {
623 				case MENU_ITEM_SHIFT:
624 					left = fCurrentMap->left_shift_key;
625 					right = fCurrentMap->right_shift_key;
626 					break;
627 
628 				case MENU_ITEM_CONTROL:
629 					left = fCurrentMap->left_control_key;
630 					right = fCurrentMap->right_control_key;
631 					break;
632 
633 				case MENU_ITEM_OPTION:
634 					left = fCurrentMap->left_option_key;
635 					right = fCurrentMap->right_option_key;
636 					break;
637 
638 				case MENU_ITEM_COMMAND:
639 					left = fCurrentMap->left_command_key;
640 					right = fCurrentMap->right_command_key;
641 					break;
642 			}
643 
644 			if (left == 0 && right == 0)
645 				continue;
646 
647 			if (left == testLeft && right == testRight) {
648 				duplicateMask |= 1 << testKey;
649 				duplicateMask |= 1 << key;
650 			}
651 		}
652 	}
653 
654 	return duplicateMask;
655 }
656 
657 
658 //	#pragma mark - ConflictView
659 
660 
661 ConflictView::ConflictView(const char* name)
662 	:
663 	BView(BRect(0, 0, 15, 15), name, B_FOLLOW_NONE, B_WILL_DRAW),
664 	fIcon(NULL),
665 	fSavedIcon(NULL)
666 {
667 	_FillSavedIcon();
668 }
669 
670 
671 ConflictView::~ConflictView()
672 {
673 	delete fSavedIcon;
674 }
675 
676 
677 void
678 ConflictView::Draw(BRect updateRect)
679 {
680 	// Draw background
681 
682 	if (Parent())
683 		SetLowColor(Parent()->ViewColor());
684 	else
685 		SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
686 
687 	FillRect(updateRect, B_SOLID_LOW);
688 
689 	// Draw icon
690 	if (fIcon == NULL)
691 		return;
692 
693 	SetDrawingMode(B_OP_ALPHA);
694 	SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
695 	DrawBitmapAsync(fIcon, BPoint(0, 0));
696 }
697 
698 
699 // get the icon
700 BBitmap*
701 ConflictView::Icon()
702 {
703 	return fIcon;
704 }
705 
706 
707 // show or hide the icon
708 void
709 ConflictView::ShowIcon(bool show)
710 {
711 	if (show)
712 		fIcon = fSavedIcon;
713 	else
714 		fIcon = NULL;
715 }
716 
717 
718 //	#pragma mark -
719 
720 
721 // fill out the icon with the stop symbol from app_server
722 void
723 ConflictView::_FillSavedIcon()
724 {
725 	// return if the fSavedIcon has already been filled out
726 	if (fSavedIcon != NULL && fSavedIcon->InitCheck() == B_OK)
727 		return;
728 
729 	BPath path;
730 	status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path);
731 	if (status < B_OK) {
732 		FTRACE((stderr,
733 			"_FillWarningIcon() - find_directory failed: %s\n",
734 			strerror(status)));
735 		delete fSavedIcon;
736 		fSavedIcon = NULL;
737 		return;
738 	}
739 
740 	path.Append("app_server");
741 	BFile file;
742 	status = file.SetTo(path.Path(), B_READ_ONLY);
743 	if (status < B_OK) {
744 		FTRACE((stderr,
745 			"_FillWarningIcon() - BFile init failed: %s\n",
746 			strerror(status)));
747 		delete fSavedIcon;
748 		fSavedIcon = NULL;
749 		return;
750 	}
751 
752 	BResources resources;
753 	status = resources.SetTo(&file);
754 	if (status < B_OK) {
755 		FTRACE((stderr,
756 			"_WarningIcon() - BResources init failed: %s\n",
757 			strerror(status)));
758 		delete fSavedIcon;
759 		fSavedIcon = NULL;
760 		return;
761 	}
762 
763 	// Allocate the fSavedIcon bitmap
764 	fSavedIcon = new(std::nothrow) BBitmap(BRect(0, 0, 15, 15), 0, B_RGBA32);
765 	if (fSavedIcon->InitCheck() < B_OK) {
766 		FTRACE((stderr, "_WarningIcon() - No memory for warning bitmap\n"));
767 		delete fSavedIcon;
768 		fSavedIcon = NULL;
769 		return;
770 	}
771 
772 	// Load the raw stop icon data
773 	size_t size = 0;
774 	const uint8* rawIcon;
775 	rawIcon = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE,
776 		"stop", &size);
777 
778 	// load vector warning icon into fSavedIcon
779 	if (rawIcon == NULL
780 		|| BIconUtils::GetVectorIcon(rawIcon, size, fSavedIcon) < B_OK) {
781 			delete fSavedIcon;
782 			fSavedIcon = NULL;
783 	}
784 }
785