Statistics
| Revision:

svn-gvsig-desktop / tags / v1_11_0_Build_1305 / docs / Andami developer guide.html @ 44114

History | View | Annotate | Download (16.6 KB)

1
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2
<html>
3
<head>
4
  <meta content="text/html; charset=ISO-8859-1"
5
 http-equiv="content-type">
6
  <title>Andami developer guide</title>
7
<link href="style.css" rel="stylesheet" type="text/css">
8
</head>
9
<body>
10
<table width="90%" border="0">
11
  <tr>
12
    <td class="Nivel2"><a href="#Introduccion"><strong><font color="#FFFFFF">Introducci&oacute;n</font></strong></a></td>
13
  </tr>
14
  <tr>
15
    <td class="Nivel2"><a href="#Creacion_de_plugins"><font color="#FFFFFF"><strong>Creaci&oacute;n 
16
      de plugins</strong></font></a></td>
17
  </tr>
18
  <tr>
19
    <td class="Nivel2"><a href="#Funcionamiento_del_class_loader"><strong><font color="#FFFFFF">Funcionamiento 
20
      del class loader</font></strong></a></td>
21
  </tr>
22
  <tr>
23
    <td class="Nivel2"><a href="#Servicios_a_los_plugins"><font color="#FFFFFF"><strong>Servicios 
24
      a los plugins</strong></font></a></td>
25
  </tr>
26
  <tr>
27
    <td><strong>&nbsp;&nbsp;&nbsp; <a
28
 href="#Ejecucion_en_segundo_plano">Ejecuci&oacute;n en segundo plano</a></strong></td>
29
  </tr>
30
  <tr>
31
    <td><strong>&nbsp;&nbsp;&nbsp; <a href="#Acceso_a_las_extensiones">Acceso 
32
      a las extensiones</a></strong></td>
33
  </tr>
34
  <tr>
35
    <td class="urbanismo"><strong>&nbsp;&nbsp;&nbsp; <a href="#Persistencia_de_los_plugins">Persistencia 
36
      de los plugins</a></strong></td>
37
  </tr>
38
  <tr>
39
    <td><strong>&nbsp;&nbsp;&nbsp; <a href="#popupmenus">Pop-up menus</a></strong></td>
40
  </tr>
41
  <tr>
42
    <td><strong>&nbsp;&nbsp;&nbsp; <a href="#Vistas">Vistas</a></strong></td>
43
  </tr>
44
  <tr>
45
    <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="#SingletonView">SingletonView's</a></td>
46
  </tr>
47
</table>
48

    
49

    
50

    
51
<p> <strong><font size="+1"><a name="Introduccion"></a>Introducci&oacute;n</font></strong></p>
52
<p> &nbsp;&nbsp;&nbsp; Andami es un framework orientado a plugins construido sobre 
53
  swing que permite la construcci&oacute;n de forma r&aacute;pida y extensible 
54
  de aplicaciones MDI (Multiple Document Interface). Tiene ya implementadas muchas 
55
  de las funcionalidades requeridas para este tipo de aplicaciones tales como 
56
  un men&uacute; Ventana, en la que van apareciendo las ventanas que se abren, 
57
  soporte para el traducciones, configuraci&oacute;n personalizada para cada usuario, 
58
  actualizaciones autom&aacute;ticas, tanto del propio Andami como de los plugins, 
59
  persistencia del tama&ntilde;o y posici&oacute;n de la ventana, del idioma, 
60
  distintos tipos de vista, con la finalidad de facilitar la programaci&oacute;n 
61
  de ventanas especiales, ... Todo esto adem&aacute;s de tener ya solventados 
62
  los problemas t&iacute;picos de la programaci&oacute;n de un entorno como &eacute;ste 
63
  que no son pocos.<br>
64
  <br>
65
  &nbsp;&nbsp;&nbsp; Adem&aacute;s, Andami est&aacute; dise&ntilde;ada de forma 
66
  que la propia l&oacute;gica MDI puede ser reemplazada. Si en lugar de una aplicaci&oacute;n 
67
  estilo arcView, se quiere que cada vista que se a&ntilde;ada, se haga en una 
68
  ventana de windows nueva (de las que aparecen en la barra de estado) o una vista 
69
  como la de Eclipse, no hay m&aacute;s que desarrollar el plugin adecuado.<br>
