Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 102081 | Differences between
and this patch

Collapse All | Expand All

(-)Eclipse UI/org/eclipse/ui/internal/dialogs/FilteredPreferenceDialog.java (-2 / +2 lines)
Lines 57-63 Link Here
57
 */
57
 */
58
public abstract class FilteredPreferenceDialog extends PreferenceDialog implements IWorkbenchPreferenceContainer{
58
public abstract class FilteredPreferenceDialog extends PreferenceDialog implements IWorkbenchPreferenceContainer{
59
59
60
	protected FilteredTextTree filteredTree;
60
	protected FilteredTree filteredTree;
61
61
62
	private Object pageData;
62
	private Object pageData;
63
	
63
	
Lines 110-116 Link Here
110
	protected TreeViewer createTreeViewer(Composite parent) {
110
	protected TreeViewer createTreeViewer(Composite parent) {
111
		PatternItemFilter filter = new PatternItemFilter(true); 
111
		PatternItemFilter filter = new PatternItemFilter(true); 
112
		int styleBits = SWT.SINGLE | SWT.H_SCROLL;
112
		int styleBits = SWT.SINGLE | SWT.H_SCROLL;
113
		filteredTree = new FilteredTextTree(parent, styleBits, filter);
113
		filteredTree = new FilteredTree(parent, styleBits, filter);
114
		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
114
		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
115
		gd.horizontalIndent = IDialogConstants.HORIZONTAL_MARGIN;
115
		gd.horizontalIndent = IDialogConstants.HORIZONTAL_MARGIN;
116
		filteredTree.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
116
		filteredTree.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
(-)Eclipse UI/org/eclipse/ui/internal/dialogs/FilteredTextTree.java (-342 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.dialogs;
12
13
import java.util.ArrayList;
14
import java.util.List;
15
16
import org.eclipse.jface.dialogs.IDialogSettings;
17
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.events.ControlAdapter;
19
import org.eclipse.swt.events.ControlEvent;
20
import org.eclipse.swt.events.DisposeEvent;
21
import org.eclipse.swt.events.DisposeListener;
22
import org.eclipse.swt.events.KeyAdapter;
23
import org.eclipse.swt.events.KeyEvent;
24
import org.eclipse.swt.events.SelectionAdapter;
25
import org.eclipse.swt.events.SelectionEvent;
26
import org.eclipse.swt.events.TraverseEvent;
27
import org.eclipse.swt.events.TraverseListener;
28
import org.eclipse.swt.graphics.Point;
29
import org.eclipse.swt.graphics.Rectangle;
30
import org.eclipse.swt.layout.GridData;
31
import org.eclipse.swt.layout.GridLayout;
32
import org.eclipse.swt.widgets.Composite;
33
import org.eclipse.swt.widgets.Display;
34
import org.eclipse.swt.widgets.Event;
35
import org.eclipse.swt.widgets.Listener;
36
import org.eclipse.swt.widgets.Shell;
37
import org.eclipse.swt.widgets.Table;
38
import org.eclipse.swt.widgets.TableItem;
39
import org.eclipse.swt.widgets.Text;
40
import org.eclipse.ui.internal.WorkbenchPlugin;
41
42
/**
43
 * The FilteredTextTree is a filtered tree that uses an editable text.
44
 */
45
public class FilteredTextTree extends FilteredTree {
46
	// A list contains all strings in search history
47
	private List searchHistory;
48
49
	private static final String SEARCHHISTORY = "search"; //$NON-NLS-1$
50
51
	// A table which contains only strings begin with typed strings
52
	private Table currentSeachTable;
53
54
	/**
55
	 * Create a new instance of the receiver.
56
	 * 
57
	 * @param parent
58
	 * @param treeStyle
59
	 */
60
	public FilteredTextTree(Composite parent, int treeStyle) {
61
		super(parent, treeStyle);
62
	}
63
64
	/**
65
	 * Create a new instance of the receiver with a supplied filter.
66
	 * 
67
	 * @param parent
68
	 * @param treeStyle
69
	 * @param filter
70
	 */
71
	public FilteredTextTree(Composite parent, int treeStyle,
72
			PatternItemFilter filter) {
73
		super(parent, treeStyle, filter);
74
	}
75
76
	/*
77
	 * (non-Javadoc)
78
	 * 
79
	 * @see org.eclipse.ui.internal.dialogs.FilteredTree#createFilterControl(org.eclipse.swt.widgets.Composite)
80
	 */
81
	protected void createFilterControl(final Composite parent) {
82
		filterText = new Text(parent, SWT.DROP_DOWN | SWT.BORDER);
83
		filterText.setFont(parent.getFont());
84
		searchHistory = getPreferenceSearchHistory();
85
86
		final Shell shell = new Shell(parent.getShell(), SWT.NO_TRIM);
87
		shell
88
				.setBackground(parent.getDisplay().getSystemColor(
89
						SWT.COLOR_WHITE));
90
		GridLayout shellGL = new GridLayout();
91
		shellGL.marginHeight = 0;
92
		shellGL.marginWidth = 0;
93
		shell.setLayout(shellGL);
94
		shell.setLayoutData(new GridData(
95
				(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL)));
96
97
		currentSeachTable = new Table(shell, SWT.SINGLE | SWT.BORDER);
98
		currentSeachTable.setLayoutData(new GridData(
99
				(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL)));
100
101
		filterText.addTraverseListener(new TraverseListener() {
102
			public void keyTraversed(TraverseEvent e) {
103
				if (e.detail == SWT.TRAVERSE_RETURN) {
104
					e.doit = false;
105
					shell.setVisible(false);
106
					if (getViewer().getTree().getItemCount() == 0) {
107
						Display.getCurrent().beep();
108
						setFilterText(""); //$NON-NLS-1$
109
					} else {
110
						getViewer().getTree().setFocus();
111
					}
112
				}
113
			}
114
		});
115
116
		filterText.addKeyListener(new KeyAdapter() {
117
			/*
118
			 * (non-Javadoc)
119
			 * 
120
			 * @see org.eclipse.swt.events.KeyAdapter#keyReleased(org.eclipse.swt.events.KeyEvent)
121
			 */
122
			public void keyReleased(KeyEvent e) {
123
124
				if (e.keyCode == SWT.ARROW_DOWN) {
125
					if (currentSeachTable.isVisible()) {
126
						// Make selection at popup table
127
						if (currentSeachTable.getSelectionCount() < 1)
128
							currentSeachTable.setSelection(0);
129
						currentSeachTable.setFocus();
130
					} else
131
						// Make selection be on the left tree
132
						treeViewer.getTree().setFocus();
133
				} else {
134
					if (e.character == SWT.CR)
135
						return;
136
137
					textChanged();
138
					List result = new ArrayList();
139
					result = reduceSearch(searchHistory, filterText.getText());
140
					upDateTable(currentSeachTable, result);
141
142
					if (currentSeachTable.getItemCount() > 0) {
143
						Rectangle textBounds = filterText.getBounds();
144
						Point point = getDisplay().map(parent, null,
145
								textBounds.x, textBounds.y);
146
						int space = currentSeachTable.getItemHeight();
147
						shell.setBounds(point.x, point.y + textBounds.height,
148
								textBounds.width, currentSeachTable
149
										.getItemHeight()
150
										* currentSeachTable.getItemCount()
151
										+ space);
152
153
						if (shell.isDisposed())
154
							shell.open();
155
156
						if (!shell.getVisible()) {
157
							shell.setVisible(true);
158
							filterText.setFocus();
159
						}
160
161
					} else
162
						shell.setVisible(false);
163
				}
164
165
			}
166
		});
167
168
		parent.getDisplay().addFilter(SWT.MouseDown, new Listener() {
169
			/*
170
			 * (non-Javadoc)
171
			 * 
172
			 * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Events)
173
			 */
174
			public void handleEvent(Event event) {
175
				if (!shell.isDisposed())
176
					shell.setVisible(false);
177
			}
178
		});
179
180
		getShell().addControlListener(new ControlAdapter() {
181
			/*
182
			 * (non-Javadoc)
183
			 * 
184
			 * @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent)
185
			 */
186
			public void controlMoved(ControlEvent e) {
187
				shell.setVisible(false);
188
			}
189
		});
190
191
		currentSeachTable.addSelectionListener(new SelectionAdapter() {
192
			/*
193
			 * (non-Javadoc)
194
			 * 
195
			 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
196
			 */
197
			public void widgetSelected(SelectionEvent e) {
198
199
				setFilterText(currentSeachTable.getSelection()[0].getText());
200
				textChanged();
201
			}
202
203
			public void widgetDefaultSelected(SelectionEvent e) {
204
				shell.setVisible(false);
205
			}
206
		});
207
208
		filterText.addDisposeListener(new DisposeListener() {
209
			/*
210
			 * (non-Javadoc)
211
			 * 
212
			 * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
213
			 */
214
			public void widgetDisposed(DisposeEvent e) {
215
				saveDialogSettings();
216
			}
217
		});
218
219
		filterText.getAccessible().addAccessibleListener(
220
				getAccessibleListener());
221
222
	}
223
224
	/**
225
	 * Find all items which start with typed words list the list contains all
226
	 * strings of the search history
227
	 * 
228
	 * @param list
229
	 *            the list to search
230
	 * @param wordsEntered
231
	 *            String
232
	 * @return a list in which all strings start from the typed letter(s)
233
	 */
234
	public List reduceSearch(List list, String wordsEntered) {
235
		List result = new ArrayList();
236
		if (list == null)
237
			return result;
238
		for (int i = 0; i < list.size(); i++) {
239
			if (filterText.getText() == "") //$NON-NLS-1$
240
				return result;
241
			else if (((String) list.get(i)).startsWith(wordsEntered))
242
				result.add(list.get(i));
243
		}
244
245
		return result;
246
	}
247
248
	/**
249
	 * Copy all elements from a list to a table
250
	 * 
251
	 * @param table
252
	 * @param list
253
	 */
254
	public void upDateTable(Table table, List list) {
255
		table.removeAll();
256
		if (list.size() > 0) {
257
			TableItem newItem;
258
			for (int i = 0; i < list.size(); i++) {
259
				newItem = new TableItem(table, SWT.NULL, i);
260
				newItem.setText((String) list.get(i));
261
262
			}
263
		}
264
265
	}
266
267
	/**
268
	 * Return a dialog setting section for this dialog
269
	 * 
270
	 * @return IDialogSettings
271
	 */
272
	private IDialogSettings getDialogSettings() {
273
		IDialogSettings settings = WorkbenchPlugin.getDefault()
274
				.getDialogSettings();
275
		IDialogSettings thisSettings = settings
276
				.getSection(getClass().getName());
277
		if (thisSettings == null)
278
			thisSettings = settings.addNewSection(getClass().getName());
279
280
		return thisSettings;
281
	}
282
283
	/**
284
	 * Get the preferences search history for this eclipse's start, Note that
285
	 * this history will not be cleared until this eclipse closes
286
	 * 
287
	 * @return a list
288
	 */
289
	public List getPreferenceSearchHistory() {
290
291
		List searchList = new ArrayList();
292
		IDialogSettings settings = getDialogSettings();
293
		String[] search = settings.getArray(SEARCHHISTORY); //$NON-NLS-1$
294
295
		if (search != null) {
296
			for (int i = 0; i < search.length; i++)
297
				searchList.add(search[i]);
298
		}
299
		return searchList;
300
301
	}
302
303
	/**
304
	 * Saves the search history.
305
	 */
306
	private void saveDialogSettings() {
307
		IDialogSettings settings = getDialogSettings();
308
309
		// If the settings contains the same key, the previous value will be
310
		// replaced by new one
311
		String[] result = new String[searchHistory.size()];
312
		listToArray(searchHistory, result);
313
		settings.put(SEARCHHISTORY, result);
314
315
	}
316
317
	private void listToArray(List list, String[] string) {
318
		int size = list.size();
319
		for (int i = 0; i < size; i++)
320
			string[i] = (String) list.get(i);
321
	}
322
323
	/*
324
	 * (non-Javadoc)
325
	 * 
326
	 * @see org.eclipse.ui.internal.dialogs.FilteredTree#filterFocusLost()
327
	 */
328
	protected void filterFocusLost() {
329
		String newText = filterText.getText();
330
		Object[] textValues = searchHistory.toArray();
331
332
		if ((newText.equals("")) || (newText.equals(initialText)))//$NON-NLS-1$
333
			return;
334
335
		for (int i = 0; i < textValues.length; i++) {
336
			if (((String) textValues[i]).equals(newText))
337
				return;
338
		}
339
		searchHistory.add(newText);
340
	}
341
342
}
(-)Eclipse UI/org/eclipse/ui/internal/dialogs/FilteredTree.java (-61 / +333 lines)
Lines 10-15 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.dialogs;
11
package org.eclipse.ui.internal.dialogs;
12
12
13
import java.util.ArrayList;
14
import java.util.List;
15
13
import org.eclipse.core.runtime.IProgressMonitor;
16
import org.eclipse.core.runtime.IProgressMonitor;
14
import org.eclipse.core.runtime.IStatus;
17
import org.eclipse.core.runtime.IStatus;
15
import org.eclipse.core.runtime.Status;
18
import org.eclipse.core.runtime.Status;
Lines 17-22 Link Here
17
import org.eclipse.jface.action.Action;
20
import org.eclipse.jface.action.Action;
18
import org.eclipse.jface.action.IAction;
21
import org.eclipse.jface.action.IAction;
19
import org.eclipse.jface.action.ToolBarManager;
22
import org.eclipse.jface.action.ToolBarManager;
23
import org.eclipse.jface.dialogs.IDialogSettings;
20
import org.eclipse.jface.resource.ImageDescriptor;
24
import org.eclipse.jface.resource.ImageDescriptor;
21
import org.eclipse.jface.resource.JFaceResources;
25
import org.eclipse.jface.resource.JFaceResources;
22
import org.eclipse.jface.viewers.TreeViewer;
26
import org.eclipse.jface.viewers.TreeViewer;
Lines 24-43 Link Here
24
import org.eclipse.swt.SWT;
28
import org.eclipse.swt.SWT;
25
import org.eclipse.swt.accessibility.AccessibleAdapter;
29
import org.eclipse.swt.accessibility.AccessibleAdapter;
26
import org.eclipse.swt.accessibility.AccessibleEvent;
30
import org.eclipse.swt.accessibility.AccessibleEvent;
31
import org.eclipse.swt.events.ControlAdapter;
32
import org.eclipse.swt.events.ControlEvent;
27
import org.eclipse.swt.events.DisposeEvent;
33
import org.eclipse.swt.events.DisposeEvent;
28
import org.eclipse.swt.events.DisposeListener;
34
import org.eclipse.swt.events.DisposeListener;
35
import org.eclipse.swt.events.FocusAdapter;
29
import org.eclipse.swt.events.FocusEvent;
36
import org.eclipse.swt.events.FocusEvent;
30
import org.eclipse.swt.events.FocusListener;
37
import org.eclipse.swt.events.FocusListener;
31
import org.eclipse.swt.events.KeyAdapter;
38
import org.eclipse.swt.events.KeyAdapter;
32
import org.eclipse.swt.events.KeyEvent;
39
import org.eclipse.swt.events.KeyEvent;
40
import org.eclipse.swt.events.SelectionAdapter;
41
import org.eclipse.swt.events.SelectionEvent;
42
import org.eclipse.swt.events.TraverseEvent;
43
import org.eclipse.swt.events.TraverseListener;
33
import org.eclipse.swt.graphics.Color;
44
import org.eclipse.swt.graphics.Color;
45
import org.eclipse.swt.graphics.Font;
46
import org.eclipse.swt.graphics.Point;
47
import org.eclipse.swt.graphics.Rectangle;
34
import org.eclipse.swt.layout.GridData;
48
import org.eclipse.swt.layout.GridData;
35
import org.eclipse.swt.layout.GridLayout;
49
import org.eclipse.swt.layout.GridLayout;
36
import org.eclipse.swt.widgets.Composite;
50
import org.eclipse.swt.widgets.Composite;
51
import org.eclipse.swt.widgets.Display;
52
import org.eclipse.swt.widgets.Event;
53
import org.eclipse.swt.widgets.Listener;
54
import org.eclipse.swt.widgets.Shell;
55
import org.eclipse.swt.widgets.Table;
56
import org.eclipse.swt.widgets.TableItem;
37
import org.eclipse.swt.widgets.Text;
57
import org.eclipse.swt.widgets.Text;
38
import org.eclipse.swt.widgets.ToolBar;
58
import org.eclipse.swt.widgets.ToolBar;
39
import org.eclipse.ui.PlatformUI;
59
import org.eclipse.ui.PlatformUI;
40
import org.eclipse.ui.internal.WorkbenchMessages;
60
import org.eclipse.ui.internal.WorkbenchMessages;
61
import org.eclipse.ui.internal.WorkbenchPlugin;
41
import org.eclipse.ui.plugin.AbstractUIPlugin;
62
import org.eclipse.ui.plugin.AbstractUIPlugin;
42
import org.eclipse.ui.progress.WorkbenchJob;
63
import org.eclipse.ui.progress.WorkbenchJob;
43
64
Lines 52-57 Link Here
52
73
53
    protected Text filterText;
74
    protected Text filterText;
54
    
75
    
76
    //A list contains all strings in search history
77
	protected List searchHistory;
78
	
79
	//A key to match dialogsetting value
80
	protected static final String SEARCHHISTORY = "search"; //$NON-NLS-1$
81
	
82
    //A table which contains only strings begin with typed string(s)
83
	private Table currentSeachTable;
84
	
85
	private Shell shell;
86
    
55
    private ToolBarManager filterToolBar;
87
    private ToolBarManager filterToolBar;
56
88
57
    protected TreeViewer treeViewer;
89
    protected TreeViewer treeViewer;
Lines 148-153 Link Here
148
        treeViewer = new TreeViewer(this, treeStyle);
180
        treeViewer = new TreeViewer(this, treeStyle);
149
        data = new GridData(GridData.FILL_BOTH);
181
        data = new GridData(GridData.FILL_BOTH);
150
        treeViewer.getControl().setLayoutData(data);
182
        treeViewer.getControl().setLayoutData(data);
183
        treeViewer.getControl().addFocusListener(new FocusAdapter(){
184
			/* Each time the tree gains focus, the current text in filterText is saved as search history
185
			 * @see org.eclipse.swt.events.FocusAdapter#focusLost(org.eclipse.swt.events.FocusEvent)
186
			 */
187
			public void focusGained(FocusEvent e) {
188
				String newText = filterText.getText();				
189
				Object[] textValues = searchHistory.toArray();
190
				
191
				if((newText.equals(""))||(newText.equals(initialText)))//$NON-NLS-1$
192
					return;
193
		
194
				for (int i = 0; i < textValues.length; i++) {
195
					if(((String)textValues[i]).equals(newText))
196
						return;					
197
				}	
198
				searchHistory.add(newText);
199
			}
200
		});
201
        			
151
        treeViewer.getControl().addDisposeListener(new DisposeListener(){
202
        treeViewer.getControl().addDisposeListener(new DisposeListener(){
152
        	/* (non-Javadoc)
203
        	/* (non-Javadoc)
153
        	 * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
204
        	 * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
Lines 206-238 Link Here
206
	/**
257
	/**
207
	 * Create the filter control.
258
	 * Create the filter control.
208
	 */
259
	 */
209
	protected void createFilterControl(Composite parent) {
260
	protected void createFilterControl(final Composite parent) {
210
		filterText =  new Text(parent, SWT.SINGLE | SWT.BORDER);
261
		
211
		filterText.getAccessible().addAccessibleListener(getAccessibleListener());
262
		filterText = new Text(parent, SWT.BORDER);
212
	    getFilterControl().addKeyListener(getKeyListener());
263
		searchHistory = getPreferenceSearchHistory();
213
264
214
	}
265
		shell = new Shell(parent.getShell(), SWT.NO_TRIM);
266
		shell.setBackground(parent.getDisplay().getSystemColor(
267
						SWT.COLOR_WHITE));
268
		GridLayout shellGL = new GridLayout();
269
		shellGL.marginHeight = 0;
270
		shellGL.marginWidth = 0;
271
		shell.setLayout(shellGL);
272
		shell.setLayoutData(new GridData(
273
				(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL)));
274
275
		currentSeachTable = new Table(shell, SWT.SINGLE | SWT.BORDER);
276
		currentSeachTable.setLayoutData(new GridData(
277
				(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL)));
278
		
279
		//Make sure show all text in the horizonal space through Changing the font size of table
280
		Font font = parent.getFont();			
281
		currentSeachTable.setFont(new Font
282
				(parent.getDisplay(),font.getFontData()[0].getName(),
283
				 font.getFontData()[0].getHeight()-1,font.getFontData()[0].getStyle()));		
284
		
285
		filterText.addTraverseListener(new TraverseListener() {
286
			public void keyTraversed(TraverseEvent e) {
287
				if (e.detail == SWT.TRAVERSE_RETURN) {
288
					e.doit = false;
289
					shell.setVisible(false);
290
					if (getViewer().getTree().getItemCount() == 0) {
291
						Display.getCurrent().beep();
292
						setFilterText(""); //$NON-NLS-1$
293
					} else {
294
						getViewer().getTree().setFocus();
295
					}
296
				}
297
			}
298
		});
299
300
		/*filterText.addFocusListener(new FocusAdapter(){
301
			Focus has been gained on the filter control.
302
            * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent)
303
            
304
           public void focusGained(FocusEvent event) {
305
        	   selectAll();
306
       		
307
           }
308
			
309
		});*/
310
		
311
		filterText.addKeyListener(new KeyAdapter() {
312
			/*
313
			 * (non-Javadoc)
314
			 * 
315
			 * @see org.eclipse.swt.events.KeyAdapter#keyReleased(org.eclipse.swt.events.KeyEvent)
316
			 */
317
			public void keyReleased(KeyEvent e) {
318
319
				if (e.keyCode == SWT.ARROW_DOWN) {
320
					if (currentSeachTable.isVisible()) {
321
						// Set focus on the popup table
322
						currentSeachTable.setFocus();
323
						currentSeachTable.setSelection(0);
324
					} else
325
						// Set focus on the left tree
326
						treeViewer.getTree().setFocus();
327
				} else {
328
					if (e.character == SWT.CR){						
329
						int index =currentSeachTable.getSelectionIndex();
330
						setFilterText(currentSeachTable.getItem(index).getText());
331
						textChanged();						
332
						shell.setVisible(false);
333
						return;
334
					}						
335
					textChanged();
336
					List result = new ArrayList();
337
					result = reduceSearch(searchHistory, filterText.getText());
338
					updateTable(currentSeachTable, result);
339
340
					if (currentSeachTable.getItemCount() > 0) {
341
						Rectangle textBounds = filterText.getBounds();
342
												
343
						setShellLocationAndSize(parent,textBounds);
344
345
						if (shell.isDisposed())
346
							shell.open();
347
348
						if (!shell.getVisible()) {
349
							shell.setVisible(true);
350
							filterText.setFocus();
351
						}
352
353
					} else
354
						shell.setVisible(false);
355
				}
356
357
			}
358
		});
359
360
		parent.getDisplay().addFilter(SWT.MouseDown, new Listener() {
361
			/*
362
			 * Anytime the parent composit detects a mouse down event, the eventhandler will set the shell unvisible
363
			 * 
364
			 * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Events)
365
			 */
366
			public void handleEvent(Event event) {
367
				if (!shell.isDisposed())
368
					shell.setVisible(false);
369
			}
370
		});
371
372
		getShell().addControlListener(new ControlAdapter() {
373
			/*
374
			 * Move dialog also make the popup shell not visible
375
			 * 
376
			 * @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent)
377
			 */
378
			public void controlMoved(ControlEvent e) {
379
				shell.setVisible(false);
380
			}
381
		});
382
383
		currentSeachTable.addSelectionListener(new SelectionAdapter() {
384
			/*
385
			 * (non-Javadoc)
386
			 * 
387
			 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
388
			 */
389
			public void widgetDefaultSelected(SelectionEvent e) {
390
				shell.setVisible(false);
391
			}
392
		});
393
394
		filterText.addDisposeListener(new DisposeListener() {
395
			/*
396
			 * (non-Javadoc)
397
			 * 
398
			 * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
399
			 */
400
			public void widgetDisposed(DisposeEvent e) {
401
				saveDialogSettings();
402
			}
403
		});
404
405
		filterText.getAccessible().addAccessibleListener(
406
				getAccessibleListener());
215
407
216
	/**
217
	 * Get the key listener used for the receiver.
218
	 * @return KeyListener
219
	 */
220
	protected KeyAdapter getKeyListener() {
221
		return new KeyAdapter() {
222
	    		
223
	            /*
224
	             * (non-Javadoc)
225
	             * 
226
	             * @see org.eclipse.swt.events.KeyAdapter#keyReleased(org.eclipse.swt.events.KeyEvent)
227
	             */
228
	            public void keyReleased(KeyEvent e) {
229
	            	// on a CR we want to transfer focus to the list
230
	            	if(e.keyCode == SWT.ARROW_DOWN)
231
	                    treeViewer.getTree().setFocus();
232
	            	else
233
	            		textChanged();
234
	            }
235
	        };
236
	}
408
	}
237
409
238
	protected AccessibleAdapter getAccessibleListener() {
410
	protected AccessibleAdapter getAccessibleListener() {
Lines 241-247 Link Here
241
			 * @see org.eclipse.swt.accessibility.AccessibleListener#getName(org.eclipse.swt.accessibility.AccessibleEvent)
413
			 * @see org.eclipse.swt.accessibility.AccessibleListener#getName(org.eclipse.swt.accessibility.AccessibleEvent)
242
			 */
414
			 */
243
			public void getName(AccessibleEvent e) {
415
			public void getName(AccessibleEvent e) {
244
				String filterTextString = getFilterText();
416
				String filterTextString = getFilterControlText();
245
				if(filterTextString.length() == 0){
417
				if(filterTextString.length() == 0){
246
					e.result = initialText;
418
					e.result = initialText;
247
				}
419
				}
Lines 253-265 Link Here
253
	}
425
	}
254
426
255
	/**
427
	/**
256
	 * Get the text from the filter widget.
257
	 * @return String
258
	 */
259
    protected String getFilterText() {
260
		return filterText.getText();
261
	}
262
	/**
263
     * update the receiver after the text has changed
428
     * update the receiver after the text has changed
264
     */
429
     */
265
    protected void textChanged() {
430
    protected void textChanged() {
Lines 362-389 Link Here
362
     */
527
     */
363
    public void setInitialText(String text) {
528
    public void setInitialText(String text) {
364
        initialText = text;
529
        initialText = text;
365
    	setFilterText(initialText);
530
    	setFilterText(initialText);    	
366
    	
531
        textChanged();        
367
        textChanged();
368
        listener = new FocusListener() {
369
            public void focusGained(FocusEvent event) {
370
                filterFocusGained();
371
            }
372
373
            /*
374
             * (non-Javadoc)
375
             * 
376
             * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
377
             */
378
            public void focusLost(FocusEvent e) {
379
            	filterFocusLost();
380
            }
381
        };
382
        getFilterControl().addFocusListener(listener);
383
    }
532
    }
384
533
385
	
386
387
	protected void selectAll() {
534
	protected void selectAll() {
388
		filterText.selectAll();
535
		filterText.selectAll();
389
	}
536
	}
Lines 419-438 Link Here
419
	}
566
	}
420
567
421
	/**
568
	/**
422
	 * Focus has been gained on the filter control.
569
	 * Find all items which start with typed words list the list contains all
423
	 *
570
	 * strings of the search history
571
	 * 
572
	 * @param list
573
	 *            the list to search
574
	 * @param wordsEntered
575
	 *            String
576
	 * @return a list in which all strings start from the typed letter(s)
424
	 */
577
	 */
425
	protected void filterFocusGained() {
578
	protected List reduceSearch(List list, String wordsEntered) {
426
		selectAll();
579
		List result = new ArrayList();
427
		getFilterControl().removeFocusListener(listener);
580
		if (list == null)
581
			return result;
582
		for (int i = 0; i < list.size(); i++) {
583
			if (filterText.getText() == "") //$NON-NLS-1$
584
				return result;
585
            String historyString = (String) list.get(i);
586
		    String typedString = wordsEntered;
587
		    if (historyString.toLowerCase().startsWith(typedString.toLowerCase()))
588
			    result.add(historyString);
589
		}
590
591
		return result;
428
	}
592
	}
429
593
430
	/**
594
	/**
431
	 * Focus has been lost on the filter control.
595
	 * Copy all elements from a list to a table
432
	 *
596
	 * 
597
	 * @param table
598
	 * @param list
433
	 */
599
	 */
434
	protected void filterFocusLost() {
600
	protected void updateTable(Table table, List list) {
601
		table.removeAll();
602
		if (list.size() > 0) {
603
			TableItem newItem;
604
			for (int i = 0; i < list.size(); i++) {
605
				newItem = new TableItem(table, SWT.NULL, i);
606
				newItem.setText((String) list.get(i));
607
608
			}
609
		}
610
611
	}
612
613
	/**
614
	 * Caculate and set the position and size of the popup shell
615
	 * @param parent
616
	 * @param textBounds
617
	 */
618
	public void setShellLocationAndSize(Composite parent, Rectangle  textBounds){
619
		
620
		//Caculate size of the popup shell
621
		int space = currentSeachTable.getItemHeight();
622
		int tableHeight = currentSeachTable
623
			    .getItemHeight()* currentSeachTable.getItemCount() + space;
624
		int tableWidth = textBounds.width;	
625
		shell.setSize(tableWidth,tableHeight);
626
		
627
		//Caculate x,y coordinator of the popup shell
628
		Point point = getDisplay().map(parent, null,
629
				textBounds.x, textBounds.y);	
630
		final int xCoord = point.x;
631
		final int yCoord = point.y + textBounds.height;
632
		
633
		final Point location = new Point(xCoord, yCoord);
634
		
635
		//Try to show whole popup shell through relocating its x and y coordinator
636
		final Display display = shell.getDisplay();		
637
		final Rectangle displayBounds = display.getClientArea();
638
		final int displayRightEdge = displayBounds.x + displayBounds.width;
435
		
639
		
640
		if (location.x <0) 
641
			location.x = 0;
642
		if ((location.x + tableWidth) > displayRightEdge) 
643
			location.x = displayRightEdge - tableWidth;
644
		
645
		final int displayBottomEdge = displayBounds.y + displayBounds.height;	
646
		if ((location.y + tableHeight) > displayBottomEdge)
647
			location.y = displayBottomEdge - tableHeight;
648
		
649
		// Set the location.
650
		shell.setLocation(location);		
651
	}
652
	/**
653
	 * Return a dialog setting section for this dialog
654
	 * 
655
	 * @return IDialogSettings
656
	 */
657
	
658
	
659
	private IDialogSettings getDialogSettings() {
660
		IDialogSettings settings = WorkbenchPlugin.getDefault()
661
				.getDialogSettings();
662
		IDialogSettings thisSettings = settings
663
				.getSection(getClass().getName());
664
		if (thisSettings == null)
665
			thisSettings = settings.addNewSection(getClass().getName());
666
667
		return thisSettings;
668
	}
669
670
	/**
671
	 * Get the preferences search history for this eclipse's start, Note that
672
	 * this history will not be cleared until this eclipse closes
673
	 * 
674
	 * @return a list
675
	 */
676
	public List getPreferenceSearchHistory() {
677
678
		List searchList = new ArrayList();
679
		IDialogSettings settings = getDialogSettings();
680
		String[] search = settings.getArray(SEARCHHISTORY); //$NON-NLS-1$
681
682
		if (search != null) {
683
			for (int i = 0; i < search.length; i++)
684
				searchList.add(search[i]);
685
		}
686
		return searchList;
687
436
	}
688
	}
689
690
	/**
691
	 * Saves the search history.
692
	 */
693
	private void saveDialogSettings() {
694
		IDialogSettings settings = getDialogSettings();
695
696
		// If the settings contains the same key, the previous value will be
697
		// replaced by new one
698
		String[] result = new String[searchHistory.size()];
699
		listToArray(searchHistory, result);
700
		settings.put(SEARCHHISTORY, result);
701
702
	}
703
	
704
	private void listToArray(List list, String[] string) {
705
		int size = list.size();
706
		for (int i = 0; i < size; i++)
707
			string[i] = (String) list.get(i);
708
	}	
437
	
709
	
438
}
710
}
(-)Eclipse UI/org/eclipse/ui/internal/dialogs/PreferenceBoldLabelProvider.java (-9 / +9 lines)
Lines 14-23 Link Here
14
		implements IFontProvider {
14
		implements IFontProvider {
15
15
16
	
16
	
17
	private FilteredTextTree comboTree;
17
	private FilteredTree filteredTree;
18
18
19
	PreferenceBoldLabelProvider(FilteredTextTree comboTree) {
19
	PreferenceBoldLabelProvider(FilteredTree theTree) {
20
		this.comboTree = comboTree;
20
		this.filteredTree = theTree;
21
	}
21
	}
22
	/**
22
	/**
23
	 * Using "false" to construct the filter so that this filter can filter
23
	 * Using "false" to construct the filter so that this filter can filter
Lines 27-50 Link Here
27
27
28
	public Font getFont(Object element) {
28
	public Font getFont(Object element) {
29
29
30
		String filterText = comboTree.getFilterControlText();
30
		String filterText = filteredTree.getFilterControlText();
31
31
32
		// Do nothing if it's empty string
32
		// Do nothing if it's empty string
33
		if (!(filterText.equals("") || filterText.equals(comboTree.getInitialText()))) {//$NON-NLS-1$
33
		if (!(filterText.equals("") || filterText.equals(filteredTree.getInitialText()))) {//$NON-NLS-1$
34
34
35
			boolean initial = comboTree.getInitialText() != null
35
			boolean initial = filteredTree.getInitialText() != null
36
					&& filterText.equals(comboTree.getInitialText());
36
					&& filterText.equals(filteredTree.getInitialText());
37
			if (initial) {
37
			if (initial) {
38
				filterForBoldElements.setPattern(null);
38
				filterForBoldElements.setPattern(null);
39
			} else {
39
			} else {
40
				filterForBoldElements.setPattern(filterText);
40
				filterForBoldElements.setPattern(filterText);
41
			}
41
			}
42
42
43
			ITreeContentProvider contentProvider = (ITreeContentProvider) comboTree.getViewer()
43
			ITreeContentProvider contentProvider = (ITreeContentProvider) filteredTree.getViewer()
44
					.getContentProvider();
44
					.getContentProvider();
45
			Object parent = contentProvider.getParent(element);
45
			Object parent = contentProvider.getParent(element);
46
46
47
			if (filterForBoldElements.select(comboTree.getViewer(), parent, element)) {
47
			if (filterForBoldElements.select(filteredTree.getViewer(), parent, element)) {
48
				return JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT);
48
				return JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT);
49
			}
49
			}
50
		}
50
		}
(-)Eclipse UI/org/eclipse/ui/internal/keys/NewKeysPreferencePage.java (-1 / +1 lines)
Line 1 Link Here
1
/*******************************************************************************
 * Copyright (c) 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 ******************************************************************************/

package org.eclipse.ui.internal.keys;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.ResourceBundle;
import java.util.Set;

import org.eclipse.core.commands.CommandManager;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.commands.contexts.ContextManager;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.bindings.Binding;
import org.eclipse.jface.bindings.BindingManager;
import org.eclipse.jface.bindings.Scheme;
import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.jface.bindings.keys.KeySequenceText;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.contexts.IContextIds;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.NamedHandleObjectLabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.dialogs.FilteredTextTree;
import org.eclipse.ui.internal.util.Util;
import org.eclipse.ui.keys.IBindingService;

/**
 * @since 3.1
 */
public final class NewKeysPreferencePage extends PreferencePage implements
		IWorkbenchPreferencePage {

	/**
	 * The resource bundle from which translations can be retrieved.
	 */
	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
			.getBundle(NewKeysPreferencePage.class.getName());

	private IBindingService bindingService = null;

	private IContextService contextService = null;

	/**
	 * A binding manager local to this preference page. When the page is
	 * initialized, the current bindings are read out from the binding service
	 * and placed in this manager. This manager is then updated as the user
	 * makes changes. When the user has finished, the contents of this manager
	 * are compared with the contents of the binding service. The changes are
	 * then persisted.
	 */
	private final BindingManager localChangeManager = new BindingManager(
			new ContextManager(), new CommandManager());

	private ComboViewer schemeCombo = null;

	private ComboViewer whenCombo = null;

	private final Control createButtonBar(final Composite parent) {
		GridLayout layout;
		GridData gridData;
		int widthHint;

		// Create the composite to house the button bar.
		final Composite buttonBar = new Composite(parent, SWT.NONE);
		layout = new GridLayout(1, false);
		layout.marginWidth = 0;
		buttonBar.setLayout(layout);
		gridData = new GridData();
		gridData.horizontalAlignment = SWT.END;
		buttonBar.setLayoutData(gridData);

		// Advanced button.
		final Button advancedButton = new Button(buttonBar, SWT.PUSH);
		gridData = new GridData();
		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
		advancedButton.setText(Util.translateString(RESOURCE_BUNDLE,
				"advancedButton.Text")); //$NON-NLS-1$
		gridData.widthHint = Math.max(widthHint, advancedButton.computeSize(
				SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
		advancedButton.setLayoutData(gridData);

		return buttonBar;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
	 */
	protected final Control createContents(final Composite parent) {
		GridData gridData = null;
		GridLayout layout = null;
		int widthHint;

		// Creates a composite to hold all of the page contents.
		final Composite page = new Composite(parent, SWT.NONE);
		layout = new GridLayout(1, false);
		layout.marginWidth = 0;
		page.setLayout(layout);

		createSchemeControls(page);
		createTree(page);
		createTreeControls(page);
		createDataControls(page);
		createButtonBar(page);

		update(true);

		return page;
	}

	private final Control createDataControls(final Composite parent) {
		GridLayout layout;
		GridData gridData;

		// Creates the data area.
		final Composite dataArea = new Composite(parent, SWT.NONE);
		layout = new GridLayout(5, false);
		layout.marginWidth = 0;
		dataArea.setLayout(layout);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		dataArea.setLayoutData(gridData);

		// FIRST ROW
		// The command name label.
		final Label commandNameLabel = new Label(dataArea, SWT.NONE);
		commandNameLabel.setText(Util.translateString(RESOURCE_BUNDLE,
				"commandNameLabel.Text")); //$NON-NLS-1$); //$NON-NLS-1$

		// The current command name.
		final Label commandNameValueLabel = new Label(dataArea, SWT.NONE);
		// TODO This should be update dynamically
		commandNameValueLabel.setText("Word Completion"); //$NON-NLS-1$
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.horizontalAlignment = SWT.BEGINNING;
		commandNameValueLabel.setLayoutData(gridData);

		// The binding label.
		final Label bindingLabel = new Label(dataArea, SWT.NONE);
		bindingLabel.setText(Util.translateString(RESOURCE_BUNDLE,
				"bindingLabel.Text")); //$NON-NLS-1$

		// The key sequence entry widget.
		final Text bindingText = new Text(dataArea, SWT.BORDER);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.widthHint = 300;
		bindingText.setLayoutData(gridData);
		final KeySequenceText keySequenceText = new KeySequenceText(bindingText);
		try {
			keySequenceText.setKeySequence(KeySequence.getInstance("ALT+/")); //$NON-NLS-1$
		} catch (final ParseException e) {
			// TODO This should be done dynamically.
		}
		keySequenceText.setKeyStrokeLimit(4);

		// Button for adding trapped key strokes
		final Button addKeyButton = new Button(dataArea, SWT.LEFT | SWT.ARROW);
		addKeyButton.setToolTipText(Util.translateString(RESOURCE_BUNDLE,
				"addKeyButton.ToolTipText")); //$NON-NLS-1$
		gridData = new GridData();
		gridData.heightHint = schemeCombo.getCombo().getTextHeight();
		addKeyButton.setLayoutData(gridData);

		// Arrow buttons aren't normally added to the tab list. Let's fix that.
		final Control[] tabStops = dataArea.getTabList();
		final ArrayList newTabStops = new ArrayList();
		for (int i = 0; i < tabStops.length; i++) {
			Control tabStop = tabStops[i];
			newTabStops.add(tabStop);
			if (bindingText.equals(tabStop)) {
				newTabStops.add(addKeyButton);
			}
		}
		final Control[] newTabStopArray = (Control[]) newTabStops
				.toArray(new Control[newTabStops.size()]);
		dataArea.setTabList(newTabStopArray);

		// Construct the menu to attach to the above button.
		final Menu addKeyMenu = new Menu(addKeyButton);
		final Iterator trappedKeyItr = KeySequenceText.TRAPPED_KEYS.iterator();
		while (trappedKeyItr.hasNext()) {
			final KeyStroke trappedKey = (KeyStroke) trappedKeyItr.next();
			final MenuItem menuItem = new MenuItem(addKeyMenu, SWT.PUSH);
			menuItem.setText(trappedKey.format());
			menuItem.addSelectionListener(new SelectionAdapter() {

				public void widgetSelected(SelectionEvent e) {
					keySequenceText.insert(trappedKey);
					bindingText.setFocus();
					bindingText.setSelection(bindingText.getTextLimit());
				}
			});
		}
		addKeyButton.addSelectionListener(new SelectionAdapter() {

			public void widgetSelected(SelectionEvent selectionEvent) {
				Point buttonLocation = addKeyButton.getLocation();
				buttonLocation = dataArea.toDisplay(buttonLocation.x,
						buttonLocation.y);
				Point buttonSize = addKeyButton.getSize();
				addKeyMenu.setLocation(buttonLocation.x, buttonLocation.y
						+ buttonSize.y);
				addKeyMenu.setVisible(true);
			}
		});

		// SECOND ROW.
		// The description label.
		final Label descriptionLabel = new Label(dataArea, SWT.NONE);
		descriptionLabel.setText(Util.translateString(RESOURCE_BUNDLE,
				"descriptionLabel.Text")); //$NON-NLS-1$
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.horizontalSpan = 2;
		descriptionLabel.setLayoutData(gridData);

		// The when label.
		final Label whenLabel = new Label(dataArea, SWT.NONE);
		whenLabel.setText(Util.translateString(RESOURCE_BUNDLE,
				"whenLabel.Text")); //$NON-NLS-1$

		// The when combo.
		whenCombo = new ComboViewer(dataArea);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.horizontalSpan = 2;
		whenCombo.getCombo().setLayoutData(gridData);
		whenCombo.setLabelProvider(new NamedHandleObjectLabelProvider());
		whenCombo.setContentProvider(new ArrayContentProvider());

		// THIRD ROW.
		// The description value.
		final Label descriptionValueLabel = new Label(dataArea, SWT.WRAP);
		// TODO This value should be updated dynamically.
		descriptionValueLabel.setText("Context insensitive completion"); //$NON-NLS-1$
		gridData = new GridData();
		gridData.horizontalSpan = 5;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalIndent = 30;
		gridData.verticalIndent = 5;
		descriptionValueLabel.setLayoutData(gridData);

		return dataArea;
	}

	private final Control createSchemeControls(final Composite parent) {
		GridLayout layout;
		GridData gridData;
		int widthHint;

		// Create a composite to hold the controls.
		final Composite schemeControls = new Composite(parent, SWT.NONE);
		layout = new GridLayout(3, false);
		layout.marginWidth = 0;
		schemeControls.setLayout(layout);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		schemeControls.setLayoutData(gridData);

		// Create the label.
		final Label schemeLabel = new Label(schemeControls, SWT.NONE);
		schemeLabel.setText(Util.translateString(RESOURCE_BUNDLE,
				"schemeLabel.Text")); //$NON-NLS-1$

		// Create the combo.
		schemeCombo = new ComboViewer(schemeControls);
		schemeCombo.setLabelProvider(new NamedHandleObjectLabelProvider());
		schemeCombo.setContentProvider(new ArrayContentProvider());
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		schemeCombo.getCombo().setLayoutData(gridData);

		// Create the delete button.
		final Button deleteSchemeButton = new Button(schemeControls, SWT.PUSH);
		gridData = new GridData();
		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
		deleteSchemeButton.setText(Util.translateString(RESOURCE_BUNDLE,
				"deleteSchemeButton.Text")); //$NON-NLS-1$
		gridData.widthHint = Math.max(widthHint, deleteSchemeButton
				.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
		deleteSchemeButton.setLayoutData(gridData);

		return schemeControls;
	}

	private final Control createTree(final Composite parent) {
		GridData gridData;

		// Creates the filtered tree.
		final FilteredTextTree filteredTree = new FilteredTextTree(parent,
				SWT.SINGLE | SWT.FULL_SELECTION);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.verticalAlignment = SWT.FILL;
		filteredTree.setLayoutData(gridData);

		return filteredTree;
	}

	private final Control createTreeControls(final Composite parent) {
		GridLayout layout;
		GridData gridData;
		int widthHint;

		// Creates controls related to the tree.
		final Composite treeControls = new Composite(parent, SWT.NONE);
		layout = new GridLayout(2, false);
		layout.marginWidth = 0;
		treeControls.setLayout(layout);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		treeControls.setLayoutData(gridData);

		// Create the show all check box.
		final Button showAllCheckBox = new Button(treeControls, SWT.CHECK);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		showAllCheckBox.setLayoutData(gridData);
		showAllCheckBox.setText(Util.translateString(RESOURCE_BUNDLE,
				"showAllCheckBox.Text")); //$NON-NLS-1$

		// Create the delete binding button.
		final Button deleteBindingButton = new Button(treeControls, SWT.PUSH);
		gridData = new GridData();
		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
		deleteBindingButton.setText(Util.translateString(RESOURCE_BUNDLE,
				"deleteBindingButton.Text")); //$NON-NLS-1$
		gridData.widthHint = Math.max(widthHint, deleteBindingButton
				.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
		deleteBindingButton.setLayoutData(gridData);

		return treeControls;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
	 */
	public final void init(final IWorkbench workbench) {
		bindingService = (IBindingService) workbench
				.getAdapter(IBindingService.class);
		contextService = (IContextService) workbench
				.getAdapter(IContextService.class);
	}

	/**
	 * Logs the given exception, and opens an error dialog saying that something
	 * went wrong. The exception is assumed to have something to do with the
	 * preference store.
	 * 
	 * @param exception
	 *            The exception to be logged; must not be <code>null</code>.
	 */
	private final void logPreferenceStoreException(final Throwable exception) {
		final String message = Util.translateString(RESOURCE_BUNDLE,
				"PreferenceStoreError.Message"); //$NON-NLS-1$
		final String title = Util.translateString(RESOURCE_BUNDLE,
				"PreferenceStoreError.Title"); //$NON-NLS-1$
		String exceptionMessage = exception.getMessage();
		if (exceptionMessage == null) {
			exceptionMessage = message;
		}
		final IStatus status = new Status(IStatus.ERROR,
				WorkbenchPlugin.PI_WORKBENCH, 0, exceptionMessage, exception);
		WorkbenchPlugin.log(message, status);
		ErrorDialog.openError(schemeCombo.getCombo().getShell(), title,
				message, status);
	}

	protected final void performDefaults() {
		// Ask the user to confirm
		final String title = Util.translateString(RESOURCE_BUNDLE,
				"restoreDefaultsMessageBoxText"); //$NON-NLS-1$
		final String message = Util.translateString(RESOURCE_BUNDLE,
				"restoreDefaultsMessageBoxMessage"); //$NON-NLS-1$
		final boolean confirmed = MessageDialog.openConfirm(getShell(), title,
				message);

		if (confirmed) {
			// Fix the scheme in the local changes.
			final String defaultSchemeId = bindingService.getDefaultSchemeId();
			final Scheme defaultScheme = localChangeManager
					.getScheme(defaultSchemeId);
			try {
				localChangeManager.setActiveScheme(defaultScheme);
			} catch (final NotDefinedException e) {
				// At least we tried....
			}

			// Fix the bindings in the local changes.
			final Binding[] currentBindings = localChangeManager.getBindings();
			final int currentBindingsLength = currentBindings.length;
			final Set trimmedBindings = new HashSet();
			for (int i = 0; i < currentBindingsLength; i++) {
				final Binding binding = currentBindings[i];
				if (binding.getType() != Binding.USER) {
					trimmedBindings.add(binding);
				}
			}
			final Binding[] trimmedBindingArray = (Binding[]) trimmedBindings
					.toArray(new Binding[trimmedBindings.size()]);
			localChangeManager.setBindings(trimmedBindingArray);

			// Apply the changes.
			try {
				bindingService.savePreferences(defaultScheme,
						trimmedBindingArray);
			} catch (final IOException e) {
				logPreferenceStoreException(e);
			}
		}

		setScheme(localChangeManager.getActiveScheme());
		super.performDefaults();
	}

	public final boolean performOk() {
		// Save the preferences.
		try {
			bindingService.savePreferences(
					localChangeManager.getActiveScheme(), localChangeManager
							.getBindings());
		} catch (final IOException e) {
			logPreferenceStoreException(e);
		}

		return super.performOk();
	}

	/**
	 * Sets the currently selected scheme.  Setting the scheme always triggers
	 * an update of the underlying widgets.
	 * 
	 * @param scheme
	 *            The scheme to select; may be <code>null</code>.
	 */
	private final void setScheme(final Scheme scheme) {
		schemeCombo.setSelection(new StructuredSelection(scheme));
	}

	private final void update(final boolean registryChanged) {
		updateSchemeCombo(registryChanged);
		updateWhenCombo(registryChanged);
	}

	private final void updateSchemeCombo(final boolean registryChanged) {
		if (registryChanged) {
			// TODO This should be sorted alphabetically.
			schemeCombo.setInput(bindingService.getDefinedSchemes());
			setScheme(bindingService.getActiveScheme());
		}
	}

	private final void updateWhenCombo(final boolean registryChanged) {
		if (registryChanged) {
			// TODO This should be sorted alphabetically.
			whenCombo.setInput(contextService.getDefinedContexts());
			// TODO This should be updated based on the active context/
			whenCombo.setSelection(new StructuredSelection(contextService
					.getContext(IContextIds.CONTEXT_ID_WINDOW)), true);
		}
	}
}
1
/*******************************************************************************
 * Copyright (c) 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 ******************************************************************************/

package org.eclipse.ui.internal.keys;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.ResourceBundle;
import java.util.Set;

import org.eclipse.core.commands.CommandManager;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.commands.contexts.ContextManager;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.bindings.Binding;
import org.eclipse.jface.bindings.BindingManager;
import org.eclipse.jface.bindings.Scheme;
import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.jface.bindings.keys.KeySequenceText;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.contexts.IContextIds;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.NamedHandleObjectLabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.dialogs.FilteredTree;
import org.eclipse.ui.internal.util.Util;
import org.eclipse.ui.keys.IBindingService;

/**
 * @since 3.1
 */
public final class NewKeysPreferencePage extends PreferencePage implements
		IWorkbenchPreferencePage {

	/**
	 * The resource bundle from which translations can be retrieved.
	 */
	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
			.getBundle(NewKeysPreferencePage.class.getName());

	private IBindingService bindingService = null;

	private IContextService contextService = null;

	/**
	 * A binding manager local to this preference page. When the page is
	 * initialized, the current bindings are read out from the binding service
	 * and placed in this manager. This manager is then updated as the user
	 * makes changes. When the user has finished, the contents of this manager
	 * are compared with the contents of the binding service. The changes are
	 * then persisted.
	 */
	private final BindingManager localChangeManager = new BindingManager(
			new ContextManager(), new CommandManager());

	private ComboViewer schemeCombo = null;

	private ComboViewer whenCombo = null;

	private final Control createButtonBar(final Composite parent) {
		GridLayout layout;
		GridData gridData;
		int widthHint;

		// Create the composite to house the button bar.
		final Composite buttonBar = new Composite(parent, SWT.NONE);
		layout = new GridLayout(1, false);
		layout.marginWidth = 0;
		buttonBar.setLayout(layout);
		gridData = new GridData();
		gridData.horizontalAlignment = SWT.END;
		buttonBar.setLayoutData(gridData);

		// Advanced button.
		final Button advancedButton = new Button(buttonBar, SWT.PUSH);
		gridData = new GridData();
		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
		advancedButton.setText(Util.translateString(RESOURCE_BUNDLE,
				"advancedButton.Text")); //$NON-NLS-1$
		gridData.widthHint = Math.max(widthHint, advancedButton.computeSize(
				SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
		advancedButton.setLayoutData(gridData);

		return buttonBar;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
	 */
	protected final Control createContents(final Composite parent) {
		GridData gridData = null;
		GridLayout layout = null;
		int widthHint;

		// Creates a composite to hold all of the page contents.
		final Composite page = new Composite(parent, SWT.NONE);
		layout = new GridLayout(1, false);
		layout.marginWidth = 0;
		page.setLayout(layout);

		createSchemeControls(page);
		createTree(page);
		createTreeControls(page);
		createDataControls(page);
		createButtonBar(page);

		update(true);

		return page;
	}

	private final Control createDataControls(final Composite parent) {
		GridLayout layout;
		GridData gridData;

		// Creates the data area.
		final Composite dataArea = new Composite(parent, SWT.NONE);
		layout = new GridLayout(5, false);
		layout.marginWidth = 0;
		dataArea.setLayout(layout);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		dataArea.setLayoutData(gridData);

		// FIRST ROW
		// The command name label.
		final Label commandNameLabel = new Label(dataArea, SWT.NONE);
		commandNameLabel.setText(Util.translateString(RESOURCE_BUNDLE,
				"commandNameLabel.Text")); //$NON-NLS-1$); //$NON-NLS-1$

		// The current command name.
		final Label commandNameValueLabel = new Label(dataArea, SWT.NONE);
		// TODO This should be update dynamically
		commandNameValueLabel.setText("Word Completion"); //$NON-NLS-1$
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.horizontalAlignment = SWT.BEGINNING;
		commandNameValueLabel.setLayoutData(gridData);

		// The binding label.
		final Label bindingLabel = new Label(dataArea, SWT.NONE);
		bindingLabel.setText(Util.translateString(RESOURCE_BUNDLE,
				"bindingLabel.Text")); //$NON-NLS-1$

		// The key sequence entry widget.
		final Text bindingText = new Text(dataArea, SWT.BORDER);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.widthHint = 300;
		bindingText.setLayoutData(gridData);
		final KeySequenceText keySequenceText = new KeySequenceText(bindingText);
		try {
			keySequenceText.setKeySequence(KeySequence.getInstance("ALT+/")); //$NON-NLS-1$
		} catch (final ParseException e) {
			// TODO This should be done dynamically.
		}
		keySequenceText.setKeyStrokeLimit(4);

		// Button for adding trapped key strokes
		final Button addKeyButton = new Button(dataArea, SWT.LEFT | SWT.ARROW);
		addKeyButton.setToolTipText(Util.translateString(RESOURCE_BUNDLE,
				"addKeyButton.ToolTipText")); //$NON-NLS-1$
		gridData = new GridData();
		gridData.heightHint = schemeCombo.getCombo().getTextHeight();
		addKeyButton.setLayoutData(gridData);

		// Arrow buttons aren't normally added to the tab list. Let's fix that.
		final Control[] tabStops = dataArea.getTabList();
		final ArrayList newTabStops = new ArrayList();
		for (int i = 0; i < tabStops.length; i++) {
			Control tabStop = tabStops[i];
			newTabStops.add(tabStop);
			if (bindingText.equals(tabStop)) {
				newTabStops.add(addKeyButton);
			}
		}
		final Control[] newTabStopArray = (Control[]) newTabStops
				.toArray(new Control[newTabStops.size()]);
		dataArea.setTabList(newTabStopArray);

		// Construct the menu to attach to the above button.
		final Menu addKeyMenu = new Menu(addKeyButton);
		final Iterator trappedKeyItr = KeySequenceText.TRAPPED_KEYS.iterator();
		while (trappedKeyItr.hasNext()) {
			final KeyStroke trappedKey = (KeyStroke) trappedKeyItr.next();
			final MenuItem menuItem = new MenuItem(addKeyMenu, SWT.PUSH);
			menuItem.setText(trappedKey.format());
			menuItem.addSelectionListener(new SelectionAdapter() {

				public void widgetSelected(SelectionEvent e) {
					keySequenceText.insert(trappedKey);
					bindingText.setFocus();
					bindingText.setSelection(bindingText.getTextLimit());
				}
			});
		}
		addKeyButton.addSelectionListener(new SelectionAdapter() {

			public void widgetSelected(SelectionEvent selectionEvent) {
				Point buttonLocation = addKeyButton.getLocation();
				buttonLocation = dataArea.toDisplay(buttonLocation.x,
						buttonLocation.y);
				Point buttonSize = addKeyButton.getSize();
				addKeyMenu.setLocation(buttonLocation.x, buttonLocation.y
						+ buttonSize.y);
				addKeyMenu.setVisible(true);
			}
		});

		// SECOND ROW.
		// The description label.
		final Label descriptionLabel = new Label(dataArea, SWT.NONE);
		descriptionLabel.setText(Util.translateString(RESOURCE_BUNDLE,
				"descriptionLabel.Text")); //$NON-NLS-1$
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.horizontalSpan = 2;
		descriptionLabel.setLayoutData(gridData);

		// The when label.
		final Label whenLabel = new Label(dataArea, SWT.NONE);
		whenLabel.setText(Util.translateString(RESOURCE_BUNDLE,
				"whenLabel.Text")); //$NON-NLS-1$

		// The when combo.
		whenCombo = new ComboViewer(dataArea);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.horizontalSpan = 2;
		whenCombo.getCombo().setLayoutData(gridData);
		whenCombo.setLabelProvider(new NamedHandleObjectLabelProvider());
		whenCombo.setContentProvider(new ArrayContentProvider());

		// THIRD ROW.
		// The description value.
		final Label descriptionValueLabel = new Label(dataArea, SWT.WRAP);
		// TODO This value should be updated dynamically.
		descriptionValueLabel.setText("Context insensitive completion"); //$NON-NLS-1$
		gridData = new GridData();
		gridData.horizontalSpan = 5;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalIndent = 30;
		gridData.verticalIndent = 5;
		descriptionValueLabel.setLayoutData(gridData);

		return dataArea;
	}

	private final Control createSchemeControls(final Composite parent) {
		GridLayout layout;
		GridData gridData;
		int widthHint;

		// Create a composite to hold the controls.
		final Composite schemeControls = new Composite(parent, SWT.NONE);
		layout = new GridLayout(3, false);
		layout.marginWidth = 0;
		schemeControls.setLayout(layout);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		schemeControls.setLayoutData(gridData);

		// Create the label.
		final Label schemeLabel = new Label(schemeControls, SWT.NONE);
		schemeLabel.setText(Util.translateString(RESOURCE_BUNDLE,
				"schemeLabel.Text")); //$NON-NLS-1$

		// Create the combo.
		schemeCombo = new ComboViewer(schemeControls);
		schemeCombo.setLabelProvider(new NamedHandleObjectLabelProvider());
		schemeCombo.setContentProvider(new ArrayContentProvider());
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		schemeCombo.getCombo().setLayoutData(gridData);

		// Create the delete button.
		final Button deleteSchemeButton = new Button(schemeControls, SWT.PUSH);
		gridData = new GridData();
		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
		deleteSchemeButton.setText(Util.translateString(RESOURCE_BUNDLE,
				"deleteSchemeButton.Text")); //$NON-NLS-1$
		gridData.widthHint = Math.max(widthHint, deleteSchemeButton
				.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
		deleteSchemeButton.setLayoutData(gridData);

		return schemeControls;
	}

	private final Control createTree(final Composite parent) {
		GridData gridData;

		// Creates the filtered tree.
		final FilteredTree filteredTree = new FilteredTree(parent,
				SWT.SINGLE | SWT.FULL_SELECTION);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		gridData.verticalAlignment = SWT.FILL;
		filteredTree.setLayoutData(gridData);

		return filteredTree;
	}

	private final Control createTreeControls(final Composite parent) {
		GridLayout layout;
		GridData gridData;
		int widthHint;

		// Creates controls related to the tree.
		final Composite treeControls = new Composite(parent, SWT.NONE);
		layout = new GridLayout(2, false);
		layout.marginWidth = 0;
		treeControls.setLayout(layout);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		treeControls.setLayoutData(gridData);

		// Create the show all check box.
		final Button showAllCheckBox = new Button(treeControls, SWT.CHECK);
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = SWT.FILL;
		showAllCheckBox.setLayoutData(gridData);
		showAllCheckBox.setText(Util.translateString(RESOURCE_BUNDLE,
				"showAllCheckBox.Text")); //$NON-NLS-1$

		// Create the delete binding button.
		final Button deleteBindingButton = new Button(treeControls, SWT.PUSH);
		gridData = new GridData();
		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
		deleteBindingButton.setText(Util.translateString(RESOURCE_BUNDLE,
				"deleteBindingButton.Text")); //$NON-NLS-1$
		gridData.widthHint = Math.max(widthHint, deleteBindingButton
				.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
		deleteBindingButton.setLayoutData(gridData);

		return treeControls;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
	 */
	public final void init(final IWorkbench workbench) {
		bindingService = (IBindingService) workbench
				.getAdapter(IBindingService.class);
		contextService = (IContextService) workbench
				.getAdapter(IContextService.class);
	}

	/**
	 * Logs the given exception, and opens an error dialog saying that something
	 * went wrong. The exception is assumed to have something to do with the
	 * preference store.
	 * 
	 * @param exception
	 *            The exception to be logged; must not be <code>null</code>.
	 */
	private final void logPreferenceStoreException(final Throwable exception) {
		final String message = Util.translateString(RESOURCE_BUNDLE,
				"PreferenceStoreError.Message"); //$NON-NLS-1$
		final String title = Util.translateString(RESOURCE_BUNDLE,
				"PreferenceStoreError.Title"); //$NON-NLS-1$
		String exceptionMessage = exception.getMessage();
		if (exceptionMessage == null) {
			exceptionMessage = message;
		}
		final IStatus status = new Status(IStatus.ERROR,
				WorkbenchPlugin.PI_WORKBENCH, 0, exceptionMessage, exception);
		WorkbenchPlugin.log(message, status);
		ErrorDialog.openError(schemeCombo.getCombo().getShell(), title,
				message, status);
	}

	protected final void performDefaults() {
		// Ask the user to confirm
		final String title = Util.translateString(RESOURCE_BUNDLE,
				"restoreDefaultsMessageBoxText"); //$NON-NLS-1$
		final String message = Util.translateString(RESOURCE_BUNDLE,
				"restoreDefaultsMessageBoxMessage"); //$NON-NLS-1$
		final boolean confirmed = MessageDialog.openConfirm(getShell(), title,
				message);

		if (confirmed) {
			// Fix the scheme in the local changes.
			final String defaultSchemeId = bindingService.getDefaultSchemeId();
			final Scheme defaultScheme = localChangeManager
					.getScheme(defaultSchemeId);
			try {
				localChangeManager.setActiveScheme(defaultScheme);
			} catch (final NotDefinedException e) {
				// At least we tried....
			}

			// Fix the bindings in the local changes.
			final Binding[] currentBindings = localChangeManager.getBindings();
			final int currentBindingsLength = currentBindings.length;
			final Set trimmedBindings = new HashSet();
			for (int i = 0; i < currentBindingsLength; i++) {
				final Binding binding = currentBindings[i];
				if (binding.getType() != Binding.USER) {
					trimmedBindings.add(binding);
				}
			}
			final Binding[] trimmedBindingArray = (Binding[]) trimmedBindings
					.toArray(new Binding[trimmedBindings.size()]);
			localChangeManager.setBindings(trimmedBindingArray);

			// Apply the changes.
			try {
				bindingService.savePreferences(defaultScheme,
						trimmedBindingArray);
			} catch (final IOException e) {
				logPreferenceStoreException(e);
			}
		}

		setScheme(localChangeManager.getActiveScheme());
		super.performDefaults();
	}

	public final boolean performOk() {
		// Save the preferences.
		try {
			bindingService.savePreferences(
					localChangeManager.getActiveScheme(), localChangeManager
							.getBindings());
		} catch (final IOException e) {
			logPreferenceStoreException(e);
		}

		return super.performOk();
	}

	/**
	 * Sets the currently selected scheme.  Setting the scheme always triggers
	 * an update of the underlying widgets.
	 * 
	 * @param scheme
	 *            The scheme to select; may be <code>null</code>.
	 */
	private final void setScheme(final Scheme scheme) {
		schemeCombo.setSelection(new StructuredSelection(scheme));
	}

	private final void update(final boolean registryChanged) {
		updateSchemeCombo(registryChanged);
		updateWhenCombo(registryChanged);
	}

	private final void updateSchemeCombo(final boolean registryChanged) {
		if (registryChanged) {
			// TODO This should be sorted alphabetically.
			schemeCombo.setInput(bindingService.getDefinedSchemes());
			setScheme(bindingService.getActiveScheme());
		}
	}

	private final void updateWhenCombo(final boolean registryChanged) {
		if (registryChanged) {
			// TODO This should be sorted alphabetically.
			whenCombo.setInput(contextService.getDefinedContexts());
			// TODO This should be updated based on the active context/
			whenCombo.setSelection(new StructuredSelection(contextService
					.getContext(IContextIds.CONTEXT_ID_WINDOW)), true);
		}
	}
}

Return to bug 102081