MokaByte Numero 15 - Gennaio 1998
Foto
 
Specifiche Glasgow
III Puntata
di
Daniela Ruggeri
Sottosistema Drag And Drop per Java Foundation Class 

 


La necessità di gestire un Meccanismo di Trasferimento Dati Uniforme (Uniform Data Transfer Mechanism),
il Clipboard e le operazioni di Drag and Drop per AWT, nasce già da un lavoro iniziato nel 1996.
Nell’AWT del JDK1.1 sono state gia’ introdotte le API per la gestione dei protocolli Uniform Data Transfer Mechanism e Clipboard.
In queste specifiche si definiscono le API per le operazioni di Drag and Drop per JDK 1.2.


 

Introduzione
 

Nel definire le specifiche per le operazioni di Drag and Drop ci si pongono innnanzi tutto i seguneti obiettivi:

  1. Un’utilità di operazione di Drag and Drop indipendente dalla piattaforma per clients Java GUI implentatata attraverso le classi AWT e JFC.
  2. L’integrazione con le operazioni di Drag and Drop dipendenti dalla piattaforma, permettendo ai clients Java di partecipare nelle operazioni DnD con applicazioni native usando:
     
  1. Far in modo che l’esistente pacchetto java.awt.datatransfer.* sia abilitato al trasferimento dei dati, descritti dal sistema di tipi di dati basato sullo standard MIME.
  2. Non precludere l’uso accessibilità dei dati dove sia possibile.

Panoramica

Come tutti sanno l’operazione di Drag and Drop coinvolge l’utente in prima persona all’interno di un’interfaccia GUI e consiste in 2 fasi
 


