1. Introducción


2.Drivers


    2.1 Drivers de lectura


    2.2 Drivers de escritura

 

3.Filtros

 

    3.1 Creación de un nuevo filtro


    3.2 Gestión de un nuevo filtro


4.Interfaces Gráficas


    4.1 Interfaz de Propiedades


    4.1 Interfaz de salvar a raster

1.Introducción

    La librería de Cresques consta de los siguientes elementos:

2. Drivers

    Los drivers de Cresques son clases que contiene un interfaz de acceso a un tipo de fichero a través de una librería o implementando sus propias funcionalidades. Para el acceso a Ecw, MrSID y Gdal utiliza librerias externas en C por lo que deberán estar instaladas correctamente para hacer uso de estos drivers. Las librerias externas al estar en C necestan un interfaz para el uso desde java. Este interfaz puede constar de otra librería en C que debe estar también instalada y un fichero .jar con las funciones en java de acceso a la librería que debe estar en el classpath. El directorio depend del proyecto de Cresques contiene las librerias C necesarias y el directorio lib las de java.

    Los drivers de lectura y escritura para un mismo tipo de fichero están separadas en clases disintas.

2.1 Drivers de lectura

    El nombre de la clase de un driver de lectura está compuesto por el tipo de fichero al que accede seguido de la palabra File, así tenemos los siguientes drivers de lectura:

    Los drivers de lectura de acceso a raster hereda todos de una misma clase abstracta GeoRasterFile para darles a todos ellos una interfaz homogenea de acceso a los datos. Los drivers que dependen de GeoRasterFile deben usar un mecanismo de registro para ser accesible. Este mecanismo permite que si creamos un driver fuera de cresques pero que herede de GeoRasterFile sea reconocido por este y pueda accederse a su funcionalidad. Para el registro, el driver en cuestión deberá incluir un bloque static en su código y añadir una entrada en la variable TreeMap supportedExtensions de GeoRasterFile con el nombre del driver y la clase que lo implementa. Esto se hará con la función registerExtension. Por ejemplo, si quisieramos hacer un driver para acceso a Jpg que use nuestra propia librería le incluiriamos un código como este:


          static {
                registerExtension("jpg",  JpgGeoRefFile.class);
          }


    Sin necesidad de instanciar la nueva clase se ejecutará el bloque static asignando a la gestión de la extensión jpg la nueva clase creada. Como esta nuevo driver heredará de GeoRasterFile tendrá el interfaz necesario para acceso a los datos por lo que no habrá ningún problema. Por lo tanto, los métodos abstractos de GeoRasterFile son de obligatoria implementación en nuestro driver. Los drivers de GeoRasterFile están registrados en esta misma clase ya que son drivers que no varian dentro de Cresques.


2.2 Drivers de escritura

    El nombre de la clase de un driver de escritura está compuesto por el tipo de fichero al que accede seguido de la palabra Writer, así tenemos los siguientes drivers de lectura:


    Estos drivers son para la escritura de ficheros raster georeferenciados.


    Los drivers de escritura en raster georeferenciados deben heredar de la misma clase abstracta GeoRasterWriter para darles a todos ellos una interfaz homogenea de escritura de datos. Los drivers que dependen de GeoRasterFile deben usar un mecanismo de registro para ser accesible. Este mecanismo permite que si creamos un driver fuera de cresques pero que herede de GeoRasterWriter sea reconocido por este y pueda accederse a su funcionalidad. Para el registro, el driver en cuestión deberá incluir un bloque static en su código y añadir una entrada en la variable TreeMap supportedExtensions de GeoRasterFile con el nombre del driver y la clase que lo implementa. Esto se hará con la función registerWriterExtension. Por ejemplo, si quisieramos hacer un driver de escritura en Jpg que use nuestra propia librería le incluiriamos un código como este:


          static {
                registerWriterExtension("jpg",  JpgGeoRefWriter.class);
          }


    Dentro del driver tendremos que escribir una clase que deberá llamarse <NombreFormato>SupportOptions y que deberá heredar de WriterSupportOptions. Esta clase contendrá las opciones de escritura concretas para este formato. Esta opciones son las que el usuario visualizará en la ventana de propiedades de escritura. Es conveniente que las opciones que corresponderan a una lista de selección (combo) se guarden aquí como un vector de Strings o cualquier otro tipo de lista de esta forma:

        private String[]                formatList = {"NONE","UINT8","YUV","MULTI","RGB"};

