Extensiones
Explicación de las interfaces y clases implicadas en la creación de Extensiones, y los mecanismos existentes para activar o desactivar extensiones.
- La interfaz IExtension
- La clase abstracta Extension
- HiddableExtension y ExtensionDecorator
- El mecanismo ExclusiveUIExtension
La interfaz IExtension
Como ya hemos explicado, las extensiones son clases que sirven de puente entre la funcionalidad básica de gvSIG y las funcionalidades aportadas por nuestro plugin. La extensión recibirá notificación de las acciones realizadas por el usuario, y ejecutará el código apropiado en respuesta a esas acciones (posiblemente usando otras clases de nuestro plugin).
El siguiente diagrama muestra de forma esquemática todas las clases que vamos a explicar en este capítulo y sus relaciones:
Todas las extensiones implementan la interfaz IExtension, que incluye los siguientes métodos:
- public void initialize() Una vez se leen y ordenan todas las extensiones presentes en los plugins, se llama a este método para cada una de ellas, de forma secuencial siguiendo el orden definido en la prioridad de las extensiones.
- public void postInitialize() Una vez se han inicializado todas las extensiones, se llama a este método para cada una de ellas, siguiendo el mismo orden de antes.
- public void terminate() Al salir de la aplicación, se llama a este método para cada una de las extensiones, siguiendo un orden secuencial inverso al que se siguió en la inicialización (es decir, la última extensión que se inicializó es la primera que se finalizará, y la primera extensión que se inicializó será la última en ser finalizada).
- public void execute(String actionCommand) En el config.xml se definen elementos de la interfaz de usuario (botones, menús, etc) que están asociados a una extensión. Cuando el usuario pulsa en uno de estos elementos de la interfaz, se busca la extensión asociada y se llama a este método. Los botones, menús, etc pueden tener asociado una cadena que actúa como identificador de comando (action command). Cuando se llama al método execute, se pasa como parámetro el actionCommand asociado al botón que se pulsó. De esta forma, si tenemos varios botones, menús, etc asociados con esta extensión, podemos discriminarlos comprobando el actionCommand que recibimos. Normalmente, será en este método donde escribiremos las principales acciones de nuestra extensión (abrir un asistente, comenzar algún procesamiento, etc).
Los dos siguientes métodos determinan si la extensión (y sus elementos de interfaz de usuario asociados) serán visibles y estarán activos. Estas propiedades se comprueban para todas las extensiones cada vez que se cambia de ventana activa y también justo después de procesar un evento de interfaz de usuario (es decir, después de llamar al método execute de una extensión).
- public boolean isEnabled() Los elementos de interfaz de usuario (botones, menús, controles de la barra de estado) asociados a esta extensión estarán activados (o desactivados) dependiendo del valor devuelto por este método. Cuando un botón está desactivado, aparece en gris claro y no es posible pulsar sobre él.
- public boolean isVisible() Los elementos de interfaz de usuario (botones, menús, controles de la barra de estado) asociados a esta extensión estarán visibles (o invisibles) dependiendo del valor devuelto por este método. Cuando un botón está invisible, no se mostrará independientemente del valor de isEnabled().
Los dos métodos siguientes sólo se usan con el mecanismo ExclusiveUIExtension, que permite a una extensión tomar el control de la interfaz y activar o desactivar (mostrar u ocultar) otras extensiones. Esto puede usarse para crear extensiones que personalicen gvSIG (por ejemplo, una extensión que transforme gvSIG en un simple visor de cartografía):
- public boolean isEnabled(IExtension extension) Decide si la extensión pasada como parámetro estará activada o no, ignorando el valor del método isEnabled de la propia extensión.
- public boolean isVisible(IExtension extension) Decide si la extensión pasada como parámetro estará visible o no, ignorando el valor del método isVisible de la propia extensión.
La clase abstracta Extension
Salvo que tengamos una necesidad muy especial, normalmente no implementaremos directamente la interfaz IExtension, sino que extenderemos la clase abstracta Extension, que a su vez ya implementa IExtension. Esto nos ofrece una cierta tranquilidad de futuro en el funcionamiento de nuestra extensión, ya que si se añadiese algún método a la interfaz IExtension, este método se implementaría en la clase Extension de forma que nuestra extensión seguiría funcionando sin cambios (a no ser que necesitase un comportamiento para el nuevo método distinto del implementado en Extension).
HiddableExtension y ExtensionDecorator
La interfaz HiddableExtension y la clase ExtensionDecorator permiten cambiar la visibilidad de una extensión (y sus controles asociados) en tiempo de ejecución, ignorando el valor que indique la propia extensión en el método isVisible. De esta forma podemos instalar una extensión que oculte un conjunto de otras extensiones, creando un gvSIG personalizado (que sólo mostraría las extensiones deseadas).
La interfaz HiddableExtension sólo contiene dos métodos:
- public void setVisibility(int state) Permite definir una visibilidad para una extensión, que prevalece sobre la visibilidad definida en el método isVisible() de la propia extensión. Los valores de visibilidad aceptados incluyen: ExtensionDecorator.INACTIVE (el Decorator está desactivado y por tanto se obedecerá a la establecido en el método isVisible() de la propia extensión), ExtensionDecorator.ALWAYS_VISIBLE (la extensión estará siempre visible) y ExtensionDecorator.ALWAYS_INVISIBLE (la extensión estará siempre invisible).
- public int getVisibility() Consulta la visibilidad que se ha adjudicado a la extensión. Los valores devueltos pueden ser ExtensionDecorator.INACTIVE, ExtensionDecorator.ALWAYS_VISIBLE o ExtensionDecorator.ALWAYS_INVISIBLE.
La clase ExtensionDecorator implementa la interfaz HiddableExtension. Cada extensión cargada por Andami posee un ExtensionDecorator asociado, que podemos obtener para cambiar la visibilidad de esa extensión. Mostramos como ejemplo el código necesario para ocultar la extensión "com.iver.cit.gvsig.StartEditing", que es la que permite poner una capa en edición. De esta forma, estaríamos desactivando las capacidades de edición de gvSIG:
ExtensionDecorator decorator = PluginServices.getDecoratedExtension(com.iver.cit.gvsig.StartEditing.class);
decorator.setVisibility(ExtensionDecorator.ALWAYS_INVISIBLE);
Por supuesto, para llevar a cabo con éxito una personalización de gvSIG, necesitamos conocer las extensiones que deseamos ocultar. Además, para poder acceder correctamente a la clase de la extensión a desactivar (en este ejemplo, com.iver.cit.gvsig.StartEditing.class) necesitamos declarar una dependencia del plugin que contenga la extensión, de lo contrario obtendremos una excepción de tipo ClassNotFoundException al ejecutar ese código. En este caso, com.iver.cit.gvsig.StartEditing.class está contenido en el plugin com.iver.cit.gvsig.cad, por tanto necesitamos añadir al config.xml de nuestro plugin una línea como la siguiente:
<depends plugin-name="com.iver.cit.gvsig.cad" />
Téngase en cuenta que cualquier extensión puede usar este mecanismo en cualquier momento para ocultar o mostrar otra extensión. Para evitar comportamientos impredecibles, ExtensionDecorator sólo debería usarse en extensiones especiales que deseen personalizar gvSIG, y no deberían instalarse dos extensiones de este tipo al mismo tiempo (de lo contrario, es posible que lo que una de ellas vaya ocultando, la otra lo vaya mostrando y será difícil prever el resultado final, salvo que ambas extensiones realicen estas ocultaciones de forma coordinada).
El mecanismo ExclusiveUIExtension
El mecanismo ExclusiveUIExtension permite realizar algo similar a lo que se consigue con ExtensionDecorator, pero en este caso existe una única extensión que decidirá el estado de las demás. Es decir, con ExtensionDecorator cualquier extensión puede modificar el estado de las demás. Con ExclusiveUIExtension, se definirá una única extensión que tendrá la capacidad de mostrar/ocultar y activar/desactivar el resto de extensiones.
En cualquier caso, ambos mecanismos pueden usarse al mismo tiempo y ExclusiveUIExtension respetará lo definido por ExtensionDecorator, de forma que si ExtensionDecorator define una visibilidad ALWAYS_VISIBLE (siempre visible), la extensión estará visible pese a que ExclusiveUIExtension defina la extensión como oculta. Es decir, ExclusiveUIExtension sólo actuará en caso de que el ExtensionDecorator esté inactivo (modo ExtensionDecorator.INACTIVE). En cualquier caso, ExtensionDecorator sólo actúa sobre la visibilidad de la extensión, mientras que el mecanismo ExclusiveUIExtension puede definir también si la extensión está activa (enabled) o no.
Para usar ExclusiveUIExtension necesitamos:
- Tener una extensión que implemente correctamente los métodos isEnabled(IExtension extension) y isVisible(IExtension extension). Esta extensión actuará como ExclusiveUIExtension, decidiendo el estado (visible/invisible, activa/desactivada) del resto de extensiones.
- Registrarse como ExclusiveUIExtension en Andami, dentro del método initialize de nuestra extensión, utilizando el método PluginServices.setExclusiveUIExtension().
- Otra opción equivalente a registrarnos utilizando el método setExclusiveUIExtension consiste en sumistrar un parámetro de arranque a gvSIG. El parámetro es el siguiente: ExclusiveUIExtension=NombreDeExtension, donde NombreDeExtension debe sustituirse por el nombre de la extensión mencionada en el punto anterior.
- En Linux, esto puede conseguirse bien editando el lanzador gvSIG.sh añadiéndole este parámetro antes del símbolo "$@", o bien pasándole el parámetro a dicho lanzador.
- En Windows se puede modificar el fichero gvSIG.ini, en la línea que empieza por command, añadiendo el parámetro justo antes del símbolo #ARGS#. También es posible pasar el parámetro al comando gvSIG.exe en el momento de su ejecución.