70
  <br>
71
  &nbsp;&nbsp;&nbsp; Andami est&aacute; dise&ntilde;ada para ser amistosa con 
72
  el usuario y para ello incorpora la posibilidad de a&ntilde;adir tooltips y 
73
  enabletexts a los botones. El tooltip es el texto que aparece cuando el rat&oacute;n 
74
  se detiene sobre un bot&oacute;n o men&uacute;. El enableText es el texto que 
75
  aparece en el caso anterior cuando el bot&oacute;n est&aacute; desactivado, 
76
  permitiendo mostrar al usuario qu&eacute; es lo que debe hacer para que dicho 
77
  bot&oacute;n se active (o cualquier otro mensaje).<br>
78
  <br>
79
  &nbsp;&nbsp;&nbsp; Por &uacute;ltimo, Andami tiene una gesti&oacute;n de errores 
80
  que agradar&aacute; a cualquier programador, ya que en casos de errores graves, 
81
  el propio framework avisa de dicho fallo y aconseja al usuario salvar los cambios 
82
  y reiniciar el programa, a parte de que toda excepci&oacute;n no capturada por 
83
  el usuario se redirige a un fichero de log configurable en el que se escribir&aacute; 
84
  su traza.<br>
85
</p>
86
<p> <strong><font size="+1"><a name="Creacion_de_plugins"></a>Creaci&oacute;n 
87
  de plugins</font></strong></p>
88
<p> &nbsp;&nbsp;&nbsp; Andami gira en torno al concepto de plugin. Andami mantiene 
89
  un directorio como directorio de los plugins, que se puede cambiar en cualquier 
90
  momento. Un plugin viene definido por la existencia de un subdirectorio dentro 
91
  del directorio de los plugins, siendo el nombre del plugin el nombre de dicho 
92
  directorio. Dentro de dicho directorio debe haber un fichero config.xml en el 
93
  que se configuran los puntos de entrada y salida del plugin (men&uacute;es, 
94
  barras de herramientas, etiquetas de la barra de estado, men&uacute;es contextuales), 
95
  las librer&iacute;as que va a usar, el paquete de traducciones, los plugins 
96
  de los que depende, etc. El fichero plugin-config.xsd contiene el esquema que 
97
  ha de seguir este fichero y est&aacute;n comentados todos los elementos. En 
98
  el CorePlugin que viene con Adami se puede ver un ejemplo de config.xml.<br>
99
  <br>
100
  &nbsp;&nbsp;&nbsp; Las rutas de los directorios son siempre relativas al directorio 
101
  del plugin y los textos de los men&uacute;es, tooltips y enabletext's son claves 
102
  en el fichero de traducciones en caso de que haya y textos literales en caso 
103
  de que no haya traducciones. El fichero de traducciones es un fichero de propiedades 
104
  com&uacute;n: ver ResourceBundle en la API de Java.<br>
105
  <br>
106
  &nbsp;&nbsp;&nbsp; Dentro de los plugins aparece el concepto de extensi&oacute;n. 
107
  Una extensi&oacute;n es instalada por los plugins mediante la implementaci&oacute;n 
108
  de la interfaz com.iver.andami.plugins.Extension y la instalaci&oacute;n de 
109
  unos controles geobernados por &eacute;sta en el fichero config.xml. Mediante 
110
  esta implementaci&oacute;n se le dice a Andami la condici&oacute;n que se debe 
111
  cumplir para que los controles sean visibles o est&eacute;n activos. Adem&aacute;s 
112
  se implementa la acci&oacute;n a llevar a cabo cuando se selecciona uno de los 
113
  men&uacute;es o botones asociados a la extensi&oacute;n. Cabe resaltar que Andami 
114
  crea una instancia de cada extensi&oacute;n configurada en config.xml, por lo 
115
  que las clases que implementen la interfaz Extension deben de tener un constructor 
116
  sin argumentos.<br>
117
  <br>
118
  &nbsp;&nbsp;&nbsp; En los tag 'extension' existe un atributo class-name en el 
119
  que se especifica la clase que gobierna el punto de extensi&oacute;n que se 
120
  est&aacute; definiendo. Esta clase deber&aacute; implementar la interfaz com.iver.andami.plugins.Extension 
