001    /******************************************************************************
002     * Copyright (C) MActor Developers. All rights reserved.                        *
003     * ---------------------------------------------------------------------------*
004     * This file is part of MActor.                                               *
005     *                                                                            *
006     * MActor is free software; you can redistribute it and/or modify             *
007     * it under the terms of the GNU General Public License as published by       *
008     * the Free Software Foundation; either version 2 of the License, or          *
009     * (at your option) any later version.                                        *
010     *                                                                            *
011     * MActor is distributed in the hope that it will be useful,                  *
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
014     * GNU General Public License for more details.                               *
015     *                                                                            *
016     * You should have received a copy of the GNU General Public License          *
017     * along with MActor; if not, write to the Free Software                      *
018     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA *
019     ******************************************************************************/
020    package org.mactor.ui.gui.project;
021    
022    import java.awt.Color;
023    import java.awt.Component;
024    import java.awt.Point;
025    import java.awt.datatransfer.StringSelection;
026    import java.awt.datatransfer.Transferable;
027    import java.awt.dnd.DnDConstants;
028    import java.awt.dnd.DragGestureEvent;
029    import java.awt.dnd.DragGestureListener;
030    import java.awt.dnd.DragSource;
031    import java.awt.dnd.DragSourceAdapter;
032    import java.awt.dnd.DragSourceContext;
033    import java.awt.dnd.DragSourceDragEvent;
034    import java.awt.dnd.DragSourceDropEvent;
035    import java.awt.dnd.DragSourceListener;
036    import java.awt.dnd.DropTarget;
037    import java.awt.dnd.DropTargetAdapter;
038    import java.awt.dnd.DropTargetDragEvent;
039    import java.awt.dnd.DropTargetDropEvent;
040    
041    import javax.swing.BorderFactory;
042    import javax.swing.Icon;
043    import javax.swing.JLabel;
044    import javax.swing.JTree;
045    import javax.swing.TransferHandler;
046    import javax.swing.border.Border;
047    import javax.swing.border.LineBorder;
048    import javax.swing.tree.DefaultTreeCellRenderer;
049    import javax.swing.tree.TreePath;
050    
051    import org.mactor.framework.MactorException;
052    import org.mactor.ui.gui.GuiUtil;
053    
054    public class ProjectTree extends JTree {
055            DragSource dragSource;
056            DragSourceContext dragSourceContext;
057            ProjectTreeNode draggedNode;
058            ProjectTreeNode currentDragOverNode;
059            int currentDragRow = -1;
060            boolean dropUnder;
061            boolean dropInto;
062            Point currentDragLocation;
063            private static Transferable dummy = new StringSelection("");
064            private DragSourceListener dragSourceListener = new DragSourceAdapter() {
065                    public void dragEnter(DragSourceDragEvent event) {
066                            dragSourceContext = event.getDragSourceContext();
067                    }
068                    @Override
069                    public void dragDropEnd(DragSourceDropEvent arg0) {
070                            super.dragDropEnd(arg0);
071                            clearDragInfo();
072                    }
073            };
074            private void clearDragInfo() {
075                    draggedNode = null;
076                    dragSourceContext = null;
077                    currentDragRow = -1;
078                    currentDragLocation = null;
079                    currentDragOverNode = null;
080                    dropInto = false;
081                    dropUnder = false;
082                    repaint();
083            }
084            DragGestureListener dragGestureListener = new DragGestureListener() {
085                    public void dragGestureRecognized(DragGestureEvent event) {
086                            TreePath path = getSelectionPath();
087                            if (path != null) {
088                                    draggedNode = (ProjectTreeNode) path.getLastPathComponent();
089                                    dragSource.startDrag(event, DragSource.DefaultMoveDrop, dummy, dragSourceListener);
090                            }
091                    }
092            };
093            public ProjectTree(ProjectModel model) {
094                    super(model);
095                    setDropTarget(new DropTarget(this, new ProjectTreeDropListener()));
096                    setCellRenderer(new ProjectTreeCellRenderer());
097                    dragSource = DragSource.getDefaultDragSource();
098                    dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, dragGestureListener);
099            }
100            class ProjectTreeCellRenderer extends DefaultTreeCellRenderer {
101                    private final Icon INCOMING_ICON = GuiUtil.loadIcon("/incoming_16.PNG");
102                    private final Icon SUBSCR_ICON = GuiUtil.loadIcon("/subscribe_16.PNG");
103                    private final Icon CONDITION_ICON = GuiUtil.loadIcon("/condition_16.PNG");
104                    private final Icon LOOP_ICON = GuiUtil.loadIcon("/loop_16.PNG");
105                    private final Icon ACTION_ICON = GuiUtil.loadIcon("/action_16.PNG");
106                    private final Icon VALUE_EXTRACT_ICON = GuiUtil.loadIcon("/value_extract_16.PNG");
107                    private final Icon OUTGOING_ICON = GuiUtil.loadIcon("/outgoing_16.PNG");
108                    private final Icon OUTGOING_RESP_ICON = GuiUtil.loadIcon("/outgoing_resp_16.PNG");
109                    private Border dropUnderBorder = BorderFactory.createMatteBorder(0, 0, 2, 0, Color.BLUE);
110                    private Border dropInsideBorder = new LineBorder(Color.BLUE, 2);
111                    private Border noDrop = BorderFactory.createEmptyBorder(0, 0, 2, 0);
112                    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean focus) {
113                            Component com = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, focus);
114                            if (row == currentDragRow) {
115                                    if ((dropUnder)) {
116                                            ((JLabel) com).setBorder(dropUnderBorder);
117                                    } else if (dropInto) {
118                                            ((JLabel) com).setBorder(dropInsideBorder);
119                                    } else {
120                                            ((JLabel) com).setBorder(noDrop);
121                                    }
122                            } else {
123                                    ((JLabel) com).setBorder(noDrop);
124                            }
125                            ProjectTreeNode node = (ProjectTreeNode) value;
126                            if (node != null) {
127                                    if (ProjectNodeType.T_MESSAGE_PUBLISH.equals(node.getNodeType()))
128                                            setIcon(OUTGOING_ICON);
129                                    else if (ProjectNodeType.T_MESSAGE_RECEIVE.equals(node.getNodeType()))
130                                            setIcon(INCOMING_ICON);
131                                    else if (ProjectNodeType.T_MESSAGE_RESPOND.equals(node.getNodeType()))
132                                            setIcon(OUTGOING_RESP_ICON);
133                                    else if (ProjectNodeType.T_MESSAGE_SUBSCRIBE.equals(node.getNodeType()))
134                                            setIcon(SUBSCR_ICON);
135                                    else if (ProjectNodeType.T_CONDITION.equals(node.getNodeType()))
136                                            setIcon(CONDITION_ICON);
137                                    else if (ProjectNodeType.T_LOOP.equals(node.getNodeType()))
138                                            setIcon(LOOP_ICON);
139                                    else if (ProjectNodeType.T_ACTION.equals(node.getNodeType()))
140                                            setIcon(ACTION_ICON);
141                                    else if (ProjectNodeType.T_VALUE.equals(node.getNodeType()))
142                                            setIcon(VALUE_EXTRACT_ICON);
143                            }
144                            return com;
145                    }
146            }
147            class ProjectTreeDropListener extends DropTargetAdapter {
148                    @Override
149                    public void dragOver(DropTargetDragEvent event) {
150                            dropInto = false;
151                            dropUnder = false;
152                            currentDragOverNode = null;
153                            DropAcceptRules.DropAcceptInfo dropAcceptInfo = null;
154                            boolean move = true;
155                            if (dragSourceContext != null) {
156                                    if (event.getDropAction() == TransferHandler.MOVE)
157                                            dragSourceContext.setCursor(DragSource.DefaultMoveDrop);
158                                    else {
159                                            move = false;
160                                            dragSourceContext.setCursor(DragSource.DefaultCopyDrop);
161                                    }
162                            }
163                            TreePath path = getPathForLocation(event.getLocation().x, event.getLocation().y);
164                            if (path != null) {
165                                    currentDragOverNode = (ProjectTreeNode) path.getLastPathComponent();
166                                    currentDragLocation = event.getLocation();
167                                    currentDragRow = getRowForLocation(currentDragLocation.x, currentDragLocation.y);
168                                    dropUnder = getRowForLocation(currentDragLocation.x, currentDragLocation.y + 6) != currentDragRow;
169                                    dropAcceptInfo = DropAcceptRules.getDropAcceptInfo(currentDragOverNode, draggedNode);
170                                    if (dropUnder) {
171                                            if (move)
172                                                    dropUnder = dropAcceptInfo.isMoveAsideAccepted();
173                                            else
174                                                    dropUnder = dropAcceptInfo.isCopyAsideAccepted();
175                                    } else {
176                                            if (move)
177                                                    dropInto = dropAcceptInfo.isMoveIntoAccepted();
178                                            else
179                                                    dropInto = dropAcceptInfo.isCopyIntoAccepted();
180                                    }
181                                    if (dragSourceContext != null) {
182                                            if (!dropInto && !dropUnder)
183                                                    dragSourceContext.setCursor(DragSource.DefaultLinkNoDrop);
184                                    }
185                            } else {
186                                    dropAcceptInfo = null;
187                                    event.rejectDrag();
188                            }
189                            repaint();
190                    }
191                    public void drop(DropTargetDropEvent event) {
192                            try {
193                                    if (currentDragOverNode != null && draggedNode != null && dragSourceContext != null) {
194                                            boolean move = (event.getDropAction() == TransferHandler.MOVE);
195                                            if (dropUnder) {
196                                                    if (move) {
197                                                            ((ProjectModel) getModel()).moveAfter(currentDragOverNode, draggedNode);
198                                                    } else {
199                                                            ((ProjectModel) getModel()).copyAfter(currentDragOverNode, draggedNode);
200                                                    }
201                                            } else if (dropInto) {
202                                                    if (move) {
203                                                            ((ProjectModel) getModel()).moveInto(currentDragOverNode, draggedNode);
204                                                    } else {
205                                                            ((ProjectModel) getModel()).copyInto(currentDragOverNode, draggedNode);
206                                                    }
207                                            }
208                                    }
209                            } catch (MactorException me) {
210                                    me.printStackTrace();
211                            }
212                    }
213            }
214    }