(SWT) DND + Reflection

T

Tobias Köhler

Hallo,

ich versuche mich zur Zeit daran, in SWT DND zu implementieren.
Gleichzeitig möchte ich durch Reflection das Ganze so halten, dass man jedes Objekt für DND nutzen kann, dass ein bestimmtes Interface implementiert.

Bisher habe ich:
- ein Interface Transferable mit den Methoden javaToNative (sendet die Daten an einen Outputstream), nativeToJava (und holt sie aus einem Inputstream), checkMyType (kann man dieses Objekt hinzufügen?)
- eine Entität, die von ByteArrayTransfer erbt und das Transferable Interface implementiert.

Nochmal zusammengefasst:
SOLL:
- Objekt erbt von Objekt, das ByteArrayTransfer und Transferable nutzt
- Anpassen der Methoden aus Interface
- für Jedes Objekt ohne zusätzliche Klassen möglich

IST:
- Objekt erbt von ByteArrayTransfer und implementiert Transferable
- Dieses Objekt kann für DND genutzt werden
- Reflection fehlt
---------------------------
Mein Source:

Das Interface
Java:
import org.eclipse.swt.dnd.TransferData;

public interface Transferable{
   
   /***********************************************************************
    * Write the Object to an OutputStream
    * @param object 
    * @param transferData
    **********************************************************************/
   public void javaToNative(Object object, TransferData transferData);
   
   /***********************************************************************
    * Create Object(s) from InputStream
    * @param transferData
    * @return
    **********************************************************************/
   public Object nativeToJava(TransferData transferData);
   
   /***********************************************************************
    * Checks the Object if it is an Instance of the Object to be transfered
    * @param object
    * @return
    **********************************************************************/
   public boolean checkMyType(Object object);

}

Das Objekt:
Java:
public class MyType extends ByteArrayTransfer implements Transferable{
   private static final String MYTYPENAME = "MyType";

   private static final int MYTYPEID = registerType(MYTYPENAME);
   
   public String fileName;

   public long fileLength;

   public long lastModified;

   public void javaToNative(Object object, TransferData transferData) {
      if (!checkMyType(object) || !isSupportedType(transferData)) {
         DND.error(DND.ERROR_INVALID_DATA);
       }
       MyType[] myTypes = (MyType[]) object;
       try {
         // write data to a byte array and then ask super to convert to
         // pMedium
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         DataOutputStream writeOut = new DataOutputStream(out);
         for (int i = 0, length = myTypes.length; i < length; i++) {
           byte[] buffer = myTypes[i].fileName.getBytes();
           writeOut.writeInt(buffer.length);
           writeOut.write(buffer);
           writeOut.writeLong(myTypes[i].fileLength);
           writeOut.writeLong(myTypes[i].lastModified);
         }
         byte[] buffer = out.toByteArray();
         writeOut.close();
         super.javaToNative(buffer, transferData);
       } catch (IOException e) {
       }
      
   }

   public Object nativeToJava(TransferData transferData) {
      if (isSupportedType(transferData)) {
        byte[] buffer = (byte[]) super.nativeToJava(transferData);
        if (buffer == null)
          return null;

        MyType[] myData = new MyType[0];
        try {
          ByteArrayInputStream in = new ByteArrayInputStream(buffer);
          DataInputStream readIn = new DataInputStream(in);
          while (readIn.available() > 20) {
            MyType datum = new MyType();
            int size = readIn.readInt();
            byte[] name = new byte[size];
            readIn.read(name);
            datum.fileName = new String(name);
            datum.fileLength = readIn.readLong();
            datum.lastModified = readIn.readLong();
            MyType[] newMyData = new MyType[myData.length + 1];
            System
                .arraycopy(myData, 0, newMyData, 0,
                    myData.length);
            newMyData[myData.length] = datum;
            myData = newMyData;
          }
          readIn.close();
        } catch (IOException ex) {
          return null;
        }
        return myData;
      }

      return null;
    }

   protected String[] getTypeNames() {
      return new String[] { MYTYPENAME };
    }

    protected int[] getTypeIds() {
      return new int[] { MYTYPEID };
    }

   public boolean checkMyType(Object object) {
      if (object == null || !(object instanceof MyType[])
          || ((MyType[]) object).length == 0) {
        return false;
      }
      MyType[] myTypes = (MyType[]) object;
      for (int i = 0; i < myTypes.length; i++) {
        if (myTypes[i] == null || myTypes[i].fileName == null
            || myTypes[i].fileName.length() == 0) {
          return false;
        }
      }
      return true;
    }
}

Und zuletzt die Klasse zum Ausführen:
Java:
public class Snippet79 {

  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    final Label label1 = new Label(shell, SWT.BORDER | SWT.WRAP);
    label1.setText("Drag Source for MyData[]");
    final Label label2 = new Label(shell, SWT.BORDER | SWT.WRAP);
    label2.setText("Drop Target for MyData[]");

    DragSource source = new DragSource(label1, DND.DROP_COPY);
    source.setTransfer(new Transfer[] { new MyType() });
    source.addDragListener(new DragSourceAdapter() {
      public void dragSetData(DragSourceEvent event) {
        MyType myType1 = new MyType();
        myType1.fileName = "C:\\abc.txt";
        myType1.fileLength = 1000;
        myType1.lastModified = 12312313;
        MyType myType2 = new MyType();
        myType2.fileName = "C:\\xyz.txt";
        myType2.fileLength = 500;
        myType2.lastModified = 12312323;
        event.data = new MyType[] { myType1, myType2 };
      }
    });
    DropTarget target = new DropTarget(label2, DND.DROP_COPY
        | DND.DROP_DEFAULT);
    target.setTransfer(new Transfer[] { new MyType() });
    target.addDropListener(new DropTargetAdapter() {
      public void dragEnter(DropTargetEvent event) {
        if (event.detail == DND.DROP_DEFAULT) {
          event.detail = DND.DROP_COPY;
        }
      }

      public void dragOperationChanged(DropTargetEvent event) {
        if (event.detail == DND.DROP_DEFAULT) {
          event.detail = DND.DROP_COPY;
        }
      }

      public void drop(DropTargetEvent event) {
        if (event.data != null) {
          MyType[] myTypes = (MyType[]) event.data;
          if (myTypes != null) {
            String string = "";
            for (int i = 0; i < myTypes.length; i++) {
              string += myTypes[i].fileName + " ";
            }
            label2.setText(string);
          }
        }
      }

    });
    shell.setSize(200, 200);
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}

Hoffe ihr könnt mir helfen und mein Problem ist verständlich ;)
 
Was möchtest du denn jetzt noch mit Reflection machen? Also wo kommst du nicht weiter?
 
Der Nachteil an meiner Implementierung ist, dass sehr unflexibel ist. Wenn ich jetzt eine weitere Entität für DND nutzen will, dann muss für diese ein extra Transferobjekt verfasst werden... Bzw Code, der eigentlich schon woanders genauso steht wird nochmal geschrieben. Das finde ich unschön. Ich hatte gehofft, über Reflection das Transferobjekt so allgemein zu halten, dass man hierüber nur noch die Attribute des Types füllen muss.... Vll denke ich auch nur zu kompliziert?:-D
 
Zurück