Package org.rssowl.ui.internal.views.explorer

Source Code of org.rssowl.ui.internal.views.explorer.BookMarkDNDImpl

/*   **********************************************************************  **
**   Copyright notice                                                       **
**                                                                          **
**   (c) 2005-2009 RSSOwl Development Team                                  **
**   http://www.rssowl.org/                                                 **
**                                                                          **
**   All rights reserved                                                    **
**                                                                          **
**   This program and the accompanying materials are made available under   **
**   the terms of the Eclipse Public License v1.0 which accompanies this    **
**   distribution, and is available at:                                     **
**   http://www.rssowl.org/legal/epl-v10.html                               **
**                                                                          **
**   A copy is found in the file epl-v10.html and important notices to the  **
**   license from the team is found in the textfile LICENSE.txt distributed **
**   in this package.                                                       **
**                                                                          **
**   This copyright notice MUST APPEAR in all copies of the file!           **
**                                                                          **
**   Contributors:                                                          **
**     RSSOwl Development Team - initial API and implementation             **
**                                                                          **
**  **********************************************************************  */

package org.rssowl.ui.internal.views.explorer;

import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.dnd.URLTransfer;
import org.rssowl.core.persist.IBookMark;
import org.rssowl.core.persist.IEntity;
import org.rssowl.core.persist.IFolder;
import org.rssowl.core.persist.IFolderChild;
import org.rssowl.core.persist.IMark;
import org.rssowl.core.persist.INews;
import org.rssowl.core.persist.INewsBin;
import org.rssowl.core.persist.dao.DynamicDAO;
import org.rssowl.core.persist.dao.IFolderDAO;
import org.rssowl.core.util.CoreUtils;
import org.rssowl.core.util.LoggingSafeRunnable;
import org.rssowl.core.util.RegExUtils;
import org.rssowl.core.util.ReparentInfo;
import org.rssowl.ui.internal.EntityGroup;
import org.rssowl.ui.internal.actions.MoveCopyNewsToBinAction;
import org.rssowl.ui.internal.actions.NewBookMarkAction;
import org.rssowl.ui.internal.editors.feed.NewsGrouping;
import org.rssowl.ui.internal.util.JobRunner;

import java.util.ArrayList;
import java.util.List;

/**
* The <code>BookMarkDropImpl</code> is handling all drop-operations resulting
* from a DND.
*
* @author bpasero
*/
public class BookMarkDNDImpl extends ViewerDropAdapter implements DragSourceListener {
  private final BookMarkExplorer fExplorer;
  private final IFolderDAO fFolderDAO;

  /**
   * @param explorer
   * @param viewer
   */
  protected BookMarkDNDImpl(BookMarkExplorer explorer, Viewer viewer) {
    super(viewer);
    fExplorer = explorer;
    fFolderDAO = DynamicDAO.getDAO(IFolderDAO.class);
  }

  /*
   * @see org.eclipse.swt.dnd.DragSourceListener#dragStart(org.eclipse.swt.dnd.DragSourceEvent)
   */
  public void dragStart(final DragSourceEvent event) {

    /* Set normalized selection into Transfer if not in grouping mode */
    if (!fExplorer.isGroupingEnabled()) {
      SafeRunner.run(new LoggingSafeRunnable() {
        public void run() throws Exception {
          LocalSelectionTransfer.getTransfer().setSelection(getNormalizedSelection());
          LocalSelectionTransfer.getTransfer().setSelectionSetTime(event.time & 0xFFFFFFFFL);
          event.doit = true;
        }
      });
    }
  }

  private ISelection getNormalizedSelection() {
    IStructuredSelection selection = (IStructuredSelection) getViewer().getSelection();
    List<?> selectedObjects = selection.toList();

    /* Retrieve dragged Marks / Folders and separate */
    List<IEntity> draggedEntities = new ArrayList<IEntity>(selectedObjects.size());
    List<IFolder> draggedFolders = new ArrayList<IFolder>(selectedObjects.size());
    for (Object object : selectedObjects) {

      /* Dragged Mark */
      if (object instanceof IMark)
        draggedEntities.add((IMark) object);

      /* Dragged Folder */
      else if (object instanceof IFolder) {
        draggedEntities.add((IFolder) object);
        draggedFolders.add((IFolder) object);
      }
    }

    /* Normalize the dragged entities */
    for (IFolder folder : draggedFolders)
      CoreUtils.normalize(folder, draggedEntities);

    return new StructuredSelection(draggedEntities);
  }

