/*
 * Java-Gnome Bindings Library
 *
 * Copyright 2005 the Java-Gnome Team, all rights reserved.
 *
 * The Java-Gnome bindings library is free software distributed under
 * the terms of the GNU Library General Public License version 2.
 */

package draganddrop;

import org.gnu.gdk.Atom;
import org.gnu.gdk.DragAction;
import org.gnu.gdk.DragContext;
import org.gnu.gdk.ModifierType;
import org.gnu.gtk.*;
import org.gnu.gtk.event.*;

/**
 * @author Ismael Juma <ismael@juma.me.uk>
 */
public class DnDExample2 {

    private TextBuffer textBuffer;

    private TextView textView;

    private RadioButton stringRadio;

    private RadioButton intRadio;

    private static final int TARGET_INT = 0;

    private static final int TARGET_STRING = 1;

    private TargetEntry[] targetList;

    public DnDExample2(String[] args) {
        Gtk.init(args);
        targetList = new TargetEntry[] {
                new TargetEntry("INTEGER", TargetFlags.NO_RESTRICTION,
                        TARGET_INT),
                new TargetEntry("STRING", TargetFlags.NO_RESTRICTION,
                        TARGET_STRING), };
        int winXSize = 450;
        int winYSize = 150;
        Window window = new Window(WindowType.TOPLEVEL);
        VBox vbox = new VBox(false, 5);
        HBox hbox = new HBox(false, 5);
        VBox radioBox = new VBox(false, 2);
        stringRadio = new RadioButton((RadioButton) null, "Send String", false);
        intRadio = new RadioButton(stringRadio, "Send int", false);
        textBuffer = new TextBuffer();
        textView = new TextView(textBuffer);
        radioBox.add(stringRadio);
        radioBox.add(intRadio);
        radioBox.add(textView);
        Button source = new Button("-[source]-", false);
        Label destination = new Label("-[destination]-");
        Label directionsLabel = new Label(
                "drag from the source to the destination");
        vbox.add(hbox);
        vbox.add(radioBox);
        window.add(vbox);
        hbox.add(source);
        hbox.add(directionsLabel);
        hbox.add(destination);
        window.setDefaultSize(winXSize, winYSize);
        source.setDragSource(ModifierType.BUTTON1_MASK, targetList,
                DragAction.COPY);
        destination.setDragDestination(DestDefaults.MOTION
                .or(DestDefaults.HIGHLIGHT), targetList, DragAction.COPY);

        window.addListener(new LifeCycleListener() {
            public boolean lifeCycleQuery(org.gnu.gtk.event.LifeCycleEvent event) {
                if (event.getType() == LifeCycleEvent.Type.DELETE
                        || event.getType() == LifeCycleEvent.Type.DESTROY) {
                    Gtk.mainQuit();
                }
                return false;
            }

            public void lifeCycleEvent(LifeCycleEvent event) {
            }
        });

        // Note if we did not intend to override all the methods of the
        // interface, then we would use DragDestinationAdapter. Using that
        // adapter we only need to implement the methods we need to
        // override.
        destination.addListener(new DragTargetListener() {
            public void dataReceived(ReceiveDragDataEvent event) {
                handleDataReceived(event);
            }

            public void destinationLeft(LeaveDragDestinationEvent event) {
                handleDestinationLeft(event);
            }

            public boolean dropped(DropDragEvent event) {
                return handleDropped(event);
            }

            public boolean motionOcurred(DragMotionEvent event) {
                return handleMotionOcurred(event);
            }
        });

        source.addListener(new DragOriginListener() {

            public void dragStarted(StartDragEvent event) {
                handleDragStarted(event);
            }

            public void dragEnded(EndDragEvent event) {
                handleDragEnded(event);
            }

            public void dataRequested(RequestDragDataEvent event) {
                handleDataRequested(event);
            }

            public void dataDeleted(DeleteDragDataEvent event) {
                handleDataDeleted(event);
            }

        });

        window.showAll();
        Gtk.main();
    }

    private void handleDragStarted(StartDragEvent event) {
        Widget w = (Widget) event.getSource();
        System.out.println(w.getName() + ": handleDragStarted");
    }

    private void handleDataDeleted(DeleteDragDataEvent event) {
        Widget w = (Widget) event.getSource();
        System.out.println(w.getName() + ": handleDragDeleted");
    }

    private void handleDestinationLeft(LeaveDragDestinationEvent event) {
        Widget w = (Widget) event.getSource();
        System.out.println(w.getName() + ": handleDestinationLeft");
    }

    private void handleDataReceived(ReceiveDragDataEvent event) {
        int iData = 0;
        String sData = null;
        boolean dndSuccess = false;
        boolean deleteSelectionData = false;
        String name = ((Widget) event.getSource()).getName();
        System.out.println(name + " handleDataReceived");
        SelectionData sd = event.getSelectionData();
        DragContext dc = event.getDragContext();
        if (dc.getAction() == DragAction.MOVE) {
            deleteSelectionData = true;
        }

        System.out.println("Receiving");
        switch (event.getTargetInfo()) {
        case TARGET_INT:
            iData = sd.getInt();
            dndSuccess = true;
            textBuffer.setText("Received int: " + iData + ".");
            break;
        case TARGET_STRING:
            sData = sd.getText();
            dndSuccess = true;
            textBuffer.setText("Received String: '" + sData + "'.");
            break;
        }

        if (dndSuccess == false) {
            textBuffer.setText("DnD data transfer failed.");
        }

        dc.finish(dndSuccess, deleteSelectionData, event.getTime());
    }

    private void handleDataRequested(RequestDragDataEvent event) {
        Widget widget = (Widget) event.getSource();
        String name = widget.getName();
        System.out.println(name + ": handleDataRequested");
        String data = "This is data from the source";
        int integerData = 42;

        System.out.println("Sending");
        SelectionData sd = event.getSelectionData();

        switch (event.getTargetInfo()) {
        case TARGET_INT:
            sd.setInt(integerData);
            break;
        case TARGET_STRING:
            sd.setText(data);
            break;

        }

    }

    private boolean handleDropped(DropDragEvent event) {
        boolean isValidDropSite = true;
        Atom targetType;
        Widget widget = (Widget) event.getSource();
        String name = widget.getName();
        System.out.println(name + ": handleDropped");
        DragContext dc = event.getDragContext();
        int index = 0;
        if (stringRadio.getState() == true) {
            index = TARGET_STRING;
        } else {
            index = TARGET_INT;
        }

        if (dc.getTargets().length > index) {
            targetType = dc.getTargets()[index];
            widget.getDragData(dc, targetType, event.getTime());
        }

        else {
            isValidDropSite = false;
        }

        return isValidDropSite;
    }

    private boolean handleMotionOcurred(DragMotionEvent event) {
        // This line was commented out as it sends a lot of output to the
        // command
        // line
        // System.out.println("handleMotionOcurred");
        return false;
    }

    private void handleDragEnded(EndDragEvent event) {
        Widget w = (Widget) event.getSource();
        System.out.println(w.getName() + ": handleDragEnded");
    }

    public static void main(String[] args) {
        DnDExample2 example = new DnDExample2(args);

    }
}