121
  y ser&aacute; mediante &eacute;sta que gobernar&aacute; los men&uacute;es y 
122
  botones asociados a este punto de extensi&oacute;n<br>
123
  <br>
124
  &nbsp;&nbsp;&nbsp; Una problema com&uacute;n en este framework es no ver c&oacute;mo 
125
  se mantiene la informaci&oacute;n del proyecto concreto que se est&aacute; desarrollando. 
126
  El lugar adecuado es una de las extensiones instaladas. Por ejemplo en el caso 
127
  de gvSIG est&aacute; la extensi&oacute;n com.iver.cit.gvsig.ProjectExtension, 
128
  en la cual hay un atributo Project que es la ra&iacute;z del &aacute;rbol jer&aacute;rquico 
129
  del cual penden las vistas, mapas, tablas, ... Adem&aacute;s esta extensi&oacute;n 
130
  tiene un m&eacute;todo getProject que devuelve la referencia al proyecto, de 
131
  manera que se puede acceder desde cualquier punto de la aplicaci&oacute;n. Para 
132
  ver el acceso a las instancias de las extensiones ver <a href="#Acceso_a_las_extensiones">acceso 
133
  a las extensiones</a></p>
134
<p><br>
135
  <font size="+1"><strong><a name="Funcionamiento_del_class_loader"></a>Funcionamiento 
136
  del class loader</strong></font></p>
137
<p> En Andami, el class loader de cada plugin delega primero en el classloader 
138
  del sistemaes decir, que si se ejecuta desde eclipse buscar&aacute; por todos 
139
  los jars que haya en el classpath del proyecto, y si se ejecuta desde la linea 
140
  de comandos, buscar&aacute; en la variable de entorno CLASSPATH o en el argumento 
141
  -classpath que se pase como par&aacute;metro a java.<br>
142
  <br>
143
  Si el class loader del sistema no satisface la b&uacute;squeda, se buscar&aacute; 
144
  en los jars del directorio especificado por el config.xml del plugin que intenta 
145
  cargar la clase y si no se encuentra en dichos jars, se buscar&aacute; en los 
146
  jars de los plugins de los cuales depende el plugin que intenta cargar la clase.<br>
147
  <br>
148
  <strong><font size="+1"><a name="Servicios_a_los_plugins"></a>Servicios 
149
  a los plugins</font></strong></p>
150
<p><br>
151
&nbsp;&nbsp;&nbsp; Andami ofrece a los plugins distintos servicios 
152
  a trav&eacute;s de la clase PluginServices en cuyo javadoc se puede obtener 
153
  informaci&oacute;n sobre como usarlos. Existen unos servicios gen&eacute;ricos 
154
  que vienen dados por m&eacute;todos est&aacute;ticos de dicha clase y luego 
155
  est&aacute; el m&eacute;todo getPluginServices que obtiene una instancia de 
156
  esta clase espec&iacute;fica del plugin, mediante la cual puede acceder a servicios 
157
  concretos de cada plugin, traducciones, persistencia, directorio del plugin, 
158
  ...<br>
159
  &nbsp;<br>
160
  <strong><a name="Ejecucion_en_segundo_plano"></a>Ejecuci&oacute;n en segundo 
161
  plano</strong><br>
162
  &nbsp;&nbsp;&nbsp; Es conveniente que la interfaz gr&aacute;fica est&eacute; 
163
  siempre en funcionamiento, nunca bloqueada, aunque sea s&oacute;lo para mostrar 
164
  al usuario que el programa est&aacute; procesando. Para ello hay que realizar 
165
  las tareas que puedan tomar demasiado tiempo en un thread a parte. La clase 
166
  PluginServices proporciona un m&eacute;todo est&aacute;tico backgroundExecution 
167
  al cual se le pasa un objeto Runnable, que es ejecutado en segundo plano, dejando 
168
  el thread de la interfaz libre para responder pero con sus eventos bloqueados 
169
  con el fin de que la interfaz responda y se redibuje, pero se ignoren los eventos 
170
  que produce el usuario mientras se procesa la petici&oacute;n<br>
171
  <br>
172
  <a name="Acceso_a_las_extensiones"></a><strong>Acceso a las extensiones</strong><br>
173
  &nbsp;&nbsp;&nbsp; Para acceder a la instancia de una extensi&oacute;n 
