/*****************************************************************************
* Copyright (c) 2007-2008 g-Eclipse Consortium
* 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
*
* Initial development of the original code was made for the
* g-Eclipse project founded by European Union
* project number: FP6-IST-034327 http://www.geclipse.eu/
*
* Contributors:
* Mathias Stuempert - initial API and implementation
*****************************************************************************/
package eu.geclipse.ui.dialogs;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import eu.geclipse.core.reporting.IProblem;
import eu.geclipse.core.reporting.ISolution;
import eu.geclipse.core.reporting.ProblemException;
import eu.geclipse.ui.internal.Activator;
import eu.geclipse.ui.internal.LogExceptionSolution;
import eu.geclipse.ui.internal.ReportProblemSolution;
import eu.geclipse.ui.internal.layout.PackData;
import eu.geclipse.ui.internal.layout.PackLayout;
/**
* The ProblemDialog is the user-friendly way of g-Eclipse of reporting
* problems to the user. It displays not only the description of the problem
* but also the registered solutions that could potentially solve the problem.
* The active solutions are clickable and perform some action, like generating
* a problem report or logging the exception.
*/
public class ProblemDialog extends ErrorDialog {
/**
* Return code determining that a solution was chosen.
*/
public static final int SOLVE = 2;
private final Throwable exc;
private ProblemDialog( final Shell parentShell,
final String dialogTitle,
final String message,
final Throwable exc ) {
super( parentShell, dialogTitle, message, getStatus( exc ),
IStatus.OK | IStatus.INFO | IStatus.WARNING | IStatus.ERROR );
this.message = message;
this.exc = exc;
}
/**
* Convenience static method for opening a {@link ProblemDialog}. This
* method has to be called from the UI thread. The parent {@link Shell}
* may be <code>null</code>. In this case a default {@link Shell} is
* chosen. Nevertheless it is recommended to not call this method
* without a valid {@link Shell}.
*
* @param parent The parent {@link Shell} of the dialog.
* @param dialogTitle The dialog's title.
* @param message A short message displayed as description of the problem.
* @param exc An optional exception. If this is a {@link ProblemException}
* the corresponding reasons and solutions are displayed.
* @return The dialog's return status.
*/
public static int openProblem( final Shell parent,
final String dialogTitle,
final String message,
final Throwable exc ) {
Shell shell = parent;
if ( shell == null ) {
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
if ( window != null ) {
shell = window.getShell();
}
}
final ProblemDialog dialog
= new ProblemDialog( shell, dialogTitle, message, exc );
if ( shell != null ) {
Display display = Display.getCurrent();
if ( ( display == null ) || ( display.isDisposed() ) ) {
display = Display.getDefault();
}
display.syncExec( new Runnable() {
public void run() {
dialog.open();
}
} );
}
return dialog.getReturnCode();
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.IconAndMessageDialog#createMessageArea(org.eclipse.swt.widgets.Composite)
*/
@Override
protected Control createMessageArea( final Composite parent ) {
Image image = getImage();
if ( image != null ) {
this.imageLabel = new Label( parent, SWT.NULL );
image.setBackground( this.imageLabel.getBackground() );
this.imageLabel.setImage( image );
// TODO mathias addAccessibleListeners missing
this.imageLabel.setLayoutData( new GridData( GridData.HORIZONTAL_ALIGN_CENTER
| GridData.VERTICAL_ALIGN_BEGINNING) );
}
Composite composite = new Composite( parent, SWT.NONE );
composite.setLayoutData( new GridData( GridData.GRAB_HORIZONTAL
| GridData.GRAB_VERTICAL
| GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_BEGINNING ) );
composite.setLayout( new PackLayout( SWT.VERTICAL ) );
createLabelArea( composite );
createReasonArea( composite );
createSolutionArea( composite );
return composite;
}
protected void createLabelArea( final Composite parent ) {
if ( this.message != null ) {
int wHint = convertHorizontalDLUsToPixels( IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH );
final ScrolledComposite sComp = createListArea( "Message:", parent, 100 );
final Composite comp = new Composite( sComp, SWT.NONE );
sComp.setContent( comp );
comp.setLayout( new GridLayout( 1, false ) );
Label label = new Label( comp, SWT.WRAP );
label.setText( this.message );
GridData gData = new GridData( GridData.FILL_HORIZONTAL );
gData.grabExcessHorizontalSpace = true;
gData.widthHint = wHint;
label.setLayoutData( gData );
Point size = comp.computeSize( wHint, SWT.DEFAULT );
comp.setSize( size );
sComp.addControlListener( new ControlAdapter() {
@Override
public void controlResized( final ControlEvent e ) {
Rectangle r = sComp.getClientArea();
Point cSize = comp.computeSize( r.width, SWT.DEFAULT );
comp.setSize( cSize );
}
} );
}
}
protected void createReasonArea( final Composite parent ) {
String[] reasons = getReasons();
if ( ( reasons != null ) && ( reasons.length > 0 ) ) {
ImageRegistry imgReg = Activator.getDefault().getImageRegistry();
Image reasonImage = imgReg.get( "reason" ); //$NON-NLS-1$
final ScrolledComposite sComp = createListArea( "Reasons:", parent, 200 );
final Composite reasonList = new Composite( sComp, SWT.NONE );
sComp.setContent( reasonList );
reasonList.setLayout( new GridLayout( 2, false ) );
for ( String reason : reasons ) {
Label imgLabel = new Label( reasonList, SWT.NONE );
imgLabel.setImage( reasonImage );
GridData gData = new GridData();
gData.horizontalAlignment = GridData.CENTER;
gData.verticalAlignment = GridData.BEGINNING;
imgLabel.setLayoutData( gData );
Label label = new Label( reasonList, SWT.WRAP );
label.setText( reason );
gData = new GridData( GridData.FILL_HORIZONTAL );
gData.grabExcessHorizontalSpace = true;
gData.horizontalAlignment = GridData.BEGINNING;
label.setLayoutData( gData );
}
int wHint = convertHorizontalDLUsToPixels( IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH );
reasonList.setSize( reasonList.computeSize( wHint, SWT.DEFAULT ) );
sComp.addControlListener( new ControlAdapter() {
@Override
public void controlResized( final ControlEvent e ) {
Rectangle r = sComp.getClientArea();
Point cSize = reasonList.computeSize( r.width, SWT.DEFAULT );
reasonList.setSize( cSize );
}
} );
}
}
protected void createSolutionArea( final Composite parent ) {
ISolution[] solutions = getSolutions();
if ( ( solutions != null ) && ( solutions.length > 0 ) ) {
ImageRegistry imgReg = Activator.getDefault().getImageRegistry();
Image solutionImage = imgReg.get( "solution" ); //$NON-NLS-1$
final ScrolledComposite sComp = createListArea( Messages.getString( "ProblemDialog.solutions_label" ), parent, 200 ); //$NON-NLS-1$
final Composite solutionList = new Composite( sComp, SWT.NONE );
sComp.setContent( solutionList );
solutionList.setLayout( new GridLayout( 2, false ) );
for ( final ISolution solution : solutions ) {
Label imgLabel = new Label( solutionList, SWT.NONE );
imgLabel.setImage( solutionImage );
GridData gData = new GridData();
gData.horizontalAlignment = GridData.CENTER;
gData.verticalAlignment = GridData.BEGINNING;
imgLabel.setLayoutData( gData );
Link link = new Link( solutionList, SWT.WRAP );
String text = solution.getDescription();
if ( solution.isActive() ) {
link.setText( "<a>" + text + "</a>" ); //$NON-NLS-1$ //$NON-NLS-2$
} else {
link.setText( text );
}
gData = new GridData( GridData.FILL_HORIZONTAL);
gData.grabExcessHorizontalSpace = true;
gData.horizontalAlignment = GridData.BEGINNING;
link.setLayoutData( gData );
link.addSelectionListener( new SelectionAdapter() {
@SuppressWarnings("synthetic-access")
@Override
public void widgetSelected( final SelectionEvent e ) {
setReturnCode( SOLVE );
close();
try {
solution.solve();
} catch ( InvocationTargetException itExc ) {
Throwable cause = itExc.getCause();
Activator.logException( cause );
}
}
} );
}
int wHint = convertHorizontalDLUsToPixels( IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH );
solutionList.setSize( solutionList.computeSize( wHint, SWT.DEFAULT ) );
sComp.addControlListener( new ControlAdapter() {
@Override
public void controlResized( final ControlEvent e ) {
Rectangle r = sComp.getClientArea();
Point cSize = solutionList.computeSize( r.width, SWT.DEFAULT );
solutionList.setSize( cSize );
}
} );
}
}
protected IProblem getProblem() {
IProblem result = null;
if ( ( this.exc != null ) && ( this.exc instanceof ProblemException ) ) {
result = ( ( ProblemException ) this.exc ).getProblem();
}
return result;
}
protected String[] getReasons() {
List< String > resultList = new ArrayList< String >();
IStatus status = getStatus();
if ( status != null ) {
resultList.add( status.getMessage() );
}
IProblem problem = getProblem();
if ( problem != null ) {
String[] reasons = problem.getReasons();
if ( reasons != null ) {
for ( String reason : reasons ) {
resultList.add( reason );
}
}
}
return resultList.isEmpty() ? null : resultList.toArray( new String[ resultList.size() ] );
}
protected ISolution[] getSolutions() {
List< ISolution > resultList = new ArrayList< ISolution >();
IProblem problem = getProblem();
if ( problem != null ) {
List< ISolution > list = Arrays.asList( problem.getSolutions() );
resultList.addAll( list );
}
if ( this.exc != null ) {
resultList.add( new LogExceptionSolution( this.exc ) );
resultList.add( new ReportProblemSolution( this.exc ) );
}
return resultList.toArray( new ISolution[ resultList.size() ] );
}
protected IStatus getStatus() {
return getStatus( this.exc );
}
private ScrolledComposite createListArea( final String title, final Composite parent, final int maxScrollableHeight ) {
Composite comp = new Composite( parent, SWT.NONE );
PackLayout layout = new PackLayout( SWT.VERTICAL );
comp.setLayout( layout );
PackData pData = new PackData();
comp.setLayoutData( pData );
Label label = new Label( comp, SWT.NONE );
label.setText( title );
final ScrolledComposite sComp = new ScrolledComposite( comp, SWT.V_SCROLL );
pData = new PackData();
pData.minHeight = 10;
pData.maxHeight = maxScrollableHeight;
sComp.setLayoutData( pData );
return sComp;
}
private static IStatus getStatus( final Throwable throwable ) {
IStatus result = null;
if ( ( throwable != null ) && ( throwable instanceof CoreException ) ) {
result = ( ( CoreException ) throwable ).getStatus();
}
else {
String message = null;
if ( throwable != null ) {
message = throwable.getMessage();
}
if ( message == null ) {
message = Messages.getString( "ProblemDialog.no_further_info" ); //$NON-NLS-1$
}
result = new Status( IStatus.ERROR,
Activator.PLUGIN_ID,
IStatus.OK,
message,
throwable );
}
return result;
}
}