14 maggio 2011

javascript: regular expression targa italiana

Indice dei tutorials: http://gheryd.blogspot.com/2011/06/javascript-gwt-tutorials.html

Questa regular expression server per testare il corretto formato per le targhe italiane sia nuovo (AA123BB) che vecchio tipo (MI12345, MI123456, ROMA12345, ROMA123456):

var targaRExp = /^(([a-zA-Z]{2}\d{3}[a-zA-Z]{2})|(([a-zA-Z]{2}|roma)(\d{5}|\d{6})))$/i
var targa = prompt("inserire una targa:");
if( targaRExp.test(targa) ) {
alert("formato targa corretto");
}else {
alert("formato targa scorretto");
}

Javascript: parseint per valori "08" e "09"

Indice dei tutorials: http://gheryd.blogspot.com/2011/06/javascript-gwt-tutorials.html

Se usate la funzione parseInt per i valori "08" e "09" (nel mio caso si riferivano ai mesi di agosto e settembre formattati a due cifre)

var n = parseInt("08") ;   // n = 0
var n = parseInt("09") ;   // n = 0

il risultato sarà sempre 0 (zero) perchè vengono interpretati come numeri a base ottale.

Occorre specificare la base numerica decimale (10) nel secondo argomento:

var n = parseInt("08", 10);   // n = 8
var n = parseInt("09", 10);   // n = 9

In generale consiglio sempre un controllo per verificare se il parsing ha avuto buon esito come nell'esempio seguente:

var s = prompt("insert a integer");
var n = parsInt(s, 10);
if(  isNaN(n) ) {
    alert("is not a number");
}else {
   alert("is number");
}



Ubuntu 11.04 attivare/ripristinare desktop classico gnome

english version

Se la versione nuova del desktop (Unity) non vi piace o comunque non vi è pratica, potete passare facilmente alla versione "classica" del desktop gnome.

Quando siete nella pagina di login di ubuntu, selezionate l'utente. Nella parte in basso allo schermo vi comparirà la barra con dei menù in cui potrete selezionare "ubuntu classic".



Personalmente sono passato alla versione classica perchè avevo parecchi problemi con le icone di notifica e  blocchi vari di unity. Penso che a breve questi problemi saranno risolti. Si può ritornare a Unity sempre dalla schermata di login ;)
Nota: ho provato a disattivare unity dal configuratore di compiz, ma aimè si è bloccato :(

Ricordo che per installare il configuratore di compiz basta fare il comando:

gheryd@gheryd-laptop:~$ sudo apt-get install compizconfig-settings-manager

Con il desktop ubuntu classic funziona alla grande :)

Su compiz, sotto la voce "desktop" c'è il flag per attivare il plugin di Unity:

30 aprile 2011

GWT currency & number textbox widget (per valuta e numeri)

english version


Indice dei tutorials: http://gheryd.blogspot.com/2011/06/javascript-gwt-tutorials.html



E possibile configurare nel modulo GWT il paese per la corretta formattazione del numero.

<?xml version="1.0" encoding="UTF-8"?>
<module>

    <extend-property name="locale" values="it_IT" />
    <set-property-fallback name="locale" value="it_IT" />

</module>

Per i formati con virgola ho addottato il valore

public static final NumberFormat nfFloat = NumberFormat.getFormat("#,##0.00");
mentre per i valori interi:

public static final NumberFormat nfInt = NumberFormat.getFormat("#,##0");

Comunque i formati  possono essere essere usati formati "custom" con il metodo "setNumberFormat" a cui occorre passare un oggetto NumberFormat. Per disabilitare la formattazione usare il metodo disableFormatting.


import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.TextBox;


public class CurrencyTextBox extends TextBox {
    
    
    public static final NumberFormat nfFloat = NumberFormat.getFormat("#,##0.00");
    public static final NumberFormat nfInt = NumberFormat.getFormat("#,##0");
    
    
    public static interface CurrencyTextBoxHandler {
        public void onChange(CurrencyTextBox currencyTextBox);
    }
    
    private int decimals = 2;
    private int integers = 10;
    
    private NumberFormat nf;
    
    private float cifra = 0f;
    private char inputSeparator = '.';
    private char currencySumbol = '€';
    private boolean enableNegative = false;
    
    private boolean enableDecimal;
    private CurrencyTextBoxHandler handler = null;
    
