11.1. DialogsWhenever information is requested from or presented to the user in a modeless fashion, it allows the user to freely interact with all the resources in the workbench. Windows, pages, editors, and views are all examples of modeless UI constructs that do not restrict the order in which the user interacts with them. Dialogs are typically modal, restricting the user to either entering the information requested or canceling the operation. The only time a modal UI construct should be used is when programming restrictions require a gathering or dissemination of information before any other processing can continue and, even then, for as short a time as possible. In one case, the program could present two different versions of a file using a dialog. Unfortunately, this approach prevents the user from switching back and forth between the comparison and some other UI construct such as another editor or view. A better approach would be to present that same information in a comparison editor. Creating a new project represents a different situation. In that case, the operation must gather all the necessary information sequentially before the operation can be performed. The user has requested the operation and typically does not need to interact with another aspect of the program until all the information is gathered and the operation is complete. In this case, a dialog or wizard is warranted. 11.1.1. SWT dialogs versus JFace dialogsThere are two distinct dialog hierarchies in Eclipse that should not be confused. SWT dialogs (org.eclipse.swt.Dialog) are Java representations of built-in platform dialogs such as a file dialog or font dialog; as such, they are not portable or extendable. JFace dialogs (org.eclipse.jface.dialogs. Dialog) are platform-independent dialogs on which wizards are built. SWT dialogs are only briefly discussed, while JFace dialogs are covered in detail. 11.1.2. Common SWT dialogsEclipse includes several SWT dialog classes that provide platform-independent interfaces to underlying platform-specific dialogs:
Valid button styles include: SWT.OK SWT.OK | SWT.CANCEL SWT.YES | SWT.NO SWT.YES | SWT.NO | SWT.CANCEL SWT.RETRY | SWT.CANCEL SWT.ABORT | SWT.RETRY | SWT.IGNORE
With any of these SWT dialogs, one of the following modal styles can be specified:
11.1.3. Common JFace dialogsThere are many JFace dialogs that can be either instantiated directly or reused via subclassing. Abstract dialogs
File dialogs
Information dialogs
Resource dialogs
Selection dialogs
Miscellaneous dialogs
11.1.4. Creating a JFace dialogThe default implementation of the Dialog class creates a dialog containing a content area for dialog-specific controls and a button bar below containing OK and Cancel buttons (see Figure 11-1). Figure 11-1. Default dialog structure.
Typically, new dialogs are created by subclassing org.eclipse.jface.dialogs.Dialog and overriding a handful of methods to customize the dialog for a particular purpose.
Dialog also provides some related utility methods:
11.1.5. Dialog unitsIf you are positioning controls in the dialog area based on absolute positioning (null layout) rather than using a layout manager, such as GridLayout or FormLayout, then problems may arise when a different font is used. If the dialog is sized for a font with one pixel size and the user has his or her system set for a font in a different pixel size, then the controls will be either too big or too small for the font used. To alleviate this problem, you should position and size the controls based on the font's average character size or based on dialog units (see Figure 11-2). Figure 11-2. Dialog units superimposed over the letter "T."
Dialog units are based on the current font and are independent of the display device; thus, they can be used to position controls within a dialog, independent of the font being used. They are defined as one-quarter of the average width of a character and one-eighth of the average height of a character. dialog unit X = average character width / 4 dialog unit Y = average character height / 8 Therefore, use the following to convert from dialog units to pixels. pixelX = (dialog unit X * average character width) / 4 pixelY = (dialog unit Y * average character height) / 8 The Eclipse dialog framework provides several convenient methods for converting dialog units or character sizes into pixel sizes.
11.1.6. Initial dialog location and sizeThe default behavior for dialogs as implemented by the dialog framework is to initially position a dialog on top of its parent window specified in the dialog's constructor. To provide a different initial location or size for a dialog, you would override the following methods as necessary.
11.1.7. Resizable dialogsBy default, subclasses of Dialog are not resizable, but there are examples of resizable dialogs within the Eclipse framework such as: org.eclipse.jdt.internal.ui.compare.ResizableDialog. Unfortunately, this dialog is within an internal package, thus, should not be reused outside of its defining plug-in (see Section 20.2, Accessing Internal Code, on page 711). The first step to making your wizard resizable is to include the SWT.RESIZE and SWT.MAX styles when the dialog is created to allow the user to resize the dialog and display the maximize window button, as follows: public ResizableDialog(Shell parentShell) { super(parentShell); } public ResizableDialog(IShellProvider parentShell) { super(parentShell); setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX); } Next, to preserve the size and location of the dialog across invocations, subclasses of this new class must supply a location in which to store values. For more about IDialogSettings see Section 11.2.7, Dialog settings, on page 441. protected abstract IDialogSettings getDialogSettings(); Methods for loading the bounds from the dialog settings and saving the bounds into the dialog settings are neeed, as follows: private static final String TAG_X = "x"; private static final String TAG_Y = "y"; private static final String TAG_WIDTH = "width"; private static final String TAG_HEIGHT = "height"; private Rectangle loadBounds() { IDialogSettings settings = getDialogSettings(); try { return new Rectangle( settings.getInt(TAG_X), settings.getInt(TAG_Y), settings.getInt(TAG_WIDTH), settings.getInt(TAG_HEIGHT)); } catch (NumberFormatException e) { return null; } } private void saveBounds(Rectangle bounds) { IDialogSettings settings = getDialogSettings(); settings.put(TAG_X, bounds.x); settings.put(TAG_Y, bounds.y); settings.put(TAG_WIDTH, bounds.width); settings.put(TAG_HEIGHT, bounds.height); } You need to override the getInitialLocation() and getInitialSize() methods so that, when the dialog is first opened, its prior location and size are restored. protected Rectangle cachedBounds; protected Point getInitialSize() { // Track the current dialog bounds. getShell().addControlListener(new ControlListener() { public void controlMoved(ControlEvent arg0) { cachedBounds = getShell().getBounds(); } public void controlResized(ControlEvent arg0) { cachedBounds = getShell().getBounds(); } }); // Answer the size from the previous incarnation. Rectangle b1 = getShell().getDisplay().getBounds(); Rectangle b2 = loadBounds(); if (b2 != null) return new Point( b1.width < b2.width ? b1.width : b2.width, b1.height < b1.height ? b2.height : b2.height); return super.getInitialSize(); } protected Point getInitialLocation(Point initialSize) { // Answer the location from the previous incarnation. Rectangle displayBounds = getShell().getDisplay().getBounds(); Rectangle bounds = loadBounds(); if (bounds != null) { int x = bounds.x; int y = bounds.y; int maxX = displayBounds.x + displayBounds.width - initialSize.x; int maxY = displayBounds.y + displayBounds.height - initialSize.y; if (x > maxX) x = maxX; if (y > maxY) y = maxY; if (x < displayBounds.x) x = displayBounds.x; if (y < displayBounds.y) y = displayBounds.y; return new Point(x, y); } return super.getInitialLocation(initialSize); } Finally, override the close method to save the dialog bounds for future incarnations: public boolean close() { boolean closed = super.close(); if (closed && cachedBounds != null) saveBounds(cachedBounds); return closed; } 11.1.8. Favorites view filter dialogAs an example, create a specialized filter dialog for the Favorites view that presents the user the option of filtering content based on name, type, or location (see Section 7.2.7, Viewer filters, on page 281 and Section 7.3.4, Pull-down menu, on page 287). The dialog restricts itself to presenting and gathering information from the user and providing accessor methods for the filter action. Start by creating a new FavoritesFilterDialog class: package com.qualityeclipse.favorites.dialogs; import ... public class FavoritesFilterDialog extends Dialog { private String namePattern; private String locationPattern; private Collection selectedTypes; public FavoritesFilterDialog( Shell parentShell, String namePattern, String locationPattern, FavoriteItemType[] selectedTypes ) { super(parentShell); this.namePattern = namePattern; this.locationPattern = locationPattern; this.selectedTypes = new HashSet(); for (int i = 0; i < selectedTypes.length; i++) this.selectedTypes.add(selectedTypes[i]); } Next, override the createDialogArea() method to create the various fields that appear in the upper area of dialog. private Text namePatternField; private Text locationPatternField; protected Control createDialogArea(Composite parent) { Composite container = (Composite) super.createDialogArea(parent); final GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 2; container.setLayout(gridLayout); final Label filterLabel = new Label(container, SWT.NONE); filterLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false, 2, 1)); filterLabel.setText("Enter a filter (* = any number of " + "characters, ? = any single character)" + "\nor an empty string for no filtering:"); final Label nameLabel = new Label(container, SWT.NONE); nameLabel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false)); nameLabel.setText("Name:"); namePatternField = new Text(container, SWT.BORDER); namePatternField.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false)); final Label locationLabel = new Label(container, SWT.NONE); final GridData gridData = new GridData(GridData.END, GridData.CENTER, false, false); gridData.horizontalIndent = 20; locationLabel.setLayoutData(gridData); locationLabel.setText("Location:"); locationPatternField = new Text(container, SWT.BORDER); locationPatternField.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false)); final Label typesLabel = new Label(container, SWT.NONE); typesLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false, 2, 1)); typesLabel.setText("Select the types of favorites to be shown:"); final Composite typeCheckboxComposite = new Composite(container, SWT.NONE); final GridData gridData_1 = new GridData(GridData.FILL, GridData.FILL, false, false, 2, 1); gridData_1.horizontalIndent = 20; typeCheckboxComposite.setLayoutData(gridData_1); final GridLayout typeCheckboxLayout = new GridLayout(); typeCheckboxLayout.numColumns = 2; typeCheckboxComposite.setLayout(typeCheckboxLayout); return container; } Next create a new createTypeCheckboxes() method, called at the end of the createDialogArea() method, to create one checkbox for each type. private Map typeFields; protected Control createDialogArea(Composite parent) { ... existing code ... createTypeCheckboxes(typeCheckboxComposite); return container; } private void createTypeCheckboxes(Composite parent) { typeFields = new HashMap(); FavoriteItemType[] allTypes = FavoriteItemType.getTypes(); for (int i = 0; i < allTypes.length; i++) { final FavoriteItemType eachType = allTypes[i]; if (eachType == FavoriteItemType.UNKNOWN) continue; final Button button = new Button(parent, SWT.CHECK); button.setText(eachType.getName()); typeFields.put(eachType, button); button.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (button.getSelection()) selectedTypes.add(eachType); else selectedTypes.remove(eachType); } }); } } Add the initContent() method that is called at the end of the createDialogArea() method to initialize the various fields in the dialog: protected Control createDialogArea(Composite parent) { ... existing code ... createTypeCheckboxes(typeCheckboxComposite); initContent(); return container; } private void initContent() { namePatternField.setText(namePattern != null ? namePattern : ""); namePatternField.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { namePattern = namePatternField.getText(); } }); locationPatternField .setText(locationPattern != null ? locationPattern : ""); locationPatternField.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { locationPattern = locationPatternField.getText(); } }); FavoriteItemType[] allTypes = FavoriteItemType.getTypes(); for (int i = 0; i < allTypes.length; i++) { FavoriteItemType eachType = allTypes[i]; if (eachType == FavoriteItemType.UNKNOWN) continue; Button button = (Button) typeFields.get(eachType); button.setSelection(selectedTypes.contains(eachType)); } } Override the configureShell() method to set the dialog title: protected void configureShell(Shell newShell) { super.configureShell(newShell); newShell.setText("Favorites View Filter Options"); } Finally, add accessor methods for clients to extract the settings specified by the user when the dialog was opened: public String getNamePattern() { return namePattern; } public String getLocationPattern() { return locationPattern; } public FavoriteItemType[] getSelectedTypes() { return (FavoriteItemType[]) selectedTypes .toArray(new FavoriteItemType[selectedTypes.size()]); } The filter action (see FavoritesViewFilterAction in Section 7.3.4, Pull-down menu, on page 287) must be modified to fill the dialog with the current filter settings, open the dialog, and process the specified filter settings if the user closes the dialog using the OK button. If the dialog is closed using the Cancel button or any other way besides the OK button, the changes are discarded as per standard dialog operation guidelines. The type and location view filters referenced in the following code are left as an exercise for the reader. public void run() { FavoritesFilterDialog dialog = new FavoritesFilterDialog( shell, nameFilter.getPattern(), typeFilter.getTypes(), locationFilter.getPattern()); if (dialog.open() != InputDialog.OK) return; nameFilter.setPattern(dialog.getNamePattern()); locationFilter.setPattern(dialog.getLocationPattern()); typeFilter.setPattern(dialog.getSelectedTypes()); } Getting the preceding run() method to compile involves adding a new FavoritesViewLocationFilter and FavoritesViewTypeFilter similar to the existing FavoritesViewNameFilter. When these changes are complete, the filter dialog presents the filter settings to the user when the Filter... menu item is selected (see Figure 11-3). Figure 11-3. New Favorites View Filter Options dialog.
11.1.9. Details dialogOne of the RFRS criteria includes identifying the plug-in and plug-in creator when reporting problems to the user. In other words, whenever the application needs to report an error message or exception to the user, the plug-in's unique identifier, version, and creator must be visible in the dialog. The org.eclipse.jface.dialogs.ErrorDialog can display exception information in a details section that is shown or hidden using a Details button, but it does not display the necessary product information as required by RFRS standards. To satisfy this requirement, ExceptionDetailsDialog was created (see Figure 11-4). Figure 11-4. Details dialog with details hidden.
When the Details button is pressed, the dialog resizes itself to show additional information (see Figure 11-5). Figure 11-5. Details dialog with details showing.
The ExceptionDetailsDialog class implements this expanding details behavior. package com.qualityeclipse.favorites.dialogs; import ... public class ExceptionDetailsDialog extends AbstractDetailsDialog { private final Object details; private final Plugin plugin; public ExceptionDetailsDialog(Shell parentShell, String title, Image image, String message, Object details, Plugin plugin) { this(new SameShellProvider(parentShell), title, image, message, details, plugin); } public ExceptionDetailsDialog(IShellProvider parentShell, String title, Image image, String message, Object details, Plugin plugin) { super(parentShell, getTitle(title, details), getImage(image, details), getMessage(message, details)); this.details = details; this.plugin = plugin; } There are several utility methods that build content based on information provided in constructor arguments. The getTitle() method returns the title based on the provided title and details object. public static String getTitle(String title, Object details) { if (title != null) return title; if (details instanceof Throwable) { Throwable e = (Throwable) details; while (e instanceof InvocationTargetException) e = ((InvocationTargetException) e).getTargetException(); String name = e.getClass().getName(); return name.substring(name.lastIndexOf('.') + 1); } return "Exception"; } The getImage() method returns the image based on the provided image and details object. public static Image getImage(Image image, Object details) { if (image != null) return image; Display display = Display.getCurrent(); if (details instanceof IStatus) { switch (((IStatus) details).getSeverity()) { case IStatus.ERROR : return display.getSystemImage(SWT.ICON_ERROR); case IStatus.WARNING : return display.getSystemImage(SWT.ICON_WARNING); case IStatus.INFO : return display.getSystemImage(SWT.ICON_INFORMATION); case IStatus.OK : return null; } } return display.getSystemImage(SWT.ICON_ERROR); } The getMessage() method and helper methods build up a message based on the message and details objects provided. public static String getMessage(String message, Object details) { if (details instanceof Throwable) { Throwable e = (Throwable) details; while (e instanceof InvocationTargetException) e = ((InvocationTargetException) e).getTargetException(); if (message == null) return e.toString(); return MessageFormat.format( message, new Object[] { e.toString() }); } if (details instanceof IStatus) { String statusMessage = ((IStatus) details).getMessage(); if (message == null) return statusMessage; return MessageFormat.format( message, new Object[] { statusMessage }); } if (message != null) return message; return "An Exception occurred."; } public static void appendException(PrintWriter writer, Throwable ex) { if (ex instanceof CoreException) { appendStatus(writer, ((CoreException) ex).getStatus(), 0); writer.println(); } appendStackTrace(writer, ex); if (ex instanceof InvocationTargetException) appendException(writer, ((InvocationTargetException) ex) .getTargetException()); } public static void appendStatus( PrintWriter writer, IStatus status, int nesting ) { for (int i = 0; i < nesting; i++) writer.print(" "); writer.println(status.getMessage()); IStatus[] children = status.getChildren(); for (int i = 0; i < children.length; i++) appendStatus(writer, children[i], nesting + 1); } public static void appendStackTrace( PrintWriter writer, Throwable ex ) { ex.printStackTrace(writer); } When the Details button is clicked, the superclass determines whether the details area needs to be shown or hidden and, as necessary, calls the createDetailsArea() method to create the content for the details area. protected Control createDetailsArea(Composite parent) { // Create the details area. Composite panel = new Composite(parent, SWT.NONE); panel.setLayoutData(new GridData(GridData.FILL_BOTH)); GridLayout layout = new GridLayout(); layout.marginHeight = 0; layout.marginWidth = 0; panel.setLayout(layout); // Create the details content. createProductInfoArea(panel); createDetailsViewer(panel); return panel; } protected Composite createProductInfoArea(Composite parent) { // If no plugin specified, then nothing to display here. if (plugin == null) return null; Composite composite = new Composite(parent, SWT.NULL); composite.setLayoutData(new GridData()); GridLayout layout = new GridLayout(); layout.numColumns = 2; layout.marginWidth = convertHorizontalDLUsToPixels( IDialogConstants.HORIZONTAL_MARGIN); composite.setLayout(layout); Dictionary bundleHeaders = plugin.getBundle().getHeaders(); String pluginId = plugin.getBundle().getSymbolicName(); String pluginVendor = (String) bundleHeaders.get("Bundle-Vendor"); String pluginName = (String) bundleHeaders.get("Bundle-Name"); String pluginVersion = (String) bundleHeaders.get("Bundle-Version"); new Label(composite, SWT.NONE).setText("Provider:"); new Label(composite, SWT.NONE).setText(pluginVendor); new Label(composite, SWT.NONE).setText("Plug-in Name:"); new Label(composite, SWT.NONE).setText(pluginName); new Label(composite, SWT.NONE).setText("Plug-in ID:"); new Label(composite, SWT.NONE).setText(pluginId); new Label(composite, SWT.NONE).setText("Version:"); new Label(composite, SWT.NONE).setText(pluginVersion); return composite; } protected Control createDetailsViewer(Composite parent) { if (details == null) return null; Text text = new Text(parent, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); text.setLayoutData(new GridData(GridData.FILL_BOTH)); // Create the content. StringWriter writer = new StringWriter(1000); if (details instanceof Throwable) appendException(new PrintWriter(writer), (Throwable) details); else if (details instanceof IStatus) appendStatus(new PrintWriter(writer), (IStatus) details, 0); text.setText(writer.toString()); return text; } The ExceptionDetailsDialog class is built on top of the more generic AbstractDetailsDialog class. This abstract dialog has a details section that can be shown or hidden by the user but subclasses are responsible for providing the content of the details section. package com.qualityeclipse.favorites.dialogs; import ... public abstract class AbstractDetailsDialog extends Dialog { private final String title; private final String message; private final Image image; public AbstractDetailsDialog(Shell parentShell, String title, Image image, String message) { this(new SameShellProvider(parentShell),title,image,message); } public AbstractDetailsDialog(IShellProvider parentShell, String title, Image image, String message) { super(parentShell); this.title = title; this.image = image; this.message = message; setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL); } The configureShell() method is responsible for setting the title: protected void configureShell(Shell shell) { super.configureShell(shell); if (title != null) shell.setText(title); } The createDialogArea() method creates and returns the contents of the upper part of this dialog (above the button bar). This includes an image, if specified, and a message. protected Control createDialogArea(Composite parent) { Composite composite = (Composite) super.createDialogArea(parent); composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); if (image != null) { ((GridLayout) composite.getLayout()).numColumns = 2; Label label = new Label(composite, 0); image.setBackground(label.getBackground()); label.setImage(image); label.setLayoutData(new GridData( GridData.HORIZONTAL_ALIGN_CENTER | GridData.VERTICAL_ALIGN_BEGINNING)); } Label label = new Label(composite, SWT.WRAP); if (message != null) label.setText(message); GridData data = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER); data.widthHint = convertHorizontalDLUsToPixels( IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); label.setLayoutData(data); label.setFont(parent.getFont()); return composite; } Override the createButtonsForButtonBar() method to create OK and Details buttons. private Button detailsButton; protected void createButtonsForButtonBar(Composite parent) { createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, false); detailsButton = createButton(parent, IDialogConstants.DETAILS_ID, IDialogConstants.SHOW_DETAILS_LABEL, false); } The buttonPressed() method is called when either the OK or Details buttons is pressed. Override this method to alternately show or hide the details area if the Details button is pressed. private Control detailsArea; private Point cachedWindowSize; protected void buttonPressed(int id) { if (id == IDialogConstants.DETAILS_ID) toggleDetailsArea(); else super.buttonPressed(id); } protected void toggleDetailsArea() { Point oldWindowSize = getShell().getSize(); Point newWindowSize = cachedWindowSize; cachedWindowSize = oldWindowSize; // Show the details area. if (detailsArea == null) { detailsArea = createDetailsArea((Composite) getContents()); detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL); } // Hide the details area. else { detailsArea.dispose(); detailsArea = null; detailsButton.setText(IDialogConstants.SHOW_DETAILS_LABEL); } /* * Must be sure to call * getContents().computeSize(SWT.DEFAULT, SWT.DEFAULT) * before calling * getShell().setSize(newWindowSize) * since controls have been added or removed. */ // Compute the new window size. Point oldSize = getContents().getSize(); Point newSize = getContents().computeSize( SWT.DEFAULT, SWT.DEFAULT); if (newWindowSize == null) newWindowSize = new Point(oldWindowSize.x, oldWindowSize.y + (newSize.y - oldSize.y)); // Crop new window size to screen. Point windowLoc = getShell().getLocation(); Rectangle screenArea = getContents().getDisplay().getClientArea(); if (newWindowSize.y > screenArea.height - (windowLoc.y - screenArea.y)) newWindowSize.y = screenArea.height - (windowLoc.y - screenArea.y); getShell().setSize(newWindowSize); ((Composite) getContents()).layout(); } Finally, subclasses must implement createDetailsArea() to provide content for the area of the dialog made visible when the Details button is clicked. 11.1.10. Opening a dialogfinding a parent shellWhen constructing a new dialog, you need to know either the parent shell or an object that can provide a parent shell (an object that has a getShell() method or implements the IShellProvider interface). You can specify null for the parent shell, but this will prevent proper association of the dialog with its parent; if the dialog is modal as many dialogs are, then specifying the correct parent shell or shell provider will prevent the user from being able to activate the parent window before closing the dialog. So the question becomes: How do you obtain the parent shell? IWorkbenchWindowActionDelegate (see example code in Section 6.2.6, Creating an action delegate, on page 216)If you have an action delegate, then Eclipse provides the workbench window from which a shell can be obtained. Immediately after the action delegate is instantiated, Eclipse calls the init() method with the workbench window as the argument. Cache this window and pass the window's shell as an argument when constructing your dialog: private IWorkbenchWindow window; public void init(IWorkbenchWindow window) { this.window = window; } public void run(IAction action) { Shell parentShell = window.getShell(); MyDialog dialog = new MyDialog(parentShell, ...); ... etc ... } IObjectActionDelegate (see Section 6.3.3, IObjectActionDelegate, on page 233)If you have an action in a context menu, Eclipse provides the target part from which a shell provider can be obtained. Before the run() method is called, Eclipse calls setActivePart() with the target part. Cache this part and pass the site containing the part as an argument when constructing your dialog. private IWorkbenchPart targetPart; public void setActivePart(IAction action, IWorkbenchPart targetPart) { this.targetPart = targetPart; } public void run(IAction action) { IWorkbenchPartSite site = targetPart.getSite(); MyDialog dialog = new MyDialog(site, ...); ... etc ... } IViewPart or IEditorPart (see Section 7.2, View Part, on page 263 or Section 8.2, Editor Part, on page 330)If you have a view or editor, then, similar to the preceding code, you can obtain a shell provider: IShellProvider shellProvider = viewOrEditor.getSite(); PlatformUIThe platform UI provides the workbench window from which a shell can be obtained. Shell parentShell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); Display (see Section 4.2.5.1, Display, on page 140)If all else fails, you can obtain the shell of the active window from Display. Shell parentShell = Display.getDefault().getActiveShell(); |