martes, 30 de marzo de 2010

How to start publishing your project in sourceforge

How to start publishing your project in sourceforge

This article is a step/by/step guide to those who want to maintain their development projects in sourceforge.net, with svn support for sharing their source code and a project web site.

First of all I suppose you have already created a new project in sourceforge.net. The important thing to remember is the project's unix name. In the following examples, my sourceforge.net user name is cancerbero_sgx and my project unix name is yui4java. As an administrator of your new project, using a linux shell, you can do the following activities:

copy files and directories with rsync:

# rsync -avP -e ssh foo.txt cancerbero_sgx,yui4java@web.sourceforge.net:htdocs/
# rsync -avP -e ssh /home/sgurin/dir1 cancerbero_sgx,yui4java@web.sourceforge.net:htdocs/

those will copy (synchronize) the file foo.txt and the directory /home/sgurin/dir1 to project's htdocs directory.

conecting using sftp:

sftp cancerbero_sgx,yui4java@web.sourceforge.net

Getting a web shell with ssh

with this option you will have access to a remote terminal in sf.net and there execute commands, access files ,etc
for connecting I use:

ssh -t cancerbero_sgx,yui4java@shell.sourceforge.net create


Publish your source code using svn

This will create a svn repository from a local source directory. Be carefull when typing commands when creating a new repository! Once this is done, you can svn checkout your own source files. Then you can work with svn (svn update, svn commit) in your own local working copy.

first you need to create a repository. for this you have to:

1)
connect via ssh as explained beore

2)
type the command :
adminrepo --checkout svn
(this will create a clone copy of your repository in /svnroot/yui4java.
* Use adminrepo --help for further information.)

