001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 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.newsourcepage;
011:
012: import java.util.List;
013:
014: import org.eclipse.core.runtime.IPath;
015: import org.eclipse.core.runtime.Path;
016:
017: import org.eclipse.core.resources.IFolder;
018: import org.eclipse.core.resources.IResource;
019:
020: import org.eclipse.swt.widgets.Display;
021: import org.eclipse.swt.widgets.Shell;
022:
023: import org.eclipse.jface.dialogs.MessageDialog;
024: import org.eclipse.jface.window.Window;
025:
026: import org.eclipse.ui.dialogs.NewFolderDialog;
027:
028: import org.eclipse.jdt.core.IClasspathEntry;
029: import org.eclipse.jdt.core.IJavaProject;
030: import org.eclipse.jdt.core.JavaModelException;
031:
032: import org.eclipse.jdt.internal.corext.util.Messages;
033:
034: import org.eclipse.jdt.ui.PreferenceConstants;
035: import org.eclipse.jdt.ui.wizards.BuildPathDialogAccess;
036:
037: import org.eclipse.jdt.internal.ui.JavaPlugin;
038: import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
039: import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListElement;
040: import org.eclipse.jdt.internal.ui.wizards.buildpaths.ExclusionInclusionDialog;
041:
042: /**
043: * Helper class for queries used by the <code>ClasspathModifier</code>.
044: * Clients can either decide to implement their own queries or just taking
045: * the predefined queries.
046: */
047: public class ClasspathModifierQueries {
048:
049: /**
050: * A validator for the output location that can be
051: * used to find out whether the entred location can be
052: * used for an output folder or not.
053: */
054: public static abstract class OutputFolderValidator {
055: protected IClasspathEntry[] fEntries;
056: protected List fElements;
057:
058: /**
059: * Create a output folder validator.
060: *
061: * @param newElements a list of elements that will be added
062: * to the buildpath. The list's items can be of type:
063: * <li><code>IJavaProject</code></li>
064: * <li><code>IPackageFragment</code></li>
065: * <li><code>IFolder</code></li>
066: * @param project the Java project
067: * @throws JavaModelException
068: */
069: public OutputFolderValidator(List newElements,
070: IJavaProject project) throws JavaModelException {
071: fEntries = project.getRawClasspath();
072: fElements = newElements;
073: }
074:
075: /**
076: * The path of the output location to be validated. The path
077: * should contain the full path within the project, for example:
078: * /ProjectXY/folderA/outputLocation.
079: *
080: * @param outputLocation the output location for the project
081: * @return <code>true</code> if the output location is valid,
082: * <code>false</code> otherwise.
083: */
084: public abstract boolean validate(IPath outputLocation);
085: }
086:
087: /**
088: * Query that processes the request of
089: * creating a link to an existing source
090: * folder.
091: */
092: public static interface ILinkToQuery {
093: /**
094: * Query that processes the request of
095: * creating a link to an existing source
096: * folder.
097: *
098: * @return <code>true</code> if the query was
099: * executed successfully (that is the result of
100: * this query can be used), <code>false</code>
101: * otherwise
102: */
103: public boolean doQuery();
104:
105: /**
106: * Get the newly created folder.
107: * This method is only valid after having
108: * called <code>doQuery</code>.
109: *
110: * @return the created folder of type
111: * <code>IFolder</code>
112: */
113: public IFolder getCreatedFolder();
114:
115: /**
116: * Getter for an output folder query.
117: *
118: * @return an output folder query which will be needed
119: * when adding the folder to the build path
120: *
121: */
122: public OutputFolderQuery getOutputFolderQuery();
123: }
124:
125: /**
126: * Query to get information about whether the project should be removed as
127: * source folder and update build folder to <code>outputLocation</code>
128: */
129: public static abstract class OutputFolderQuery {
130: protected IPath fDesiredOutputLocation;
131:
132: /**
133: * Constructor gets the desired output location
134: * of the project
135: *
136: * @param outputLocation desired output location for the
137: * project. It is possible that the desired output location
138: * equals the current project's output location (for example if
139: * it is not intended to change the output location at this time).
140: */
141: public OutputFolderQuery(IPath outputLocation) {
142: if (outputLocation != null)
143: fDesiredOutputLocation = outputLocation.makeAbsolute();
144: }
145:
146: /**
147: * Getter for the desired output location.
148: *
149: * @return the project's desired output location
150: */
151: public IPath getDesiredOutputLocation() {
152: return fDesiredOutputLocation;
153: }
154:
155: /**
156: * Get the output location that was determined by the
157: * query for the project. Note that this output location
158: * does not have to be the same as the desired output location
159: * that is passed to the constructor.
160: *
161: * This method is only intended to be called if <code>doQuery</code>
162: * has been executed successfully and had return <code>true</code> to
163: * indicate that changes were accepted.
164: *
165: *@return the effective output location
166: */
167: public abstract IPath getOutputLocation();
168:
169: /**
170: * Find out wheter the project should be removed from the classpath
171: * or not.
172: *
173: * This method is only intended to be called if <code>doQuery</code>
174: * has been executed successfully and had return <code>true</code> to
175: * indicate that changes were accepted.
176: *
177: * @return <code>true</code> if the project should be removed from
178: * the classpath, <code>false</code> otherwise.
179: */
180: public abstract boolean removeProjectFromClasspath();
181:
182: /**
183: * Query to get information about whether the project should be removed as
184: * source folder and update build folder to <code>outputLocation</code>.
185: *
186: * There are several situations for setting up a project where it is not possible
187: * to have the project folder itself as output folder. Therefore, the query asks in the
188: * first place for changing the output folder. Additionally, it also can be usefull to
189: * remove the project from the classpath. This information can be retrieved by calling
190: * <code>removeProjectFromClasspath()</code>.
191: *
192: * Note: if <code>doQuery</code> returns false, the started computation will stop immediately.
193: * There is no additional dialog that informs the user about this abort. Therefore it is important
194: * that the query informs the users about the consequences of not allowing to change the output
195: * folder.
196: *
197: * @param editingOutputFolder <code>true</code> if currently an output folder is changed,
198: * <code>false</code> otherwise. This information can be usefull to generate an appropriate
199: * message to ask the user for an action.
200: * @param validator a validator to find out whether the chosen output location is valid or not
201: * @param project the Java project
202: * @return <code>true</code> if the execution was successfull (e.g. not aborted) and
203: * the caller should execute additional steps as setting the output location for the project or (optionally)
204: * removing the project from the classpath, <code>false</code> otherwise.
205: * @throws JavaModelException if the output location of the project could not be retrieved
206: */
207: public abstract boolean doQuery(
208: final boolean editingOutputFolder,
209: final OutputFolderValidator validator,
210: final IJavaProject project) throws JavaModelException;
211:
212: }
213:
214: /**
215: * Query to get information about the inclusion and exclusion filters of
216: * an element.
217: */
218: public static interface IInclusionExclusionQuery {
219: /**
220: * Query to get information about the
221: * inclusion and exclusion filters of
222: * an element.
223: *
224: * While executing <code>doQuery</code>,
225: * these filter might change.
226: *
227: * On calling <code>getInclusionPattern()</code>
228: * or <code>getExclusionPattern()</code> it
229: * is expected to get the new and updated
230: * filters back.
231: *
232: * @param element the element to get the
233: * information from
234: * @param focusOnExcluded
235: * @return <code>true</code> if changes
236: * have been accepted and <code>getInclusionPatter</code>
237: * or <code>getExclusionPattern</code> can
238: * be called.
239: */
240: public boolean doQuery(CPListElement element,
241: boolean focusOnExcluded);
242:
243: /**
244: * Can only be called after <code>
245: * doQuery</code> has been executed and
246: * has returned <code>true</code>
247: *
248: * @return the new inclusion filters
249: */
250: public IPath[] getInclusionPattern();
251:
252: /**
253: * Can only be called after <code>
254: * doQuery</code> has been executed and
255: * has returned <code>true</code>
256: *
257: * @return the new exclusion filters
258: */
259: public IPath[] getExclusionPattern();
260: }
261:
262: /**
263: * Query to get information about the output location that should be used for a
264: * given element.
265: */
266: public static interface IOutputLocationQuery {
267: /**
268: * Query to get information about the output
269: * location that should be used for a
270: * given element.
271: *
272: * @param element the element to get
273: * an output location for
274: * @return <code>true</code> if the output
275: * location has changed, <code>false</code>
276: * otherwise.
277: */
278: public boolean doQuery(CPListElement element);
279:
280: /**
281: * Gets the new output location.
282: *
283: * May only be called after having
284: * executed <code>doQuery</code> which
285: * must have returned <code>true</code>
286: *
287: * @return the new output location, can be <code>null</code>
288: */
289: public IPath getOutputLocation();
290:
291: /**
292: * Get a query for information about whether the project should be removed as
293: * source folder and update build folder
294: *
295: * @param outputLocation desired output location for the
296: * project
297: * @return query giving information about output and source folders
298: * @throws JavaModelException
299: *
300: */
301: public OutputFolderQuery getOutputFolderQuery(
302: IPath outputLocation) throws JavaModelException;
303: }
304:
305: /**
306: * Query to determine whether a linked folder should be removed.
307: */
308: public static interface IRemoveLinkedFolderQuery {
309:
310: /** Remove status indicating that the removal should be cancelled */
311: public static final int REMOVE_CANCEL = 0;
312:
313: /** Remove status indicating that the folder should be removed from the build path only */
314: public static final int REMOVE_BUILD_PATH = 1;
315:
316: /** Remove status indicating that the folder should be removed from the build path and deleted */
317: public static final int REMOVE_BUILD_PATH_AND_FOLDER = 2;
318:
319: /**
320: * Query to determined whether the linked folder should be removed as well.
321: *
322: * @param folder the linked folder to remove
323: * @return a status code corresponding to one of the IRemoveLinkedFolderQuery#REMOVE_XXX constants
324: */
325: public int doQuery(IFolder folder);
326: }
327:
328: /**
329: * Query to create a folder.
330: */
331: public static interface ICreateFolderQuery {
332: /**
333: * Query to create a folder.
334: *
335: * @return <code>true</code> if the operation
336: * was successful (e.g. no cancelled), <code>
337: * false</code> otherwise
338: */
339: public boolean doQuery();
340:
341: /**
342: * Find out whether a source folder is about
343: * to be created or a normal folder which
344: * is not on the classpath (and therefore
345: * might have to be excluded).
346: *
347: * Should only be called after having executed
348: * <code>doQuery</code>, because otherwise
349: * it might not be sure if a result exists or
350: * not.
351: *
352: * @return <code>true</code> if a source
353: * folder should be created, <code>false
354: * </code> otherwise
355: */
356: public boolean isSourceFolder();
357:
358: /**
359: * Get the newly created folder.
360: * This method is only valid after having
361: * called <code>doQuery</code>.
362: *
363: * @return the created folder of type
364: * <code>IFolder</code>
365: */
366: public IFolder getCreatedFolder();
367: }
368:
369: /**
370: * Query to add archives (.jar or .zip files) to the buildpath.
371: */
372: public static interface IAddArchivesQuery {
373: /**
374: * Get the paths to the new archive entries that should be added to the buildpath.
375: *
376: * @return Returns the new classpath container entry paths or an empty array if the query has
377: * been cancelled by the user.
378: */
379: public IPath[] doQuery();
380: }
381:
382: /**
383: * Query to add libraries to the buildpath.
384: */
385: public static interface IAddLibrariesQuery {
386: /**
387: * Get the new classpath entries for libraries to be added to the buildpath.
388: *
389: * @param project the Java project
390: * @param entries an array of classpath entries for the project
391: * @return Returns the selected classpath container entries or an empty if the query has
392: * been cancelled by the user.
393: */
394: public IClasspathEntry[] doQuery(final IJavaProject project,
395: final IClasspathEntry[] entries);
396: }
397:
398: /**
399: * The query is used to get information about whether the project should be removed as
400: * source folder and update build folder to <code>outputLocation</code>
401: *
402: * @param shell shell if there is any or <code>null</code>
403: * @param outputLocation the desired project's output location
404: * @return an <code>IOutputFolderQuery</code> that can be executed
405: *
406: * @see OutputFolderQuery
407: */
408: public static OutputFolderQuery getDefaultFolderQuery(
409: final Shell shell, IPath outputLocation) {
410:
411: return new OutputFolderQuery(outputLocation) {
412: protected IPath fOutputLocation;
413: protected boolean fRemoveProject;
414:
415: public boolean doQuery(final boolean editingOutputFolder,
416: final OutputFolderValidator validator,
417: final IJavaProject project)
418: throws JavaModelException {
419: final boolean[] result = { false };
420: fRemoveProject = false;
421: fOutputLocation = project.getOutputLocation();
422: Display.getDefault().syncExec(new Runnable() {
423: public void run() {
424: Shell sh = shell != null ? shell : JavaPlugin
425: .getActiveWorkbenchShell();
426:
427: String title = NewWizardMessages.ClasspathModifier_ChangeOutputLocationDialog_title;
428:
429: if (fDesiredOutputLocation.segmentCount() == 1) {
430: String outputFolderName = PreferenceConstants
431: .getPreferenceStore()
432: .getString(
433: PreferenceConstants.SRCBIN_BINNAME);
434: IPath newOutputFolder = fDesiredOutputLocation
435: .append(outputFolderName);
436: newOutputFolder = getValidPath(
437: newOutputFolder, validator);
438: String message = Messages
439: .format(
440: NewWizardMessages.ClasspathModifier_ChangeOutputLocationDialog_project_outputLocation,
441: newOutputFolder);
442: fRemoveProject = true;
443: if (MessageDialog.openConfirm(sh, title,
444: message)) {
445: fOutputLocation = newOutputFolder;
446: result[0] = true;
447: }
448: } else {
449: IPath newOutputFolder = fDesiredOutputLocation;
450: newOutputFolder = getValidPath(
451: newOutputFolder, validator);
452: if (editingOutputFolder) {
453: fOutputLocation = newOutputFolder;
454: result[0] = true;
455: return; // show no dialog
456: }
457: String message = NewWizardMessages.ClasspathModifier_ChangeOutputLocationDialog_project_message;
458: fRemoveProject = true;
459: if (MessageDialog.openQuestion(sh, title,
460: message)) {
461: fOutputLocation = newOutputFolder;
462: result[0] = true;
463: }
464: }
465: }
466: });
467: return result[0];
468: }
469:
470: public IPath getOutputLocation() {
471: return fOutputLocation;
472: }
473:
474: public boolean removeProjectFromClasspath() {
475: return fRemoveProject;
476: }
477:
478: private IPath getValidPath(IPath newOutputFolder,
479: OutputFolderValidator validator) {
480: int i = 1;
481: IPath path = newOutputFolder;
482: while (!validator.validate(path)) {
483: path = new Path(newOutputFolder.toString() + i);
484: i++;
485: }
486: return path;
487: }
488: };
489: }
490:
491: /**
492: * A default query for inclusion and exclusion filters.
493: * The query is used to get information about the
494: * inclusion and exclusion filters of an element.
495: *
496: * @param shell shell if there is any or <code>null</code>
497: * @return an <code>IInclusionExclusionQuery</code> that can be executed
498: *
499: * @see ClasspathModifierQueries.IInclusionExclusionQuery
500: */
501: public static IInclusionExclusionQuery getDefaultInclusionExclusionQuery(
502: final Shell shell) {
503: return new IInclusionExclusionQuery() {
504:
505: protected IPath[] fInclusionPattern;
506: protected IPath[] fExclusionPattern;
507:
508: public boolean doQuery(final CPListElement element,
509: final boolean focusOnExcluded) {
510: final boolean[] result = { false };
511: Display.getDefault().syncExec(new Runnable() {
512: public void run() {
513: Shell sh = shell != null ? shell : JavaPlugin
514: .getActiveWorkbenchShell();
515: ExclusionInclusionDialog dialog = new ExclusionInclusionDialog(
516: sh, element, focusOnExcluded);
517: result[0] = dialog.open() == Window.OK;
518: fInclusionPattern = dialog
519: .getInclusionPattern();
520: fExclusionPattern = dialog
521: .getExclusionPattern();
522: }
523: });
524: return result[0];
525: }
526:
527: public IPath[] getInclusionPattern() {
528: return fInclusionPattern;
529: }
530:
531: public IPath[] getExclusionPattern() {
532: return fExclusionPattern;
533: }
534: };
535: }
536:
537: /**
538: * Query to create a linked source folder.
539: *
540: * The default query shows a dialog which allows
541: * the user to specify the new folder that should
542: * be created.
543: *
544: * @param shell shell if there is any or <code>null</code>
545: * @param project the Java project to create the linked source folder for
546: * @return an <code>ILinkToQuery</code> showing a dialog
547: * to create a linked source folder.
548: *
549: * @see ClasspathModifierQueries.ICreateFolderQuery
550: * @see LinkFolderDialog
551: */
552: public static ILinkToQuery getDefaultLinkQuery(final Shell shell,
553: final IJavaProject project,
554: final IPath desiredOutputLocation) {
555: return new ILinkToQuery() {
556: protected IFolder fFolder;
557:
558: public boolean doQuery() {
559: final boolean[] isOK = { false };
560: Display.getDefault().syncExec(new Runnable() {
561: public void run() {
562: Shell sh = shell != null ? shell : JavaPlugin
563: .getActiveWorkbenchShell();
564:
565: LinkFolderDialog dialog = new LinkFolderDialog(
566: sh, project.getProject());
567: isOK[0] = dialog.open() == Window.OK;
568: if (isOK[0])
569: fFolder = dialog.getCreatedFolder();
570: }
571: });
572: return isOK[0];
573: }
574:
575: public IFolder getCreatedFolder() {
576: return fFolder;
577: }
578:
579: public OutputFolderQuery getOutputFolderQuery() {
580: return getDefaultFolderQuery(shell,
581: desiredOutputLocation);
582: }
583:
584: };
585: }
586:
587: /**
588: * Shows the UI to select new external JAR or ZIP archive entries. If the query
589: * was aborted, the result is an empty array.
590: *
591: * @param shell The parent shell for the dialog, can be <code>null</code>
592: * @return an <code>IAddArchivesQuery</code> showing a dialog to selected archive files
593: * to be added to the buildpath
594: *
595: * @see IAddArchivesQuery
596: */
597: public static IAddArchivesQuery getDefaultArchivesQuery(
598: final Shell shell) {
599: return new IAddArchivesQuery() {
600:
601: public IPath[] doQuery() {
602: final IPath[][] selected = { null };
603: Display.getDefault().syncExec(new Runnable() {
604: public void run() {
605: Shell sh = shell != null ? shell : JavaPlugin
606: .getActiveWorkbenchShell();
607: selected[0] = BuildPathDialogAccess
608: .chooseExternalJAREntries(sh);
609: }
610: });
611: if (selected[0] == null)
612: return new IPath[0];
613: return selected[0];
614: }
615: };
616: }
617:
618: /**
619: * Shows the UI to prompt whether a linked folder which has been removed from the build path should be deleted as well.
620: *
621: * @param shell The parent shell for the dialog, can be <code>null</code>
622: * @return an <code>IRemoveLinkedFolderQuery</code> showing a dialog to prompt whether the linked folder should be deleted as well
623: *
624: * @see IRemoveLinkedFolderQuery
625: */
626: public static IRemoveLinkedFolderQuery getDefaultRemoveLinkedFolderQuery(
627: final Shell shell) {
628: return new IRemoveLinkedFolderQuery() {
629:
630: public final int doQuery(final IFolder folder) {
631: final int[] result = { IRemoveLinkedFolderQuery.REMOVE_BUILD_PATH };
632: Display.getDefault().syncExec(new Runnable() {
633:
634: public final void run() {
635: final RemoveLinkedFolderDialog dialog = new RemoveLinkedFolderDialog(
636: (shell != null ? shell : JavaPlugin
637: .getActiveWorkbenchShell()),
638: folder);
639: final int status = dialog.open();
640: if (status == 0)
641: result[0] = dialog.getRemoveStatus();
642: else
643: result[0] = IRemoveLinkedFolderQuery.REMOVE_CANCEL;
644: }
645: });
646: return result[0];
647: }
648: };
649: }
650:
651: /**
652: * Shows the UI to choose new classpath container classpath entries. See {@link IClasspathEntry#CPE_CONTAINER} for
653: * details about container classpath entries.
654: * The query returns the selected classpath entries or an empty array if the query has
655: * been cancelled.
656: *
657: * @param shell The parent shell for the dialog, can be <code>null</code>
658: * @return Returns the selected classpath container entries or an empty array if the query has
659: * been cancelled by the user.
660: */
661: public static IAddLibrariesQuery getDefaultLibrariesQuery(
662: final Shell shell) {
663: return new IAddLibrariesQuery() {
664:
665: public IClasspathEntry[] doQuery(
666: final IJavaProject project,
667: final IClasspathEntry[] entries) {
668: final IClasspathEntry[][] selected = { null };
669: Display.getDefault().syncExec(new Runnable() {
670: public void run() {
671: Shell sh = shell != null ? shell : JavaPlugin
672: .getActiveWorkbenchShell();
673: selected[0] = BuildPathDialogAccess
674: .chooseContainerEntries(sh, project,
675: entries);
676: }
677: });
678: if (selected[0] == null)
679: return new IClasspathEntry[0];
680: return selected[0];
681: }
682: };
683: }
684:
685: /**
686: * Shows the UI to create a new source folder.
687: *
688: * @param shell The parent shell for the dialog, can be <code>null</code>
689: * @param project the Java project to create the source folder for
690: * @return returns the query
691: */
692: public static ICreateFolderQuery getDefaultCreateFolderQuery(
693: final Shell shell, final IJavaProject project) {
694: return new ICreateFolderQuery() {
695:
696: private IFolder fNewFolder;
697:
698: public boolean doQuery() {
699: final boolean[] isOK = { false };
700: Display.getDefault().syncExec(new Runnable() {
701: public void run() {
702: Shell sh = shell != null ? shell : JavaPlugin
703: .getActiveWorkbenchShell();
704:
705: NewFolderDialog dialog = new NewFolderDialog(
706: sh, project.getProject());
707: isOK[0] = dialog.open() == Window.OK;
708: if (isOK[0]) {
709: IResource sourceContainer = (IResource) dialog
710: .getResult()[0];
711: if (sourceContainer instanceof IFolder) {
712: fNewFolder = (IFolder) sourceContainer;
713: } else {
714: fNewFolder = null;
715: }
716: }
717: }
718: });
719: return isOK[0];
720: }
721:
722: public boolean isSourceFolder() {
723: return true;
724: }
725:
726: public IFolder getCreatedFolder() {
727: return fNewFolder;
728: }
729:
730: };
731: }
732: }
|