    private String suffix = "";
    
    
    public CurrencyTextBox() {
        this(true, true);
    }
    
    
    public CurrencyTextBox(boolean showCurrencySimbol, boolean enableDecimal) {
        
        super.setTextAlignment(TextBox.ALIGN_RIGHT);
        
        if(!showCurrencySimbol) {
            currencySumbol = ' ';
        }
        
        this.enableDecimal = enableDecimal;
        if(enableDecimal) {
            nf = nfFloat;
        }else {
            nf = nfInt;
        }
        
        addKeyPressHandler(keyPressHandler);
        addBlurHandler(new BlurHandler() {
            
            @Override
            public void onBlur(BlurEvent event) {
                if(CurrencyTextBox.this.isReadOnly()) {
                    return;
                }
                parse();
                showFormatted();
                if(handler!=null) {
                    handler.onChange(CurrencyTextBox.this);
                }
            }
        });
        
        addFocusHandler(new FocusHandler() {
            
            @Override
            public void onFocus(FocusEvent event) {
                if(CurrencyTextBox.this.isReadOnly()) {
                    return;
                }
                if(CurrencyTextBox.this.enableDecimal) {
                    CurrencyTextBox.super.setText( (cifra==0f?"":cifra)+"" );
                }else {
                    int n = (int)cifra;
                    CurrencyTextBox.super.setText( (n==0?"":n)+"" );
                }
                
            }
        });
        
        showFormatted();
        
    }
    
    
    @Override
    public void setValue(String value) {
        setText(value);
    }
    
    
    @Override
    public String getValue() {
        return getText();
    }
    
    
    @Override
    public void setText(String text) {
        float n = 0f;
        try {
            n = Float.parseFloat( text );
        }catch(Exception e){}
        setNumber(n);
    }
    
    
    @Override
    public String getText() {
        if(enableDecimal) {
            Float n = getNumber();
            return "" + (n==null ? "" : n);
        }else {
            Integer n = getNumberAsInteger();
            return "" + (n==null ? "" : n);
        }
    }
    
    
    public void setNumberFormat(NumberFormat nf) {
        this.nf = nf;
        showFormatted();
    }
    
    
    public void disableFormatting() {
        this.nf = null;
    }
    
    public void setEnableNegative(boolean enableNegative) {
        this.enableNegative = enableNegative;
    }
    
    
    public void setCurrencyTextBoxHandler(CurrencyTextBoxHandler handler) {
        this.handler = handler;
    }
    
    
    public void setDecimals(int decimals) {
        this.decimals = decimals;
    }
    
    
    public void setIntegers(int integers) {
        this.integers = integers;
    }
    
    
    public void setCurrencySymbol(char symbol) {
        this.currencySumbol = symbol;
        showFormatted();
    }
    
    
    public float getNumber() {
        return cifra;
    }
    
    
    public int getNumberAsInteger() {
        return (int)cifra;
    }
    
    
    public void setNumber(Integer cifra) {
        if (cifra!=null){
            setNumber(cifra.floatValue());
        }else {
            setNumber(0f);
        }
    }
    
    
    public void setNumber(Float cifra) {
        if (cifra!=null){
            if(enableDecimal) {
                this.cifra = cifra;
            }else {
                this.cifra = cifra.intValue();
            }
            
        }else {
            this.cifra = 0f;
        }
        showFormatted();
    }
    
    
    private KeyPressHandler keyPressHandler = new KeyPressHandler(){
        
        @Override
        public void onKeyPress(KeyPressEvent event) {
            
            char c = event.getCharCode();
            
            if(c==KeyCodes.KEY_ENTER || c==KeyCodes.KEY_TAB) {
                CurrencyTextBox.this.setFocus(false);
                return;
            }
            
            String text = CurrencyTextBox.super.getText();
            int curPos = CurrencyTextBox.this.getCursorPos();
            if(c==KeyCodes.KEY_BACKSPACE || c==KeyCodes.KEY_DELETE || c==KeyCodes.KEY_RIGHT || c==KeyCodes.KEY_LEFT) {
                return;
            }else if( c==KeyCodes.KEY_UP ) {
                parse();
                cifra++;
                CurrencyTextBox.super.setText(cifra+"");
            }else if( c==KeyCodes.KEY_DOWN ) {
                parse();
                cifra--;
                CurrencyTextBox.super.setText(cifra+"");
            }else if(curPos == 0 && enableNegative && c == '-' && !text.startsWith("c")) {
                
            }else if(c==inputSeparator) {
                if(enableDecimal) {
                    int index = CurrencyTextBox.super.getText().indexOf(inputSeparator);
                    if(index>-1 &&  text.length()>=index) {
                        CurrencyTextBox.this.cancelKey();
                    }
                }else {
                    CurrencyTextBox.this.cancelKey();
                }
                
             }else if(  !Character.isDigit(c) ) {
                
                CurrencyTextBox.this.cancelKey();
            }
            
            int posSep = -1;
            
            if(enableDecimal)
            posSep = text.indexOf(inputSeparator);
            
            if(Character.isDigit(c) && posSep>-1) {
                // c'è il punto
                if(  curPos>posSep && (text.length()-posSep)>decimals ) {
                    CurrencyTextBox.this.cancelKey();
                    }else if(curPos<=posSep && posSep>integers ) {
                    CurrencyTextBox.this.cancelKey();
                }
             }else if(posSep==-1 && text.length()>=integers) {
                // non c'è il punto
                CurrencyTextBox.this.cancelKey();
            }
            
            
        }
        
    };
    
    
    private void parse() {
        cifra = 0f;
        try {
            cifra= Float.parseFloat(CurrencyTextBox.super.getText());
        }catch(Exception e) {
            cifra = 0f;
        }
    }
    
    
    private void showFormatted() {
        CurrencyTextBox.super.setText(  (currencySumbol!=' '?currencySumbol:"")+" "+ getFormatted() + suffix );
    }
    
    
    private String getFormatted() {
        if(nf!=null) {
            return nf.format(cifra);
        }else {
            if(enableDecimal) {
                return cifra+"";
            }else {
                return getNumberAsInteger()+"";
            }
            
        }
    }
    
    
    public void setSuffix(String suffix) {
        this.suffix = suffix;
        showFormatted();
    }
}

