001: /*******************************************************************************
002: * Copyright (c) 2004, 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: *******************************************************************************/package org.eclipse.ui.internal.ide;
011:
012: import java.io.File;
013:
014: import org.eclipse.core.runtime.IProduct;
015: import org.eclipse.core.runtime.Platform;
016: import org.eclipse.jface.dialogs.Dialog;
017: import org.eclipse.jface.dialogs.IDialogConstants;
018: import org.eclipse.jface.dialogs.IDialogSettings;
019: import org.eclipse.jface.dialogs.TitleAreaDialog;
020: import org.eclipse.jface.util.Geometry;
021: import org.eclipse.jface.window.Window;
022: import org.eclipse.osgi.util.NLS;
023: import org.eclipse.osgi.util.TextProcessor;
024: import org.eclipse.swt.SWT;
025: import org.eclipse.swt.events.ModifyEvent;
026: import org.eclipse.swt.events.ModifyListener;
027: import org.eclipse.swt.events.SelectionAdapter;
028: import org.eclipse.swt.events.SelectionEvent;
029: import org.eclipse.swt.graphics.Point;
030: import org.eclipse.swt.graphics.Rectangle;
031: import org.eclipse.swt.layout.GridData;
032: import org.eclipse.swt.layout.GridLayout;
033: import org.eclipse.swt.widgets.Button;
034: import org.eclipse.swt.widgets.Combo;
035: import org.eclipse.swt.widgets.Composite;
036: import org.eclipse.swt.widgets.Control;
037: import org.eclipse.swt.widgets.DirectoryDialog;
038: import org.eclipse.swt.widgets.Label;
039: import org.eclipse.swt.widgets.Monitor;
040: import org.eclipse.swt.widgets.Shell;
041:
042: /**
043: * A dialog that prompts for a directory to use as a workspace.
044: */
045: public class ChooseWorkspaceDialog extends TitleAreaDialog {
046:
047: private static final String DIALOG_SETTINGS_SECTION = "ChooseWorkspaceDialogSettings"; //$NON-NLS-1$
048:
049: private ChooseWorkspaceData launchData;
050:
051: private Combo text;
052:
053: private boolean suppressAskAgain = false;
054:
055: private boolean centerOnMonitor = false;
056:
057: /**
058: * Create a modal dialog on the arugment shell, using and updating the
059: * argument data object.
060: * @param parentShell the parent shell for this dialog
061: * @param launchData the launch data from past launches
062: *
063: * @param suppressAskAgain
064: * true means the dialog will not have a "don't ask again" button
065: * @param centerOnMonitor indicates whether the dialog should be centered on
066: * the monitor or according to it's parent if there is one
067: */
068: public ChooseWorkspaceDialog(Shell parentShell,
069: ChooseWorkspaceData launchData, boolean suppressAskAgain,
070: boolean centerOnMonitor) {
071: super (parentShell);
072: this .launchData = launchData;
073: this .suppressAskAgain = suppressAskAgain;
074: this .centerOnMonitor = centerOnMonitor;
075: }
076:
077: /**
078: * Show the dialog to the user (if needed). When this method finishes,
079: * #getSelection will return the workspace that should be used (whether it
080: * was just selected by the user or some previous default has been used.
081: * The parameter can be used to override the users preference. For example,
082: * this is important in cases where the default selection is already in use
083: * and the user is forced to choose a different one.
084: *
085: * @param force
086: * true if the dialog should be opened regardless of the value of
087: * the show dialog checkbox
088: */
089: public void prompt(boolean force) {
090: if (force || launchData.getShowDialog()) {
091: open();
092:
093: // 70576: make sure dialog gets dismissed on ESC too
094: if (getReturnCode() == CANCEL) {
095: launchData.workspaceSelected(null);
096: }
097:
098: return;
099: }
100:
101: String[] recent = launchData.getRecentWorkspaces();
102:
103: // If the selection dialog was not used then the workspace to use is either the
104: // most recent selection or the initialDefault (if there is no history).
105: String workspace = null;
106: if (recent != null && recent.length > 0) {
107: workspace = recent[0];
108: }
109: if (workspace == null || workspace.length() == 0) {
110: workspace = launchData.getInitialDefault();
111: }
112: launchData
113: .workspaceSelected(TextProcessor.deprocess(workspace));
114: }
115:
116: /**
117: * Creates and returns the contents of the upper part of this dialog (above
118: * the button bar).
119: * <p>
120: * The <code>Dialog</code> implementation of this framework method creates
121: * and returns a new <code>Composite</code> with no margins and spacing.
122: * </p>
123: *
124: * @param parent the parent composite to contain the dialog area
125: * @return the dialog area control
126: */
127: protected Control createDialogArea(Composite parent) {
128: String productName = null;
129: IProduct product = Platform.getProduct();
130: if (product != null) {
131: productName = product.getName();
132: }
133: if (productName == null) {
134: productName = IDEWorkbenchMessages.ChooseWorkspaceDialog_defaultProductName;
135: }
136:
137: Composite composite = (Composite) super
138: .createDialogArea(parent);
139: setTitle(IDEWorkbenchMessages.ChooseWorkspaceDialog_dialogTitle);
140: setMessage(NLS
141: .bind(
142: IDEWorkbenchMessages.ChooseWorkspaceDialog_dialogMessage,
143: productName));
144:
145: // bug 59934: load title image for sizing, but set it non-visible so the
146: // white background is displayed
147: if (getTitleImageLabel() != null) {
148: getTitleImageLabel().setVisible(false);
149: }
150:
151: createWorkspaceBrowseRow(composite);
152: if (!suppressAskAgain) {
153: createShowDialogButton(composite);
154: }
155: Dialog.applyDialogFont(composite);
156: return composite;
157: }
158:
159: /**
160: * Configures the given shell in preparation for opening this window
161: * in it.
162: * <p>
163: * The default implementation of this framework method
164: * sets the shell's image and gives it a grid layout.
165: * Subclasses may extend or reimplement.
166: * </p>
167: *
168: * @param shell the shell
169: */
170: protected void configureShell(Shell shell) {
171: super .configureShell(shell);
172: shell
173: .setText(IDEWorkbenchMessages.ChooseWorkspaceDialog_dialogName);
174: }
175:
176: /**
177: * Notifies that the ok button of this dialog has been pressed.
178: * <p>
179: * The <code>Dialog</code> implementation of this framework method sets
180: * this dialog's return code to <code>Window.OK</code>
181: * and closes the dialog. Subclasses may override.
182: * </p>
183: */
184: protected void okPressed() {
185: launchData.workspaceSelected(TextProcessor
186: .deprocess(getWorkspaceLocation()));
187: super .okPressed();
188: }
189:
190: /**
191: * Get the workspace location from the widget.
192: * @return String
193: */
194: protected String getWorkspaceLocation() {
195: return text.getText();
196: }
197:
198: /**
199: * Notifies that the cancel button of this dialog has been pressed.
200: * <p>
201: * The <code>Dialog</code> implementation of this framework method sets
202: * this dialog's return code to <code>Window.CANCEL</code>
203: * and closes the dialog. Subclasses may override if desired.
204: * </p>
205: */
206: protected void cancelPressed() {
207: launchData.workspaceSelected(null);
208: super .cancelPressed();
209: }
210:
211: /**
212: * The main area of the dialog is just a row with the current selection
213: * information and a drop-down of the most recently used workspaces.
214: */
215: private void createWorkspaceBrowseRow(Composite parent) {
216: Composite panel = new Composite(parent, SWT.NONE);
217:
218: GridLayout layout = new GridLayout(3, false);
219: layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
220: layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
221: layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
222: layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
223: panel.setLayout(layout);
224: panel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
225: panel.setFont(parent.getFont());
226:
227: Label label = new Label(panel, SWT.NONE);
228: label
229: .setText(IDEWorkbenchMessages.ChooseWorkspaceDialog_workspaceEntryLabel);
230:
231: text = new Combo(panel, SWT.BORDER | SWT.LEAD | SWT.DROP_DOWN);
232: text.setFocus();
233: text.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
234: | GridData.FILL_HORIZONTAL));
235: text.addModifyListener(new ModifyListener() {
236: public void modifyText(ModifyEvent e) {
237: Button okButton = getButton(Window.OK);
238: if (okButton != null && !okButton.isDisposed()) {
239: boolean nonWhitespaceFound = false;
240: String characters = getWorkspaceLocation();
241: for (int i = 0; !nonWhitespaceFound
242: && i < characters.length(); i++) {
243: if (!Character.isWhitespace(characters
244: .charAt(i))) {
245: nonWhitespaceFound = true;
246: }
247: }
248: okButton.setEnabled(nonWhitespaceFound);
249: }
250: }
251: });
252: setInitialTextValues(text);
253:
254: Button browseButton = new Button(panel, SWT.PUSH);
255: browseButton
256: .setText(IDEWorkbenchMessages.ChooseWorkspaceDialog_browseLabel);
257: setButtonLayoutData(browseButton);
258: GridData data = (GridData) browseButton.getLayoutData();
259: data.horizontalAlignment = GridData.HORIZONTAL_ALIGN_END;
260: browseButton.setLayoutData(data);
261: browseButton.addSelectionListener(new SelectionAdapter() {
262: public void widgetSelected(SelectionEvent e) {
263: DirectoryDialog dialog = new DirectoryDialog(getShell());
264: dialog
265: .setText(IDEWorkbenchMessages.ChooseWorkspaceDialog_directoryBrowserTitle);
266: dialog
267: .setMessage(IDEWorkbenchMessages.ChooseWorkspaceDialog_directoryBrowserMessage);
268: dialog.setFilterPath(getInitialBrowsePath());
269: String dir = dialog.open();
270: if (dir != null) {
271: text.setText(TextProcessor.process(dir));
272: }
273: }
274: });
275: }
276:
277: /**
278: * Return a string containing the path that is closest to the current
279: * selection in the text widget. This starts with the current value and
280: * works toward the root until there is a directory for which File.exists
281: * returns true. Return the current working dir if the text box does not
282: * contain a valid path.
283: *
284: * @return closest parent that exists or an empty string
285: */
286: private String getInitialBrowsePath() {
287: File dir = new File(getWorkspaceLocation());
288: while (dir != null && !dir.exists()) {
289: dir = dir.getParentFile();
290: }
291:
292: return dir != null ? dir.getAbsolutePath() : System
293: .getProperty("user.dir"); //$NON-NLS-1$
294: }
295:
296: /*
297: * see org.eclipse.jface.Window.getInitialLocation()
298: */
299: protected Point getInitialLocation(Point initialSize) {
300: Composite parent = getShell().getParent();
301:
302: if (!centerOnMonitor || parent == null) {
303: return super .getInitialLocation(initialSize);
304: }
305:
306: Monitor monitor = parent.getMonitor();
307: Rectangle monitorBounds = monitor.getClientArea();
308: Point centerPoint = Geometry.centerPoint(monitorBounds);
309:
310: return new Point(centerPoint.x - (initialSize.x / 2), Math.max(
311: monitorBounds.y, Math.min(centerPoint.y
312: - (initialSize.y * 2 / 3), monitorBounds.y
313: + monitorBounds.height - initialSize.y)));
314: }
315:
316: /**
317: * The show dialog button allows the user to choose to neven be nagged again.
318: */
319: private void createShowDialogButton(Composite parent) {
320: Composite panel = new Composite(parent, SWT.NONE);
321: panel.setFont(parent.getFont());
322:
323: GridLayout layout = new GridLayout(1, false);
324: layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
325: panel.setLayout(layout);
326:
327: GridData data = new GridData(GridData.FILL_BOTH);
328: data.verticalAlignment = GridData.END;
329: panel.setLayoutData(data);
330:
331: Button button = new Button(panel, SWT.CHECK);
332: button
333: .setText(IDEWorkbenchMessages.ChooseWorkspaceDialog_useDefaultMessage);
334: button.setSelection(!launchData.getShowDialog());
335: button.addSelectionListener(new SelectionAdapter() {
336: public void widgetSelected(SelectionEvent e) {
337: launchData.toggleShowDialog();
338: }
339: });
340: }
341:
342: private void setInitialTextValues(Combo text) {
343: String[] recentWorkspaces = launchData.getRecentWorkspaces();
344: for (int i = 0; i < recentWorkspaces.length; ++i) {
345: if (recentWorkspaces[i] != null) {
346: text.add(recentWorkspaces[i]);
347: }
348: }
349:
350: text.setText(TextProcessor
351: .process((text.getItemCount() > 0 ? text.getItem(0)
352: : launchData.getInitialDefault())));
353: }
354:
355: /* (non-Javadoc)
356: * @see org.eclipse.jface.window.Dialog#getDialogBoundsSettings()
357: *
358: * @since 3.2
359: */
360: protected IDialogSettings getDialogBoundsSettings() {
361: // If we were explicitly instructed to center on the monitor, then
362: // do not provide any settings for retrieving a different location or, worse,
363: // saving the centered location.
364: if (centerOnMonitor) {
365: return null;
366: }
367:
368: IDialogSettings settings = IDEWorkbenchPlugin.getDefault()
369: .getDialogSettings();
370: IDialogSettings section = settings
371: .getSection(DIALOG_SETTINGS_SECTION);
372: if (section == null) {
373: section = settings.addNewSection(DIALOG_SETTINGS_SECTION);
374: }
375: return section;
376: }
377:
378: }
|