001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.ui.wizards.buildpaths;
011:
012: import java.lang.reflect.InvocationTargetException;
013: import java.util.ArrayList;
014: import java.util.Arrays;
015: import java.util.Iterator;
016: import java.util.List;
017:
018: import org.eclipse.core.runtime.CoreException;
019: import org.eclipse.core.runtime.IPath;
020: import org.eclipse.core.runtime.IProgressMonitor;
021: import org.eclipse.core.runtime.OperationCanceledException;
022: import org.eclipse.core.runtime.SubProgressMonitor;
023:
024: import org.eclipse.core.resources.ResourcesPlugin;
025:
026: import org.eclipse.swt.SWT;
027: import org.eclipse.swt.custom.CLabel;
028: import org.eclipse.swt.layout.GridData;
029: import org.eclipse.swt.widgets.Composite;
030: import org.eclipse.swt.widgets.Control;
031: import org.eclipse.swt.widgets.Shell;
032:
033: import org.eclipse.jface.dialogs.Dialog;
034: import org.eclipse.jface.dialogs.IDialogConstants;
035: import org.eclipse.jface.dialogs.MessageDialog;
036: import org.eclipse.jface.dialogs.ProgressMonitorDialog;
037: import org.eclipse.jface.operation.IRunnableWithProgress;
038: import org.eclipse.jface.resource.JFaceResources;
039: import org.eclipse.jface.viewers.IDoubleClickListener;
040: import org.eclipse.jface.viewers.ISelection;
041: import org.eclipse.jface.viewers.ISelectionChangedListener;
042: import org.eclipse.jface.viewers.StructuredSelection;
043: import org.eclipse.jface.viewers.Viewer;
044: import org.eclipse.jface.viewers.ViewerComparator;
045: import org.eclipse.jface.window.Window;
046:
047: import org.eclipse.jdt.core.IClasspathEntry;
048: import org.eclipse.jdt.core.IJavaModel;
049: import org.eclipse.jdt.core.IJavaProject;
050: import org.eclipse.jdt.core.JavaCore;
051: import org.eclipse.jdt.core.JavaModelException;
052:
053: import org.eclipse.jdt.internal.ui.JavaPlugin;
054: import org.eclipse.jdt.internal.ui.util.CoreUtility;
055: import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
056: import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
057: import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
058: import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
059: import org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter;
060: import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
061: import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField;
062:
063: public class VariableBlock {
064:
065: private ListDialogField fVariablesList;
066: private Control fControl;
067: private CLabel fWarning;
068: private boolean fHasChanges;
069:
070: private List fSelectedElements;
071: private boolean fAskToBuild;
072: private final boolean fEditOnDoubleclick;
073:
074: public VariableBlock(boolean inPreferencePage, String initSelection) {
075:
076: fSelectedElements = new ArrayList(0);
077: fEditOnDoubleclick = inPreferencePage;
078: fAskToBuild = true;
079:
080: String[] buttonLabels = new String[] {
081: NewWizardMessages.VariableBlock_vars_add_button,
082: NewWizardMessages.VariableBlock_vars_edit_button,
083: NewWizardMessages.VariableBlock_vars_remove_button };
084:
085: VariablesAdapter adapter = new VariablesAdapter();
086:
087: CPVariableElementLabelProvider labelProvider = new CPVariableElementLabelProvider(
088: inPreferencePage);
089:
090: fVariablesList = new ListDialogField(adapter, buttonLabels,
091: labelProvider);
092: fVariablesList.setDialogFieldListener(adapter);
093: fVariablesList
094: .setLabelText(NewWizardMessages.VariableBlock_vars_label);
095: fVariablesList.setRemoveButtonIndex(2);
096:
097: fVariablesList.enableButton(1, false);
098:
099: fVariablesList.setViewerComparator(new ViewerComparator() {
100: public int compare(Viewer viewer, Object e1, Object e2) {
101: if (e1 instanceof CPVariableElement
102: && e2 instanceof CPVariableElement) {
103: return getComparator().compare(
104: ((CPVariableElement) e1).getName(),
105: ((CPVariableElement) e2).getName());
106: }
107: return super .compare(viewer, e1, e2);
108: }
109: });
110: refresh(initSelection);
111: }
112:
113: public boolean hasChanges() {
114: return fHasChanges;
115: }
116:
117: public void setChanges(boolean hasChanges) {
118: fHasChanges = hasChanges;
119: }
120:
121: public Control createContents(Composite parent) {
122: Composite composite = new Composite(parent, SWT.NONE);
123: composite.setFont(parent.getFont());
124:
125: LayoutUtil.doDefaultLayout(composite,
126: new DialogField[] { fVariablesList }, true, 0, 0);
127: LayoutUtil.setHorizontalGrabbing(fVariablesList
128: .getListControl(null));
129:
130: fWarning = new CLabel(composite, SWT.NONE);
131: fWarning.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true,
132: false, fVariablesList.getNumberOfControls() - 1, 1));
133:
134: fControl = composite;
135: updateDeprecationWarning();
136:
137: return composite;
138: }
139:
140: public void addDoubleClickListener(IDoubleClickListener listener) {
141: fVariablesList.getTableViewer()
142: .addDoubleClickListener(listener);
143: }
144:
145: public void addSelectionChangedListener(
146: ISelectionChangedListener listener) {
147: fVariablesList.getTableViewer().addSelectionChangedListener(
148: listener);
149: }
150:
151: private Shell getShell() {
152: if (fControl != null) {
153: return fControl.getShell();
154: }
155: return JavaPlugin.getActiveWorkbenchShell();
156: }
157:
158: private class VariablesAdapter implements IDialogFieldListener,
159: IListAdapter {
160:
161: // -------- IListAdapter --------
162:
163: public void customButtonPressed(ListDialogField field, int index) {
164: switch (index) {
165: case 0: /* add */
166: editEntries(null);
167: break;
168: case 1: /* edit */
169: List selected = field.getSelectedElements();
170: editEntries((CPVariableElement) selected.get(0));
171: break;
172: }
173: }
174:
175: public void selectionChanged(ListDialogField field) {
176: doSelectionChanged(field);
177: }
178:
179: public void doubleClicked(ListDialogField field) {
180: if (fEditOnDoubleclick) {
181: List selected = field.getSelectedElements();
182: if (canEdit(selected, containsReadOnly(selected))) {
183: editEntries((CPVariableElement) selected.get(0));
184: }
185: }
186: }
187:
188: // ---------- IDialogFieldListener --------
189:
190: public void dialogFieldChanged(DialogField field) {
191: }
192:
193: }
194:
195: private boolean containsReadOnly(List selected) {
196: for (int i = selected.size() - 1; i >= 0; i--) {
197: if (((CPVariableElement) selected.get(i)).isReadOnly()) {
198: return true;
199: }
200: }
201: return false;
202: }
203:
204: private boolean canEdit(List selected, boolean containsReadOnly) {
205: return selected.size() == 1 && !containsReadOnly;
206: }
207:
208: private void doSelectionChanged(DialogField field) {
209: List selected = fVariablesList.getSelectedElements();
210: boolean containsReadOnly = containsReadOnly(selected);
211:
212: // edit
213: fVariablesList.enableButton(1, canEdit(selected,
214: containsReadOnly));
215: // remove button
216: fVariablesList.enableButton(2, !containsReadOnly);
217:
218: fSelectedElements = selected;
219: updateDeprecationWarning();
220: }
221:
222: private void updateDeprecationWarning() {
223: if (fWarning == null || fWarning.isDisposed())
224: return;
225:
226: for (Iterator iter = fSelectedElements.iterator(); iter
227: .hasNext();) {
228: CPVariableElement element = (CPVariableElement) iter.next();
229: String deprecationMessage = element.getDeprecationMessage();
230: if (deprecationMessage != null) {
231: fWarning.setText(deprecationMessage);
232: fWarning.setImage(JFaceResources
233: .getImage(Dialog.DLG_IMG_MESSAGE_WARNING));
234: return;
235: }
236: }
237: fWarning.setText(null);
238: fWarning.setImage(null);
239: }
240:
241: private void editEntries(CPVariableElement entry) {
242: List existingEntries = fVariablesList.getElements();
243:
244: VariableCreationDialog dialog = new VariableCreationDialog(
245: getShell(), entry, existingEntries);
246: if (dialog.open() != Window.OK) {
247: return;
248: }
249: CPVariableElement newEntry = dialog.getClasspathElement();
250: if (entry == null) {
251: fVariablesList.addElement(newEntry);
252: entry = newEntry;
253: fHasChanges = true;
254: } else {
255: boolean hasChanges = !(entry.getName().equals(
256: newEntry.getName()) && entry.getPath().equals(
257: newEntry.getPath()));
258: if (hasChanges) {
259: fHasChanges = true;
260: entry.setName(newEntry.getName());
261: entry.setPath(newEntry.getPath());
262: fVariablesList.refresh();
263: }
264: }
265: fVariablesList.selectElements(new StructuredSelection(entry));
266: }
267:
268: public List getSelectedElements() {
269: return fSelectedElements;
270: }
271:
272: public boolean performOk() {
273: ArrayList removedVariables = new ArrayList();
274: ArrayList changedVariables = new ArrayList();
275: removedVariables.addAll(Arrays.asList(JavaCore
276: .getClasspathVariableNames()));
277:
278: // remove all unchanged
279: List changedElements = fVariablesList.getElements();
280: for (int i = changedElements.size() - 1; i >= 0; i--) {
281: CPVariableElement curr = (CPVariableElement) changedElements
282: .get(i);
283: if (curr.isReadOnly()) {
284: changedElements.remove(curr);
285: } else {
286: IPath path = curr.getPath();
287: IPath prevPath = JavaCore.getClasspathVariable(curr
288: .getName());
289: if (prevPath != null && prevPath.equals(path)) {
290: changedElements.remove(curr);
291: } else {
292: changedVariables.add(curr.getName());
293: }
294: }
295: removedVariables.remove(curr.getName());
296: }
297: int steps = changedElements.size() + removedVariables.size();
298: if (steps > 0) {
299:
300: boolean needsBuild = false;
301: if (fAskToBuild
302: && doesChangeRequireFullBuild(removedVariables,
303: changedVariables)) {
304: String title = NewWizardMessages.VariableBlock_needsbuild_title;
305: String message = NewWizardMessages.VariableBlock_needsbuild_message;
306:
307: MessageDialog buildDialog = new MessageDialog(
308: getShell(), title, null, message,
309: MessageDialog.QUESTION, new String[] {
310: IDialogConstants.YES_LABEL,
311: IDialogConstants.NO_LABEL,
312: IDialogConstants.CANCEL_LABEL }, 2);
313: int res = buildDialog.open();
314: if (res != 0 && res != 1) {
315: return false;
316: }
317: needsBuild = (res == 0);
318: }
319:
320: final VariableBlockRunnable runnable = new VariableBlockRunnable(
321: removedVariables, changedElements);
322: final ProgressMonitorDialog dialog = new ProgressMonitorDialog(
323: getShell());
324: try {
325: dialog.run(true, true, runnable);
326: } catch (InvocationTargetException e) {
327: ExceptionHandler
328: .handle(
329: new InvocationTargetException(
330: new NullPointerException()),
331: getShell(),
332: NewWizardMessages.VariableBlock_variableSettingError_titel,
333: NewWizardMessages.VariableBlock_variableSettingError_message);
334: return false;
335: } catch (InterruptedException e) {
336: return false;
337: }
338:
339: if (needsBuild) {
340: CoreUtility.getBuildJob(null).schedule();
341: }
342: }
343: return true;
344: }
345:
346: private boolean doesChangeRequireFullBuild(List removed,
347: List changed) {
348: try {
349: IJavaModel model = JavaCore.create(ResourcesPlugin
350: .getWorkspace().getRoot());
351: IJavaProject[] projects = model.getJavaProjects();
352: for (int i = 0; i < projects.length; i++) {
353: IClasspathEntry[] entries = projects[i]
354: .getRawClasspath();
355: for (int k = 0; k < entries.length; k++) {
356: IClasspathEntry curr = entries[k];
357: if (curr.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
358: String var = curr.getPath().segment(0);
359: if (removed.contains(var)
360: || changed.contains(var)) {
361: return true;
362: }
363: }
364: }
365: }
366: } catch (JavaModelException e) {
367: return true;
368: }
369: return false;
370: }
371:
372: private class VariableBlockRunnable implements
373: IRunnableWithProgress {
374: private List fToRemove;
375: private List fToChange;
376:
377: public VariableBlockRunnable(List toRemove, List toChange) {
378: fToRemove = toRemove;
379: fToChange = toChange;
380: }
381:
382: /*
383: * @see IRunnableWithProgress#run(IProgressMonitor)
384: */
385: public void run(IProgressMonitor monitor)
386: throws InvocationTargetException, InterruptedException {
387: monitor.beginTask(
388: NewWizardMessages.VariableBlock_operation_desc, 1);
389: try {
390: setVariables(monitor);
391:
392: } catch (CoreException e) {
393: throw new InvocationTargetException(e);
394: } catch (OperationCanceledException e) {
395: throw new InterruptedException();
396: } finally {
397: monitor.done();
398: }
399: }
400:
401: public void setVariables(IProgressMonitor monitor)
402: throws JavaModelException, CoreException {
403: int nVariables = fToChange.size() + fToRemove.size();
404:
405: String[] names = new String[nVariables];
406: IPath[] paths = new IPath[nVariables];
407: int k = 0;
408:
409: for (int i = 0; i < fToChange.size(); i++) {
410: CPVariableElement curr = (CPVariableElement) fToChange
411: .get(i);
412: names[k] = curr.getName();
413: paths[k] = curr.getPath();
414: k++;
415: }
416: for (int i = 0; i < fToRemove.size(); i++) {
417: names[k] = (String) fToRemove.get(i);
418: paths[k] = null;
419: k++;
420: }
421: JavaCore.setClasspathVariables(names, paths,
422: new SubProgressMonitor(monitor, 1));
423: }
424: }
425:
426: /**
427: * If set to true, a dialog will ask the user to build on variable changed
428: * @param askToBuild The askToBuild to set
429: */
430: public void setAskToBuild(boolean askToBuild) {
431: fAskToBuild = askToBuild;
432: }
433:
434: /**
435: *
436: */
437: public void refresh(String initSelection) {
438: CPVariableElement initSelectedElement = null;
439:
440: String[] entries = JavaCore.getClasspathVariableNames();
441: ArrayList elements = new ArrayList(entries.length);
442: for (int i = 0; i < entries.length; i++) {
443: String name = entries[i];
444: CPVariableElement elem;
445: IPath entryPath = JavaCore.getClasspathVariable(name);
446: if (entryPath != null) {
447: elem = new CPVariableElement(name, entryPath);
448: elements.add(elem);
449: if (name.equals(initSelection)) {
450: initSelectedElement = elem;
451: }
452: } else {
453: JavaPlugin
454: .logErrorMessage("VariableBlock: Classpath variable with null value: " + name); //$NON-NLS-1$
455: }
456: }
457:
458: fVariablesList.setElements(elements);
459:
460: if (initSelectedElement != null) {
461: ISelection sel = new StructuredSelection(
462: initSelectedElement);
463: fVariablesList.selectElements(sel);
464: } else {
465: fVariablesList.selectFirstElement();
466: }
467:
468: fHasChanges = false;
469: }
470:
471: public void setSelection(String elementName) {
472: for (int i = 0; i < fVariablesList.getSize(); i++) {
473: CPVariableElement elem = (CPVariableElement) fVariablesList
474: .getElement(i);
475: if (elem.getName().equals(elementName)) {
476: fVariablesList.selectElements(new StructuredSelection(
477: elem));
478: return;
479: }
480: }
481: }
482:
483: }
|