y además se definan variables para los valores seleccionados por defecto


    Deben crearse métodos para la lectura y escritura de todas las propiedades


El constructor estará vacio en funcionalidades pero llamará al constructor del padre pasando como parámetro un string que identifica al driver.

        EcwSupportOptions(){
                super("Ecw");
        }

    Constructor sin parámetros:


    Este constructor inicializa el xxxSupportOptions que contiene las opciones de escritura y asigna valores a estas opciones especificas del driver que estamos implementando

         public EcwWriter(){
                this.support = new EcwSupportOptions();
                this.driver = "ecw";
                this.support.setBlockSize(64);
                this.support.setCompressionDefault(10); 
                this.support.setFormatDefault(4);
                this.support.setWriteGeoref(true);
                this.ident = "Ecw";
                this.consulta = true;
                
        }

    Constructor para salvar una sola imagen completa

         public EcwWriter(      PxRaster raster, 
                        String outfilename, 
                        String infilename, 
                        int compresion)throws EcwException, IOException 

    Para este constructor se ha de pasar como parámetro el PxRaster de la imagen que se desea salvar a disco. Se inicializará la clase xxxSupportOptions de la misma forma que en el constructor anterior y se asignarán valores a variables de instancia con datos para salvar a raster tales como georeferenciación, número de bandas, ancho, alto, tamaño de pixel, ...


    Los drivers de escritura diseñan su propia ventana de propiedades en java. Para ello tiene un método getXMLPropertiesDialog que dice como será esta ventana. Para ello debe devolver una cadena de texto con un XML que contiene esta configuración. El Xml deberá comenzar definiendo el tamaño de la ventana de esta forma:

<window sizex="340" sizey="180">
... Cuerpo de la ventana ...
</window>

    Dentro del cuerpo de la ventana deberán definirse los panels con los componentes. Solo está permitido un nivel de anidamiento y el uso de Checkbox, labels, combos, sliders.

<panel sizex="330" sizey="170" layout="FlowLayout" border="yes" >
</panel>

<label>Tamaño bloque:
</label>

<combo ident="BLOCKSIZE" selected="64">
  <elem>32</elem>
  <elem>64</elem>
  <elem>128</elem>
</combo>

<check ident="GEOREF" selected="10”>
</check>

    Las opciones del driver que se incorporan pueden ser almacenadas y consultadas en una clase que herede de WriteSupportOptions. WriterSupportOptions contiene todas las opciones de salvado comunes a todos los drivers. Por ejemplo, el driver de escritura de ecw tendrá una clase EcwSupportOptions con las opciones especificas de salvado.

    El salvado a raster puede realizarse en dos modos:

3. Filtros

