001: /*
002: * ChainBuilder ESB
003: * Visual Enterprise Integration
004: *
005: * Copyright (C) 2006 Bostech Corporation
006: *
007: * This program is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the
009: * Free Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
014: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
015: * for more details.
016: *
017: * You should have received a copy of the GNU General Public License along with
018: * this program; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: *
022: * $Id$
023: */
024: package com.bostechcorp.cbesb.ui.ide.wizards;
025:
026: import java.io.ByteArrayInputStream;
027: import java.io.InputStream;
028: import java.lang.reflect.InvocationTargetException;
029: import java.util.Iterator;
030:
031: import org.eclipse.core.resources.IFile;
032: import org.eclipse.core.resources.IFolder;
033: import org.eclipse.core.resources.IResource;
034: import org.eclipse.core.resources.IResourceStatus;
035: import org.eclipse.core.resources.IWorkspaceRoot;
036: import org.eclipse.core.resources.ResourcesPlugin;
037: import org.eclipse.core.runtime.CoreException;
038: import org.eclipse.core.runtime.IAdaptable;
039: import org.eclipse.core.runtime.IPath;
040: import org.eclipse.core.runtime.IProgressMonitor;
041: import org.eclipse.core.runtime.IStatus;
042: import org.eclipse.core.runtime.OperationCanceledException;
043: import org.eclipse.core.runtime.Path;
044: import org.eclipse.core.runtime.Preferences;
045: import org.eclipse.core.runtime.SubProgressMonitor;
046: import org.eclipse.core.runtime.jobs.ISchedulingRule;
047: import org.eclipse.jface.dialogs.ErrorDialog;
048: import org.eclipse.jface.dialogs.MessageDialog;
049: import org.eclipse.jface.viewers.IStructuredSelection;
050: import org.eclipse.jface.wizard.WizardPage;
051: import org.eclipse.osgi.util.NLS;
052: import org.eclipse.swt.SWT;
053: import org.eclipse.swt.events.SelectionAdapter;
054: import org.eclipse.swt.events.SelectionEvent;
055: import org.eclipse.swt.graphics.Point;
056: import org.eclipse.swt.layout.GridData;
057: import org.eclipse.swt.layout.GridLayout;
058: import org.eclipse.swt.widgets.Button;
059: import org.eclipse.swt.widgets.Composite;
060: import org.eclipse.swt.widgets.Event;
061: import org.eclipse.swt.widgets.Listener;
062: import org.eclipse.swt.widgets.Shell;
063: import org.eclipse.ui.PlatformUI;
064: import org.eclipse.ui.actions.WorkspaceModifyOperation;
065: import org.eclipse.ui.dialogs.ContainerGenerator;
066: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
067: import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
068: import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
069: import org.eclipse.ui.internal.ide.dialogs.CreateLinkedResourceGroup;
070:
071: import com.bostechcorp.cbesb.common.i18n.Message;
072: import com.bostechcorp.cbesb.common.i18n.Messages;
073:
074: /**
075: * Standard main page for a wizard that creates a file resource.
076: * <p>
077: * This page may be used by clients as-is; it may be also be subclassed to suit.
078: * </p>
079: * <p>
080: * Subclasses may override
081: * <ul>
082: * <li><code>getInitialContents</code></li>
083: * <li><code>getNewFileLabel</code></li>
084: * </ul>
085: * </p>
086: * <p>
087: * Subclasses may extend
088: * <ul>
089: * <li><code>handleEvent</code></li>
090: * </ul>
091: * </p>
092: */
093: public class WizardNewFileCreationPage extends WizardPage implements
094: Listener {
095: private static final int SIZING_CONTAINER_GROUP_HEIGHT = 250;
096:
097: // the current resource selection
098: private IStructuredSelection currentSelection;
099:
100: private String prefix = "";
101:
102: // cache of newly-created file
103: private IFile newFile;
104:
105: private IPath linkTargetPath;
106:
107: protected String path = "";
108:
109: protected String key = "";
110:
111: // widgets
112: protected ResourceAndContainerGroup resourceGroup;
113:
114: private Button advancedButton;
115:
116: private CreateLinkedResourceGroup linkedResourceGroup;
117:
118: private Composite linkedResourceParent;
119:
120: private Composite linkedResourceComposite;
121:
122: // initial value stores
123: private String initialFileName;
124:
125: private IPath initialContainerFullPath;
126:
127: /**
128: * Height of the "advanced" linked resource group. Set when the advanced
129: * group is first made visible.
130: */
131: private int linkedResourceGroupHeight = -1;
132:
133: /**
134: * First time the advanced group is validated.
135: */
136: private boolean firstLinkCheck = true;
137:
138: /**
139: * Creates a new file creation wizard page. If the initial resource
140: * selection contains exactly one container resource then it will be used as
141: * the default container resource.
142: *
143: * @param pageName
144: * the name of the page
145: * @param selection
146: * the current resource selection
147: */
148: public WizardNewFileCreationPage(String pageName,
149: IStructuredSelection selection) {
150: super (pageName);
151: setPageComplete(false);
152: this .currentSelection = selection;
153: }
154:
155: /**
156: * Creates the widget for advanced options.
157: *
158: * @param parent
159: * the parent composite
160: */
161: protected void createAdvancedControls(Composite parent) {
162: Preferences preferences = ResourcesPlugin.getPlugin()
163: .getPluginPreferences();
164:
165: if (preferences
166: .getBoolean(ResourcesPlugin.PREF_DISABLE_LINKING) == false) {
167: linkedResourceParent = new Composite(parent, SWT.NONE);
168: linkedResourceParent.setFont(parent.getFont());
169: linkedResourceParent.setLayoutData(new GridData(
170: GridData.FILL_HORIZONTAL));
171: GridLayout layout = new GridLayout();
172: layout.marginHeight = 0;
173: layout.marginWidth = 0;
174: linkedResourceParent.setLayout(layout);
175:
176: advancedButton = new Button(linkedResourceParent, SWT.PUSH);
177: advancedButton.setFont(linkedResourceParent.getFont());
178: advancedButton.setText(IDEWorkbenchMessages.showAdvanced);
179: GridData data = setButtonLayoutData(advancedButton);
180: data.horizontalAlignment = GridData.BEGINNING;
181: advancedButton.setLayoutData(data);
182: advancedButton.addSelectionListener(new SelectionAdapter() {
183: public void widgetSelected(SelectionEvent e) {
184: handleAdvancedButtonSelect();
185: }
186: });
187: }
188: linkedResourceGroup = new CreateLinkedResourceGroup(
189: IResource.FILE, new Listener() {
190: public void handleEvent(Event e) {
191: setPageComplete(validatePage(path, key));
192: firstLinkCheck = false;
193: }
194: }, new CreateLinkedResourceGroup.IStringValue() {
195: public void setValue(String string) {
196: resourceGroup.setResource(string, prefix);
197: }
198:
199: public String getValue() {
200: return resourceGroup.getResource();
201: }
202: });
203: }
204:
205: /**
206: * (non-Javadoc) Method declared on IDialogPage.
207: */
208: public void createControl(Composite parent) {
209: initializeDialogUnits(parent);
210: // top level group
211: Composite topLevel = new Composite(parent, SWT.NONE);
212: topLevel.setLayout(new GridLayout());
213: topLevel.setLayoutData(new GridData(
214: GridData.VERTICAL_ALIGN_FILL
215: | GridData.HORIZONTAL_ALIGN_FILL));
216: topLevel.setFont(parent.getFont());
217: PlatformUI.getWorkbench().getHelpSystem().setHelp(topLevel,
218: IIDEHelpContextIds.NEW_FILE_WIZARD_PAGE);
219:
220: // resource and container group
221: resourceGroup = new ResourceAndContainerGroup(topLevel, this ,
222: getNewFileLabel(),
223: IDEWorkbenchMessages.WizardNewFileCreationPage_file,
224: false, SIZING_CONTAINER_GROUP_HEIGHT);
225: resourceGroup.setAllowExistingResources(false);
226: initialPopulateContainerNameField();
227: createAdvancedControls(topLevel);
228: if (initialFileName != null) {
229: resourceGroup.setResource(initialFileName, prefix);
230: }
231: validatePage(path, key);
232: // Show description on opening
233: setErrorMessage(null);
234: setMessage(null);
235: setControl(topLevel);
236: }
237:
238: /**
239: * Creates a file resource given the file handle and contents.
240: *
241: * @param fileHandle
242: * the file handle to create a file resource with
243: * @param contents
244: * the initial contents of the new file resource, or
245: * <code>null</code> if none (equivalent to an empty stream)
246: * @param monitor
247: * the progress monitor to show visual progress with
248: * @exception CoreException
249: * if the operation fails
250: * @exception OperationCanceledException
251: * if the operation is canceled
252: */
253: protected void createFile(IFile fileHandle, InputStream contents,
254: IProgressMonitor monitor) throws CoreException {
255: if (contents == null) {
256: contents = new ByteArrayInputStream(new byte[0]);
257: }
258:
259: try {
260: // Create a new file resource in the workspace
261: if (linkTargetPath != null) {
262: fileHandle.createLink(linkTargetPath,
263: IResource.ALLOW_MISSING_LOCAL, monitor);
264: } else {
265: IPath path = fileHandle.getFullPath();
266: IWorkspaceRoot root = ResourcesPlugin.getWorkspace()
267: .getRoot();
268: int numSegments = path.segmentCount();
269: if (numSegments > 2
270: && !root.getFolder(path.removeLastSegments(1))
271: .exists()) {
272: // If the direct parent of the path doesn't exist, try to
273: // create the
274: // necessary directories.
275: for (int i = numSegments - 2; i > 0; i--) {
276: IFolder folder = root.getFolder(path
277: .removeLastSegments(i));
278: if (!folder.exists()) {
279: folder.create(false, true, monitor);
280: }
281: }
282: }
283: fileHandle.create(contents, false, monitor);
284: }
285: } catch (CoreException e) {
286: // If the file already existed locally, just refresh to get contents
287: if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED) {
288: fileHandle.refreshLocal(IResource.DEPTH_ZERO, null);
289: } else {
290: throw e;
291: }
292: }
293:
294: if (monitor.isCanceled()) {
295: throw new OperationCanceledException();
296: }
297: }
298:
299: /**
300: * Creates a file resource handle for the file with the given workspace
301: * path. This method does not create the file resource; this is the
302: * responsibility of <code>createFile</code>.
303: *
304: * @param filePath
305: * the path of the file resource to create a handle for
306: * @return the new file resource handle
307: * @see #createFile
308: */
309: protected IFile createFileHandle(IPath filePath) {
310: return IDEWorkbenchPlugin.getPluginWorkspace().getRoot()
311: .getFile(filePath);
312: }
313:
314: /**
315: * Creates the link target path if a link target has been specified.
316: */
317: protected void createLinkTarget() {
318: String linkTarget = linkedResourceGroup.getLinkTarget();
319: if (linkTarget != null) {
320: linkTargetPath = new Path(linkTarget);
321: } else {
322: linkTargetPath = null;
323: }
324: }
325:
326: /**
327: * Creates a new file resource in the selected container and with the
328: * selected name. Creates any missing resource containers along the path;
329: * does nothing if the container resources already exist.
330: * <p>
331: * In normal usage, this method is invoked after the user has pressed Finish
332: * on the wizard; the enablement of the Finish button implies that all
333: * controls on on this page currently contain valid values.
334: * </p>
335: * <p>
336: * Note that this page caches the new file once it has been successfully
337: * created; subsequent invocations of this method will answer the same file
338: * resource without attempting to create it again.
339: * </p>
340: * <p>
341: * This method should be called within a workspace modify operation since it
342: * creates resources.
343: * </p>
344: *
345: * @return the created file resource, or <code>null</code> if the file was
346: * not created
347: */
348: public IFile createNewFile(String prefix) {
349: if (newFile != null) {
350: return newFile;
351: }
352:
353: // create the new file and cache it if successful
354:
355: final IPath containerPath = resourceGroup
356: .getContainerFullPath();
357: IPath newFilePath = containerPath.append(resourceGroup
358: .getResource().concat("." + prefix));
359: final IFile newFileHandle = createFileHandle(newFilePath);
360: final InputStream initialContents = getInitialContents();
361:
362: createLinkTarget();
363: WorkspaceModifyOperation op = new WorkspaceModifyOperation(
364: createRule(newFileHandle)) {
365: protected void execute(IProgressMonitor monitor)
366: throws CoreException {
367: try {
368: monitor
369: .beginTask(
370: IDEWorkbenchMessages.WizardNewFileCreationPage_progress,
371: 2000);
372: ContainerGenerator generator = new ContainerGenerator(
373: containerPath);
374: generator.generateContainer(new SubProgressMonitor(
375: monitor, 1000));
376: createFile(newFileHandle, initialContents,
377: new SubProgressMonitor(monitor, 1000));
378: } finally {
379: monitor.done();
380: }
381: }
382: };
383:
384: try {
385: getContainer().run(true, true, op);
386: } catch (InterruptedException e) {
387: // TODO
388: return null;
389: } catch (InvocationTargetException e) {
390: if (e.getTargetException() instanceof CoreException) {
391: ErrorDialog
392: .openError(
393: getContainer().getShell(), // Was
394: // Utilities.getFocusShell()
395: IDEWorkbenchMessages.WizardNewFileCreationPage_errorTitle,
396: null, // no special message
397: ((CoreException) e.getTargetException())
398: .getStatus());
399: } else {
400: // CoreExceptions are handled above, but unexpected runtime
401: // exceptions and errors may still occur.
402: IDEWorkbenchPlugin.log(getClass(),
403: "createNewFile()", e.getTargetException()); //$NON-NLS-1$
404: MessageDialog
405: .openError(
406: getContainer().getShell(),
407: IDEWorkbenchMessages.WizardNewFileCreationPage_internalErrorTitle,
408: NLS
409: .bind(
410: IDEWorkbenchMessages.WizardNewFileCreationPage_internalErrorMessage,
411: e.getTargetException()
412: .getMessage()));
413: }
414: return null;
415: }
416:
417: newFile = newFileHandle;
418:
419: return newFile;
420: }
421:
422: /**
423: * Returns the scheduling rule to use when creating the resource at the
424: * given container path. The rule should be the creation rule for the
425: * top-most non-existing parent.
426: *
427: * @param resource
428: * The resource being created
429: * @return The scheduling rule for creating the given resource
430: * @since 3.1
431: */
432: protected ISchedulingRule createRule(IResource resource) {
433: IResource parent = resource.getParent();
434: while (parent != null) {
435: if (parent.exists()) {
436: return resource.getWorkspace().getRuleFactory()
437: .createRule(resource);
438: }
439: resource = parent;
440: parent = parent.getParent();
441: }
442: return resource.getWorkspace().getRoot();
443: }
444:
445: /**
446: * Returns the current full path of the containing resource as entered or
447: * selected by the user, or its anticipated initial value.
448: *
449: * @return the container's full path, anticipated initial value, or
450: * <code>null</code> if no path is known
451: */
452: public IPath getContainerFullPath() {
453: return resourceGroup.getContainerFullPath();
454: }
455:
456: /**
457: * Returns the current file name as entered by the user, or its anticipated
458: * initial value.
459: *
460: * @return the file name, its anticipated initial value, or
461: * <code>null</code> if no file name is known
462: */
463: public String getFileName() {
464: if (resourceGroup == null) {
465: return initialFileName;
466: }
467:
468: return resourceGroup.getResource();
469: }
470:
471: /**
472: * Returns a stream containing the initial contents to be given to new file
473: * resource instances. <b>Subclasses</b> may wish to override. This default
474: * implementation provides no initial contents.
475: *
476: * @return initial contents to be given to new file resource instances
477: */
478: protected InputStream getInitialContents() {
479: return null;
480: }
481:
482: /**
483: * Returns the label to display in the file name specification visual
484: * component group.
485: * <p>
486: * Subclasses may reimplement.
487: * </p>
488: *
489: * @return the label to display in the file name specification visual
490: * component group
491: */
492: protected String getNewFileLabel() {
493: return IDEWorkbenchMessages.WizardNewFileCreationPage_fileLabel;
494: }
495:
496: /**
497: * Shows/hides the advanced option widgets.
498: */
499: protected void handleAdvancedButtonSelect() {
500: Shell shell = getShell();
501: Point shellSize = shell.getSize();
502: Composite composite = (Composite) getControl();
503:
504: if (linkedResourceComposite != null) {
505: linkedResourceComposite.dispose();
506: linkedResourceComposite = null;
507: composite.layout();
508: shell.setSize(shellSize.x, shellSize.y
509: - linkedResourceGroupHeight);
510: advancedButton.setText(IDEWorkbenchMessages.showAdvanced);
511: } else {
512: linkedResourceComposite = linkedResourceGroup
513: .createContents(linkedResourceParent);
514: if (linkedResourceGroupHeight == -1) {
515: Point groupSize = linkedResourceComposite.computeSize(
516: SWT.DEFAULT, SWT.DEFAULT, true);
517: linkedResourceGroupHeight = groupSize.y;
518: }
519: shell.setSize(shellSize.x, shellSize.y
520: + linkedResourceGroupHeight);
521: composite.layout();
522: advancedButton.setText(IDEWorkbenchMessages.hideAdvanced);
523: }
524: }
525:
526: /**
527: * The <code>WizardNewFileCreationPage</code> implementation of this
528: * <code>Listener</code> method handles all events and enablements for
529: * controls on this page. Subclasses may extend.
530: */
531: public void handleEvent(Event event) {
532: // setPageComplete(validatePage(path, key));
533: }
534:
535: /**
536: * Sets the initial contents of the container name entry field, based upon
537: * either a previously-specified initial value or the ability to determine
538: * such a value.
539: */
540: protected void initialPopulateContainerNameField() {
541: if (initialContainerFullPath != null) {
542: resourceGroup
543: .setContainerFullPath(initialContainerFullPath);
544: } else {
545: Iterator it = currentSelection.iterator();
546: if (it.hasNext()) {
547: Object object = it.next();
548: IResource selectedResource = null;
549: if (object instanceof IResource) {
550: selectedResource = (IResource) object;
551: } else if (object instanceof IAdaptable) {
552: selectedResource = (IResource) ((IAdaptable) object)
553: .getAdapter(IResource.class);
554: }
555: if (selectedResource != null) {
556: if (selectedResource.getType() == IResource.FILE) {
557: selectedResource = selectedResource.getParent();
558: }
559: if (selectedResource.isAccessible()) {
560: resourceGroup
561: .setContainerFullPath(selectedResource
562: .getFullPath());
563: }
564: }
565: }
566: }
567: }
568:
569: /**
570: * Sets the value of this page's container name field, or stores it for
571: * future use if this page's controls do not exist yet.
572: *
573: * @param path
574: * the full path to the container
575: */
576: public void setContainerFullPath(IPath path) {
577: if (resourceGroup == null) {
578: initialContainerFullPath = path;
579: } else {
580: resourceGroup.setContainerFullPath(path);
581: }
582: }
583:
584: /**
585: * Sets the value of this page's file name field, or stores it for future
586: * use if this page's controls do not exist yet.
587: *
588: * @param value
589: * new file name
590: */
591: public void setFileName(String value, String prefix) {
592: this .prefix = prefix;
593: if (resourceGroup == null) {
594: initialFileName = value;
595: } else {
596: resourceGroup.setResource(value, prefix);
597: }
598: }
599:
600: /**
601: * Checks whether the linked resource target is valid. Sets the error
602: * message accordingly and returns the status.
603: *
604: * @return IStatus validation result from the CreateLinkedResourceGroup
605: */
606: protected IStatus validateLinkedResource() {
607: IPath containerPath = resourceGroup.getContainerFullPath();
608: IPath newFilePath = containerPath.append(resourceGroup
609: .getResource());
610: IFile newFileHandle = createFileHandle(newFilePath);
611: IStatus status = linkedResourceGroup
612: .validateLinkLocation(newFileHandle);
613:
614: if (status.getSeverity() == IStatus.ERROR) {
615: if (firstLinkCheck) {
616: setMessage(status.getMessage());
617: } else {
618: setErrorMessage(status.getMessage());
619: }
620: } else if (status.getSeverity() == IStatus.WARNING) {
621: setMessage(status.getMessage(), WARNING);
622: setErrorMessage(null);
623: }
624: return status;
625: }
626:
627: /**
628: * Returns whether this page's controls currently all contain valid values.
629: *
630: * @param key
631: *
632: * @return <code>true</code> if all controls are valid, and
633: * <code>false</code> if at least one is invalid
634: */
635: protected boolean validatePage(String path, String key) {
636: this .path = path;
637: this .key = key;
638: boolean valid = true;
639:
640: if (!resourceGroup.areAllValuesValid()) {
641: // if blank name then fail silently
642: if (resourceGroup.getProblemType() == ResourceAndContainerGroup.PROBLEM_RESOURCE_EMPTY
643: || resourceGroup.getProblemType() == ResourceAndContainerGroup.PROBLEM_CONTAINER_EMPTY) {
644: setMessage(resourceGroup.getProblemMessage());
645: setErrorMessage(null);
646: } else {
647: setErrorMessage(resourceGroup.getProblemMessage());
648: }
649: valid = false;
650: }
651:
652: IStatus linkedResourceStatus = null;
653: if (valid) {
654: linkedResourceStatus = validateLinkedResource();
655: if (linkedResourceStatus.getSeverity() == IStatus.ERROR) {
656: valid = false;
657: }
658: }
659: // validateLinkedResource sets messages itself
660: if (valid
661: && (linkedResourceStatus == null || linkedResourceStatus
662: .isOK())) {
663: setMessage(null);
664: setErrorMessage(null);
665: }
666: return valid;
667: }
668:
669: public boolean canFlipToNextPagebyName(String name) {
670: if (key.equals(name)) {
671: if (path.indexOf(key) != -1) {
672: return true;
673: } else {
674: setErrorMessage(new Message(Messages.IDE_KEY, key)
675: .getMessage());
676: return false;
677: }
678: }
679: return false;
680:
681: }
682:
683: /*
684: * @see DialogPage.setVisible(boolean)
685: */
686: public void setVisible(boolean visible) {
687: super .setVisible(visible);
688: if (visible) {
689: resourceGroup.setFocus();
690: }
691:
692: }
693:
694: public boolean isPageComplete() {
695: if (!path.endsWith(key)) {
696: setErrorMessage(new Message(Messages.IDE_KEY, key)
697: .getMessage());
698: return false;
699: }
700: return validatePage(path, key);
701: }
702: }
|