3)
type the following commands (be carefull!)
rm -rf /svnroot/yui4java/*
# (Remove the clone copy of your repo)
create /svnroot/PROJECT
# (Create a new repository)

4)
type the following commands
cd
adminrepo --save svn


that operation can take some seconds... Once it is done, you can use your new svn repository. With the following command we will import a local source code directory into the svn repository:

svn import /home/sgurin/my/local/src/folder https://yui4java.svn.sourceforge.net/svnroot/yui4java/trunk

web page

The last thing we will create for our new project is its web page in sourceforge.net. In our project's main folder, we have the directory htdocs and this is the directory that is exposed to the web. In my example, this diretory is located at /home/groups/y/yu/yui4java/htdocs. This means that a file there, for example, /home/groups/y/yu/yui4java/htdocs/example.html can be navigated from http://yui4java.sourceforge.net/example.html.

it is important that all directory accesible from the web (for example, directories with javascript, css, images, etc), to contain a file .htaccess with the following content:

Options +Indexes
that's all. I hope this can be usefull to new sourceforge users.

miércoles, 3 de marzo de 2010

Problem with SVG feConvolveMatrix filter with kernel which sum is zero

Here I will document an issue that I had working with SVG feConvolveMatrix primitive filter that was a really pain for me but has a simple solution.

My problem was using feConvolveMatrix filter primitive to apply operations like blur, sharp, edge detection, etc to images. Everything works OK, except for kernel matrix which elements sum equals 0.

For example, the following filters works as spected:


<filter id="vstripe">
<feConvolveMatrix order="3"
kernelMatrix="
2 -1 2
-1 2 -1
2 -1 2"
/>
</filter>


but the following filter (with a kernel which elements sum equals 0) won't work ( will show an empty rectangle):


<filter id="vstripe">
<feConvolveMatrix order="3"
kernelMatrix="
-1 -1 -1
-1 8 -1
-1 -1 -1"
/>
</filter>


This problem manifest only for svg elements and in all svg user agents (mozilla, webkit, opera, inskape, etc). This problem is very frustrating because, there are a lot of convolution filters that use kernels which element sum must be 0 (specially edge detector filters).

The problem was because of the alpha channel of images. In most images, the alpha channel has a constant value for all pixels in a region and so, a convolution using these kernels will give 0 (totally transparent) and that is the reason for the empty rectangle.

The solution is setting the parameter preserveAlpha="true" so the alpha channel is not processed in the convolution:


<filter id="vstripe">
<feConvolveMatrix order="3" preserveAlpha="true"
kernelMatrix="
-1 -1 -1
-1 8 -1
-1 -1 -1"
/>
</filter>


I hope this article can help those poor souls that, like me, are stagnant with this problem.

martes, 2 de febrero de 2010

replacing text on files recursively over directories

In very special ocations, when I'm programming, I need to recursively replace text of all files in directories. For example, you want to recursively replace the string "import org.foo.bar.Class1" with "org2.foo.bar.Class1" in all .java files, in a java source folder. I know this can be done with a relatively simple shell (bash) script using sed, grep, etc unix commands, but what about systems that doesn't have bash? Also, there is a program called rpl (http://www.laffeycomputer.com/rpl.html) which purpose is this but, unfortunately, didn't worked for me (I compiled it on my machine, but the command fails with an error message (couldn't allocate memory or simply doesn't finnish its execution). So I implemented this functionality in java. I tested it on large source folders and works quick and nice. I hope this can be helpful for somebody:



package org.sgx.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
* replace strings with new strings in multiple text files recursively over
* directories and supports limiting the search to specific file names.
*
* @author sgurin
*
*/
public class RPL {
public static void copyDirAndReplaceRecursively(File src, File dest,
String filter, String str, String replacement)
throws FileNotFoundException, IOException {
if (src.isDirectory()) {
dest.mkdirs();
File[] childs = src.listFiles();
for (int i = 0; i < childs.length; i++) {
File child = childs[i];
File destChild = new File(dest.getAbsolutePath()
+ File.separator + child.getName());
copyDirAndReplaceRecursively(child, destChild, filter, str,
replacement);
}
} else {
if (src.getName().contains(filter)) {
copyFileAnReplacetext(src, dest, str, replacement);
} else {
copyFileAnReplacetext(src, dest, null, null);
}
}

}

public static void copyFileAnReplacetext(File srcFile, File destFile,
String str, String replacement) throws FileNotFoundException,
IOException {
StringBuffer sb = new StringBuffer();
InputStream is = new FileInputStream(srcFile);
readFile(is, sb);
is.close();
String s = sb.toString();
if (str != null && replacement != null)
s = s.replace(str, replacement);
FileOutputStream os = new FileOutputStream(destFile);
os.write(s.getBytes());
os.close();
}

public static void readFile(InputStream in, StringBuffer sb)
throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
}

// test
public static void main(String[] args) {
try {
File srcDir = new File(
"/home/sebastian/desarrollo/portal4/blogsJavas/src2"), destDir = new File(
"/home/sebastian/desarrollo/portal4/blogsJavas/src");
String str = "com.liferay.portlet.blogs", repl = "org.sgx.portlet.circulares";
FSUtils.copyDirAndReplaceRecursively(srcDir, destDir, ".java", str,
repl);

} catch (Exception e) {
e.printStackTrace();
}
}
}

lunes, 18 de enero de 2010

Problem with keyboard event handling in java, both with swing and swt

I will try to explain, with my bad english, a recent problem that I'm having with keyboard event handling in java using both swing and swt GUI libraries. Basically the problem is that there is not a way, both in swing and swt, of knowing the status of the keyboard keys. Basically the problem is that, while the user is still pressing the key (and never release it), keyrelease events are being throwed (!) and for that it is impossible to get the real keyrelease event. This problem only manifest in programs that need to use advance keyboard controlling; think for example in a piano simulator in which the user uses the keyboard keys as if it where a piano's keys. When the user presses a key a note turn on, and it is turned off only when the user releases it. The user can hold the key an arbitrary amount of time without release it and the note must be turned on in all that time.