Esempio:
CurrencyTextBox ctb = new CurrencyTextBox();
ctb.setNumber(1000);
RootPanel.get().add(ctb);

Ubuntu 11.04 desktop bloccato

Dopo aver aggiornato ubuntu 10.10 con la nuova release 11.04, ho avuto l'infelice idea di installare compiz config.
Il nuovo deskop unity utilizzato nella versione 11.04 è scomparso :(
Ho provato a riavviare, niente.
Cercando in giro consigliavano il comando "unity --reset", ma non avevo installato questo comando, quindi ho fatto un bel apt-get install e dopo sono riuscito a eseguire il comando.
Tutto e' ritornato a posto :)
Nota: potete eseguire i comandi avviando ubuntu in modalità provvisoria oppure premendo ctrl+alt+f1 per accedere alla console (blocco permettendo ;) )

gheryd@gheryd-laptop:~$ sudo apt-get install unity

gheryd@gheryd-laptop:~$ unity --reset

Se preferite utilizzare il vecchio buon desktop gnome potete seguire le instruzioni in questo post:
http://gheryd.blogspot.com/2011/05/ubuntu-1104-attivare-desktop-classico.html

Ricordo che per installare il configuratore di compiz basta fare il comando:

gheryd@gheryd-laptop:~$ sudo apt-get install compizconfig-settings-manager

27 marzo 2011

GWT detect popup blocker (rilevazione del blocco popup)

Indice dei tutorials: http://gheryd.blogspot.com/2011/06/javascript-gwt-tutorials.html

english version

