/**
   * Resets the cursor. Cleans up what was painted before. Searches a destination dock for the last
   * mouse location and tries to dock the dragged dockable in this dock.
   */
  public void stopDragging(MouseEvent mouseEvent) {

    // Reset the old cursor.
    cursorManager.resetCursor();

    // Clean up what was painted for dragging.
    dockableDragPainter.clear();

    // Get the mouse location in screen coordinates.
    computeScreenLocation(mouseEvent);

    // Do we have to move an externalized dockable?
    if (draggedDockable.getState() == DockableState.EXTERNALIZED) {
      // Move the dockable.
      ExternalizedDraggerSupport.moveExternalizedDockable(
          draggedDockable, screenLocation, dockableOffset);

      // No dragging anymore.
      reset();

      return;
    }

    // Get the destination dock.
    Dock[] destinationDocks =
        dockRetriever.retrieveHighestPriorityDock(screenLocation, draggedDockable);
    if (destinationDocks == null) {
      return;
    }
    Dock destinationDock = destinationDocks[0];

    // Is the destination dock different from the origin?
    if (destinationDock != null) {
      if (!destinationDock.equals(originDock)) {
        // Get the mouse location for the new dock.
        locationInDestinationDock.setLocation(screenLocation.x, screenLocation.y);
        if (destinationDock instanceof Component) {
          SwingUtilities.convertPointFromScreen(
              locationInDestinationDock, (Component) destinationDock);
        }

        // Check if we can move the dock of the dockable in the float dock.
        if (destinationDock instanceof FloatDock) {
          // Get the root dock and the dock under the root.
          Dock rootDock = originDock;
          Dock dockUnderRoot = null;
          while (rootDock.getParentDock() != null) {
            dockUnderRoot = rootDock;
            rootDock = rootDock.getParentDock();
          }

          // Is the root dock the float dock?
          if (rootDock instanceof FloatDock) {
            // Is the dockable already in this dock and are there no others?
            List childrenOfDockable = new ArrayList();
            List childrenOfDock = new ArrayList();
            DockingUtil.retrieveDockables(draggedDockable, childrenOfDockable);
            DockingUtil.retrieveDockables(dockUnderRoot, childrenOfDock);
            if (sameElements(childrenOfDockable, childrenOfDock)) {
              ((FloatDock) rootDock)
                  .moveDock(dockUnderRoot, locationInDestinationDock, dockableOffset);
              return;
            }
          }
        }

        // Get the real dockable in the model with this ID.
        Dockable dockableWrapper = DockingUtil.retrieveDockableOfDockModel(draggedDockable.getID());
        if (dockableWrapper == null) {
          throw new IllegalStateException(
              "The dragged dockable should be docked in the dock model.");
        }

        // Remove the dockable from the old dock, add to the new dock.
        // Use the docking manager for the addition and removal, because the listenenrs have to
        // informed.
        if (!originDock.equals(draggedDockable.getDock())) {
          throw new IllegalStateException("The origin dock is not the parent of the dockable.");
        }
        DockingManager.getDockingExecutor()
            .changeDocking(
                dockableWrapper, destinationDock, locationInDestinationDock, dockableOffset);

        // Clean the dock from which the dockable is removed.
        DockingManager.getDockingExecutor().cleanDock(originDock, false);

      } else {
        // Get the real dockable in the model with this ID.
        Dockable dockableWrapper = DockingUtil.retrieveDockableOfDockModel(draggedDockable.getID());
        if (dockableWrapper == null) {
          throw new IllegalStateException(
              "The dragged dockable should be docked in the dock model.");
        }

        // Move the dockable to a new position in the same dock.
        if (!originDock.equals(draggedDockable.getDock())) {
          throw new IllegalStateException("The origin dock is not the parent of the dockable.");
        }
        DockingManager.getDockingExecutor()
            .changeDocking(dockableWrapper, originDock, locationInDestinationDock, new Point(0, 0));
      }
    }

    // No dragging anymore.
    reset();
  }
  /**
   * Searches the dock where the dockable will be docked for the current mouse location. A rectangle
   * is painted that shows, where the dockable will be docked. The cursor shows, if we can dock, or
   * if we cannot dock for the current location.
   */
  public void drag(MouseEvent mouseEvent) {

    // Get the component of the mouse event.
    Component mouseComponent = (Component) mouseEvent.getSource();

    // Get the mouse location in screen coordinates.
    computeScreenLocation(mouseEvent);

    // Do we have to move an externalized dockable?
    if (draggedDockable.getState() == DockableState.EXTERNALIZED) {
      // Move the dockable.
      ExternalizedDraggerSupport.moveExternalizedDockable(
          draggedDockable, screenLocation, dockableOffset);
      return;
    }

    // Get the destination dock for this position for the dockable that we are dragging.
    Dock[] destinationDocks =
        dockRetriever.retrieveHighestPriorityDock(screenLocation, draggedDockable);
    if (destinationDocks == null) {
      // We have no destination dock any more. Clean up what was painted before.
      clearPainting();

      // Set the 'cannot dock' cursor.
      cursorManager.setCursor(mouseComponent, retrieveCanNotDockCursor());

      return;
    }
    Dock destinationDock = destinationDocks[0];

    // Do we have a destination dock?
    if (destinationDock != null) {

      // Does the destination dock inherit from java.awt.Component or is it the float dock?
      if (destinationDock instanceof Component) {

        // Get the docking rectangle for the destination dock.
        locationInDestinationDock.setLocation(screenLocation.x, screenLocation.y);
        SwingUtilities.convertPointFromScreen(
            locationInDestinationDock, (Component) destinationDock);
        destinationDock.retrieveDockingRectangle(
            draggedDockable, locationInDestinationDock, dockableOffset, dockableDragRectangle);

        // Paint the new rectangle.
        dockableDragPainter.paintDockableDrag(
            draggedDockable, destinationDock, dockableDragRectangle, locationInDestinationDock);

        // Set the 'can dock' cursor.
        cursorManager.setCursor((Component) destinationDock, retrieveCanDockCursor());

      } else if (destinationDock instanceof FloatDock) {

        // Are we in the special situation that we will move a child dock of the float dock?
        boolean move = false;

        // Get the root dock and the dock under the root.
        Dock rootDock = originDock;
        Dock dockUnderRoot = null;
        while (rootDock.getParentDock() != null) {
          dockUnderRoot = rootDock;
          rootDock = rootDock.getParentDock();
        }

        // Is the root dock the float dock?
        if (rootDock instanceof FloatDock) {
          // Is the dockable already in this dock and are there no others?
          List childrenOfDockable = new ArrayList();
          List childrenOfDock = new ArrayList();
          DockingUtil.retrieveDockables(draggedDockable, childrenOfDockable);
          DockingUtil.retrieveDockables(dockUnderRoot, childrenOfDock);
          if (sameElements(childrenOfDockable, childrenOfDock)) {
            move = true;
          }
        }

        // We cannot paint on the screen, but maybe we can paint in the pane of the origin dock.
        if (originDock instanceof Component) {
          if (move) {
            locationInDestinationDock.setLocation(
                screenLocation.x - dockableOffset.x, screenLocation.y - dockableOffset.y);
            SwingUtilities.convertPointFromScreen(
                locationInDestinationDock, (Component) originDock);
            dockableDragRectangle.setLocation(locationInDestinationDock);
            Window window = SwingUtilities.getWindowAncestor((Component) dockUnderRoot);
            dockableDragRectangle.setSize(window.getSize());
            locationInDestinationDock.setLocation(
                locationInDestinationDock.x + dockableOffset.x,
                locationInDestinationDock.y + dockableOffset.y);
          } else {
            // Get the docking rectangle for the destination float dock.
            destinationDock.retrieveDockingRectangle(
                draggedDockable, screenLocation, dockableOffset, dockableDragRectangle);

            // Convert this rectangle to the origindock.
            locationInDestinationDock.setLocation(dockableDragRectangle.x, dockableDragRectangle.y);
            SwingUtilities.convertPointFromScreen(
                locationInDestinationDock, (Component) originDock);
            dockableDragRectangle.setLocation(locationInDestinationDock);
            locationInDestinationDock.setLocation(
                locationInDestinationDock.x + dockableOffset.x,
                locationInDestinationDock.y + dockableOffset.y);
          }
          // Paint the new rectangle.
          dockableDragPainter.paintDockableDrag(
              draggedDockable, originDock, dockableDragRectangle, locationInDestinationDock);
        } else {
          // We couldn't find a dock where we can paint.
          clearPainting();
        }

        // Set the 'can dock' cursor.
        cursorManager.setCursor(mouseComponent, retrieveCanDockCursor());

      } else {
        // Currentle this should not happen. All docks, except the float dock inherit from
        // java.awt.Component.
        // We have a dock where we cannot paint. Clean up what was painted before.
        clearPainting();

        // Set the 'can dock' cursor.
        cursorManager.setCursor(mouseComponent, retrieveCanDockCursor());
      }

    } else {
      // We have no destination dock any more. Clean up what was paintedbefore.
      clearPainting();

      // Set the 'cannot dock' cursor.
      cursorManager.setCursor(mouseComponent, retrieveCanNotDockCursor());
    }
  }