Visores

Por qué iba a querer utilizar un visor si las contribuciones de UI, como vistas, editores, asistentes y diálogos pueden implementarse directamente con widgets de SWT?  

Los visores le permiten crear widgets mientras utiliza los objetos de modelo.  Si utiliza un widget de SWT directamente, tiene que convertir los objetos en las series e imágenes que SWT espera.  Los visores actúan como adaptadores en widgets de SWT y manejan el código común para utilizar eventos de widgets que, de lo contrario, tendría que implementar usted mismo. 

Al principio se ha mostrado un visor en la contribución de la vista de la herramienta readme, en ReadmeSectionsView.

public void createPartControl(Composite parent) {
viewer = new ListViewer(parent);
...

Nota:  Los visores pueden utilizarse para proporcionar la implementación tanto para los editores como para las vistas de entorno de trabajo. El término visor no implica que un visor sólo se pueda utilizar para implementar vistas. Por ejemplo, el TextViewer se utiliza en la implementación de muchos de los editores de entorno de trabajo y de conector.

Visores estándar

JFace proporciona visores para la mayoría de los widgets no triviales de SWT. Los visores se utilizan comúnmente para widgets de listas, árboles, tablas y texto. 

Cada visor tiene un widget de SWT asociado. Este widget se puede crear implícitamente, suministrando el Composite padre en un constructor de visores adecuado; o explícitamente, creándolo primero y suministrándolo al visor en su constructor.

Visores orientados a listas

Listas, árboles y tablas comparten muchas posibilidades comunes desde el punto de vista del usuario, como relleno con objetos, selección, clasificación y filtración. 

Estos visores mantienen una lista de objetos de dominio (llamados elementos) y se visualizan en su widget de SWT correspondiente. Un visor de listas sabe cómo obtener una etiqueta de texto de cualquier elemento de la lista.  Obtiene la etiqueta de un ILabelProvider que puede estar establecido en el visor.  Sabe cómo correlacionar las llamadas de retorno de widget con la serie de elementos conocidos por el cliente del visor.

Los clientes que utilizan un widget de SWT plano tienen que operar a nivel de SWT, donde las series y eventos suelen hacer relación a un índice en la lista de series. Los visores proporcionan semántica de alto nivel. A los clientes se les notifica de la selecciones y cambios en la lista mediante los elementos que proporcionan al visor. Los visores realizan todo el trabajo tedioso para correlacionar índices con elementos, efectuando ajustes para un vista filtrada de los objetos y reorganizaciones en caso necesario.

La posibilidad de filtración y clasificación se lleva a cabo designando un clasificador de visor (ViewerSorter) y/o un filtro de visor (ViewerFilter) para el visor. (Éstos pueden especificarse para visores de árboles y tablas además de para visores de listas.) El cliente sólo tiene que proporcionar una clase que pueda comparar o filtrar los objetos de la lista. El visor maneja los detalles del relleno de la lista de acuerdo al orden y el filtro especificados, así como del mantenimiento del orden y del filtro como elementos que se añaden y eliminan.

Los visores no están pensados para que el cliente los pueda ampliar.  Para personalizar un visor, puede configurarlo con los proveedores de contenido y etiquetas.

Un ListViewer correlaciona elementos de una lista con un control List de SWT.

Un TreeViewer visualiza objetos de manera jerárquica en un widget Tree de SWT. Maneja los detalles para ampliar y colapsar elementos. Existen distintos tipos de visores de árboles para diferentes controles de árbol de SWT (árbol plano, árbol de tabla, árbol de recuadro de selección).

Un TableViewer es muy parecido a un visor de listas, pero cuenta con la posibilidad de ver varias columnas de información para cada elemento de la tabla.  Los visores de tablas amplían de manera significativa la función del widget de tabla de SWT introduciendo el concepto de edición de casilla. Pueden utilizarse editores de casillas especiales para permitir al usuario editar una casilla de tablas utilizando un recuadro combinado, un diálogo o un widget de texto. El visor de tablas maneja la creación y la colocación de estos widgets cuando el usuario los necesita para efectuar tareas de edición.  Este se lleva a cabo utilizando clases CellEditor, como TextCellEditor y CheckboxCellEditor.

Visores de texto

Los widgets de texto tienen semántica común, como doble pulsación, deshacer, colorear y navegar por índice o línea.  Un TextViewer es un adaptador para un widget StyledText de SWT. Los visores de texto proporcionan un modelo de documento al cliente y gestionan la conversión del documento a la información de texto con estilo que el widget de texto ha proporcionado.

Los visores de texto se tratan de manera más detallada en Editores del entorno de trabajo.

Arquitectura de visores

Para entender cómo funciona un visor, debe conocer la relación entre un elemento de entrada del mismo, su contenido, su selección y la información que se visualiza realmente en el widget que manipula.

Elementos de entrada

Un elemento de entrada es el objeto principal que el visor está visualizando (o editando). En el ámbito del visor, un elemento de entrada puede ser cualquier objeto. No presupone que el elemento de entrada ha implementado una interfaz concreta. (El motivo se explicará más adelante, cuando se hable de los proveedores de contenido.)

Un visor debe poder manejar un cambio de elemento de entrada. Si se establece un nuevo elemento de entrada en un visor, debe volver a rellenar su widget de acuerdo al nuevo elemento y eliminar la asociación que guarda con el elemento de entrada anterior. La semántica para registrarse como un escuchador en un elemento de entrada y rellenar el widget según dicho elemento es distinta en cada tipo de visor.

Visores de contenido

Un visor de contenido es un visor que tienen protocolo bien definido para obtener información de su elemento de entrada. Los visores de contenido utilizan dos clases de ayuda especializada, IContentProvider y ILabelProvider, para rellenar su widget y visualizar información sobre el elemento de entrada.

IContentProvider proporciona un protocolo de ciclo de vida básico para asociar un proveedor de contenido con un elemento de entrada y manejar un cambio de elemento de entrada. Se han implementado proveedores de contenido más especializados para diferentes tipos de visores. El proveedor de contenido más común es IStructuredContentProvider, que puede proporcionar una lista de objetos determinada como un elemento de entrada. Se utiliza en visores de tipo vista, como listas, tablas o árboles. Generalmente, el proveedor de contenido sabe cómo correlacionar el elemento de entrada con el contenido del visor esperado.

ILabelProvider incluye alguna función más. A partir del contenido de un visor (que se deriva del elemento de entrada y del proveedor de contenido), puede producir los elementos de UI específicos, como nombres e iconos, que se necesitan para visualizar el contenido del visor. Los proveedores de etiquetas pueden ayudar a guardar recursos de iconos ya que aseguran que se utiliza la misma instancia del icono para todos los tipos en un visor.

Nota:  Las instancias de proveedores concretos de contenido y etiquetas no están pensadas para compartirse entre varios visores. Incluso si todos los visores utilizan el mismo tipo de proveedor de contenido o etiquetas, cada visor debe inicializarse con su propia instancia de clase de proveedor. El protocolo de ciclo de vida de proveedor está diseñado para que entre un proveedor y su visor haya una relación de igual a igual.  

Los elementos de entrada, los proveedores de contenido y los proveedores de etiquetas permiten a los visores ocultar la mayoría de los detalles de implementación para rellenar widgets. Los clientes de un visor sólo necesitan preocuparse de rellenar el visor con el tipo de entrada y el proveedor de contenido correctos. El proveedor de etiquetas debe saber cómo derivar la información de la UI del contenido del visor.

Visores y entorno de trabajo

La versatilidad que los visores, los proveedores de contenido y los proveedores de etiquetas proporcionan queda patente al ver cómo el entorno de trabajo los utiliza.

El WorkbenchContentProvider es un proveedor de contenido estructurado que obtiene el contenido de un elemento de entrada pidiendo sus hijos. Se vuelve a utilizar el concepto de adaptadores para implementar una función genérica. Cuando se pide la lista de elementos de su elemento de entrada, WorkbenchContentProvider obtiene un IWorkbenchAdapter para el elemento de entrada. Si se ha registrado un IWorkbenchAdapter para el elemento de entrada, el proveedor de contenido puede presuponer con seguridad que se puede solicitar al elemento información sobre sus hijos.  WorkbenchContentProvider también lleva acabo el trabajo necesario para mantener su visor actualizado cuando se modifica el área de trabajo. 

El WorkbenchLabelProvider es un proveedor de etiquetas que obtiene un IWorkbenchAdapter de un objeto al objeto de buscar su texto y su imagen. El concepto de proveedor de etiquetas resulta particularmente satisfactorio en objetos de entorno de trabajo porque permite a un solo proveedor de etiquetas guardar en antememoria imágenes que se utilizan habitualmente en un visor. Por ejemplo, en cuanto el WorkbenchLabelProvider obtiene una imagen para utilizarlos en un IProject, puede guardar en antememoria dicha imagen y utilizarla en todos los IProject que se muestran en el visor.

Definir un adaptador común, IWorkbenchAdapter, y registrarlo en la mayoría de las distintas plataformas, hace que estas plataformas se representen correctamente en la mayoría de los visores comunes y de la vistas de entorno de trabajo que los contiene.