  /*
   * @see org.eclipse.swt.dnd.DragSourceListener#dragSetData(org.eclipse.swt.dnd.DragSourceEvent)
   */
  public void dragSetData(final DragSourceEvent event) {
    SafeRunner.run(new LoggingSafeRunnable() {
      public void run() throws Exception {

        /* Set Selection using LocalSelectionTransfer */
        if (LocalSelectionTransfer.getTransfer().isSupportedType(event.dataType))
          event.data = LocalSelectionTransfer.getTransfer().getSelection();

        /* Set Text using TextTransfer */
        else if (TextTransfer.getInstance().isSupportedType(event.dataType))
          setTextData(event);

        /* Set Text using URLTranser */
        else if (URLTransfer.getInstance().isSupportedType(event.dataType))
          setURLData(event);
      }
    });
  }

  private void setTextData(DragSourceEvent event) {
    StringBuilder str = new StringBuilder(""); //$NON-NLS-1$
    IStructuredSelection selection = (IStructuredSelection) getViewer().getSelection();
    List<?> selectedObjects = selection.toList();
    for (Object selectedObject : selectedObjects) {

      /* IBookMark */
      if (selectedObject instanceof IBookMark) {
        IBookMark bookmark = (IBookMark) selectedObject;
        str.append(bookmark.getFeedLinkReference().getLinkAsText()).append("\n"); //$NON-NLS-1$
        str.append(bookmark.getName()).append("\n\n"); //$NON-NLS-1$
      }

      /* Any other Folder Child */
      else if (selectedObject instanceof IFolderChild) {
        IFolderChild folderchild = (IFolderChild) selectedObject;
        str.append(folderchild.getName()).append("\n"); //$NON-NLS-1$
      }

      /* Entity Group */
      else if (selectedObject instanceof EntityGroup) {
        EntityGroup entitygroup = (EntityGroup) selectedObject;
        str.append(entitygroup.getName()).append("\n"); //$NON-NLS-1$
      }
    }

    if (str.length() > 0)
      event.data = str.toString();
  }

  private void setURLData(DragSourceEvent event) {
    StringBuilder str = new StringBuilder(""); //$NON-NLS-1$
    IStructuredSelection selection = (IStructuredSelection) getViewer().getSelection();
    List<?> selectedObjects = selection.toList();
    for (Object selectedObject : selectedObjects) {

      /* IBookMark */
      if (selectedObject instanceof IBookMark) {
        IBookMark bookmark = (IBookMark) selectedObject;
        str.append(bookmark.getFeedLinkReference().getLinkAsText()).append("\n"); //$NON-NLS-1$
      }
    }

    if (str.length() > 0)
      event.data = str.toString();
  }

  /*
   * @see org.eclipse.swt.dnd.DragSourceListener#dragFinished(org.eclipse.swt.dnd.DragSourceEvent)
   */
  public void dragFinished(DragSourceEvent event) {
    SafeRunner.run(new LoggingSafeRunnable() {
      public void run() throws Exception {
        LocalSelectionTransfer.getTransfer().setSelection(null);
        LocalSelectionTransfer.getTransfer().setSelectionSetTime(0);
      }
    });
  }

