001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 BEA Systems, Inc.
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: * wharley@bea.com - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.apt.ui.internal.preferences;
011:
012: import java.util.ArrayList;
013: import java.util.LinkedHashMap;
014: import java.util.List;
015: import java.util.Map;
016:
017: import org.eclipse.core.resources.IFile;
018: import org.eclipse.core.resources.IProject;
019: import org.eclipse.core.resources.IResource;
020: import org.eclipse.core.resources.IWorkspaceRoot;
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.core.runtime.IPath;
023: import org.eclipse.core.runtime.Path;
024: import org.eclipse.core.runtime.preferences.IScopeContext;
025: import org.eclipse.jdt.apt.core.internal.util.FactoryContainer;
026: import org.eclipse.jdt.apt.core.internal.util.FactoryPath;
027: import org.eclipse.jdt.apt.core.internal.util.FactoryPathUtil;
028: import org.eclipse.jdt.apt.core.internal.util.FactoryPath.Attributes;
029: import org.eclipse.jdt.apt.core.util.AptConfig;
030: import org.eclipse.jdt.apt.core.util.IFactoryPath;
031: import org.eclipse.jdt.apt.ui.internal.util.ExceptionHandler;
032: import org.eclipse.jdt.core.IJavaProject;
033: import org.eclipse.jdt.core.JavaCore;
034: import org.eclipse.jdt.internal.ui.util.PixelConverter;
035: import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener;
036: import org.eclipse.jdt.internal.ui.wizards.dialogfields.CheckedListDialogField;
037: import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
038: import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
039: import org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter;
040: import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
041: import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField;
042: import org.eclipse.jdt.ui.wizards.BuildPathDialogAccess;
043: import org.eclipse.jface.dialogs.Dialog;
044: import org.eclipse.jface.viewers.ITableLabelProvider;
045: import org.eclipse.jface.viewers.LabelProvider;
046: import org.eclipse.jface.window.Window;
047: import org.eclipse.swt.SWT;
048: import org.eclipse.swt.graphics.Image;
049: import org.eclipse.swt.widgets.Composite;
050: import org.eclipse.swt.widgets.Control;
051: import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
052:
053: /**
054: * Data and controls for the Java Annotation Factory Path preference page.
055: */
056: public class FactoryPathConfigurationBlock extends
057: BaseConfigurationBlock {
058:
059: private static final int IDX_UP = 0;
060: private static final int IDX_DOWN = 1;
061: // 2
062: private static final int IDX_ADDJAR = 3;
063: private static final int IDX_ADDEXTJAR = 4;
064: private static final int IDX_ADDVAR = 5;
065: // 6
066: private static final int IDX_EDIT = 7;
067: private static final int IDX_ADVANCED = 8;
068: private static final int IDX_REMOVE = 9;
069: // 10
070: private static final int IDX_ENABLEALL = 11;
071: private static final int IDX_DISABLEALL = 12;
072:
073: private final static String[] buttonLabels = {
074: Messages.FactoryPathConfigurationBlock_up,
075: Messages.FactoryPathConfigurationBlock_down,
076: null, // 2
077: Messages.FactoryPathConfigurationBlock_addJars,
078: Messages.FactoryPathConfigurationBlock_addExternalJars,
079: Messages.FactoryPathConfigurationBlock_addVariable,
080: null, // 6
081: Messages.FactoryPathConfigurationBlock_edit,
082: Messages.FactoryPathConfigurationBlock_advanced,
083: Messages.FactoryPathConfigurationBlock_remove,
084: null, // 10
085: Messages.FactoryPathConfigurationBlock_enableAll,
086: Messages.FactoryPathConfigurationBlock_disableAll };
087:
088: /**
089: * Event handler for factory path list control
090: */
091: private class FactoryPathAdapter implements IListAdapter,
092: IDialogFieldListener {
093: public void customButtonPressed(ListDialogField field, int index) {
094: FactoryPathConfigurationBlock.this
095: .customButtonPressed(index);
096: }
097:
098: public void selectionChanged(ListDialogField field) {
099: boolean enableRemove = canRemove();
100: field.enableButton(IDX_REMOVE, enableRemove);
101: boolean enableEdit = canEdit();
102: field.enableButton(IDX_EDIT, enableEdit);
103: boolean enableAdvanced = canAdvanced();
104: field.enableButton(IDX_ADVANCED, enableAdvanced);
105: }
106:
107: /**
108: * This method gets called when, among other things, a checkbox is
109: * clicked. However, it doesn't get any information about which
110: * item it was whose checkbox was clicked. We could hook into the
111: * list control's CheckboxTableViewer event listener for changes to
112: * individual checkboxes; but that does not get called for enableAll
113: * and disableAll events.
114: */
115: public void dialogFieldChanged(DialogField field) {
116: if (!fSettingListContents) {
117: updateFactoryPathEntries();
118: }
119: }
120:
121: public void doubleClicked(ListDialogField field) {
122: if (canEdit()) {
123: editSelectedItem();
124: }
125: }
126: }
127:
128: private class FactoryPathLabelProvider extends LabelProvider
129: implements ITableLabelProvider {
130:
131: public Image getColumnImage(Object element, int columnIndex) {
132: return null;
133: }
134:
135: public String getColumnText(Object element, int columnIndex) {
136: if (!(element instanceof FactoryPathEntry)) {
137: return ""; //$NON-NLS-1$
138: }
139: FactoryPathEntry fpe = (FactoryPathEntry) element;
140: if (columnIndex == 0) {
141: return fpe._fc.toString();
142: } else {
143: return ""; //$NON-NLS-1$
144: }
145: }
146: }
147:
148: /**
149: * The factory path is a list of containers, plus some information about
150: * each container. That makes it a list of FactoryPathEntry.
151: */
152: private static class FactoryPathEntry {
153: /* shallow copies - beware! */
154: public final FactoryContainer _fc;
155: public FactoryPath.Attributes _attr;
156:
157: // CONSTRUCTORS
158: public FactoryPathEntry(FactoryContainer fc,
159: FactoryPath.Attributes attr) {
160: _fc = fc;
161: _attr = attr;
162: }
163:
164: // CONVERSION TO/FROM INDIVIDUAL ELEMENTS
165: public static Map<FactoryContainer, Attributes> pathMapFromList(
166: List<FactoryPathEntry> list) {
167: Map<FactoryContainer, FactoryPath.Attributes> map = new LinkedHashMap<FactoryContainer, FactoryPath.Attributes>(
168: list.size());
169: for (FactoryPathEntry fpe : list) {
170: map.put(fpe._fc, fpe._attr);
171: }
172: return map;
173: }
174:
175: public static List<FactoryPathEntry> pathListFromMap(
176: Map<FactoryContainer, Attributes> map) {
177: List<FactoryPathEntry> list = new ArrayList<FactoryPathEntry>(
178: map.size());
179: for (Map.Entry<FactoryContainer, Attributes> entry : map
180: .entrySet()) {
181: FactoryPathEntry fpe = new FactoryPathEntry(entry
182: .getKey(), entry.getValue());
183: list.add(fpe);
184: }
185: return list;
186: }
187:
188: // SUPPORT FOR COMPARISON
189: public boolean equals(Object obj) {
190: if (!(obj instanceof FactoryPathEntry))
191: return false;
192: FactoryPathEntry fpe = (FactoryPathEntry) obj;
193: return _fc.equals(fpe._fc) && _attr.equals(fpe._attr);
194: }
195:
196: public int hashCode() {
197: return _fc.hashCode() ^ _attr.hashCode();
198: }
199:
200: }
201:
202: private PixelConverter fPixelConverter;
203: private Composite fBlockControl; // the control representing the entire configuration block
204:
205: /**
206: * The factory path at the time this pref pane was launched.
207: * Use this to see if anything changed at save time.
208: */
209: private List<FactoryPathEntry> fOriginalPath;
210:
211: private final IJavaProject fJProj;
212:
213: /**
214: * The GUI control representing the factory path. Its data items
215: * are of type FactoryPathEntry.
216: */
217: private CheckedListDialogField fFactoryPathList;
218:
219: /**
220: * True while inside setListContents(). Used in order to efficiently
221: * and correctly add new elements to the factory list: short-circuits
222: * the factory list field listener code.
223: */
224: private boolean fSettingListContents = false;
225:
226: public FactoryPathConfigurationBlock(IStatusChangeListener context,
227: IProject project, IWorkbenchPreferenceContainer container) {
228: super (context, project, new Key[] {}, container);
229:
230: fJProj = JavaCore.create(project);
231:
232: FactoryPathAdapter adapter = new FactoryPathAdapter();
233: FactoryPathLabelProvider labelProvider = new FactoryPathLabelProvider();
234:
235: fFactoryPathList = new CheckedListDialogField(adapter,
236: buttonLabels, labelProvider);
237: fFactoryPathList.setDialogFieldListener(adapter);
238: fFactoryPathList
239: .setLabelText(Messages.FactoryPathConfigurationBlock_pluginsAndJars);
240: fFactoryPathList.setUpButtonIndex(IDX_UP);
241: fFactoryPathList.setDownButtonIndex(IDX_DOWN);
242: fFactoryPathList.setRemoveButtonIndex(IDX_REMOVE);
243: fFactoryPathList.setCheckAllButtonIndex(IDX_ENABLEALL);
244: fFactoryPathList.setUncheckAllButtonIndex(IDX_DISABLEALL);
245: }
246:
247: /**
248: * Respond to the user checking the "enabled" checkbox of an entry
249: * in the factory path control, by replacing the FactoryPathEntry
250: * with a new one with the correct "enabled" value.
251: * We don't have information about which entry was changed, so we
252: * have to look at all of them. This is inefficient - somewhere
253: * around O(n log n) depending on how the list is implemented - but
254: * hopefully the list is not so huge that it's a problem.
255: */
256: private void updateFactoryPathEntries() {
257: for (FactoryPathEntry fpe : getListContents()) {
258: boolean checked = fFactoryPathList.isChecked(fpe);
259: if (checked != fpe._attr.isEnabled()) {
260: fpe._attr.setEnabled(checked);
261: }
262: }
263: }
264:
265: /**
266: * Respond to a button in the button bar.
267: * Most buttons are handled by code in CheckedListDialogField;
268: * this method is for the rest, e.g., Add External Jar.
269: * @param index
270: */
271: public void customButtonPressed(int index) {
272: FactoryPathEntry[] newEntries = null;
273: switch (index) {
274: case IDX_ADDJAR: // add jars in project
275: newEntries = openJarFileDialog(null);
276: addEntries(newEntries);
277: break;
278:
279: case IDX_ADDEXTJAR: // add external jars
280: newEntries = openExtJarFileDialog(null);
281: addEntries(newEntries);
282: break;
283:
284: case IDX_ADDVAR: // add jar from classpath variable
285: newEntries = openVariableSelectionDialog(null);
286: addEntries(newEntries);
287: break;
288:
289: case IDX_EDIT: // edit selected item
290: if (canEdit()) {
291: editSelectedItem();
292: }
293: break;
294:
295: case IDX_ADVANCED: // advanced options
296: advancedOptionsDialog();
297: break;
298: }
299:
300: }
301:
302: /**
303: * Can't remove a selection that contains a plugin.
304: */
305: private boolean canRemove() {
306: List<FactoryPathEntry> selected = getSelectedListContents();
307: boolean containsPlugin = false;
308: for (FactoryPathEntry fpe : selected) {
309: if (fpe._fc.getType() == FactoryContainer.FactoryType.PLUGIN) {
310: containsPlugin = true;
311: break;
312: }
313: }
314: return !containsPlugin;
315: }
316:
317: /**
318: * Can only edit a single item at a time. Can't edit plugins.
319: */
320: private boolean canEdit() {
321: List<FactoryPathEntry> selected = getSelectedListContents();
322: if (selected.size() != 1) {
323: return false;
324: }
325: FactoryContainer fc = selected.get(0)._fc;
326: return (fc.getType() != FactoryContainer.FactoryType.PLUGIN);
327: }
328:
329: /**
330: * Can only launch the 'advanced' dialog on a single item at a time.
331: */
332: private boolean canAdvanced() {
333: List<FactoryPathEntry> selected = getSelectedListContents();
334: return (selected.size() == 1);
335: }
336:
337: /**
338: * Edit the item selected.
339: * Precondition: exactly one item is selected in the list,
340: * and it is an editable item (not a plugin).
341: * @param field a listbox of FactoryContainers.
342: */
343: private void editSelectedItem() {
344: List<FactoryPathEntry> selected = getSelectedListContents();
345: if (selected.size() != 1) {
346: return;
347: }
348: FactoryPathEntry original = selected.get(0);
349: FactoryPathEntry[] edited = null;
350: switch (original._fc.getType()) {
351: case PLUGIN:
352: return;
353: case EXTJAR:
354: edited = openExtJarFileDialog(original);
355: break;
356: case VARJAR:
357: edited = openVariableSelectionDialog(original);
358: break;
359: case WKSPJAR:
360: edited = openJarFileDialog(original);
361: break;
362: }
363: if (edited != null && edited.length > 0) {
364: fFactoryPathList.replaceElement(original, edited[0]);
365: }
366: }
367:
368: /* (non-Javadoc)
369: * @see org.eclipse.jdt.apt.ui.internal.preferences.BaseConfigurationBlock#createContents(org.eclipse.swt.widgets.Composite)
370: */
371: protected Control createContents(Composite parent) {
372: setShell(parent.getShell());
373:
374: fPixelConverter = new PixelConverter(parent);
375:
376: fBlockControl = new Composite(parent, SWT.NONE);
377: fBlockControl.setFont(parent.getFont());
378:
379: Dialog.applyDialogFont(fBlockControl);
380:
381: LayoutUtil.doDefaultLayout(fBlockControl,
382: new DialogField[] { fFactoryPathList }, true,
383: SWT.DEFAULT, SWT.DEFAULT);
384: LayoutUtil.setHorizontalGrabbing(fFactoryPathList
385: .getListControl(null));
386:
387: fFactoryPathList.enableButton(IDX_ADDJAR, (fJProj != null));
388: // bugzilla 139101: only enable Advanced and Edit buttons if there is a selection
389: fFactoryPathList.enableButton(IDX_ADVANCED, false);
390: fFactoryPathList.enableButton(IDX_EDIT, false);
391: int buttonBarWidth = fPixelConverter
392: .convertWidthInCharsToPixels(24);
393: fFactoryPathList.setButtonsMinWidth(buttonBarWidth);
394:
395: return fBlockControl;
396: }
397:
398: @Override
399: public boolean hasProjectSpecificOptionsNoCache(IProject project) {
400: return (project == null) ? false
401: : AptConfig.hasProjectSpecificFactoryPath(JavaCore
402: .create(project));
403: }
404:
405: /**
406: * Initialize the user interface based on the cached original settings.
407: */
408: @Override
409: protected void initContents() {
410: setListContents(fOriginalPath);
411: }
412:
413: /**
414: * Save reference copies of the settings, so we can see if anything changed.
415: * This must stay in sync with the actual saved values for the rebuild logic
416: * to work; so be sure to call this any time you save (eg in performApply()).
417: */
418: @Override
419: protected void cacheOriginalValues() {
420: IFactoryPath ifp = AptConfig.getFactoryPath(fJProj);
421: // we'll risk this downcast because we're such good buddies with apt.core.
422: FactoryPath fp = (FactoryPath) ifp;
423: Map<FactoryContainer, FactoryPath.Attributes> path = fp
424: .getAllContainers();
425: fOriginalPath = FactoryPathEntry.pathListFromMap(path);
426: super .cacheOriginalValues();
427: }
428:
429: /*
430: * Helper method to get rid of unchecked conversion warning
431: */
432: @SuppressWarnings("unchecked")
433: private List<FactoryPathEntry> getListContents() {
434: List<FactoryPathEntry> contents = fFactoryPathList
435: .getElements();
436: return contents;
437: }
438:
439: /*
440: * Helper method to get rid of unchecked conversion warning
441: */
442: @SuppressWarnings("unchecked")
443: private List<FactoryPathEntry> getSelectedListContents() {
444: List<FactoryPathEntry> contents = fFactoryPathList
445: .getSelectedElements();
446: return contents;
447: }
448:
449: /**
450: * Add new entries to the list control. Differs from setListContents()
451: * in that the list is not cleared first, and the entries are not copied
452: * before being added to the list.
453: * @param entries can be null.
454: */
455: private void addEntries(FactoryPathEntry[] entries) {
456: if (null == entries) {
457: return;
458: }
459: int insertAt;
460: List<FactoryPathEntry> selectedElements = getSelectedListContents();
461: if (selectedElements.size() == 1) {
462: insertAt = fFactoryPathList
463: .getIndexOfElement(selectedElements.get(0)) + 1;
464: } else {
465: insertAt = fFactoryPathList.getSize();
466: }
467: try {
468: fSettingListContents = true;
469: for (int i = 0; i < entries.length; ++i) {
470: fFactoryPathList.addElement(entries[i], insertAt + i);
471: fFactoryPathList.setChecked(entries[i],
472: entries[i]._attr.isEnabled());
473: }
474: } finally {
475: fSettingListContents = false;
476: }
477: }
478:
479: /**
480: * Set the contents of the list control. The FPEs in the input list
481: * will be copied; the originals are left untouched, so that if the
482: * list control's contents are modified they can be compared with the
483: * original.
484: * @param fpeList can be null.
485: */
486: private void setListContents(List<FactoryPathEntry> fpeList) {
487: try {
488: fSettingListContents = true;
489: fFactoryPathList.removeAllElements();
490: if (fpeList == null) {
491: return;
492: }
493: for (FactoryPathEntry originalFpe : fpeList) {
494: // clone, because we may later want to compare with the original.
495: FactoryPathEntry fpe = new FactoryPathEntry(
496: originalFpe._fc, new Attributes(
497: originalFpe._attr));
498: fFactoryPathList.addElement(fpe);
499: fFactoryPathList.setChecked(fpe, fpe._attr.isEnabled());
500: }
501: } finally {
502: fSettingListContents = false;
503: }
504: }
505:
506: /**
507: * Get all the containers of a certain type currently on the list.
508: * The format of the returned paths will depend on the container type:
509: * for EXTJAR it will be an absolute path; for WKSPJAR it will be a
510: * path relative to the workspace root; for VARJAR it will be a path
511: * whose first segment is the name of a classpath variable.
512: * @param type may not be PLUGIN
513: * @param ignore null, or an item to not put on the list (used when
514: * editing an existing item).
515: * @return an array, possibly empty (but never null)
516: */
517: private IPath[] getExistingPaths(FactoryContainer.FactoryType type,
518: FactoryContainer ignore) {
519: if (type == FactoryContainer.FactoryType.PLUGIN) {
520: throw new IllegalArgumentException();
521: }
522: List<FactoryPathEntry> all = getListContents();
523: // find out how many entries there are of this type
524: int countType = 0;
525: for (FactoryPathEntry fpe : all) {
526: FactoryContainer fc = fpe._fc;
527: if (fc.getType() == type && fc != ignore) {
528: ++countType;
529: }
530: }
531: // create an array of paths, one per entry of this type
532: IPath[] some = new IPath[countType];
533: int i = 0;
534: for (FactoryPathEntry fpe : all) {
535: FactoryContainer fc = fpe._fc;
536: if (fc.getType() == type && fc != ignore) {
537: some[i++] = new Path(fc.getId());
538: }
539: }
540: return some;
541: }
542:
543: /**
544: * Launch the "advanced options" dialog, which displays the factory classes
545: * contained by the selected container and allows the user to specify
546: * options that are needed only in certain special cases.
547: *
548: * We treat advanced options as an attribute of the factory path, not of the
549: * container; the same container may have different advanced options in different
550: * projects. We treat advanced options the same way as the "enabled" flag.
551: */
552: private void advancedOptionsDialog() {
553: List<FactoryPathEntry> selected = getSelectedListContents();
554: if (selected.size() != 1) {
555: return;
556: }
557: FactoryPathEntry original = selected.get(0);
558: AdvancedFactoryPathOptionsDialog dialog = new AdvancedFactoryPathOptionsDialog(
559: getShell(), original._fc, original._attr);
560: if (dialog.open() == Window.OK) {
561: original._attr = dialog.getResult();
562: // If the dialog could change the enabled attribute, we would also
563: // need to update the checkbox in the GUI here. But it doesn't.
564: }
565: }
566:
567: /**
568: * Add or edit a project-relative jar file. Only possible when editing
569: * project properties; this method is disabled in workspace prefs.
570: * @param original null, or an existing list entry to be edited
571: * @return a list of additional factory path entries to be added
572: */
573: private FactoryPathEntry[] openJarFileDialog(
574: FactoryPathEntry original) {
575: if (fJProj == null) {
576: return null;
577: }
578: IWorkspaceRoot root = fJProj.getProject().getWorkspace()
579: .getRoot();
580:
581: if (original == null) {
582: IPath[] results = BuildPathDialogAccess.chooseJAREntries(
583: getShell(), fJProj.getPath(), new IPath[0]);
584: if (results == null) {
585: return null;
586: }
587: ArrayList<FactoryPathEntry> res = new ArrayList<FactoryPathEntry>();
588: for (int i = 0; i < results.length; i++) {
589: IResource resource = root.findMember(results[i]);
590: if (resource instanceof IFile) {
591: FactoryContainer fc = FactoryPathUtil
592: .newWkspJarFactoryContainer(results[i]);
593: // assume defaults of enabled=true, runInAptMode=false
594: FactoryPath.Attributes attr = new FactoryPath.Attributes(
595: true, false);
596: FactoryPathEntry fpe = new FactoryPathEntry(fc,
597: attr);
598: res.add(fpe);
599: }
600: //TODO: handle missing jars
601: }
602: return res.toArray(new FactoryPathEntry[res.size()]);
603: } else {
604: IPath[] existingPaths = getExistingPaths(
605: FactoryContainer.FactoryType.WKSPJAR, original._fc);
606: IPath result = BuildPathDialogAccess.configureJAREntry(
607: getShell(), new Path(original._fc.getId()),
608: existingPaths);
609: if (result == null) {
610: return null;
611: }
612: IResource resource = root.findMember(result);
613: if (resource instanceof IFile) {
614: FactoryPathEntry[] edited = new FactoryPathEntry[1];
615: FactoryContainer fc = FactoryPathUtil
616: .newWkspJarFactoryContainer(result);
617: // Use prior value for isEnabled. Assume default of runInAptMode=false
618: FactoryPath.Attributes attr = new FactoryPath.Attributes(
619: original._attr.isEnabled(), false);
620: edited[0] = new FactoryPathEntry(fc, attr);
621: return edited;
622: }
623: //TODO: handle missing jars
624: return null;
625: }
626: }
627:
628: /**
629: * Add or edit an external (not project-relative) jar file.
630: * @param original null, or an existing list entry to be edited
631: * @return a list of additional factory path entries to be added
632: */
633: private FactoryPathEntry[] openExtJarFileDialog(
634: FactoryPathEntry original) {
635: if (original == null) {
636: IPath[] selected = BuildPathDialogAccess
637: .chooseExternalJAREntries(getShell());
638: if (selected == null) {
639: return null;
640: }
641: ArrayList<FactoryPathEntry> res = new ArrayList<FactoryPathEntry>();
642: for (int i = 0; i < selected.length; i++) {
643: FactoryContainer fc = FactoryPathUtil
644: .newExtJarFactoryContainer(selected[i].toFile());
645: // assume defaults of enabled=true, runInAptMode=false
646: FactoryPath.Attributes attr = new FactoryPath.Attributes(
647: true, false);
648: FactoryPathEntry fpe = new FactoryPathEntry(fc, attr);
649: res.add(fpe);
650: }
651: return res.toArray(new FactoryPathEntry[res.size()]);
652: } else {
653: IPath result = BuildPathDialogAccess
654: .configureExternalJAREntry(getShell(), new Path(
655: original._fc.getId()));
656: if (result == null) {
657: return null;
658: }
659: FactoryPathEntry[] edited = new FactoryPathEntry[1];
660: FactoryContainer fc = FactoryPathUtil
661: .newExtJarFactoryContainer(result.toFile());
662: // Use prior value for isEnabled. Assume default of runInAptMode=false
663: FactoryPath.Attributes attr = new FactoryPath.Attributes(
664: original._attr.isEnabled(), false);
665: edited[0] = new FactoryPathEntry(fc, attr);
666: return edited;
667: }
668: }
669:
670: /**
671: * Add or edit an external (not project-relative) jar file whose
672: * location includes a classpath variable name.
673: * @param original null, or an existing list entry to be edited
674: * @return a list of additional factory path entries to be added
675: */
676: private FactoryPathEntry[] openVariableSelectionDialog(
677: FactoryPathEntry original) {
678: if (original == null) {
679: IPath[] selected = BuildPathDialogAccess
680: .chooseVariableEntries(getShell(), new IPath[0]);
681: if (selected == null) {
682: return null;
683: }
684: ArrayList<FactoryPathEntry> res = new ArrayList<FactoryPathEntry>();
685: for (int i = 0; i < selected.length; i++) {
686: FactoryContainer fc = FactoryPathUtil
687: .newVarJarFactoryContainer(selected[i]);
688: // assume defaults of enabled=true, runInAptMode=false
689: FactoryPath.Attributes attr = new FactoryPath.Attributes(
690: true, false);
691: FactoryPathEntry fpe = new FactoryPathEntry(fc, attr);
692: res.add(fpe);
693: }
694: return res.toArray(new FactoryPathEntry[res.size()]);
695: } else {
696: IPath[] existingPaths = getExistingPaths(
697: FactoryContainer.FactoryType.VARJAR, original._fc);
698: IPath result = BuildPathDialogAccess
699: .configureVariableEntry(getShell(), new Path(
700: original._fc.getId()), existingPaths);
701: if (result == null) {
702: return null;
703: }
704: FactoryPathEntry[] edited = new FactoryPathEntry[1];
705: FactoryContainer fc = FactoryPathUtil
706: .newVarJarFactoryContainer(result);
707: // Use prior value for isEnabled. Assume default of runInAptMode=false
708: FactoryPath.Attributes attr = new FactoryPath.Attributes(
709: original._attr.isEnabled(), false);
710: edited[0] = new FactoryPathEntry(fc, attr);
711: return edited;
712: }
713: }
714:
715: /* (non-Javadoc)
716: * @see org.eclipse.jdt.apt.ui.internal.preferences.BaseConfigurationBlock#updateModel(org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField)
717: */
718: protected void updateModel(DialogField field) {
719: // We don't use IEclipsePreferences for this pane, so no need to do anything.
720: }
721:
722: /* (non-Javadoc)
723: * @see org.eclipse.jdt.apt.ui.internal.preferences.BaseConfigurationBlock#validateSettings(org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock.Key, java.lang.String, java.lang.String)
724: */
725: protected void validateSettings(Key changedKey, String oldValue,
726: String newValue) {
727: // TODO: validate that all the specified factory containers exist?
728: }
729:
730: protected void saveSettings() {
731: FactoryPath fp;
732: if ((fJProj != null) && !fBlockControl.isEnabled()) {
733: // We're in a project properties pane but the entire configuration
734: // block control is disabled. That means the per-project settings checkbox
735: // is unchecked. To save that state, we'll delete the settings file.
736: fp = null;
737: } else {
738: List<FactoryPathEntry> containers;
739: Map<FactoryContainer, FactoryPath.Attributes> map;
740: containers = getListContents();
741: map = FactoryPathEntry.pathMapFromList(containers);
742: fp = new FactoryPath();
743: fp.setContainers(map);
744: }
745:
746: try {
747: AptConfig.setFactoryPath(fJProj, fp);
748: } catch (CoreException e) {
749: final String title = Messages.FactoryPathConfigurationBlock_unableToSaveFactorypath_title;
750: final String message = Messages.FactoryPathConfigurationBlock_unableToSaveFactorypath_message;
751: ExceptionHandler.handle(e, fBlockControl.getShell(), title,
752: message);
753: }
754:
755: super .saveSettings();
756: }
757:
758: /**
759: * If per-project, restore list contents to current workspace settings;
760: * the per-project settings checkbox will be cleared for us automatically.
761: * If workspace, restore list contents to factory-default settings.
762: */
763: public void performDefaults() {
764: IFactoryPath ifp = AptConfig.getDefaultFactoryPath(fJProj);
765: // we'll risk this downcast because we're such good buddies with apt.core.
766: FactoryPath fp = (FactoryPath) ifp;
767: Map<FactoryContainer, FactoryPath.Attributes> map = fp
768: .getAllContainers();
769: List<FactoryPathEntry> defaults = FactoryPathEntry
770: .pathListFromMap(map);
771: setListContents(defaults);
772: super .performDefaults();
773: }
774:
775: /**
776: * @return true if settings or project-specificness changed since
777: * the pane was launched - that is, if there is anything to save.
778: */
779: @Override
780: protected boolean settingsChanged(IScopeContext currContext) {
781: if (fOriginalPath == null) {
782: // shouldn't happen, but just in case it does, consider it a change.
783: return true;
784: }
785: // Is the new path the same size, containing the same items
786: // in the same order? We rely on FactoryPathEntry.equals() here.
787: List<FactoryPathEntry> newPath = getListContents();
788: return !fOriginalPath.equals(newPath);
789: }
790:
791: }
|