3.1 Creación de un nuevo filtro

    Crear una nueva clase abstracta que heredará de RasterFilter y que tendrá como nombre el nombre del filtro (en inglés a poder ser) seguido de Filter. Usaremos como ejemplo la generación del filtro de transparencia. En este caso, esta clase abstracta debe llamarse TransparencyFilter.

    Crear una clase que hereda de esta clase que hemos creado para cada tipo de dato básico que se da soporte. En nuestro caso dos clases heredan de TransparencyFilter y son TransparencyImageFilter y TransparencyShortFilter. Notese que la nomenclatura hace referencia al tipo de dato que maneja. La primera funciona para objetos Image de java y la segunda para imágenes de 16 bits.Estas últimas están representadas por una clase llamada RasterBuf. Si fuera necesario debería hacerse para Float, Double, ...

    El constructor de los filtros es recomendable que esté vacio.

    En la clase base del filtro que estamos creando (TransparencyFilter) deben ponerse las variables de instancia que contengan los parámetros necesarios para el filtro. En este caso tendriamos 3 vectores bidimensionales que contendran los intervalos de valores a poner como transparentes y cuatro enteros que representan el alpha y el color de transparencia en caso de querer proporcionar alguno. Por defecto será blanco, es decir totalmente transparente y sin ninguna tonalidad.

    Aquí deben ponerse también todas las funcionalidades comunes a todos los tipos de filtro de transparencia. Como TransparencyFilter hereda de RasterFilter que es abstracta y tiene métodos abstractos obligará a implementar estos. Si es necesario que estos métodos abstractos tengan código podemos implementarlos aquí sino podrá hacerse en las clases hijas que contienen la especificación para el filtro de transparencia sobre cada tipo de dato concreto. Los métodos abstractos que es preciso implementar son:

    Aquí pondremos las operaciones que hay que realizar antes de ejecutar el filtro que estamos creando. En nuestro caso está implementado en la clase base del filtro y en las hijas . En la clase base tiene código común para los filtros de transparencia de cualquier tipo de datos.

        public void pre(){
                this.rangesR = (int[][])params.get("red");
                this.rangesG = (int[][])params.get("green");
                this.rangesB = (int[][])params.get("blue");
                this.alpha = ((Integer)params.get("alpha")).intValue();
                this.transparencyColorRed = ((Integer)params.get("transparencyRed")).intValue();
                this.transparencyColorGreen = ((Integer)params.get("transparencyGreen")).intValue();
                this.transparencyColorBlue = ((Integer)params.get("transparencyBlue")).intValue();
        }

    En las clases hijas se pone la implementación concreta para ese tipo de dato. En el caso de la transparencia sobre un Image obtenemos el parámetro que contiene la Image y asignamos los valore de altura y anchura de raster a partir de este Image. Antes de finalizar llama al pre() de TransparencyFilter.

        public void pre(){
                this.image = (Image)params.get("raster");
                height = image.getHeight(null);
                width = image.getWidth(null);
                super.pre();
        }

    Aquí se ponen las operaciones a realizar después de ejecutar el filtro. En el caso que estamos viendo no es necesario hacer nada por lo que estará vacio. Podria ser necesario alguna operación como por ejemplo cargar el resultado de la operación en alguna variable de salida o algo así.

    Este método es el encargado de procesar el filtro para un pixel de la imagen. La clase abstracta RasterFilter de la cual heredan todos los filtros tiene el metodo execute() que hará lo siguiente:

                pre();
                     for (int y=0; y<height; y=y+incY)
                        for (int x=0; x<width; x=x+incX) {
                                process(x, y);
                        }
                post();

    Por esto debemos tener en process el código que ejecuta el filtro. Esto siempre suele rellenarse en las clases que representan a un filtro de un tipo de dato concreto. Para nuestro ejemplo en TransparencyImageFilter el process tendrá el siguiente código:

        public void process(int x, int y) {
                int pt = ((BufferedImage) image).getRGB(x,y);
                int []px4 = {(pt & 0xff000000) >> 24,(pt & 0xff0000) >> 16, (pt & 0x00ff00) >> 8, (pt &                                 0x0000ff)};
                if(rangesR!=null)
                        processRange(rangesR, 1, px4);
                if(rangesG!=null)
                        processRange(rangesG, 2, px4);
                if(rangesB!=null)
                        processRange(rangesB, 3, px4);
                ((BufferedImage) image).setRGB(x,y, (
                        (px4[0] << 24) & 0xff000000 | (px4[1] << 16) & 0x00ff0000 |
                        (px4[2] << 8)  & 0x0000ff00 | (px4[3] & 0x0000ff) ));
        }



    Esta función obtendrá el pixel del buffer lo procesará y salvará el resultado sobre el mismo buffer.

    Esta función realizará el mismo proceso que process(int x, int y) pero aplicada directamente a una línea del buffer.

    Devuelve el tipo de dato del buffer de entrada. La clase RasterBuf tiene constantes que tiene todos los tipos de datos posibles por lo que puede realizarse algo así:

        public int getInRasterDataType(){
                return RasterBuf.TYPE_IMAGE;
        }       

    Devuelve el tipo de dato del buffer de salida. La clase RasterBuf tiene constantes que tiene todos los tipos de datos posibles por lo que puede realizarse algo así:

        public int getOutRasterDataType(){
                return RasterBuf.TYPE_IMAGE;
        }

    Obtiene el resultado del filtro en un Object. Para esto se la pasa un parámetro con la clave del resultado y nos devolverá el Object correspondiente. Esto es necesario porque un mismo filtro puede tener varias salidas, por ejemplo puede tener un raster con el resultado de aplicar el filtro y una clase con algunas estadisticas calculadas en el proceso. En este caso el filtro de transparencia solo devuelve un raster de salida por lo que se hará una función por tipo de dato tal que:

        public Object getResult(String name){
                if(name.equals("raster"))
                        return (Object)this.image;
                else 
                        return null;
        }

    Esta es la que se hará para TransparencyImageFilter ya que devuelve un tipo Image.


 