174
  se puede usar simplemente el m&eacute;todo de PluginServices getExtension(Class) 
175
  a la cual habr&aacute; que pasar como par&aacute;metro la clase de la extensi&oacute;n 
176
  a la que se quiere acceder. Dicho m&eacute;todo retorna un objeto Extensi&oacute;n 
177
  y por tanto habr&aacute; que hacer casting a la clase concreta de dicha extensi&oacute;n, 
178
  habiendo obtenido as&iacute; la referencia a la instancia de la extensi&oacute;n 
179
  deseada.<br>
180
  &nbsp;&nbsp;&nbsp; A la hora de desarrollar habr&aacute; que tener en el build 
181
  path del entorno de desarrollo que se use, el jar del plugin dentro del cual 
182
  est&aacute; la extensi&oacute;n que se quiere obtener, para poder pasarle como 
183
  par&aacute;metro a getExtension(Class) la clase de la misma.<br>
184
  <br>
185
  <strong><a name="Persistencia_de_los_plugins"></a>Persistencia de 
186
  los plugins</strong><br>
187
  &nbsp;&nbsp;&nbsp; Uno de los servicios que ofrece Andami a los 
188
  plugins es la facilidad de guardar datos gen&eacute;ricos de los mismos en el 
189
  directorio del usuario de manera que cada usuario mantiene su propia configuraci&oacute;n 
190
  de los plugins. Para ello, las instancias de PluginServices contienen una propiedad 
191
  persistentXML que puede ser obtenida y asignada y que es de tipo XMLEntity, 
192
  pudiendo a&ntilde;adir informaci&oacute;n de tipo b&aacute;sico (String, int, 
193
  long, ...) a dicha instancia y siendo esta informaci&oacute;n persistente entre 
194
  ejecuciones.<br>
195
  <br>
196
  <strong><a name="popupmenus"></a>Pop-up menus</strong><br>
197
  &nbsp;&nbsp;&nbsp;&nbsp; Otro servicio proporcionado por Andami es el de pop-up 
198
  menu's extensibles. Mediante el XML se puede definir un pop-up menu con un nombre 
199
  y unas entradas al igual que cualquier otro men&uacute;, con la &uacute;nica 
200
  diferencia que para mostrar el popup men&uacute; habr&aacute; que registrar 
201
  un listener de la siguiente manera:<br>
202
</p>
203
<div style="text-align: center;">
204
<pre><>public void addPopupMenuListener(String name, Component c, ActionListener listener)</><br></pre>
205
</div>
206
&nbsp;&nbsp;&nbsp; Lo cual har&aacute; que al pinchar con el
207
bot&oacute;n derecho sobre el componente 'c' aparezca el men&uacute;
208
'name' del fichero de configuraci&oacute;n del plugin y al seleccionar
209
cualquier entrada se ejecutar&aacute; el ActionListener que se pasa
210
como par&aacute;metro.<br>
211
<br>
212
&nbsp;&nbsp;&nbsp; Estos men&uacute;es son extensibles porque cualquier
213
otro plugin puede a&ntilde;adir entradas a dicho men&uacute; en su
214
propio fichero config.xml referenciando el men&uacute; al que quiere
215
extender mediante el nombre del plugin m&aacute;s el nombre del
216
men&uacute;. Un ejemplo. Tenemos un plugin llamado com.iver.cit.gvsig
217
que instala un men&uacute; de la siguiente manera:<br>
218
<pre>                &lt;popupMenu name="cascada"&gt;<br>                        &lt;entry text="Cascada" <br>                                tooltip="cascada_tooltip" <br>                                enableText="cascada_enable" actionCommand="CASCADA"/&gt;<br>                        &lt;entry text="Tile" <br>                                tooltip="tile_tooltip" <br>                                enableText="cascada_enable" actionCommand="CASCADA"/&gt;<br>                &lt;/popupMenu&gt;<br></pre>
219
y tenemos otro plugin que quiere a&ntilde;adir una entrada a dicho
220
men&uacute;. Para ello deber&aacute; de incluir un fragmento similar a
221
este en su fichero config.xml:<br>
222
<pre>                &lt;popupMenu name="com.iver.cit.gvsig.cascada"&gt;<br>                        &lt;entry text="Nueva entrada" actionCommand="NUEVA"/&gt;<br>                &lt;/popupMenu&gt;<br></pre>
223
y adem&aacute;s deber&aacute; de registrarse como listener de la manera
224
que se explic&oacute; anteriormente.<br>
225
<br>
226
<strong><a name="Vistas"></a>Vistas</strong><br>
227
&nbsp;&nbsp;&nbsp; El servicio m&aacute;s importante que
228
proporciona Andami es el de a&ntilde;adir vistas al marco principal.
229
Podemos calsificar las vistas por varios criterios:<br>
230
<ul>
231
  <li>Por su modalidad</li>
