Source Code Cross Referenced for KeysPreferencePage.java in  » IDE-Eclipse » ui-workbench » org » eclipse » ui » internal » keys » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Eclipse » ui workbench » org.eclipse.ui.internal.keys 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Copyright (c) 2000, 2007 IBM Corporation and others.
0003:         * All rights reserved. This program and the accompanying materials
0004:         * are made available under the terms of the Eclipse Public License v1.0
0005:         * which accompanies this distribution, and is available at
0006:         * http://www.eclipse.org/legal/epl-v10.html
0007:         *
0008:         * Contributors:
0009:         *     IBM Corporation - initial API and implementation
0010:         *******************************************************************************/package org.eclipse.ui.internal.keys;
0011:
0012:        import java.io.BufferedWriter;
0013:        import java.io.FileWriter;
0014:        import java.io.IOException;
0015:        import java.io.Writer;
0016:        import java.util.ArrayList;
0017:        import java.util.Arrays;
0018:        import java.util.Collection;
0019:        import java.util.Collections;
0020:        import java.util.Comparator;
0021:        import java.util.HashMap;
0022:        import java.util.HashSet;
0023:        import java.util.Iterator;
0024:        import java.util.List;
0025:        import java.util.Map;
0026:        import java.util.ResourceBundle;
0027:        import java.util.Set;
0028:
0029:        import org.eclipse.core.commands.Category;
0030:        import org.eclipse.core.commands.Command;
0031:        import org.eclipse.core.commands.CommandManager;
0032:        import org.eclipse.core.commands.ParameterizedCommand;
0033:        import org.eclipse.core.commands.common.NotDefinedException;
0034:        import org.eclipse.core.commands.contexts.Context;
0035:        import org.eclipse.core.commands.contexts.ContextManager;
0036:        import org.eclipse.core.runtime.IStatus;
0037:        import org.eclipse.core.runtime.SafeRunner;
0038:        import org.eclipse.core.runtime.Status;
0039:        import org.eclipse.jface.bindings.Binding;
0040:        import org.eclipse.jface.bindings.BindingManager;
0041:        import org.eclipse.jface.bindings.Scheme;
0042:        import org.eclipse.jface.bindings.TriggerSequence;
0043:        import org.eclipse.jface.bindings.keys.KeyBinding;
0044:        import org.eclipse.jface.bindings.keys.KeySequence;
0045:        import org.eclipse.jface.bindings.keys.KeySequenceText;
0046:        import org.eclipse.jface.bindings.keys.KeyStroke;
0047:        import org.eclipse.jface.contexts.IContextIds;
0048:        import org.eclipse.jface.dialogs.IDialogConstants;
0049:        import org.eclipse.jface.dialogs.MessageDialog;
0050:        import org.eclipse.jface.preference.IPreferenceStore;
0051:        import org.eclipse.jface.preference.PreferencePage;
0052:        import org.eclipse.jface.util.SafeRunnable;
0053:        import org.eclipse.swt.SWT;
0054:        import org.eclipse.swt.events.DisposeEvent;
0055:        import org.eclipse.swt.events.DisposeListener;
0056:        import org.eclipse.swt.events.FocusEvent;
0057:        import org.eclipse.swt.events.FocusListener;
0058:        import org.eclipse.swt.events.ModifyEvent;
0059:        import org.eclipse.swt.events.ModifyListener;
0060:        import org.eclipse.swt.events.MouseAdapter;
0061:        import org.eclipse.swt.events.MouseEvent;
0062:        import org.eclipse.swt.events.SelectionAdapter;
0063:        import org.eclipse.swt.events.SelectionEvent;
0064:        import org.eclipse.swt.events.SelectionListener;
0065:        import org.eclipse.swt.graphics.Image;
0066:        import org.eclipse.swt.graphics.Point;
0067:        import org.eclipse.swt.layout.GridData;
0068:        import org.eclipse.swt.layout.GridLayout;
0069:        import org.eclipse.swt.widgets.Button;
0070:        import org.eclipse.swt.widgets.Combo;
0071:        import org.eclipse.swt.widgets.Composite;
0072:        import org.eclipse.swt.widgets.Control;
0073:        import org.eclipse.swt.widgets.FileDialog;
0074:        import org.eclipse.swt.widgets.Group;
0075:        import org.eclipse.swt.widgets.Label;
0076:        import org.eclipse.swt.widgets.Menu;
0077:        import org.eclipse.swt.widgets.MenuItem;
0078:        import org.eclipse.swt.widgets.TabFolder;
0079:        import org.eclipse.swt.widgets.TabItem;
0080:        import org.eclipse.swt.widgets.Table;
0081:        import org.eclipse.swt.widgets.TableColumn;
0082:        import org.eclipse.swt.widgets.TableItem;
0083:        import org.eclipse.swt.widgets.Text;
0084:        import org.eclipse.ui.IWorkbench;
0085:        import org.eclipse.ui.IWorkbenchPreferencePage;
0086:        import org.eclipse.ui.PlatformUI;
0087:        import org.eclipse.ui.activities.IActivityManager;
0088:        import org.eclipse.ui.commands.ICommandService;
0089:        import org.eclipse.ui.contexts.IContextService;
0090:        import org.eclipse.ui.internal.IPreferenceConstants;
0091:        import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
0092:        import org.eclipse.ui.internal.WorkbenchPlugin;
0093:        import org.eclipse.ui.internal.misc.StatusUtil;
0094:        import org.eclipse.ui.internal.util.PrefUtil;
0095:        import org.eclipse.ui.internal.util.Util;
0096:        import org.eclipse.ui.keys.IBindingService;
0097:        import org.eclipse.ui.statushandlers.StatusManager;
0098:
0099:        import com.ibm.icu.text.Collator;
0100:        import com.ibm.icu.text.MessageFormat;
0101:
0102:        /**
0103:         * The preference page for defining keyboard shortcuts. While some of its
0104:         * underpinning have been made generic to "bindings" rather than "key bindings",
0105:         * it will still take some work to remove the link entirely.
0106:         * 
0107:         * @since 3.0
0108:         */
0109:        public final class KeysPreferencePage extends PreferencePage implements 
0110:                IWorkbenchPreferencePage {
0111:
0112:            /**
0113:             * A selection listener to be used on the columns in the table on the view
0114:             * tab. This selection listener modifies the sort order so that the
0115:             * appropriate column is in the first position.
0116:             * 
0117:             * @since 3.1
0118:             */
0119:            private class SortOrderSelectionListener extends SelectionAdapter {
0120:
0121:                /**
0122:                 * The column to be put in the first position. This value should be one
0123:                 * of the constants defined by <code>SORT_COLUMN_</code>.
0124:                 */
0125:                private final int columnSelected;
0126:
0127:                /**
0128:                 * Constructs a new instance of <code>SortOrderSelectionListener</code>.
0129:                 * 
0130:                 * @param columnSelected
0131:                 *            The column to be given first priority in the sort order;
0132:                 *            this value should be one of the constants defined as
0133:                 *            <code>SORT_COLUMN_</code>.
0134:                 */
0135:                private SortOrderSelectionListener(final int columnSelected) {
0136:                    this .columnSelected = columnSelected;
0137:                }
0138:
0139:                /*
0140:                 * (non-Javadoc)
0141:                 * 
0142:                 * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
0143:                 */
0144:                public void widgetSelected(SelectionEvent e) {
0145:                    // Change the column titles.
0146:                    final int oldSortIndex = sortOrder[0];
0147:                    final TableColumn oldSortColumn = tableBindings
0148:                            .getColumn(oldSortIndex);
0149:                    oldSortColumn.setText(UNSORTED_COLUMN_NAMES[oldSortIndex]);
0150:                    final TableColumn newSortColumn = tableBindings
0151:                            .getColumn(columnSelected);
0152:                    newSortColumn.setText(SORTED_COLUMN_NAMES[columnSelected]);
0153:
0154:                    // Change the sort order.
0155:                    boolean columnPlaced = false;
0156:                    boolean enoughRoom = false;
0157:                    int bumpedColumn = -1;
0158:                    for (int i = 0; i < sortOrder.length; i++) {
0159:                        if (sortOrder[i] == columnSelected) {
0160:                            /*
0161:                             * We've found the place where the column existing in the
0162:                             * old sort order. No matter what at this point, we have
0163:                             * completed the reshuffling.
0164:                             */
0165:                            enoughRoom = true;
0166:                            if (bumpedColumn != -1) {
0167:                                // We have already started bumping things around, so
0168:                                // drop the last bumped column here.
0169:                                sortOrder[i] = bumpedColumn;
0170:                            } else {
0171:                                // The order has not changed.
0172:                                columnPlaced = true;
0173:                            }
0174:                            break;
0175:
0176:                        } else if (columnPlaced) {
0177:                            // We are currently bumping, so just bump another.
0178:                            int temp = sortOrder[i];
0179:                            sortOrder[i] = bumpedColumn;
0180:                            bumpedColumn = temp;
0181:
0182:                        } else {
0183:                            /*
0184:                             * We are not currently bumping, so drop the column and
0185:                             * start bumping.
0186:                             */
0187:                            bumpedColumn = sortOrder[i];
0188:                            sortOrder[i] = columnSelected;
0189:                            columnPlaced = true;
0190:                        }
0191:                    }
0192:
0193:                    // Grow the sort order.
0194:                    if (!enoughRoom) {
0195:                        final int[] newSortOrder = new int[sortOrder.length + 1];
0196:                        System.arraycopy(sortOrder, 0, newSortOrder, 0,
0197:                                sortOrder.length);
0198:                        newSortOrder[sortOrder.length] = bumpedColumn;
0199:                        sortOrder = newSortOrder;
0200:                    }
0201:
0202:                    // Update the view tab.
0203:                    updateViewTab();
0204:                }
0205:            }
0206:
0207:            /**
0208:             * The data key for the binding stored on an SWT widget. The key is a
0209:             * fully-qualified name, but in reverse order. This is so that the equals
0210:             * method will detect misses faster.
0211:             */
0212:            private static final String BINDING_KEY = "Binding.bindings.jface.eclipse.org"; //$NON-NLS-1$
0213:
0214:            /**
0215:             * The image associate with a binding that exists as part of the system
0216:             * definition.
0217:             */
0218:            private static final Image IMAGE_BLANK = ImageFactory
0219:                    .getImage("blank"); //$NON-NLS-1$
0220:
0221:            /**
0222:             * The image associated with a binding changed by the user.
0223:             */
0224:            private static final Image IMAGE_CHANGE = ImageFactory
0225:                    .getImage("change"); //$NON-NLS-1$
0226:
0227:            /**
0228:             * The data key at which the <code>Binding</code> instance for a table
0229:             * item is stored.
0230:             */
0231:            private static final String ITEM_DATA_KEY = "org.eclipse.jface.bindings"; //$NON-NLS-1$
0232:
0233:            /**
0234:             * The number of items to show in the combo boxes.
0235:             */
0236:            private static final int ITEMS_TO_SHOW = 9;
0237:
0238:            /**
0239:             * The resource bundle from which translations can be retrieved.
0240:             */
0241:            private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
0242:                    .getBundle(KeysPreferencePage.class.getName());
0243:
0244:            /**
0245:             * The total number of columns on the view tab.
0246:             */
0247:            private static final int VIEW_TOTAL_COLUMNS = 4;
0248:
0249:            /**
0250:             * The translated names for the columns when they are the primary sort key
0251:             * (e.g., ">Category<").
0252:             */
0253:            private static final String[] SORTED_COLUMN_NAMES = new String[VIEW_TOTAL_COLUMNS];
0254:
0255:            /**
0256:             * The index of the modify tab.
0257:             * 
0258:             * @since 3.1
0259:             */
0260:            private static final int TAB_INDEX_MODIFY = 1;
0261:
0262:            /**
0263:             * The translated names for the columns when they are not the primary sort
0264:             * key (e.g., "Category").
0265:             */
0266:            private static final String[] UNSORTED_COLUMN_NAMES = new String[VIEW_TOTAL_COLUMNS];
0267:
0268:            /**
0269:             * The index of the column on the view tab containing the category name.
0270:             */
0271:            private static final int VIEW_CATEGORY_COLUMN_INDEX = 0;
0272:
0273:            /**
0274:             * The index of the column on the view tab containing the command name.
0275:             */
0276:            private static final int VIEW_COMMAND_COLUMN_INDEX = 1;
0277:
0278:            /**
0279:             * The index of the column on the view tab containing the context name.
0280:             */
0281:            private static final int VIEW_CONTEXT_COLUMN_INDEX = 3;
0282:
0283:            /**
0284:             * The index of the column on the view tab containing the key sequence.
0285:             */
0286:            private static final int VIEW_KEY_SEQUENCE_COLUMN_INDEX = 2;
0287:
0288:            static {
0289:                UNSORTED_COLUMN_NAMES[VIEW_CATEGORY_COLUMN_INDEX] = Util
0290:                        .translateString(RESOURCE_BUNDLE, "tableColumnCategory"); //$NON-NLS-1$
0291:                UNSORTED_COLUMN_NAMES[VIEW_COMMAND_COLUMN_INDEX] = Util
0292:                        .translateString(RESOURCE_BUNDLE, "tableColumnCommand"); //$NON-NLS-1$
0293:                UNSORTED_COLUMN_NAMES[VIEW_KEY_SEQUENCE_COLUMN_INDEX] = Util
0294:                        .translateString(RESOURCE_BUNDLE,
0295:                                "tableColumnKeySequence"); //$NON-NLS-1$
0296:                UNSORTED_COLUMN_NAMES[VIEW_CONTEXT_COLUMN_INDEX] = Util
0297:                        .translateString(RESOURCE_BUNDLE, "tableColumnContext"); //$NON-NLS-1$
0298:
0299:                SORTED_COLUMN_NAMES[VIEW_CATEGORY_COLUMN_INDEX] = Util
0300:                        .translateString(RESOURCE_BUNDLE,
0301:                                "tableColumnCategorySorted"); //$NON-NLS-1$
0302:                SORTED_COLUMN_NAMES[VIEW_COMMAND_COLUMN_INDEX] = Util
0303:                        .translateString(RESOURCE_BUNDLE,
0304:                                "tableColumnCommandSorted"); //$NON-NLS-1$
0305:                SORTED_COLUMN_NAMES[VIEW_KEY_SEQUENCE_COLUMN_INDEX] = Util
0306:                        .translateString(RESOURCE_BUNDLE,
0307:                                "tableColumnKeySequenceSorted"); //$NON-NLS-1$
0308:                SORTED_COLUMN_NAMES[VIEW_CONTEXT_COLUMN_INDEX] = Util
0309:                        .translateString(RESOURCE_BUNDLE,
0310:                                "tableColumnContextSorted"); //$NON-NLS-1$
0311:            }
0312:
0313:            /**
0314:             * The workbench's activity manager. This activity manager is used to see if
0315:             * certain commands should be filtered from the user interface.
0316:             */
0317:            private IActivityManager activityManager;
0318:
0319:            /**
0320:             * The workbench's binding service. This binding service is used to access
0321:             * the current set of bindings, and to persist changes.
0322:             */
0323:            private IBindingService bindingService;
0324:
0325:            /**
0326:             * The add button located on the bottom left of the preference page. This
0327:             * button adds the current trigger sequence to the currently selected
0328:             * command.
0329:             */
0330:            private Button buttonAdd;
0331:
0332:            /**
0333:             * The remove button located on the bottom left of the preference page. This
0334:             * button removes the current trigger sequence from the current command.
0335:             */
0336:            private Button buttonRemove;
0337:
0338:            /**
0339:             * The restore button located on the bottom left of the preference page.
0340:             * This button attempts to restore the currently trigger sequence to its
0341:             * initial (i.e., Binding.SYSTEM) state -- undoing all user modifications.
0342:             */
0343:            private Button buttonRestore;
0344:
0345:            /**
0346:             * A map of all the category identifiers indexed by the names that appear in
0347:             * the user interface. This look-up table is built during initialization.
0348:             */
0349:            private Map categoryIdsByUniqueName;
0350:
0351:            /**
0352:             * A map of all the category names in the user interface indexed by their
0353:             * identifiers. This look-up table is built during initialization.
0354:             */
0355:            private Map categoryUniqueNamesById;
0356:
0357:            /**
0358:             * The combo box containing the list of all categories for commands.
0359:             */
0360:            private Combo comboCategory;
0361:
0362:            /**
0363:             * The combo box containing the list of commands relevent for the currently
0364:             * selected category.
0365:             */
0366:            private Combo comboCommand;
0367:
0368:            /**
0369:             * The combo box containing the list of contexts in the system.
0370:             */
0371:            private Combo comboContext;
0372:
0373:            /**
0374:             * The combo box containing the list of schemes in the system.
0375:             */
0376:            private Combo comboScheme;
0377:
0378:            /**
0379:             * A map of all the command identifiers indexed by the categories to which
0380:             * they belong. This look-up table is built during initialization.
0381:             */
0382:            private Map commandIdsByCategoryId;
0383:
0384:            /**
0385:             * The parameterized commands corresponding to the current contents of
0386:             * <code>comboCommand</code>. The commands in this array are in the same
0387:             * order as in the combo. This value can be <code>null</code> if nothing
0388:             * is selected in the combo.
0389:             */
0390:            private ParameterizedCommand[] commands = null;
0391:
0392:            /**
0393:             * The workbench's command service. This command service is used to access
0394:             * the list of commands.
0395:             */
0396:            private ICommandService commandService;
0397:
0398:            /**
0399:             * A map of all the context identifiers indexed by the names that appear in
0400:             * the user interface. This look-up table is built during initialization.
0401:             */
0402:            private Map contextIdsByUniqueName;
0403:
0404:            /**
0405:             * The workbench's context service. This context service is used to access
0406:             * the list of contexts.
0407:             */
0408:            private IContextService contextService;
0409:
0410:            /**
0411:             * A map of all the category names in the user interface indexed by their
0412:             * identifiers. This look-up table is built during initialization.
0413:             */
0414:            private Map contextUniqueNamesById;
0415:
0416:            /**
0417:             * The workbench's help system. This is used to register the page with the
0418:             * help system.
0419:             * 
0420:             * TODO Add a help context
0421:             */
0422:            // private IWorkbenchHelpSystem helpSystem;
0423:            /**
0424:             * This is the label next to the table showing the bindings matching a
0425:             * particular command. The label is disabled if there isn't a selected
0426:             * command identifier.
0427:             */
0428:            private Label labelBindingsForCommand;
0429:
0430:            /**
0431:             * This is the label next to the table showing the bindings matching a
0432:             * particular trigger sequence. The label is disabled if there isn't a
0433:             * current key sequence.
0434:             */
0435:            private Label labelBindingsForTriggerSequence;
0436:
0437:            /**
0438:             * The label next to the context combo box. This label indicates whether the
0439:             * context is a child of another context. If the current context is not a
0440:             * child, then this label is blank.
0441:             */
0442:            private Label labelContextExtends;
0443:
0444:            /**
0445:             * The label next to the scheme combo box. This label indicates whether the
0446:             * scheme is a child of another scheme. If the current scheme is not a
0447:             * child, then this label is blank.
0448:             */
0449:            private Label labelSchemeExtends;
0450:
0451:            /**
0452:             * A binding manager local to this preference page. When the page is
0453:             * initialized, the current bindings are read out from the binding service
0454:             * and placed in this manager. This manager is then updated as the user
0455:             * makes changes. When the user has finished, the contents of this manager
0456:             * are compared with the contents of the binding service. The changes are
0457:             * then persisted.
0458:             */
0459:            private final BindingManager localChangeManager = new BindingManager(
0460:                    new ContextManager(), new CommandManager());
0461:
0462:            /**
0463:             * A map of all the scheme identifiers indexed by the names that appear in
0464:             * the user interface. This look-up table is built during initialization.
0465:             */
0466:            private Map schemeIdsByUniqueName;
0467:
0468:            /**
0469:             * A map of all the scheme names in the user interface indexed by their
0470:             * identifiers. This look-up table is built during initialization.
0471:             */
0472:            private Map schemeUniqueNamesById;
0473:
0474:            /**
0475:             * The sort order to be used on the view tab to display all of the key
0476:             * bindings. This sort order can be changed by the user. This array is never
0477:             * <code>null</code>, but may be empty.
0478:             */
0479:            private int[] sortOrder = { VIEW_CATEGORY_COLUMN_INDEX,
0480:                    VIEW_COMMAND_COLUMN_INDEX, VIEW_KEY_SEQUENCE_COLUMN_INDEX,
0481:                    VIEW_CONTEXT_COLUMN_INDEX };
0482:
0483:            /**
0484:             * The top-most tab folder for the preference page -- containing a view and
0485:             * a modify tab.
0486:             */
0487:            private TabFolder tabFolder;
0488:
0489:            /**
0490:             * A table of the key bindings currently defined. This table appears on the
0491:             * view tab; it is intended to be an easy way for users to learn the key
0492:             * bindings in Eclipse. This value is only <code>null</code> until the
0493:             * controls are first created.
0494:             */
0495:            private Table tableBindings;
0496:
0497:            /**
0498:             * The table containing all of the bindings matching the selected command.
0499:             */
0500:            private Table tableBindingsForCommand;
0501:
0502:            /**
0503:             * The table containing all of the bindings matching the current trigger
0504:             * sequence.
0505:             */
0506:            private Table tableBindingsForTriggerSequence;
0507:
0508:            /**
0509:             * The text widget where keys are entered. This widget is managed by
0510:             * <code>textTriggerSequenceManager</code>, which provides its special
0511:             * behaviour.
0512:             */
0513:            private Text textTriggerSequence;
0514:
0515:            /**
0516:             * The manager for the text widget that traps incoming key events. This
0517:             * manager should be used to access the widget, rather than accessing the
0518:             * widget directly.
0519:             */
0520:            private KeySequenceText textTriggerSequenceManager;
0521:
0522:            /* (non-Javadoc)
0523:             * @see org.eclipse.jface.preference.PreferencePage#applyData(java.lang.Object)
0524:             */
0525:            public void applyData(Object data) {
0526:                if (data instanceof  Binding) {
0527:                    editBinding((Binding) data);
0528:                }
0529:            }
0530:
0531:            protected final Control createContents(final Composite parent) {
0532:
0533:                PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
0534:                        IWorkbenchHelpContextIds.KEYS_PREFERENCE_PAGE);
0535:
0536:                tabFolder = new TabFolder(parent, SWT.NULL);
0537:
0538:                // View tab
0539:                final TabItem viewTab = new TabItem(tabFolder, SWT.NULL);
0540:                viewTab.setText(Util.translateString(RESOURCE_BUNDLE,
0541:                        "viewTab.Text")); //$NON-NLS-1$
0542:                viewTab.setControl(createViewTab(tabFolder));
0543:
0544:                // Modify tab
0545:                final TabItem modifyTab = new TabItem(tabFolder, SWT.NULL);
0546:                modifyTab.setText(Util.translateString(RESOURCE_BUNDLE,
0547:                        "modifyTab.Text")); //$NON-NLS-1$
0548:                modifyTab.setControl(createModifyTab(tabFolder));
0549:
0550:                // Do some fancy stuff.
0551:                applyDialogFont(tabFolder);
0552:                final IPreferenceStore store = getPreferenceStore();
0553:                final int selectedTab = store
0554:                        .getInt(IPreferenceConstants.KEYS_PREFERENCE_SELECTED_TAB);
0555:                if ((tabFolder.getItemCount() > selectedTab)
0556:                        && (selectedTab > 0)) {
0557:                    tabFolder.setSelection(selectedTab);
0558:                }
0559:
0560:                return tabFolder;
0561:            }
0562:
0563:            /**
0564:             * Creates the tab that allows the user to change the keyboard shortcuts.
0565:             * 
0566:             * @param parent
0567:             *            The tab folder in which the tab should be created; must not be
0568:             *            <code>null</code>.
0569:             * @return The composite which represents the contents of the tab; never
0570:             *         <code>null</code>.
0571:             */
0572:            private final Composite createModifyTab(final TabFolder parent) {
0573:                final Composite composite = new Composite(parent, SWT.NULL);
0574:                composite.setLayout(new GridLayout());
0575:                GridData gridData = new GridData(GridData.FILL_BOTH);
0576:                composite.setLayoutData(gridData);
0577:                final Composite compositeKeyConfiguration = new Composite(
0578:                        composite, SWT.NULL);
0579:                GridLayout gridLayout = new GridLayout();
0580:                gridLayout.numColumns = 3;
0581:                compositeKeyConfiguration.setLayout(gridLayout);
0582:                gridData = new GridData(GridData.FILL_HORIZONTAL);
0583:                compositeKeyConfiguration.setLayoutData(gridData);
0584:                final Label labelKeyConfiguration = new Label(
0585:                        compositeKeyConfiguration, SWT.LEFT);
0586:                labelKeyConfiguration.setText(Util.translateString(
0587:                        RESOURCE_BUNDLE, "labelScheme")); //$NON-NLS-1$
0588:                comboScheme = new Combo(compositeKeyConfiguration,
0589:                        SWT.READ_ONLY);
0590:                gridData = new GridData();
0591:                gridData.widthHint = 200;
0592:                comboScheme.setLayoutData(gridData);
0593:                comboScheme.setVisibleItemCount(ITEMS_TO_SHOW);
0594:
0595:                comboScheme.addSelectionListener(new SelectionAdapter() {
0596:                    public final void widgetSelected(final SelectionEvent e) {
0597:                        selectedComboScheme();
0598:                    }
0599:                });
0600:
0601:                labelSchemeExtends = new Label(compositeKeyConfiguration,
0602:                        SWT.LEFT);
0603:                gridData = new GridData(GridData.FILL_HORIZONTAL);
0604:                labelSchemeExtends.setLayoutData(gridData);
0605:                final Control spacer = new Composite(composite, SWT.NULL);
0606:                gridData = new GridData();
0607:                gridData.heightHint = 10;
0608:                gridData.widthHint = 10;
0609:                spacer.setLayoutData(gridData);
0610:                final Group groupCommand = new Group(composite, SWT.SHADOW_NONE);
0611:                gridLayout = new GridLayout();
0612:                gridLayout.numColumns = 3;
0613:                groupCommand.setLayout(gridLayout);
0614:                gridData = new GridData(GridData.FILL_BOTH);
0615:                groupCommand.setLayoutData(gridData);
0616:                groupCommand.setText(Util.translateString(RESOURCE_BUNDLE,
0617:                        "groupCommand")); //$NON-NLS-1$	
0618:                final Label labelCategory = new Label(groupCommand, SWT.LEFT);
0619:                gridData = new GridData();
0620:                labelCategory.setLayoutData(gridData);
0621:                labelCategory.setText(Util.translateString(RESOURCE_BUNDLE,
0622:                        "labelCategory")); //$NON-NLS-1$
0623:                comboCategory = new Combo(groupCommand, SWT.READ_ONLY);
0624:                gridData = new GridData();
0625:                gridData.horizontalSpan = 2;
0626:                gridData.widthHint = 200;
0627:                comboCategory.setLayoutData(gridData);
0628:                comboCategory.setVisibleItemCount(ITEMS_TO_SHOW);
0629:
0630:                comboCategory.addSelectionListener(new SelectionAdapter() {
0631:                    public final void widgetSelected(final SelectionEvent e) {
0632:                        update();
0633:                    }
0634:                });
0635:
0636:                final Label labelCommand = new Label(groupCommand, SWT.LEFT);
0637:                gridData = new GridData();
0638:                labelCommand.setLayoutData(gridData);
0639:                labelCommand.setText(Util.translateString(RESOURCE_BUNDLE,
0640:                        "labelCommand")); //$NON-NLS-1$
0641:                comboCommand = new Combo(groupCommand, SWT.READ_ONLY);
0642:                gridData = new GridData();
0643:                gridData.horizontalSpan = 2;
0644:                gridData.widthHint = 300;
0645:                comboCommand.setLayoutData(gridData);
0646:                comboCommand.setVisibleItemCount(9);
0647:
0648:                comboCommand.addSelectionListener(new SelectionAdapter() {
0649:                    public final void widgetSelected(final SelectionEvent e) {
0650:                        update();
0651:                    }
0652:                });
0653:
0654:                labelBindingsForCommand = new Label(groupCommand, SWT.LEFT);
0655:                gridData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
0656:                gridData.verticalAlignment = GridData.FILL_VERTICAL;
0657:                labelBindingsForCommand.setLayoutData(gridData);
0658:                labelBindingsForCommand.setText(Util.translateString(
0659:                        RESOURCE_BUNDLE, "labelAssignmentsForCommand")); //$NON-NLS-1$
0660:                tableBindingsForCommand = new Table(groupCommand, SWT.BORDER
0661:                        | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL);
0662:                tableBindingsForCommand.setHeaderVisible(true);
0663:                gridData = new GridData(GridData.FILL_BOTH);
0664:                gridData.heightHint = 60;
0665:                gridData.horizontalSpan = 2;
0666:                gridData.widthHint = "carbon".equals(SWT.getPlatform()) ? 620 : 520; //$NON-NLS-1$
0667:                tableBindingsForCommand.setLayoutData(gridData);
0668:                TableColumn tableColumnDelta = new TableColumn(
0669:                        tableBindingsForCommand, SWT.NULL, 0);
0670:                tableColumnDelta.setResizable(false);
0671:                tableColumnDelta.setText(Util.ZERO_LENGTH_STRING);
0672:                tableColumnDelta.setWidth(20);
0673:                TableColumn tableColumnContext = new TableColumn(
0674:                        tableBindingsForCommand, SWT.NULL, 1);
0675:                tableColumnContext.setResizable(true);
0676:                tableColumnContext.setText(Util.translateString(
0677:                        RESOURCE_BUNDLE, "tableColumnContext")); //$NON-NLS-1$
0678:                tableColumnContext.pack();
0679:                tableColumnContext.setWidth(200);
0680:                final TableColumn tableColumnKeySequence = new TableColumn(
0681:                        tableBindingsForCommand, SWT.NULL, 2);
0682:                tableColumnKeySequence.setResizable(true);
0683:                tableColumnKeySequence.setText(Util.translateString(
0684:                        RESOURCE_BUNDLE, "tableColumnKeySequence")); //$NON-NLS-1$
0685:                tableColumnKeySequence.pack();
0686:                tableColumnKeySequence.setWidth(300);
0687:
0688:                tableBindingsForCommand.addMouseListener(new MouseAdapter() {
0689:
0690:                    public void mouseDoubleClick(MouseEvent mouseEvent) {
0691:                        update();
0692:                    }
0693:                });
0694:
0695:                tableBindingsForCommand
0696:                        .addSelectionListener(new SelectionAdapter() {
0697:
0698:                            public void widgetSelected(
0699:                                    SelectionEvent selectionEvent) {
0700:                                selectedTableBindingsForCommand();
0701:                            }
0702:                        });
0703:
0704:                final Group groupKeySequence = new Group(composite,
0705:                        SWT.SHADOW_NONE);
0706:                gridLayout = new GridLayout();
0707:                gridLayout.numColumns = 4;
0708:                groupKeySequence.setLayout(gridLayout);
0709:                gridData = new GridData(GridData.FILL_BOTH);
0710:                groupKeySequence.setLayoutData(gridData);
0711:                groupKeySequence.setText(Util.translateString(RESOURCE_BUNDLE,
0712:                        "groupKeySequence")); //$NON-NLS-1$	
0713:                final Label labelKeySequence = new Label(groupKeySequence,
0714:                        SWT.LEFT);
0715:                gridData = new GridData();
0716:                labelKeySequence.setLayoutData(gridData);
0717:                labelKeySequence.setText(Util.translateString(RESOURCE_BUNDLE,
0718:                        "labelKeySequence")); //$NON-NLS-1$
0719:
0720:                // The text widget into which the key strokes will be entered.
0721:                textTriggerSequence = new Text(groupKeySequence, SWT.BORDER);
0722:                // On MacOS X, this font will be changed by KeySequenceText
0723:                textTriggerSequence.setFont(groupKeySequence.getFont());
0724:                gridData = new GridData();
0725:                gridData.horizontalSpan = 2;
0726:                gridData.widthHint = 300;
0727:                textTriggerSequence.setLayoutData(gridData);
0728:                textTriggerSequence.addModifyListener(new ModifyListener() {
0729:                    public void modifyText(ModifyEvent e) {
0730:                        update();
0731:                    }
0732:                });
0733:                textTriggerSequence.addFocusListener(new FocusListener() {
0734:                    public void focusGained(FocusEvent e) {
0735:                        bindingService.setKeyFilterEnabled(false);
0736:                    }
0737:
0738:                    public void focusLost(FocusEvent e) {
0739:                        bindingService.setKeyFilterEnabled(true);
0740:                    }
0741:                });
0742:                textTriggerSequence.addDisposeListener(new DisposeListener() {
0743:                    public void widgetDisposed(DisposeEvent e) {
0744:                        if (!bindingService.isKeyFilterEnabled()) {
0745:                            bindingService.setKeyFilterEnabled(true);
0746:                        }
0747:                    }
0748:                });
0749:
0750:                // The manager for the key sequence text widget.
0751:                textTriggerSequenceManager = new KeySequenceText(
0752:                        textTriggerSequence);
0753:                textTriggerSequenceManager.setKeyStrokeLimit(4);
0754:
0755:                // Button for adding trapped key strokes
0756:                final Button buttonAddKey = new Button(groupKeySequence,
0757:                        SWT.LEFT | SWT.ARROW);
0758:                buttonAddKey.setToolTipText(Util.translateString(
0759:                        RESOURCE_BUNDLE, "buttonAddKey.ToolTipText")); //$NON-NLS-1$
0760:                gridData = new GridData();
0761:                gridData.heightHint = comboCategory.getTextHeight();
0762:                buttonAddKey.setLayoutData(gridData);
0763:
0764:                // Arrow buttons aren't normally added to the tab list. Let's fix that.
0765:                final Control[] tabStops = groupKeySequence.getTabList();
0766:                final ArrayList newTabStops = new ArrayList();
0767:                for (int i = 0; i < tabStops.length; i++) {
0768:                    Control tabStop = tabStops[i];
0769:                    newTabStops.add(tabStop);
0770:                    if (textTriggerSequence.equals(tabStop)) {
0771:                        newTabStops.add(buttonAddKey);
0772:                    }
0773:                }
0774:                final Control[] newTabStopArray = (Control[]) newTabStops
0775:                        .toArray(new Control[newTabStops.size()]);
0776:                groupKeySequence.setTabList(newTabStopArray);
0777:
0778:                // Construct the menu to attach to the above button.
0779:                final Menu menuButtonAddKey = new Menu(buttonAddKey);
0780:                final Iterator trappedKeyItr = KeySequenceText.TRAPPED_KEYS
0781:                        .iterator();
0782:                while (trappedKeyItr.hasNext()) {
0783:                    final KeyStroke trappedKey = (KeyStroke) trappedKeyItr
0784:                            .next();
0785:                    final MenuItem menuItem = new MenuItem(menuButtonAddKey,
0786:                            SWT.PUSH);
0787:                    menuItem.setText(trappedKey.format());
0788:                    menuItem.addSelectionListener(new SelectionAdapter() {
0789:
0790:                        public void widgetSelected(SelectionEvent e) {
0791:                            textTriggerSequenceManager.insert(trappedKey);
0792:                            textTriggerSequence.setFocus();
0793:                            textTriggerSequence
0794:                                    .setSelection(textTriggerSequence
0795:                                            .getTextLimit());
0796:                        }
0797:                    });
0798:                }
0799:                buttonAddKey.addSelectionListener(new SelectionAdapter() {
0800:
0801:                    public void widgetSelected(SelectionEvent selectionEvent) {
0802:                        Point buttonLocation = buttonAddKey.getLocation();
0803:                        buttonLocation = groupKeySequence.toDisplay(
0804:                                buttonLocation.x, buttonLocation.y);
0805:                        Point buttonSize = buttonAddKey.getSize();
0806:                        menuButtonAddKey.setLocation(buttonLocation.x,
0807:                                buttonLocation.y + buttonSize.y);
0808:                        menuButtonAddKey.setVisible(true);
0809:                    }
0810:                });
0811:
0812:                labelBindingsForTriggerSequence = new Label(groupKeySequence,
0813:                        SWT.LEFT);
0814:                gridData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
0815:                gridData.verticalAlignment = GridData.FILL_VERTICAL;
0816:                labelBindingsForTriggerSequence.setLayoutData(gridData);
0817:                labelBindingsForTriggerSequence.setText(Util.translateString(
0818:                        RESOURCE_BUNDLE, "labelAssignmentsForKeySequence")); //$NON-NLS-1$
0819:                tableBindingsForTriggerSequence = new Table(groupKeySequence,
0820:                        SWT.BORDER | SWT.FULL_SELECTION | SWT.H_SCROLL
0821:                                | SWT.V_SCROLL);
0822:                tableBindingsForTriggerSequence.setHeaderVisible(true);
0823:                gridData = new GridData(GridData.FILL_BOTH);
0824:                gridData.heightHint = 60;
0825:                gridData.horizontalSpan = 3;
0826:                gridData.widthHint = "carbon".equals(SWT.getPlatform()) ? 620 : 520; //$NON-NLS-1$
0827:                tableBindingsForTriggerSequence.setLayoutData(gridData);
0828:                tableColumnDelta = new TableColumn(
0829:                        tableBindingsForTriggerSequence, SWT.NULL, 0);
0830:                tableColumnDelta.setResizable(false);
0831:                tableColumnDelta.setText(Util.ZERO_LENGTH_STRING);
0832:                tableColumnDelta.setWidth(20);
0833:                tableColumnContext = new TableColumn(
0834:                        tableBindingsForTriggerSequence, SWT.NULL, 1);
0835:                tableColumnContext.setResizable(true);
0836:                tableColumnContext.setText(Util.translateString(
0837:                        RESOURCE_BUNDLE, "tableColumnContext")); //$NON-NLS-1$
0838:                tableColumnContext.pack();
0839:                tableColumnContext.setWidth(200);
0840:                final TableColumn tableColumnCommand = new TableColumn(
0841:                        tableBindingsForTriggerSequence, SWT.NULL, 2);
0842:                tableColumnCommand.setResizable(true);
0843:                tableColumnCommand.setText(Util.translateString(
0844:                        RESOURCE_BUNDLE, "tableColumnCommand")); //$NON-NLS-1$
0845:                tableColumnCommand.pack();
0846:                tableColumnCommand.setWidth(300);
0847:
0848:                tableBindingsForTriggerSequence
0849:                        .addMouseListener(new MouseAdapter() {
0850:
0851:                            public void mouseDoubleClick(MouseEvent mouseEvent) {
0852:                                update();
0853:                            }
0854:                        });
0855:
0856:                tableBindingsForTriggerSequence
0857:                        .addSelectionListener(new SelectionAdapter() {
0858:
0859:                            public void widgetSelected(
0860:                                    SelectionEvent selectionEvent) {
0861:                                selectedTableBindingsForTriggerSequence();
0862:                            }
0863:                        });
0864:
0865:                final Composite compositeContext = new Composite(composite,
0866:                        SWT.NULL);
0867:                gridLayout = new GridLayout();
0868:                gridLayout.numColumns = 3;
0869:                compositeContext.setLayout(gridLayout);
0870:                gridData = new GridData(GridData.FILL_HORIZONTAL);
0871:                compositeContext.setLayoutData(gridData);
0872:                final Label labelContext = new Label(compositeContext, SWT.LEFT);
0873:                labelContext.setText(Util.translateString(RESOURCE_BUNDLE,
0874:                        "labelContext")); //$NON-NLS-1$
0875:                comboContext = new Combo(compositeContext, SWT.READ_ONLY);
0876:                gridData = new GridData();
0877:                gridData.widthHint = 250;
0878:                comboContext.setLayoutData(gridData);
0879:                comboContext.setVisibleItemCount(ITEMS_TO_SHOW);
0880:
0881:                comboContext.addSelectionListener(new SelectionAdapter() {
0882:                    public final void widgetSelected(final SelectionEvent e) {
0883:                        update();
0884:                    }
0885:                });
0886:
0887:                labelContextExtends = new Label(compositeContext, SWT.LEFT);
0888:                gridData = new GridData(GridData.FILL_HORIZONTAL);
0889:                labelContextExtends.setLayoutData(gridData);
0890:                final Composite compositeButton = new Composite(composite,
0891:                        SWT.NULL);
0892:                gridLayout = new GridLayout();
0893:                gridLayout.marginHeight = 20;
0894:                gridLayout.marginWidth = 0;
0895:                gridLayout.numColumns = 3;
0896:                compositeButton.setLayout(gridLayout);
0897:                gridData = new GridData();
0898:                compositeButton.setLayoutData(gridData);
0899:                buttonAdd = new Button(compositeButton, SWT.CENTER | SWT.PUSH);
0900:                gridData = new GridData();
0901:                int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
0902:                buttonAdd.setText(Util.translateString(RESOURCE_BUNDLE,
0903:                        "buttonAdd")); //$NON-NLS-1$
0904:                gridData.widthHint = Math.max(widthHint, buttonAdd.computeSize(
0905:                        SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
0906:                buttonAdd.setLayoutData(gridData);
0907:
0908:                buttonAdd.addSelectionListener(new SelectionAdapter() {
0909:
0910:                    public void widgetSelected(SelectionEvent selectionEvent) {
0911:                        selectedButtonAdd();
0912:                    }
0913:                });
0914:
0915:                buttonRemove = new Button(compositeButton, SWT.CENTER
0916:                        | SWT.PUSH);
0917:                gridData = new GridData();
0918:                widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
0919:                buttonRemove.setText(Util.translateString(RESOURCE_BUNDLE,
0920:                        "buttonRemove")); //$NON-NLS-1$
0921:                gridData.widthHint = Math.max(widthHint, buttonRemove
0922:                        .computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
0923:                buttonRemove.setLayoutData(gridData);
0924:
0925:                buttonRemove.addSelectionListener(new SelectionAdapter() {
0926:
0927:                    public void widgetSelected(SelectionEvent selectionEvent) {
0928:                        selectedButtonRemove();
0929:                    }
0930:                });
0931:
0932:                buttonRestore = new Button(compositeButton, SWT.CENTER
0933:                        | SWT.PUSH);
0934:                gridData = new GridData();
0935:                widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
0936:                buttonRestore.setText(Util.translateString(RESOURCE_BUNDLE,
0937:                        "buttonRestore")); //$NON-NLS-1$
0938:                gridData.widthHint = Math.max(widthHint, buttonRestore
0939:                        .computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
0940:                buttonRestore.setLayoutData(gridData);
0941:
0942:                buttonRestore.addSelectionListener(new SelectionAdapter() {
0943:
0944:                    public void widgetSelected(SelectionEvent selectionEvent) {
0945:                        selectedButtonRestore();
0946:                    }
0947:                });
0948:
0949:                return composite;
0950:            }
0951:
0952:            /**
0953:             * Creates a tab on the main page for displaying an uneditable list of the
0954:             * current key bindings. This is intended as a discovery tool for new users.
0955:             * It shows all of the key bindings for the current key configuration,
0956:             * platform and locale.
0957:             * 
0958:             * @param parent
0959:             *            The tab folder in which the tab should be created; must not be
0960:             *            <code>null</code>.
0961:             * @return The newly created composite containing all of the controls; never
0962:             *         <code>null</code>.
0963:             * @since 3.1
0964:             */
0965:            private final Composite createViewTab(final TabFolder parent) {
0966:                GridData gridData = null;
0967:                int widthHint;
0968:
0969:                // Create the composite for the tab.
0970:                final Composite composite = new Composite(parent, SWT.NONE);
0971:                composite.setLayoutData(new GridData(GridData.FILL_BOTH));
0972:                composite.setLayout(new GridLayout());
0973:
0974:                // Place a table inside the tab.
0975:                tableBindings = new Table(composite, SWT.BORDER
0976:                        | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL);
0977:                tableBindings.setHeaderVisible(true);
0978:                gridData = new GridData(GridData.FILL_BOTH);
0979:                gridData.heightHint = 400;
0980:                gridData.horizontalSpan = 2;
0981:                tableBindings.setLayoutData(gridData);
0982:                final TableColumn tableColumnCategory = new TableColumn(
0983:                        tableBindings, SWT.NONE, VIEW_CATEGORY_COLUMN_INDEX);
0984:                tableColumnCategory
0985:                        .setText(SORTED_COLUMN_NAMES[VIEW_CATEGORY_COLUMN_INDEX]);
0986:                tableColumnCategory
0987:                        .addSelectionListener(new SortOrderSelectionListener(
0988:                                VIEW_CATEGORY_COLUMN_INDEX));
0989:                final TableColumn tableColumnCommand = new TableColumn(
0990:                        tableBindings, SWT.NONE, VIEW_COMMAND_COLUMN_INDEX);
0991:                tableColumnCommand
0992:                        .setText(UNSORTED_COLUMN_NAMES[VIEW_COMMAND_COLUMN_INDEX]);
0993:                tableColumnCommand
0994:                        .addSelectionListener(new SortOrderSelectionListener(
0995:                                VIEW_COMMAND_COLUMN_INDEX));
0996:                final TableColumn tableColumnKeySequence = new TableColumn(
0997:                        tableBindings, SWT.NONE, VIEW_KEY_SEQUENCE_COLUMN_INDEX);
0998:                tableColumnKeySequence
0999:                        .setText(UNSORTED_COLUMN_NAMES[VIEW_KEY_SEQUENCE_COLUMN_INDEX]);
1000:                tableColumnKeySequence
1001:                        .addSelectionListener(new SortOrderSelectionListener(
1002:                                VIEW_KEY_SEQUENCE_COLUMN_INDEX));
1003:                final TableColumn tableColumnContext = new TableColumn(
1004:                        tableBindings, SWT.NONE, VIEW_CONTEXT_COLUMN_INDEX);
1005:                tableColumnContext
1006:                        .setText(UNSORTED_COLUMN_NAMES[VIEW_CONTEXT_COLUMN_INDEX]);
1007:                tableColumnContext
1008:                        .addSelectionListener(new SortOrderSelectionListener(
1009:                                VIEW_CONTEXT_COLUMN_INDEX));
1010:                tableBindings.addSelectionListener(new SelectionAdapter() {
1011:                    public final void widgetDefaultSelected(
1012:                            final SelectionEvent e) {
1013:                        selectedTableKeyBindings();
1014:                    }
1015:                });
1016:
1017:                // A composite for the buttons.
1018:                final Composite buttonBar = new Composite(composite, SWT.NONE);
1019:                buttonBar.setLayout(new GridLayout(2, false));
1020:                gridData = new GridData();
1021:                gridData.horizontalAlignment = GridData.END;
1022:                buttonBar.setLayoutData(gridData);
1023:
1024:                // A button for editing the current selection.
1025:                final Button editButton = new Button(buttonBar, SWT.PUSH);
1026:                gridData = new GridData();
1027:                widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
1028:                editButton.setText(Util.translateString(RESOURCE_BUNDLE,
1029:                        "buttonEdit")); //$NON-NLS-1$
1030:                gridData.widthHint = Math.max(widthHint, editButton
1031:                        .computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
1032:                editButton.setLayoutData(gridData);
1033:                editButton.addSelectionListener(new SelectionListener() {
1034:
1035:                    /*
1036:                     * (non-Javadoc)
1037:                     * 
1038:                     * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
1039:                     */
1040:                    public final void widgetDefaultSelected(
1041:                            final SelectionEvent event) {
1042:                        selectedTableKeyBindings();
1043:                    }
1044:
1045:                    /*
1046:                     * (non-Javadoc)
1047:                     * 
1048:                     * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
1049:                     */
1050:                    public void widgetSelected(SelectionEvent e) {
1051:                        widgetDefaultSelected(e);
1052:                    }
1053:                });
1054:
1055:                // A button for exporting the contents to a file.
1056:                final Button buttonExport = new Button(buttonBar, SWT.PUSH);
1057:                gridData = new GridData();
1058:                widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
1059:                buttonExport.setText(Util.translateString(RESOURCE_BUNDLE,
1060:                        "buttonExport")); //$NON-NLS-1$
1061:                gridData.widthHint = Math.max(widthHint, buttonExport
1062:                        .computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
1063:                buttonExport.setLayoutData(gridData);
1064:                buttonExport.addSelectionListener(new SelectionListener() {
1065:
1066:                    /*
1067:                     * (non-Javadoc)
1068:                     * 
1069:                     * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
1070:                     */
1071:                    public final void widgetDefaultSelected(
1072:                            final SelectionEvent event) {
1073:                        selectedButtonExport();
1074:                    }
1075:
1076:                    /*
1077:                     * (non-Javadoc)
1078:                     * 
1079:                     * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
1080:                     */
1081:                    public void widgetSelected(SelectionEvent e) {
1082:                        widgetDefaultSelected(e);
1083:                    }
1084:                });
1085:
1086:                return composite;
1087:            }
1088:
1089:            protected IPreferenceStore doGetPreferenceStore() {
1090:                return PrefUtil.getInternalPreferenceStore();
1091:            }
1092:
1093:            /**
1094:             * Allows the user to change the key bindings for a particular command.
1095:             * Switches the tab to the modify tab, and then selects the category and
1096:             * command that corresponds with the given command name. It then selects the
1097:             * given key sequence and gives focus to the key sequence text widget.
1098:             * 
1099:             * @param binding
1100:             *            The binding to be edited; if <code>null</code>, then just
1101:             *            switch to the modify tab. If the <code>binding</code> does
1102:             *            not correspond to anything in the keys preference page, then
1103:             *            this also just switches to the modify tab.
1104:             * @since 3.1
1105:             */
1106:            public final void editBinding(final Binding binding) {
1107:                // Switch to the modify tab.
1108:                tabFolder.setSelection(TAB_INDEX_MODIFY);
1109:
1110:                // If there is no command name, stop here.
1111:                if (binding == null) {
1112:                    return;
1113:                }
1114:
1115:                /*
1116:                 * Get the corresponding category and command names. If either is
1117:                 * undefined, then we can just stop now. We won't be able to find their
1118:                 * name.
1119:                 */
1120:                final ParameterizedCommand command = binding
1121:                        .getParameterizedCommand();
1122:                String categoryName = null;
1123:                String commandName = null;
1124:                try {
1125:                    categoryName = command.getCommand().getCategory().getName();
1126:                    commandName = command.getName();
1127:                } catch (final NotDefinedException e) {
1128:                    return; // no name
1129:                }
1130:
1131:                // Update the category combo box.
1132:                final String[] categoryNames = comboCategory.getItems();
1133:                int i = 0;
1134:                for (; i < categoryNames.length; i++) {
1135:                    if (categoryName.equals(categoryNames[i])) {
1136:                        break;
1137:                    }
1138:                }
1139:                if (i >= comboCategory.getItemCount()) {
1140:                    // Couldn't find the category, so abort.
1141:                    return;
1142:                }
1143:                comboCategory.select(i);
1144:
1145:                // Update the commands combo box.
1146:                updateComboCommand();
1147:
1148:                // Update the command combo box.
1149:                final String[] commandNames = comboCommand.getItems();
1150:                int j = 0;
1151:                for (; j < commandNames.length; j++) {
1152:                    if (commandName.equals(commandNames[j])) {
1153:                        if (comboCommand.getSelectionIndex() != j) {
1154:                            comboCommand.select(j);
1155:                        }
1156:                        break;
1157:                    }
1158:                }
1159:                if (j >= comboCommand.getItemCount()) {
1160:                    // Couldn't find the command, so just select the first and then stop
1161:                    if (comboCommand.getSelectionIndex() != 0) {
1162:                        comboCommand.select(0);
1163:                    }
1164:                    update();
1165:                    return;
1166:                }
1167:
1168:                /*
1169:                 * Update and validate the state of the modify tab in response to these
1170:                 * selection changes.
1171:                 */
1172:                update();
1173:
1174:                // Select the right key binding, if possible.
1175:                final TableItem[] items = tableBindingsForCommand.getItems();
1176:                int k = 0;
1177:                for (; k < items.length; k++) {
1178:                    final String currentKeySequence = items[k].getText(2);
1179:                    if (binding.getTriggerSequence().format().equals(
1180:                            currentKeySequence)) {
1181:                        break;
1182:                    }
1183:                }
1184:                if (k < tableBindingsForCommand.getItemCount()) {
1185:                    tableBindingsForCommand.select(k);
1186:                    tableBindingsForCommand
1187:                            .notifyListeners(SWT.Selection, null);
1188:                    textTriggerSequence.setFocus();
1189:                }
1190:            }
1191:
1192:            /**
1193:             * Returns the identifier for the currently selected category.
1194:             * 
1195:             * @return The selected category; <code>null</code> if none.
1196:             */
1197:            private final String getCategoryId() {
1198:                return !commandIdsByCategoryId.containsKey(null)
1199:                        || comboCategory.getSelectionIndex() > 0 ? (String) categoryIdsByUniqueName
1200:                        .get(comboCategory.getText())
1201:                        : null;
1202:            }
1203:
1204:            /**
1205:             * Returns the identifier for the currently selected context.
1206:             * 
1207:             * @return The selected context; <code>null</code> if none.
1208:             */
1209:            private final String getContextId() {
1210:                return comboContext.getSelectionIndex() >= 0 ? (String) contextIdsByUniqueName
1211:                        .get(comboContext.getText())
1212:                        : null;
1213:            }
1214:
1215:            /**
1216:             * Returns the current trigger sequence.
1217:             * 
1218:             * @return The trigger sequence; may be empty, but never <code>null</code>.
1219:             */
1220:            private final KeySequence getKeySequence() {
1221:                return textTriggerSequenceManager.getKeySequence();
1222:            }
1223:
1224:            /**
1225:             * Returns the currently-selected fully-parameterized command.
1226:             * 
1227:             * @return The selected fully-parameterized command; <code>null</code> if
1228:             *         none.
1229:             */
1230:            private final ParameterizedCommand getParameterizedCommand() {
1231:                final int selectionIndex = comboCommand.getSelectionIndex();
1232:                if ((selectionIndex >= 0) && (commands != null)
1233:                        && (selectionIndex < commands.length)) {
1234:                    return commands[selectionIndex];
1235:                }
1236:
1237:                return null;
1238:            }
1239:
1240:            /**
1241:             * Returns the identifier for the currently selected scheme.
1242:             * 
1243:             * @return The selected scheme; <code>null</code> if none.
1244:             */
1245:            private final String getSchemeId() {
1246:                return comboScheme.getSelectionIndex() >= 0 ? (String) schemeIdsByUniqueName
1247:                        .get(comboScheme.getText())
1248:                        : null;
1249:            }
1250:
1251:            public final void init(final IWorkbench workbench) {
1252:                activityManager = workbench.getActivitySupport()
1253:                        .getActivityManager();
1254:                bindingService = (IBindingService) workbench
1255:                        .getService(IBindingService.class);
1256:                commandService = (ICommandService) workbench
1257:                        .getService(ICommandService.class);
1258:                contextService = (IContextService) workbench
1259:                        .getService(IContextService.class);
1260:            }
1261:
1262:            /**
1263:             * Checks whether the activity manager knows anything about this command
1264:             * identifier. If the activity manager is currently filtering this command,
1265:             * then it does not appear in the user interface.
1266:             * 
1267:             * @param command
1268:             *            The command which should be checked against the activities;
1269:             *            must not be <code>null</code>.
1270:             * @return <code>true</code> if the command identifier is not filtered;
1271:             *         <code>false</code> if it is
1272:             */
1273:            private final boolean isActive(final Command command) {
1274:                return activityManager.getIdentifier(command.getId())
1275:                        .isEnabled();
1276:            }
1277:
1278:            /**
1279:             * Logs the given exception, and opens an error dialog saying that something
1280:             * went wrong. The exception is assumed to have something to do with the
1281:             * preference store.
1282:             * 
1283:             * @param exception
1284:             *            The exception to be logged; must not be <code>null</code>.
1285:             */
1286:            private final void logPreferenceStoreException(
1287:                    final Throwable exception) {
1288:                final String message = Util.translateString(RESOURCE_BUNDLE,
1289:                        "PreferenceStoreError.Message"); //$NON-NLS-1$
1290:                String exceptionMessage = exception.getMessage();
1291:                if (exceptionMessage == null) {
1292:                    exceptionMessage = message;
1293:                }
1294:                final IStatus status = new Status(IStatus.ERROR,
1295:                        WorkbenchPlugin.PI_WORKBENCH, 0, exceptionMessage,
1296:                        exception);
1297:                WorkbenchPlugin.log(message, status);
1298:                StatusUtil.handleStatus(message, exception, StatusManager.SHOW);
1299:            }
1300:
1301:            public final boolean performCancel() {
1302:                // Save the selected tab for future reference.
1303:                persistSelectedTab();
1304:
1305:                return super .performCancel();
1306:            }
1307:
1308:            protected final void performDefaults() {
1309:                // Ask the user to confirm
1310:                final String title = Util.translateString(RESOURCE_BUNDLE,
1311:                        "restoreDefaultsMessageBoxText"); //$NON-NLS-1$
1312:                final String message = Util.translateString(RESOURCE_BUNDLE,
1313:                        "restoreDefaultsMessageBoxMessage"); //$NON-NLS-1$
1314:                final boolean confirmed = MessageDialog.openConfirm(getShell(),
1315:                        title, message);
1316:
1317:                if (confirmed) {
1318:                    // Fix the scheme in the local changes.
1319:                    final String defaultSchemeId = bindingService
1320:                            .getDefaultSchemeId();
1321:                    final Scheme defaultScheme = localChangeManager
1322:                            .getScheme(defaultSchemeId);
1323:                    try {
1324:                        localChangeManager.setActiveScheme(defaultScheme);
1325:                    } catch (final NotDefinedException e) {
1326:                        // At least we tried....
1327:                    }
1328:
1329:                    // Fix the bindings in the local changes.
1330:                    final Binding[] currentBindings = localChangeManager
1331:                            .getBindings();
1332:                    final int currentBindingsLength = currentBindings.length;
1333:                    final Set trimmedBindings = new HashSet();
1334:                    for (int i = 0; i < currentBindingsLength; i++) {
1335:                        final Binding binding = currentBindings[i];
1336:                        if (binding.getType() != Binding.USER) {
1337:                            trimmedBindings.add(binding);
1338:                        }
1339:                    }
1340:                    final Binding[] trimmedBindingArray = (Binding[]) trimmedBindings
1341:                            .toArray(new Binding[trimmedBindings.size()]);
1342:                    localChangeManager.setBindings(trimmedBindingArray);
1343:
1344:                    // Apply the changes.
1345:                    try {
1346:                        bindingService.savePreferences(defaultScheme,
1347:                                trimmedBindingArray);
1348:                    } catch (final IOException e) {
1349:                        logPreferenceStoreException(e);
1350:                    }
1351:                }
1352:
1353:                setScheme(localChangeManager.getActiveScheme()); // update the scheme
1354:                update(true);
1355:                super .performDefaults();
1356:            }
1357:
1358:            public final boolean performOk() {
1359:                // Save the preferences.
1360:                try {
1361:                    bindingService.savePreferences(localChangeManager
1362:                            .getActiveScheme(), localChangeManager
1363:                            .getBindings());
1364:                } catch (final IOException e) {
1365:                    logPreferenceStoreException(e);
1366:                }
1367:
1368:                // Save the selected tab for future reference.
1369:                persistSelectedTab();
1370:
1371:                return super .performOk();
1372:            }
1373:
1374:            /**
1375:             * Remembers the currently selected tab for when the preference page next
1376:             * opens.
1377:             */
1378:            private final void persistSelectedTab() {
1379:                final IPreferenceStore store = getPreferenceStore();
1380:                store.setValue(
1381:                        IPreferenceConstants.KEYS_PREFERENCE_SELECTED_TAB,
1382:                        tabFolder.getSelectionIndex());
1383:            }
1384:
1385:            /**
1386:             * Handles the selection event on the add button. This removes all
1387:             * user-defined bindings matching the given key sequence, scheme and
1388:             * context. It then adds a new binding with the current selections.
1389:             */
1390:            private final void selectedButtonAdd() {
1391:                final ParameterizedCommand command = getParameterizedCommand();
1392:                final String contextId = getContextId();
1393:                final String schemeId = getSchemeId();
1394:                final KeySequence keySequence = getKeySequence();
1395:                localChangeManager.removeBindings(keySequence, schemeId,
1396:                        contextId, null, null, null, Binding.USER);
1397:                localChangeManager.addBinding(new KeyBinding(keySequence,
1398:                        command, schemeId, contextId, null, null, null,
1399:                        Binding.USER));
1400:                update(true);
1401:            }
1402:
1403:            /**
1404:             * Provides a facility for exporting the viewable list of key bindings to a
1405:             * file. Currently, this only supports exporting to a list of
1406:             * comma-separated values. The user is prompted for which file should
1407:             * receive our bounty.
1408:             * 
1409:             * @since 3.1
1410:             */
1411:            private final void selectedButtonExport() {
1412:                final FileDialog fileDialog = new FileDialog(getShell(),
1413:                        SWT.SAVE);
1414:                fileDialog.setFilterExtensions(new String[] { "*.csv" }); //$NON-NLS-1$
1415:                fileDialog.setFilterNames(new String[] { Util.translateString(
1416:                        RESOURCE_BUNDLE, "csvFilterName") }); //$NON-NLS-1$
1417:                final String filePath = fileDialog.open();
1418:                if (filePath == null) {
1419:                    return;
1420:                }
1421:
1422:                final SafeRunnable runnable = new SafeRunnable() {
1423:                    public final void run() throws IOException {
1424:                        Writer fileWriter = null;
1425:                        try {
1426:                            fileWriter = new BufferedWriter(new FileWriter(
1427:                                    filePath));
1428:                            final TableItem[] items = tableBindings.getItems();
1429:                            final int numColumns = tableBindings
1430:                                    .getColumnCount();
1431:                            for (int i = 0; i < items.length; i++) {
1432:                                final TableItem item = items[i];
1433:                                for (int j = 0; j < numColumns; j++) {
1434:                                    String buf = Util.replaceAll(item
1435:                                            .getText(j), "\"", //$NON-NLS-1$
1436:                                            "\"\""); //$NON-NLS-1$
1437:                                    fileWriter.write("\"" + buf + "\""); //$NON-NLS-1$//$NON-NLS-2$
1438:                                    if (j < numColumns - 1) {
1439:                                        fileWriter.write(',');
1440:                                    }
1441:                                }
1442:                                fileWriter.write(System
1443:                                        .getProperty("line.separator")); //$NON-NLS-1$
1444:                            }
1445:
1446:                        } finally {
1447:                            if (fileWriter != null) {
1448:                                try {
1449:                                    fileWriter.close();
1450:                                } catch (final IOException e) {
1451:                                    // At least I tried.
1452:                                }
1453:                            }
1454:
1455:                        }
1456:                    }
1457:                };
1458:                SafeRunner.run(runnable);
1459:            }
1460:
1461:            /**
1462:             * Handles the selection event on the remove button. This removes all
1463:             * user-defined bindings matching the given key sequence, scheme and
1464:             * context. It then adds a new deletion binding for the selected trigger
1465:             * sequence.
1466:             */
1467:            private final void selectedButtonRemove() {
1468:                final String contextId = getContextId();
1469:                final String schemeId = getSchemeId();
1470:                final KeySequence keySequence = getKeySequence();
1471:                localChangeManager.removeBindings(keySequence, schemeId,
1472:                        contextId, null, null, null, Binding.USER);
1473:                localChangeManager.addBinding(new KeyBinding(keySequence, null,
1474:                        schemeId, contextId, null, null, null, Binding.USER));
1475:                update(true);
1476:            }
1477:
1478:            /**
1479:             * Handles the selection event on the restore button. This removes all
1480:             * user-defined bindings matching the given key sequence, scheme and
1481:             * context.
1482:             */
1483:            private final void selectedButtonRestore() {
1484:                String contextId = getContextId();
1485:                String schemeId = getSchemeId();
1486:                KeySequence keySequence = getKeySequence();
1487:                localChangeManager.removeBindings(keySequence, schemeId,
1488:                        contextId, null, null, null, Binding.USER);
1489:                update(true);
1490:            }
1491:
1492:            /**
1493:             * Updates the local managers active scheme, and then updates the interface.
1494:             */
1495:            private final void selectedComboScheme() {
1496:                final String activeSchemeId = getSchemeId();
1497:                final Scheme activeScheme = localChangeManager
1498:                        .getScheme(activeSchemeId);
1499:                try {
1500:                    localChangeManager.setActiveScheme(activeScheme);
1501:                } catch (final NotDefinedException e) {
1502:                    // Oh, well.
1503:                }
1504:                update(true);
1505:            }
1506:
1507:            /**
1508:             * Handles the selection event on the table containing the bindings for a
1509:             * particular command. This updates the context and trigger sequence based
1510:             * on the selected binding.
1511:             */
1512:            private final void selectedTableBindingsForCommand() {
1513:                final int selection = tableBindingsForCommand
1514:                        .getSelectionIndex();
1515:                if ((selection >= 0)
1516:                        && (selection < tableBindingsForCommand.getItemCount())) {
1517:                    final TableItem item = tableBindingsForCommand
1518:                            .getItem(selection);
1519:                    final KeyBinding binding = (KeyBinding) item
1520:                            .getData(ITEM_DATA_KEY);
1521:                    setContextId(binding.getContextId());
1522:                    setKeySequence(binding.getKeySequence());
1523:                }
1524:
1525:                update();
1526:            }
1527:
1528:            /**
1529:             * Handles the selection event on the table containing the bindings for a
1530:             * particular trigger sequence. This updates the context based on the
1531:             * selected binding.
1532:             */
1533:            private final void selectedTableBindingsForTriggerSequence() {
1534:                final int selection = tableBindingsForTriggerSequence
1535:                        .getSelectionIndex();
1536:                if ((selection >= 0)
1537:                        && (selection < tableBindingsForTriggerSequence
1538:                                .getItemCount())) {
1539:                    final TableItem item = tableBindingsForTriggerSequence
1540:                            .getItem(selection);
1541:                    final Binding binding = (Binding) item
1542:                            .getData(ITEM_DATA_KEY);
1543:                    setContextId(binding.getContextId());
1544:                }
1545:
1546:                update();
1547:            }
1548:
1549:            /**
1550:             * Responds to some kind of trigger on the View tab by taking the current
1551:             * selection on the key bindings table and selecting the appropriate items
1552:             * in the Modify tab.
1553:             * 
1554:             * @since 3.1
1555:             */
1556:            private final void selectedTableKeyBindings() {
1557:                final int selectionIndex = tableBindings.getSelectionIndex();
1558:                if (selectionIndex != -1) {
1559:                    final TableItem item = tableBindings
1560:                            .getItem(selectionIndex);
1561:                    final Binding binding = (Binding) item.getData(BINDING_KEY);
1562:                    editBinding(binding);
1563:
1564:                } else {
1565:                    editBinding(null);
1566:                }
1567:            }
1568:
1569:            /**
1570:             * Changes the selected context name in the context combo box. The context
1571:             * selected is either the one matching the identifier provided (if
1572:             * possible), or the default context identifier. If no matching name can be
1573:             * found in the combo, then the first item is selected.
1574:             * 
1575:             * @param contextId
1576:             *            The context identifier for the context to be selected in the
1577:             *            combo box; may be <code>null</code>.
1578:             */
1579:            private final void setContextId(final String contextId) {
1580:                // Clear the current selection.
1581:                comboContext.clearSelection();
1582:                comboContext.deselectAll();
1583:
1584:                // Figure out which name to look for.
1585:                String contextName = (String) contextUniqueNamesById
1586:                        .get(contextId);
1587:                if (contextName == null) {
1588:                    contextName = (String) contextUniqueNamesById
1589:                            .get(IContextIds.CONTEXT_ID_WINDOW);
1590:                }
1591:                if (contextName == null) {
1592:                    contextName = Util.ZERO_LENGTH_STRING;
1593:                }
1594:
1595:                // Scan the list for the selection we're looking for.
1596:                final String[] items = comboContext.getItems();
1597:                boolean found = false;
1598:                for (int i = 0; i < items.length; i++) {
1599:                    if (contextName.equals(items[i])) {
1600:                        comboContext.select(i);
1601:                        found = true;
1602:                        break;
1603:                    }
1604:                }
1605:
1606:                // If we didn't find an item, then set the first item as selected.
1607:                if ((!found) && (items.length > 0)) {
1608:                    comboContext.select(0);
1609:                }
1610:            }
1611:
1612:            /**
1613:             * Sets the current trigger sequence.
1614:             * 
1615:             * @param keySequence
1616:             *            The trigger sequence; may be <code>null</code>.
1617:             */
1618:            private final void setKeySequence(final KeySequence keySequence) {
1619:                textTriggerSequenceManager.setKeySequence(keySequence);
1620:            }
1621:
1622:            /**
1623:             * Changes the selection in the command combo box.
1624:             * 
1625:             * @param command
1626:             *            The fully-parameterized command to select; may be
1627:             *            <code>null</code>.
1628:             */
1629:            private final void setParameterizedCommand(
1630:                    final ParameterizedCommand command) {
1631:                int i = 0;
1632:                if (commands != null) {
1633:                    final int commandCount = commands.length;
1634:                    for (; i < commandCount; i++) {
1635:                        if (commands[i].equals(command)) {
1636:                            if ((comboCommand.getSelectionIndex() != i)
1637:                                    && (i < comboCommand.getItemCount())) {
1638:                                comboCommand.select(i);
1639:                            }
1640:                            break;
1641:                        }
1642:                    }
1643:                    if ((i >= comboCommand.getItemCount())
1644:                            && (comboCommand.getSelectionIndex() != 0)) {
1645:                        comboCommand.select(0);
1646:                    }
1647:                }
1648:            }
1649:
1650:            /**
1651:             * Sets the currently selected scheme
1652:             * 
1653:             * @param scheme
1654:             *            The scheme to select; may be <code>null</code>.
1655:             */
1656:            private final void setScheme(final Scheme scheme) {
1657:                comboScheme.clearSelection();
1658:                comboScheme.deselectAll();
1659:                final String schemeUniqueName = (String) schemeUniqueNamesById
1660:                        .get(scheme.getId());
1661:
1662:                if (schemeUniqueName != null) {
1663:                    final String items[] = comboScheme.getItems();
1664:
1665:                    for (int i = 0; i < items.length; i++) {
1666:                        if (schemeUniqueName.equals(items[i])) {
1667:                            comboScheme.select(i);
1668:                            break;
1669:                        }
1670:                    }
1671:                }
1672:            }
1673:
1674:            /**
1675:             * Builds the internal look-up tables before allowing the page to become
1676:             * visible.
1677:             */
1678:            public final void setVisible(final boolean visible) {
1679:                if (visible == true) {
1680:                    Map contextsByName = new HashMap();
1681:
1682:                    for (Iterator iterator = contextService
1683:                            .getDefinedContextIds().iterator(); iterator
1684:                            .hasNext();) {
1685:                        Context context = contextService
1686:                                .getContext((String) iterator.next());
1687:                        try {
1688:                            String name = context.getName();
1689:                            Collection contexts = (Collection) contextsByName
1690:                                    .get(name);
1691:
1692:                            if (contexts == null) {
1693:                                contexts = new HashSet();
1694:                                contextsByName.put(name, contexts);
1695:                            }
1696:
1697:                            contexts.add(context);
1698:                        } catch (final NotDefinedException e) {
1699:                            // Do nothing.
1700:                        }
1701:                    }
1702:
1703:                    Map commandsByName = new HashMap();
1704:
1705:                    for (Iterator iterator = commandService
1706:                            .getDefinedCommandIds().iterator(); iterator
1707:                            .hasNext();) {
1708:                        Command command = commandService
1709:                                .getCommand((String) iterator.next());
1710:                        if (!isActive(command)) {
1711:                            continue;
1712:                        }
1713:
1714:                        try {
1715:                            String name = command.getName();
1716:                            Collection commands = (Collection) commandsByName
1717:                                    .get(name);
1718:
1719:                            if (commands == null) {
1720:                                commands = new HashSet();
1721:                                commandsByName.put(name, commands);
1722:                            }
1723:
1724:                            commands.add(command);
1725:                        } catch (NotDefinedException eNotDefined) {
1726:                            // Do nothing
1727:                        }
1728:                    }
1729:
1730:                    // moved here to allow us to remove any empty categories
1731:                    commandIdsByCategoryId = new HashMap();
1732:
1733:                    for (Iterator iterator = commandService
1734:                            .getDefinedCommandIds().iterator(); iterator
1735:                            .hasNext();) {
1736:                        final Command command = commandService
1737:                                .getCommand((String) iterator.next());
1738:                        if (!isActive(command)) {
1739:                            continue;
1740:                        }
1741:
1742:                        try {
1743:                            String categoryId = command.getCategory().getId();
1744:                            Collection commandIds = (Collection) commandIdsByCategoryId
1745:                                    .get(categoryId);
1746:
1747:                            if (commandIds == null) {
1748:                                commandIds = new HashSet();
1749:                                commandIdsByCategoryId.put(categoryId,
1750:                                        commandIds);
1751:                            }
1752:
1753:                            commandIds.add(command.getId());
1754:                        } catch (NotDefinedException eNotDefined) {
1755:                            // Do nothing
1756:                        }
1757:                    }
1758:
1759:                    Map categoriesByName = new HashMap();
1760:
1761:                    for (Iterator iterator = commandService
1762:                            .getDefinedCategoryIds().iterator(); iterator
1763:                            .hasNext();) {
1764:                        Category category = commandService
1765:                                .getCategory((String) iterator.next());
1766:
1767:                        try {
1768:                            if (commandIdsByCategoryId.containsKey(category
1769:                                    .getId())) {
1770:                                String name = category.getName();
1771:                                Collection categories = (Collection) categoriesByName
1772:                                        .get(name);
1773:
1774:                                if (categories == null) {
1775:                                    categories = new HashSet();
1776:                                    categoriesByName.put(name, categories);
1777:                                }
1778:
1779:                                categories.add(category);
1780:                            }
1781:                        } catch (NotDefinedException eNotDefined) {
1782:                            // Do nothing
1783:                        }
1784:                    }
1785:
1786:                    Map schemesByName = new HashMap();
1787:
1788:                    final Scheme[] definedSchemes = bindingService
1789:                            .getDefinedSchemes();
1790:                    for (int i = 0; i < definedSchemes.length; i++) {
1791:                        final Scheme scheme = definedSchemes[i];
1792:                        try {
1793:                            String name = scheme.getName();
1794:                            Collection schemes = (Collection) schemesByName
1795:                                    .get(name);
1796:
1797:                            if (schemes == null) {
1798:                                schemes = new HashSet();
1799:                                schemesByName.put(name, schemes);
1800:                            }
1801:
1802:                            schemes.add(scheme);
1803:                        } catch (final NotDefinedException e) {
1804:                            // Do nothing.
1805:                        }
1806:                    }
1807:
1808:                    contextIdsByUniqueName = new HashMap();
1809:                    contextUniqueNamesById = new HashMap();
1810:
1811:                    for (Iterator iterator = contextsByName.entrySet()
1812:                            .iterator(); iterator.hasNext();) {
1813:                        Map.Entry entry = (Map.Entry) iterator.next();
1814:                        String name = (String) entry.getKey();
1815:                        Set contexts = (Set) entry.getValue();
1816:                        Iterator iterator2 = contexts.iterator();
1817:
1818:                        if (contexts.size() == 1) {
1819:                            Context context = (Context) iterator2.next();
1820:                            contextIdsByUniqueName.put(name, context.getId());
1821:                            contextUniqueNamesById.put(context.getId(), name);
1822:                        } else {
1823:                            while (iterator2.hasNext()) {
1824:                                Context context = (Context) iterator2.next();
1825:                                String uniqueName = MessageFormat
1826:                                        .format(
1827:                                                Util.translateString(
1828:                                                        RESOURCE_BUNDLE,
1829:                                                        "uniqueName"), new Object[] { name, //$NON-NLS-1$
1830:                                                        context.getId() });
1831:                                contextIdsByUniqueName.put(uniqueName, context
1832:                                        .getId());
1833:                                contextUniqueNamesById.put(context.getId(),
1834:                                        uniqueName);
1835:                            }
1836:                        }
1837:                    }
1838:
1839:                    categoryIdsByUniqueName = new HashMap();
1840:                    categoryUniqueNamesById = new HashMap();
1841:
1842:                    for (Iterator iterator = categoriesByName.entrySet()
1843:                            .iterator(); iterator.hasNext();) {
1844:                        Map.Entry entry = (Map.Entry) iterator.next();
1845:                        String name = (String) entry.getKey();
1846:                        Set categories = (Set) entry.getValue();
1847:                        Iterator iterator2 = categories.iterator();
1848:
1849:                        if (categories.size() == 1) {
1850:                            Category category = (Category) iterator2.next();
1851:                            categoryIdsByUniqueName.put(name, category.getId());
1852:                            categoryUniqueNamesById.put(category.getId(), name);
1853:                        } else {
1854:                            while (iterator2.hasNext()) {
1855:                                Category category = (Category) iterator2.next();
1856:                                String uniqueName = MessageFormat
1857:                                        .format(
1858:                                                Util.translateString(
1859:                                                        RESOURCE_BUNDLE,
1860:                                                        "uniqueName"), new Object[] { name, //$NON-NLS-1$
1861:                                                        category.getId() });
1862:                                categoryIdsByUniqueName.put(uniqueName,
1863:                                        category.getId());
1864:                                categoryUniqueNamesById.put(category.getId(),
1865:                                        uniqueName);
1866:                            }
1867:                        }
1868:                    }
1869:
1870:                    schemeIdsByUniqueName = new HashMap();
1871:                    schemeUniqueNamesById = new HashMap();
1872:
1873:                    for (Iterator iterator = schemesByName.entrySet()
1874:                            .iterator(); iterator.hasNext();) {
1875:                        Map.Entry entry = (Map.Entry) iterator.next();
1876:                        String name = (String) entry.getKey();
1877:                        Set keyConfigurations = (Set) entry.getValue();
1878:                        Iterator iterator2 = keyConfigurations.iterator();
1879:
1880:                        if (keyConfigurations.size() == 1) {
1881:                            Scheme scheme = (Scheme) iterator2.next();
1882:                            schemeIdsByUniqueName.put(name, scheme.getId());
1883:                            schemeUniqueNamesById.put(scheme.getId(), name);
1884:                        } else {
1885:                            while (iterator2.hasNext()) {
1886:                                Scheme scheme = (Scheme) iterator2.next();
1887:                                String uniqueName = MessageFormat
1888:                                        .format(
1889:                                                Util.translateString(
1890:                                                        RESOURCE_BUNDLE,
1891:                                                        "uniqueName"), new Object[] { name, //$NON-NLS-1$
1892:                                                        scheme.getId() });
1893:                                schemeIdsByUniqueName.put(uniqueName, scheme
1894:                                        .getId());
1895:                                schemeUniqueNamesById.put(scheme.getId(),
1896:                                        uniqueName);
1897:                            }
1898:                        }
1899:                    }
1900:
1901:                    Scheme activeScheme = bindingService.getActiveScheme();
1902:
1903:                    // Make an internal copy of the binding manager, for local changes.
1904:                    try {
1905:                        for (int i = 0; i < definedSchemes.length; i++) {
1906:                            final Scheme scheme = definedSchemes[i];
1907:                            final Scheme copy = localChangeManager
1908:                                    .getScheme(scheme.getId());
1909:                            copy.define(scheme.getName(), scheme
1910:                                    .getDescription(), scheme.getParentId());
1911:                        }
1912:                        localChangeManager.setActiveScheme(bindingService
1913:                                .getActiveScheme());
1914:                    } catch (final NotDefinedException e) {
1915:                        throw new Error(
1916:                                "There is a programmer error in the keys preference page"); //$NON-NLS-1$
1917:                    }
1918:                    localChangeManager.setLocale(bindingService.getLocale());
1919:                    localChangeManager
1920:                            .setPlatform(bindingService.getPlatform());
1921:                    localChangeManager
1922:                            .setBindings(bindingService.getBindings());
1923:
1924:                    // Populate the category combo box.
1925:                    List categoryNames = new ArrayList(categoryIdsByUniqueName
1926:                            .keySet());
1927:                    Collections.sort(categoryNames, Collator.getInstance());
1928:                    if (commandIdsByCategoryId.containsKey(null)) {
1929:                        categoryNames.add(0, Util.translateString(
1930:                                RESOURCE_BUNDLE, "other")); //$NON-NLS-1$
1931:                    }
1932:                    comboCategory.setItems((String[]) categoryNames
1933:                            .toArray(new String[categoryNames.size()]));
1934:                    comboCategory.clearSelection();
1935:                    comboCategory.deselectAll();
1936:                    if (commandIdsByCategoryId.containsKey(null)
1937:                            || !categoryNames.isEmpty()) {
1938:                        comboCategory.select(0);
1939:                    }
1940:
1941:                    // Populate the scheme combo box.
1942:                    List schemeNames = new ArrayList(schemeIdsByUniqueName
1943:                            .keySet());
1944:                    Collections.sort(schemeNames, Collator.getInstance());
1945:                    comboScheme.setItems((String[]) schemeNames
1946:                            .toArray(new String[schemeNames.size()]));
1947:                    setScheme(activeScheme);
1948:
1949:                    // Update the entire page.
1950:                    update(true);
1951:                }
1952:
1953:                super .setVisible(visible);
1954:            }
1955:
1956:            /**
1957:             * Updates the entire preference page -- except the view tab -- based on
1958:             * current selection sate. This preference page is written so that
1959:             * everything can be made consistent simply by inspecting the state of its
1960:             * widgets. A change is triggered by the user, and an event is fired. The
1961:             * event triggers an update. It is possible for extra work to be done by
1962:             * this page before calling update.
1963:             */
1964:            private final void update() {
1965:                update(false);
1966:            }
1967:
1968:            /**
1969:             * Updates the entire preference page based on current changes. This
1970:             * preference page is written so that everything can be made consistent
1971:             * simply by inspecting the state of its widgets. A change is triggered by
1972:             * the user, and an event is fired. The event triggers an update. It is
1973:             * possible for extra work to be done by this page before calling update.
1974:             * 
1975:             * @param updateViewTab
1976:             *            Whether the view tab should be updated as well.
1977:             */
1978:            private final void update(final boolean updateViewTab) {
1979:                if (updateViewTab) {
1980:                    updateViewTab();
1981:                }
1982:                updateComboCommand();
1983:                updateComboContext();
1984:                final TriggerSequence triggerSequence = getKeySequence();
1985:                updateTableBindingsForTriggerSequence(triggerSequence);
1986:                final ParameterizedCommand command = getParameterizedCommand();
1987:                updateTableBindingsForCommand(command);
1988:                final String contextId = getContextId();
1989:                updateSelection(tableBindingsForTriggerSequence, contextId,
1990:                        triggerSequence);
1991:                updateSelection(tableBindingsForCommand, contextId,
1992:                        triggerSequence);
1993:                updateLabelSchemeExtends();
1994:                updateLabelContextExtends();
1995:                updateEnabled(triggerSequence, command);
1996:            }
1997:
1998:            /**
1999:             * Updates the contents of the commands combo box, based on the current
2000:             * selection in the category combo box.
2001:             */
2002:            private final void updateComboCommand() {
2003:                // Remember the current selection, so we can restore it later.
2004:                final ParameterizedCommand command = getParameterizedCommand();
2005:
2006:                // Figure out where command identifiers apply to the selected category.
2007:                final String categoryId = getCategoryId();
2008:                Set commandIds = (Set) commandIdsByCategoryId.get(categoryId);
2009:                if (commandIds == null) {
2010:                    commandIds = Collections.EMPTY_SET;
2011:                }
2012:
2013:                /*
2014:                 * Generate an array of parameterized commands based on these
2015:                 * identifiers. The parameterized commands will be sorted based on their
2016:                 * names.
2017:                 */
2018:                List commands = new ArrayList();
2019:                final Iterator commandIdItr = commandIds.iterator();
2020:                while (commandIdItr.hasNext()) {
2021:                    final String currentCommandId = (String) commandIdItr
2022:                            .next();
2023:                    final Command currentCommand = commandService
2024:                            .getCommand(currentCommandId);
2025:                    try {
2026:                        commands.addAll(ParameterizedCommand
2027:                                .generateCombinations(currentCommand));
2028:                    } catch (final NotDefinedException e) {
2029:                        // It is safe to just ignore undefined commands.
2030:                    }
2031:                }
2032:
2033:                // sort the commands with a collator, so they appear in the
2034:                // combo correctly
2035:                commands = sortParameterizedCommands(commands);
2036:
2037:                final int commandCount = commands.size();
2038:                this .commands = (ParameterizedCommand[]) commands
2039:                        .toArray(new ParameterizedCommand[commandCount]);
2040:
2041:                /*
2042:                 * Generate an array of command names based on this array of
2043:                 * parameterized commands.
2044:                 */
2045:                final String[] commandNames = new String[commandCount];
2046:                for (int i = 0; i < commandCount; i++) {
2047:                    try {
2048:                        commandNames[i] = this .commands[i].getName();
2049:                    } catch (final NotDefinedException e) {
2050:                        throw new Error(
2051:                                "Concurrent modification of the command's defined state"); //$NON-NLS-1$
2052:                    }
2053:                }
2054:
2055:                /*
2056:                 * Copy the command names into the combo box, but only if they've
2057:                 * changed. We do this to try to avoid unnecessary calls out to the
2058:                 * operating system, as well as to defend against bugs in SWT's event
2059:                 * mechanism.
2060:                 */
2061:                final String[] currentItems = comboCommand.getItems();
2062:                if (!Arrays.equals(currentItems, commandNames)) {
2063:                    comboCommand.setItems(commandNames);
2064:                }
2065:
2066:                // Try to restore the selection.
2067:                setParameterizedCommand(command);
2068:
2069:                /*
2070:                 * Just to be extra careful, make sure that we have a selection at this
2071:                 * point. This line could probably be removed, but it makes the code a
2072:                 * bit more robust.
2073:                 */
2074:                if ((comboCommand.getSelectionIndex() == -1)
2075:                        && (commandCount > 0)) {
2076:                    comboCommand.select(0);
2077:                }
2078:            }
2079:
2080:            /**
2081:             * Sort the commands using the correct language.
2082:             * @param commands the List of ParameterizedCommands
2083:             * @return The sorted List
2084:             */
2085:            private List sortParameterizedCommands(List commands) {
2086:                final Collator collator = Collator.getInstance();
2087:
2088:                // this comparator is based on the ParameterizedCommands#compareTo(*)
2089:                // method, but uses the collator.
2090:                Comparator comparator = new Comparator() {
2091:                    public int compare(Object o1, Object o2) {
2092:                        String name1 = null;
2093:                        String name2 = null;
2094:                        try {
2095:                            name1 = ((ParameterizedCommand) o1).getName();
2096:                        } catch (NotDefinedException e) {
2097:                            return -1;
2098:                        }
2099:                        try {
2100:                            name2 = ((ParameterizedCommand) o2).getName();
2101:                        } catch (NotDefinedException e) {
2102:                            return 1;
2103:                        }
2104:                        int rc = collator.compare(name1, name2);
2105:                        if (rc != 0) {
2106:                            return rc;
2107:                        }
2108:
2109:                        String id1 = ((ParameterizedCommand) o1).getId();
2110:                        String id2 = ((ParameterizedCommand) o2).getId();
2111:                        return collator.compare(id1, id2);
2112:                    }
2113:                };
2114:                Collections.sort(commands, comparator);
2115:                return commands;
2116:            }
2117:
2118:            /**
2119:             * Updates the contents of the context combo box, as well as its selection.
2120:             */
2121:            private final void updateComboContext() {
2122:                final String contextId = getContextId();
2123:                final Map contextIdsByName = new HashMap(contextIdsByUniqueName);
2124:
2125:                final List contextNames = new ArrayList(contextIdsByName
2126:                        .keySet());
2127:                Collections.sort(contextNames, Collator.getInstance());
2128:
2129:                comboContext.setItems((String[]) contextNames
2130:                        .toArray(new String[contextNames.size()]));
2131:                setContextId(contextId);
2132:
2133:                if (comboContext.getSelectionIndex() == -1
2134:                        && !contextNames.isEmpty()) {
2135:                    comboContext.select(0);
2136:                }
2137:            }
2138:
2139:            /**
2140:             * Updates the enabled state of the various widgets on this page. The
2141:             * decision is based on the current trigger sequence and the currently
2142:             * selected command.
2143:             * 
2144:             * @param triggerSequence
2145:             *            The current trigger sequence; may be empty, but never
2146:             *            <code>null</code>.
2147:             * @param command
2148:             *            The currently selected command, if any; <code>null</code>
2149:             *            otherwise.
2150:             */
2151:            private final void updateEnabled(
2152:                    final TriggerSequence triggerSequence,
2153:                    final ParameterizedCommand command) {
2154:                final boolean commandSelected = command != null;
2155:                labelBindingsForCommand.setEnabled(commandSelected);
2156:                tableBindingsForCommand.setEnabled(commandSelected);
2157:
2158:                final boolean triggerSequenceSelected = !triggerSequence
2159:                        .isEmpty();
2160:                labelBindingsForTriggerSequence
2161:                        .setEnabled(triggerSequenceSelected);
2162:                tableBindingsForTriggerSequence
2163:                        .setEnabled(triggerSequenceSelected);
2164:
2165:                /*
2166:                 * TODO Do some better button enablement.
2167:                 */
2168:                final boolean buttonsEnabled = commandSelected
2169:                        && triggerSequenceSelected;
2170:                buttonAdd.setEnabled(buttonsEnabled);
2171:                buttonRemove.setEnabled(buttonsEnabled);
2172:                buttonRestore.setEnabled(buttonsEnabled);
2173:            }
2174:
2175:            /**
2176:             * Updates the label next to the context that says "extends" if the context
2177:             * is a child of another context. If the context is not a child of another
2178:             * context, then the label is simply blank.
2179:             */
2180:            private final void updateLabelContextExtends() {
2181:                final String contextId = getContextId();
2182:
2183:                if (contextId != null) {
2184:                    final Context context = contextService
2185:                            .getContext(getContextId());
2186:                    if (context.isDefined()) {
2187:                        try {
2188:                            final String parentId = context.getParentId();
2189:                            if (parentId != null) {
2190:                                final String name = (String) contextUniqueNamesById
2191:                                        .get(parentId);
2192:                                if (name != null) {
2193:                                    labelContextExtends.setText(MessageFormat
2194:                                            .format(
2195:                                                    Util.translateString(
2196:                                                            RESOURCE_BUNDLE,
2197:                                                            "extends"), //$NON-NLS-1$
2198:                                                    new Object[] { name }));
2199:                                    return;
2200:                                }
2201:                            }
2202:                        } catch (final NotDefinedException e) {
2203:                            // Do nothing
2204:                        }
2205:                    }
2206:                }
2207:
2208:                labelContextExtends.setText(Util.ZERO_LENGTH_STRING);
2209:            }
2210:
2211:            /**
2212:             * Updates the label next to the scheme that says "extends" if the scheme is
2213:             * a child of another scheme. If the scheme is not a child of another
2214:             * scheme, then the label is simply blank.
2215:             */
2216:            private final void updateLabelSchemeExtends() {
2217:                final String schemeId = getSchemeId();
2218:
2219:                if (schemeId != null) {
2220:                    final Scheme scheme = bindingService.getScheme(schemeId);
2221:                    try {
2222:                        final String name = (String) schemeUniqueNamesById
2223:                                .get(scheme.getParentId());
2224:                        if (name != null) {
2225:                            labelSchemeExtends.setText(MessageFormat.format(
2226:                                    Util.translateString(RESOURCE_BUNDLE,
2227:                                            "extends"), //$NON-NLS-1$
2228:                                    new Object[] { name }));
2229:                            return;
2230:                        }
2231:                    } catch (final NotDefinedException e) {
2232:                        // Do nothing
2233:                    }
2234:                }
2235:
2236:                labelSchemeExtends.setText(Util.ZERO_LENGTH_STRING);
2237:            }
2238:
2239:            /**
2240:             * Tries to select the correct entry in table based on the currently
2241:             * selected context and trigger sequence. If the table hasn't really
2242:             * changed, then this method is essentially trying to restore the selection.
2243:             * If it has changed, then it is trying to select the most entry based on
2244:             * the context.
2245:             * 
2246:             * @param table
2247:             *            The table to be changed; must not be <code>null</code>.
2248:             * @param contextId
2249:             *            The currently selected context; should not be
2250:             *            <code>null</code>.
2251:             * @param triggerSequence
2252:             *            The current trigger sequence; should not be <code>null</code>.
2253:             */
2254:            private final void updateSelection(final Table table,
2255:                    final String contextId,
2256:                    final TriggerSequence triggerSequence) {
2257:                if (table.getSelectionCount() > 1) {
2258:                    table.deselectAll();
2259:                }
2260:
2261:                final TableItem[] items = table.getItems();
2262:                int selection = -1;
2263:                for (int i = 0; i < items.length; i++) {
2264:                    final Binding binding = (Binding) items[i]
2265:                            .getData(ITEM_DATA_KEY);
2266:                    if ((Util.equals(contextId, binding.getContextId()))
2267:                            && (Util.equals(triggerSequence, binding
2268:                                    .getTriggerSequence()))) {
2269:                        selection = i;
2270:                        break;
2271:                    }
2272:                }
2273:
2274:                if (selection != -1) {
2275:                    table.select(selection);
2276:                }
2277:            }
2278:
2279:            /**
2280:             * Updates the contents of the table showing the bindings for the currently
2281:             * selected command. The selection is destroyed by this process.
2282:             * 
2283:             * @param parameterizedCommand
2284:             *            The currently selected fully-parameterized command; may be
2285:             *            <code>null</code>.
2286:             */
2287:            private final void updateTableBindingsForCommand(
2288:                    final ParameterizedCommand parameterizedCommand) {
2289:                // Clear the table of existing items.
2290:                tableBindingsForCommand.removeAll();
2291:
2292:                // Add each of the bindings, if the command identifier matches.
2293:                final Collection bindings = localChangeManager
2294:                        .getActiveBindingsDisregardingContextFlat();
2295:                final Iterator bindingItr = bindings.iterator();
2296:                while (bindingItr.hasNext()) {
2297:                    final Binding binding = (Binding) bindingItr.next();
2298:                    if (!Util.equals(parameterizedCommand, binding
2299:                            .getParameterizedCommand())) {
2300:                        continue; // binding does not match
2301:                    }
2302:
2303:                    final TableItem tableItem = new TableItem(
2304:                            tableBindingsForCommand, SWT.NULL);
2305:                    tableItem.setData(ITEM_DATA_KEY, binding);
2306:
2307:                    /*
2308:                     * Set the associated image based on the type of binding. Either it
2309:                     * is a user binding or a system binding.
2310:                     * 
2311:                     * TODO Identify more image types.
2312:                     */
2313:                    if (binding.getType() == Binding.SYSTEM) {
2314:                        tableItem.setImage(0, IMAGE_BLANK);
2315:                    } else {
2316:                        tableItem.setImage(0, IMAGE_CHANGE);
2317:                    }
2318:
2319:                    String contextName = (String) contextUniqueNamesById
2320:                            .get(binding.getContextId());
2321:                    if (contextName == null) {
2322:                        contextName = Util.ZERO_LENGTH_STRING;
2323:                    }
2324:                    tableItem.setText(1, contextName);
2325:                    tableItem.setText(2, binding.getTriggerSequence().format());
2326:                }
2327:            }
2328:
2329:            /**
2330:             * Updates the contents of the table showing the bindings for the current
2331:             * trigger sequence. The selection is destroyed by this process.
2332:             * 
2333:             * @param triggerSequence
2334:             *            The current trigger sequence; may be <code>null</code> or
2335:             *            empty.
2336:             */
2337:            private final void updateTableBindingsForTriggerSequence(
2338:                    final TriggerSequence triggerSequence) {
2339:                // Clear the table of its existing items.
2340:                tableBindingsForTriggerSequence.removeAll();
2341:
2342:                // Get the collection of bindings for the current command.
2343:                final Map activeBindings = localChangeManager
2344:                        .getActiveBindingsDisregardingContext();
2345:                final Collection bindings = (Collection) activeBindings
2346:                        .get(triggerSequence);
2347:                if (bindings == null) {
2348:                    return;
2349:                }
2350:
2351:                // Add each of the bindings.
2352:                final Iterator bindingItr = bindings.iterator();
2353:                while (bindingItr.hasNext()) {
2354:                    final Binding binding = (Binding) bindingItr.next();
2355:                    final Context context = contextService.getContext(binding
2356:                            .getContextId());
2357:                    final ParameterizedCommand parameterizedCommand = binding
2358:                            .getParameterizedCommand();
2359:                    final Command command = parameterizedCommand.getCommand();
2360:                    if ((!context.isDefined()) && (!command.isDefined())) {
2361:                        continue;
2362:                    }
2363:
2364:                    final TableItem tableItem = new TableItem(
2365:                            tableBindingsForTriggerSequence, SWT.NULL);
2366:                    tableItem.setData(ITEM_DATA_KEY, binding);
2367:
2368:                    /*
2369:                     * Set the associated image based on the type of binding. Either it
2370:                     * is a user binding or a system binding.
2371:                     * 
2372:                     * TODO Identify more image types.
2373:                     */
2374:                    if (binding.getType() == Binding.SYSTEM) {
2375:                        tableItem.setImage(0, IMAGE_BLANK);
2376:                    } else {
2377:                        tableItem.setImage(0, IMAGE_CHANGE);
2378:                    }
2379:
2380:                    try {
2381:                        tableItem.setText(1, context.getName());
2382:                        tableItem.setText(2, parameterizedCommand.getName());
2383:                    } catch (final NotDefinedException e) {
2384:                        throw new Error(
2385:                                "Context or command became undefined on a non-UI thread while the UI thread was processing."); //$NON-NLS-1$
2386:                    }
2387:                }
2388:            }
2389:
2390:            /**
2391:             * Updates the contents of the view tab. This queries the command manager
2392:             * for a list of key sequence binding definitions, and these definitions are
2393:             * then added to the table.
2394:             * 
2395:             * @since 3.1
2396:             */
2397:            private final void updateViewTab() {
2398:                // Clear out the existing table contents.
2399:                tableBindings.removeAll();
2400:
2401:                // Get a sorted list of key binding contents.
2402:                final List bindings = new ArrayList(localChangeManager
2403:                        .getActiveBindingsDisregardingContextFlat());
2404:                Collections.sort(bindings, new Comparator() {
2405:                    /**
2406:                     * Compares two instances of <code>Binding</code> based on the
2407:                     * current sort order.
2408:                     * 
2409:                     * @param object1
2410:                     *            The first object to compare; must be an instance of
2411:                     *            <code>Binding</code> (i.e., not <code>null</code>).
2412:                     * @param object2
2413:                     *            The second object to compare; must be an instance of
2414:                     *            <code>Binding</code> (i.e., not <code>null</code>).
2415:                     * @return The integer value representing the comparison. The
2416:                     *         comparison is based on the current sort order.
2417:                     * @since 3.1
2418:                     */
2419:                    public final int compare(final Object object1,
2420:                            final Object object2) {
2421:                        final Binding binding1 = (Binding) object1;
2422:                        final Binding binding2 = (Binding) object2;
2423:
2424:                        /*
2425:                         * Get the category name, command name, formatted key sequence
2426:                         * and context name for the first binding.
2427:                         */
2428:                        final Command command1 = binding1
2429:                                .getParameterizedCommand().getCommand();
2430:                        String categoryName1 = Util.ZERO_LENGTH_STRING;
2431:                        String commandName1 = Util.ZERO_LENGTH_STRING;
2432:                        try {
2433:                            commandName1 = command1.getName();
2434:                            categoryName1 = command1.getCategory().getName();
2435:                        } catch (final NotDefinedException e) {
2436:                            // Just use the zero-length string.
2437:                        }
2438:                        final String triggerSequence1 = binding1
2439:                                .getTriggerSequence().format();
2440:                        final String contextId1 = binding1.getContextId();
2441:                        String contextName1 = Util.ZERO_LENGTH_STRING;
2442:                        if (contextId1 != null) {
2443:                            final Context context = contextService
2444:                                    .getContext(contextId1);
2445:                            try {
2446:                                contextName1 = context.getName();
2447:                            } catch (final org.eclipse.core.commands.common.NotDefinedException e) {
2448:                                // Just use the zero-length string.
2449:                            }
2450:                        }
2451:
2452:                        /*
2453:                         * Get the category name, command name, formatted key sequence
2454:                         * and context name for the first binding.
2455:                         */
2456:                        final Command command2 = binding2
2457:                                .getParameterizedCommand().getCommand();
2458:                        String categoryName2 = Util.ZERO_LENGTH_STRING;
2459:                        String commandName2 = Util.ZERO_LENGTH_STRING;
2460:                        try {
2461:                            commandName2 = command2.getName();
2462:                            categoryName2 = command2.getCategory().getName();
2463:                        } catch (final org.eclipse.core.commands.common.NotDefinedException e) {
2464:                            // Just use the zero-length string.
2465:                        }
2466:                        final String keySequence2 = binding2
2467:                                .getTriggerSequence().format();
2468:                        final String contextId2 = binding2.getContextId();
2469:                        String contextName2 = Util.ZERO_LENGTH_STRING;
2470:                        if (contextId2 != null) {
2471:                            final Context context = contextService
2472:                                    .getContext(contextId2);
2473:                            try {
2474:                                contextName2 = context.getName();
2475:                            } catch (final org.eclipse.core.commands.common.NotDefinedException e) {
2476:                                // Just use the zero-length string.
2477:                            }
2478:                        }
2479:
2480:                        // Compare the items in the current sort order.
2481:                        int compare = 0;
2482:                        for (int i = 0; i < sortOrder.length; i++) {
2483:                            switch (sortOrder[i]) {
2484:                            case VIEW_CATEGORY_COLUMN_INDEX:
2485:                                compare = Util.compare(categoryName1,
2486:                                        categoryName2);
2487:                                if (compare != 0) {
2488:                                    return compare;
2489:                                }
2490:                                break;
2491:                            case VIEW_COMMAND_COLUMN_INDEX:
2492:                                compare = Util.compare(commandName1,
2493:                                        commandName2);
2494:                                if (compare != 0) {
2495:                                    return compare;
2496:                                }
2497:                                break;
2498:                            case VIEW_KEY_SEQUENCE_COLUMN_INDEX:
2499:                                compare = Util.compare(triggerSequence1,
2500:                                        keySequence2);
2501:                                if (compare != 0) {
2502:                                    return compare;
2503:                                }
2504:                                break;
2505:                            case VIEW_CONTEXT_COLUMN_INDEX:
2506:                                compare = Util.compare(contextName1,
2507:                                        contextName2);
2508:                                if (compare != 0) {
2509:                                    return compare;
2510:                                }
2511:                                break;
2512:                            default:
2513:                                throw new Error(
2514:                                        "Programmer error: added another sort column without modifying the comparator."); //$NON-NLS-1$
2515:                            }
2516:                        }
2517:
2518:                        return compare;
2519:                    }
2520:
2521:                    /**
2522:                     * @see Object#equals(java.lang.Object)
2523:                     */
2524:                    public final boolean equals(final Object object) {
2525:                        return super .equals(object);
2526:                    }
2527:                });
2528:
2529:                // Add a table item for each item in the list.
2530:                final Iterator keyBindingItr = bindings.iterator();
2531:                while (keyBindingItr.hasNext()) {
2532:                    final Binding binding = (Binding) keyBindingItr.next();
2533:
2534:                    // Get the command and category name.
2535:                    final ParameterizedCommand command = binding
2536:                            .getParameterizedCommand();
2537:                    String commandName = Util.ZERO_LENGTH_STRING;
2538:                    String categoryName = Util.ZERO_LENGTH_STRING;
2539:                    try {
2540:                        commandName = command.getName();
2541:                        categoryName = command.getCommand().getCategory()
2542:                                .getName();
2543:                    } catch (final org.eclipse.core.commands.common.NotDefinedException e) {
2544:                        // Just use the zero-length string.
2545:                    }
2546:
2547:                    // Ignore items with a meaningless command name.
2548:                    if ((commandName == null) || (commandName.length() == 0)) {
2549:                        continue;
2550:                    }
2551:
2552:                    // Get the context name.
2553:                    final String contextId = binding.getContextId();
2554:                    String contextName = Util.ZERO_LENGTH_STRING;
2555:                    if (contextId != null) {
2556:                        final Context context = contextService
2557:                                .getContext(contextId);
2558:                        try {
2559:                            contextName = context.getName();
2560:                        } catch (final org.eclipse.core.commands.common.NotDefinedException e) {
2561:                            // Just use the zero-length string.
2562:                        }
2563:                    }
2564:
2565:                    // Create the table item.
2566:                    final TableItem item = new TableItem(tableBindings,
2567:                            SWT.NONE);
2568:                    item.setText(VIEW_CATEGORY_COLUMN_INDEX, categoryName);
2569:                    item.setText(VIEW_COMMAND_COLUMN_INDEX, commandName);
2570:                    item.setText(VIEW_KEY_SEQUENCE_COLUMN_INDEX, binding
2571:                            .getTriggerSequence().format());
2572:                    item.setText(VIEW_CONTEXT_COLUMN_INDEX, contextName);
2573:                    item.setData(BINDING_KEY, binding);
2574:                }
2575:
2576:                // Pack the columns.
2577:                for (int i = 0; i < tableBindings.getColumnCount(); i++) {
2578:                    tableBindings.getColumn(i).pack();
2579:                }
2580:            }
2581:
2582:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.