3.2 Gestión de un nuevo filtro

    Para el almacenaje de filtros seleccionados hay una clase llamada RasterFilterStack que contiene la pila de filtros y que es generica para cualquier tipo de filtro realizado, es decir, en condiciones normales, en la creación de un nuevo filtro esta clase no debe tocarse. Sin embargo si debe añadirse la gestión del nuevo filtro con filterStackManager . Para añadir este nuevo filtro deberá crearse una nueva clase que heredará de RasterFilterStackManager. RasterFilter esla encargada de añadir filtros a la pila ya que ella es la que sabrá el orden en el que deben ir estos . Un orden de la pila incorrecto da un resultado de aplicaciones de filtros indeseado. Con esto deducimos que la pila es tratada como tal para la ejecución de filtros pero que estos deben estar de antemano ordenados correctamente por lo que no es una pila en el sentido estricto.

    Este nuevo gestor de filtros deberá implementar la interfaz StackManager de forma que la definición de nuestra nueva clase sería más o menos asi:

public class PruebaStackManager extends RasterFilterStackManager implements StackManager{
...
}

    Para el nuevo filtro debe añadirse en esta nueva clase una constante que represente el tipo del nuevo filtro. Lo más lógico es darle un número de orden consecutivo a las que hay pero podría asignarse otro en caso de haber una causa justificada. Las actualmente asignadas en la RasterFilterStackManager son

        transparency = 0;
        enhanced=1;
        computeminmax=2;
        tail=3;

    El vector order de RasterFilterStackManager contiene la forma de ordenación de los filtros de la pila. Este orden es importante, por ejemplo la transparencia debe aplicarse despues del realce de la imagen ya que esta se aplica a rangos de colores y antes o después del realce los rangos de colores difieren por lo que la transparencia debe aplicarse sobre la imagen realzada y no al revés. Para asignar este nuevo order deberemos indicarlo en el constructor de esta clase que hemos creado.

        public PruebaStackManager(RasterFilterStack filterStack){
                super(filterStack);
                addTypeFilter("prueba", PruebaStackManager.prueba, 2);
        }



    Habrá que elegir una posición para el nuevo filtro creado para que produzca el resultado deseado. La función addTypeFilter tendrá como parámetros en nombre del filtro, constante asignada y posición para la ordenación. Si introducimos el nuevo filtro en la posición 3 la ordenación inicial:

computeminmax, tail, enhanced, transparency 



quedará

computeminmax, tail, prueba, enhanced, transparency 



ya que la posición en el vector de ordenación tiene en cuenta la posición 0.

    En RasterFilterStackManager también existe una función llamada getType que devuelve el tipo de filtro que contiene un RasterFilter. Deberemos añadir el nuestro para una correcta gestión. Para ello sobrescribiremos el método getType de esta forma:

        public int getType(RasterFilter rasterFilter){
                if(rasterFilter instanceof <<NuestoFiltro>>)
                        return PruebaStackManager.<<Nuestra constante>>;
                                        
                return super.getType(rasterFilter);
        }



