File Source: ReorderableJList.java

         /* 
    P/P   *  Method: com.dmdirc.addons.ui_swing.components.reorderablelist.ReorderableJList__static_init
          */
     1  /*
     2   * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
     3   *
     4   * Permission is hereby granted, free of charge, to any person obtaining a copy
     5   * of this software and associated documentation files (the "Software"), to deal
     6   * in the Software without restriction, including without limitation the rights
     7   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   * copies of the Software, and to permit persons to whom the Software is
     9   * furnished to do so, subject to the following conditions:
    10   *
    11   * The above copyright notice and this permission notice shall be included in
    12   * all copies or substantial portions of the Software.
    13   *
    14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20   * SOFTWARE.
    21   */
    22  
    23  package com.dmdirc.addons.ui_swing.components.reorderablelist;
    24  
    25  
    26  import com.dmdirc.addons.ui_swing.components.renderers.ReorderableJListCellRenderer;
    27  import com.dmdirc.logger.ErrorLevel;
    28  import com.dmdirc.logger.Logger;
    29  
    30  import java.awt.Cursor;
    31  import java.awt.Point;
    32  import java.awt.Rectangle;
    33  import java.awt.datatransfer.DataFlavor;
    34  import java.awt.datatransfer.Transferable;
    35  import java.awt.datatransfer.UnsupportedFlavorException;
    36  import java.awt.dnd.DnDConstants;
    37  import java.awt.dnd.DragGestureEvent;
    38  import java.awt.dnd.DragGestureListener;
    39  import java.awt.dnd.DragSource;
    40  import java.awt.dnd.DragSourceDragEvent;
    41  import java.awt.dnd.DragSourceDropEvent;
    42  import java.awt.dnd.DragSourceEvent;
    43  import java.awt.dnd.DragSourceListener;
    44  import java.awt.dnd.DropTarget;
    45  import java.awt.dnd.DropTargetDragEvent;
    46  import java.awt.dnd.DropTargetDropEvent;
    47  import java.awt.dnd.DropTargetEvent;
    48  import java.awt.dnd.DropTargetListener;
    49  import java.io.IOException;
    50  import java.util.ArrayList;
    51  
    52  import javax.swing.DefaultListModel;
    53  import javax.swing.JList;
    54  import javax.swing.ListSelectionModel;
    55  
    56  /**
    57   * Reorderable JList.
    58   */
         /* 
    P/P   *  Method: ListModel getModel()
          * 
          *  Postconditions:
          *    init'ed(return_value)
          */
    59  public final class ReorderableJList extends JList implements DragSourceListener,
    60          DropTargetListener, DragGestureListener {
    61      
    62      /**
    63       * A version number for this class. It should be changed whenever the class
    64       * structure is changed (or anything else that would prevent serialized
    65       * objects being unserialized with the new class).
    66       */
    67      private static final long serialVersionUID = 1;
    68      
    69      /** Drag source. */
    70      private final DragSource dragSource;
    71      /** Drag target. */
    72      private final DropTarget dropTarget;
    73      /** Drop target. */
    74      private Object dropTargetCell;
    75      /** Dragged index. */
    76      private int draggedIndex = -1;
    77      /** Data flavor. */
    78      private DataFlavor dataFlavor;
    79      /** Below drop target. */
    80      private boolean belowTarget;
    81      
    82      /** Instantiate new ReorderableJList. */
    83      public ReorderableJList() {
                 /* 
    P/P           *  Method: void com.dmdirc.addons.ui_swing.components.reorderablelist.ReorderableJList()
                  * 
                  *  Presumptions:
                  *    java.awt.dnd.DragSource:getDefaultDragSource(...)@99 != null
                  * 
                  *  Postconditions:
                  *    this.dataFlavor == One-of{&new DataFlavor(ReorderableJList#4), null}
                  *    this.dataFlavor in Addr_Set{null,&new DataFlavor(ReorderableJList#4)}
                  *    this.dragSource != null
                  *    init'ed(this.draggedIndex)
                  *    this.dropTarget == &new DropTarget(ReorderableJList#3)
                  *    new DataFlavor(ReorderableJList#4) num objects <= 1
                  *    new DropTarget(ReorderableJList#3) num objects == 1
                  */
    84          this(new DefaultListModel());
    85      }
    86  
    87      /**
    88       * Instantiate new ReorderableJList.
    89       *
    90       * @param model Model
    91       */
    92      public ReorderableJList(final DefaultListModel model) {
                 /* 
    P/P           *  Method: void com.dmdirc.addons.ui_swing.components.reorderablelist.ReorderableJList(DefaultListModel)
                  * 
                  *  Presumptions:
                  *    init'ed(com.dmdirc.logger.ErrorLevel.LOW)
                  *    java.awt.dnd.DragSource:getDefaultDragSource(...)@99 != null
                  * 
                  *  Postconditions:
                  *    this.dataFlavor in Addr_Set{null,&amp;new DataFlavor(ReorderableJList#4)}
                  *    this.dragSource != null
                  *    init'ed(this.draggedIndex)
                  *    this.dropTarget == &amp;new DropTarget(ReorderableJList#3)
                  *    new DataFlavor(ReorderableJList#4) num objects <= 1
                  *    new DropTarget(ReorderableJList#3) num objects == 1
                  */
    93          super(model);
    94          
    95          setCellRenderer(new ReorderableJListCellRenderer(this));
    96          setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    97          setTransferHandler(new ArrayListTransferHandler());
    98          
    99          dragSource = DragSource.getDefaultDragSource();
   100          dropTarget = new DropTarget(this, this);
   101          
   102          dragSource.createDefaultDragGestureRecognizer(this,
   103                  DnDConstants.ACTION_MOVE, this);
   104          try {
   105              
   106              dataFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType
   107                      + ";class=java.util.ArrayList");
   108          } catch (ClassNotFoundException e) {
   109              Logger.userError(ErrorLevel.LOW, "unable to create data flavor: "
   110                      + e.getMessage());
   111              dataFlavor = null;
   112          }
   113      }
   114      
   115      /** {@inheritDoc} */
   116      @Override
   117      public DefaultListModel getModel() {
                 /* 
    P/P           *  Method: DefaultListModel getModel()
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   118          return (DefaultListModel) super.getModel();
   119      }
   120      
   121      /** 
   122       * Sets the model for the list.
   123       *
   124       * @param model Model for the list
   125       */
   126      public void setModel(final DefaultListModel model) { //NOPMD stupid
                 /* 
    P/P           *  Method: void setModel(DefaultListModel)
                  */
   127          super.setModel(model);
   128      }
   129      
   130      /**
   131       * Returns the target drop item.
   132       *
   133       * @return Drop target cell
   134       */
   135      public Object getTargetCell() {
                 /* 
    P/P           *  Method: Object getTargetCell()
                  * 
                  *  Preconditions:
                  *    init'ed(this.dropTargetCell)
                  * 
                  *  Postconditions:
                  *    return_value == this.dropTargetCell
                  *    init'ed(return_value)
                  */
   136          return dropTargetCell;
   137      }
   138      
   139      /**
   140       * Returns whether the target is below the drop cell.
   141       *
   142       * @return if the target is above or below the point
   143       */
   144      public boolean getBelowTarget() {
                 /* 
    P/P           *  Method: bool getBelowTarget()
                  * 
                  *  Preconditions:
                  *    init'ed(this.belowTarget)
                  * 
                  *  Postconditions:
                  *    return_value == this.belowTarget
                  *    init'ed(return_value)
                  */
   145          return belowTarget;
   146      }
   147      
   148      /** {@inheritDoc} */
   149      @Override
   150      public void dragEnter(final DragSourceDragEvent dsde) {
   151          //Ignore
             /* 
    P/P       *  Method: void dragEnter(DragSourceDragEvent)
              */
   152      }
   153      
   154      /** {@inheritDoc} */
   155      @Override
   156      public void dragOver(final DragSourceDragEvent dsde) {
   157          //Ignore
             /* 
    P/P       *  Method: void dragOver(DragSourceDragEvent)
              */
   158      }
   159      
   160      /** {@inheritDoc} */
   161      @Override
   162      public void dropActionChanged(final DragSourceDragEvent dsde) {
   163          //Ignore
             /* 
    P/P       *  Method: void dropActionChanged(DragSourceDragEvent)
              */
   164      }
   165      
   166      /** {@inheritDoc} */
   167      @Override
   168      public void dragExit(final DragSourceEvent dse) {
   169          //Ignore
             /* 
    P/P       *  Method: void dragExit(DragSourceEvent)
              */
   170      }
   171      
   172      /** {@inheritDoc} */
   173      @Override
   174      public void dragDropEnd(final DragSourceDropEvent dsde) {
   175          //clear drop variables and repaint
                 /* 
    P/P           *  Method: void dragDropEnd(DragSourceDropEvent)
                  * 
                  *  Postconditions:
                  *    this.draggedIndex == -1
                  *    this.dropTargetCell == null
                  */
   176          dropTargetCell = null;
   177          draggedIndex = -1;
   178          repaint();
   179      }
   180      
   181      /** {@inheritDoc} */
   182      @Override
   183      public void dragEnter(final DropTargetDragEvent dtde) {
   184          //check whether to accept drag
                 /* 
    P/P           *  Method: void dragEnter(DropTargetDragEvent)
                  * 
                  *  Preconditions:
                  *    dtde != null
                  */
   185          if (dtde.getSource() == dropTarget) {
   186              dtde.acceptDrag(DnDConstants.ACTION_MOVE);
   187          } else {
   188              dtde.rejectDrag();
   189          }
   190      }
   191      
   192      /** {@inheritDoc} */
   193      @Override
   194      public void dragOver(final DropTargetDragEvent dtde) {
   195          //Reject drops on self
                 /* 
    P/P           *  Method: void dragOver(DropTargetDragEvent)
                  * 
                  *  Preconditions:
                  *    dtde != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.addons.ui_swing.components.reorderablelist.ReorderableJList:getCellBounds(...)@210 != null
                  *    java.awt.dnd.DropTargetDragEvent:getLocation(...)@201 != null
                  *    javax.swing.JList:getModel(...)@118 != null
                  * 
                  *  Postconditions:
                  *    possibly_updated(this.belowTarget)
                  *    init'ed(this.dropTargetCell)
                  * 
                  *  Test Vectors:
                  *    com.dmdirc.addons.ui_swing.components.reorderablelist.ReorderableJList:locationToIndex(...)@202: {-231..-2, 0..232-2}, {-1}
                  */
   196          if (dtde.getSource() != dropTarget) {
   197              dtde.rejectDrag();
   198          }
   199          
   200          //get location and index
   201          final Point dragPoint = dtde.getLocation();
   202          final int index = locationToIndex(dragPoint);
   203          
   204          //set drag variables and repaint
   205          if (index == -1) {
   206              dropTargetCell = null;
   207          } else {
   208              dropTargetCell = getModel().getElementAt(index);
   209              //check whether the drop point is after the last index
   210              final Rectangle bounds = getCellBounds(index, index);
   211              if (index == getModel().getSize() - 1 
   212                      && dragPoint.y > bounds.y + bounds.height) {
   213                  belowTarget = true;
   214              } else {
   215                  belowTarget = false;
   216              }
   217          }
   218          
   219          repaint();
   220      }
   221      
   222      /** {@inheritDoc} */
   223      @Override
   224      public void dropActionChanged(final DropTargetDragEvent dtde) {
   225          //Ignore
             /* 
    P/P       *  Method: void dropActionChanged(DropTargetDragEvent)
              */
   226      }
   227      
   228      /** {@inheritDoc} */
   229      @Override
   230      public void dragExit(final DropTargetEvent dte) {
   231          //Ignore
             /* 
    P/P       *  Method: void dragExit(DropTargetEvent)
              */
   232      }
   233      
   234      /** {@inheritDoc} */
   235      @Override
   236      public void drop(final DropTargetDropEvent dtde) {
   237          //check source and reject
                 /* 
    P/P           *  Method: void drop(DropTargetDropEvent)
                  * 
                  *  Preconditions:
                  *    dtde != null
                  *    (soft) init'ed(this.belowTarget)
                  *    (soft) init'ed(this.dataFlavor)
                  *    (soft) init'ed(this.draggedIndex)
                  * 
                  *  Presumptions:
                  *    com.dmdirc.addons.ui_swing.components.reorderablelist.ReorderableJList:getSelectionModel(...)@277 != null
                  *    com.dmdirc.addons.ui_swing.components.reorderablelist.ReorderableJList:locationToIndex(...)@244 <= 232-2
                  *    java.awt.datatransfer.Transferable:getTransferData(...)@261 != null
                  *    java.awt.dnd.DropTargetDropEvent:getTransferable(...)@261 != null
                  *    java.util.ArrayList:iterator(...)@273 != null
                  *    ...
                  * 
                  *  Test Vectors:
                  *    this.belowTarget: {0}, {1}
                  *    java.util.Iterator:hasNext(...)@273: {0}, {1}
                  */
   238          if (dtde.getSource() != dropTarget) {
   239              dtde.rejectDrop();
   240              return;
   241          }
   242          //get object location and index
   243          final Point dropPoint = dtde.getLocation();
   244          int index = locationToIndex(dropPoint);
   245          if (belowTarget) {
   246              index++;
   247          }
   248          
   249          //reject invalid drops
   250          if ((index == -1) || (index == draggedIndex)) {
   251              dtde.rejectDrop();
   252              return;
   253          }
   254          
   255          //accept drop as a move
   256          dtde.acceptDrop(DnDConstants.ACTION_MOVE);
   257          
   258          //get dropped item
   259          Object dragged;
   260          try {
   261              dragged = dtde.getTransferable().getTransferData(dataFlavor);
   262          } catch (UnsupportedFlavorException e) {
   263              return;
   264          } catch (IOException e) {
   265              return;
   266          }
   267          
   268          //move items
   269          final boolean sourceBeforeTarget = draggedIndex < index;
   270          final DefaultListModel mod = getModel();
   271          final int newIndex = sourceBeforeTarget ? index - 1 : index;
   272          mod.remove(draggedIndex);
   273          for (Object item : (ArrayList) dragged) {
   274              mod.add(newIndex, item);
   275          }
   276          
   277          getSelectionModel().setSelectionInterval(newIndex, newIndex);
   278          
   279          //drop complete
   280          dtde.dropComplete(true);
   281      }
   282      
   283      /** {@inheritDoc} */
   284      @Override
   285      public void dragGestureRecognized(final DragGestureEvent dge) {
   286          //find the objects location and index
                 /* 
    P/P           *  Method: void dragGestureRecognized(DragGestureEvent)
                  * 
                  *  Preconditions:
                  *    dge != null
                  *    (soft) this.dragSource != null
                  * 
                  *  Presumptions:
                  *    javax.swing.JList:getModel(...)@118 != null
                  * 
                  *  Postconditions:
                  *    possibly_updated(this.draggedIndex)
                  * 
                  *  Test Vectors:
                  *    com.dmdirc.addons.ui_swing.components.reorderablelist.ReorderableJList:locationToIndex(...)@288: {-231..-2, 0..232-1}, {-1}
                  */
   287          final Point clickPoint = dge.getDragOrigin();
   288          final int index = locationToIndex(clickPoint);
   289          
   290          if (index == -1) {
   291              return;
   292          }
   293          
   294          //get the list object
   295          final Object target = getModel().getElementAt(index);
   296          //create the trasnferable object
   297          final ArrayList<Object> transferObject = new ArrayList<Object>();
   298          transferObject.add(target);
   299          final Transferable trans = new ArrayListTransferable(transferObject);
   300          //start drag
   301          draggedIndex = index;
   302          dragSource.startDrag(dge, Cursor.getDefaultCursor(), trans, this);
   303      }
   304  }
   305  
   306  








SofCheck Inspector Build Version : 2.17854
ReorderableJList.java 2009-Jun-25 01:54:24
ReorderableJList.class 2009-Sep-02 17:04:15