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.ui.internal.wizards.datatransfer;
011:
012: import java.io.File;
013: import java.lang.reflect.InvocationTargetException;
014: import java.util.List;
015:
016: import org.eclipse.core.resources.IContainer;
017: import org.eclipse.core.resources.IProject;
018: import org.eclipse.core.resources.IWorkspaceRoot;
019: import org.eclipse.core.resources.ResourcesPlugin;
020: import org.eclipse.core.runtime.IPath;
021: import org.eclipse.core.runtime.IStatus;
022: import org.eclipse.core.runtime.Path;
023: import org.eclipse.jface.dialogs.ErrorDialog;
024: import org.eclipse.jface.dialogs.IDialogSettings;
025: import org.eclipse.jface.viewers.IStructuredSelection;
026: import org.eclipse.osgi.util.NLS;
027: import org.eclipse.swt.SWT;
028: import org.eclipse.swt.graphics.Font;
029: import org.eclipse.swt.layout.GridData;
030: import org.eclipse.swt.layout.GridLayout;
031: import org.eclipse.swt.widgets.Button;
032: import org.eclipse.swt.widgets.Combo;
033: import org.eclipse.swt.widgets.Composite;
034: import org.eclipse.swt.widgets.DirectoryDialog;
035: import org.eclipse.swt.widgets.Event;
036: import org.eclipse.swt.widgets.Group;
037: import org.eclipse.swt.widgets.Label;
038: import org.eclipse.swt.widgets.Listener;
039: import org.eclipse.swt.widgets.Widget;
040: import org.eclipse.ui.PlatformUI;
041: import org.eclipse.ui.dialogs.WizardExportResourcesPage;
042:
043: /**
044: * Page 1 of the base resource export-to-file-system Wizard
045: */
046: public class WizardFileSystemResourceExportPage1 extends
047: WizardExportResourcesPage implements Listener {
048:
049: // widgets
050: private Combo destinationNameField;
051:
052: private Button destinationBrowseButton;
053:
054: protected Button overwriteExistingFilesCheckbox;
055:
056: protected Button createDirectoryStructureButton;
057:
058: protected Button createSelectionOnlyButton;
059:
060: // dialog store id constants
061: private static final String STORE_DESTINATION_NAMES_ID = "WizardFileSystemResourceExportPage1.STORE_DESTINATION_NAMES_ID"; //$NON-NLS-1$
062:
063: private static final String STORE_OVERWRITE_EXISTING_FILES_ID = "WizardFileSystemResourceExportPage1.STORE_OVERWRITE_EXISTING_FILES_ID"; //$NON-NLS-1$
064:
065: private static final String STORE_CREATE_STRUCTURE_ID = "WizardFileSystemResourceExportPage1.STORE_CREATE_STRUCTURE_ID"; //$NON-NLS-1$
066:
067: //messages
068: private static final String SELECT_DESTINATION_MESSAGE = DataTransferMessages.FileExport_selectDestinationMessage;
069:
070: private static final String SELECT_DESTINATION_TITLE = DataTransferMessages.FileExport_selectDestinationTitle;
071:
072: /**
073: * Create an instance of this class
074: */
075: protected WizardFileSystemResourceExportPage1(String name,
076: IStructuredSelection selection) {
077: super (name, selection);
078: }
079:
080: /**
081: * Create an instance of this class.
082: *
083: * @param selection the selection
084: */
085: public WizardFileSystemResourceExportPage1(
086: IStructuredSelection selection) {
087: this ("fileSystemExportPage1", selection); //$NON-NLS-1$
088: setTitle(DataTransferMessages.DataTransfer_fileSystemTitle);
089: setDescription(DataTransferMessages.FileExport_exportLocalFileSystem);
090: }
091:
092: /**
093: * Add the passed value to self's destination widget's history
094: *
095: * @param value java.lang.String
096: */
097: protected void addDestinationItem(String value) {
098: destinationNameField.add(value);
099: }
100:
101: /** (non-Javadoc)
102: * Method declared on IDialogPage.
103: */
104: public void createControl(Composite parent) {
105: super .createControl(parent);
106: giveFocusToDestination();
107: PlatformUI
108: .getWorkbench()
109: .getHelpSystem()
110: .setHelp(
111: getControl(),
112: IDataTransferHelpContextIds.FILE_SYSTEM_EXPORT_WIZARD_PAGE);
113: }
114:
115: /**
116: * Create the export destination specification widgets
117: *
118: * @param parent org.eclipse.swt.widgets.Composite
119: */
120: protected void createDestinationGroup(Composite parent) {
121:
122: Font font = parent.getFont();
123: // destination specification group
124: Composite destinationSelectionGroup = new Composite(parent,
125: SWT.NONE);
126: GridLayout layout = new GridLayout();
127: layout.numColumns = 3;
128: destinationSelectionGroup.setLayout(layout);
129: destinationSelectionGroup.setLayoutData(new GridData(
130: GridData.HORIZONTAL_ALIGN_FILL
131: | GridData.VERTICAL_ALIGN_FILL));
132: destinationSelectionGroup.setFont(font);
133:
134: Label destinationLabel = new Label(destinationSelectionGroup,
135: SWT.NONE);
136: destinationLabel.setText(getDestinationLabel());
137: destinationLabel.setFont(font);
138:
139: // destination name entry field
140: destinationNameField = new Combo(destinationSelectionGroup,
141: SWT.SINGLE | SWT.BORDER);
142: destinationNameField.addListener(SWT.Modify, this );
143: destinationNameField.addListener(SWT.Selection, this );
144: GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
145: | GridData.GRAB_HORIZONTAL);
146: data.widthHint = SIZING_TEXT_FIELD_WIDTH;
147: destinationNameField.setLayoutData(data);
148: destinationNameField.setFont(font);
149:
150: // destination browse button
151: destinationBrowseButton = new Button(destinationSelectionGroup,
152: SWT.PUSH);
153: destinationBrowseButton
154: .setText(DataTransferMessages.DataTransfer_browse);
155: destinationBrowseButton.addListener(SWT.Selection, this );
156: destinationBrowseButton.setFont(font);
157: setButtonLayoutData(destinationBrowseButton);
158:
159: new Label(parent, SWT.NONE); // vertical spacer
160: }
161:
162: /**
163: * Create the buttons in the options group.
164: */
165:
166: protected void createOptionsGroupButtons(Group optionsGroup) {
167:
168: Font font = optionsGroup.getFont();
169: createOverwriteExisting(optionsGroup, font);
170:
171: createDirectoryStructureOptions(optionsGroup, font);
172: }
173:
174: /**
175: * Create the buttons for the group that determine if the entire or
176: * selected directory structure should be created.
177: * @param optionsGroup
178: * @param font
179: */
180: protected void createDirectoryStructureOptions(
181: Composite optionsGroup, Font font) {
182: // create directory structure radios
183: createDirectoryStructureButton = new Button(optionsGroup,
184: SWT.RADIO | SWT.LEFT);
185: createDirectoryStructureButton
186: .setText(DataTransferMessages.FileExport_createDirectoryStructure);
187: createDirectoryStructureButton.setSelection(false);
188: createDirectoryStructureButton.setFont(font);
189:
190: // create directory structure radios
191: createSelectionOnlyButton = new Button(optionsGroup, SWT.RADIO
192: | SWT.LEFT);
193: createSelectionOnlyButton
194: .setText(DataTransferMessages.FileExport_createSelectedDirectories);
195: createSelectionOnlyButton.setSelection(true);
196: createSelectionOnlyButton.setFont(font);
197: }
198:
199: /**
200: * Create the button for checking if we should ask if we are going to
201: * overwrite existing files.
202: * @param optionsGroup
203: * @param font
204: */
205: protected void createOverwriteExisting(Group optionsGroup, Font font) {
206: // overwrite... checkbox
207: overwriteExistingFilesCheckbox = new Button(optionsGroup,
208: SWT.CHECK | SWT.LEFT);
209: overwriteExistingFilesCheckbox
210: .setText(DataTransferMessages.ExportFile_overwriteExisting);
211: overwriteExistingFilesCheckbox.setFont(font);
212: }
213:
214: /**
215: * Attempts to ensure that the specified directory exists on the local file system.
216: * Answers a boolean indicating success.
217: *
218: * @return boolean
219: * @param directory java.io.File
220: */
221: protected boolean ensureDirectoryExists(File directory) {
222: if (!directory.exists()) {
223: if (!queryYesNoQuestion(DataTransferMessages.DataTransfer_createTargetDirectory)) {
224: return false;
225: }
226:
227: if (!directory.mkdirs()) {
228: displayErrorDialog(DataTransferMessages.DataTransfer_directoryCreationError);
229: giveFocusToDestination();
230: return false;
231: }
232: }
233:
234: return true;
235: }
236:
237: /**
238: * If the target for export does not exist then attempt to create it.
239: * Answer a boolean indicating whether the target exists (ie.- if it
240: * either pre-existed or this method was able to create it)
241: *
242: * @return boolean
243: */
244: protected boolean ensureTargetIsValid(File targetDirectory) {
245: if (targetDirectory.exists() && !targetDirectory.isDirectory()) {
246: displayErrorDialog(DataTransferMessages.FileExport_directoryExists);
247: giveFocusToDestination();
248: return false;
249: }
250:
251: return ensureDirectoryExists(targetDirectory);
252: }
253:
254: /**
255: * Set up and execute the passed Operation. Answer a boolean indicating success.
256: *
257: * @return boolean
258: */
259: protected boolean executeExportOperation(
260: FileSystemExportOperation op) {
261: op.setCreateLeadupStructure(createDirectoryStructureButton
262: .getSelection());
263: op.setOverwriteFiles(overwriteExistingFilesCheckbox
264: .getSelection());
265:
266: try {
267: getContainer().run(true, true, op);
268: } catch (InterruptedException e) {
269: return false;
270: } catch (InvocationTargetException e) {
271: displayErrorDialog(e.getTargetException());
272: return false;
273: }
274:
275: IStatus status = op.getStatus();
276: if (!status.isOK()) {
277: ErrorDialog.openError(getContainer().getShell(),
278: DataTransferMessages.DataTransfer_exportProblems,
279: null, // no special message
280: status);
281: return false;
282: }
283:
284: return true;
285: }
286:
287: /**
288: * The Finish button was pressed. Try to do the required work now and answer
289: * a boolean indicating success. If false is returned then the wizard will
290: * not close.
291: *
292: * @return boolean
293: */
294: public boolean finish() {
295: List resourcesToExport = getWhiteCheckedResources();
296: if (!ensureTargetIsValid(new File(getDestinationValue()))) {
297: return false;
298: }
299:
300: //Save dirty editors if possible but do not stop if not all are saved
301: saveDirtyEditors();
302: // about to invoke the operation so save our state
303: saveWidgetValues();
304:
305: return executeExportOperation(new FileSystemExportOperation(
306: null, resourcesToExport, getDestinationValue(), this ));
307: }
308:
309: /**
310: * Answer the string to display in self as the destination type
311: *
312: * @return java.lang.String
313: */
314: protected String getDestinationLabel() {
315: return DataTransferMessages.FileExport_toDirectory;
316: }
317:
318: /**
319: * Answer the contents of self's destination specification widget
320: *
321: * @return java.lang.String
322: */
323: protected String getDestinationValue() {
324: return destinationNameField.getText().trim();
325: }
326:
327: /**
328: * Set the current input focus to self's destination entry field
329: */
330: protected void giveFocusToDestination() {
331: destinationNameField.setFocus();
332: }
333:
334: /**
335: * Open an appropriate destination browser so that the user can specify a source
336: * to import from
337: */
338: protected void handleDestinationBrowseButtonPressed() {
339: DirectoryDialog dialog = new DirectoryDialog(getContainer()
340: .getShell(), SWT.SAVE);
341: dialog.setMessage(SELECT_DESTINATION_MESSAGE);
342: dialog.setText(SELECT_DESTINATION_TITLE);
343: dialog.setFilterPath(getDestinationValue());
344: String selectedDirectoryName = dialog.open();
345:
346: if (selectedDirectoryName != null) {
347: setErrorMessage(null);
348: setDestinationValue(selectedDirectoryName);
349: }
350: }
351:
352: /**
353: * Handle all events and enablements for widgets in this page
354: * @param e Event
355: */
356: public void handleEvent(Event e) {
357: Widget source = e.widget;
358:
359: if (source == destinationBrowseButton) {
360: handleDestinationBrowseButtonPressed();
361: }
362:
363: updatePageCompletion();
364: }
365:
366: /**
367: * Hook method for saving widget values for restoration by the next instance
368: * of this class.
369: */
370: protected void internalSaveWidgetValues() {
371: // update directory names history
372: IDialogSettings settings = getDialogSettings();
373: if (settings != null) {
374: String[] directoryNames = settings
375: .getArray(STORE_DESTINATION_NAMES_ID);
376: if (directoryNames == null) {
377: directoryNames = new String[0];
378: }
379:
380: directoryNames = addToHistory(directoryNames,
381: getDestinationValue());
382: settings.put(STORE_DESTINATION_NAMES_ID, directoryNames);
383:
384: // options
385: settings.put(STORE_OVERWRITE_EXISTING_FILES_ID,
386: overwriteExistingFilesCheckbox.getSelection());
387:
388: settings.put(STORE_CREATE_STRUCTURE_ID,
389: createDirectoryStructureButton.getSelection());
390:
391: }
392: }
393:
394: /**
395: * Hook method for restoring widget values to the values that they held
396: * last time this wizard was used to completion.
397: */
398: protected void restoreWidgetValues() {
399: IDialogSettings settings = getDialogSettings();
400: if (settings != null) {
401: String[] directoryNames = settings
402: .getArray(STORE_DESTINATION_NAMES_ID);
403: if (directoryNames == null) {
404: return; // ie.- no settings stored
405: }
406:
407: // destination
408: setDestinationValue(directoryNames[0]);
409: for (int i = 0; i < directoryNames.length; i++) {
410: addDestinationItem(directoryNames[i]);
411: }
412:
413: // options
414: overwriteExistingFilesCheckbox.setSelection(settings
415: .getBoolean(STORE_OVERWRITE_EXISTING_FILES_ID));
416:
417: boolean createDirectories = settings
418: .getBoolean(STORE_CREATE_STRUCTURE_ID);
419: createDirectoryStructureButton
420: .setSelection(createDirectories);
421: createSelectionOnlyButton.setSelection(!createDirectories);
422: }
423: }
424:
425: /**
426: * Set the contents of the receivers destination specification widget to
427: * the passed value
428: *
429: */
430: protected void setDestinationValue(String value) {
431: destinationNameField.setText(value);
432: }
433:
434: /**
435: * Answer a boolean indicating whether the receivers destination specification
436: * widgets currently all contain valid values.
437: */
438: protected boolean validateDestinationGroup() {
439: String destinationValue = getDestinationValue();
440: if (destinationValue.length() == 0) {
441: setMessage(destinationEmptyMessage());
442: return false;
443: }
444:
445: String conflictingContainer = getConflictingContainerNameFor(destinationValue);
446: if (conflictingContainer == null) {
447: // no error message, but warning may exists
448: String threatenedContainer = getOverlappingProjectName(destinationValue);
449: if (threatenedContainer == null)
450: setMessage(null);
451: else
452: setMessage(
453: NLS
454: .bind(
455: DataTransferMessages.FileExport_conflictingContainer,
456: threatenedContainer), WARNING);
457:
458: } else {
459: setErrorMessage(NLS
460: .bind(
461: DataTransferMessages.FileExport_conflictingContainer,
462: conflictingContainer));
463: giveFocusToDestination();
464: return false;
465: }
466:
467: return true;
468: }
469:
470: /*
471: * (non-Javadoc)
472: * @see org.eclipse.ui.dialogs.WizardDataTransferPage#validateSourceGroup()
473: */
474: protected boolean validateSourceGroup() {
475: // there must be some resources selected for Export
476: boolean isValid = true;
477: List resourcesToExport = getWhiteCheckedResources();
478: if (resourcesToExport.size() == 0) {
479: setErrorMessage(DataTransferMessages.FileExport_noneSelected);
480: isValid = false;
481: } else {
482: setErrorMessage(null);
483: }
484: return super .validateSourceGroup() && isValid;
485: }
486:
487: /**
488: * Get the message used to denote an empty destination.
489: */
490: protected String destinationEmptyMessage() {
491: return DataTransferMessages.FileExport_destinationEmpty;
492: }
493:
494: /**
495: * Returns the name of a container with a location that encompasses targetDirectory.
496: * Returns null if there is no conflict.
497: *
498: * @param targetDirectory the path of the directory to check.
499: * @return the conflicting container name or <code>null</code>
500: */
501: protected String getConflictingContainerNameFor(
502: String targetDirectory) {
503:
504: IPath rootPath = ResourcesPlugin.getWorkspace().getRoot()
505: .getLocation();
506: IPath testPath = new Path(targetDirectory);
507: // cannot export into workspace root
508: if (testPath.equals(rootPath))
509: return rootPath.lastSegment();
510:
511: //Are they the same?
512: if (testPath.matchingFirstSegments(rootPath) == rootPath
513: .segmentCount()) {
514: String firstSegment = testPath.removeFirstSegments(
515: rootPath.segmentCount()).segment(0);
516: if (!Character.isLetterOrDigit(firstSegment.charAt(0)))
517: return firstSegment;
518: }
519:
520: return null;
521:
522: }
523:
524: /**
525: * Returns the name of a {@link IProject} with a location that includes
526: * targetDirectory. Returns null if there is no such {@link IProject}.
527: *
528: * @param targetDirectory
529: * the path of the directory to check.
530: * @return the overlapping project name or <code>null</code>
531: */
532: private String getOverlappingProjectName(String targetDirectory) {
533: IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
534: IPath testPath = new Path(targetDirectory);
535: IContainer[] containers = root
536: .findContainersForLocation(testPath);
537: if (containers.length > 0) {
538: return containers[0].getProject().getName();
539: }
540: return null;
541: }
542:
543: }
|