sustituyendo <<NuestroFiltro>> por el nombre de la clase abstracta base del filtro que hemos construido y <<Nuestra constante>> por la constante que representa nuestro filtro.

    Dentro de nuestra clase habrá que definir una función para añadir el nuevo filtro. Esta función debe tener como argumentos los parámetros necesarios para el nuevo filtro. En el caso de un filtro de transparencia podrian ser los intervalos para RGB y el color de transparencia.

    En esta función hay que hacer algunas acciones obligatorias y otras opcionales. Podemos verlas sobre un ejemplo:

    Cabecera de la función ya comentada:



                public void addTransparencyFilter(      int[][] red,
                                                        int[][] green,
                                                        int[][] blue,
                                                        int alpha,
                                                        int transparencyRed,
                                                        int transparencyGreen,
                                                        int transparencyBlue){
                

    Es necesario crear un RasterFilter de un tipo u otro dependiendo del tipo de dato que nos diga la pila que necesita. El método filterStack.getDataTypeInFilter(RasterFilterStackManager.transparency) devuelve el tipo de dato que necesitamos si el filtro que vamos a meter es de transparencia. Esta función de la pila calculará en que posición debe ir el filtro y que tipo de dato devuelve el que tendrá por encima, por lo tanto sabremos de que tipo es el filtro que debemos crear. Podemos hacer la selección con un switch de esta forma:

                RasterFilter filtro = null;
                switch(filterStack.getDataTypeInFilter(((Integer)typeFilters.get("transparency")).intValue())){
                        case RasterBuf.TYPE_IMAGE:filtro = new TransparencyImageFilter();break;
                        case RasterBuf.TYPE_SHORT:
                        case RasterBuf.TYPE_USHORT:
                        case RasterBuf.TYPE_INT:filtro = new TransparencyShortFilter();break;
                }



    Si tiene parámetros deberemos añadirlos al filtro creado con addParam. Cada parámetro debe ser añadido con una clave. Esta debe coincidir con la que definimos para su recuperación en el método pre() del filtro.

                if(red != null)filtro.addParam("red", red);
                if(green != null)filtro.addParam("green", green);
                if(blue != null)filtro.addParam("blue", blue);
                filtro.addParam("alpha", new Integer(alpha));
                filtro.addParam("transparencyRed", new Integer(transparencyRed));
                filtro.addParam("transparencyGreen",  new Integer(transparencyGreen));
                filtro.addParam("transparencyBlue",  new Integer(transparencyBlue));

    En este momento podriamos añadir el filtro a la pila con addFilter si no necesitara ninguna restricción. En este caso tenemos que añadir código para comprobar que si hay filtros equivalentes no será necesario añadir el nuevo o si hay varios filtros de transparencia que están contenidos en el nuevo tendremos que eliminar estos y añadir el nuevo.

                //Elimina los filtros que son equivalentes a este

                for(int i=0;i<filterStack.lenght();i++){
                        if( filterStack.get(i) instanceof TransparencyImageFilter ||
                                filterStack.get(i) instanceof TransparencyShortFilter){
                                 
                                //Si este filtro es equivalente a uno de la pila se elimina este
                                if(((TransparencyFilter)filtro).isEquivalent((TransparencyFilter)filterStack.get(i)))
                                        filterStack.removeFilter(filterStack.get(i));   
                                
                        }       
                }
                //Añade el filtro si no hay uno equivalente 
                
                boolean equivalentFilter = false;
                for(int i=0;i<filterStack.lenght();i++){
                        if( filterStack.get(i) instanceof TransparencyImageFilter ||
                                filterStack.get(i) instanceof TransparencyShortFilter){
                                
                                //Si no existe en la pila un filtro equivalente se añade
                                if(((TransparencyFilter)filterStack.get(i)).isEquivalent((TransparencyFilter)filtro)){
                                        equivalentFilter = true;
                                        break;
                                }
                        }       
                }
                if(!equivalentFilter)
                        filterStack.addFilter(RasterFilterStackManager.transparency, filtro);
        }

    Teniendo la nueva función para añadir filtro ya podremos añadirlo desde un dialogo creando un RasterFilterStackManager o usando uno ya creado y leyendo los parámetros del filtro desde el cuadro (también podemos ponerlos fijos si nos interesa). En nuestro caso:

