Diálogo «de detalles» JFace

Desde hace unas semanas, y sólo por curiosidad, decidimos buscar una clase de tipo Dialog del JFace o del SWT que implementara el clásico diálogo que:

  • Muestra un icono.
  • Muestra un mensaje principal.
  • Muestra un botón de «detalles». Si dicho botón es pulsado, se expande una región, debajo del diálogo, que muestra un texto predefinible por el usuario. Esta región viene a ser un «área de detalles» donde al usuario se le puede especificar un mensaje más explicativo que el mero mensaje principal del diálogo. Si el botón de «detalles» se vuelve a pulsar, este área de detalles es colapsada.

Eclipse muestra este tipo de diálogos en múltiples ocasiones. Así por ejemplo, cuando se está ejecutando una tera de larga duración, se muestra un diálogo como el siguiente:

Diálogo de detalles colapsado

Cuando se pulsa el botón «Details >>», el diálogo se expande, mostrando el área de detalles en cuestión:

Diálogo de detalles expandido

Por desgracia, tras diversas búsquedas, no pudimos dar con un código fuente que lo implementara. Con el deseo de ayudar a aquellos que, como nosotros, no encontraron este tipo de diálogo implementado, hemos decidido crear una clase propia que lo implemente.

Actualmente esta clase permite definir un área de detalles que está formada sólo por texto no editable. Esto, por supuesto, es una limitación, pero también es cierto que es trivial abstraer esta clase para que, en el área de detalles, se pueda mostrar cualquier tipo de contenido. Por falta de tiempo, sólo hemos implementado la clase que define un diálogo con un área de detalles de tipo textual. Esta clase, además, permite definir el tipo de icono mostrado en el diálogo. La clase, DialogoDetalles, puede ser accedida desde este link. Su aspecto es el que se muestra  a continuación:

Diálogo de detalles

El código fuente de la clase es el siguiente:


import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IconAndMessageDialog;
import org.eclipse.swt.SWT;
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.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

/**
 * <p>
 * La clase DialogoDetalles representa un diálogo emergente que muestra un
 * icono, un mensaje, y un área de detalles donde se puede mostrar texto plano.
 * <p>
 * Está clase está pensada para mostrar al usuario el clásico diálogo en el que
 * puede pulsar un botón de "detalles" para así visualizar un informe detallado
 * del mensaje transmitido por el diálogo.
 * <p>
 * Este diálogo consta de dos botones, uno de "cerrar" y otro de "detalles". El
 * botón de detalles permite hacer visible u ocultar el área de detalles del
 * diálogo. El icono visualizado en el diálogo también puede ser especificado
 * por el usuario.
 * 
 * @author L.A González Jaime
 * @author R.J Palma Durán
 */
public class DialogoDetalles extends IconAndMessageDialog{
	/*
	 * Tipo de icono a usar. Es una de las constantes ERROR,
	 * WARNING,INFORMATIO,QUESTION.
	 */
	protected int tipoIcono;
	/*
	 * Detalles del diálogo. Este texto es el mostrado en el área de detalles.
	 */
	protected String detalles;
	/*
	 * Área de texto donde se muestran los detalles.
	 */
	protected Text textoDetalles;
	/*
	 * Booleano que indica si el área de texto de los detalles (textoDetalles)
	 * está creada o no. La visualización y el ocultamiento del área de detalles
	 * se gestiona creando y destrullendo el textoDetalles. Este flag nos indica
	 * si, en efecto, el textoDetalles está o no creado.
	 */
	protected boolean textoDetallesCreado = false;
	/**
	 * Constante que indica que el icono visualizado en el diálogo es de error.
	 */
	public static final int ERROR = 0;
	/**
	 * Constante que indica que el icono visualizado en el diálogo es de
	 * advertencia.
	 */
	public static final int WARNING = 1;
	/**
	 * Constante que indica que el icono visualizado en el diálogo es de
	 * información.
	 */
	public static final int INFORMATION = 2;
	/**
	 * Constante que indica que el icono visualizado en el diálogo es de
	 * pregunta.
	 */
	public static final int QUESTION = 3;
	/*
	 * Botón que permite mostrar y ocultar los detalles del diálogo.
	 */
	protected Button botonDetalles;
	/*
	 * Título del diálogo.
	 */
	protected String titulo;