Ho avuto l'esigenza di verificare se il browser in cui girava la mia applicazione gwt, avesse attivo il blocco dei popup.
Spulciando un po' in giro ho trovato del codice javascript che ho utilizzato in una classe jsni  gwt .
Ho inserito il codice javascript dentro dei native methods. Il sistema e' un po' rozzo ma funzionante (per ora l'ho solo testato su Chrome, eventualmente si può migliorare dentro i native methods).
La classe ha solo metodi statici ed è sufficiente avviare la rilevazione (detect) nel seguente maniera:
PopupBlockerController.detect();
Dopo 4 secondi (periodMillis) viene verificato se il il popup è stato correttamente aperto.
E' possibile così sapere se c'è un blocco pupup:
if( PopupBlockerController.isPopupBlocked() ) {
    Window.alert("popup bloccati");
}
La cosa migliore sarebbe avere un handler che viene chiamato quando i 4 secondi sono passati, ma purtroppo per ora non ho avuto il tempo. Dimenticavo una cosa importante, occorre creare un file html "popuptest.html" con il seguente codice:
popuptest.html
<!DOCTYPE html PUBLIC PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"; >
<head>
<title>Popup test</title>
<script type="text/javascript" language="Javascript">
function test() { return window.innerHeight!=0; }
</script>
</head>
<body>DETECT POPUP BLOCKER</body>
</html>
Questo html viene mostrato nel popup che il PopupBlockerController cercherà di aprire e contiene la funzione javascript test() che verrà richiamata dopo 4 secondi.
public class PopupBlockerController {


    private final static int periodMillis = 4000;


    public static void detect() {
       startPopupBlockerDetection();
       timer.schedule(periodMillis);
    }

    private static Timer timer = new Timer() {
        @Override
        public void run() {
            if( !isPopupBlocked() ) {
               checkTestPopup();
            }
        }
    };

    public static boolean isPopupBlocked() {
       return isPopupBlockedNative();
    }


    private static native boolean isPopupBlockedNative() /*-{
        return $wnd.popUpsBlocked;
    }-*/;

 
    private static native void startPopupBlockerDetection() /*-{
        $wnd.popUpsBlocked = false;
        $wnd.testPopup = $wnd.open('popuptest.html', 'popuptest', 'width=1px,height=1px,left=0,top=0,scrollbars=no');
        if( !$wnd.testPopup || $wnd.testPopup.closed || 
                   typeof $wnd.testPopup.closed=='undefined' )  {
            $wnd.popUpsBlocked = true
           if($wnd.testPopup) $wnd.testPopup.close();
         } else {
            $wnd.popUpsBlocked = false;
         }
     }-*/;


    private static native void checkTestPopup() /*-{
       if($wnd.testPopup) {
          if( $wnd.testPopup.test( )) {
               $wnd.popUpsBlocked = false;
          } else {
             $wnd.popUpsBlocked = true;
          }
             $wnd.testPopup.close();
       }
    }-*/;
}

15 marzo 2011

gwt widget tree patch for hidden items

Indice dei tutorials: http://gheryd.blogspot.com/2011/06/javascript-gwt-tutorials.html

Mi è capitato di avere l'esigenza di nascondere degli item del widget tree di gwt, come nell'esempio seguente:
Tree tree = new Tree();
  TreeItem root = new TreeItem("root");
  tree.addItem(root);
  for(int i=0;i<10;i++) 
      root.addItem( new TreeItem( "item_"+i ) );
  root.getItem(5).setVisible(false);
L'item con indice 5 viene nascosto, ma se si usano i tasti freccia su e giu, è selezionabile come tutti gli altri. Chiaramente questo non ha senso. Quindi ritengo questo un bug!
Ho risolto questo problema estendendo la classe Tree (api tree). Con un override del metodo "onBrowserEvent", intercetto l'evento prima che venga gestito dalla classe Tree.
Se l'evento è relativo alla tastiera (keyboard event) , allora l'oggetto "event" viene salvato e poi inoltrato alla metodo analogo della classe madre che procederà quindi nella selezione.
Dato che questo evento scatena una chiamata di eventuali SelectionHandler registrati, quanto istanzio la classe TreeExt, occorre necessariamente aggiungere l'handler in cui verrà verificato se l'item selezionato è nascosto (hidden). In tal caso viene chiamato il metodo fireLastEvent che di fatto è come se l'utente ripremesse lo stesso tasto. Quindi l'ultimo evento da tastiera verrà scatenato ripetutamente via codice finchè non verrà selezionato un item visibile.
public class TreeExt extends Tree {  
     private Event lastEvent = null;   
     TreeExt() {}
  
     @Override  
     public void onBrowserEvent(Event event) {  
       int eventType = DOM.eventGetType(event);  
       lastEvent = 
              (eventType== Event.ONKEYPRESS || eventType == Event.ONKEYDOWN) ? 
                  event : null;  
       super.onBrowserEvent(event);  
     }  
     public void fireLastEvent(){  
       if( lastEvent !=null ) {  
         super.onBrowserEvent(lastEvent);  
       }  
     }  
 }  
// Example  
 final TreeExt t = new TreeExt();  
 t.addSelectionHandler( new SelectionHandler() {  
    @Override  
    public void onSelection(SelectionEvent event) {  
      TreeItem item = event.getSelectedItem();  
      if( !item.isVisible() ) {  
         //Window.alert("not visible");  
         t.fireLastEvent();  
         return;  
      }  
      //TODO handle event for visible item  
   }  
 });  
E' possile sovrascrivere il metodo addSelectionHandler per fare in modo che sia la stessa classe TreeExt a controllare se l'item è visibile- Il codice per chi utilizza questa classe sarebbe più pulito ed elegante. Beh, se questo tocco di eleganza vi gusta allora provateci ;)