1 /*******************************************************************************
2 * Copyright (c) 2002, 2008 QNX Software Systems 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
9 * QNX Software Systems - Initial API and implementation
10 * IBM Corporation - initial API and implementation
11 *******************************************************************************/
13 package org.eclipse.cdt.internal.ui.preferences;
16 import java.util.HashSet;
18 import java.util.SortedMap;
19 import java.util.TreeMap;
20 import java.util.Map.Entry;
22 import org.eclipse.core.resources.IPathVariableManager;
23 import org.eclipse.core.resources.IResource;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IPath;
26 import org.eclipse.core.runtime.Path;
27 import org.eclipse.jface.dialogs.Dialog;
28 import org.eclipse.jface.dialogs.ErrorDialog;
29 import org.eclipse.jface.dialogs.IDialogConstants;
30 import org.eclipse.jface.resource.ImageDescriptor;
31 import org.eclipse.jface.window.Window;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.events.SelectionAdapter;
34 import org.eclipse.swt.events.SelectionEvent;
35 import org.eclipse.swt.graphics.Font;
36 import org.eclipse.swt.graphics.FontMetrics;
37 import org.eclipse.swt.graphics.GC;
38 import org.eclipse.swt.graphics.Image;
39 import org.eclipse.swt.layout.GridData;
40 import org.eclipse.swt.layout.GridLayout;
41 import org.eclipse.swt.widgets.Button;
42 import org.eclipse.swt.widgets.Composite;
43 import org.eclipse.swt.widgets.Control;
44 import org.eclipse.swt.widgets.Event;
45 import org.eclipse.swt.widgets.Label;
46 import org.eclipse.swt.widgets.Listener;
47 import org.eclipse.swt.widgets.Shell;
48 import org.eclipse.swt.widgets.Table;
49 import org.eclipse.swt.widgets.TableItem;
50 import org.eclipse.ui.ISharedImages;
51 import org.eclipse.ui.PlatformUI;
53 import org.eclipse.cdt.core.CCorePlugin;
54 import org.eclipse.cdt.core.resources.IPathEntryVariableManager;
56 import org.eclipse.cdt.internal.ui.CPluginImages;
59 * @deprecated in CDT 8.0. This class appears to be never used.
62 public class PathEntryVariablesGroup {
65 * Simple data structure that holds a path variable name/value pair.
67 public static class PathEntryVariableElement {
74 private static final int SIZING_SELECTION_PANE_WIDTH = 400;
79 private Label variableLabel;
81 private Table variableTable;
83 private Button addButton;
85 private Button editButton;
87 private Button removeButton;
89 // used to compute layout sizes
90 private FontMetrics fontMetrics;
92 // create a multi select table
93 private boolean multiSelect;
95 // IResource.FILE and/or IResource.FOLDER
96 private int variableType;
98 // External listener called when the table selection changes
99 protected Listener selectionListener;
101 // temporary collection for keeping currently defined variables
102 private SortedMap<String, IPath> tempPathVariables;
104 // set of removed variables' names
105 private Set<String> removedVariableNames;
107 // reference to the workspace's path variable manager
108 private IPathEntryVariableManager pathEntryVariableManager;
111 private final Image FILE_IMG = PlatformUI.getWorkbench().getSharedImages()
112 .getImage(ISharedImages.IMG_OBJ_FILE);
115 private final Image FOLDER_IMG = PlatformUI.getWorkbench()
116 .getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER);
118 // unknown (non-existent) image. created locally, dispose locally
119 private Image imageUnkown;
122 * Creates a new PathVariablesGroup.
124 * @param multiSelect create a multi select tree
125 * @param variableType the type of variables that are displayed in
126 * the widget group. <code>IResource.FILE</code> and/or <code>IResource.FOLDER</code>
127 * logically ORed together.
129 public PathEntryVariablesGroup(boolean multiSelect, int variableType) {
130 this.multiSelect = multiSelect;
131 this.variableType = variableType;
132 pathEntryVariableManager = CCorePlugin.getDefault().getPathEntryVariableManager();
133 removedVariableNames = new HashSet<String>();
134 tempPathVariables = new TreeMap<String, IPath>();
135 // initialize internal model
136 initTemporaryState();
140 * Creates a new PathVariablesGroup.
142 * @param multiSelect create a multi select tree
143 * @param variableType the type of variables that are displayed in
144 * the widget group. <code>IResource.FILE</code> and/or <code>IResource.FOLDER</code>
145 * logically ORed together.
146 * @param selectionListener listener notified when the selection changes
147 * in the variables list.
149 public PathEntryVariablesGroup(boolean multiSelect, int variableType,
150 Listener selectionListener) {
151 this(multiSelect, variableType);
152 this.selectionListener = selectionListener;
156 * Opens a dialog for creating a new variable.
158 protected void addNewVariable() {
159 // constructs a dialog for editing the new variable's current name and value
160 PathEntryVariableDialog dialog = new PathEntryVariableDialog(shell,
161 PathEntryVariableDialog.NEW_VARIABLE, variableType, tempPathVariables.keySet());
163 // opens the dialog - just returns if the user cancels it
164 if (dialog.open() == Window.CANCEL)
167 // otherwise, adds the new variable (or updates an existing one) in the
168 // temporary collection of currently defined variables
169 String newVariableName = dialog.getVariableName();
170 IPath newVariableValue = new Path(dialog.getVariableValue());
171 tempPathVariables.put(newVariableName, newVariableValue);
173 // the UI must be updated
174 updateWidgetState(newVariableName);
178 * Creates the widget group.
179 * Callers must call <code>dispose</code> when the group is no
182 * @param parent the widget parent
183 * @return container of the widgets
185 public Control createContents(Composite parent) {
186 Font font = parent.getFont();
188 if (imageUnkown == null) {
189 ImageDescriptor descriptor = CPluginImages.DESC_OVR_WARNING;
190 imageUnkown = descriptor.createImage();
192 initializeDialogUnits(parent);
193 shell = parent.getShell();
195 // define container & its layout
196 Composite pageComponent = new Composite(parent, SWT.NULL);
197 GridLayout layout = new GridLayout();
198 layout.numColumns = 2;
199 layout.marginWidth = 0;
200 layout.marginHeight = 0;
201 pageComponent.setLayout(layout);
202 GridData data = new GridData(GridData.FILL_BOTH);
203 data.widthHint = SIZING_SELECTION_PANE_WIDTH;
204 pageComponent.setLayoutData(data);
205 pageComponent.setFont(font);
207 // layout the table & its buttons
208 variableLabel = new Label(pageComponent, SWT.LEFT);
209 variableLabel.setText(PreferencesMessages.PathEntryVariablesBlock_variablesLabel);
210 data = new GridData();
211 data.horizontalAlignment = GridData.FILL;
212 data.horizontalSpan = 2;
213 variableLabel.setLayoutData(data);
214 variableLabel.setFont(font);
216 int tableStyle = SWT.BORDER | SWT.FULL_SELECTION;
218 tableStyle |= SWT.MULTI;
220 variableTable = new Table(pageComponent, tableStyle);
221 variableTable.addSelectionListener(new SelectionAdapter() {
223 public void widgetSelected(SelectionEvent e) {
224 updateEnabledState();
225 if (selectionListener != null)
226 selectionListener.handleEvent(new Event());
229 data = new GridData(GridData.FILL_BOTH);
230 data.heightHint = variableTable.getItemHeight() * 7;
231 variableTable.setLayoutData(data);
232 variableTable.setFont(font);
234 createButtonGroup(pageComponent);
235 // populate table with current internal state and set buttons' initial state
236 updateWidgetState(null);
238 return pageComponent;
242 * Disposes the group's resources.
244 public void dispose() {
245 if (imageUnkown != null) {
246 imageUnkown.dispose();
252 * Opens a dialog for editing an existing variable.
254 * @see PathEntryVariableDialog
256 protected void editSelectedVariable() {
257 // retrieves the name and value for the currently selected variable
258 TableItem item = variableTable.getItem(variableTable
259 .getSelectionIndex());
260 String variableName = (String) item.getData();
261 IPath variableValue = tempPathVariables.get(variableName);
263 // constructs a dialog for editing the variable's current name and value
264 PathEntryVariableDialog dialog = new PathEntryVariableDialog(shell,
265 PathEntryVariableDialog.EXISTING_VARIABLE, variableType, tempPathVariables.keySet());
266 dialog.setVariableName(variableName);
267 dialog.setVariableValue(variableValue.toOSString());
269 // opens the dialog - just returns if the user cancels it
270 if (dialog.open() == Window.CANCEL)
273 // the name can be changed, so we remove the current variable definition...
274 removedVariableNames.add(variableName);
275 tempPathVariables.remove(variableName);
277 String newVariableName = dialog.getVariableName();
278 IPath newVariableValue = new Path(dialog.getVariableValue());
280 // and add it again (maybe with a different name)
281 tempPathVariables.put(newVariableName, newVariableValue);
283 // now we must refresh the UI state
284 updateWidgetState(newVariableName);
289 * Returns the enabled state of the group's widgets.
290 * Returns <code>true</code> if called prior to calling
291 * <code>createContents</code>.
293 * @return boolean the enabled state of the group's widgets.
294 * <code>true</code> if called prior to calling <code>createContents</code>.
296 public boolean getEnabled() {
297 if (variableTable != null && !variableTable.isDisposed()) {
298 return variableTable.getEnabled();
304 * Returns the selected variables.
306 * @return the selected variables. Returns an empty array if
307 * the widget group has not been created yet by calling
308 * <code>createContents</code>
310 public PathEntryVariableElement[] getSelection() {
311 if (variableTable == null) {
312 return new PathEntryVariableElement[0];
314 TableItem[] items = variableTable.getSelection();
315 PathEntryVariableElement[] selection = new PathEntryVariableElement[items.length];
317 for (int i = 0; i < items.length; i++) {
318 String name = (String) items[i].getData();
319 selection[i] = new PathEntryVariableElement();
320 selection[i].name = name;
321 selection[i].path = tempPathVariables.get(name);
327 * Creates the add/edit/remove buttons
329 * @param parent the widget parent
331 private void createButtonGroup(Composite parent) {
332 Font font = parent.getFont();
333 Composite groupComponent = new Composite(parent, SWT.NULL);
334 GridLayout groupLayout = new GridLayout();
335 groupLayout.marginWidth = 0;
336 groupLayout.marginHeight = 0;
337 groupComponent.setLayout(groupLayout);
338 GridData data = new GridData();
339 data.verticalAlignment = GridData.FILL;
340 data.horizontalAlignment = GridData.FILL;
341 groupComponent.setLayoutData(data);
342 groupComponent.setFont(font);
344 addButton = new Button(groupComponent, SWT.PUSH);
345 addButton.setText(PreferencesMessages.PathEntryVariablesBlock_addVariableButton);
346 addButton.addSelectionListener(new SelectionAdapter() {
348 public void widgetSelected(SelectionEvent e) {
352 addButton.setFont(font);
353 setButtonLayoutData(addButton);
355 editButton = new Button(groupComponent, SWT.PUSH);
356 editButton.setText(PreferencesMessages.PathEntryVariablesBlock_editVariableButton);
357 editButton.addSelectionListener(new SelectionAdapter() {
359 public void widgetSelected(SelectionEvent e) {
360 editSelectedVariable();
363 editButton.setFont(font);
364 setButtonLayoutData(editButton);
366 removeButton = new Button(groupComponent, SWT.PUSH);
367 removeButton.setText(PreferencesMessages.PathEntryVariablesBlock_removeVariableButton);
368 removeButton.addSelectionListener(new SelectionAdapter() {
370 public void widgetSelected(SelectionEvent e) {
371 removeSelectedVariables();
374 removeButton.setFont(font);
375 setButtonLayoutData(removeButton);
379 * Initializes the computation of horizontal and vertical dialog units
380 * based on the size of current font.
382 * This method must be called before <code>setButtonLayoutData</code>
386 * @param control a control from which to obtain the current font
388 protected void initializeDialogUnits(Control control) {
389 // Compute and store a font metric
390 GC gc = new GC(control);
391 gc.setFont(control.getFont());
392 fontMetrics = gc.getFontMetrics();
397 * (Re-)Initialize collections used to mantain temporary variable state.
399 private void initTemporaryState() {
400 String[] varNames = pathEntryVariableManager.getVariableNames();
402 tempPathVariables.clear();
403 for (String varName : varNames) {
404 IPath value = pathEntryVariableManager.getValue(varName);
406 // the value may not exist any more
408 boolean isFile = value.toFile().isFile();
409 if ((isFile && (variableType & IResource.FILE) != 0)
410 || (isFile == false && (variableType & IResource.FOLDER) != 0)) {
412 tempPathVariables.put(varName, value);
416 removedVariableNames.clear();
420 * Updates button enabled state, depending on the number of currently selected
421 * variables in the table.
423 protected void updateEnabledState() {
424 int itemsSelectedCount = variableTable.getSelectionCount();
425 editButton.setEnabled(itemsSelectedCount == 1);
426 removeButton.setEnabled(itemsSelectedCount > 0);
430 * Rebuilds table widget state with the current list of variables (reflecting
431 * any changes, additions and removals), and selects the item corresponding to
432 * the given variable name. If the variable name is <code>null</code>, the
433 * first item (if any) will be selected.
435 * @param selectedVarName the name for the variable to be selected (may be
437 * @see IPathVariableManager#getPathVariableNames()
438 * @see IPathVariableManager#getValue(String)
440 private void updateVariableTable(String selectedVarName) {
441 variableTable.removeAll();
442 int selectedVarIndex = 0;
443 for (String varName : tempPathVariables.keySet()) {
444 TableItem item = new TableItem(variableTable, SWT.NONE);
445 IPath value = tempPathVariables.get(varName);
446 File file = value.toFile();
448 item.setText(varName + " - " + value.toOSString()); //$NON-NLS-1$
449 // the corresponding variable name is stored in each table widget item
450 item.setData(varName);
451 item.setImage(file.exists() ? (file.isFile() ? FILE_IMG
452 : FOLDER_IMG) : imageUnkown);
453 if (varName.equals(selectedVarName))
454 selectedVarIndex = variableTable.getItemCount() - 1;
456 if (variableTable.getItemCount() > selectedVarIndex) {
457 variableTable.setSelection(selectedVarIndex);
458 if (selectionListener != null)
459 selectionListener.handleEvent(new Event());
460 } else if (variableTable.getItemCount() == 0
461 && selectionListener != null)
462 selectionListener.handleEvent(new Event());
466 * Commits the temporary state to the path variable manager in response to user
469 * @see IPathEntryVariableManager#setValue(String, IPath)
471 public boolean performOk() {
473 // first process removed variables
474 for (String removedVariableName : removedVariableNames) {
475 // only removes variables that have not been added again
476 if (!tempPathVariables.containsKey(removedVariableName))
477 pathEntryVariableManager.setValue(removedVariableName, null);
480 // then process the current collection of variables, adding/updating them
481 for (Entry<String, IPath> entry : tempPathVariables.entrySet()) {
482 String variableName = entry.getKey();
483 IPath variableValue = entry.getValue();
484 pathEntryVariableManager.setValue(variableName, variableValue);
486 // re-initialize temporary state
487 initTemporaryState();
489 // performOk accepted
491 } catch (CoreException ce) {
492 ErrorDialog.openError(shell, null, null, ce.getStatus());
498 * Removes the currently selected variables.
500 protected void removeSelectedVariables() {
501 // remove each selected element
502 int[] selectedIndices = variableTable.getSelectionIndices();
503 for (int selectedIndice : selectedIndices) {
504 TableItem selectedItem = variableTable.getItem(selectedIndice);
505 String varName = (String) selectedItem.getData();
506 removedVariableNames.add(varName);
507 tempPathVariables.remove(varName);
509 updateWidgetState(null);
513 * Sets the <code>GridData</code> on the specified button to
514 * be one that is spaced for the current dialog page units. The
515 * method <code>initializeDialogUnits</code> must be called once
516 * before calling this method for the first time.
518 * @param button the button to set the <code>GridData</code>
519 * @return the <code>GridData</code> set on the specified button
521 private GridData setButtonLayoutData(Button button) {
522 GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
523 int widthHint = Dialog.convertHorizontalDLUsToPixels(fontMetrics,
524 IDialogConstants.BUTTON_WIDTH);
525 data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT,
526 SWT.DEFAULT, true).x);
527 button.setLayoutData(data);
532 * Sets the enabled state of the group's widgets.
533 * Does nothing if called prior to calling <code>createContents</code>.
535 * @param enabled the new enabled state of the group's widgets
537 public void setEnabled(boolean enabled) {
538 if (variableTable != null && !variableTable.isDisposed()) {
539 variableLabel.setEnabled(enabled);
540 variableTable.setEnabled(enabled);
541 addButton.setEnabled(enabled);
543 updateEnabledState();
545 editButton.setEnabled(enabled);
546 removeButton.setEnabled(enabled);
552 * Updates the widget's current state: refreshes the table with the current
553 * defined variables, selects the item corresponding to the given variable
554 * (selects the first item if <code>null</code> is provided) and updates
555 * the enabled state for the Add/Remove/Edit buttons.
557 * @param selectedVarName the name of the variable to be selected (may be null)
559 private void updateWidgetState(String selectedVarName) {
560 updateVariableTable(selectedVarName);
561 updateEnabledState();