| /******************************************************************************* |
| * Copyright (c) 2009, 2016 IBM Corporation and others. |
| * 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: |
| * IBM Corporation - initial API and implementation |
| * Patrik Suzzi <psuzzi@gmail.com> - Bug 473973 |
| * Friederike Schertel <friederike@schertel.org> - Bug 478336 |
| ******************************************************************************/ |
| package org.eclipse.ui.internal.statushandlers; |
| |
| import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter; |
| |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.Map; |
| import org.eclipse.core.runtime.Adapters; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.DialogTray; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.dialogs.MessageDialogWithToggle; |
| import org.eclipse.jface.dialogs.TrayDialog; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.viewers.IContentProvider; |
| import org.eclipse.jface.viewers.IStructuredContentProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.TableViewer; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.MouseListener; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Link; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.internal.Workbench; |
| import org.eclipse.ui.internal.WorkbenchMessages; |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.eclipse.ui.internal.progress.ProgressManagerUtil; |
| import org.eclipse.ui.internal.progress.ProgressMessages; |
| import org.eclipse.ui.progress.IProgressConstants; |
| import org.eclipse.ui.statushandlers.StatusAdapter; |
| import org.eclipse.ui.statushandlers.StatusManager; |
| import org.eclipse.ui.views.IViewDescriptor; |
| |
| |
| /** |
| * Parent window actually does not use its Shell to build dialog on. The |
| * window passes the shell to the InternalDialog, and it can do switching |
| * modality and recreate the window silently. |
| * |
| * @since 3.4 |
| */ |
| public class InternalDialog extends TrayDialog { |
| |
| /** |
| * The id of the goto action button |
| */ |
| static final int GOTO_ACTION_ID = IDialogConstants.CLIENT_ID + 1; |
| |
| static final String LOG_VIEW_ID = "org.eclipse.pde.runtime.LogView"; //$NON-NLS-1$ |
| |
| /** |
| * Preference used to indicate whether the user should be prompted to |
| * confirm the execution of the job's goto action |
| */ |
| static final String PREF_SKIP_GOTO_ACTION_PROMPT = "pref_skip_goto_action_prompt"; //$NON-NLS-1$ |
| |
| /** |
| * This composite holds all components of the dialog. |
| */ |
| private Composite dialogArea; |
| /** |
| * This composite is initially scrolled to the 0 x 0 size. When more |
| * than one status arrives, listArea is resized and a list is created on |
| * it to present statuses to the user. |
| */ |
| private Composite listArea; |
| /** |
| * On this composite are presented additional elements for displaying |
| * single status. Currently it is the second label that displays the |
| * second most important message to the user. |
| */ |
| private Composite singleStatusDisplayArea; |
| /** |
| * This label is used to display the second most important message to |
| * the user. It is placed on singleStatusDisplayArea. |
| */ |
| private Label singleStatusLabel; |
| /** |
| * A list from which the user selects statuses. The list is placed on |
| * listArea. |
| */ |
| private TableViewer statusListViewer; |
| /** |
| * Composite on the left bottom corner. Allows for opening support tray |
| * & Error Log. |
| */ |
| private Composite linkComposite; |
| /** |
| * This item is used to launch support tray |
| */ |
| private Link launchTrayLink; |
| /** |
| * This fields contains indicator if link to ErrorLog view should be |
| * present. |
| */ |
| private Link showErrorLogLink; |
| /** |
| * Main dialog image holder. |
| */ |
| private Label titleImageLabel; |
| /** |
| * Message in the header. |
| */ |
| private Label mainMessageLabel; |
| /** |
| * Header area. |
| */ |
| private Composite titleArea; |
| |
| /** |
| * In this support tray status support providers are displayed. |
| */ |
| private SupportTray supportTray; |
| |
| private DetailsAreaManager detailsManager; |
| |
| private Map dialogState; |
| |
| /** |
| * @param dialogState |
| * @param modal |
| */ |
| public InternalDialog(final Map dialogState, boolean modal) { |
| super(ProgressManagerUtil.getDefaultParent()); |
| this.dialogState = dialogState; |
| supportTray = new SupportTray(dialogState, event -> { |
| dialogState.put(IStatusDialogConstants.TRAY_OPENED, |
| Boolean.FALSE); |
| // close the tray |
| closeTray(); |
| // set focus back to shell |
| getShell().setFocus(); |
| }); |
| detailsManager = new DetailsAreaManager(dialogState); |
| setShellStyle(SWT.RESIZE | SWT.MAX | SWT.MIN | getShellStyle()); |
| setBlockOnOpen(false); |
| |
| if (!modal) { |
| setShellStyle(~SWT.APPLICATION_MODAL & getShellStyle()); |
| } |
| } |
| |
| @Override |
| protected void buttonPressed(int id) { |
| if (id == GOTO_ACTION_ID) { |
| IAction gotoAction = getGotoAction(); |
| if (gotoAction != null) { |
| if (isPromptToClose()) { |
| okPressed(); // close the dialog |
| gotoAction.run(); // run the goto action |
| } |
| } |
| } |
| if (id == IDialogConstants.DETAILS_ID) { |
| // was the details button pressed? |
| dialogState.put(IStatusDialogConstants.DETAILS_OPENED, Boolean.valueOf( |
| toggleDetailsArea())); |
| } else { |
| super.buttonPressed(id); |
| } |
| } |
| |
| @Override |
| final protected void configureShell(Shell shell) { |
| super.configureShell(shell); |
| shell.setText(getString(IStatusDialogConstants.TITLE)); |
| } |
| |
| /** |
| * Status dialog button should be aligned SWT.END. |
| */ |
| @Override |
| protected void setButtonLayoutData(Button button) { |
| GridData data = new GridData(SWT.END, SWT.CENTER, false, false); |
| int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH); |
| Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); |
| data.widthHint = Math.max(widthHint, minSize.x); |
| button.setLayoutData(data); |
| } |
| |
| @Override |
| protected Control createDialogArea(Composite parent) { |
| createTitleArea(parent); |
| createListArea(parent); |
| dialogArea = parent; |
| Dialog.applyDialogFont(dialogArea); |
| return parent; |
| } |
| |
| @Override |
| protected boolean isResizable() { |
| return true; |
| } |
| |
| /** |
| * Creates title area. |
| * |
| * @param parent |
| * A composite on which the title area should be created. |
| */ |
| private void createTitleArea(Composite parent) { |
| titleArea = new Composite(parent, SWT.NONE); |
| titleArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, |
| false)); |
| |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = 2; |
| layout.horizontalSpacing = 10; |
| layout.marginLeft = 10; |
| layout.marginTop = 10; |
| layout.marginBottom = 0; |
| titleArea.setLayout(layout); |
| |
| titleImageLabel = new Label(titleArea, SWT.NONE); |
| titleImageLabel.setImage(getLabelProviderWrapper() |
| .getImage(getCurrentStatusAdapter())); |
| GridData layoutData = new GridData(); |
| layoutData.verticalSpan = 2; |
| layoutData.verticalAlignment = SWT.TOP; |
| titleImageLabel.setLayoutData(layoutData); |
| |
| GridData messageData = new GridData(SWT.FILL, SWT.FILL, true, true); |
| messageData.widthHint = convertWidthInCharsToPixels(50); |
| mainMessageLabel = new Label(titleArea, SWT.WRAP); |
| mainMessageLabel.setLayoutData(messageData); |
| // main message set up early, to address bug 222391 |
| mainMessageLabel.setText(getLabelProviderWrapper() |
| .getMainMessage(getCurrentStatusAdapter())); |
| if (!isMulti()) { |
| singleStatusDisplayArea = createSingleStatusDisplayArea(titleArea); |
| } |
| } |
| |
| /** |
| * Create an area which allows the user to view the status if only one |
| * is created or to select one of reported statuses when there are many. |
| * |
| * @param parent |
| * the parent composite on which all components should be |
| * placed. |
| */ |
| private void createListArea(Composite parent) { |
| listArea = new Composite(parent, SWT.NONE); |
| GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); |
| layoutData.heightHint = 0; |
| layoutData.widthHint = 0; |
| listArea.setLayoutData(layoutData); |
| GridLayout layout = new GridLayout(); |
| listArea.setLayout(layout); |
| if (isMulti()) { |
| fillListArea(listArea); |
| } |
| } |
| |
| /** |
| * This function checks if the dialog is modal. |
| * |
| * @return true if the dialog is modal, false otherwise |
| * |
| */ |
| public boolean isModal() { |
| return ((getShellStyle() & SWT.APPLICATION_MODAL) == SWT.APPLICATION_MODAL); |
| } |
| |
| /** |
| * @return Returns the supportTray. |
| */ |
| public SupportTray getSupportTray() { |
| return supportTray; |
| } |
| |
| /** |
| * @param supportTray |
| * The supportTray to set. |
| */ |
| public void setSupportTray(SupportTray supportTray) { |
| this.supportTray = supportTray; |
| } |
| |
| @Override |
| public int open() { |
| boolean modalitySwitch = getBooleanValue(IStatusDialogConstants.MODALITY_SWITCH); |
| int result = super.open(); |
| if (modalitySwitch) { |
| if (getBooleanValue(IStatusDialogConstants.DETAILS_OPENED)) { |
| showDetailsArea(); |
| } |
| if (getBooleanValue(IStatusDialogConstants.TRAY_OPENED)) { |
| openTray(); |
| } |
| } else { |
| if (getBooleanValue(IStatusDialogConstants.ANIMATION)) { |
| Rectangle shellPosition = getShell().getBounds(); |
| ProgressManagerUtil.animateUp(shellPosition); |
| } |
| } |
| return result; |
| } |
| |
| @Override |
| public void closeTray() throws IllegalStateException { |
| if (getTray() != null) { |
| super.closeTray(); |
| } |
| //preserve state during modality switch |
| if (!getBooleanValue(IStatusDialogConstants.MODALITY_SWITCH)) { |
| dialogState.put(IStatusDialogConstants.TRAY_OPENED, Boolean.FALSE); |
| } |
| if (launchTrayLink != null && !launchTrayLink.isDisposed()) { |
| launchTrayLink.setEnabled(providesSupport() |
| && !getBooleanValue(IStatusDialogConstants.TRAY_OPENED)); |
| } |
| } |
| |
| /** |
| * Method which should be invoked when new errors become available for |
| * display. |
| */ |
| void refresh() { |
| if (dialogArea == null || dialogArea.isDisposed()) { |
| return; |
| } |
| updateTitleArea(); |
| updateListArea(); |
| updateEnablements(); |
| // adjust width if necessary |
| Point currentSize = getShell().getSize(); |
| Point desiredSize = getShell() |
| .computeSize(SWT.DEFAULT, SWT.DEFAULT); |
| if (currentSize.x < desiredSize.x) { |
| getShell().setSize(desiredSize.x, currentSize.y); |
| } else { |
| getShell().layout(); |
| } |
| } |
| |
| void refreshDialogSize() { |
| if (dialogArea == null || dialogArea.isDisposed()) { |
| return; |
| } |
| Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT); |
| getShell().setSize(newSize); |
| } |
| |
| /** |
| * Show the details portion of the dialog if it is not already visible. |
| * This method will only work when it is invoked after the control of |
| * the dialog has been set. In other words, after the |
| * <code>createContents</code> method has been invoked and has returned |
| * the control for the content area of the dialog. Invoking the method |
| * before the content area has been set or after the dialog has been |
| * disposed will have no effect. |
| */ |
| private void showDetailsArea() { |
| if (dialogArea != null && !dialogArea.isDisposed()) { |
| if (detailsManager.isOpen()) { |
| detailsManager.close(); |
| detailsManager.createDetailsArea(dialogArea, |
| getCurrentStatusAdapter()); |
| dialogState.put(IStatusDialogConstants.DETAILS_OPENED, |
| Boolean.TRUE); |
| } else { |
| toggleDetailsArea(); |
| dialogState.put(IStatusDialogConstants.DETAILS_OPENED, |
| Boolean.TRUE); |
| } |
| dialogArea.layout(); |
| } |
| } |
| |
| /** |
| * Toggles the unfolding of the details area. This is triggered by the |
| * user pressing the details button. |
| * |
| */ |
| private boolean toggleDetailsArea() { |
| boolean opened = false; |
| Point windowSize = getShell().getSize(); |
| if (detailsManager.isOpen()) { |
| detailsManager.close(); |
| getButton(IDialogConstants.DETAILS_ID).setText( |
| IDialogConstants.SHOW_DETAILS_LABEL); |
| opened = false; |
| } else { |
| detailsManager.createDetailsArea(dialogArea, |
| getCurrentStatusAdapter()); |
| getButton(IDialogConstants.DETAILS_ID).setText( |
| IDialogConstants.HIDE_DETAILS_LABEL); |
| opened = true; |
| } |
| |
| GridData listAreaGridData = (GridData) listArea.getLayoutData(); |
| // if there is only one status to display, |
| // make sure that the list area is as small as possible |
| if (!isMulti()) { |
| listAreaGridData.heightHint = 0; |
| } |
| // allow listArea to grab space depending if details |
| // are opened or not |
| if (opened) { |
| listAreaGridData.grabExcessVerticalSpace = false; |
| } else { |
| listAreaGridData.grabExcessVerticalSpace = true; |
| } |
| listArea.setLayoutData(listAreaGridData); |
| |
| Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT); |
| int diffY = newSize.y - windowSize.y; |
| // increase the dialog height if details were opened and such |
| // increase is necessary |
| // decrease the dialog height if details were closed and empty space |
| // appeared |
| if ((opened && diffY > 0) || (!opened && diffY < 0)) { |
| getShell().setSize( |
| new Point(windowSize.x, windowSize.y + (diffY))); |
| } |
| dialogArea.layout(); |
| return opened; |
| } |
| |
| /** |
| * This method should initialize the dialog bounds. |
| */ |
| @Override |
| protected void initializeBounds() { |
| super.initializeBounds(); |
| refreshDialogSize(); |
| boolean modalitySwitch = getBooleanValue(IStatusDialogConstants.MODALITY_SWITCH); |
| if (modalitySwitch) { |
| getShell().setBounds(getShellBounds()); |
| } |
| } |
| |
| @Override |
| public Point getInitialLocation(Point initialSize) { |
| return super.getInitialLocation(initialSize); |
| } |
| |
| /** |
| * The selection in the multiple job list has changed. Update widget |
| * enablements, repopulate the list and show details. |
| */ |
| private void handleSelectionChange() { |
| StatusAdapter newSelection = getSingleSelection(); |
| if (newSelection != null) { |
| dialogState.put(IStatusDialogConstants.CURRENT_STATUS_ADAPTER, |
| newSelection); |
| showDetailsArea(); |
| refresh(); |
| } |
| } |
| |
| /** |
| * This method creates display area for {@link StatusAdapter}s when more |
| * is available. |
| * |
| * @param parent |
| * A parent composite on which all components should be |
| * placed. |
| */ |
| private void fillListArea(Composite parent) { |
| // it is necessary to make list parent composite taller |
| GridData listAreaGD = (GridData) parent.getLayoutData(); |
| listAreaGD.grabExcessHorizontalSpace = true; |
| if (!detailsManager.isOpen()) { |
| listAreaGD.grabExcessVerticalSpace = true; |
| } |
| listAreaGD.heightHint = SWT.DEFAULT; |
| |
| // create list viewer |
| statusListViewer = new TableViewer(parent, SWT.SINGLE |
| | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); |
| statusListViewer.setComparator(getLabelProviderWrapper()); |
| Control control = statusListViewer.getControl(); |
| GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); |
| data.heightHint = convertHeightInCharsToPixels(5); |
| control.setLayoutData(data); |
| initContentProvider(); |
| initLabelProvider(); |
| statusListViewer.addPostSelectionChangedListener(event -> { |
| handleSelectionChange(); |
| if ((getTray() == null) && getBooleanValue(IStatusDialogConstants.TRAY_OPENED) |
| && providesSupport()) { |
| silentTrayOpen(); |
| return; |
| } |
| if ((getTray() != null) && !providesSupport()) { |
| silentTrayClose(); |
| return; |
| } |
| supportTray.selectionChanged(event); |
| }); |
| Dialog.applyDialogFont(parent); |
| } |
| |
| /** |
| * closes the tray without changing any flag |
| */ |
| private void silentTrayClose() { |
| super.closeTray(); |
| } |
| |
| /** opens the tray without changing any flag */ |
| private void silentTrayOpen() { |
| if (getTray() == null) |
| super.openTray(supportTray); |
| } |
| /** |
| * This methods switches StatusAdapters presentation depending if there |
| * is one status or more. |
| */ |
| private void updateListArea() { |
| // take care about list area if there is more than one status |
| if (isMulti()) { |
| if (singleStatusDisplayArea != null) { |
| singleStatusDisplayArea.dispose(); |
| } |
| if (statusListViewer == null |
| || statusListViewer.getControl().isDisposed()) { |
| fillListArea(listArea); |
| listArea.layout(); |
| listArea.getParent().layout(); |
| getShell().setSize( |
| getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT)); |
| } |
| refreshStatusListArea(); |
| } |
| } |
| |
| /** |
| * Updated title area. Adjust title, title message and title image |
| * according to selected {@link StatusAdapter}. |
| */ |
| private void updateTitleArea() { |
| Image image = getLabelProviderWrapper().getImage( |
| getCurrentStatusAdapter()); |
| titleImageLabel.setImage(image); |
| if (getCurrentStatusAdapter() != null) { |
| mainMessageLabel.setText(getLabelProviderWrapper() |
| .getMainMessage(getCurrentStatusAdapter())); |
| } |
| if (singleStatusDisplayArea != null) { |
| if (isMulti()) { |
| singleStatusDisplayArea.dispose(); |
| } else { |
| refreshSingleStatusArea(); |
| } |
| } |
| titleArea.layout(); |
| } |
| |
| /** |
| * This method creates button bar that is available on the bottom of the |
| * dialog. |
| */ |
| @Override |
| protected Control createButtonBar(Composite parent) { |
| Composite composite = new Composite(parent, SWT.NONE); |
| GridLayout layout = new GridLayout(); |
| layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); |
| layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); |
| composite.setLayout(layout); |
| composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, |
| false)); |
| |
| linkComposite = createLinkComposite(composite); |
| |
| // Add the buttons to the button bar. |
| createButtonsForButtonBar(composite); |
| |
| composite.layout(); |
| return composite; |
| } |
| |
| /** |
| * This method creates buttons that are placed on button bar. |
| */ |
| @Override |
| protected void createButtonsForButtonBar(Composite parent) { |
| IAction gotoAction = getGotoAction(); |
| String text = null; |
| if (gotoAction != null) { |
| text = gotoAction.getText(); |
| } |
| Button button = createButton(parent, GOTO_ACTION_ID, |
| text == null ? "" : text, //$NON-NLS-1$ |
| false); |
| if (text == null) |
| hideButton(button, true); |
| |
| createButton(parent, IDialogConstants.OK_ID, |
| IDialogConstants.OK_LABEL, true); |
| |
| createButton(parent, IDialogConstants.DETAILS_ID, |
| IDialogConstants.SHOW_DETAILS_LABEL, false); |
| } |
| |
| /** |
| * This method creates additional display area for {@link StatusAdapter} |
| * when only one is available. |
| * |
| * It creates one label on a composite currently for secondary message. |
| * |
| * @param parent |
| * A parent composite on which all components should be |
| * placed. |
| * @return composite the composite on which are all components for |
| * displaying status when only one is available. |
| */ |
| private Composite createSingleStatusDisplayArea(Composite parent) { |
| // secondary message is displayed on separate composite with no |
| // margins |
| Composite singleStatusParent = new Composite(parent, SWT.NONE); |
| GridLayout gridLayout = new GridLayout(); |
| gridLayout.marginWidth = 0; |
| singleStatusParent.setLayout(gridLayout); |
| GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false); |
| singleStatusParent.setLayoutData(gd); |
| |
| // label that wraps |
| singleStatusLabel = new Label(singleStatusParent, SWT.WRAP); |
| GridData labelLayoutData = new GridData(SWT.FILL, SWT.FILL, true, |
| true); |
| labelLayoutData.widthHint = convertWidthInCharsToPixels(50); |
| singleStatusLabel.setLayoutData(labelLayoutData); |
| // main message set up early, to address bug 222391 |
| singleStatusLabel.setText(getLabelProviderWrapper() |
| .getColumnText(getCurrentStatusAdapter(), 0)); |
| |
| singleStatusLabel.addMouseListener(new MouseListener() { |
| @Override |
| public void mouseDoubleClick(MouseEvent e) { |
| } |
| |
| @Override |
| public void mouseDown(MouseEvent e) { |
| showDetailsArea(); |
| } |
| |
| @Override |
| public void mouseUp(MouseEvent e) { |
| } |
| }); |
| return singleStatusParent; |
| } |
| |
| /** |
| * This method closes the dialog. |
| */ |
| @Override |
| public boolean close() { |
| boolean modalitySwitch = getBooleanValue(IStatusDialogConstants.MODALITY_SWITCH); |
| if (detailsManager.isOpen()) { |
| dialogState.put(IStatusDialogConstants.DETAILS_OPENED, Boolean.TRUE); |
| toggleDetailsArea(); |
| } |
| if (getBooleanValue(IStatusDialogConstants.TRAY_OPENED)) { |
| closeTray(); |
| if (modalitySwitch) { |
| dialogState.put(IStatusDialogConstants.DETAILS_OPENED, Boolean.TRUE); |
| } |
| } |
| dialogState.put(IStatusDialogConstants.SHELL_BOUNDS, getShell().getBounds()); |
| statusListViewer = null; |
| boolean result = super.close(); |
| if (!modalitySwitch && getBooleanValue(IStatusDialogConstants.ANIMATION)) { |
| ProgressManagerUtil.animateDown(getShellBounds()); |
| } |
| return result; |
| } |
| |
| /** |
| * Hide the button if hide is <code>true</code>. |
| * |
| * @param button |
| * @param hide |
| */ |
| private void hideButton(Button button, boolean hide) { |
| ((GridData) button.getLayoutData()).exclude = hide; |
| button.setVisible(!hide); |
| button.setEnabled(!hide); |
| } |
| |
| /** |
| * Update the button enablements |
| */ |
| private void updateEnablements() { |
| Button details = getButton(IDialogConstants.DETAILS_ID); |
| if (details != null) { |
| details.setEnabled(true); |
| } |
| Button gotoButton = getButton(GOTO_ACTION_ID); |
| if (gotoButton != null) { |
| IAction gotoAction = getGotoAction(); |
| boolean hasValidGotoAction = (gotoAction != null) |
| && (gotoAction.getText() != null); |
| if (hasValidGotoAction) { |
| hideButton(gotoButton, false); |
| gotoButton.setText(gotoAction.getText()); |
| |
| ((GridData) gotoButton.getLayoutData()).widthHint = gotoButton |
| .computeSize(SWT.DEFAULT, SWT.DEFAULT).x; |
| gotoButton.getParent().layout(); |
| } else |
| hideButton(gotoButton, true); |
| } |
| // and tray enablement button |
| if (providesSupport() && !getBooleanValue(IStatusDialogConstants.HIDE_SUPPORT_BUTTON)) { |
| if (launchTrayLink == null || launchTrayLink.isDisposed()) { |
| launchTrayLink = createGetSupportLink(); |
| } |
| launchTrayLink |
| .setEnabled(!getBooleanValue(IStatusDialogConstants.TRAY_OPENED)); |
| } else { |
| if (launchTrayLink != null && !launchTrayLink.isDisposed()) { |
| launchTrayLink.dispose(); |
| launchTrayLink = null; |
| } |
| } |
| IViewDescriptor descriptor = shouldDisplayLinkToErrorLog(); |
| if (descriptor != null) { |
| if (showErrorLogLink == null || showErrorLogLink.isDisposed()) { |
| showErrorLogLink = createShowErrorLogLink(); |
| } |
| } else { |
| if (showErrorLogLink != null && !showErrorLogLink.isDisposed()) { |
| showErrorLogLink.dispose(); |
| } |
| } |
| linkComposite.getParent().layout(); |
| } |
| |
| private IViewDescriptor shouldDisplayLinkToErrorLog() { |
| /* no support for error log */ |
| if (!getBooleanValue(IStatusDialogConstants.ERRORLOG_LINK)) { |
| return null; |
| } |
| /* check handling hint and display link if it is expected */ |
| boolean shouldDisplay = false; |
| Iterator it = ((Collection) dialogState |
| .get(IStatusDialogConstants.STATUS_ADAPTERS)).iterator(); |
| while (it.hasNext()) { |
| StatusAdapter adapter = (StatusAdapter) it.next(); |
| Integer hint = (Integer) adapter.getProperty(WorkbenchStatusDialogManagerImpl.HINT); |
| if (hint != null |
| && ((hint.intValue() & StatusManager.LOG) != 0)) { |
| shouldDisplay |= true; |
| break; |
| } |
| } |
| if (!shouldDisplay) { |
| return null; |
| } |
| /* view description */ |
| return Workbench.getInstance().getViewRegistry().find(LOG_VIEW_ID); |
| } |
| |
| /** |
| * Opens the dialog tray (support area at the right side of the dialog) |
| */ |
| @Override |
| public void openTray(DialogTray tray) throws IllegalStateException, |
| UnsupportedOperationException { |
| if (launchTrayLink != null && !launchTrayLink.isDisposed()) { |
| launchTrayLink.setEnabled(false); |
| } |
| if (providesSupport()) { |
| super.openTray(tray); |
| } |
| dialogState.put(IStatusDialogConstants.TRAY_OPENED, Boolean.TRUE); |
| } |
| |
| /** |
| * Refreshes the single status area. Is called only when there is one |
| * and only one error. |
| */ |
| private void refreshSingleStatusArea() { |
| String description = getLabelProviderWrapper() |
| .getColumnText(getCurrentStatusAdapter(), 0); |
| if (description.equals(singleStatusLabel.getText())) |
| singleStatusLabel.setText(" "); //$NON-NLS-1$ |
| singleStatusLabel.setText(description); |
| singleStatusDisplayArea.layout(); |
| getShell().setText(getString(IStatusDialogConstants.TITLE)); |
| } |
| |
| /** |
| * Refresh the contents of the viewer. |
| */ |
| private void refreshStatusListArea() { |
| if (statusListViewer != null |
| && !statusListViewer.getControl().isDisposed()) { |
| statusListViewer.refresh(); |
| if (statusListViewer.getTable().getItemCount() > 1) { |
| getShell() |
| .setText( |
| WorkbenchMessages.WorkbenchStatusDialog_MultipleProblemsHaveOccured); |
| } else { |
| getShell().setText( |
| getString(IStatusDialogConstants.TITLE)); |
| } |
| } |
| } |
| |
| /** |
| * Sets the content provider for the viewer. |
| */ |
| private void initContentProvider() { |
| IContentProvider provider = new IStructuredContentProvider() { |
| @Override |
| public void dispose() { |
| // Nothing of interest here |
| } |
| |
| @Override |
| public Object[] getElements(Object inputElement) { |
| return ((Collection) dialogState |
| .get(IStatusDialogConstants.STATUS_ADAPTERS)).toArray(); |
| } |
| |
| @Override |
| public void inputChanged(Viewer viewer, Object oldInput, |
| Object newInput) { |
| if (newInput != null) { |
| refreshStatusListArea(); |
| } |
| } |
| }; |
| statusListViewer.setContentProvider(provider); |
| statusListViewer.setInput(this); |
| statusListViewer.setSelection(new StructuredSelection( |
| getCurrentStatusAdapter())); |
| } |
| |
| /** |
| * Creates a new control that provides access to support providers. |
| * <p> |
| * The <code>WorkbenchStatusDialog</code> implementation of this method |
| * creates the control, registers it for selection events including |
| * selection, Note that the parent's layout is assumed to be a |
| * <code>GridLayout</code> and the number of columns in this layout is |
| * incremented. Subclasses may override. |
| * </p> |
| * |
| * @param parent |
| * A parent composite on which all components should be |
| * placed. |
| * @return the report control |
| */ |
| private Composite createLinkComposite(Composite parent) { |
| Composite linkArea = new Composite(parent, SWT.NONE) { |
| |
| // the composite should be as small as possible when there is no |
| // additional controls on it |
| @Override |
| public Point computeSize(int wHint, int hHint, boolean changed) { |
| Point newSize = super.computeSize(wHint, hHint, changed); |
| if (getChildren().length == 0) { |
| newSize.x = 0; |
| newSize.y = 0; |
| } |
| return newSize; |
| } |
| |
| }; |
| GridLayout layout = new GridLayout(); |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| layout.verticalSpacing = 0; |
| linkArea.setLayout(layout); |
| |
| ((GridLayout) parent.getLayout()).numColumns++; |
| |
| GridData layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, true, |
| false); |
| linkArea.setLayoutData(layoutData); |
| return linkArea; |
| } |
| |
| /** |
| * Creates a button with a report image. This is only used if there is |
| * an image available. |
| */ |
| private Link createGetSupportLink() { |
| // no support |
| if (!providesSupport() || getBooleanValue(IStatusDialogConstants.HIDE_SUPPORT_BUTTON)) { |
| return null; |
| } |
| |
| Link link = new Link(linkComposite, SWT.NONE); |
| link |
| .setText(WorkbenchMessages.WorkbenchStatusDialog_SupportHyperlink); |
| link |
| .setToolTipText(WorkbenchMessages.WorkbenchStatusDialog_SupportTooltip); |
| link.addSelectionListener(widgetSelectedAdapter(e -> openTray())); |
| Dialog.applyDialogFont(link); |
| return link; |
| } |
| |
| private Link createShowErrorLogLink() { |
| Link link = new Link(linkComposite, SWT.NONE); |
| link.addSelectionListener(widgetSelectedAdapter(e -> { |
| try { |
| Workbench.getInstance().getActiveWorkbenchWindow().getActivePage().showView(LOG_VIEW_ID); |
| } catch (CoreException ce) { |
| StatusManager.getManager().handle(ce, WorkbenchPlugin.PI_WORKBENCH); |
| } |
| })); |
| link.setText(WorkbenchMessages.ErrorLogUtil_ShowErrorLogHyperlink); |
| link |
| .setToolTipText(WorkbenchMessages.ErrorLogUtil_ShowErrorLogTooltip); |
| Dialog.applyDialogFont(link); |
| return link; |
| } |
| |
| /** |
| * Sets initial label provider. |
| */ |
| private void initLabelProvider() { |
| statusListViewer.setLabelProvider(getLabelProviderWrapper()); |
| } |
| |
| /** |
| * Returns {@link IAction} associated with selected StatusAdapter. |
| * |
| * @return {@link IAction} that is set as {@link StatusAdapter} property |
| * with Job.class key. |
| */ |
| private IAction getGotoAction() { |
| Object property = null; |
| |
| Job job = Adapters.adapt(getCurrentStatusAdapter(), Job.class); |
| if (job != null) { |
| property = job.getProperty(IProgressConstants.ACTION_PROPERTY); |
| } |
| |
| if (property instanceof IAction) { |
| return (IAction) property; |
| } |
| return null; |
| } |
| |
| /** |
| * Get the single selection. Return null if the selection is not just |
| * one element. |
| * |
| * @return StatusAdapter or <code>null</code>. |
| */ |
| private StatusAdapter getSingleSelection() { |
| IStructuredSelection selection = statusListViewer.getStructuredSelection(); |
| if (selection != null && selection.size() == 1) { |
| return (StatusAdapter) selection.getFirstElement(); |
| } |
| return null; |
| } |
| |
| /* |
| * Prompt to inform the user that the dialog will close and the errors |
| * cleared. |
| */ |
| private boolean isPromptToClose() { |
| IPreferenceStore store = WorkbenchPlugin.getDefault() |
| .getPreferenceStore(); |
| if (!store.contains(PREF_SKIP_GOTO_ACTION_PROMPT) |
| || !store.getString(PREF_SKIP_GOTO_ACTION_PROMPT).equals( |
| MessageDialogWithToggle.ALWAYS)) { |
| MessageDialogWithToggle dialog = MessageDialogWithToggle.open( |
| MessageDialog.CONFIRM, getShell(), |
| ProgressMessages.JobErrorDialog_CloseDialogTitle, |
| ProgressMessages.JobErrorDialog_CloseDialogMessage, |
| ProgressMessages.JobErrorDialog_DoNotShowAgainMessage, |
| false, store, PREF_SKIP_GOTO_ACTION_PROMPT, SWT.SHEET); |
| return dialog.getReturnCode() == Window.OK; |
| } |
| return true; |
| } |
| |
| public void openTray() { |
| openTray(supportTray); |
| } |
| |
| public boolean providesSupport() { |
| return supportTray.providesSupport(getCurrentStatusAdapter()) != null; |
| } |
| |
| private String getString(Object key) { |
| return (String) dialogState.get(key); |
| } |
| |
| private StatusAdapter getCurrentStatusAdapter() { |
| return (StatusAdapter) dialogState |
| .get(IStatusDialogConstants.CURRENT_STATUS_ADAPTER); |
| } |
| |
| private boolean getBooleanValue(Object key) { |
| Boolean b = (Boolean) dialogState.get(key); |
| if (b == null) { |
| return false; |
| } |
| return b.booleanValue(); |
| } |
| |
| private Rectangle getShellBounds() { |
| return (Rectangle) dialogState.get(IStatusDialogConstants.SHELL_BOUNDS); |
| } |
| |
| private LabelProviderWrapper getLabelProviderWrapper() { |
| return (LabelProviderWrapper) dialogState |
| .get(IStatusDialogConstants.LABEL_PROVIDER); |
| } |
| |
| private boolean isMulti() { |
| return ((Collection) dialogState |
| .get(IStatusDialogConstants.STATUS_ADAPTERS)).size() > 1; |
| } |
| } |