I will present the problem with two simple GUI snippets, one for swing and other for swt, and I will compile and execute them both in windows and linux, using sun jdk version 1.6_13. The snippets are a window that listens to keypressed and keyreleased events and prints a message when the event notification is received. In all the tests, the user will press a key and will keep it pressed for some time (more than a second) and then release it. So the correct output for this "use case" would be only two messages "keyPressed" and
"keyReleased" in the output console. The only toolkit and OS combination that worked as spected was swt+linux. In the rest of the combinations, several "keyPressed" and
"keyReleased" are repeated while the user is keeping the key presssed.











SWT snippetSWING snippet

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class KeyPressTest extends org.eclipse.swt.widgets.Dialog {
    
    private Shell dialogShell;
    
    public KeyPressTest(Shell parent, int style) {
        super(parent, style);
    }
    
    public void open() {
        try {
            Shell parent = getParent();
            dialogShell = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
            dialogShell.addKeyListener(new KeyListener() {
                @Override
                public void keyReleased(KeyEvent arg0) {
                    System.out.println("keyReleased");
                }
                @Override
                public void keyPressed(KeyEvent arg0) {
                    System.out.println("keyPressed");
                }
            });
            dialogShell.setLayout(new FormLayout());
            dialogShell.layout();
            dialogShell.pack();
            dialogShell.setLocation(getParent().toDisplay(100, 100));
            dialogShell.open();
            Display display = dialogShell.getDisplay();
            while (!dialogShell.isDisposed()) {
                if (!display.readAndDispatch())
                display.sleep();
            }
            } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        try {
            Display display = Display.getDefault();
            Shell shell = new Shell(display);
            KeyPressTest inst = new KeyPressTest(shell, SWT.NULL);
            inst.open();
            } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

public class KeyPressTest extends javax.swing.JFrame {
    public KeyPressTest() {
        super();
        initGUI();
    }
    private void initGUI() {
        try {
            setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            this.addKeyListener(new KeyListener() {
                @Override
                public void keyTyped(KeyEvent e) {
                }
                @Override
                public void keyReleased(KeyEvent e) {
                    System.out.println("keyReleased");
                }
                @Override
                public void keyPressed(KeyEvent e) {
                    System.out.println("keyPressed");
                }
            });
            pack();
            setSize(400, 300);
            } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                KeyPressTest inst = new KeyPressTest();
                inst.setLocationRelativeTo(null);
                inst.setVisible(true);
            }
        });
    }
}


And the results, for swing and swt in combination with windows and linux are:















windowslinux
swing

keyPressed
keyReleased
keyPressed
keyReleased
keyPressed
keyReleased
....
keyPressed
keyReleased

keyPressed
keyReleased
keyPressed
keyReleased
keyPressed
keyReleased
....
keyPressed
keyReleased
SWT

keyPressed
keyReleased
keyPressed
keyReleased
keyPressed
keyReleased
....
keyPressed
keyReleased

keyPressed
keyPressed
keyPressed
keyPressed
keyPressed
...
keyPressed
keyPressed
keyReleased


As I understand, THIS IS A BUG, because the behaviour does not apply the documentation. For example, this is the more relevant paragraph about keypressed and keyreleased events of swing (java.awt.event.KeyEvent javadoc):

"Key pressed" and "key released" events are lower-level and depend on the platform and keyboard layout. They are generated whenever a key is pressed or released, and are the only way to find out about keys that don't generate character input (e.g., action keys, modifier keys, etc.).

and this is not true because keyreleased events are generated without a key being released

Note that the only different situation is swt in linux. Imho it is still incorrect (because several keypressed events are fired but only one actually happens) but in this case we can we can know when the key is really releaed. In the other scenarios it is impossible.

IMHO, a cause of this problem coud be that swt and swing designers have modeled the keyboard event system thinking on text and not in other keyboard usage. In the case of swt that heavily relies on underlying plafform (gtk in linux, winapi in windows), I think the event stuff is a responsability of the uderlying platform and it is there where we note the defferencies.