  /*
   * @see org.eclipse.jface.viewers.ViewerDropAdapter#dragOver(org.eclipse.swt.dnd.DropTargetEvent)
   */
  @Override
  public void dragOver(DropTargetEvent event) {
    super.dragOver(event);

    Object currentTarget = getCurrentTarget();
    boolean isFolderChildsDragged = isFolderChildsDragged();

    /* Un-Set some feedback if sorting by name */
    if (fExplorer.isSortByNameEnabled()) {
      event.feedback &= ~DND.FEEDBACK_INSERT_AFTER;
      event.feedback &= ~DND.FEEDBACK_INSERT_BEFORE;
    }

    /* Un-Set some feedback if grouping */
    if (fExplorer.isGroupingEnabled() && !(currentTarget instanceof INewsBin)) {
      event.feedback &= ~DND.FEEDBACK_INSERT_AFTER;
      event.feedback &= ~DND.FEEDBACK_INSERT_BEFORE;
      event.feedback &= ~DND.FEEDBACK_SELECT;
    }

    /* Never give Select as Feedback from a Mark except INewsBin */
    if (currentTarget instanceof IMark && (!(currentTarget instanceof INewsBin) || isFolderChildsDragged))
      event.feedback &= ~DND.FEEDBACK_SELECT;

    /* Don't show this feedback for News Bins when non Folder-Childs are dragged */
    if (currentTarget instanceof INewsBin && !isFolderChildsDragged) {
      event.feedback &= ~DND.FEEDBACK_INSERT_AFTER;
      event.feedback &= ~DND.FEEDBACK_INSERT_BEFORE;
    }

    /* Unset some feedback when Text- or URLTransfer is used */
    if (TextTransfer.getInstance().isSupportedType(event.currentDataType) || URLTransfer.getInstance().isSupportedType(event.currentDataType)) {
      event.feedback &= ~DND.FEEDBACK_INSERT_AFTER;
      event.feedback &= ~DND.FEEDBACK_INSERT_BEFORE;
    }

    /* Fix for eclipse bug 235136 in ViewerDropAdapter that does not support URLTransfer */
    if (event.detail == DND.DROP_NONE && URLTransfer.getInstance().isSupportedType(event.currentDataType))
      event.detail = DND.DROP_LINK;
  }

  private boolean isFolderChildsDragged() {
    IStructuredSelection currentSource = (IStructuredSelection) LocalSelectionTransfer.getTransfer().getSelection();
    if (currentSource != null) {
      List<?> draggedItems = currentSource.toList();
      return containsFolderChilds(draggedItems);
    }

    return true;
  }

  /*
   * @see org.eclipse.jface.viewers.ViewerDropAdapter#validateDrop(java.lang.Object,
   * int, org.eclipse.swt.dnd.TransferData)
   */
  @Override
  public boolean validateDrop(final Object target, int operation, TransferData transferType) {

    /* Text- and URLTransfer (supported for all) */
    if (TextTransfer.getInstance().isSupportedType(transferType) || URLTransfer.getInstance().isSupportedType(transferType))
      return true;

    /* Require Entity as Target for other transfers */
    if (!(target instanceof IEntity))
      return false;

    /* Selection Transfer */
    if (LocalSelectionTransfer.getTransfer().isSupportedType(transferType)) {
      final boolean[] result = new boolean[] { false };
      SafeRunner.run(new LoggingSafeRunnable() {
        public void run() throws Exception {
          ISelection selection = LocalSelectionTransfer.getTransfer().getSelection();
          if (selection instanceof IStructuredSelection) {
            List<?> draggedObjects = ((IStructuredSelection) selection).toList();
            result[0] = isValidDrop((IEntity) target, draggedObjects);
          }
        }
      });

      return result[0];
    }

    return false;
  }

  private boolean isValidDrop(IEntity dropTarget, List<?> draggedObjects) {

    /* Check validity for each dragged Object */
    for (Object draggedObject : draggedObjects) {

      /* Shared rule: Do not allow drop when grouping is enabled */
      if (draggedObject instanceof IFolderChild && fExplorer.isGroupingEnabled())
        return false;

      /* Shared rule: Do not allow to drop on same Entity */
      if (draggedObject.equals(dropTarget))
        return false;

      /* Dragged Folder */
      if (draggedObject instanceof IFolder) {
        IFolder draggedFolder = (IFolder) draggedObject;
        if (!isValidDrop(draggedFolder, dropTarget))
          return false;
      }

      /* Dragged Mark */
      else if (draggedObject instanceof IMark) {
        IMark draggedMark = (IMark) draggedObject;
        if (!isValidDrop(draggedMark, dropTarget))
          return false;
      }

      /* Dragged News */
      else if (draggedObject instanceof INews) {
        INews draggedNews = (INews) draggedObject;
        return isValidDrop(draggedNews, dropTarget);
      }

      /* Dragged Entity Group of News */
      else if (draggedObject instanceof EntityGroup) {
        EntityGroup group = (EntityGroup) draggedObject;
        return isValidDrop(group, dropTarget);
      }
    }

    return true;
  }