	/**
	 * Cosntruye un DialogoDetalles. El estilo del diálogo creado (el estilo de
	 * la shell) es
	 * <code>SWT.CLOSE | SWT.RESIZE | SWT.MAX | SWT.MODELESS</code>.
	 * 
	 * @param titulo título del diálogo.
	 * @param mensaje mensaje principal mostrado en el diálogo.
	 * @param detalles texto que se muestra en el área de detalles.
	 * @param tipoIcono tipo de icono a mostrar en el diálogo. Puede ser alguna de las constantes
	 * <code>DialogoDetalles.ERROR</code>, <code>DialogoDetalles.WARNING</code>, <code>DialogoDetalles.INFORMATION</code>
	 * , <code>DialogoDetalles.QUESTION</code>.
	 * @param parentShell la Shell padre de este diálogo. Si es null, se creará una shell de alto nivel.
	 */
	public DialogoDetalles(String titulo, String mensaje, String detalles, int tipoIcono, Shell parentShell){
		this(titulo,mensaje,detalles,tipoIcono,parentShell,SWT.CLOSE | SWT.RESIZE | SWT.MAX | SWT.MODELESS);
	}

	/**
	 * Cosntruye un DialogoDetalles. Permite crear el estilo (estilo de la Shell) del
	 * diálogo creado.
	 * 
	 * @param titulo título del diálogo.
	 * @param mensaje mensaje principal mostrado en el diálogo.
	 * @param detalles texto que se muestra en el área de detalles.
	 * @param tipoIcono tipo de icono a mostrar en el diálogo. Puede ser alguna de las constantes
	 * <code>DialogoDetalles.ERROR</code>, <code>DialogoDetalles.WARNING</code>, <code>DialogoDetalles.INFORMATION</code>
	 * , <code>DialogoDetalles.QUESTION</code>.
	 * @param parentShell la Shell padre de este diálogo. Si es null, se creará una shell de alto nivel.
	 * @param estiloShell el estilo de la Shell del diálogo.
	 */
	public DialogoDetalles(String titulo, String mensaje, String detalles, int tipoIcono, Shell parentShell,
			int estiloShell){
		super(parentShell);
		if(mensaje == null){
			throw new IllegalArgumentException("The input message cannot be null");
		}
		this.message = mensaje;
		if(tipoIcono < 0 || tipoIcono > 3){
			throw new IllegalArgumentException("Invalid image type");
		}
		if(detalles == null){
			throw new IllegalArgumentException("Details cannot be null");
		}
		if(titulo == null){
			throw new IllegalArgumentException("Title cannot be null");
		}
		this.detalles = detalles;
		this.tipoIcono = tipoIcono;
		this.titulo = titulo;
		this.setBlockOnOpen(false);
		this.setShellStyle(estiloShell);
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
	 */
	protected Control createDialogArea(Composite parent){
		return createMessageArea(parent);
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse
	 * .swt.widgets.Composite)
	 */
	protected void createButtonsForButtonBar(Composite parent){
		createButton(parent, IDialogConstants.CLOSE_ID, IDialogConstants.CLOSE_LABEL, true);
		this.botonDetalles = createButton(parent, IDialogConstants.DETAILS_ID, IDialogConstants.SHOW_DETAILS_LABEL,
				false);
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int)
	 */
	protected void buttonPressed(int buttonId){
		if(buttonId == IDialogConstants.DETAILS_ID){
			/*
			 * Si se ha pulsado el botón de "detalles", se debe mostrar u ocultar el área de
			 * detalles, dependiendo de que estuviera o no oculta. Además, tras ocultar el
			 * área o visualizarla, se debe redimensionar el diálogo, para que así se ajuste
			 * al nuevo tamaño provocado por la aparición o desaparición del área de detalles.
			 */
			Point dimensionAnteriorDialogo = getShell().getSize();
			if(this.textoDetallesCreado){
				/*
				 * Si el área de texto está actualmente siendo mostrada, la eliminamos. Además,
				 * cambiamos la etiqueta del botón de "mostrar detalles".
				 */
				this.botonDetalles.setText(IDialogConstants.SHOW_DETAILS_LABEL);
				this.textoDetalles.dispose();
			}
			else{
				/*
				 * Si el área de texto actualmente no está siendo visualizada, la mostramos. Para
				 * ello, iniciamos a this.textoDetalles. Además, debemos cambiar la etiqueta
				 * del botón de "mostrar detalles". 
				 */
				this.botonDetalles.setText(IDialogConstants.HIDE_DETAILS_LABEL);
				this.textoDetalles = new Text((Composite)getContents(), SWT.BORDER | SWT.READ_ONLY | SWT.MULTI
						| SWT.WRAP | SWT.H_SCROLL | SWT.V_SCROLL);
				this.textoDetalles.setText(this.detalles);
				GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
				this.textoDetalles.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
				data.horizontalSpan = 2;
				this.textoDetalles.setLayoutData(data);
			}
			getContents().getShell().layout();
			this.textoDetallesCreado = !this.textoDetallesCreado;
			
			/*
			 * Se redimensiona el diálogo.
			 */
			Point dimensionNuevaDialogo = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
			int altoPantalla = Display.getCurrent().getClientArea().height;
			getShell().setSize(new Point(dimensionAnteriorDialogo.x, Math.min(dimensionNuevaDialogo.y, altoPantalla)));
		}
		else{
			/*
			 * Si se pulsa el botón de "cerrar", cerramos la ventana.
			 */
			close();
		}
		setReturnCode(buttonId);
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.IconAndMessageDialog#getImage()
	 */
	protected Image getImage(){
		switch(this.tipoIcono){
			case ERROR:
				return getErrorImage();
			case WARNING:
				return getWarningImage();
			case INFORMATION:
				return getInfoImage();
			case QUESTION:
				return getQuestionImage();
			default:
				throw new RuntimeException("Invalid image type");
		}
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets
	 * .Shell)
	 */
	protected void configureShell(Shell shell){
		super.configureShell(shell);
		// Título del diálogo
		shell.setText(this.titulo);
	}
}

3 respuestas to “Diálogo «de detalles» JFace”

  1. Has probado con ?

    Sino, yo uso el plugin WPCodeBox en mi blog para mostrar código en un post. Aunque para eso debes tener acceso a instalar plugins de wordpress.

  2. Que nos vamos para Sevilla!!!

    No os imagináis la ilusión que me ha hecho veros a vosotros también en la parte final del CUSL 🙂

    Sobre lo de los cuadros de diálogo, JFace y SWT ofrece bastantes cuadros de diálogo, pero hay veces que es complicado saber cuál utilizar… ¿qué ventajas me ofrece un TileDialog sobre un Dialog normal?, además que en la documentación «oficial» no aparecen capturas de pantallas, mientras que quizá es lo más práctico a la hora de elegir uno.

    Cuando estaba desarrollando eOPSOA estuve buscando información sobre eso mismo, y algo encontré [1] [2]. Durante ese tiempo reuní una gran cantidad de enlaces[3], a lo mejor os son útiles 🙂

    Nos vemos la semana que viene!!

    [1] http://blog.eclipse-tips.com/2008/07/selection-dialogs-in-eclipse.html
    [2] http://sureshkrishna.wordpress.com/2008/03/15/jface-dialogs-which-one-is-right-for-you/
    [3] http://is.gd/vjGY

  3. odracirnumira Says:

    Pues resulta que al final WordPress ofrece unas etiquetas para el código fuente. En el siguiente enlace se explica:

    Code

Deja un comentario