So my question for java developers reading this is if there exists a way of being correctly notified when a keyrelease event occurs using swing or swt. Other question could be if there exists other library for java which handles this correctly because now, I havent figure out how to do this simple task in java ;(.

If you are a java programmer and want a workaround, I think the only one is the following. Since, while the key is pressed the keypressed event is fired regularly, the way we have to know that a key is released is when keypressed event is not firing anymore for that key. Note that this will be incorrect (because it is not really a keyrelease event) and can be expensive to implement because it because it require, for each key, a listener thread that triggers the fake keyrelease event when it detects no more keypressed. My proposal is the following keylistener (KeyListener2 inner class):


package org.sgx.javatests.keypress.swingAll;

import java.awt.Component;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

public class SwingSollutionAllClasses {

/**
* this class is responsible for maintaining a key status map
* @author sebastian
*
*/
static class InputManager implements KeyListener {
//sgurin : þe last keypressed and keyreleased events registered for each key
Map lastKeyPressedEvents = new HashMap();
Map lastKeyReleasedEvents = new HashMap();
//one for each ascii character.
public boolean[] key_state_up = new boolean[256]; //true if pressed
public boolean[] key_state_down = new boolean[256]; //true if not pressed
//a string used as a buffer by widgets or other text input controls
private String keyCache = "";
public InputManager(){
for (int i = 0; i < key_state_up.length; i++) {
key_state_up[i]=true;
key_state_down[i]=false;
}
}
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if( code >= 0 && code < 256 ) {
key_state_down[code] = true;
key_state_up[code] = false;
lastKeyPressedEvents.put(code, e);
}
}
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
if( code >= 0 && code < 256 ) {
key_state_up[code] = true;
key_state_down[code] = false;
lastKeyReleasedEvents.put(code, e);
}
}
public void keyTyped(KeyEvent e) {
keyCache += e.getKeyChar();
}
public boolean isKeyDown( int key ) {
return key_state_down[key];
}
public boolean isKeyUp( int key ) {
return key_state_up[key];
}
}

/**
* this class is a new KeyListener adapter that corrects the default keyreleased
* notification policy (repeatedly notifies keypressed and keyreleased events
* when a key is pressed and not released for a while).
*
* note that this is a heavy listener, use only at special cases (when you need different behaviour for keyreleased event handling)
* it uses an InputManager that mantains the key status and starts a thread that checks each key status and notify changes
*
* @author sgurin
*
*/
static abstract class KeyListener2 implements KeyListener {

KeyChecker checkerThread ;
public KeyListener2(Component target) {
super();
checkerThread=new KeyChecker(this, target);
checkerThread.start();
}
public void destroy() {
checkerThread.stopChecking();
}

static class KeyChecker extends Thread implements KeyListener {
private static final long SLEEP_AMOUNT =50;
InputManager iman;
Component target;
volatile private boolean stoped;
public boolean[] last_key_state_up=null, last_key_state_down=null;
KeyListener2 listener;

public KeyChecker(KeyListener2 listener, Component target){
iman = new InputManager();
this.target = target;
this.listener = listener;
target.addKeyListener(iman);
target.addKeyListener(this);
}

@Override
public void run() {
last_key_state_down=cloneArray(iman.key_state_down);
last_key_state_up = cloneArray(iman.key_state_up);
while(!stoped) {
try {
Thread.sleep(SLEEP_AMOUNT);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < last_key_state_up.length; i++) {
if(last_key_state_up[i] && iman.key_state_down[i])
listener.keyPressed(iman.lastKeyPressedEvents.get(i));
if(last_key_state_down[i] && iman.key_state_up[i])
listener.keyReleased(iman.lastKeyReleasedEvents.get(i));
}
last_key_state_down=cloneArray(iman.key_state_down);
last_key_state_up = cloneArray(iman.key_state_up);
}
}
private boolean[] cloneArray(boolean[] a) {
if(a==null)
return null;
boolean [] r = new boolean[a.length];
for (int i = 0; i < r.length; i++)
r[i]=a[i];
return r;
}
public void stopChecking() {
stoped=true;
}
@Override
public void keyPressed(KeyEvent e) {}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
listener.keyTyped(e);
}
}
}