  private boolean isValidDrop(@SuppressWarnings("unused") INews dragSource, IEntity dropTarget) {
    int loc = getCurrentLocation();

    /* Require to drop on actual Entity */
    if (loc == LOCATION_BEFORE || loc == LOCATION_AFTER)
      return false;

    /* Require News Bin as target */
    return dropTarget instanceof INewsBin;
  }

  private boolean isValidDrop(EntityGroup group, IEntity dropTarget) {
    int loc = getCurrentLocation();

    /* Require to drop on actual Entity */
    if (loc == LOCATION_BEFORE || loc == LOCATION_AFTER)
      return false;

    /* Require News Bin as target */
    return dropTarget instanceof INewsBin && NewsGrouping.GROUP_CATEGORY_ID.equals(group.getCategory());
  }

  private boolean isValidDrop(IFolder dragSource, IEntity dropTarget) {
    int loc = getCurrentLocation();

    /* Do not allow dropping on same Parent */
    if (loc == LOCATION_ON && dragSource.getParent().equals(dropTarget))
      return false;

    /* Do not allow Re-Ordering of Entities if sort by name */
    if (fExplorer.isSortByNameEnabled() && (loc == LOCATION_AFTER || loc == LOCATION_BEFORE)) {
      if (dropTarget instanceof IFolder) {
        IFolder target = (IFolder) dropTarget;
        if (target.getParent().containsChild(dragSource))
          return false;
      }
    }

    /* Do not allow Re-Ordering over IMarks (when sorting or grouping) */
    if ((fExplorer.isSortByNameEnabled() || fExplorer.isGroupingEnabled()) && dropTarget instanceof IMark) {
      IMark target = (IMark) dropTarget;
      if (target.getParent().containsChild(dragSource))
        return false;
    }

    /* Do not allow dropping in Child of Drag-Folder */
    if (CoreUtils.hasChildRelation(dragSource, dropTarget))
      return false;

    return true;
  }

  private boolean isValidDrop(IMark dragSource, IEntity dropTarget) {
    int loc = getCurrentLocation();

    /* Do not allow dropping on same Parent */
    if (loc == LOCATION_ON && dragSource.getParent().equals(dropTarget))
      return false;

    /* Do not allow Re-Ordering of Entities if sort by name */
    if (fExplorer.isSortByNameEnabled()) {
      if (dropTarget instanceof IMark) {
        IMark target = (IMark) dropTarget;
        if (target.getParent().containsChild(dragSource))
          return false;
      }
    }

    /* Do not allow Re-Ordering over IFolder (when sorting or grouping) */
    if ((fExplorer.isSortByNameEnabled() || fExplorer.isGroupingEnabled()) && dropTarget instanceof IFolder && (loc == LOCATION_AFTER || loc == LOCATION_BEFORE)) {
      IFolder target = (IFolder) dropTarget;
      if (target.getParent().containsChild(dragSource))
        return false;
    }

    return true;
  }

  private boolean containsFolderChilds(List<?> draggedObjects) {
    for (Object object : draggedObjects) {
      if (object instanceof IFolderChild)
        return true;
    }

    return false;
  }

  /*
   * @see org.eclipse.jface.viewers.ViewerDropAdapter#performDrop(java.lang.Object)
   */
  @Override
  public boolean performDrop(final Object data) {

    /* Selection-Transfer */
    if (data instanceof IStructuredSelection) {
      SafeRunner.run(new LoggingSafeRunnable() {
        public void run() throws Exception {
          IStructuredSelection selection = (IStructuredSelection) data;
          List<?> draggedObjects = selection.toList();

          if (getCurrentTarget() instanceof INewsBin && !containsFolderChilds(draggedObjects))
            perfromNewsDrop(draggedObjects);
          else
            perfromFolderChildDrop(draggedObjects);
        }
      });

      return true;
    }

    /* Text-Transfer (check for URLs) */
    else if (data instanceof String) {
      SafeRunner.run(new LoggingSafeRunnable() {
        public void run() throws Exception {
          final List<String> urls = RegExUtils.extractLinksFromText((String) data, false);
          if (urls.size() > 0) {

            /* Determine parent folder */
            final IFolder parent;
            Object dropTarget = getCurrentTarget();
            if (dropTarget instanceof IFolder)
              parent = (IFolder) dropTarget;
            else if (dropTarget instanceof IMark)
              parent = ((IMark) dropTarget).getParent();
            else
              parent = null;

            /* Determine Position */
            final IMark position = (IMark) ((dropTarget instanceof IMark) ? dropTarget : null);

            /* Open Dialog to add new BookMark (asyncly!) */
            JobRunner.runInUIThread(0, true, getViewer().getControl(), new Runnable() {
              public void run() {
                new NewBookMarkAction(getViewer().getControl().getShell(), parent, position, urls.get(0)).run(null);
              }
            });
          }
        }
      });

      return true;
    }

    return false;
  }

