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: * Leon J. Breedt - Added multiple folder creation support (in WizardNewFolderMainPage)
011: *
012: *******************************************************************************/package org.eclipse.ui.dialogs;
013:
014: import java.lang.reflect.InvocationTargetException;
015: import java.net.URI;
016: import java.util.Iterator;
017: import org.eclipse.core.commands.ExecutionException;
018: import org.eclipse.core.resources.IFolder;
019: import org.eclipse.core.resources.IResource;
020: import org.eclipse.core.resources.IResourceStatus;
021: import org.eclipse.core.resources.IWorkspaceRoot;
022: import org.eclipse.core.resources.ResourcesPlugin;
023: import org.eclipse.core.runtime.CoreException;
024: import org.eclipse.core.runtime.IAdaptable;
025: import org.eclipse.core.runtime.IPath;
026: import org.eclipse.core.runtime.IProgressMonitor;
027: import org.eclipse.core.runtime.IStatus;
028: import org.eclipse.core.runtime.OperationCanceledException;
029: import org.eclipse.core.runtime.Preferences;
030: import org.eclipse.core.runtime.SubProgressMonitor;
031: import org.eclipse.jface.dialogs.ErrorDialog;
032: import org.eclipse.jface.dialogs.MessageDialog;
033: import org.eclipse.jface.operation.IRunnableWithProgress;
034: import org.eclipse.jface.viewers.IStructuredSelection;
035: import org.eclipse.jface.wizard.WizardPage;
036: import org.eclipse.osgi.util.NLS;
037: import org.eclipse.swt.SWT;
038: import org.eclipse.swt.events.SelectionAdapter;
039: import org.eclipse.swt.events.SelectionEvent;
040: import org.eclipse.swt.graphics.Point;
041: import org.eclipse.swt.layout.GridData;
042: import org.eclipse.swt.layout.GridLayout;
043: import org.eclipse.swt.widgets.Button;
044: import org.eclipse.swt.widgets.Composite;
045: import org.eclipse.swt.widgets.Event;
046: import org.eclipse.swt.widgets.Listener;
047: import org.eclipse.swt.widgets.Shell;
048: import org.eclipse.ui.PlatformUI;
049: import org.eclipse.ui.ide.undo.CreateFolderOperation;
050: import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
051: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
052: import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
053: import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
054: import org.eclipse.ui.internal.ide.dialogs.CreateLinkedResourceGroup;
055: import org.eclipse.ui.internal.ide.misc.ResourceAndContainerGroup;
056:
057: /**
058: * Standard main page for a wizard that creates a folder resource.
059: * <p>
060: * This page may be used by clients as-is; it may be also be subclassed to suit.
061: * </p>
062: * <p>
063: * Subclasses may extend
064: * <ul>
065: * <li><code>handleEvent</code></li>
066: * </ul>
067: * </p>
068: */
069: public class WizardNewFolderMainPage extends WizardPage implements
070: Listener {
071: private static final int SIZING_CONTAINER_GROUP_HEIGHT = 250;
072:
073: private IStructuredSelection currentSelection;
074:
075: private IFolder newFolder;
076:
077: // link target location
078: private URI linkTargetPath;
079:
080: // widgets
081: private ResourceAndContainerGroup resourceGroup;
082:
083: private Button advancedButton;
084:
085: private CreateLinkedResourceGroup linkedResourceGroup;
086:
087: private Composite linkedResourceParent;
088:
089: private Composite linkedResourceComposite;
090:
091: /**
092: * Height of the "advanced" linked resource group. Set when the advanced
093: * group is first made visible.
094: */
095: private int linkedResourceGroupHeight = -1;
096:
097: /**
098: * First time the advanced group is validated.
099: */
100: private boolean firstLinkCheck = true;
101:
102: /**
103: * Creates a new folder creation wizard page. If the initial resource
104: * selection contains exactly one container resource then it will be used as
105: * the default container resource.
106: *
107: * @param pageName
108: * the name of the page
109: * @param selection
110: * the current resource selection
111: */
112: public WizardNewFolderMainPage(String pageName,
113: IStructuredSelection selection) {
114: super ("newFolderPage1");//$NON-NLS-1$
115: setTitle(pageName);
116: setDescription(IDEWorkbenchMessages.WizardNewFolderMainPage_description);
117: this .currentSelection = selection;
118: }
119:
120: /**
121: * Creates the widget for advanced options.
122: *
123: * @param parent
124: * the parent composite
125: */
126: protected void createAdvancedControls(Composite parent) {
127: Preferences preferences = ResourcesPlugin.getPlugin()
128: .getPluginPreferences();
129:
130: if (preferences
131: .getBoolean(ResourcesPlugin.PREF_DISABLE_LINKING) == false) {
132: linkedResourceParent = new Composite(parent, SWT.NONE);
133: linkedResourceParent.setFont(parent.getFont());
134: linkedResourceParent.setLayoutData(new GridData(
135: GridData.FILL_HORIZONTAL));
136: GridLayout layout = new GridLayout();
137: layout.marginHeight = 0;
138: layout.marginWidth = 0;
139: linkedResourceParent.setLayout(layout);
140:
141: advancedButton = new Button(linkedResourceParent, SWT.PUSH);
142: advancedButton.setFont(linkedResourceParent.getFont());
143: advancedButton.setText(IDEWorkbenchMessages.showAdvanced);
144: GridData data = setButtonLayoutData(advancedButton);
145: data.horizontalAlignment = GridData.BEGINNING;
146: advancedButton.setLayoutData(data);
147: advancedButton.addSelectionListener(new SelectionAdapter() {
148: public void widgetSelected(SelectionEvent e) {
149: handleAdvancedButtonSelect();
150: }
151: });
152: }
153: linkedResourceGroup = new CreateLinkedResourceGroup(
154: IResource.FOLDER, new Listener() {
155: public void handleEvent(Event e) {
156: setPageComplete(validatePage());
157: firstLinkCheck = false;
158: }
159: }, new CreateLinkedResourceGroup.IStringValue() {
160: public String getValue() {
161: return resourceGroup.getResource();
162: }
163:
164: public void setValue(String string) {
165: resourceGroup.setResource(string);
166: }
167: });
168: }
169:
170: /**
171: * (non-Javadoc) Method declared on IDialogPage.
172: */
173: public void createControl(Composite parent) {
174: initializeDialogUnits(parent);
175: // top level group
176: Composite composite = new Composite(parent, SWT.NONE);
177: composite.setFont(parent.getFont());
178: composite.setLayout(new GridLayout());
179: composite.setLayoutData(new GridData(
180: GridData.VERTICAL_ALIGN_FILL
181: | GridData.HORIZONTAL_ALIGN_FILL));
182:
183: PlatformUI.getWorkbench().getHelpSystem().setHelp(composite,
184: IIDEHelpContextIds.NEW_FOLDER_WIZARD_PAGE);
185:
186: resourceGroup = new ResourceAndContainerGroup(
187: composite,
188: this ,
189: IDEWorkbenchMessages.WizardNewFolderMainPage_folderName,
190: IDEWorkbenchMessages.WizardNewFolderMainPage_folderLabel,
191: false, SIZING_CONTAINER_GROUP_HEIGHT);
192: resourceGroup.setAllowExistingResources(false);
193: createAdvancedControls(composite);
194: initializePage();
195: validatePage();
196: // Show description on opening
197: setErrorMessage(null);
198: setMessage(null);
199: setControl(composite);
200: }
201:
202: /**
203: * Creates a folder resource given the folder handle.
204: *
205: * @param folderHandle
206: * the folder handle to create a folder resource for
207: * @param monitor
208: * the progress monitor to show visual progress with
209: * @exception CoreException
210: * if the operation fails
211: * @exception OperationCanceledException
212: * if the operation is canceled
213: *
214: * @deprecated As of 3.3, use {@link #createNewFolder()} which uses the
215: * undoable operation support.
216: */
217: protected void createFolder(IFolder folderHandle,
218: IProgressMonitor monitor) throws CoreException {
219: try {
220: // Create the folder resource in the workspace
221: // Update: Recursive to create any folders which do not exist
222: // already
223: if (!folderHandle.exists()) {
224: if (linkTargetPath != null) {
225: folderHandle.createLink(linkTargetPath,
226: IResource.ALLOW_MISSING_LOCAL, monitor);
227: } else {
228: IPath path = folderHandle.getFullPath();
229: IWorkspaceRoot root = ResourcesPlugin
230: .getWorkspace().getRoot();
231: int numSegments = path.segmentCount();
232: if (numSegments > 2
233: && !root.getFolder(
234: path.removeLastSegments(1))
235: .exists()) {
236: // If the direct parent of the path doesn't exist, try
237: // to create the
238: // necessary directories.
239: for (int i = numSegments - 2; i > 0; i--) {
240: IFolder folder = root.getFolder(path
241: .removeLastSegments(i));
242: if (!folder.exists()) {
243: folder.create(false, true, monitor);
244: }
245: }
246: }
247: folderHandle.create(false, true, monitor);
248: }
249: }
250: } catch (CoreException e) {
251: // If the folder already existed locally, just refresh to get
252: // contents
253: if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED) {
254: folderHandle.refreshLocal(IResource.DEPTH_INFINITE,
255: new SubProgressMonitor(monitor, 500));
256: } else {
257: throw e;
258: }
259: }
260:
261: if (monitor.isCanceled()) {
262: throw new OperationCanceledException();
263: }
264: }
265:
266: /**
267: * Creates a folder resource handle for the folder with the given workspace
268: * path. This method does not create the folder resource; this is the
269: * responsibility of <code>createFolder</code>.
270: *
271: * @param folderPath
272: * the path of the folder resource to create a handle for
273: * @return the new folder resource handle
274: * @see #createFolder
275: */
276: protected IFolder createFolderHandle(IPath folderPath) {
277: return IDEWorkbenchPlugin.getPluginWorkspace().getRoot()
278: .getFolder(folderPath);
279: }
280:
281: /**
282: * Creates the link target path if a link target has been specified.
283: */
284: protected void createLinkTarget() {
285: linkTargetPath = linkedResourceGroup.getLinkTargetURI();
286: }
287:
288: /**
289: * Creates a new folder resource in the selected container and with the
290: * selected name. Creates any missing resource containers along the path;
291: * does nothing if the container resources already exist.
292: * <p>
293: * In normal usage, this method is invoked after the user has pressed Finish
294: * on the wizard; the enablement of the Finish button implies that all
295: * controls on this page currently contain valid values.
296: * </p>
297: * <p>
298: * Note that this page caches the new folder once it has been successfully
299: * created; subsequent invocations of this method will answer the same
300: * folder resource without attempting to create it again.
301: * </p>
302: * <p>
303: * This method should be called within a workspace modify operation since it
304: * creates resources.
305: * </p>
306: *
307: * @return the created folder resource, or <code>null</code> if the folder
308: * was not created
309: */
310: public IFolder createNewFolder() {
311: if (newFolder != null) {
312: return newFolder;
313: }
314:
315: // create the new folder and cache it if successful
316: final IPath containerPath = resourceGroup
317: .getContainerFullPath();
318: IPath newFolderPath = containerPath.append(resourceGroup
319: .getResource());
320: final IFolder newFolderHandle = createFolderHandle(newFolderPath);
321:
322: createLinkTarget();
323: IRunnableWithProgress op = new IRunnableWithProgress() {
324: public void run(IProgressMonitor monitor) {
325: CreateFolderOperation op = new CreateFolderOperation(
326: newFolderHandle,
327: linkTargetPath,
328: IDEWorkbenchMessages.WizardNewFolderCreationPage_title);
329: try {
330: PlatformUI
331: .getWorkbench()
332: .getOperationSupport()
333: .getOperationHistory()
334: .execute(
335: op,
336: monitor,
337: WorkspaceUndoUtil
338: .getUIInfoAdapter(getShell()));
339: } catch (final ExecutionException e) {
340: getContainer().getShell().getDisplay().syncExec(
341: new Runnable() {
342: public void run() {
343: if (e.getCause() instanceof CoreException) {
344: ErrorDialog
345: .openError(
346: getContainer()
347: .getShell(), // Was Utilities.getFocusShell()
348: IDEWorkbenchMessages.WizardNewFolderCreationPage_errorTitle,
349: null, // no special message
350: ((CoreException) e
351: .getCause())
352: .getStatus());
353: } else {
354: IDEWorkbenchPlugin
355: .log(
356: getClass(),
357: "createNewFolder()", e.getCause()); //$NON-NLS-1$
358: MessageDialog
359: .openError(
360: getContainer()
361: .getShell(),
362: IDEWorkbenchMessages.WizardNewFolderCreationPage_internalErrorTitle,
363: NLS
364: .bind(
365: IDEWorkbenchMessages.WizardNewFolder_internalError,
366: e
367: .getCause()
368: .getMessage()));
369: }
370: }
371: });
372: }
373: }
374: };
375:
376: try {
377: getContainer().run(true, true, op);
378: } catch (InterruptedException e) {
379: return null;
380: } catch (InvocationTargetException e) {
381: // ExecutionExceptions are handled above, but unexpected runtime
382: // exceptions and errors may still occur.
383: IDEWorkbenchPlugin.log(getClass(),
384: "createNewFolder()", e.getTargetException()); //$NON-NLS-1$
385: MessageDialog
386: .openError(
387: getContainer().getShell(),
388: IDEWorkbenchMessages.WizardNewFolderCreationPage_internalErrorTitle,
389: NLS
390: .bind(
391: IDEWorkbenchMessages.WizardNewFolder_internalError,
392: e.getTargetException()
393: .getMessage()));
394: return null;
395: }
396:
397: newFolder = newFolderHandle;
398:
399: return newFolder;
400: }
401:
402: /**
403: * Shows/hides the advanced option widgets.
404: */
405: protected void handleAdvancedButtonSelect() {
406: Shell shell = getShell();
407: Point shellSize = shell.getSize();
408: Composite composite = (Composite) getControl();
409:
410: if (linkedResourceComposite != null) {
411: linkedResourceComposite.dispose();
412: linkedResourceComposite = null;
413: composite.layout();
414: shell.setSize(shellSize.x, shellSize.y
415: - linkedResourceGroupHeight);
416: advancedButton.setText(IDEWorkbenchMessages.showAdvanced);
417: } else {
418: linkedResourceComposite = linkedResourceGroup
419: .createContents(linkedResourceParent);
420: if (linkedResourceGroupHeight == -1) {
421: Point groupSize = linkedResourceComposite.computeSize(
422: SWT.DEFAULT, SWT.DEFAULT, true);
423: linkedResourceGroupHeight = groupSize.y;
424: }
425: shell.setSize(shellSize.x, shellSize.y
426: + linkedResourceGroupHeight);
427: composite.layout();
428: advancedButton.setText(IDEWorkbenchMessages.hideAdvanced);
429: }
430: }
431:
432: /**
433: * The <code>WizardNewFolderCreationPage</code> implementation of this
434: * <code>Listener</code> method handles all events and enablements for
435: * controls on this page. Subclasses may extend.
436: */
437: public void handleEvent(Event ev) {
438: setPageComplete(validatePage());
439: }
440:
441: /**
442: * Initializes this page's controls.
443: */
444: protected void initializePage() {
445: Iterator it = currentSelection.iterator();
446: if (it.hasNext()) {
447: Object next = it.next();
448: IResource selectedResource = null;
449: if (next instanceof IResource) {
450: selectedResource = (IResource) next;
451: } else if (next instanceof IAdaptable) {
452: selectedResource = (IResource) ((IAdaptable) next)
453: .getAdapter(IResource.class);
454: }
455: if (selectedResource != null) {
456: if (selectedResource.getType() == IResource.FILE) {
457: selectedResource = selectedResource.getParent();
458: }
459: if (selectedResource.isAccessible()) {
460: resourceGroup.setContainerFullPath(selectedResource
461: .getFullPath());
462: }
463: }
464: }
465:
466: setPageComplete(false);
467: }
468:
469: /*
470: * @see DialogPage.setVisible(boolean)
471: */
472: public void setVisible(boolean visible) {
473: super .setVisible(visible);
474: if (visible) {
475: resourceGroup.setFocus();
476: }
477: }
478:
479: /**
480: * Checks whether the linked resource target is valid. Sets the error
481: * message accordingly and returns the status.
482: *
483: * @return IStatus validation result from the CreateLinkedResourceGroup
484: */
485: protected IStatus validateLinkedResource() {
486: IPath containerPath = resourceGroup.getContainerFullPath();
487: IPath newFolderPath = containerPath.append(resourceGroup
488: .getResource());
489: IFolder newFolderHandle = createFolderHandle(newFolderPath);
490: IStatus status = linkedResourceGroup
491: .validateLinkLocation(newFolderHandle);
492:
493: if (status.getSeverity() == IStatus.ERROR) {
494: if (firstLinkCheck) {
495: setMessage(status.getMessage());
496: } else {
497: setErrorMessage(status.getMessage());
498: }
499: } else if (status.getSeverity() == IStatus.WARNING) {
500: setMessage(status.getMessage(), WARNING);
501: setErrorMessage(null);
502: }
503: return status;
504: }
505:
506: /**
507: * Returns whether this page's controls currently all contain valid values.
508: *
509: * @return <code>true</code> if all controls are valid, and
510: * <code>false</code> if at least one is invalid
511: */
512: protected boolean validatePage() {
513: boolean valid = true;
514:
515: if (!resourceGroup.areAllValuesValid()) {
516: // if blank name then fail silently
517: if (resourceGroup.getProblemType() == ResourceAndContainerGroup.PROBLEM_RESOURCE_EMPTY
518: || resourceGroup.getProblemType() == ResourceAndContainerGroup.PROBLEM_CONTAINER_EMPTY) {
519: setMessage(resourceGroup.getProblemMessage());
520: setErrorMessage(null);
521: } else {
522: setErrorMessage(resourceGroup.getProblemMessage());
523: }
524: valid = false;
525: }
526:
527: IStatus linkedResourceStatus = null;
528: if (valid) {
529: linkedResourceStatus = validateLinkedResource();
530: if (linkedResourceStatus.getSeverity() == IStatus.ERROR) {
531: valid = false;
532: }
533: }
534: // validateLinkedResource sets messages itself
535: if (valid
536: && (linkedResourceStatus == null || linkedResourceStatus
537: .isOK())) {
538: setMessage(null);
539: setErrorMessage(null);
540: }
541: return valid;
542: }
543:
544: }
|