/** * Copyright 2010 The University of North Carolina at Chapel Hill * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package unc.lib.cdr.workbench.arrange; import gov.loc.mets.AmdSecType; import gov.loc.mets.DivType; import gov.loc.mets.MdSecType; import gov.loc.mets.MetsPackage; import gov.loc.mets.MetsType; import gov.loc.mets.util.METSConstants; import gov.loc.mets.util.METSUtils; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.command.CompoundCommand; import org.eclipse.emf.edit.command.AddCommand; import org.eclipse.emf.edit.command.RemoveCommand; import org.eclipse.emf.edit.command.SetCommand; import org.eclipse.jface.util.LocalSelectionTransfer; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ViewerDropAdapter; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.TransferData; import org.eclipse.ui.navigator.CommonDropAdapter; import org.eclipse.ui.navigator.CommonDropAdapterAssistant; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import unc.lib.cdr.workbench.capture.CaptureJob; import unc.lib.cdr.workbench.originals.OriginalFileStore; import unc.lib.cdr.workbench.project.MetsProjectNature; import unc.lib.cdr.workbench.xwalk.MetadataCompartment; public class ArrangementCommonDropAdapterAssistant extends CommonDropAdapterAssistant { @Override public void setCommonDropAdapter(CommonDropAdapter dropAdapter) { super.setCommonDropAdapter(dropAdapter); dropAdapter.setFeedbackEnabled(true); } @Override public boolean isSupportedType(TransferData aTransferType) { if (LocalSelectionTransfer.getTransfer().isSupportedType(aTransferType)) { //LOG.debug("found local selection transfer type"); return true; } /* * else if (ResourceTransfer.getInstance().isSupportedType(aTransferType)) { * LOG.debug("found resource transfer type"); return true; } else if * (PluginTransfer.getInstance().isSupportedType(aTransferType)) { LOG.debug("found plugin transfer type"); * return true; } /*else if (FileTransfer.getInstance().isSupportedType(aTransferType)) { * LOG.debug("found file transfer type"); return true; } */else { return false; } } private static final Logger LOG = LoggerFactory.getLogger(ArrangementCommonDropAdapterAssistant.class); @Override public IStatus validateDrop(Object target, int operation, TransferData transferType) { ISelection selection = LocalSelectionTransfer.getTransfer().getSelection(); int location = getCommonDropAdapter().getCurrentLocation(); // Invalidate the drop if there is more than one type of object in the selection // as handled in handleDrop if (selection instanceof IStructuredSelection) { int seen = 0; for (Object selected : ((IStructuredSelection) selection).toList()) { if (selected instanceof OriginalFileStore) seen |= 1 << 0; else if (selected instanceof DivType) seen |= 1 << 1; else if (selected instanceof MdSecType) seen |= 1 << 2; else if (selected instanceof MetadataCompartment) seen |= 1 << 3; // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan if ((seen & (seen - 1)) != 0) return Status.CANCEL_STATUS; } } // Validate drop based on the type of the target if (target instanceof DivType) { DivType targetDiv = (DivType) target; if (selection instanceof IStructuredSelection) { for (Object selected : ((IStructuredSelection) selection).toList()) { if (selected instanceof DivType) { DivType selectedDiv = (DivType) selected; // Invalidate the drop if the target is not a container and the location is "on" if (!METSUtils.isContainer(targetDiv) && location == ViewerDropAdapter.LOCATION_ON) return Status.CANCEL_STATUS; // Invalidate the drop if a selected item is the same object as the target and the location is "on" if (selectedDiv == targetDiv && location == ViewerDropAdapter.LOCATION_ON) return Status.CANCEL_STATUS; // Invalidate the drop if a selected item is an ancestor of the target DivType div = targetDiv; while (div.eContainer() instanceof DivType) { if (selectedDiv == div) return Status.CANCEL_STATUS; div = (DivType) div.eContainer(); } } } } return Status.OK_STATUS; } else if (target instanceof ArrangementProjectElement) { // Validate the drop only if the location is "on", since it doesn't make sense to put something // before or after the root. if (location == ViewerDropAdapter.LOCATION_ON) return Status.OK_STATUS; } return Status.CANCEL_STATUS; } @Override public IStatus validatePluginTransferDrop(IStructuredSelection aDragSelection, Object aDropTarget) { //LOG.debug("trying to validate plugin transfer drop"); return super.validatePluginTransferDrop(aDragSelection, aDropTarget); } @Override public IStatus handleDrop(CommonDropAdapter aDropAdapter, DropTargetEvent event, Object aTarget) { //LOG.debug("handle drop found transfer type: {}", aDropAdapter.getCurrentTransfer()); event.detail = DND.DROP_NONE; /* * if (ResourceTransfer.getInstance().isSupportedType(aDropAdapter. getCurrentTransfer())) { * LOG.debug("found resource transfer, event data: {}", event.data); IResource[] res = (IResource[]) event.data; * List<IResource> items = new ArrayList<IResource>(res.length); for (IResource r : res) { items.add(r); } return * dropResources(items); } else */ if (LocalSelectionTransfer.getTransfer().isSupportedType(event.currentDataType)) { //LOG.debug("found local selection transfer data, event data: {}", event.data); // put the transfer data somewhere safe IStructuredSelection select = (IStructuredSelection) LocalSelectionTransfer.getTransfer().getSelection(); //LOG.debug("selection: {}", select); List items = select.toList(); if (items.size() > 0) { if (items.get(0) instanceof OriginalFileStore) { return dropOriginals(items); } else if (items.get(0) instanceof DivType) { return dropDivs(items); } else if (items.get(0) instanceof MdSecType) { return dropMdSec((MdSecType)items.get(0)); } else if (items.get(0) instanceof MetadataCompartment) { MetadataCompartment mc = (MetadataCompartment)items.get(0); for(MdSecType mdSec : mc.metadataSections) dropMdSec(mdSec); } } } return Status.CANCEL_STATUS; } /** * @param mdSecs * @return */ private IStatus dropMdSec(MdSecType md) { //LOG.debug("dropMdSecs called"); if (getCommonDropAdapter().getCurrentTarget() instanceof DivType) { // record at a time MetsProjectNature mpn = MetsProjectNature.getNatureForMetsObject(md); DivType bag = METSUtils.findBagDiv(mpn.getMets()); CompoundCommand comboCommand = new CompoundCommand("match crosswalked record to object"); // unlink the mdSec from any divs Iterator iter = bag.eAllContents(); while (iter.hasNext()) { Object o = iter.next(); if (o instanceof DivType) { DivType d = (DivType) o; if (d.getDmdSec().contains(md)) { List<MdSecType> dmdSecs = new ArrayList<MdSecType>(); dmdSecs.addAll(d.getDmdSec()); dmdSecs.remove(md); Command removeDMDID = RemoveCommand.create(mpn.getEditingDomain(), d, MetsPackage.eINSTANCE.getDivType_DmdSec(), md); comboCommand.append(removeDMDID); } else if (d.getMdSec().contains(md)) { List<MdSecType> newMdSecs = new ArrayList<MdSecType>(); newMdSecs.addAll(d.getMdSec()); newMdSecs.remove(md); Command removeDMDID = RemoveCommand.create(mpn.getEditingDomain(), d, MetsPackage.eINSTANCE.getDivType_MdSec(), md); comboCommand.append(removeDMDID); } } } DivType div = (DivType) getCommonDropAdapter().getCurrentTarget(); // add new link // set the status of the mdSec to user linked crosswalk Command setStatus = SetCommand.create(mpn.getEditingDomain(), md, MetsPackage.eINSTANCE.getMdSecType_STATUS(), METSConstants.MD_STATUS_CROSSWALK_USER_LINKED); comboCommand.append(setStatus); List<MdSecType> newDMDIDs = new ArrayList<MdSecType>(); newDMDIDs.addAll(div.getDmdSec()); newDMDIDs.add(md); if(md.eContainer() instanceof AmdSecType) { comboCommand.append(AddCommand.create(mpn.getEditingDomain(), div, MetsPackage.eINSTANCE.getDivType_MdSec(), md)); } else { comboCommand.append(AddCommand.create(mpn.getEditingDomain(), div, MetsPackage.eINSTANCE.getDivType_DmdSec(), md)); } if (comboCommand.canExecute()) { comboCommand.execute(); } else { LOG.debug("Cannot execute drop command: {}", comboCommand.toString()); } // refresh return Status.OK_STATUS; } return Status.CANCEL_STATUS; } /** * @param items * @return */ private IStatus dropDivs(List<DivType> items) { //LOG.debug("dropping Divs"); Object target = getCommonDropAdapter().getCurrentTarget(); if (target instanceof ArrangementProjectElement) { ArrangementProjectElement e = (ArrangementProjectElement) target; MetsProjectNature mpn = e.getProjectNature(); MetsType m = mpn.getMets(); DivType bag = METSUtils.findBagDiv(m); switch (getCommonDropAdapter().getCurrentLocation()) { case ViewerDropAdapter.LOCATION_AFTER: // drop at top level, first insertOrMoveAll(items, bag, 0); break; case ViewerDropAdapter.LOCATION_NONE: case ViewerDropAdapter.LOCATION_BEFORE: case ViewerDropAdapter.LOCATION_ON: // drop at top level, last insertOrMoveAll(items, bag, bag.getDiv().size()); break; } } else if (target instanceof DivType) { DivType d = (DivType) target; DivType parent = (DivType) d.eContainer(); int parentIndex = parent.getDiv().indexOf(d); if (METSUtils.isContainer(d)) { switch (getCommonDropAdapter().getCurrentLocation()) { case ViewerDropAdapter.LOCATION_BEFORE: // drop before this div insertOrMoveAll(items, parent, parentIndex); break; case ViewerDropAdapter.LOCATION_AFTER: // drop after this div insertOrMoveAll(items, parent, parentIndex + 1); break; case ViewerDropAdapter.LOCATION_NONE: case ViewerDropAdapter.LOCATION_ON: // drop in this div, last insertOrMoveAll(items, d, d.getDiv().size()); break; } } else { // it is a File switch (getCommonDropAdapter().getCurrentLocation()) { case ViewerDropAdapter.LOCATION_BEFORE: // drop before this div insertOrMoveAll(items, parent, parentIndex); break; case ViewerDropAdapter.LOCATION_AFTER: // drop after this div insertOrMoveAll(items, parent, parentIndex + 1); break; default: return Status.CANCEL_STATUS; } } } return Status.OK_STATUS; } private void insertOrMoveAll(List<DivType> items, DivType dest, int index) { Iterator<DivType> i = items.iterator(); int insertIndex = index; while (i.hasNext()) { DivType d = i.next(); if (dest.getDiv().contains(d)) { int current = dest.getDiv().indexOf(d); if (current < insertIndex) { insertIndex--; } dest.getDiv().move(insertIndex, d); insertIndex = dest.getDiv().indexOf(d) + 1; } else { if (insertIndex < dest.getDiv().size()) { dest.getDiv().add(insertIndex, d); } else { dest.getDiv().add(d); } insertIndex++; } } } private IStatus dropOriginals(List<OriginalFileStore> items) { //LOG.debug("dropping Resources"); CaptureJob job = null; Object target = getCommonDropAdapter().getCurrentTarget(); if (target instanceof ArrangementProjectElement) { ArrangementProjectElement e = (ArrangementProjectElement) target; MetsProjectNature mpn = e.getProjectNature(); MetsType m = mpn.getMets(); DivType bag = METSUtils.findBagDiv(m); DivType insertBefore = null; switch (getCommonDropAdapter().getCurrentLocation()) { case ViewerDropAdapter.LOCATION_NONE: case ViewerDropAdapter.LOCATION_BEFORE: break; case ViewerDropAdapter.LOCATION_AFTER: // drop at top level, first if (bag.getDiv().size() > 0) { insertBefore = bag.getDiv().get(0); } case ViewerDropAdapter.LOCATION_ON: // drop at top level, last job = new CaptureJob("Capturing dragged resources at top of arrangement", items, bag, insertBefore); break; } } else if (getCommonDropAdapter().getCurrentTarget() instanceof DivType) { DivType d = (DivType) getCommonDropAdapter().getCurrentTarget(); if (METSUtils.isContainer(d)) { switch (getCommonDropAdapter().getCurrentLocation()) { case ViewerDropAdapter.LOCATION_NONE: break; case ViewerDropAdapter.LOCATION_BEFORE: // drop before this div job = new CaptureJob("Capturing dragged resources at specified location", items, (DivType) d.eContainer(), d); break; case ViewerDropAdapter.LOCATION_AFTER: // drop after this div DivType insertBefore = null; DivType parent = (DivType) d.eContainer(); int idx = parent.getDiv().indexOf(d); if (idx + 1 < parent.getDiv().size()) { insertBefore = parent.getDiv().get(idx + 1); } job = new CaptureJob("Capturing dragged resources at specified location", items, (DivType) d.eContainer(), insertBefore); break; case ViewerDropAdapter.LOCATION_ON: // drop in this div, last job = new CaptureJob("Capturing dragged resources at specified location", items, d, null); break; } } else { // it is a File switch (getCommonDropAdapter().getCurrentLocation()) { case ViewerDropAdapter.LOCATION_BEFORE: // drop before this div job = new CaptureJob("Capturing dragged resources at specified location", items, (DivType) d.eContainer(), d); break; case ViewerDropAdapter.LOCATION_AFTER: // drop after this div DivType insertBefore = null; DivType parent = (DivType) d.eContainer(); int idx = parent.getDiv().indexOf(d); if (idx + 1 < parent.getDiv().size()) { insertBefore = parent.getDiv().get(idx + 1); } job = new CaptureJob("Capturing dragged resources at specified location", items, (DivType) d.eContainer(), insertBefore); break; } } } if (job != null) { job.schedule(Job.LONG); return Status.OK_STATUS; } return Status.CANCEL_STATUS; } }