/******************************************************************************* * Copyright (c) 2008 Pierre-Antoine Grégoire. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Pierre-Antoine Grégoire - initial API and implementation *******************************************************************************/ package org.org.eclipse.core.utils.platform.dialogs.message; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTError; import org.eclipse.swt.SWTException; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.org.eclipse.core.utils.platform.Messages; /** * A dialog for showing messages to the user. * <p> * This concrete dialog class can be instantiated as is, or further subclassed as required. * </p> */ public abstract class AbstractInformationDialog extends AbstractMessageAndButtonDialog { /** * Size of the text in lines. */ protected static final int TEXT_LINE_COUNT = 15; /** * Labels for buttons in the button bar (localized strings). */ private String[] buttonLabels; /** * The buttons. Parallels <code>buttonLabels</code>. */ private Button[] buttons; /** * Index into <code>buttonLabels</code> of the default button. */ private int defaultButtonIndex; private String detail; protected int detailButtonIndex = -1; private Text text; /** * Dialog title (a localized string). */ private String title; /** * Dialog title image. */ private Image titleImage; /** * Create a message dialog. Note that the dialog will have no visual representation (no widgets) until it is told to open. * <p> * The labels of the buttons to appear in the button bar are supplied in this constructor as an array. The <code>open</code> method will return the index of the label in this array corresponding to the button that was pressed to close the dialog. If the dialog was dismissed without pressing a button (ESC, etc.) then -1 is returned. Note that the <code>open</code> method blocks. * </p> * * @param parentShell * the parent shell * @param dialogTitle * the dialog title, or <code>null</code> if none * @param dialogSubTitle * the dialog subTitle, or <code>null</code> if none * @param dialogTitleImage * the dialog title image, or <code>null</code> if none * @param dialogMessage * the dialog message * @param dialogImageType * one of the following values: * <ul> * <li><code>AbstractInformationDialog.NONE</code> for a dialog with no image</li> * <li><code>AbstractInformationDialog.ERROR</code> for a dialog with an error image</li> * <li><code>AbstractInformationDialog.INFORMATION</code> for a dialog with an information image</li> * <li><code>AbstractInformationDialog.QUESTION </code> for a dialog with a question image</li> * <li><code>AbstractInformationDialog.WARNING</code> for a dialog with a warning image</li> * </ul> * @param dialogButtonLabels * an array of labels for the buttons in the button bar * @param defaultIndex * the index in the button label array of the default button */ public AbstractInformationDialog(Shell parentShell, String dialogTitle, String dialogSubTitle, Image dialogTitleImage, String dialogMessage, String[] dialogButtonLabels, int defaultButtonIndex, int detailButtonIndex) { super(parentShell); this.title = dialogTitle; this.subTitle = dialogSubTitle; this.titleImage = dialogTitleImage; this.message = dialogMessage; this.buttonLabels = dialogButtonLabels; this.defaultButtonIndex = defaultButtonIndex; this.detailButtonIndex = detailButtonIndex; } /* * (non-Javadoc) * * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int) */ protected void buttonPressed(int buttonId) { if (buttonId == detailButtonIndex) { toggleDetailsArea(); } else { setReturnCode(buttonId); close(); } } /* * (non-Javadoc) * * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) */ protected void configureShell(Shell shell) { super.configureShell(shell); if (title != null) shell.setText(title); if (titleImage != null) shell.setImage(titleImage); } /* * @see org.eclipse.jface.dialogs.Dialog#createButton(org.eclipse.swt.widgets.Composite, int, java.lang.String, boolean) */ protected Button createButton(Composite parent, int id, String label, boolean defaultButton) { Button button = super.createButton(parent, id, label, defaultButton,SWT.FLAT); // Be sure to set the focus if the custom area cannot so as not // to lose the defaultButton. if(id==detailButtonIndex&& getDetail()==null){ button.setVisible(false); } if (defaultButton){ button.setFocus(); } return button; } /* * (non-Javadoc) Method declared on Dialog. */ protected void createButtonsForButtonBar(Composite parent) { buttons = new Button[buttonLabels.length]; for (int i = 0; i < buttonLabels.length; i++) { String label = buttonLabels[i]; Button button = createButton(parent, i, label, defaultButtonIndex == i); buttons[i] = button; } } /** * This implementation of the <code>Dialog</code> framework method creates and lays out a composite and calls <code>createMessageArea</code> and <code>createCustomArea</code> to populate it. Subclasses should override <code>createCustomArea</code> to add contents below the message. */ protected Control createDialogArea(Composite parent) { // create message area createMessageArea(parent); return parent; } /** * Create this dialog's drop-down list component. * * @param parent * the parent composite * @return the drop-down list component */ protected void createDropDownText(Composite parent) { int parentWitdh = parent.getSize().x; // create the list text = new Text(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); text.setFont(parent.getFont()); // print the stacktrace in the text field text.setText(getDetail()); GridData data = new GridData(); data.horizontalIndent=0; data.heightHint = text.getLineHeight() * TEXT_LINE_COUNT; data.widthHint = parentWitdh; text.setLayoutData(data); } /** * Gets a button in this dialog's button bar. * * @param index * the index of the button in the dialog's button bar * @return a button in the dialog's button bar */ protected Button getButton(int index) { return buttons[index]; } /** * An accessor for the labels to use on the buttons. * * @return The button labels to used; never <code>null</code>. */ protected String[] getButtonLabels() { return buttonLabels; } /** * An accessor for the index of the default button in the button array. * * @return The default button index. */ protected int getDefaultButtonIndex() { return defaultButtonIndex; } /** * Create this dialog's drop-down list component. * * @param parent * the parent composite * @return the drop-down list component */ protected String getDetail() { return this.detail; } /** * Handle the shell close. Set the return code to <code>SWT.DEFAULT</code> as there has been no explicit close by the user. * * @see org.eclipse.jface.window.Window#handleShellCloseEvent() */ protected void handleShellCloseEvent() { // Sets a return code of SWT.DEFAULT since none of the dialog buttons // were pressed to close the dialog. super.handleShellCloseEvent(); setReturnCode(SWT.DEFAULT); } // Workaround. SWT does not seem to set rigth the default button if // there is not control with focus. Bug: 14668 public int open() { create(); Button b = getButton(defaultButtonIndex); b.setFocus(); b.getShell().setDefaultButton(b); return super.open(); } /** * A mutator for the button labels. * * @param buttonLabels * The button labels to use; must not be <code>null</code>. */ protected void setButtonLabels(String[] buttonLabels) { if (buttonLabels == null) { throw new NullPointerException("The array of button labels cannot be null.");} //$NON-NLS-1$ this.buttonLabels = buttonLabels; } /** * A mutator for the array of buttons in the button bar. * * @param buttons * The buttons in the button bar; must not be <code>null</code>. */ protected void setButtons(Button[] buttons) { if (buttons == null) { throw new NullPointerException("The array of buttons cannot be null.");} //$NON-NLS-1$ this.buttons = buttons; } protected void setDefaultButtonIndex(int defaultButtonIndex) { this.defaultButtonIndex = defaultButtonIndex; } protected void setDetail(Object detail) { String result = Messages.AbstractInformationDialog_error_detailsretrieval; if (detail != null) { if (detail instanceof Throwable) { Throwable throwable= (Throwable) detail; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos); throwable.printStackTrace(ps); if ((throwable instanceof SWTError) && (((SWTError) throwable).throwable != null)) { ps.println("\n*** Stack trace of contained throwable ***"); //$NON-NLS-1$ ((SWTError) throwable).throwable.printStackTrace(ps); } else if ((throwable instanceof SWTException) && (((SWTException) throwable).throwable != null)) { ps.println("\n*** Stack trace of contained throwable ***"); //$NON-NLS-1$ ((SWTException) throwable).throwable.printStackTrace(ps); } ps.flush(); baos.flush(); result = baos.toString(); } catch (IOException e) { result += e.getMessage(); } } else { result = detail.toString(); } } else { result= null; } this.detail = result; } /** * Set the detail button; */ public void setDetailButton(int index) { detailButtonIndex = index; } /** * Toggles the unfolding of the details area. This is triggered by the user pressing the details button. */ private void toggleDetailsArea() { Point windowSize = getShell().getSize(); Point oldSize = getContents().computeSize(SWT.DEFAULT, SWT.DEFAULT); if (text != null) { text.dispose(); text = null; getButton(detailButtonIndex).setText(IDialogConstants.SHOW_DETAILS_LABEL); } else { createDropDownText((Composite) getDialogArea()); text.setSize(oldSize.x - this.convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING), oldSize.y - convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING)); getButton(detailButtonIndex).setText(IDialogConstants.HIDE_DETAILS_LABEL); } Point newSize = getContents().computeSize(SWT.DEFAULT, SWT.DEFAULT); getContents().setSize(new Point(windowSize.x + (newSize.x - oldSize.x), windowSize.y + (newSize.y - oldSize.y))); } }