/**
* swing test
*/
static class KeyPressTest extends javax.swing.JFrame {
public KeyPressTest() {
super();
initGUI();
}
private void initGUI() {
try {
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
new KeyListener2(this) {
@Override
public void keyTyped(KeyEvent e) {}
@Override
public void keyReleased(KeyEvent e) {
System.out.println("keyReleased");
}
@Override
public void keyPressed(KeyEvent e) {
System.out.println("keyPressed");
}
};
pack();
setSize(400, 300);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
KeyPressTest inst = new KeyPressTest();
inst.setLocationRelativeTo(null);
inst.setVisible(true);
}
});
}
}
public static void main(String[] args) {
KeyPressTest.main(args);
}
}



Related information I found:
http://stackoverflow.com/questions/1736828/how-to-stop-repeated-keypressed-keyreleased-events-in-swing
http://groups.google.com/group/comp.lang.java.gui/browse_thread/thread/e215f9729154511e
http://gpsnippets.blogspot.com/2008/03/keyboard-input-polling-system-in-java.html

sábado, 20 de junio de 2009

java2script SWT portlets

author: Sebastián Gurin
Añadir vídeo
In this document I will try to explain how to make a simple jsp portlet with a java2script swt application as its contents. We will use liferay portal for testing it. You can download the portlet WAR file and project sources from java2script group files . the file is called MyJ2sPortlet.war

This is not a tutorial neither of swt gui applications, portlets, or client-server application. Here I will only show what is the best way, IMHO, of showing a swt shell as a portlet..

If you want to test this portlet you only need to download liferay portal. If you want to import this as an eclipse project and make your own swt portlet you will have to be familiarized with portlet development and java2script.

In the first place I developed a simple swt application using my favorite visual editor in eclipse. In gnome it looks like the following:


We want to render it as a portlet. In this solution, the resulting portlet (with red halo) will be:

In the following picture we use liferay freeform layout. Observe that the shell will expand accordingly to the portlet size:



deploying the portlet to liferay for testing

The .war file is a web application portlet archive ready for deploy in a portal application. For testing the .war portlet in liferay you must:

  1. download liferay-bundled-with-tomcat, for example liferay 4.4.1 bundled with tomcat 5.5 http://sourceforge.net/project/downloading.php?group_id=49260&filename=liferay-portal-tomcat-5.5-4.4.1.zip&a=34438561

  2. run bin/startup,

  3. login as test@liferay.com password “test”.

  4. copy myJ2sPortlet.war to /home/yourusername/liferay/deploy (or in the case of windows something like c:\Documents and settings\Users\yourusername\liferay\deploy).

  5. Wait until liferay console prints “22:43:54,308 INFO [PortletHotDeployListener:425] Portlets for myJ2sPortlet registered successfully”

  6. Click on “welcome test!” → add application → java2script → myj2sportlet and the portlet should be added to the page

In the 4 step is where we actually make the portlet hot deploy in liferay. Alternatively, you can install de portlet from inside the portal. Just open Admin->admin liferay portlet, click "plugins" tab, click "install more plugins", click "upload file" tab, and choose MyJ2sPortlet.war. Once this step is finnished, liferay console should print somethings like the following telling us the portlet was successfully deployed:

13:06:38,595 INFO [BaseDeployer:493] Deploying myJ2sPortlet.war
Expanding: /home/sebastian/beeblos4/deploy/myJ2sPortlet.war into /tmp/20090621130638598
Copying 1 file to /tmp/20090621130638598/WEB-INF
13:06:39,230 INFO [BaseDeployer:1132] Modifying Servlet 2.5 /tmp/20090621130638598/WEB-INF/web.xml
Copying 735 files to /home/sebastian/desarrollo/portal4/tomcat/webapps/myJ2sPortlet
Copied 76 empty directories to 3 empty directories under /home/sebastian/desarrollo/portal4/tomcat/webapps/myJ2sPortlet
Copying 1 file to /home/sebastian/desarrollo/portal4/tomcat/webapps/myJ2sPortlet
Deleting directory /tmp/20090621130638598
13:06:40,151 INFO [PortletAutoDeployListener:87] Portlets for /home/sebastian/beeblos4/deploy/myJ2sPortlet.war copied successfully
13:06:43,934 INFO [PluginPackageHotDeployListener:74] Reading plugin package for myJ2sPortlet
13:06:43,935 WARN [PluginPackageHotDeployListener:123] Plugin package on context myJ2sPortlet cannot be tracked because this WAR does not contain a liferay-plugin-package.xml file
13:06:44,506 INFO [PluginPackageHotDeployListener:187] Plugin package myJ2sPortlet/myJ2sPortlet/unknown/war registered successfully
13:06:44,511 INFO [PortletHotDeployListener:133] Registering portlets for myJ2sPortlet
13:06:44,600 INFO [PortletHotDeployListener:425] Portlets for myJ2sPortlet registered successfully

Note that the portlet is not deployed until liferay prints " Portlets for myJ2sPortlet registered successfully"

Steps I followed for creating the project

The .war file is a zip and contains both binary (.class and .js) and source code (java). in src/ directory you can find portlet and servlet code and in /html/myJ2s_j2sproject/src-j2s it is the swt shell java sources.

I recommend you to decompress it and import the project to eclipse. This is a “portlet project” and you can easily build, package and deploy on liferay via a simple ant script (configure build.properties according to your system).

In summary this web application serve the java2script content statically and once deployed it still can be accessed from outside the portal application , for example from http://localhost:8080/myJ2sPortlet/html/myJ2s_j2sproject/org.sgx.portlet.myJ2sPortlet.gui.Dialog1.html

For one side, we have an html and javascript files generated by java2script that will render a maximized swt shell:

dialogShell = new Shell(parent, SWT.NONE);

//.... initialize shell content......

dialogShell.layout();

dialogShell.pack();

dialogShell.open();

dialogShell.setMaximized(true);

Display display = dialogShell.getDisplay();

while (!dialogShell.isDisposed()) {

if (!display.readAndDispatch())

display.sleep();

}

(see Dialog1.java)

in the other side, out portlet contents will be a maximized iframe which points to the static content. Portlet's View.jsp:

<%@page contentType="text/html"%>

<%@page pageEncoding="UTF-8"%>

<iframe height="100%" width="100%" src="/myJ2sPortlet/html/myJ2s_j2sproject/org.sgx.portlet.myJ2sPortlet.gui.Dialog1.html"/>

Having java2script application in a separate iframe (and thus in a separate dom) will prevent to have nasty javascript libraries incompatibilities. Also we took advantage of swt shell maximization for the portlet content size adjustment.

Hope this can be useful for people who wish to experiment with java2script applications inside portals.




miércoles, 20 de mayo de 2009

Cómo hacer que eclipse se vea mejor en linux


Plase translate this article to your favorite language:



Una de las principales incomodidades de eclipse para linux es el desperdicio de espacio (principalmente vertical). Comparemos a continuación la versión de windows y la versión de linux. Observemos en particular, como la versión de windows es capaz de mostrar muchísima más información en la vista package explorer que la versión de linux:

eclispe para linux (sin ajustes)


eclipse para windows:
Para proyectos grandes, con muchos recursos, este desperdicio de espacio es bastante molesto ya que cuanto más se tenga que hacer scroll para encontrar un recurso, más se distrae uno. Además de las vistas en forma de árbol como la package explorer, navigator, ant, outline, etc, en mi opinión eclipse para linux también desperdicia mucho espacio horizontal en los botones de la barra de herramientas, menu, etc.

