| /******************************************************************************* |
| * Copyright (c) 2004, 2016 BitMethods Inc and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * BitMethods Inc - initial API and implementation |
| * Sascha Radike <sradike@ejectlag.com> - Support for workspace browsing and small improvements |
| * James Blackburn (Broadcom Corp.) |
| *******************************************************************************/ |
| package org.eclipse.cdt.utils.ui.controls; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| |
| import org.eclipse.cdt.core.cdtvariables.CdtVariableException; |
| import org.eclipse.cdt.core.cdtvariables.ICdtVariable; |
| import org.eclipse.cdt.internal.core.resources.ResourceLookup; |
| import org.eclipse.cdt.internal.ui.newui.Messages; |
| import org.eclipse.cdt.ui.CDTSharedImages; |
| import org.eclipse.cdt.ui.CUIPlugin; |
| import org.eclipse.cdt.ui.newui.CDTStatusInfo; |
| import org.eclipse.cdt.ui.newui.TypedCDTViewerFilter; |
| import org.eclipse.cdt.utils.cdtvariables.CdtVariableResolver; |
| import org.eclipse.cdt.utils.cdtvariables.IVariableContextInfo; |
| import org.eclipse.cdt.utils.cdtvariables.IVariableSubstitutor; |
| import org.eclipse.cdt.utils.cdtvariables.SupplierBasedCdtVariableManager; |
| import org.eclipse.cdt.utils.cdtvariables.SupplierBasedCdtVariableSubstitutor; |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.commands.operations.AbstractOperation; |
| import org.eclipse.core.commands.operations.IOperationHistory; |
| import org.eclipse.core.commands.operations.IUndoContext; |
| import org.eclipse.core.commands.operations.IUndoableOperation; |
| import org.eclipse.core.commands.operations.ObjectUndoContext; |
| import org.eclipse.core.commands.operations.OperationHistoryFactory; |
| import org.eclipse.core.filesystem.URIUtil; |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.variables.IStringVariableManager; |
| import org.eclipse.core.variables.VariablesPlugin; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.dialogs.IInputValidator; |
| import org.eclipse.jface.dialogs.InputDialog; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.dnd.Clipboard; |
| import org.eclipse.swt.dnd.TextTransfer; |
| import org.eclipse.swt.dnd.Transfer; |
| import org.eclipse.swt.events.KeyAdapter; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.MouseAdapter; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.graphics.Image; |
| 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.DirectoryDialog; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.FileDialog; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.List; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.ToolBar; |
| import org.eclipse.swt.widgets.ToolItem; |
| import org.eclipse.swt.widgets.Widget; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; |
| import org.eclipse.ui.dialogs.ISelectionStatusValidator; |
| import org.eclipse.ui.model.WorkbenchContentProvider; |
| import org.eclipse.ui.model.WorkbenchLabelProvider; |
| import org.eclipse.ui.swt.IFocusService; |
| import org.eclipse.ui.views.navigator.ResourceComparator; |
| |
| /** |
| * Instances of this class allow the user to add, remove, delete, moveup and movedown |
| * the items in the list control. |
| * |
| * @noextend This class is not intended to be subclassed by clients. |
| */ |
| public class FileListControl { |
| |
| /** |
| * Constant copied from ManagedBuild IOption indicating that the entries in this |
| * FileListControl are neither files nor directories -- they're treated as a plain |
| * String list. |
| * |
| * #see org.eclipse.cdt.managedbuilder.core.IOption#BROWSE_NONE |
| * @since 5.2 |
| */ |
| public static final int BROWSE_NONE = 0; |
| /** |
| * Constant copied from ManagedBuild IOption indicating that the entries in this |
| * FileListControl are Files. |
| * |
| * #see org.eclipse.cdt.managedbuilder.core.IOption#BROWSE_FILE |
| * @since 5.2 |
| */ |
| public static final int BROWSE_FILE = 1; |
| /** |
| * Constant copied from ManagedBuild IOption indicating that the entries in this |
| * FileListControl are Directories. |
| * |
| * #see org.eclipse.cdt.managedbuilder.core.IOption#BROWSE_DIR |
| * @since 5.2 |
| */ |
| public static final int BROWSE_DIR = 2; |
| |
| /** |
| * Multi-purpose dialog to prompt the user for a value, path, or file. |
| * |
| * @since 2.0 |
| */ |
| class SelectPathInputDialog extends InputDialog { |
| |
| private String[] values = new String[0]; |
| |
| private int type; |
| /* True if user successfully set the text value by a browse dialog */ |
| private boolean fSetByBrowseDialog = false; |
| |
| /** |
| * @param parentShell |
| * @param dialogTitle |
| * @param dialogMessage |
| * @param initialValue |
| * @param validator |
| * @param browseType |
| */ |
| public SelectPathInputDialog(Shell parentShell, String dialogTitle, String dialogMessage, String initialValue, |
| IInputValidator validator, int browseType) { |
| super(parentShell, dialogTitle, dialogMessage, initialValue, validator); |
| this.type = browseType; |
| } |
| |
| private String getInitialValue(String initialValue) { |
| IDialogSettings dialogSettings = CUIPlugin.getDefault().getDialogSettings(); |
| // restore file |
| String sfile = dialogSettings.get(FileListControl.class.getName()); |
| if (sfile != null && (initialValue == null || initialValue.isEmpty())) { |
| return sfile; |
| } |
| return initialValue; |
| } |
| |
| protected void saveWidgetValues() { |
| IDialogSettings dialogSettings = CUIPlugin.getDefault().getDialogSettings(); |
| // save file name |
| dialogSettings.put(FileListControl.class.getName(), getValue()); |
| } |
| |
| @Override |
| public boolean close() { |
| saveWidgetValues(); |
| return super.close(); |
| } |
| |
| @Override |
| protected Control createContents(Composite parent) { |
| Control area = super.createContents(parent); |
| getText().setText(getInitialValue(getValue())); |
| return area; |
| } |
| |
| /** |
| * Returns true if the value has been set by a browse dialog. |
| */ |
| public boolean isValueSetByBrowse() { |
| return fSetByBrowseDialog; |
| } |
| |
| /** |
| * Allow this dialog to return multiple entires |
| * @return String[] represeting the collected values |
| */ |
| public String[] getValues() { |
| // If values only has one entry or fewer, then return getValue() to catch more recent changes to edit field |
| if (values.length <= 1) |
| return new String[] { getValue() }; |
| return values; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) |
| */ |
| @Override |
| protected void createButtonsForButtonBar(Composite parent) { |
| super.createButtonsForButtonBar(parent); |
| |
| if (((type == BROWSE_DIR) || (type == BROWSE_FILE)) && (fWorkspaceSupport)) { |
| |
| /* Browse button for workspace folders/files */ |
| final Button workspaceButton = createButton(parent, 3, WORKSPACEBUTTON_NAME, false); |
| workspaceButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent ev) { |
| /* Before opening the browse dialog we try to convert the current |
| * path text to a valid workspace resource, so we can set it |
| * as initial selection in the dialog. |
| * |
| * First we remove all double-quotes. Then the build macro provider |
| * will resolve all macros/variables (like workspace_loc, ...). |
| * |
| * If the workspace location path is a prefix of our resolved path, |
| * we will remove that part and finally get a full path relative to the |
| * workspace. We can use that path to set the initially selected resource. |
| */ |
| |
| String currentPathText = getText().getText(); |
| |
| /* Remove double quotes */ |
| currentPathText = currentPathText.replaceAll("\"", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| /* Resolve variables */ |
| IStringVariableManager variableManager = VariablesPlugin.getDefault() |
| .getStringVariableManager(); |
| |
| /* See if we can discover the project from the context * |
| * and check whether the path must be resolved... */ |
| IProject project = null; |
| |
| if (contextInfo != null) { |
| try { |
| // Try to find the project |
| ICdtVariable var = SupplierBasedCdtVariableManager.getVariable(PROJECTNAME_VAR, |
| contextInfo, true); |
| if (var != null && var.getValueType() == ICdtVariable.VALUE_TEXT) |
| project = ResourcesPlugin.getWorkspace().getRoot().getProject(var.getStringValue()); |
| |
| // Try to resolve the currentPathText |
| IVariableSubstitutor varSubs = new SupplierBasedCdtVariableSubstitutor(contextInfo, "", //$NON-NLS-1$ |
| ""); //$NON-NLS-1$ |
| currentPathText = CdtVariableResolver.resolveToString(currentPathText, varSubs); |
| |
| } catch (CdtVariableException e) { |
| // It's OK not to find the project... carry on as before |
| } |
| } else { |
| try { |
| currentPathText = variableManager.performStringSubstitution(currentPathText, false); |
| } catch (CoreException e) { |
| // ignore |
| } |
| } |
| IResource resource = null; |
| if (!currentPathText.isEmpty()) { |
| IResource rs[] = null; |
| try { |
| rs = ResourcesPlugin.getWorkspace().getRoot() |
| .findContainersForLocationURI(URIUtil.toURI(currentPathText)); |
| } catch (Exception e) { |
| // rs will be null here, exception is throw is path is not absolute |
| } |
| if (rs == null || rs.length == 0) |
| resource = ResourceLookup.selectFileForLocation(new Path(currentPathText), null); |
| else |
| resource = rs[0]; |
| } |
| |
| /* Create workspace folder/file selection dialog and |
| * set initial selection */ |
| ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), |
| new WorkbenchLabelProvider(), new WorkbenchContentProvider()); |
| |
| dialog.setInput(ResourcesPlugin.getWorkspace().getRoot()); |
| dialog.setComparator(new ResourceComparator(ResourceComparator.NAME)); |
| |
| if (type == BROWSE_DIR) { |
| dialog.setInitialSelection(resource); |
| Class<?>[] filteredResources = { IContainer.class, IProject.class }; |
| dialog.addFilter(new TypedCDTViewerFilter(filteredResources)); |
| dialog.setTitle(WORKSPACE_DIR_DIALOG_TITLE); |
| dialog.setMessage(WORKSPACE_DIR_DIALOG_MSG); |
| } else { |
| dialog.setInitialSelection(resource); |
| dialog.setValidator(new ISelectionStatusValidator() { |
| @Override |
| public IStatus validate(Object[] selection) { |
| if (selection != null) |
| for (Object sel : selection) |
| if (!(sel instanceof IFile)) |
| return new CDTStatusInfo(IStatus.ERROR, WORKSPACE_FILE_DIALOG_ERR); |
| return new CDTStatusInfo(); |
| } |
| }); |
| dialog.setTitle(WORKSPACE_FILE_DIALOG_TITLE); |
| dialog.setMessage(WORKSPACE_FILE_DIALOG_MSG); |
| } |
| |
| /* Open dialog and process result. |
| * If a resource has been selected we create a workspace relative path for it. |
| * Use ${ProjName} if the full path is relative to the context's location */ |
| if (dialog.open() == Window.OK) { |
| fSetByBrowseDialog = true; |
| |
| Object[] rs = dialog.getResult(); |
| |
| if (rs != null) { |
| int i = 0; |
| values = new String[rs.length]; |
| for (Object o : rs) { |
| resource = (IResource) o; |
| if (resource.getProject().equals(project)) |
| values[i++] = variableManager.generateVariableExpression(WORKSPACELOC_VAR, |
| PROJECTNAME_PATH.append(resource.getProjectRelativePath()) |
| .makeAbsolute().toString()); |
| else |
| values[i++] = variableManager.generateVariableExpression(WORKSPACELOC_VAR, |
| resource.getFullPath().toString()); |
| } |
| // If only one entry, update the text field |
| if (values.length == 1) |
| getText().setText(values[0]); |
| else |
| // More then one item selected and OK pressed. Exit this edit dialog |
| buttonPressed(IDialogConstants.OK_ID); |
| } |
| } |
| } |
| }); |
| } |
| |
| if (type != BROWSE_NONE) { |
| /* Browse button for external directories/files */ |
| final Button externalButton = createButton(parent, 4, FILESYSTEMBUTTON_NAME, false); |
| externalButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent ev) { |
| String currentName; |
| String result; |
| switch (type) { |
| case BROWSE_DIR: |
| DirectoryDialog dialog = new DirectoryDialog(getParentShell(), |
| SWT.OPEN | SWT.APPLICATION_MODAL); |
| currentName = getText().getText(); |
| if (currentName != null && currentName.trim().length() != 0) { |
| dialog.setFilterPath(currentName); |
| } else if (FileListControl.this.filterPath != null) { |
| dialog.setFilterPath(FileListControl.this.filterPath); |
| } |
| dialog.setMessage(FILESYSTEM_DIR_DIALOG_MSG); |
| result = dialog.open(); |
| if (result != null) { |
| fSetByBrowseDialog = true; |
| getText().setText(result); |
| } |
| break; |
| case BROWSE_FILE: |
| FileDialog browseDialog = new FileDialog(getParentShell()); |
| currentName = getText().getText(); |
| if (currentName != null && currentName.trim().length() != 0) { |
| browseDialog.setFilterPath(currentName); |
| } else if (FileListControl.this.filterPath != null) { |
| browseDialog.setFilterPath(FileListControl.this.filterPath); |
| } |
| if (FileListControl.this.filterExtensions != null) { |
| browseDialog.setFilterExtensions(FileListControl.this.filterExtensions); |
| } |
| result = browseDialog.open(); |
| if (result != null) { |
| fSetByBrowseDialog = true; |
| getText().setText(result); |
| } |
| break; |
| } |
| } |
| }); |
| } |
| } |
| |
| } |
| |
| /** |
| * An extended List control with support for cut / copy / paste & undo |
| * Needs to be public for the copy method to be called by the platform via reflection |
| * @since 5.2 |
| * @noinstantiate This class is not intended to be instantiated by clients. |
| */ |
| public final class ClipboardList extends List { |
| private Clipboard clipboard; |
| |
| public ClipboardList(Composite parent, int style) { |
| super(parent, style); |
| } |
| |
| private String[] getClipboardContents() { |
| Clipboard cp = getClipboard(); |
| String contents = (String) cp.getContents(TextTransfer.getInstance()); |
| if (contents != null) { |
| String[] arr = contents.split("\n"); //$NON-NLS-1$ |
| return arr; |
| } |
| return new String[0]; |
| } |
| |
| public void copy() { |
| String[] toCopy = getSelection(); |
| if (toCopy != null && toCopy.length > 0) { |
| StringBuilder sb = new StringBuilder(); |
| for (String item : toCopy) |
| sb.append(item.trim()).append("\n"); //$NON-NLS-1$ |
| Clipboard cp = getClipboard(); |
| cp.setContents(new Object[] { sb.toString().trim() }, new Transfer[] { TextTransfer.getInstance() }); |
| } |
| } |
| |
| public void cut() { |
| copy(); |
| // Only remove from the list box if the cut was successful |
| if (Arrays.equals(getClipboardContents(), getSelection())) |
| removePressed(); |
| } |
| |
| public void paste() { |
| String[] pasteBuffer = getClipboardContents(); |
| int i = getSelectionIndex(); |
| // insert items at the correct location |
| for (String item : pasteBuffer) |
| if (!item.trim().isEmpty()) |
| add(item.trim(), ++i); |
| checkNotificationNeeded(); |
| } |
| |
| public void undo() { |
| try { |
| operationHistory.undo(undoContext, null, null); |
| } catch (ExecutionException e) { |
| CUIPlugin.log(e); |
| } |
| } |
| |
| public void redo() { |
| try { |
| operationHistory.redo(undoContext, null, null); |
| } catch (ExecutionException e) { |
| CUIPlugin.log(e); |
| } |
| } |
| |
| private Clipboard getClipboard() { |
| if (clipboard == null) |
| clipboard = new Clipboard(Display.getDefault()); |
| return clipboard; |
| } |
| |
| @Override |
| public void dispose() { |
| super.dispose(); |
| if (clipboard != null) |
| clipboard.dispose(); |
| } |
| |
| /** |
| * Handle backspace / delete key |
| */ |
| public void delete() { |
| removePressed(); |
| } |
| |
| @Override |
| protected void checkSubclass() { |
| // We're adding action handlers, override... |
| } |
| } |
| |
| /* Variable names */ |
| /* See CdtMacroSupplier: used for making absolute paths relative if desired */ |
| private static final String WORKSPACELOC_VAR = "workspace_loc"; //$NON-NLS-1$ |
| private static final String PROJECTNAME_VAR = "ProjName"; //$NON-NLS-1$ |
| private static final IPath PROJECTNAME_PATH = new Path( |
| VariablesPlugin.getDefault().getStringVariableManager().generateVariableExpression(PROJECTNAME_VAR, null)); |
| |
| /* Names, messages and titles */ |
| private static final String WORKSPACEBUTTON_NAME = Messages.FileListControl_button_workspace; |
| private static final String FILESYSTEMBUTTON_NAME = Messages.FileListControl_button_fs; |
| |
| private static final String ADD_STR = Messages.FileListControl_add; |
| private static final String DEL_STR = Messages.FileListControl_delete; |
| private static final String EDIT_STR = Messages.FileListControl_edit; |
| private static final String MOVEUP_STR = Messages.FileListControl_moveup; |
| private static final String MOVEDOWN_STR = Messages.FileListControl_movedown; |
| private static final String FILE_TITLE_ADD = Messages.BrowseEntryDialog_file_title_add; |
| private static final String DIR_TITLE_ADD = Messages.BrowseEntryDialog_dir_title_add; |
| private static final String FILE_TITLE_EDIT = Messages.BrowseEntryDialog_file_title_edit; |
| private static final String DIR_TITLE_EDIT = Messages.BrowseEntryDialog_dir_title_edit; |
| private static final String WORKSPACE_DIR_DIALOG_TITLE = Messages.BrowseEntryDialog_wsp_dir_dlg_title; |
| private static final String WORKSPACE_FILE_DIALOG_TITLE = Messages.BrowseEntryDialog_wsp_file_dlg_title; |
| private static final String WORKSPACE_DIR_DIALOG_MSG = Messages.FileListControl_BrowseEntryDialog_wsp_dir_dlg_msg; |
| private static final String WORKSPACE_FILE_DIALOG_MSG = Messages.FileListControl_BrowseEntryDialog_wsp_file_dlg_msg; |
| private static final String WORKSPACE_FILE_DIALOG_ERR = Messages.FileListControl_BrowseEntryDialog_wsp_file_dlg_err; |
| private static final String FILESYSTEM_DIR_DIALOG_MSG = Messages.BrowseEntryDialog_fs_dir_dlg_msg; |
| private static final String FILE_MSG = Messages.BrowseEntryDialog_message_file; |
| private static final String DIR_MSG = Messages.BrowseEntryDialog_message_directory; |
| private static final String TITLE = Messages.BuildPropertyCommon_label_title; |
| |
| /** flag which prevents us from resetting the prompt for delete flag */ |
| private boolean neverPromptForDelete; |
| /** Flag indicating whether the user should be prompted for delete */ |
| private boolean promptForDelete; |
| |
| //toolbar |
| private ToolBar toolBar; |
| // toolbar items |
| private ToolItem addItem, deleteItem, editItem, moveUpItem, moveDownItem; |
| // title label |
| private Label title; |
| // list control |
| private ClipboardList list; |
| private String compTitle; |
| private SelectionListener selectionListener; |
| private GridData tgdata, grid3, grid4, grid2; |
| |
| // The type of browse support that is required |
| private int browseType; |
| private String filterPath; |
| private String[] filterExtensions; |
| /** The base path that should be used when adding new resources */ |
| private IPath path = new Path(""); //$NON-NLS-1$ |
| |
| /* Workspace support */ |
| private boolean fWorkspaceSupport = false; |
| private IVariableContextInfo contextInfo; |
| /** Undo support */ |
| IUndoContext undoContext; |
| IOperationHistory operationHistory = OperationHistoryFactory.getOperationHistory(); |
| |
| private java.util.List<IFileListChangeListener> listeners = new ArrayList<>(); |
| private String[] oldValue; |
| |
| //images |
| private final Image IMG_ADD = CDTSharedImages.getImage(CDTSharedImages.IMG_FILELIST_ADD); |
| private final Image IMG_DEL = CDTSharedImages.getImage(CDTSharedImages.IMG_FILELIST_DEL); |
| private final Image IMG_EDIT = CDTSharedImages.getImage(CDTSharedImages.IMG_FILELIST_EDIT); |
| private final Image IMG_MOVEUP = CDTSharedImages.getImage(CDTSharedImages.IMG_FILELIST_MOVEUP); |
| private final Image IMG_MOVEDOWN = CDTSharedImages.getImage(CDTSharedImages.IMG_FILELIST_MOVEDOWN); |
| |
| /** |
| * Constructor |
| * |
| * @param parent |
| * @param compTitle |
| * @param type |
| * @param promptForDelete indicates whether the user should be prompted on delete |
| * @see #FileListControl(Composite, String, int) |
| * @since 5.2 |
| */ |
| public FileListControl(Composite parent, String compTitle, int type, boolean promptForDelete) { |
| this(parent, compTitle, type); |
| this.promptForDelete = promptForDelete; |
| this.neverPromptForDelete = !promptForDelete; |
| } |
| |
| /** |
| * Constructor |
| * |
| * This FileListControl only prompts the user on Delete for BROWSE_FILE and BROWSE_DIR |
| * @param parent |
| * @param compTitle |
| * @param type one of the IOption BROWSE types |
| * @see #BROWSE_NONE |
| * @see #BROWSE_FILE |
| * @see #BROWSE_DIR |
| */ |
| public FileListControl(Composite parent, String compTitle, int type) { |
| promptForDelete = type == BROWSE_FILE || type == BROWSE_DIR; |
| |
| // Default to no browsing |
| browseType = type; |
| |
| //file panel |
| Composite filePanel = new Composite(parent, SWT.NONE); |
| GridLayout form1 = new GridLayout(); |
| form1.numColumns = 1; |
| form1.horizontalSpacing = 0; |
| form1.verticalSpacing = 0; |
| form1.marginHeight = 0; |
| form1.marginWidth = 0; |
| filePanel.setLayout(form1); |
| filePanel.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| |
| // title panel |
| Composite titlePanel = new Composite(filePanel, SWT.BORDER); |
| GridLayout titleform = new GridLayout(2, false); |
| titleform.horizontalSpacing = 0; |
| titleform.verticalSpacing = 0; |
| titleform.marginHeight = 0; |
| titleform.marginWidth = 0; |
| titlePanel.setLayout(titleform); |
| tgdata = new GridData(GridData.FILL_HORIZONTAL); |
| tgdata.heightHint = IDialogConstants.BUTTON_BAR_HEIGHT; |
| titlePanel.setLayoutData(tgdata); |
| title = new Label(titlePanel, SWT.NONE | SWT.BOLD); |
| this.compTitle = " " + compTitle; //$NON-NLS-1$ |
| title.setText(this.compTitle); |
| grid2 = new GridData(GridData.FILL_HORIZONTAL); |
| title.setLayoutData(grid2); |
| //button panel |
| Composite buttonPanel = new Composite(titlePanel, SWT.NONE); |
| GridLayout form2 = new GridLayout(); |
| form2.numColumns = 5; |
| form2.horizontalSpacing = 0; |
| form2.verticalSpacing = 0; |
| form2.marginWidth = 0; |
| form2.marginHeight = 0; |
| buttonPanel.setLayout(form2); |
| // toolbar |
| toolBar = new ToolBar(buttonPanel, SWT.HORIZONTAL | SWT.RIGHT | SWT.FLAT); |
| // add toolbar item |
| addItem = new ToolItem(toolBar, SWT.PUSH); |
| addItem.setImage(IMG_ADD); |
| addItem.setToolTipText(ADD_STR); |
| addItem.addSelectionListener(getSelectionListener()); |
| // delete toolbar item |
| deleteItem = new ToolItem(toolBar, SWT.PUSH); |
| deleteItem.setImage(IMG_DEL); |
| deleteItem.setToolTipText(DEL_STR); |
| deleteItem.addSelectionListener(getSelectionListener()); |
| // edit toolbar item |
| editItem = new ToolItem(toolBar, SWT.PUSH); |
| editItem.setImage(IMG_EDIT); |
| editItem.setToolTipText(EDIT_STR); |
| editItem.addSelectionListener(getSelectionListener()); |
| // moveup toolbar item |
| moveUpItem = new ToolItem(toolBar, SWT.PUSH); |
| moveUpItem.setImage(IMG_MOVEUP); |
| moveUpItem.setToolTipText(MOVEUP_STR); |
| moveUpItem.addSelectionListener(getSelectionListener()); |
| // movedown toolbar item |
| moveDownItem = new ToolItem(toolBar, SWT.PUSH); |
| moveDownItem.setImage(IMG_MOVEDOWN); |
| moveDownItem.setToolTipText(MOVEDOWN_STR); |
| moveDownItem.addSelectionListener(getSelectionListener()); |
| grid3 = new GridData(GridData.FILL_HORIZONTAL | GridData.HORIZONTAL_ALIGN_END); |
| buttonPanel.setLayoutData(grid3); |
| // list control |
| list = new ClipboardList(filePanel, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.MULTI); |
| grid4 = new GridData(GridData.FILL_BOTH); |
| // force the list to be no wider than the title bar |
| Point preferredSize = titlePanel.computeSize(SWT.DEFAULT, SWT.DEFAULT); |
| grid4.widthHint = preferredSize.x; |
| grid4.heightHint = preferredSize.y * 3; |
| grid4.horizontalSpan = 2; |
| list.setLayoutData(grid4); |
| list.addSelectionListener(getSelectionListener()); |
| //Add a double-click event handler |
| list.addMouseListener(new MouseAdapter() { |
| @Override |
| public void mouseDoubleClick(MouseEvent e) { |
| // Popup the editor on the selected item from the list |
| editSelection(); |
| } |
| }); |
| // Add a delete key listener |
| list.addKeyListener(new KeyAdapter() { |
| /* (non-Javadoc) |
| * @see org.eclipse.swt.events.KeyAdapter#keyPressed(org.eclipse.swt.events.KeyEvent) |
| */ |
| @Override |
| public void keyPressed(KeyEvent e) { |
| switch (e.keyCode) { |
| case SWT.BS: |
| case SWT.DEL: |
| if (e.stateMask == SWT.NONE) |
| removePressed(); |
| break; |
| } |
| } |
| }); |
| |
| // Set-up Undo history |
| undoContext = new ObjectUndoContext(this); |
| operationHistory.setLimit(undoContext, 50); |
| |
| // Add command handlers for undo to the control |
| try { |
| IFocusService fs = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart() |
| .getSite().getService(IFocusService.class); |
| fs.addFocusTracker(list, "org.eclipse.cdt.ui.FileListControl"); //$NON-NLS-1$ |
| } catch (Exception e) { |
| // Any of the get* methods may return null. As this is in the UI constructor for this control |
| // it shouldn't happen. Log and carry on. |
| CUIPlugin.log(e); |
| } |
| |
| selectionChanged(); |
| } |
| |
| /** |
| * Set list values |
| * |
| * @param listVal |
| */ |
| public void setList(String[] listVal) { |
| if (list != null) { |
| list.removeAll(); |
| } |
| for (String element : listVal) { |
| list.add(element); |
| } |
| checkNotificationNeeded(); |
| } |
| |
| public void addChangeListener(IFileListChangeListener listener) { |
| listeners.add(listener); |
| } |
| |
| public void removeChangeListener(IFileListChangeListener listener) { |
| listeners.remove(listener); |
| } |
| |
| /** |
| * Checks whether a notification is needed, and notifies listeners |
| * |
| * Persist any changes in the undo history. |
| * |
| * This method must be called after every change to the contents of the list box |
| * |
| * At end of method oldValue.equals(list.getItems()) |
| */ |
| public void checkNotificationNeeded() { |
| final String items[] = getItems(); |
| if (oldValue != null) { |
| if (Arrays.equals(oldValue, items)) |
| return; |
| |
| // Add some context to the undo history |
| IUndoableOperation op = new AbstractOperation("") { //$NON-NLS-1$ |
| final String[] previousValue = oldValue; |
| final String[] newValue = items; |
| |
| @Override |
| public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { |
| list.setItems(previousValue); |
| notifyListeners(newValue, previousValue); |
| oldValue = previousValue; |
| return Status.OK_STATUS; |
| } |
| |
| @Override |
| public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { |
| list.setItems(newValue); |
| notifyListeners(previousValue, newValue); |
| oldValue = newValue; |
| return Status.OK_STATUS; |
| } |
| |
| @Override |
| public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { |
| return Status.CANCEL_STATUS; |
| } |
| }; |
| op.addContext(undoContext); |
| operationHistory.add(op); |
| System.arraycopy(items, 0, oldValue = new String[items.length], 0, items.length); |
| notifyListeners(oldValue, items); |
| list.setFocus(); // Ensure this control retains focus |
| } else |
| System.arraycopy(items, 0, oldValue = new String[items.length], 0, items.length); |
| } |
| |
| public void notifyListeners(String oldVal[], String newVal[]) { |
| for (IFileListChangeListener listener : listeners) { |
| listener.fileListChanged(this, oldVal, newVal); |
| } |
| } |
| |
| /** |
| * Set selection |
| * |
| * @param sel |
| */ |
| public void setSelection(int sel) { |
| if (list.getItemCount() > 0) |
| list.setSelection(sel); |
| selectionChanged(); |
| } |
| |
| /** |
| * Set default selection |
| */ |
| public void setSelection() { |
| if (list.getItemCount() > 0) |
| list.setSelection(0); |
| } |
| |
| /** |
| * removes all items from list control |
| */ |
| public void removeAll() { |
| if (list != null) { |
| list.removeAll(); |
| checkNotificationNeeded(); |
| } |
| } |
| |
| /** |
| * get list items |
| */ |
| public String[] getItems() { |
| return list.getItems(); |
| } |
| |
| /** |
| * Create selection listener for buttons |
| */ |
| private void createSelectionListener() { |
| selectionListener = new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent event) { |
| Widget widget = event.widget; |
| if (widget == addItem) { |
| addPressed(); |
| } else if (widget == deleteItem) { |
| removePressed(); |
| } else if (widget == moveUpItem) { |
| upPressed(); |
| } else if (widget == moveDownItem) { |
| downPressed(); |
| } else if (widget == list) { |
| selectionChanged(); |
| } else if (widget == editItem) { |
| editSelection(); |
| } |
| } |
| }; |
| } |
| |
| /** |
| * Returns selection listener |
| * |
| * @return |
| */ |
| private SelectionListener getSelectionListener() { |
| if (selectionListener == null) |
| createSelectionListener(); |
| return selectionListener; |
| } |
| |
| /** |
| * This method will be called when the add button is pressed |
| */ |
| private void addPressed() { |
| // Prompt user for a new item |
| String[] input = getNewInputObject(); |
| |
| // Add it to the list |
| if (input.length > 0) { |
| int index = list.getSelectionIndex(); |
| int i = 0; |
| for (String s : input) |
| list.add(s, index + ++i); |
| list.setSelection(index + 1); |
| checkNotificationNeeded(); |
| } |
| |
| selectionChanged(); |
| } |
| |
| /** |
| * This method will be called when the remove button is pressed |
| */ |
| private void removePressed() { |
| if (list.getSelectionCount() == 0 || list.getSelectionIndex() == -1) |
| return; |
| boolean delDir = true; |
| if (promptForDelete) { |
| String quest = Messages.FileListControl_deletedialog_message; |
| String title = Messages.FileListControl_deletedialog_title; |
| delDir = MessageDialog.openQuestion(list.getShell(), title, quest); |
| } |
| if (delDir) { |
| list.remove(list.getSelectionIndices()); |
| checkNotificationNeeded(); |
| } |
| selectionChanged(); |
| } |
| |
| /** |
| * This method will be called when the move up button is pressed |
| */ |
| private void upPressed() { |
| int index = list.getSelectionIndex(); |
| String curSelList = list.getItem(index); |
| String preList = list.getItem(index - 1); |
| list.setItem(index - 1, curSelList); |
| list.setItem(index, preList); |
| list.setSelection(index - 1); |
| checkNotificationNeeded(); |
| selectionChanged(); |
| } |
| |
| /** |
| * This method will be called when the move down button is pressed |
| */ |
| private void downPressed() { |
| int index = list.getSelectionIndex(); |
| String curSelList = list.getItem(index); |
| String nextList = list.getItem(index + 1); |
| list.setItem(index + 1, curSelList); |
| list.setItem(index, nextList); |
| list.setSelection(index + 1); |
| checkNotificationNeeded(); |
| selectionChanged(); |
| } |
| |
| /** |
| * This method will be called when the edit button is pressed |
| */ |
| private void editSelection() { |
| final int index = list.getSelectionIndex(); |
| if (index != -1) { |
| String selItem = list.getItem(index); |
| if (selItem != null) { |
| /* Use SelectPathInputDialog for IOption.BROWSE_DIR and |
| * IOption.BROWSE_FILE. Use simple input dialog otherwise. |
| */ |
| InputDialog dialog; |
| if ((browseType == BROWSE_DIR) || (browseType == BROWSE_FILE)) { |
| |
| String title; |
| String message; |
| if (browseType == BROWSE_DIR) { |
| title = DIR_TITLE_EDIT; |
| message = DIR_MSG; |
| } else { |
| title = FILE_TITLE_EDIT; |
| message = FILE_MSG; |
| } |
| dialog = new SelectPathInputDialog(getListControl().getShell(), title, message, selItem, null, |
| browseType); |
| } else { |
| String title = Messages.FileListControl_editdialog_title; |
| dialog = new InputDialog(null, title, compTitle, selItem, null); |
| } |
| |
| if (dialog.open() == Window.OK) { |
| String[] newItems; |
| |
| /* If newItem is a directory or file path we need to |
| * double-quote it if required. We only do this if the user |
| * selected a new path using a browse button. If he/she simply |
| * edited the text, we skip this so the user can remove quotes if he/she |
| * wants to. |
| */ |
| if (dialog instanceof SelectPathInputDialog) { |
| SelectPathInputDialog selDialog = (SelectPathInputDialog) dialog; |
| newItems = selDialog.getValues(); |
| if (selDialog.isValueSetByBrowse()) |
| for (int i = 0; i < newItems.length; i++) |
| newItems[i] = doubleQuotePath(newItems[i]); |
| } else |
| newItems = new String[] { dialog.getValue() }; |
| |
| // If no change, return |
| if (newItems.length == 1 && newItems[0].equals(selItem)) |
| return; |
| |
| // Replace the changed item & insert new items |
| list.setItem(index, newItems[0]); |
| for (int i = 1; i < newItems.length; i++) |
| list.add(newItems[i], index + i); |
| checkNotificationNeeded(); |
| selectionChanged(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * This method will be called when the list selection changed |
| */ |
| public void selectionChanged() { |
| int index = list.getSelectionIndex(); |
| int size = list.getItemCount(); |
| int selectionCount = list.getSelectionCount(); |
| deleteItem.setEnabled(size > 0); |
| moveUpItem.setEnabled(size > 1 && index > 0 && selectionCount == 1); |
| moveDownItem.setEnabled(size > 1 && index >= 0 && index < size - 1 && selectionCount == 1); |
| editItem.setEnabled(selectionCount == 1); |
| } |
| |
| /** |
| * Returns List control |
| */ |
| public List getListControl() { |
| return list; |
| } |
| |
| /** |
| * Sets the IPath of the project the field editor was |
| * created for. |
| * |
| * @param path The path to the |
| */ |
| public void setPath(IPath path) { |
| this.path = path; |
| } |
| |
| /** |
| * Set browseType |
| * @deprecated This class should be constructed with the correct type |
| */ |
| @Deprecated |
| public void setType(int type) { |
| browseType = type; |
| if (!neverPromptForDelete) |
| promptForDelete = type == BROWSE_FILE || type == BROWSE_DIR; |
| } |
| |
| /** |
| * Sets the default filter-path for the underlying Browse dialog. Only applies when browseType is 'file' or 'dir'. |
| * @param filterPath |
| * |
| * @since 5.2 |
| */ |
| public void setFilterPath(String filterPath) { |
| this.filterPath = filterPath; |
| } |
| |
| /** |
| * Sets the filter-extensions for the underlying Browse dialog. Only applies when browseType is 'file'. |
| * @param filterExtensions |
| * |
| * @since 5.2 |
| */ |
| public void setFilterExtensions(String[] filterExtensions) { |
| this.filterExtensions = filterExtensions; |
| } |
| |
| /** |
| * Enable/Disable workspace support. If enabled, the workspace browse button |
| * will be visible in the SelectPathInputDialog. |
| * @param enable |
| */ |
| public void setWorkspaceSupport(boolean enable) { |
| fWorkspaceSupport = enable; |
| } |
| |
| /** |
| * Set the field editor context. |
| */ |
| public void setContext(IVariableContextInfo info) { |
| contextInfo = info; |
| for (; info != null; info = info.getNext()) { |
| /* |
| if(info.getContextType() == IBuildMacroProvider.CONTEXT_PROJECT){ |
| IManagedProject mngProj = (IManagedProject)info.getContextData(); |
| this.rc = mngProj.getOwner(); |
| break; |
| } |
| */ |
| } |
| } |
| |
| /** |
| * Returns the input dialog string |
| */ |
| private String[] getNewInputObject() { |
| // Create a dialog to prompt for a new list item |
| String[] input = new String[0]; |
| String title = ""; //$NON-NLS-1$ |
| String message = ""; //$NON-NLS-1$ |
| String initVal = ""; //$NON-NLS-1$ |
| |
| if (browseType == BROWSE_DIR) { |
| title = DIR_TITLE_ADD; |
| message = DIR_MSG; |
| initVal = path.toString(); |
| } else if (browseType == BROWSE_FILE) { |
| title = FILE_TITLE_ADD; |
| message = FILE_MSG; |
| initVal = path.toString(); |
| } else { |
| title = TITLE; |
| message = compTitle; |
| } |
| |
| // Prompt for value |
| SelectPathInputDialog dialog = new SelectPathInputDialog(getListControl().getShell(), title, message, initVal, |
| null, browseType); |
| if (dialog.open() == Window.OK) { |
| input = dialog.getValues(); |
| |
| /* Double-quote (if required) the text if it is a directory or file */ |
| if (input.length > 0) { |
| if (browseType == BROWSE_DIR || browseType == BROWSE_FILE) |
| for (int i = 0; i < input.length; i++) |
| input[i] = doubleQuotePath(input[i]); |
| } |
| } |
| |
| return input; |
| } |
| |
| public Label getLabelControl() { |
| return title; |
| } |
| |
| public void setEnabled(boolean enabled) { |
| title.setEnabled(enabled); |
| toolBar.setEnabled(enabled); |
| list.setEnabled(enabled); |
| } |
| |
| /** |
| * Double-quotes a path name if it contains white spaces, backslahes |
| * or a macro/variable (We don't know if a macro will contain spaces, so we |
| * have to be on the safe side). |
| * @param pathName The path name to double-quote. |
| * @return |
| */ |
| private String doubleQuotePath(String pathName) { |
| /* Trim */ |
| pathName = pathName.trim(); |
| |
| /* Check if path is already double-quoted */ |
| boolean bStartsWithQuote = pathName.startsWith("\""); //$NON-NLS-1$ |
| boolean bEndsWithQuote = pathName.endsWith("\""); //$NON-NLS-1$ |
| |
| /* Check for spaces, backslashes or macros */ |
| int i = pathName.indexOf(" ") + pathName.indexOf("\\") //$NON-NLS-1$ //$NON-NLS-2$ |
| + pathName.indexOf("${"); //$NON-NLS-1$ |
| |
| /* If indexof didn't fail all three times, double-quote path */ |
| if (i != -3) { |
| if (!bStartsWithQuote) |
| pathName = "\"" + pathName; //$NON-NLS-1$ |
| if (!bEndsWithQuote) |
| pathName = pathName + "\""; //$NON-NLS-1$ |
| } |
| |
| return pathName; |
| } |
| } |