001: /*******************************************************************************
002: * Copyright (c) 2005, 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: * Neil Rickards <neil.rickards@arm.com> - fix for Bug 161026
011: * [Wizards] ProjectContentsLocationArea uses wrong file separator
012: *******************************************************************************/package org.eclipse.ui.internal.ide.dialogs;
013:
014: import java.net.URI;
015: import java.net.URISyntaxException;
016:
017: import org.eclipse.core.filesystem.IFileInfo;
018: import org.eclipse.core.filesystem.URIUtil;
019: import org.eclipse.core.resources.IProject;
020: import org.eclipse.core.resources.ResourcesPlugin;
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.core.runtime.IStatus;
023: import org.eclipse.core.runtime.Platform;
024: import org.eclipse.osgi.util.TextProcessor;
025: import org.eclipse.swt.SWT;
026: import org.eclipse.swt.events.ModifyEvent;
027: import org.eclipse.swt.events.ModifyListener;
028: import org.eclipse.swt.events.SelectionAdapter;
029: import org.eclipse.swt.events.SelectionEvent;
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.DirectoryDialog;
035: import org.eclipse.swt.widgets.Label;
036: import org.eclipse.swt.widgets.Text;
037: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
038: import org.eclipse.ui.internal.ide.filesystem.FileSystemConfiguration;
039: import org.eclipse.ui.internal.ide.filesystem.FileSystemSupportRegistry;
040:
041: /**
042: * ProjectContentsLocationArea is a convenience class for area that handle entry
043: * of locations using URIs.
044: *
045: * @since 3.2
046: *
047: */
048: public class ProjectContentsLocationArea {
049: /**
050: * IErrorMessageReporter is an interface for type that allow message
051: * reporting.
052: *
053: */
054: public interface IErrorMessageReporter {
055: /**
056: * Report the error message
057: *
058: * @param errorMessage
059: * String or <code>null</code>. If the errorMessage is
060: * null then clear any error state.
061: */
062: public void reportError(String errorMessage);
063: }
064:
065: private static String BROWSE_LABEL = IDEWorkbenchMessages.ProjectLocationSelectionDialog_browseLabel;
066:
067: private static final int SIZING_TEXT_FIELD_WIDTH = 250;
068:
069: private static final String FILE_SCHEME = "file"; //$NON-NLS-1$
070:
071: private Label locationLabel;
072:
073: private Text locationPathField;
074:
075: private Button browseButton;
076:
077: private IErrorMessageReporter errorReporter;
078:
079: private String projectName = IDEResourceInfoUtils.EMPTY_STRING;
080:
081: private String userPath = IDEResourceInfoUtils.EMPTY_STRING;
082:
083: private Button useDefaultsButton;
084:
085: private IProject existingProject;
086:
087: private FileSystemSelectionArea fileSystemSelectionArea;
088:
089: /**
090: * Create a new instance of the receiver.
091: *
092: * @param reporter
093: * @param composite
094: * @param startProject
095: */
096: public ProjectContentsLocationArea(IErrorMessageReporter reporter,
097: Composite composite, IProject startProject) {
098:
099: errorReporter = reporter;
100: projectName = startProject.getName();
101: existingProject = startProject;
102:
103: boolean defaultEnabled = true;
104: try {
105: defaultEnabled = startProject.getDescription()
106: .getLocationURI() == null;
107: } catch (CoreException e1) {
108: // If we get a CoreException assume the default.
109: }
110: createContents(composite, defaultEnabled);
111: }
112:
113: public void setExistingProject(IProject existingProject) {
114: projectName = existingProject.getName();
115: this .existingProject = existingProject;
116: }
117:
118: /**
119: * Create a new instance of a ProjectContentsLocationArea.
120: *
121: * @param reporter
122: * @param composite
123: */
124: public ProjectContentsLocationArea(IErrorMessageReporter reporter,
125: Composite composite) {
126: errorReporter = reporter;
127:
128: // If it is a new project always start enabled
129: createContents(composite, true);
130: }
131:
132: /**
133: * Create the contents of the receiver.
134: *
135: * @param composite
136: * @param defaultEnabled
137: */
138: private void createContents(Composite composite,
139: boolean defaultEnabled) {
140:
141: int columns = 4;
142:
143: // project specification group
144: Composite projectGroup = new Composite(composite, SWT.NONE);
145: GridLayout layout = new GridLayout();
146: layout.numColumns = columns;
147: projectGroup.setLayout(layout);
148: projectGroup.setLayoutData(new GridData(
149: GridData.FILL_HORIZONTAL));
150:
151: useDefaultsButton = new Button(projectGroup, SWT.CHECK
152: | SWT.RIGHT);
153: useDefaultsButton
154: .setText(IDEWorkbenchMessages.ProjectLocationSelectionDialog_useDefaultLabel);
155: useDefaultsButton.setSelection(defaultEnabled);
156: GridData buttonData = new GridData();
157: buttonData.horizontalSpan = columns;
158: useDefaultsButton.setLayoutData(buttonData);
159:
160: createUserEntryArea(projectGroup, defaultEnabled);
161:
162: useDefaultsButton.addSelectionListener(new SelectionAdapter() {
163: public void widgetSelected(SelectionEvent e) {
164: boolean useDefaults = useDefaultsButton.getSelection();
165:
166: if (useDefaults) {
167: userPath = locationPathField.getText();
168: locationPathField.setText(TextProcessor
169: .process(getDefaultPathDisplayString()));
170: } else {
171: locationPathField.setText(TextProcessor
172: .process(userPath));
173: }
174: setUserAreaEnabled(!useDefaults);
175: }
176: });
177: setUserAreaEnabled(!defaultEnabled);
178: }
179:
180: /**
181: * Return whether or not we are currently showing the default location for
182: * the project.
183: *
184: * @return boolean
185: */
186: public boolean isDefault() {
187: return useDefaultsButton.getSelection();
188: }
189:
190: /**
191: * Create the area for user entry.
192: *
193: * @param composite
194: * @param defaultEnabled
195: */
196: private void createUserEntryArea(Composite composite,
197: boolean defaultEnabled) {
198: // location label
199: locationLabel = new Label(composite, SWT.NONE);
200: locationLabel
201: .setText(IDEWorkbenchMessages.ProjectLocationSelectionDialog_locationLabel);
202:
203: // project location entry field
204: locationPathField = new Text(composite, SWT.BORDER);
205: GridData data = new GridData(GridData.FILL_HORIZONTAL);
206: data.widthHint = SIZING_TEXT_FIELD_WIDTH;
207: data.horizontalSpan = 2;
208: locationPathField.setLayoutData(data);
209:
210: // browse button
211: browseButton = new Button(composite, SWT.PUSH);
212: browseButton.setText(BROWSE_LABEL);
213: browseButton.addSelectionListener(new SelectionAdapter() {
214: public void widgetSelected(SelectionEvent event) {
215: handleLocationBrowseButtonPressed();
216: }
217: });
218:
219: createFileSystemSelection(composite);
220:
221: if (defaultEnabled) {
222: locationPathField.setText(TextProcessor
223: .process(getDefaultPathDisplayString()));
224: } else {
225: if (existingProject == null) {
226: locationPathField
227: .setText(IDEResourceInfoUtils.EMPTY_STRING);
228: } else {
229: locationPathField.setText(TextProcessor
230: .process(existingProject.getLocation()
231: .toOSString()));
232: }
233: }
234:
235: locationPathField.addModifyListener(new ModifyListener() {
236: /*
237: * (non-Javadoc)
238: *
239: * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
240: */
241: public void modifyText(ModifyEvent e) {
242: errorReporter.reportError(checkValidLocation());
243: }
244: });
245: }
246:
247: /**
248: * Create the file system selection area.
249: *
250: * @param composite
251: */
252: private void createFileSystemSelection(Composite composite) {
253:
254: // Always use the default if that is all there is.
255: if (FileSystemSupportRegistry.getInstance().hasOneFileSystem()) {
256: return;
257: }
258:
259: new Label(composite, SWT.NONE);
260:
261: fileSystemSelectionArea = new FileSystemSelectionArea();
262: fileSystemSelectionArea.createContents(composite);
263: }
264:
265: /**
266: * Return the path we are going to display. If it is a file URI then remove
267: * the file prefix.
268: *
269: * @return String
270: */
271: private String getDefaultPathDisplayString() {
272:
273: URI defaultURI = null;
274: if (existingProject != null) {
275: defaultURI = existingProject.getLocationURI();
276: }
277:
278: // Handle files specially. Assume a file if there is no project to query
279: if (defaultURI == null
280: || defaultURI.getScheme().equals(FILE_SCHEME)) {
281: return Platform.getLocation().append(projectName)
282: .toOSString();
283: }
284: return defaultURI.toString();
285:
286: }
287:
288: /**
289: * Set the enablement state of the receiver.
290: *
291: * @param enabled
292: */
293: private void setUserAreaEnabled(boolean enabled) {
294:
295: locationLabel.setEnabled(enabled);
296: locationPathField.setEnabled(enabled);
297: browseButton.setEnabled(enabled);
298: if (fileSystemSelectionArea != null) {
299: fileSystemSelectionArea.setEnabled(enabled);
300: }
301: }
302:
303: /**
304: * Return the browse button. Usually referenced in order to set the layout
305: * data for a dialog.
306: *
307: * @return Button
308: */
309: public Button getBrowseButton() {
310: return browseButton;
311: }
312:
313: /**
314: * Open an appropriate directory browser
315: */
316: private void handleLocationBrowseButtonPressed() {
317:
318: String selectedDirectory = null;
319: String dirName = getPathFromLocationField();
320:
321: if (!dirName.equals(IDEResourceInfoUtils.EMPTY_STRING)) {
322: IFileInfo info;
323: info = IDEResourceInfoUtils.getFileInfo(dirName);
324:
325: if (info == null || !(info.exists()))
326: dirName = IDEResourceInfoUtils.EMPTY_STRING;
327: }
328:
329: FileSystemConfiguration config = getSelectedConfiguration();
330: if (config == null
331: || config.equals(FileSystemSupportRegistry
332: .getInstance().getDefaultConfiguration())) {
333: DirectoryDialog dialog = new DirectoryDialog(
334: locationPathField.getShell());
335: dialog
336: .setMessage(IDEWorkbenchMessages.ProjectLocationSelectionDialog_directoryLabel);
337:
338: dialog.setFilterPath(dirName);
339:
340: selectedDirectory = dialog.open();
341:
342: } else {
343: URI uri = getSelectedConfiguration().getContributor()
344: .browseFileSystem(dirName, browseButton.getShell());
345: if (uri != null)
346: selectedDirectory = uri.toString();
347: }
348:
349: if (selectedDirectory != null)
350: updateLocationField(selectedDirectory);
351: }
352:
353: /**
354: * Update the location field based on the selected path.
355: *
356: * @param selectedPath
357: */
358: private void updateLocationField(String selectedPath) {
359: locationPathField.setText(TextProcessor.process(selectedPath));
360: }
361:
362: /**
363: * Return the path on the location field.
364: *
365: * @return String
366: */
367: private String getPathFromLocationField() {
368: URI fieldURI;
369: try {
370: fieldURI = new URI(locationPathField.getText());
371: } catch (URISyntaxException e) {
372: return locationPathField.getText();
373: }
374: return fieldURI.getPath();
375: }
376:
377: /**
378: * Check if the entry in the widget location is valid. If it is valid return
379: * null. Otherwise return a string that indicates the problem.
380: *
381: * @return String
382: */
383: public String checkValidLocation() {
384:
385: String locationFieldContents = locationPathField.getText();
386: if (locationFieldContents.length() == 0) {
387: return IDEWorkbenchMessages.WizardNewProjectCreationPage_projectLocationEmpty;
388: }
389:
390: URI newPath = getProjectLocationURI();
391: if (newPath == null) {
392: return IDEWorkbenchMessages.ProjectLocationSelectionDialog_locationError;
393: }
394:
395: if (existingProject == null && isDefault()) {
396: return IDEWorkbenchMessages.WizardNewProjectCreationPage_projectNameEmpty;
397: }
398:
399: IStatus locationStatus = ResourcesPlugin.getWorkspace()
400: .validateProjectLocationURI(existingProject,
401: isDefault() ? null : newPath);
402:
403: if (!locationStatus.isOK()) {
404: return locationStatus.getMessage();
405: }
406:
407: if (existingProject != null) {
408: URI projectPath = existingProject.getLocationURI();
409: if (projectPath != null
410: && URIUtil.equals(projectPath, newPath)) {
411: return IDEWorkbenchMessages.ProjectLocationSelectionDialog_locationError;
412: }
413: }
414:
415: return null;
416: }
417:
418: /**
419: * Get the URI for the location field if possible.
420: *
421: * @return URI or <code>null</code> if it is not valid.
422: */
423: public URI getProjectLocationURI() {
424:
425: FileSystemConfiguration configuration = getSelectedConfiguration();
426: if (configuration == null) {
427: return null;
428: }
429:
430: return configuration.getContributor().getURI(
431: locationPathField.getText());
432:
433: }
434:
435: /**
436: * Return the selected contributor
437: *
438: * @return FileSystemConfiguration or <code>null</code> if it cannot be
439: * determined.
440: */
441: private FileSystemConfiguration getSelectedConfiguration() {
442: if (fileSystemSelectionArea == null) {
443: return FileSystemSupportRegistry.getInstance()
444: .getDefaultConfiguration();
445: }
446:
447: return fileSystemSelectionArea.getSelectedConfiguration();
448: }
449:
450: /**
451: * Set the text to the default or clear it if not using the defaults.
452: *
453: * @param useDefaults
454: * @param newName
455: * the name of the project to use. If <code>null</code> use the
456: * existing project name.
457: */
458: public void updateProjectName(String newName) {
459: projectName = newName;
460: if (isDefault()) {
461: locationPathField.setText(TextProcessor
462: .process(getDefaultPathDisplayString()));
463: }
464:
465: }
466:
467: /**
468: * Return the location for the project. If we are using defaults then return
469: * the workspace root so that core creates it with default values.
470: *
471: * @return String
472: */
473: public String getProjectLocation() {
474: if (isDefault()) {
475: return Platform.getLocation().toOSString();
476: }
477: return locationPathField.getText();
478: }
479: }
|