lunes, 30 de abril de 2012

Cambiar Look & Feel en NetBeans Platform

Cuando desarrollamos aplicaciones de escritorio en Java la apariencia no nos interesa demasiado al principio, pero conforme creamos más y más nos damos cuenta que no parecen muy agradables a la vista parcen aplicaiones viejas, como de windows 98.

Afortunadamente la apariencia o Look & Feel (LAF) se puede cambiar con unas cuantas líneas de código e incluso existen librerías para crear nuestros propios temas. Vamos a ver algo de esto con aplicaciones construidas sobre la plataforma NetBeans así que veamos como luce una aplicación por default:
Si deseamos cambiar el Look And Feel de una aplicación construida sobre NetBeans Platform sin librerías adicionales la forma más sencilla es aplicar Nimbus (disponible a partir de Java SE 6 Update 10). Esto se puede lograr de varias formas, la primera es agregar la siguiente línea a project properties:
run.args.extra=--laf Nimbus
ahora ejecutamos y vemos los cambios:
esto funciona si ejecutamos la aplicación desde el propio NetBeans, pero no lo hace cuando ejecutamos el programa ya instalado. 

Lo que realmente nos interesa es cambiar el aspecto a la aplicación una vez que está instalada y ejecutándose. Para lograrlo podemos modificar el archivo que NetBeans toma como base para la configuración de las aplicaciones construidas sobre su plataforma. Ese archivo se encuentra en <directorio donde está instalado netbeans> -> harness -> etc -> app.conf

Del archivo nos interesa modificar la línea default options agregándole --laf Nimbus:
default_options="--branding ${branding.token} -J-Xms24m -J-Xmx64m --laf Nimbus"
De esta forma el cambio no se notará ejecutando la aplicación desde el NetBeans, pero sí cuando instalemos la aplicación. Con éste método existe el problema de que todas las aplicaciones desarrolladas con NetBeans Platform tendrán el LAF Nimbus, entonces resulta conveniente cambiar la línea default options de la aplicación que estamos construyendo. Para esto necesitamos editar el archivo build.xml añadiendo lo siguiente dentro del tag project:
<target name="build-launchers" depends="suite.build-launchers">
        <replace file="build/launcher/etc/${app.name}.conf" token="--branding lafdemo -J-Xms24m -J-Xmx64m" value="--branding lafdemo -J-Xms24m -J-Xmx64m --laf Nimbus"/>
</target>
donde lafdemo lo debemos cambiar por el nombre de nuestro proyecto (en minúculas). Así no tocamos el archivo app.conf y el cambio se ve únicamente reflejado para esa aplicación.

Pero basta de nimbus, vamos a probar NimROD Look And Feel. Para esto creamos un nuevo módulo, digamos lookandfeel , posteriormente le agregamos la librería nimrodlf-*.*.jar y creamos un Installer/Activator que tendrá el siguiente código en el método restored():
try{
  File theme = InstalledFileLocator.getDefault().locate(
                    "NimRODThemeFile.theme",
                    "NimrodLAF",
                    false);
  NimRODTheme nt = new NimRODTheme(theme.toString());
  NimRODLookAndFeel nf = new NimRODLookAndFeel();
  NimRODLookAndFeel.setCurrentTheme(nt);
  UIManager.setLookAndFeel(nf);
}catch(UnsupportedLookAndFeelException ex){
            Exceptions.printStackTrace(ex); }

donde NimRODThemeFile.theme es el tema que hemos creado con la librería y se encuentra en el carpeta relsease (Ctrl+2 -> lookandfeel -> release, si no existe la creamos). Este método tiene la ventaja de que el cambio de LAF se nota cuando estamos ejecutando desde el NetBeans y también cuando ejecutamos la aplicación una vez instalada. El resultado puede ser algo como esto:

Si utilizan una librería diferente basta con cambiar el argumento de setLookAndFeel():
setLookAndFeel(LookAndFeel newLookAndFeel)
setLookAndFeel(String className)

Listo.

martes, 24 de abril de 2012

Asignar shotcut a SaveAction en NetBeans Platform

Asignar un atajo de teclado a un SaveAction (o más bien a un SaveCookie) es tan sencillo pero que me tardé  un poco en descubrirlo como agregar lo siguiente a nuestro archivo layer.xml :

<folder name="Shortcuts">
 <file name="D-G.shadow">
  <attr name="originalFile" stringvalue="Actions/System/org-openide-actions-SaveAction.instance"/>                                              </file>                                                                 </folder>
donde  D-G.shadow indica el shortcut que en este caso es Ctrl+G. Para Alt y Shift se utilizan O y S respectivamente, como lo podemos ver en dzone.

sábado, 21 de abril de 2012

Listar archivos en un JAR

Listar archivos en Java es muy sencillo, pero cuando tales archivos se encuentran dentro de un JAR el método listFiles() no funciona. Si buscas un poco seguro encuentras como hacerlo en java2s ó en stackoverflow.

Aquí dejo un método basado en la respuesta de stackoverflow con unas pequeñas modificaciones que lo hacen más flexible:
public List<String> listFiles4JAR(Class clazz, String pack, String ext, boolean includeSubPackage) {

        CodeSource src = clazz.getProtectionDomain().getCodeSource();
        List<String> list = new ArrayList<String>();
        String extension = ext.contains(".") ? ext : "." + ext;
        pack = pack.replace('.', '/');

        int numFolders = 0;
        if( !includeSubPackage ){
            numFolders = pack.split("/").length;
        }
        
        try{

            if(src != null){

                String location = src.getLocation().getPath().replaceAll("%20", " ").replaceAll("!/", "");
                URL jarUrl = new URL(location);

                ZipInputStream zip = new ZipInputStream(jarUrl.openStream());
                ZipEntry ze = null;

                while((ze = zip.getNextEntry()) != null){
                    String entryName = ze.getName();

                    if(entryName.startsWith(pack)
                            && (entryName.endsWith(extension.toLowerCase())
                            || entryName.endsWith(extension.toUpperCase()))){
                        
                        if( !includeSubPackage ){
                            
                            if( numFolders == entryName.split("/").length-1 ){
                                list.add(entryName);
                            }
                            continue;
                        }
                        
                        list.add(entryName);
                    }
                }

            }

        }catch(IOException ex){
            Logger.getAnonymousLogger().log(Level.SEVERE, ext);
        }

        return list;
    }


donde:
            clazz es un clase que se encuentra en el JAR que queremos inspeccionar
            pack es el paquete a examinar
            ext es la extensión de los archivos a listar
            includeSubPackage indica si se listan o no los archivos de los sub-paquetes

Ahora solo queda colocar el método en una clase Utils, digamos JARUtils. De esta forma podremos llamar a nuestro método desde cualquier parte:
public class JARUtils {

    private static final JARUtils jarUtis = new JARUtils();

    private JARUtils() {
    }

    public static JARUtils getInstance() {
        return jarUtis;
    }

    ...

}
Y finalmente hacemos algo como:
List<String> list = JARUtils.getInstance().listFiles4JAR(this.getClass(), "un.paquete.con.imagenes", "png", false);
que nos devolverá la lista de imágenes png en el paquete un.paquete.con.imagenes que se encuentra en el JAR que contiene a la clase que realiza la llamada this.getClass().