Finalmente sono riuscito ad installare il Visual Editor su Eclipse Helios, ma ho dovuto scaricare il pacchetto e installarlo manualmente come fosse un repository locale. Per aprire un file visuale con l'editor è necessario fare click destro sulla risorsa e selezionare Open With -> Visual Editor (al posto di Java Editor). Da notare che nel mio caso (applicazione RCP con viste e editor) l'editor non si comporta bene poiché non riconosce esattamente la vista o l'editor se questo viene creato con variabili "temporanee" (ossia non di istanza). Dovrò lavorare un po' per adattare il mio sistema all'uso del VE.
Visualizzazione post con etichetta swt. Mostra tutti i post
Visualizzazione post con etichetta swt. Mostra tutti i post
martedì 14 dicembre 2010
Nebula Table Combo
Usare il Table Combo di Nebula è un'operazione tutto sommato semplice, anche se manca un po' di documentazione a riguardo. Mostro di seguito i passi necessari all'utilizzo del widget, che nel caso della mia applicazione visualizzano una semplice tabella con ID/Descrizione di elementi.
Anzitutto occorre inizializzare il componento e definire le colonne (se si omette questo passo si avrà un combo che visualizza solo una delle colonne). Successivamente si decide se visualizzare o meno le intestazioni di colonna e infine si stabilisce quale colonna (con indice numerato partendo da zero) si deve rendere visibile nel combo quando questo è chiuso. Il seguente pezzo di codice illustra quanto appena descritto:
// create the combo with the right style
this.combo = new TableCombo( this , SWT.READ_ONLY );
// say I want two columns
this.combo.defineColumns( new String[]{ "ID", "Descrizione" } );
this.combo.setShowTableHeader( true );
// the description is the column used for the selection
this.combo.setDisplayColumnIndex( 1 );
this.combo = new TableCombo( this , SWT.READ_ONLY );
// say I want two columns
this.combo.defineColumns( new String[]{ "ID", "Descrizione" } );
this.combo.setShowTableHeader( true );
// the description is the column used for the selection
this.combo.setDisplayColumnIndex( 1 );
Successivamente occorre inserire gli elementi nel combo, tenendo presente che occorrerà passare una coppia di stringhe in un unico oggetto array:
TableItem tableItem = new TableItem( this.combo.getTable(), SWT.NONE );
tableItem.setText(
new String[]{ newElement.getId(), newElement.getDescription() } );
venerdì 3 dicembre 2010
Compilazione di Nebula
Visto che i download binari di Nebula continuano a non essere accessibili per via del refactoring, l'unica alternativa per usare i widget di questo fantastico progetto è quello di compilarli "manualmente". Per compilare i widget occorre avere CVS (per il dowload del codice), Maven per la compilazione e poi un po' di pazienza (tutto sommato il build è veloce).
I passi da seguire sono i seguenti:
- creare una cartella che conterrà tutto il progetto;
- effettuare il login anonimo al server CVS
cvs -d :pserver:anonymous@dev.eclipse.org:/cvsroot/technology login
- scaricare l'albero dei sorgenti e dei progetti di Nebula:
cvs -d ':pserver:anonymous@dev.eclipse.org:/cvsroot/technology' co org.eclipse.swt.nebula
- e infine compilare i progetti org.eclipse.swt.nebula.nebula-incubation (ancora non stabili) e org.eclipse.swt.nebula.nebula-release (stabili): occorre entrare nella directory di ogni progetto e dare il comando mvn install. Ogni progetto avrà poi una cartella target che conterrà il jar finale.
martedì 30 novembre 2010
SWT CLabel
Come è noto SWT è una libreria che utilizza un approccio totalmente differente rispetto a Swing: in SWT si cerca di utilizzare quanto prima i componenti messi a disposizione del sistema operativo, costruendo poi su questi componenti piu' complessi. Questa differenza è evidente ad esempio se si considera un widget tanto semplice quanto utile: le etichette (label). In Swing una label può essere dotata di una propria immagine, mentre in SWT una Label può avere un testo o una immagine, ma non entrambi. La ragione di ciò è nelle limitazioni del sistema operativo stesso e nell'uso pesante che SWT fa dei componenti nativi. Per ovviare all'inconveniente, SWT utilizza una serie di widget custom i cui nomi tipicamente iniziano con una 'C' (per evitare conflitti nello spazio dei nomi), come ad esempio CLabel. Osservando la gerarchia di una CLabel si nota come questa di fatto erediti da un Canvas, ossia da una zona che può essere disegnata arbitrariamente, mentre la piu' povera Label eredita direttamente da Control, e quindi non prevede personalizzazioni particolari. La differenza di gerarchia fra i due componenti evidenzia l'approccio SWT: Label sfrutta tutte e sole le caratteristiche del sistema operativo, mentre CLabel disegna da se i componenti che servono e li dispone nel modo che ritiene piu' opportuno (immagine a fianco del testo).
mercoledì 10 novembre 2010
Nebula download corrotto
E' ormai da un paio di settimane che il sito del progetto Nebula, una serie di widget addizionali basati su SWT, non permette il download dei jar in fase di incubazione riportando uno spaventoso messaggio circa la corruzione di tutti i build del progetto stesso.
Quello che c'è dietro a questo messaggio di errore viene spiegato in un messaggio sul forum ufficiale di Nebula: un build server è andato in crash, causando l'errore nella ricostruzione dei pacchetti binari. Tutto questo succede mentre il progetto sta migrando la propria storia su un altro sistema, ecco quindi che si è preferito terminare la migrazione piuttosto che spendere tempo nella ricostruzione degli archivi legacy.
RCP: ottenere le informazioni di plugin a run-time (immagini e versione del prodotto)
Capita spesso di dover accedere a delle informazioni di definizione di un plugin RCP a run-time. Gli esempi piu' ricorrenti sono le immagini associate ad una applicazione RCP e i dati del bundle che definisce l'applicazione stessa (ad esempio il numero di versione). RCP mette a disposizione una serie di facilities per ottenere tali informazioni.
Il primo passo consiste nell'ottenere una istanza di IProduct, dal quale si può estrarre il defining bundle e da questo la lista delle immagini configurate nel file plugin.xml. Tale lista è in realtà una stringa unica con tutte le immagini alle varie dimensioni (16x16, 32x32, 48x48, ecc.) dalla quale occorre estrarre la lista effettiva dei percorsi (relativi al bundle) delle immagini. Avendo ottenuto la lista delle immagini è possibile inserirle nella shell corrente (ad esempio uno splash screen). Il seguente blocco di codice riassume i passi da fare:
// get the product for the running instance
IProduct product = Platform.getProduct();
// get my shell
Shell myShell = ...
// the product can be null if the running instance is launched
// as an eclipse application (e.g., during the development)
if( product == null )
return;
// get the bundle symbolic name
String bundleID = product.getDefiningBundle().getSymbolicName();
// get the array of the application icons (defined thru the product)
// the method will return a single string with the list of images
// used at different sizes (16x16, 32x32, 48x48 and so on). The list is
// comma separated, so I need to extract every single item.
String imagePaths = product.getProperty(
IProduct product = Platform.getProduct();
// get my shell
Shell myShell = ...
// the product can be null if the running instance is launched
// as an eclipse application (e.g., during the development)
if( product == null )
return;
// get the bundle symbolic name
String bundleID = product.getDefiningBundle().getSymbolicName();
// get the array of the application icons (defined thru the product)
// the method will return a single string with the list of images
// used at different sizes (16x16, 32x32, 48x48 and so on). The list is
// comma separated, so I need to extract every single item.
String imagePaths = product.getProperty(
IProductConstants.WINDOW_IMAGES );
List imagePathList = new LinkedList();
StringTokenizer commaTokenizer = new StringTokenizer(imagePaths, ",");
while( commaTokenizer.hasMoreTokens() )
imagePathList.add( commaTokenizer.nextToken() );
// now that I've got the list of image paths (separated)
List
StringTokenizer commaTokenizer = new StringTokenizer(imagePaths, ",");
while( commaTokenizer.hasMoreTokens() )
imagePathList.add( commaTokenizer.nextToken() );
// now that I've got the list of image paths (separated)
// I can create every
// single image using an ImageDescriptor
Image[] windowImages = new Image[ imagePathList.size() ];
for( int i = 0; i < imagePathList.size(); i++ ){
ImageDescriptor currentDescriptor =
// single image using an ImageDescriptor
Image[] windowImages = new Image[ imagePathList.size() ];
for( int i = 0; i < imagePathList.size(); i++ ){
ImageDescriptor currentDescriptor =
AbstractUIPlugin.imageDescriptorFromPlugin( bundleID,
imagePathList.get(i) );
windowImages[ i ] = currentDescriptor.createImage();
}
// now set the images for this window
myShell.setImages( windowImages );
imagePathList.get(i) );
windowImages[ i ] = currentDescriptor.createImage();
}
// now set the images for this window
myShell.setImages( windowImages );
Analogamente, se si volessero ottenere informazioni circa la versione e il nome dell'applicativo si puo' usare il seguente pezzo di codice:
Bundle definingBundle = product.getDefiningBundle();
Label valueLabel = new Label( definingBundle.getSymbolicName() );
Label versionLabel = new Label( definingBundle.getVersion().toString() );
o se si vuole cambiare il titolo della finestra principale del workspace affinché rifletta tali informazioni è sufficiente, nel metodo ApplicationWorkbenchWindowAdvisor.preWindowOpen() il seguente blocco di codice:
// get the window configurer object
IWorkbenchWindowConfigurer configurer = this.getWindowConfigurer();
// set the title of the window
StringBuffer title = new StringBuffer( 100 );
title.append( "My App" ); // the fixed part of the title
// get the information from the product
IProduct product = Platform.getProduct();
if( product == null )
title.append( " [Eclipse Application - Development]" );
else{
title.append( " [RCP Product -" );
title.append( product.getName() );
title.append( " ~~ " );
// get some information from the bundle
Bundle definingBundle = product.getDefiningBundle();
title.append(" ID: " );
title.append( definingBundle.getSymbolicName() );
title.append(" ~~ Ver.: " );
title.append( definingBundle.getVersion() );
}
// set the real title
configurer.setTitle( title.toString() );
giovedì 14 ottobre 2010
SWT Widget Disposed & asyncExec
Quando si eseguono operazioni time-consuming in una applicazione SWT occorre che queste siano eseguite fuori dal thread grafico, pena il freeze dell'interfaccia grafica. SWT mette a disposizione due metodi per l'esecuzione di task lunghi:
- i job, simili a dei thread Java contengono il codice da eseguire secondo una politica di schedulazione (anche immediata)
- gli sync/asyncExec, ossia l'esecuzione di un Runnable appena il thread grafico (UI Thread) può
I due approcci, seppur simili,hanno un utilizzo piuttosto differente: i job vengono usati per tutto quello che è prevalentemente non-UI e che non aggiornerà l'interfaccia grafica, mentre gli xxxExec sono per quei processi che richiedono un aggiornamento costante dell'interfaccia grafica, ad esempio per riportare il progresso di una operazione.
Il problema degli asyncExec è che potrebbero venire schedulati per l'esecuzione dopo il disposal di un widget, cosa che si verifica ad esempio quando l'applicazione viene chiusa. In questo caso viene generata una eccezione SWTException che indica appunto che era rimasto in coda un qualche Runnable per l'esecuzione ma che il thread UI non ha fatto in tempo ad eseguirlo prima della chiusura del widget:
org.eclipse.swt.SWTException: Failed to execute runnable (org.eclipse.swt.SWTException: Widget is disposed)
Per ovviare al problema, ogni asyncExec deve testare la validità del widget sopra il quale opera prima di effettuare le modifiche. Si noti che non basta controllare la validità del widget prima della schedulazione del Runnable, poiché questo problema si verifica in base alla capacità del thread UI di schedulare i Runnable e questa non è nota a priori. I Control dispongono tutti di un metodo isDisposed(), che non è però esposto in un Viewer, perciò se si opera con questi ultimi occorre prima recuperare il Control interno (getControl()) e testare quest'ultimo.
mercoledì 7 luglio 2010
SWT vs JFace
Il titolo di questo post è sbagliato: non può esserci competizione fra SWT e JFace, ma solo collaborazione!
E' comunque opportuno spiegare cosa siano SWT e JFace poiché noto che c'è molta confusione sull'argomento, specialmente per chi proviene dal mondo Swing (praticamente tutti gli sviluppatori Java).
SWT è una libreria grafica ad alte prestazioni. In sostanza è un wrapper JNI attorno ai componenti grafici del sistema operativo, quindi attorno a componenti nativi. Questo confluisce le caratteristiche principali di SWT: le prestazioni (al pari del sistema operativo) e il look and feel (del sistema operativo). Per sistema operativo si intende in realtà la shell grafica, e quindi ad esempio Gnome per *nix, Carbon per Mac OSX e così via. Tuttavia SWT è una libreria di basso livello, ossia non fornisce le caratteristiche tipiche della programmazione ad oggetti, ma funziona solo come wrapper attorno ai componenti grafici nativi. In altre parole una tabella SWT non è capace di interpretare un albero di oggetti da visualizzare, ma solo un array di stringhe di testo da inserire ognuna nella propria cella. Questo fa storcere il naso a chi vuole lavorare con modelli complessi e vuole le astrazioni tipiche dell'OOP. Ecco allora che arriva JFace, che altro non è che un wrapper Java attorno a SWT e che consente la programmazione attraverso modelli, handler, eventi specifici.
Sostanzialmente quindi SWT fornisce solo il livello grafico di basso livello, ed è compito del programmatore stabilire come tradurre i propri oggetti in testo da visualizzare, mentre JFace è una libreria ad oggetti che consente di lavorare agevolmente con gli oggetti del proprio business model da tradurre in visualizzazione grafica.
Tornando all'esempio della tabella, SWT accetta un array di stringhe di testo da posizionare nelle celle, e quindi è compito del programmatore scorrere il modello per trasformare tutto in un sol colpo in un formato testo. In JFace invece si hanno degli oggetti (detti provider) che consentono di scorrere il modello in maniera piu' agevole (ad esempio conoscendo l'indice della tupla) e di fornire un pezzo alla volta la forma testuale da visualizzare. Ovviamente le prestazioni sono pressoché identiche, la separazione dei due flussi è solo concettuale.
JFace implementa un MVC molto piu' simile a quello di Swing, ma il cuore del sistema resta sempre e solo SWT.
mercoledì 30 giugno 2010
SWT Virtual Table, libpango e lo strano crash dell'applicazione...
Dopo un sacco di tempo speso nel debugging di una applicazione RCP, sono riuscito a scoprire la causa, abbastanza subdola, di uno strano crash che sembrava essere dovuto da libpango.
La mia applicazione utilizza una serie di tabelle SWT in modalità virtual, quindi con un rendering delle righe fatta su richiesta a seconda della visualizzazione del componente grafico. E qui entra in gioco libpango che si occupa della visualizzazione del testo in Gnome (e quindi su sistemi *nix). Ogni tanto ahimé capitava che l'applicazione andasse in crash con il blocco totale della JVM e uno stack libpango seguito da un dump completo della memoria.
Ebbene ecco la causa:
- essendo la tabella in modalità virtual, ogni volta che doveva disegnare una nuova riga si entra in uno stack nativo (SWT si appoggia ai componenti nativi grafici)
- la tabella richiama un handler Java per ottenere i dati da visualizzare
- nel mio caso l'handler utilizza JDBC/Spring per recuperare un dato da un database
- la connettività genera un'eccezione
- l'eccezione produce un errore nello stack nativo, che a sua volta produce un crash nella libreria libpango e quindi il blocco della JVM
Rimuovendo l'eccezione nell'handler Java (ovvero gestendo opportunamente gli errori) sono giunto alla eliminazione del crash.
Ovviamente, come si evince dalla trattazione, scoprire questo problema non è stato per niente banale a causa dello stack nativo e del suo wrapping attorno al vero problema lato Java che si veniva a generare.
lunedì 15 febbraio 2010
SWT.FULL_SELECTION: momenti di panico nella migrazione di un prodotto
Le tabelle SWT hanno un comportamento abbastanza curioso: di default su piattaforma Linux consentono la selezione di una tupla cliccando su uno qualunque degli elementi visualizzati, mentre su piattaforma Microsoft Windows no. Ho scoperto questo dopo aver migrato un prodotto da Linux a Windows: all'avvio del programma su Windows tutto sembrava regolare, fino a quando non mi sono accorto di essere incapace di selezionare qualunque tupla di una qualunque tabella. Dopo vari esperimenti, aggiornamenti di JVM, ri-esportazione del prodotto, clean dell'intero progetto, il panico ha iniziato a prendere il sopravvento. Poi per caso ho scoperto di riuscire a selezionare la prima cella di ogni riga, e che quello corrispondeva alla selezione dell'intera riga. Avendo ripreso lucidità ho fatto qualche indagine arrivando a scoprire che esiste un particolare flag di SWT, SWT.FULL_SELECTION, che abilita la selezione di una tupla di una tabella indipendentemente dalla cella sulla quale si effettua il click del mouse.
Comportamento abbastanza bizzarro!
mercoledì 20 gennaio 2010
Scrolling automatico di una immagine SWT
E' stata abbastanza dura riuscire a creare una view di Eclipse che potesse fare lo scrolling di una immagine in automatico. Mentre in Swing esiste il poliedrico componente ScrollPane, capace di fare scrolling automatico su praticamente ogni componente (ivi incluse le immagini), nel caso di SWT l'affare si complica.
Anzitutto occorre creare un canvas capace di visualizzare l'immagine, e quindi con associato un paint listener che reagisca agli eventi di rivisualizzazione e disegni l'immagine al suo interno. Attenzione: l'immagine deve essere disegnata sempre nello stesso punto (ad esempio alle coordinate 0,0) poiché non è il canvas a muovere l'immagine ma lo scrolled composite che conterrà il canvas. Terminata la costruzione del canvas, si procede al wrapping dello stesso in uno ScrolledComposite che si preoccuperà di muovere il canvas contenuto. Purtroppo c'è un po' di lavoro in piu' da fare: lo scrolled composite deve avere esplicitamente settato il suo contenuto (il canvas).
Da un punto di vista di codice, questo si traduce nel seguente frammento di inizializzazione della vista Eclipse:
Anzitutto occorre creare un canvas capace di visualizzare l'immagine, e quindi con associato un paint listener che reagisca agli eventi di rivisualizzazione e disegni l'immagine al suo interno. Attenzione: l'immagine deve essere disegnata sempre nello stesso punto (ad esempio alle coordinate 0,0) poiché non è il canvas a muovere l'immagine ma lo scrolled composite che conterrà il canvas. Terminata la costruzione del canvas, si procede al wrapping dello stesso in uno ScrolledComposite che si preoccuperà di muovere il canvas contenuto. Purtroppo c'è un po' di lavoro in piu' da fare: lo scrolled composite deve avere esplicitamente settato il suo contenuto (il canvas).
Da un punto di vista di codice, questo si traduce nel seguente frammento di inizializzazione della vista Eclipse:
public void createPartControl(Composite parent) {
// create a scrolling composite
ScrolledComposite scroller = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL );
// now create a canvas for this view
this.canvas = new Canvas( scroller, SWT.NONE );
scroller.setContent( this.canvas );
// this canvas must show the image when loaded
this.canvas.addPaintListener( new PaintListener(){
@Override
public void paintControl(PaintEvent event) {
if( image != null )
event.gc.drawImage(image, 0, 0 );
}
});
...
}
mercoledì 16 dicembre 2009
Un ComboBox per selezionare le viste di una applicazione RCP
In una applicazione RCP che sto sviluppando mi è capitato di avere molte viste, ciascuna che deve essere associabile ad una serie di permessi. Per permettere ad un utente amministratore di selezionare a quali viste concedere quali permessi, ho creato un semplice wrapper attorno ad un combo che contiene l'array delle viste disponibili e la loro descrizione. Il codice è abbastanza banale, ma potrebbe tornare utile in altre applicazioni.
public class ViewsCombo {
/**
* The combo that will be displayed.
*/
private Combo combo = null;
/**
* The available views in the system.
*/
private IViewDescriptor[] availableViews = null;
/**
* Initializes the combo and the map to contain the views.
* @param parent
*/
public ViewsCombo( Composite parent, String viewIDToSelect ){
super();
// create the combo
this.combo = new Combo( parent, SWT.READ_ONLY );
// fill the combo with the data
this.fillComboAndMap();
// select a view if specified
if( viewIDToSelect != null )
for( int i = 0; i < availableviews =" (IViewDescriptor[])">
public class ViewsCombo {
/**
* The combo that will be displayed.
*/
private Combo combo = null;
/**
* The available views in the system.
*/
private IViewDescriptor[] availableViews = null;
/**
* Initializes the combo and the map to contain the views.
* @param parent
*/
public ViewsCombo( Composite parent, String viewIDToSelect ){
super();
// create the combo
this.combo = new Combo( parent, SWT.READ_ONLY );
// fill the combo with the data
this.fillComboAndMap();
// select a view if specified
if( viewIDToSelect != null )
for( int i = 0; i < availableviews =" (IViewDescriptor[])">
venerdì 27 novembre 2009
SWT e class inheritance
I widget SWT non consentono l'eredità: al loro interno esiste un metodo (checkSubclass()) che effettua dei controlli per garantire che una sottoclasse non venga utilizzata in una applicazione.
Ovviamente questa è una restrizione a run-time, di fatto i componenti possono essere derivati da altri anche se poi non risulteranno utilizzabili a run-time.
Le motivazioni di questa scelta progettuale risiedono nella preferenza della composizione rispetto all'ereditarietà, e mi fa molto piacere vedere che esistano dei framework che si spingono in questa direzione.
Tuttavia ogni tanto è piu' comodo derivare widget da altri piuttosto che usare la composizione (che costringe l'utilizzo di interfacce e la costruzione di API wrapper), ma questo dovrebbe avvenire solo per widget per cui sia garantita la portabilità. Se non si vuole poi implementare la propria logica di controllo nel metodo checkSubclass() è necessario inserire i widgets in un package org.eclipse.swt.widgets.
Ovviamente questa è una restrizione a run-time, di fatto i componenti possono essere derivati da altri anche se poi non risulteranno utilizzabili a run-time.
Le motivazioni di questa scelta progettuale risiedono nella preferenza della composizione rispetto all'ereditarietà, e mi fa molto piacere vedere che esistano dei framework che si spingono in questa direzione.
Tuttavia ogni tanto è piu' comodo derivare widget da altri piuttosto che usare la composizione (che costringe l'utilizzo di interfacce e la costruzione di API wrapper), ma questo dovrebbe avvenire solo per widget per cui sia garantita la portabilità. Se non si vuole poi implementare la propria logica di controllo nel metodo checkSubclass() è necessario inserire i widgets in un package org.eclipse.swt.widgets.
SWT: Combo box con modello integrato
Il widget Combo della libreria SWT non consente l'inserimento nel drop down menu' di oggetti qualunque, ma solo di String. Questa è ovviamente una limitazione perché richiede che il combobox sia affiancato da un modello dati che consenta la correlazione fra indice selezionato e oggetto a cui ci si riferisce.
Creare un wrapper per il Combo che contenga un semplice modello dati lineare (monodimensionale) è un'operazione quasi banale. Nell'esempio sottostante si suppone che BusinessObject sia il capostipite degli oggetti che si vogliono selezionare tramite il Combo; questo wrapper rende il comportamento di Combo piu' simile al suo duale Swing JComboBox.
Creare un wrapper per il Combo che contenga un semplice modello dati lineare (monodimensionale) è un'operazione quasi banale. Nell'esempio sottostante si suppone che BusinessObject sia il capostipite degli oggetti che si vogliono selezionare tramite il Combo; questo wrapper rende il comportamento di Combo piu' simile al suo duale Swing JComboBox.
public class BusinessObjectCombo extends Combo {
public BusinessObjectCombo(Composite parent, int style) {
super(parent, style);
}
/**
* An internal list to keep track of all elements this combo is displaying.
*/
private Listmodel = new LinkedList ();
/**
* Provides the business object corresponding to the selected element in the combo.
* @return the business object from the combo
*/
public synchronized final BusinessObject getSelectedBusinessObject(){
// get the selected index
int index = this.getSelectionIndex();
// return the element from the model
return this.model.get(index);
}
/**
* Adds a new business object to the combo and to the internal model.
* @param newElement
*/
public synchronized final void add(BusinessObject newElement){
// check arguments
if( newElement == null )
return;
else{
// add the element to the list and to the combo
this.model.add(newElement);
this.add( newElement.toString() );
}
}
/**
* Removes the specified element from the combo.
* @param element
*/
public synchronized final void remove(BusinessObject element){
// get the index from the model
int index = this.model.indexOf(element);
if( index >= 0 ){
this.model.remove(index);
this.remove(index);
}
}
/**
* Clears all the elements from the combo and the internal model.
*/
public synchronized final void clear(){
this.model = new LinkedList();
this.removeAll();
}
/**
* Adds all the elements from the specified collection.
* @param businessObjects
*/
public synchronized final void addAll(Collection businessObjects ){
for( BusinessObject bo : businessObjects )
this.add( bo );
}
}
Iscriviti a:
Post (Atom)