stackManager.addTransparencyFilter( contentPane.getRangeRed(),  //Parámetros leidos desde el dialogo                                            contentPane.getRangeGreen(),
contentPane.getRangeBlue(),     
0x10,                                                                 //Parámetros a valor fijo                         
0xff,
0xff,
0xff);

    Para que sea posible salvar el estado de un raster cuando se salva un proyecto y se le hayan aplicado filtros es necesario codificar esta posibilidad para ello deberemos crear dos métodos obligados por el interfaz en nuestro Manager. Estos son:

        public ArrayList getStringsFromStack(RasterFilter rf);  y 
        public void createStackFromStrings(ArrayList f, Integer pos);

    En el primero es para añadir las cadenas al XML que salva el proyecto y habrá que comprobar si primero si el RasterFilter pasado es instancia de este filtro que estamos implementando y si lo es añadir las cadenas adecuadas de esta forma:

        public ArrayList getStringsFromStack(RasterFilter rf){
                if(rf instanceof PruebaFilter){
                        filterList.add("filter.prueba.active=true");
                }
        }

    El segundo es para recuperar el estado de un proyecto. Para ello lo primero que deberemos hacer es recuperar del array el elemento analizado, comprobar que contiene la cadena que representa nuestro filtro y si es así eliminar esa entrada del vector ya que ya ha sido analizada y añadir las acciones que conllevan la adición de nuestro filtro. En este caso un simple addPruebaFilter añadirá el filtro creado cuando se habra un proyecto con la cadena filter.prueba.active=true.

        public void createStackFromStrings(ArrayList f, Integer pos){
                String fil = (String)f.get(pos);
                if(fil.startsWith("filter.prueba.active") && getValue(fil).equals("true")){
                        filters.remove(pos.intValue());
                        this.addPruebaFilter();
                        pos = -1;
                }
        }

4.Interfaces Gráficas


    Cresques tiene incluidas interfaces gráficas para la gestión de propiedades y filtros y el salvado a raster. Estas interfaces no tienen funcionalidad completa sino que son paneles con los controles para una recogida de datos desde la aplicación cliente. El cliente debe insertar estos paneles dentro de sus propios frames y gestionar la recogida y escritura de datos.


4.1 Interfaz de propiedades

    Para la gestión de los controles de propiedades, el cliente deberá crear una clase que herede de org.cresques.ui.raster.FilterRasterDialogPanel para tener el acceso a los controles protected que tiene. Por ejemplo, podemos querer incluir los paneles dentro de un frame con un botón de Aceptar, otro de Cancelar y otro de Aplicar. Un ejemplo de lo que aquí se explica puede encontrarse en gvSIG dentro de la clase com.iver.cit.gvsig.gui.panels.PropertiesRasterDialog.

    Si se desea gestionar la restauración de valores cuando se pulsa cancelar deberá hacerlo en esta clase. Una posibilidad es crear una clase, por ejemplo Status que guarde los valores al entrar y los restaure al salir en caso que las acciones sean canceladas.

    Para la traducción del panel habrá que crear una función normalmente llamada por el constructor que sustituya las siguientes cadenas por el idioma que se desee:

this.getBandSetup().getFileList().getJButtonAdd().setText("Anadir");
this.getBandSetup().getFileList().getJButtonRemove().setText(“Eliminar");
this.getBandSetup().getFileList().lbandasVisibles.setText("bandas");                    

RasterTransparencyPanel tpan = this.getTransparencyPanel();
tpan.lGreenValue.setText("Valor verde:");
tpan.lRedValue.setText("Valor rojo:");
tpan.lBlueValue.setText("Valor azul:");
tpan.getTransparencyCheck().setText("transparencia");
tpan.getOpacityCheck().setText("opacidad");
tpan.lRange.setText("usar_rango: 1,3,5:8");
tpan.lPixelValue.setText("valor pixel: 0 a 255");                               

EnhancedPanel ep = this.getEnhancedPanel();
ep.lLineal.setText("lineal directo");
ep.lQueue.setText("recorte colas");
ep.lWithoutEnhanced.setText("sin realce");
ep.lCut.setText("% "recorte");
ep.lRemove.setText("eliminar extremos");
                                
for(int i=0;i<this.getTab().getTabCount();i++){
        if(this.getTab().getTitleAt(i).equals("Info"))
                this.getTab().setTitleAt(i,"info");
        if(this.getTab().getTitleAt(i).equals("Transparencia"))
                this.getTab().setTitleAt(i,"Transparencia");
        if(this.getTab().getTitleAt(i).equals("Bandas"))
                this.getTab().setTitleAt(i,"bandas");
        if(this.getTab().getTitleAt(i).equals("Realce"))
                this.getTab().setTitleAt(i,"realce");
}
                
this.getAcceptButton().setText("Aceptar");
this.getApplyButton().setText("Aplicar");
this.getCancelButton().setText("Cancelar");

    En la gestión de eventos del botón Aceptar hay que controlar el estado de cada panel a acceder a los métodos de estos para recuperar la información y poder procesarla. Cada panel tiene los suyos:

4.2 Interfaz de salvar a raster

    Para la gestión de los controles de raster, el cliente deberá crear una clase que herede de org.cresques.ui.raster.SaveRasterDialogPanel para tener el acceso a los controles protected que tiene. Por ejemplo, podemos querer incluir los paneles dentro de un frame con un botón de Aceptar y otro de Cancelar. Un ejemplo de lo que aquí se explica puede encontrarse en gvSIG dentro de la clase com.iver.cit.gvsig.gui.panels.SaveRasterDialog.

    Para la traducción del panel habrá que crear una función normalmente llamada por el constructor que sustituya las siguientes cadenas por el idioma que se desee:

DataInputSaveRaster dInput = ((SaveSetupPanel)super.getContentPanel()).getSaveParameters();
dInput.lSupIzq.setText("lsup izq :");
dInput.lInfDer.setText("linf der :");
dInput.lFile.setText("Fichero :");
dInput.lResolucion.setText("resolucion");
dInput.lEscala.setText("escala 1:");
dInput.lPpp.setText("ppp");
dInput.bSeleccion.setText("Seleccionar");
dInput.lAncho.setText("ancho.");
dInput.lAlto.setText("alto.");

    En la gestión de eventos del botón Aceptar hay que controlar el estado de cada panel a acceder a los métodos de estos para recuperar la información y poder procesarla.

(DataInputSaveRaster)((SaveSetupPanel)((SaveRasterDialogPanel)this.getContentPane()).getContentPanel()).getSaveParameters(): Obtiene el dialogo de tipo DataInputSaveRaster

dialog.getTinf_derX().getText(): Obtiene la coordenada X inferior derecha.

dialog.getTinf_derY().getText(): Obtiene la coordenada Y inferior derecha.

dialog.getTsup_izqX().getText(): Obtiene la coordenada X superior izquierda.

dialog.getTsup_izqY().getText(): Obtiene la coordenada Y superior izquierda.

((SaveSetupPanel)((SaveRasterDialogPanel)this.getContentPane()).getContentPanel()).getFileName(); Obtiene el nombre del fichero sobre el que se salvará.

dialog.getBPropiedades(): Obtiene el botón de propiedades.


    El botón de propiedades de raster debe de capturarse el evento de pulsado para ser procesado. Dependiendo del tipo de driver cargado hará una acción u otra. El tipo de driver puede determinarse a través del texto del control, ya que este cambia cuando hemos seleccionado una extensión de raster con “Seleccionar”. Este botón de propiedades mostrará el dialogo de propiedades del driver. La configuración de esta ventana es leida directamente desde el mismo driver a través de un texto en formato XML. Para esto crearemos la ventana en una clase, por ejemplo SaveRasterPropsDialog que puede heredar de Jdialog en cuyo constructor crearemos el parser del XML y asignaremos el tamaño a nuestra ventana de esta forma:

         String xml = writer.getXMLPropertiesDialog();
        if(xml!=null){
                CXMLParser parser = new CXMLParser(xml);
                widthWindow = Integer.parseInt(parser.getAttr("window","sizex"));
                heightWindow = Integer.parseInt(parser.getAttr("window","sizey"));
        }
                   setContentPane(getContentPane());

donde el writer es el driver de tipo GeoRasterWriter y contentPane es un SaveRasterPropsDialogPanel. El panel de propiedades puede añadirse de forma facil con una función como esta:

         public Container getContentPane() {
                if (contentPane == null) {
                        contentPane = new SaveRasterPropsDialogPanel(writer); 
                }
                return contentPane;
        }

Este dialogo puede tener botones de aceptar y cancelar cuyos eventos de pulsado deben ser capturados.