Lamentablemente, las preferencias de eclipse no permiten cambiar la fuente, ni el espaciado de los elementos de este tipo de componentes. Sin embargo, dado de que en linux, SWT (el toolkit gráfico utilizado por eclipse) se basa en los widgets de gtk+ lo que sí podemos hacer es personalizar la theme gtk de forma de solucionar esto.

La forma más fácil de hacer esto es editando el archivo ~/.gtkrc-2.0 con el siguiente contenido:

style "gtkcompact" {
font_name="Sans 8"
GtkButton::default_border={0,0,0,0}
GtkButton::default_outside_border={0,0,0,0}
GtkButtonBox::child_min_width=0
GtkButtonBox::child_min_heigth=0
GtkButtonBox::child_internal_pad_x=0
GtkButtonBox::child_internal_pad_y=0
GtkMenu::vertical-padding=1
GtkMenuBar::internal_padding=0
GtkMenuItem::horizontal_padding=4
GtkToolbar::internal-padding=0
GtkToolbar::space-size=0
GtkOptionMenu::indicator_size=0
GtkOptionMenu::indicator_spacing=0
GtkPaned::handle_size=4
GtkRange::trough_border=0
GtkRange::stepper_spacing=0
GtkScale::value_spacing=0
GtkScrolledWindow::scrollbar_spacing=0
GtkExpander::expander_size=10
GtkExpander::expander_spacing=0
GtkTreeView::vertical-separator=0
GtkTreeView::horizontal-separator=0
GtkTreeView::expander-size=8
GtkTreeView::fixed-height-mode=TRUE
GtkWidget::focus_padding=0
}
class "GtkWidget" style "gtkcompact"

style "gtkcompactextra" {
xthickness=0
ythickness=0
}
class "GtkButton" style "gtkcompactextra"
class "GtkToolbar" style "gtkcompactextra"
class "GtkPaned" style "gtkcompactextra"

Básicamente, las expresiones que comienzan con "style" son reglas de estilo, mientras que las expresiones que comienzan con "class" aplican una regla de estilo a algún tipo de widget gtk. Luego de este cambio, al iniciar eclipse se ve prácticamente con el mismo espaciado que la versión de windows:



Notar que particularmente el problema es que todas las themes gtk que comunmente vienen instaladas dejan demasiado espacio (en el contexto de un programador) entre items del widget Tree de gtk (GtkTreeView).

Este pequeño cambio hace, en mi opinión, 100% más utilizable a eclipse en linux.

.... Y los años transcurrieron y esta información sigue siendo relevante para eclipse 4.3 en linux arch, y especialmente más útil ahora que eclipse 4.X desperdicia muchísimo más espacio, veamos el antes y después:
Antes: 

Después:


Notar la gran diferencia de ahorro de espacio en la tool bar superior y en el árbol de trabajo de la izquierda.BTW - at least in arch linux -  you can modify the file /home/sg/.gtkrc-2.0.mine instead original and often auto generated /home/sg/.gtkrc-2.0

lunes, 4 de mayo de 2009

tomcat 5.5 behind apache 2.2

Recently I needed to add a web application hosted in tomcat 5.5 to an apache 2.2 web server that already serves static content, svn, web dav, etc. I tried lots of ways of making this, and in this document I will describe the best sollution I've found.

In your apache's httpd.conf file add the following lines, for example at the end of the file:


LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
<Location /tomcatSite/ >
ProxyPass ajp://localhost:8009/
</Location>


This tells apache that all http requests pointing to http://yourhost/tomcatSite/ will be redirected to a running apache instance. So save the file, restart apache, start tomcat and try to navigate to http http://yourhost/tomcatSite/. In a regular tomcat installation you should see the tomcat's main page.

The idea is that apache to listen on port 80 and tomcat to listen on another port, for example 8080. In my case as I said, this allow me to have my j2ee application in http://yourhost/tomcatSite/ but taking advantage of apache's flexibility, efficiency, supported protocols/servers like svn, webdav, etc.

I hope this can be usefull for somebody as it was for me...