  private void perfromNewsDrop(List<?> draggedObjects) {
    int operation = getCurrentOperation();
    INewsBin dropTarget = (INewsBin) getCurrentTarget();

    new MoveCopyNewsToBinAction(new StructuredSelection(draggedObjects), dropTarget, operation == DND.DROP_MOVE).run();
  }

  private void perfromFolderChildDrop(List<?> draggedObjects) {
    Object dropTarget = getCurrentTarget();
    int location = getCurrentLocation();

    IFolder parentFolder = null;
    boolean requireSave = false;
    boolean on = (location == ViewerDropAdapter.LOCATION_ON);

    IFolderChild position = dropTarget != null ? (IFolderChild) dropTarget : null;

    /* Fix invalid Position */
    if (on && dropTarget instanceof IFolder)
      position = null;

    Boolean after = (location == ViewerDropAdapter.LOCATION_AFTER);
    if (position == null)
      after = null;

    /* Target is a Folder */
    if (dropTarget instanceof IFolder) {
      IFolder dropFolder = (IFolder) dropTarget;

      /* Target is the exact Folder */
      if (on)
        parentFolder = (IFolder) dropTarget;

      /* Target is below or above of the Folder */
      else
        parentFolder = dropFolder.getParent();
    }

    /* Target is a Mark */
    else if (dropTarget instanceof IMark) {
      IMark dropMark = (IMark) dropTarget;
      parentFolder = dropMark.getParent();
    }

    /* Require a Parent-Folder */
    if (parentFolder == null)
      return;

    /* Separate into Reparented FolderChildren and Re-Orders */
    List<IFolderChild> childReordering = null;
    List<ReparentInfo<IFolderChild, IFolder>> reparenting = null;

    /* For each dragged Object */
    for (Object object : draggedObjects) {

      /* Dragged Folder or Mark */
      if (object instanceof IFolder || object instanceof IMark) {
        IFolderChild draggedFolderChild = (IFolderChild) object;

        /* Reparenting to new Parent */
        if (!draggedFolderChild.getParent().equals(parentFolder)) {
          if (reparenting == null)
            reparenting = new ArrayList<ReparentInfo<IFolderChild, IFolder>>(draggedObjects.size());

          ReparentInfo<IFolderChild, IFolder> reparentInfo = ReparentInfo.create(draggedFolderChild, parentFolder, position, after);
          reparenting.add(reparentInfo);
        }

        /* Re-Ordering in same Parent */
        else {
          if (childReordering == null)
            childReordering = new ArrayList<IFolderChild>(draggedObjects.size());
          childReordering.add(draggedFolderChild);
        }
      }
    }

    /* Perform reparenting */
    if (reparenting != null) {
      final List<ReparentInfo<IFolderChild, IFolder>> finalReparenting = reparenting;
      BusyIndicator.showWhile(getViewer().getControl().getDisplay(), new Runnable() {
        public void run() {
          CoreUtils.reparentWithProperties(finalReparenting);
        }
      });
    }

    /* Perform Re-Ordering on Children */
    if (childReordering != null) {
      parentFolder.reorderChildren(childReordering, (IFolderChild) dropTarget, after);
      requireSave = true;
    }

    /* Save the Folder if required */
    if (requireSave)
      fFolderDAO.save(parentFolder);
  }
}
TOP

Related Classes of org.rssowl.ui.internal.views.explorer.BookMarkDNDImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.