| /******************************************************************************* |
| * Copyright (c) 2000, 2017 IBM Corporation and others. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.ui.wizards.buildpath; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.IBuildpathEntry; |
| import org.eclipse.dltk.core.IScriptModel; |
| import org.eclipse.dltk.core.IScriptProject; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.internal.ui.util.CoreUtility; |
| import org.eclipse.dltk.internal.ui.wizards.NewWizardMessages; |
| import org.eclipse.dltk.internal.ui.wizards.dialogfields.DialogField; |
| import org.eclipse.dltk.internal.ui.wizards.dialogfields.IDialogFieldListener; |
| import org.eclipse.dltk.internal.ui.wizards.dialogfields.IListAdapter; |
| import org.eclipse.dltk.internal.ui.wizards.dialogfields.LayoutUtil; |
| import org.eclipse.dltk.internal.ui.wizards.dialogfields.ListDialogField; |
| import org.eclipse.dltk.ui.DLTKUIPlugin; |
| import org.eclipse.dltk.ui.util.ExceptionHandler; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.dialogs.ProgressMonitorDialog; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| import org.eclipse.jface.viewers.IDoubleClickListener; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.CLabel; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Shell; |
| |
| public class VariableBlock { |
| |
| private final ListDialogField fVariablesList; |
| private Control fControl; |
| private CLabel fWarning; |
| private boolean fHasChanges; |
| |
| private List fSelectedElements; |
| private boolean fAskToBuild; |
| private final boolean fEditOnDoubleclick; |
| |
| public VariableBlock(boolean inPreferencePage, String initSelection) { |
| |
| fSelectedElements = new ArrayList(0); |
| fEditOnDoubleclick = inPreferencePage; |
| fAskToBuild = true; |
| |
| String[] buttonLabels = new String[] { |
| NewWizardMessages.VariableBlock_vars_add_button, |
| NewWizardMessages.VariableBlock_vars_edit_button, |
| NewWizardMessages.VariableBlock_vars_remove_button }; |
| |
| VariablesAdapter adapter = new VariablesAdapter(); |
| |
| BPVariableElementLabelProvider labelProvider = new BPVariableElementLabelProvider( |
| inPreferencePage); |
| |
| fVariablesList = new ListDialogField(adapter, buttonLabels, |
| labelProvider); |
| fVariablesList.setDialogFieldListener(adapter); |
| fVariablesList.setLabelText(NewWizardMessages.VariableBlock_vars_label); |
| fVariablesList.setRemoveButtonIndex(2); |
| |
| fVariablesList.enableButton(1, false); |
| |
| // TODO: create a sorter or modify ListDialogField to work with |
| // comparators |
| // fVariablesList.setViewerComparator(new ViewerComparator() { |
| // public int compare(Viewer viewer, Object e1, Object e2) { |
| // if (e1 instanceof BPVariableElement |
| // && e2 instanceof BPVariableElement) { |
| // return getComparator().compare( |
| // ((BPVariableElement) e1).getName(), |
| // ((BPVariableElement) e2).getName()); |
| // } |
| // return super.compare(viewer, e1, e2); |
| // } |
| // }); |
| refresh(initSelection); |
| } |
| |
| public boolean hasChanges() { |
| return fHasChanges; |
| } |
| |
| public void setChanges(boolean hasChanges) { |
| fHasChanges = hasChanges; |
| } |
| |
| public Control createContents(Composite parent) { |
| Composite composite = new Composite(parent, SWT.NONE); |
| composite.setFont(parent.getFont()); |
| |
| LayoutUtil.doDefaultLayout(composite, |
| new DialogField[] { fVariablesList }, true, 0, 0); |
| LayoutUtil.setHorizontalGrabbing(fVariablesList.getListControl(null)); |
| |
| fWarning = new CLabel(composite, SWT.NONE); |
| fWarning.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, |
| fVariablesList.getNumberOfControls() - 1, 1)); |
| |
| fControl = composite; |
| |
| return composite; |
| } |
| |
| public void addDoubleClickListener(IDoubleClickListener listener) { |
| fVariablesList.getTableViewer().addDoubleClickListener(listener); |
| } |
| |
| public void addSelectionChangedListener(ISelectionChangedListener listener) { |
| fVariablesList.getTableViewer().addSelectionChangedListener(listener); |
| } |
| |
| private Shell getShell() { |
| if (fControl != null) { |
| return fControl.getShell(); |
| } |
| return DLTKUIPlugin.getActiveWorkbenchShell(); |
| } |
| |
| private class VariablesAdapter implements IDialogFieldListener, |
| IListAdapter { |
| |
| // -------- IListAdapter -------- |
| |
| @Override |
| public void customButtonPressed(ListDialogField field, int index) { |
| switch (index) { |
| case 0: /* add */ |
| editEntries(null); |
| break; |
| case 1: /* edit */ |
| List selected = field.getSelectedElements(); |
| editEntries((BPVariableElement) selected.get(0)); |
| break; |
| } |
| } |
| |
| @Override |
| public void selectionChanged(ListDialogField field) { |
| doSelectionChanged(field); |
| } |
| |
| @Override |
| public void doubleClicked(ListDialogField field) { |
| if (fEditOnDoubleclick) { |
| List selected = field.getSelectedElements(); |
| if (canEdit(selected, containsReadOnly(selected))) { |
| editEntries((BPVariableElement) selected.get(0)); |
| } |
| } |
| } |
| |
| // ---------- IDialogFieldListener -------- |
| |
| @Override |
| public void dialogFieldChanged(DialogField field) { |
| } |
| |
| } |
| |
| private boolean containsReadOnly(List selected) { |
| for (int i = selected.size() - 1; i >= 0; i--) { |
| if (((BPVariableElement) selected.get(i)).isReadOnly()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean canEdit(List selected, boolean containsReadOnly) { |
| return selected.size() == 1 && !containsReadOnly; |
| } |
| |
| /** |
| * @param field |
| * the dialog field |
| */ |
| private void doSelectionChanged(DialogField field) { |
| List selected = fVariablesList.getSelectedElements(); |
| boolean containsReadOnly = containsReadOnly(selected); |
| |
| // edit |
| fVariablesList.enableButton(1, canEdit(selected, containsReadOnly)); |
| // remove button |
| fVariablesList.enableButton(2, !containsReadOnly); |
| |
| fSelectedElements = selected; |
| } |
| |
| private void editEntries(BPVariableElement entry) { |
| List existingEntries = fVariablesList.getElements(); |
| |
| VariableCreationDialog dialog = new VariableCreationDialog(getShell(), |
| entry, existingEntries); |
| if (dialog.open() != Window.OK) { |
| return; |
| } |
| BPVariableElement newEntry = dialog.getBuildpathElement(); |
| if (entry == null) { |
| fVariablesList.addElement(newEntry); |
| entry = newEntry; |
| fHasChanges = true; |
| } else { |
| boolean hasChanges = !(entry.getName().equals(newEntry.getName()) && entry |
| .getPath().equals(newEntry.getPath())); |
| if (hasChanges) { |
| fHasChanges = true; |
| entry.setName(newEntry.getName()); |
| entry.setPath(newEntry.getPath()); |
| fVariablesList.refresh(); |
| } |
| } |
| fVariablesList.selectElements(new StructuredSelection(entry)); |
| } |
| |
| public List getSelectedElements() { |
| return fSelectedElements; |
| } |
| |
| public boolean performOk() { |
| ArrayList removedVariables = new ArrayList(); |
| ArrayList changedVariables = new ArrayList(); |
| removedVariables.addAll(Arrays.asList(DLTKCore |
| .getBuildpathVariableNames())); |
| |
| // remove all unchanged |
| List changedElements = fVariablesList.getElements(); |
| for (int i = changedElements.size() - 1; i >= 0; i--) { |
| BPVariableElement curr = (BPVariableElement) changedElements.get(i); |
| if (curr.isReadOnly()) { |
| changedElements.remove(curr); |
| } else { |
| IPath path = curr.getPath(); |
| IPath prevPath = DLTKCore.getBuildpathVariable(curr.getName()); |
| if (prevPath != null && prevPath.equals(path)) { |
| changedElements.remove(curr); |
| } else { |
| changedVariables.add(curr.getName()); |
| } |
| } |
| removedVariables.remove(curr.getName()); |
| } |
| int steps = changedElements.size() + removedVariables.size(); |
| if (steps > 0) { |
| |
| boolean needsBuild = false; |
| if (fAskToBuild |
| && doesChangeRequireFullBuild(removedVariables, |
| changedVariables)) { |
| String title = NewWizardMessages.VariableBlock_needsbuild_title; |
| String message = NewWizardMessages.VariableBlock_needsbuild_message; |
| |
| MessageDialog buildDialog = new MessageDialog(getShell(), |
| title, null, message, MessageDialog.QUESTION, |
| new String[] { IDialogConstants.YES_LABEL, |
| IDialogConstants.NO_LABEL, |
| IDialogConstants.CANCEL_LABEL }, 2); |
| int res = buildDialog.open(); |
| if (res != 0 && res != 1) { |
| return false; |
| } |
| needsBuild = (res == 0); |
| } |
| |
| final VariableBlockRunnable runnable = new VariableBlockRunnable( |
| removedVariables, changedElements); |
| final ProgressMonitorDialog dialog = new ProgressMonitorDialog( |
| getShell()); |
| try { |
| dialog.run(true, true, runnable); |
| } catch (InvocationTargetException e) { |
| ExceptionHandler |
| .handle( |
| new InvocationTargetException( |
| new NullPointerException()), |
| getShell(), |
| NewWizardMessages.VariableBlock_variableSettingError_titel, |
| NewWizardMessages.VariableBlock_variableSettingError_message); |
| return false; |
| } catch (InterruptedException e) { |
| return false; |
| } |
| |
| if (needsBuild) { |
| CoreUtility.getBuildJob(null).schedule(); |
| } |
| } |
| return true; |
| } |
| |
| private boolean doesChangeRequireFullBuild(List removed, List changed) { |
| try { |
| IScriptModel model = DLTKCore.create(ResourcesPlugin.getWorkspace() |
| .getRoot()); |
| IScriptProject[] projects = model.getScriptProjects(); |
| for (int i = 0; i < projects.length; i++) { |
| IBuildpathEntry[] entries = projects[i].getRawBuildpath(); |
| for (int k = 0; k < entries.length; k++) { |
| IBuildpathEntry curr = entries[k]; |
| if (curr.getEntryKind() == IBuildpathEntry.BPE_VARIABLE) { |
| String var = curr.getPath().segment(0); |
| if (removed.contains(var) || changed.contains(var)) { |
| return true; |
| } |
| } |
| } |
| } |
| } catch (ModelException e) { |
| return true; |
| } |
| return false; |
| } |
| |
| private class VariableBlockRunnable implements IRunnableWithProgress { |
| private final List fToRemove; |
| private final List fToChange; |
| |
| public VariableBlockRunnable(List toRemove, List toChange) { |
| fToRemove = toRemove; |
| fToChange = toChange; |
| } |
| |
| @Override |
| public void run(IProgressMonitor monitor) |
| throws InvocationTargetException, InterruptedException { |
| monitor |
| .beginTask(NewWizardMessages.VariableBlock_operation_desc, |
| 1); |
| try { |
| setVariables(monitor); |
| |
| } catch (CoreException e) { |
| throw new InvocationTargetException(e); |
| } catch (OperationCanceledException e) { |
| throw new InterruptedException(); |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| public void setVariables(IProgressMonitor monitor) |
| throws ModelException, CoreException { |
| int nVariables = fToChange.size() + fToRemove.size(); |
| |
| String[] names = new String[nVariables]; |
| IPath[] paths = new IPath[nVariables]; |
| int k = 0; |
| |
| for (int i = 0; i < fToChange.size(); i++) { |
| BPVariableElement curr = (BPVariableElement) fToChange.get(i); |
| names[k] = curr.getName(); |
| paths[k] = curr.getPath(); |
| k++; |
| } |
| for (int i = 0; i < fToRemove.size(); i++) { |
| names[k] = (String) fToRemove.get(i); |
| paths[k] = null; |
| k++; |
| } |
| DLTKCore.setBuildpathVariables(names, paths, |
| new SubProgressMonitor(monitor, 1)); |
| } |
| } |
| |
| /** |
| * If set to true, a dialog will ask the user to build on variable changed |
| * |
| * @param askToBuild |
| * The askToBuild to set |
| */ |
| public void setAskToBuild(boolean askToBuild) { |
| fAskToBuild = askToBuild; |
| } |
| |
| /** |
| * @param initSelection |
| * the initial selection |
| */ |
| public void refresh(String initSelection) { |
| BPVariableElement initSelectedElement = null; |
| |
| String[] entries = DLTKCore.getBuildpathVariableNames(); |
| ArrayList elements = new ArrayList(entries.length); |
| for (int i = 0; i < entries.length; i++) { |
| String name = entries[i]; |
| BPVariableElement elem; |
| IPath entryPath = DLTKCore.getBuildpathVariable(name); |
| if (entryPath != null) { |
| elem = new BPVariableElement(name, entryPath); |
| elements.add(elem); |
| if (name.equals(initSelection)) { |
| initSelectedElement = elem; |
| } |
| } else { |
| DLTKUIPlugin |
| .logErrorMessage("VariableBlock: Buildpath variable with null value: " + name); //$NON-NLS-1$ |
| } |
| } |
| |
| fVariablesList.setElements(elements); |
| |
| if (initSelectedElement != null) { |
| ISelection sel = new StructuredSelection(initSelectedElement); |
| fVariablesList.selectElements(sel); |
| } else { |
| fVariablesList.selectFirstElement(); |
| } |
| |
| fHasChanges = false; |
| } |
| |
| public void setSelection(String elementName) { |
| for (int i = 0; i < fVariablesList.getSize(); i++) { |
| BPVariableElement elem = (BPVariableElement) fVariablesList |
| .getElement(i); |
| if (elem.getName().equals(elementName)) { |
| fVariablesList.selectElements(new StructuredSelection(elem)); |
| return; |
| } |
| } |
| } |
| |
| } |