232
  <ul>
233
    <li>Modales</li>
234
    <li>No modales</li>
235
  </ul>
236
</ul>
237
<ul>
238
  <li>Por su contenido</li>
239
  <ul>
240
    <li>Singleton (Contenido identificable)</li>
241
    <li>Normales (Contenido no identificable)</li>
242
  </ul>
243
</ul>
244
&nbsp;&nbsp;&nbsp; Para crear una vista hay que hacer una clase que
245
derive de JPanel en la que se pone toda la funcionalidad como si de un
246
di&aacute;logo normal se tratara. Adem&aacute;s esta clase ha de
247
implementar la interfaz View la cual proporciona un m&eacute;todo
248
getViewInfo que es invocado una vez en la vida de la vista. Este objeto
249
contiene las caracter&iacute;sticas que tendr&aacute; la vista:
250
maximizable, resizable, title, ... y puede ser actualizado en cualquier
251
momento, reflej&aacute;ndose estos cambios de manera autom&aacute;tica
252
en la interfaz de usuario. Una vez implementada la vista, hay que
253
a&ntilde;adirla al manger MDI, que es el encargado de manejar toda la
254
l&oacute;gica relacionada con las vistas. Para obtener una referencia
255
al manager MDI la clase PluginServices tiene un m&eacute;todo
256
getMDIManager, el cual a su vez tiene un m&eacute;todo addView mediante
257
el cual se puede a&ntilde;adir la vista.<br>
258
<br>
259
&nbsp;&nbsp;&nbsp; Si durante la ejecuci&oacute;n se quiere cambiar
260
alguna propiedad de la vista tal como el tama&ntilde;o, la
261
posici&oacute;n o el
262
t&iacute;tulo, s&oacute;lo hay que acceder al objeto ViewInfo de la
263
misma y realizar los cambios de la manera deseada. El siguiente trozo
264
de c&oacute;digo cambia el t&iacute;tulo de una ventana (se supone que
265
es ejecutado desde la clase que implementa View).<br>
266
<pre>        PluginServices.getMDIManager().getViewInfo(this).setTitle("Nuevo t&iacute;tulo");<br></pre>
267
&nbsp;&nbsp;&nbsp; Puede ser necesario que algunas vistas realicen
268
alg&uacute;n tipo de procesamiento al ser activadas pero esto no se
269
sabe cuando ocurre ya que lo que se entrega al manager MDI es un
270
JPanel. Para recibir los eventos sobre las vistas, adem&aacute;s de
271
implementar View hay que implementar ViewListener la cual
272
proporcionar&aacute; los m&eacute;todos que ser&aacute;n invocados
273
cuando sucedan los eventos oportunos en las vistas.<br>
274
<br>
275
<big><a name="SingletonView"></a>SingletonView<br>
276
</big>&nbsp;&nbsp;&nbsp; Un tipo especial de vistas son las
277
SingletonView. Su principal caracter&iacute;stica es que se les define
278
el contenido de las mismas, de manera que cuando hay una SingletonView
279
minimizada en el proyecto y se intenta a&ntilde;adir un JPanel con el
280
mismo contenido, en lugar de aparecer otra ventana en el escritorio, lo
281
que sucede es que la ventana que estaba minimizada se restaura a su
282
posici&oacute;n anterior. Para esto, el m&eacute;todo addView devuelve
283
una referencia a la vista que se muestra, sea esta la que se
284
est&aacute; a&ntilde;adiendo o la que ya est&aacute; a&ntilde;adida.
285
Adem&aacute;s, al cerrar dicha ventana se guardan las dimensiones y la
286
posici&oacute;n de las mismas, de manera que al volverla a abrir se
287
recuerdan estos datos.<br>
288
</body>
289
</html>