In genere le operazioni che vengono eseguite dal sistema sono due: copy e move, cioè copy o move dell’oggetto source nel target scelto (per esempio copy di un file da una directory ad un'altra).

Una tipica operazione di Drag and Drop può essere decomposta nei seguenti stati (non tutti strettamente sequenziali):
 

  1. Un Drag Source per segnalare la sua esistenza viene associato ad un elemento Gui che rappresenta il tipo di oggetto e l’intenzione all’operazione di trasferimento file.( Per esempio in figura 1. appare un simbolo di Drag source che rappresenta che si vuole trasportare un file (in questo caso html) in una directory.
  2. 1 o più Drop Targets (dipendenti dal tipo di ambiente dove si sta operando) per segnalare la loro esistenza vengono associati ad elementi GUI, che rappresentano l’intenzione di portare a termine l’operazione di trasferimento dati.
  3. L'utente inizia l’operazione di Drag and Drop. In questo momento il Drag Source riceve la notifica dell’operazione allo scopo di poter gestire un effetto di "Drag Over", i Drop Target(s) ricevono la notifica allo scopo di poter gestire un effetto di "Drag Under". I due effetti si traducono con una particolare rappresentazione del cursore che si sta muovendo.
  4. Il successo o il fallimento dell’operazione di trasferimento dati dipende dai seguenti parametri:

Il nuovo modello Drag and Drop comprende
 

La classe DragSource
 

Il DragSource è l'entità responsabile della coordinazione dell'operazione Drag and Drop.

Struttura DragSource:

public abstract class java.awt.dnd.DragSource {

        public static int ACTION_NONE = 0x0;

        public static int ACTION_COPY = 0x1;

        public static int ACTION_MOVE = 0x2;

        public static int ACTION_COPY_OR_MOVE = ACTION_COPY | ACTION_MOVE;

        public DragSourceContext startDrag(Component c,

                                                AWTEvent trigger, int actions,

                                                Point imgaeOffset,

                                                Image dragImage,

                                                Transferable transferable,

                                                DragSourceListener dsl)

                        throws InvalidDnDOperationException;

        public DragSourceContext startDrag(Component c,

                                                AWTEvent trigger,

                                                int actions,

                                                Transferable transferable,

                                                DragSourceListener dsl)

                        throws InvalidDnDOperationException;

        public void setDefaultSourceActions(int actions);

        public int getDefaultSourceActions();

        public void setDefaultDragCursor(Cursor c);

        public Cursor getDefaultDragCursor();

        public void setDefaultDropCursor(Cursor c);

        public Cursor getDefaultDropCursor();

        public void setDefaultNoDropCursor(Cursor c);

        public Cursor getDefaultNoDropCursor();

        public boolean isDragTrigger(AWTEvent trigger);

        public Rectangle getDragThresholdBBox(Point hotspot);

        public Rectangle getDragThresholdBBox(AWTEvent awte);

}
 

Il DragSource può essere utilizzato in uno dei seguenti scenari: Le piattaforme con sistema Window usualmente definiscono un insieme di azioni manuali (tipicamente realizzate tramite mouse o tastiera) associate con un'operazione di Drag and Drop.
Il DragSource fornisce un meccanismo che permette di testare se uno stream di un AWTEvent associato a quell'azione manuale è possibile per una particolare piattaforma.
In particolare il metodo isDragTrigger() esamina l'AWTEvent per determinare se esso sia un possibile evento Drag scatenabile.
Inoltre, il metodo getDragThresholdBBox() ritorna un Rectangle, centrato nel Point che risulta (a secondo la struttura del metodo): Nel secondo caso questo contorno definisce la minima area attraverso la quale il cursore può muoversi in ciascuna coordinata x e y al fine di completare l’azione manuale iniziata.

Quando un'azione manuale viene iniziata, viene invocato il metodo startDrag(). Se l'operazione di Drug ha un esito positivo, questo metodo ritorna al chiamante un'istanza della classe DragSourceContext. I parametri del metodo startDrag() includono:


Il DragSourceContext ritornato fornisce lo stato e il controllo all’originatore dell'operazione Drag per tutta la sua durata attraverso l'interfaccia associata al DragSourceListener (altro parametro passato nella chiamata al startDrag() ).
Infine il parametroTransferable (interfaccia che fornisce informazioni sui dati da trasferire) associato con il DragSourceContext all'inizio dell'operazione Drag, rappresenta il dato o l'oggetto fulcro, cioè l'informazione passata tra il DragSource e il DropTarget come risultato di un Drop con esito positivo.
 
 

La classe DragSourceContext

Questa classe rappresenta uno dei possibili stati attraversati durante l'operazione di Drag.

Struttura:

public interface DragSourceContext {

        DragSource getDragSource();

        Component getComponent();

        AWTEvent getTrigger();

        public Transferable getTransferable();

        void cancelDrag() throws InvalidDnDOperationException;

        void commitDrop() throws InvalidDnDOperationException;

        int getSourceActions();

        void setSourceActions(int actions) throws InvalidDnDOperationException;

        void setCursor(Cursor Cursor);

        Cursor getCursor();

        void addDragSourceListener(DragSourceListener dsl) throws TooManyListenersException;

        void removeDragSourceListener(DragSourceListener dsl);

}
 
 
 

Se poniamo ds = DragSource, dsl = DragSourceListener, dc = DragSourceContext, gli stati attravversati dall’operazione Drag and Drop iniziano dal metodo ds.startDrag() per passare al metodo dsl.DragBegin(), dopo di che tutte le possibili sequenze di metodi richiamati sono dettagliati nella tabella di seguito (ogni riga rappresenta uno stato e i simboli * # + indicano delle ricorrenze nei percorsi):
 
 
 
dsl.dragGestureChanged()+ dc.commitDrop() dsl.dragDropEnd()      
dsl.dragGestureChanged() # dc.cancelDrag() dsl.dragDropEnd()      
dsl.dragEnter()* dsl.dragGestureChanged()+ dc.commitDrop() dsl.dragDropEnd()    
dsl.dragEnter()* dsl.dragGestureChanged()# dc.cancelDrag() dsl.dragDropEnd()    
dsl.dragEnter()+ dc.commitDrop() dsl.dragDropEnd()      
dsl.dragEnter() dsl.dragOver()* dsl.dragGestureChanged()+ dc.commitDrop() dsl.dragDropEnd()  
dsl.dragEnter() dsl.dragOver()* dsl.dragGestureChanged()# dc.cancelDrag() dsl.dragDropEnd()  
dsl.dragEnter() dsl.dragOver()+ dc.commitDrop() dsl.dragDropEnd()    
dsl.dragEnter() dsl.dragOver()* dsl.dragExit()* dsl.dragGestureChanged()+ dc.commitDrop() dsl.dragDropEnd()
dsl.dragEnter() dsl.dragOver()* dsl.dragExit()* dsl.dragGestureChanged() # dc.cancelDrag() dsl.dragDropEnd()
dsl.dragEnter() dsl.dragOver()+ dsl.dragExit() dsl.dragDropEnd()    
dc.cancelDrag() dsl.dragDropEnd()        

 
 
 

La notifica dei cambiamenti di stato durante l’operazione di Drag and Drop sono spediti dal DragSource, all’appropriato DragSourceContext, che delega le notifiche a un arbitrario oggetto che implementa DragSourceListener che gestisce il cambiamento del cursore. L'arbitrario oggetto è un JavaBeans con associata un'estensione dell’interfaccia EventListener unicast (ovvero con un solo ascoltatore, in quanto per gestire il cambiamento del cursore basta una sola classe che sia in ascolto e intervenga al momento opportuno).

Il compito primario del DragSourceListener è quello di monitorare la navigazione dell’utente durante l’operazione Drag and Drop e di fornire un effetto "Drag-over" all’utente. Tipicamente questo si traduce nel cambiamento a secondo dei casi del cursore nella fase di Drag (Drag Cursor).

Ogni oggetto DragSource ha 3 possibili tipi di cursori di default a secondo dello stato in cui si trova:


Questi valori di default sono usati dal DragSource durante l’operazione di drag, ma possono essere ridefiniti dal DragSourceListener chiamando il metodo setCursor() dell’interfaccia DragSourceContext interface ottenuta attraverso il DragEvent.
 
 

L’interfaccia DragSourceListener

Questa è l'interfaccia associata allo stato  DragSourceContext dell'operazione di Drug.
 

Struttura:

public interface java.awt.dnd.DragSourceListener extends java.util.EventListener {

        void dragBegin (DragSourceDragEvent dsde);

        void dragEnter (DragSourceDragEvent dsde);

        void dragOver (DragSourceDragEvent dsde);

        void dragGestureChanged(DragSourceDragEvent dsde);

        void dragExit (DragSourceDragEvent dsde);

        void dropStart (DragSourceDropEvent dsde);

        void dragDropEnd (DragSourceDropEvent dsde);

}
 

Il metodo dragBegin() è chiamato come risultato dell’invocazione del metodo startDrag() e rappresenta la semplice notifica dell’inizio del drag.

I metodi che vengono successivamente invocati durante la navigazione del cursore logico di drug quando questo incontra oggetti GUI con associati DropTargets, sono:
 


Il DragSourceListener può durante l’invocazione dei metodi dragEnter(), dragOver(), dragExit() o dragGestureChanged() può a sua volta:

Il metodo dragGestureChanged() è invocato quando cambia lo stato del dispositivo di input (usualmente i bottoni del mouse o i caratteri della tastiera) manovrato dall’utente per gestire l’operazione di Drag.

Questo cambiamento viene interpretato come un drop, e il metodo lo segnala all’indietro al DragSource attraverso il metodo commitDrop().

Il DragSource notificherà al DropTarget l’avvenuto Drop e gli passerà i dati Transferable[].

Successivamente viene invocato il metodo dragDropEnd() che compunica che l’operazione è completata.

I metodi isDragAborted() e isDropSuccessful() del DragSourceDropEvent possono essere usati per sapere lo stato di terminazione dell’operazione.
 
 

La classe DragSourceDragEvent

E' l'evento gestito dalla lista ascoltatrice DragSourceListener in fase di Drag.

Struttura:
 

public class java.awt.dnd.DragSourceDragEvent extends java.util.EventObject {

        public DragSourceContext getDragSourceContext();

        public int getTargetActions();

        public int getGestureModifiers();

}
 


Un’istanza di questa classe viene passata ai metodi dragBegin(), dragEnter(), dragOver(), dragGestureChanged() e dragExit() della DragSourceListener.

Il metodo getDragSourceContext() ritorna il DragSourceContext associato al corrente stato di dell’operazione Drag and Drop.

Il metodo getTargetActions() ritorna le azioni dell’operazione drop, supportate e ritornate dal corrente DropTarget.

Il metodo getGestureModifiers() ritorna il corrente stato del dispositivo di input (mouse o tastiera) usato dall’utente per gestire l’operazione.
 
 

La classe DragSourceDropEvent

E' l'evento gestiti dalla lista ascoltatrice DragSourceListener in fase di Drop.

Struttura:

public public class java.awt.dnd.DragSourceDropEvent extends java.util.EventObject {

        boolean isDragCancelled();

        boolean isDropSuccessful();

}
 

Un’istanza di questa classe viene passata al metodo dragDropEnd() della DragSourceListener.

Se un’operazione Drag abortisce per qualche ragione viene richiamato il metodo cancelDrag() dell’interfaccia DragSourceContext, e il metodo isDropAborted() restituisce vero; se invece l’operazione riesce, il metodo isDropAborted() restituisce falso.

Se il Drop occorre, allora il DropTarget coinvolto segnalerà il successo o il fallimento del trasferimento dati attraverso il metodo dropComplete() dell’interfaccia DropTargetContext; il metodo isDropSuccessful() restituirà vero o falso a secondo dei casi.
 
 

DropTarget

Un DropTarget incapsula tutti gli handling sulla determinata piattaforma del protocollo Drag and Drop che rispettano le regole della destinazione dell'operazione.

Un'istanza di un DropTarget può essere associata ad un'arbritraria istanza di java.awt.Component supportata.

Struttura:

public abstract class java.awt.dnd.DropTarget {

        public Component getComponent();

        public void setAutoScrollInsets(Insets scrollInsets);

        public Insets getAutoScrollInsets();

        public void setDefaultTargetActions(int actions);

        public int getDefaultTargetActions();

        public void addDropTargetListener(DropTargetListener dte) throws TooManyListenersException;

        public void removeDropTargetListener(DropTargetListener dte);

        public void setTargetActive(boolean active);

        public boolean isTargetActive();

}
 

Se il Component associato con il particolare DropTarget supporta lo scrolling, il DropTarget può comunicare questa funzionalità all'operazione Drag and Drop, permetendo quindi ai componenti gestiti un "autoscroll" del loro contenuto, sotto il cursore logico. Questa funzionalità viene attivata in un periodo di stasi del cursore entro una regione corrispondente alla scatola del componente meno gli Insets impostati dal metodo setAutoScrollInsets().

L'interfaccia DropTargetContext

Esattamente come un DragSourceContext fornisce informazioni su uno degli stati intermedi nell'operazione di Drag and Drop, così un DropTargetContext fornisce informazioni sullo stato (uno solo) e sul controllo sullo stato finale Drop.

 Struttura:

 public interface DropTargetContext {
                DropTarget getDropTarget();
                Component getComponent();
                void setTargetActions(int actions) throws InvalidDnDOperationException;
                int getTargetActions();
                void dropComplete(boolean dropSucceeded) throws InvalidDnDOperationException;
}
Come vedete l'associazione con la lista ascoltatrice non si trova qui come avveniva nell'analoga interfaccia DragSourceContext per la lista DragSourceListener, ma è spostata nella classe DropTarget in quanto nell'operazione di Drag erano possibili più stati e quindi più istanze della lista, qui invece c'è da gestire il solo stato Drop.

 Dall'evento DropTargetEvent passato ai metodi dell'interfaccia DropTargetListener e che dal quale si può risalire all'interfaccia DropTargetContext, si può conoscere

La classe DropTargetListener

Fornisce un effetto "Drag-under", e processa ogni successivo Drop. E' abilitato attraverso l'interfaccia DropTargetListener associata al DropTarget.

Il DropTargetListener determina l'appropriato effetto "Drag-under" e le risposte al DragSource circa la possibilità in fase di drop di elaborare tutte le azioni scatenate e circa l'accessibilità ai tipi di dati da trasferire.

L'istanza DropTargetListener può essere associata con un DropTarget mediante il metodo addDropTargetListener() e rimossa mediante il metodo removeDropTargetListener().

public interface java.awt.dnd.DropTargetListener extends java.util.EventListener {
                void dragEnter (DropTargetDragEvent dtde);
                void dragOver (DropTargetDragEvent dtde);
                void dragExit (DropTargetDragEvent dtde);
                void dragGestureChanged(DropTargetDragEvent dtde);
                void dragScroll (DropTargetDragEvent dtde);
                void drop (DropTargetDropEvent dtde);
}
I metodi dragEnter(), dragOver () e dragExit() hanno lo stesso significato dei metodi dell'interfaccia DragSourceListener solo che qui vengono gestiti dall'interfaccia DropTargetListener

Il metodo dragScroll() viene invocato quando il puntamento di un cursore logico "Drag" è rimasto fermo un piccolo periodo di tempo, e interseca sia il Component associato al DropTarget sia la zona Scroll Insets. La DropTargetListener, dopo ricevuta la notifica deve, se supporta lo scrolling, scrollare il contenuto di dati associato al Component del DropTarget (per esempio il contenuto di una choice se questa rappresenta il Component assocciato).

Il metodo drop() è invocato in seguito all'invocazione del metodo commitDrop() riguardante il DragSource.

La DropTargetListener, ricevuta questa notifica, deve eseguire l'operazione specificata dal valore di ritorno del metodo getSourceActions() sull'oggetto DropTargetDropEvent con i Transferable[] object[s] restituiti dal metodo getTransferable() e successivamente deve invocare il metodo dropComplete() per segnalare il successo o il fallimento dell'operazione.
 
 

Gli eventi DropTargetEvent, DropTargetDragEvent e DropTargetDropEvent

Gli eventi di competenza della classe DropTarget riguardano la classe DropTargetEvent e le sue estensioni DropTargetDragEvent e DropTargetDropEvent
 

Struttura della classe DropTargetEvent:

public interface DropTargetContext {

        DropTarget getDropTarget();

        Component getComponent();

        void setTargetActions(int actions) throws InvalidDnDOperationException;

        int getTargetActions();

        void dropComplete(boolean dropSucceeded) throws InvalidDnDOperationException;

}
 
 
 

Il metodo getCursorLocation() ritorna le coordinate, relativamente al componente associato, del puntatore del cursore logico di "Drag".

Il metodo getSourceActions() ritorna le correnti azioni o operazioni (ACTION_MOVE o ACTION_COPY) associate dal DragSource al corrente gesto manuale di Drag and Drop.

Struttura della classe DropTargetDragEvent:

public class java.awt.dnd.DropTargetDragEvent extends java.awt.dnd.DropTargetEvent {

        public DataFlavor[][] getDataFlavors();

}
 
 
 

Il DropTargetDragEvent  è l'evento passato ai metodi dragEnter(), dragOver(), dragExit() and dragScroll() dell'nterfaccia DropTargetListener.

Il metodo getDataFlavors() ritorna i tipi di dati disponibili in ordine discendente di preferenza dei dati coinvolti nell'operazione Drag and Drop.

Struttura della classe DropTargetDropEvent:

public class java.awt.dnd.DropTargetDropEvent extends java.awt.dnd.DropTargetEvent []

        public Transferable getTransferable();

}
 
 
 

Il DropTargetDropEvent  è l'evento passato al metodo  drop() dell'interfaccia DropTargetListener non appena il  Drop occurre. Questo evento fornisce il metodo getTransferable() che restituisce l'interfaccia Transferable (interfaccia che fornire i dati per le operazioni di trasferimento alle classi a cui serve).

Conclusione

Con questa puntata concludiamo le specifiche Glasgow. Speriamo che questi articoli siano stati di utilità a chi sta intraprendere lo studio dell'affascinante mondo dei JavaBeans.

                                                                                                                                                                Daniela Ruggeri
 
 
 


MokaByte Web  1998 - www.mokabyte.it

MokaByte ricerca nuovi collaboratori. 
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it