001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 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: * Bob Foster <bob@objfac.com>
011: * - Fix for bug 23025 - SaveAsDialog should not assume what is being saved is an IFile
012: * Benjamin Muskalla <b.muskalla@gmx.net>
013: * - Fix for bug 82541 - [Dialogs] SaveAsDialog should better handle closed projects
014: *******************************************************************************/package org.eclipse.ui.dialogs;
015:
016: import org.eclipse.core.resources.IFile;
017: import org.eclipse.core.resources.IProject;
018: import org.eclipse.core.resources.IResource;
019: import org.eclipse.core.resources.IWorkspace;
020: import org.eclipse.core.resources.ResourcesPlugin;
021: import org.eclipse.core.runtime.IPath;
022: import org.eclipse.core.runtime.IStatus;
023: import org.eclipse.jface.dialogs.IDialogConstants;
024: import org.eclipse.jface.dialogs.IDialogSettings;
025: import org.eclipse.jface.dialogs.MessageDialog;
026: import org.eclipse.jface.dialogs.TitleAreaDialog;
027: import org.eclipse.osgi.util.NLS;
028: import org.eclipse.swt.SWT;
029: import org.eclipse.swt.graphics.Image;
030: import org.eclipse.swt.layout.GridData;
031: import org.eclipse.swt.layout.GridLayout;
032: import org.eclipse.swt.widgets.Button;
033: import org.eclipse.swt.widgets.Composite;
034: import org.eclipse.swt.widgets.Control;
035: import org.eclipse.swt.widgets.Event;
036: import org.eclipse.swt.widgets.Listener;
037: import org.eclipse.swt.widgets.Shell;
038: import org.eclipse.ui.PlatformUI;
039: import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages;
040: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
041: import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
042: import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
043: import org.eclipse.ui.internal.ide.misc.ResourceAndContainerGroup;
044:
045: /**
046: * A standard "Save As" dialog which solicits a path from the user. The
047: * <code>getResult</code> method returns the path. Note that the folder
048: * at the specified path might not exist and might need to be created.
049: * <p>
050: * This class may be instantiated; it is not intended to be subclassed.
051: * </p>
052: *
053: * @see org.eclipse.ui.dialogs.ContainerGenerator
054: */
055: public class SaveAsDialog extends TitleAreaDialog {
056:
057: private static final String DIALOG_SETTINGS_SECTION = "SaveAsDialogSettings"; //$NON-NLS-1$
058:
059: private IFile originalFile = null;
060:
061: private String originalName = null;
062:
063: private IPath result;
064:
065: // widgets
066: private ResourceAndContainerGroup resourceGroup;
067:
068: private Button okButton;
069:
070: /**
071: * Image for title area
072: */
073: private Image dlgTitleImage = null;
074:
075: /**
076: * Creates a new Save As dialog for no specific file.
077: *
078: * @param parentShell the parent shell
079: */
080: public SaveAsDialog(Shell parentShell) {
081: super (parentShell);
082: }
083:
084: /* (non-Javadoc)
085: * Method declared in Window.
086: */
087: protected void configureShell(Shell shell) {
088: super .configureShell(shell);
089: shell.setText(IDEWorkbenchMessages.SaveAsDialog_text);
090: PlatformUI.getWorkbench().getHelpSystem().setHelp(shell,
091: IIDEHelpContextIds.SAVE_AS_DIALOG);
092: }
093:
094: /* (non-Javadoc)
095: * Method declared in Window.
096: */
097: protected Control createContents(Composite parent) {
098:
099: Control contents = super .createContents(parent);
100:
101: initializeControls();
102: validatePage();
103: resourceGroup.setFocus();
104: setTitle(IDEWorkbenchMessages.SaveAsDialog_title);
105: dlgTitleImage = IDEInternalWorkbenchImages.getImageDescriptor(
106: IDEInternalWorkbenchImages.IMG_DLGBAN_SAVEAS_DLG)
107: .createImage();
108: setTitleImage(dlgTitleImage);
109: setMessage(IDEWorkbenchMessages.SaveAsDialog_message);
110:
111: return contents;
112: }
113:
114: /**
115: * The <code>SaveAsDialog</code> implementation of this <code>Window</code>
116: * method disposes of the banner image when the dialog is closed.
117: */
118: public boolean close() {
119: if (dlgTitleImage != null) {
120: dlgTitleImage.dispose();
121: }
122: return super .close();
123: }
124:
125: /* (non-Javadoc)
126: * Method declared on Dialog.
127: */
128: protected void createButtonsForButtonBar(Composite parent) {
129: okButton = createButton(parent, IDialogConstants.OK_ID,
130: IDialogConstants.OK_LABEL, true);
131: createButton(parent, IDialogConstants.CANCEL_ID,
132: IDialogConstants.CANCEL_LABEL, false);
133: }
134:
135: /* (non-Javadoc)
136: * Method declared on Dialog.
137: */
138: protected Control createDialogArea(Composite parent) {
139: // top level composite
140: Composite parentComposite = (Composite) super
141: .createDialogArea(parent);
142:
143: // create a composite with standard margins and spacing
144: Composite composite = new Composite(parentComposite, SWT.NONE);
145: GridLayout layout = new GridLayout();
146: layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
147: layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
148: layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
149: layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
150: composite.setLayout(layout);
151: composite.setLayoutData(new GridData(GridData.FILL_BOTH));
152: composite.setFont(parentComposite.getFont());
153:
154: Listener listener = new Listener() {
155: public void handleEvent(Event event) {
156: setDialogComplete(validatePage());
157: }
158: };
159:
160: resourceGroup = new ResourceAndContainerGroup(composite,
161: listener, IDEWorkbenchMessages.SaveAsDialog_fileLabel,
162: IDEWorkbenchMessages.SaveAsDialog_file);
163: resourceGroup.setAllowExistingResources(true);
164:
165: return parentComposite;
166: }
167:
168: /**
169: * Returns the full path entered by the user.
170: * <p>
171: * Note that the file and container might not exist and would need to be created.
172: * See the <code>IFile.create</code> method and the
173: * <code>ContainerGenerator</code> class.
174: * </p>
175: *
176: * @return the path, or <code>null</code> if Cancel was pressed
177: */
178: public IPath getResult() {
179: return result;
180: }
181:
182: /**
183: * Initializes the controls of this dialog.
184: */
185: private void initializeControls() {
186: if (originalFile != null) {
187: resourceGroup.setContainerFullPath(originalFile.getParent()
188: .getFullPath());
189: resourceGroup.setResource(originalFile.getName());
190: } else if (originalName != null) {
191: resourceGroup.setResource(originalName);
192: }
193: setDialogComplete(validatePage());
194: }
195:
196: /* (non-Javadoc)
197: * Method declared on Dialog.
198: */
199: protected void okPressed() {
200: // Get new path.
201: IPath path = resourceGroup.getContainerFullPath().append(
202: resourceGroup.getResource());
203:
204: //If the user does not supply a file extension and if the save
205: //as dialog was provided a default file name append the extension
206: //of the default filename to the new name
207: if (path.getFileExtension() == null) {
208: if (originalFile != null
209: && originalFile.getFileExtension() != null) {
210: path = path.addFileExtension(originalFile
211: .getFileExtension());
212: } else if (originalName != null) {
213: int pos = originalName.lastIndexOf('.');
214: if (++pos > 0 && pos < originalName.length()) {
215: path = path.addFileExtension(originalName
216: .substring(pos));
217: }
218: }
219: }
220:
221: // If the path already exists then confirm overwrite.
222: IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(
223: path);
224: if (file.exists()) {
225: String[] buttons = new String[] {
226: IDialogConstants.YES_LABEL,
227: IDialogConstants.NO_LABEL,
228: IDialogConstants.CANCEL_LABEL };
229: String question = NLS
230: .bind(
231: IDEWorkbenchMessages.SaveAsDialog_overwriteQuestion,
232: path.toOSString());
233: MessageDialog d = new MessageDialog(getShell(),
234: IDEWorkbenchMessages.Question, null, question,
235: MessageDialog.QUESTION, buttons, 0);
236: int overwrite = d.open();
237: switch (overwrite) {
238: case 0: // Yes
239: break;
240: case 1: // No
241: return;
242: case 2: // Cancel
243: default:
244: cancelPressed();
245: return;
246: }
247: }
248:
249: // Store path and close.
250: result = path;
251: close();
252: }
253:
254: /**
255: * Sets the completion state of this dialog and adjusts the enable state of
256: * the Ok button accordingly.
257: *
258: * @param value <code>true</code> if this dialog is compelete, and
259: * <code>false</code> otherwise
260: */
261: protected void setDialogComplete(boolean value) {
262: okButton.setEnabled(value);
263: }
264:
265: /**
266: * Sets the original file to use.
267: *
268: * @param originalFile the original file
269: */
270: public void setOriginalFile(IFile originalFile) {
271: this .originalFile = originalFile;
272: }
273:
274: /**
275: * Set the original file name to use.
276: * Used instead of <code>setOriginalFile</code>
277: * when the original resource is not an IFile.
278: * Must be called before <code>create</code>.
279: * @param originalName default file name
280: */
281: public void setOriginalName(String originalName) {
282: this .originalName = originalName;
283: }
284:
285: /**
286: * Returns whether this page's visual components all contain valid values.
287: *
288: * @return <code>true</code> if valid, and <code>false</code> otherwise
289: */
290: private boolean validatePage() {
291: if (!resourceGroup.areAllValuesValid()) {
292: if (!resourceGroup.getResource().equals("")) { //$NON-NLS-1$
293: setErrorMessage(resourceGroup.getProblemMessage());
294: } else {
295: setErrorMessage(null);
296: }
297: return false;
298: }
299:
300: String resourceName = resourceGroup.getResource();
301: IWorkspace workspace = ResourcesPlugin.getWorkspace();
302:
303: // Do not allow a closed project to be selected
304: IPath fullPath = resourceGroup.getContainerFullPath();
305: if (fullPath != null) {
306: String projectName = fullPath.segment(0);
307: IStatus isValidProjectName = workspace.validateName(
308: projectName, IResource.PROJECT);
309: if (isValidProjectName.isOK()) {
310: IProject project = workspace.getRoot().getProject(
311: projectName);
312: if (!project.isOpen()) {
313: setErrorMessage(IDEWorkbenchMessages.SaveAsDialog_closedProjectMessage);
314: return false;
315: }
316: }
317: }
318:
319: IStatus result = workspace.validateName(resourceName,
320: IResource.FILE);
321: if (!result.isOK()) {
322: setErrorMessage(result.getMessage());
323: return false;
324: }
325:
326: setErrorMessage(null);
327: return true;
328: }
329:
330: /* (non-Javadoc)
331: * @see org.eclipse.jface.window.Dialog#getDialogBoundsSettings()
332: *
333: * @since 3.2
334: */
335: protected IDialogSettings getDialogBoundsSettings() {
336: IDialogSettings settings = IDEWorkbenchPlugin.getDefault()
337: .getDialogSettings();
338: IDialogSettings section = settings
339: .getSection(DIALOG_SETTINGS_SECTION);
340: if (section == null) {
341: section = settings.addNewSection(DIALOG_SETTINGS_SECTION);
342: }
343: return section;
344: }
345:
346: /*
347: * (non-Javadoc)
348: * @see org.eclipse.jface.dialogs.Dialog#isResizable()
349: */
350: protected boolean isResizable() {
351: return true;
352: }
353: }
|