/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.ui.internal.editpolicies;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Display;
import org.xmind.core.Core;
import org.xmind.core.IRelationship;
import org.xmind.core.ISheet;
import org.xmind.core.ITitled;
import org.xmind.core.ITopic;
import org.xmind.core.ITopicComponent;
import org.xmind.gef.GEF;
import org.xmind.gef.ISourceProvider;
import org.xmind.gef.IViewer;
import org.xmind.gef.Request;
import org.xmind.gef.command.Command;
import org.xmind.gef.dnd.DndData;
import org.xmind.gef.dnd.IDndClient;
import org.xmind.gef.dnd.IDndSupport;
import org.xmind.gef.part.IPart;
import org.xmind.ui.commands.CommandMessages;
import org.xmind.ui.commands.ModifyTitleTextCommand;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.util.MindMapUtils;
public class EditablePolicy extends DeletablePolicy {
// private static final String DEFAULT_DND_CLIENT_ID = MindMapUI.DND_MINDMAP_ELEMENT;
// private boolean isCutPrev = false;
// private Map<Object, Object> transferMap = null;
public boolean understands(String requestType) {
return super.understands(requestType)
|| GEF.REQ_COPY.equals(requestType)
|| GEF.REQ_CUT.equals(requestType)
|| GEF.REQ_PASTE.equals(requestType)
|| MindMapUI.REQ_REPLACE_ALL.equals(requestType);
}
public void handle(Request request) {
String reqType = request.getType();
if (GEF.REQ_COPY.equals(reqType)) {
copy(request);
} else if (GEF.REQ_CUT.equals(reqType)) {
cut(request);
} else if (GEF.REQ_PASTE.equals(reqType)) {
paste(request);
} else if (MindMapUI.REQ_REPLACE_ALL.equals(reqType)) {
replaceAll(request);
} else if (!GEF.REQ_DELETE.equals(reqType)) {
super.handle(request);
}
}
protected void copy(Request request) {
IViewer viewer = request.getTargetViewer();
if (viewer == null)
return;
List<IPart> sources = request.getTargets();
List<Object> models = filter(MindMapUtils.getRealModels(sources),
viewer);
if (models.isEmpty())
return;
performCopy(models.toArray(), request.getTargetViewer());
}
protected List<Object> filter(List<Object> elements, IViewer viewer) {
ISheet sheet = (ISheet) viewer.getAdapter(ISheet.class);
ITopic root = (ITopic) viewer.getAdapter(ITopic.class);
ArrayList<Object> list = new ArrayList<Object>(elements.size());
for (Object o : elements) {
if (!shouldRemove(o, elements, sheet, root, viewer))
list.add(o);
}
return list;
}
private boolean shouldRemove(Object element, List<Object> elements,
ISheet sheet, ITopic root, IViewer viewer) {
if (element instanceof IRelationship) {
IRelationship r = (IRelationship) element;
for (Object o : elements) {
if (o instanceof ISheet && o.equals(r.getParent()))
return true;
}
} else if (element instanceof ITopicComponent) {
ITopicComponent c = (ITopicComponent) element;
ISheet s = null;
ITopic p = null;
for (Object o : elements) {
if (o instanceof ISheet) {
if (s == null)
s = c.getOwnedSheet();
if (o.equals(s))
return true;
}
if (p == null)
p = c.getParent();
if (o instanceof ITopic && p != null
&& MindMapUtils.isDescendentOf(p, (ITopic) o))
return true;
}
}
return false;
}
protected void performCopy(Object[] elements, IViewer viewer) {
elements = filterAndSort(elements);
IDndSupport dndSupport = viewer.getDndSupport();
if (dndSupport != null) {
String[] ids = dndSupport.getDndClientIds();
if (ids.length > 0) {
List<Object> data = new ArrayList<Object>(ids.length);
List<Transfer> transfers = new ArrayList<Transfer>(ids.length);
for (String id : ids) {
IDndClient client = dndSupport.getDndClient(id);
if (client != null) {
Object object = client.toTransferData(elements, viewer);
if (object != null) {
data.add(object);
Transfer transfer = client.getTransfer();
transfers.add(transfer);
}
}
}
if (!data.isEmpty()) {
Clipboard clipboard = new Clipboard(Display.getCurrent());
clipboard.setContents(data.toArray(),
transfers.toArray(new Transfer[0]));
clipboard.dispose();
}
}
}
}
private Object[] filterAndSort(Object[] elements) {
if (elements == null) {
return null;
}
List<ITopic> topics = new ArrayList<ITopic>();
List<Object> others = new ArrayList<Object>();
for (Object element : elements) {
if (element instanceof ITopic) {
topics.add((ITopic) element);
} else {
others.add(element);
}
}
List<ITopic> filteredTopics = MindMapUtils.filterOutDescendents(topics,
null);
Collections.sort(filteredTopics, Core.getTopicComparator());
List<Object> all = new ArrayList<Object>(filteredTopics);
all.addAll(others);
return all.toArray();
}
protected void cut(Request request) {
List<IPart> sources = request.getTargets();
List<Object> models = MindMapUtils.getRealModels(sources);
if (models.isEmpty())
return;
// isCutPrev = true;
performCopy(models.toArray(), request.getTargetViewer());
delete(request);
}
protected String getDeleteLabel(String type) {
if (MindMapUI.CATEGORY_TOPIC.equals(type))
return CommandMessages.Command_CutTopic;
if (MindMapUI.CATEGORY_RELATIONSHIP.equals(type))
return CommandMessages.Command_CutRelationship;
if (MindMapUI.CATEGORY_MARKER.equals(type))
return CommandMessages.Command_DeleteMarker;
if (MindMapUI.CATEGORY_SHEET.equals(type))
return CommandMessages.Command_CutSheet;
if (MindMapUI.CATEGORY_BOUNDARY.equals(type))
return CommandMessages.Command_DeleteBoundary;
return CommandMessages.Command_Cut;
}
protected void paste(Request request) {
IViewer viewer = request.getTargetViewer();
if (viewer == null)
return;
IDndSupport dndSupport = viewer.getDndSupport();
if (dndSupport == null)
return;
Clipboard cb = new Clipboard(Display.getCurrent());
DndData dndData;
try {
dndData = dndSupport.parseData(cb.getAvailableTypes(), cb, false);
} finally {
cb.dispose();
}
if (dndData == null)
return;
IDndClient client = dndSupport.getDndClient(dndData.clientId);
if (client == null)
return;
request.setParameter(GEF.PARAM_DROP_OPERATION, DND.DROP_COPY);
Command command = client.makeDNDCommand(dndData.parsedData, request);
if (command == null)
return;
command.setLabel(CommandMessages.Command_Paste);
saveAndRun(command, request.getTargetDomain());
if (command instanceof ISourceProvider) {
select(((ISourceProvider) command).getSources(), viewer);
}
//
// ISheet targetSheet = (ISheet) viewer.getAdapter(ISheet.class);
// if (targetSheet == null)
// return;
//
// IWorkbook targetWorkbook = targetSheet.getParent();
// if (targetWorkbook == null)
// return;
//
// IPart target = request.getPrimaryTarget();
// Object targetModel = target == null ? viewer.getAdapter(ITopic.class)
// : MindMapUtils.getRealModel(target);
// Object[] elements = getElementsFromClipboard(viewer, targetModel);
// if (elements == null || elements.length == 0)
// return;
//
// paste(request, elements, viewer, target,
// MindMapUtils.getRealModels(request.getTargets()).toArray(),
// targetWorkbook);
}
// protected void paste(Request request, Object[] elements, IViewer viewer,
// IPart targetPart, Object[] targets, IWorkbook targetWorkbook) {
//
// ICloneData result = targetWorkbook.clone(Arrays.asList(elements));
// if (!result.hasCloned())
// return;
//
// Collection<Object> cloneds = result.getCloneds();
// ITopic targetTopic;
// if (targets.length > 0 && targets[0] instanceof ITopic) {
// targetTopic = (ITopic) targets[0];
// } else {
// targetTopic = (ITopic) viewer.getAdapter(ITopic.class);
// }
// ISheet sheet = (ISheet) viewer.getAdapter(ISheet.class);
// List<Command> cmds = new ArrayList<Command>(cloneds.size());
// for (Object cloned : cloneds) {
// if (cloned instanceof ITopic) {
// if (targetTopic != null) {
// ITopic clonedTopic = (ITopic) cloned;
// AddTopicCommand addTopic = new AddTopicCommand(clonedTopic,
// targetTopic, -1, ITopic.ATTACHED);
// cmds.add(addTopic);
// ModifyPositionCommand resetPosition = new ModifyPositionCommand(
// clonedTopic, null);
// cmds.add(resetPosition);
// }
// } else if (cloned instanceof IRelationship) {
// if (sheet != null) {
// IRelationship clonedRelationship = (IRelationship) cloned;
// AddRelationshipCommand addRel = new AddRelationshipCommand(
// clonedRelationship, sheet);
// cmds.add(addRel);
// }
// } else if (cloned instanceof IMarker
// || cloned instanceof IMarkerRef) {
// if (targetTopic != null) {
// IMarker marker = (cloned instanceof IMarker) ? (IMarker) cloned
// : ((IMarkerRef) cloned).getMarker();
// if (marker != null) {
// IMarkerGroup group = marker.getParent();
// if (group.isSingleton()) {
// for (IMarker m : group.getMarkers()) {
// if (targetTopic.hasMarker(m.getId())) {
// cmds.add(new DeleteMarkerCommand(
// targetTopic, m.getId()));
// }
// }
// }
// String markerId = (cloned instanceof IMarker) ? ((IMarker) cloned)
// .getId() : ((IMarkerRef) cloned).getMarkerId();
// AddMarkerCommand addMarker = new AddMarkerCommand(
// targetTopic, markerId);
// cmds.add(addMarker);
// }
// }
// } else if (cloned instanceof IBoundary) {
// IBoundary b = (IBoundary) cloned;
// List<ITopic> topics = getSiblingTopics(targets);
// if (!topics.isEmpty() && !hasBoundary(topics)) {
// if (topics.get(0).isAttached()) {
// cmds.add(new ModifyTopicRangeCommand(b, topics.get(0),
// topics.get(topics.size() - 1)));
// cmds.add(new AddBoundaryCommand(b, topics.get(0)
// .getParent()));
// } else if (topics.size() == 1 && !topics.get(0).isRoot()) {
// cmds.add(new ModifyBoundaryMasterCommand(b, true));
// cmds.add(new AddBoundaryCommand(b, topics.get(0)));
// }
// }
// } else if (cloned instanceof IImage) {
// IImage image = (IImage) cloned;
// if (targetTopic != null) {
// cmds.add(new ModifyImageSourceCommand(targetTopic, image
// .getSource()));
// cmds.add(new ModifyImageSizeCommand(targetTopic, image
// .getWidth(), image.getHeight()));
// cmds.add(new ModifyImageAlignmentCommand(targetTopic, image
// .getAlignment()));
// }
// } else if (cloned instanceof URI) {
// URI uri = (URI) cloned;
// if (targetTopic != null) {
// cmds.add(new ModifyTopicHyperlinkCommand(targetTopic, uri
// .toString()));
// }
// }
// }
//
//// if (isCutPrev)
//// modifyTopicLinksRef(elements, targetWorkbook, cmds, result);
//
// if (cmds.isEmpty())
// return;
//
// CompoundCommand cmd = new CompoundCommand(cmds);
// cmd.setLabel(CommandMessages.Command_Paste);
// saveAndRun(cmd, request.getTargetDomain());
// select(cmd.getSources(), viewer);
// }
// private void modifyTopicLinksRef(Object[] elements,
// IWorkbook targetWorkbook, List<Command> cmds, ICloneData result) {
//
// ITopicRefCounter topicLinkRef = (ITopicRefCounter) targetWorkbook
// .getAdapter(ITopicRefCounter.class);
// for (Object element : elements) {
// if (element instanceof ITopic) {
// ITopic originTopic = (ITopic) transferMap.get(element);
// ITopic clonedTopic = (ITopic) result.get(element);
// modifyTopicLink(originTopic, clonedTopic, topicLinkRef, cmds);
// }
// }
// }
// private void modifyTopicLink(ITopic originTopic, ITopic clonedTopic,
// ITopicRefCounter topicLinkRef, List<Command> cmds) {
// String oldHref = originTopic.getId();
// List<ITopic> topicLinks = topicLinkRef.getLinkTopics(oldHref);
// if (topicLinks != null && !topicLinks.isEmpty()) {
// String newHref = clonedTopic.getId();
//// ModifyTopicLinkCommand cmd = new ModifyTopicLinkCommand(topicLinks,
//// newHref);
//// cmds.add(cmd);
//// topicLinkRef.modifyTargetLink(oldHref, newHref);
//
// ModifyTopicHyperlinkCommand command = new ModifyTopicHyperlinkCommand(
// topicLinks, "xmind:#" + newHref); //$NON-NLS-1$
// cmds.add(command);
// }
//
// List<ITopic> children = originTopic.getAllChildren();
// if (children != null && !children.isEmpty()) {
// for (int i = 0; i < children.size(); i++) {
// ITopic oTopic = children.get(i);
// ITopic eTopic = clonedTopic.getAllChildren().get(i);
// modifyTopicLink(oTopic, eTopic, topicLinkRef, cmds);
// }
// }
// }
// private List<ITopic> getSiblingTopics(Object[] targets) {
// ITopic start = null;
// ITopic end = null;
// for (Object o : targets) {
// if (o instanceof ITopic) {
// ITopic t = (ITopic) o;
// if (start != null && MindMapUtils.isDescendentOf(start, t)) {
// start = null;
// }
// if (end != null && MindMapUtils.isDescendentOf(end, t)) {
// end = null;
// }
// if (start == null) {
// start = t;
// } else if (t.getParent().equals(start.getParent())
// && t.getType().equals(start.getType())
// && t.getIndex() < start.getIndex()) {
// start = t;
// }
// if (end == null) {
// end = t;
// } else if (t.getParent().equals(end.getParent())
// && t.getType().equals(end.getType())
// && t.getIndex() > end.getIndex()) {
// end = t;
// }
// }
// }
// if (start == null || end == null)
// return Collections.emptyList();
// return Arrays.asList(start, end);
// }
//
// private boolean hasBoundary(List<ITopic> topics) {
// if (topics.get(0).isAttached()) {
// int startIndex = topics.get(0).getIndex();
// int endIndex = topics.get(topics.size() - 1).getIndex();
// for (IBoundary b : topics.get(0).getParent().getBoundaries()) {
// if (b.getStartIndex() == startIndex
// || b.getEndIndex() == endIndex)
// return true;
// }
// } else if (topics.size() == 1) {
// for (IBoundary b : topics.get(0).getBoundaries()) {
// if (b.isMasterBoundary())
// return true;
// }
// }
// return false;
// }
//
// protected Object[] getElementsFromClipboard(IViewer viewer, Object target) {
// IDndSupport dndSupport = viewer.getDndSupport();
// if (dndSupport != null) {
// String[] ids = dndSupport.getDndClientIds();
// if (ids.length > 0) {
// Clipboard clipboard = new Clipboard(Display.getCurrent());
// try {
// return getElementsFromClipboard(viewer, target, clipboard,
// dndSupport, ids);
// } finally {
// clipboard.dispose();
// }
// }
// }
// return null;
// }
//
// protected Object[] getElementsFromClipboard(IViewer viewer, Object target,
// Clipboard clipboard, IDndSupport dndSupport, String[] ids) {
// TransferData[] types = clipboard.getAvailableTypes();
// IDndClient elementClient = dndSupport
// .getDndClient(DEFAULT_DND_CLIENT_ID);
// if (elementClient != null) {
// Object[] elements = getElementsFromClipboard(viewer, target,
// elementClient, clipboard, types);
// if (elements != null)
// return elements;
// }
// for (String id : ids) {
// if (!DEFAULT_DND_CLIENT_ID.equals(id)) {
// IDndClient client = dndSupport.getDndClient(id);
// Object[] elements = getElementsFromClipboard(viewer, target,
// client, clipboard, types);
// if (elements != null)
// return elements;
// }
// }
// return null;
// }
//
// protected Object[] getElementsFromClipboard(IViewer viewer, Object target,
// IDndClient client, Clipboard clipboard, TransferData[] types) {
// if (client == null)
// return null;
// Transfer transfer = client.getTransfer();
// if (transfer == null)
// return null;
//// if (transfer instanceof MindMapElementTransfer) {
//// transferMap = ((MindMapElementTransfer) transfer).getTransferMap();
//// }
// for (TransferData type : types) {
// if (transfer.isSupportedType(type)) {
// Object contents = clipboard.getContents(transfer);
// if (contents != null)
// return client.toViewerElements(contents, viewer, target);
// }
// }
// return null;
// }
private void replaceAll(Request request) {
String text = (String) request.getParameter(GEF.PARAM_TEXT);
String replacement = (String) request
.getParameter(MindMapUI.PARAM_REPLACEMENT);
if (text == null || replacement == null)
return;
boolean ignoreCase = Boolean.TRUE
.equals(request.getParameter(MindMapUI.PARAM_IGNORE_CASE));
List<IPart> targets = request.getTargets();
if (targets.isEmpty())
return;
if (ignoreCase) {
text = text.toLowerCase();
}
PropertyCommandBuilder builder = new PropertyCommandBuilder(request);
if (builder.canStart()) {
builder.start();
for (IPart target : targets) {
Object model = MindMapUtils.getRealModel(target);
if (model instanceof ITitled) {
ITitled t = (ITitled) model;
String oldText = t.getTitleText();
if (oldText != null) {
String searchText = ignoreCase ? oldText.toLowerCase()
: oldText;
StringBuilder sb = new StringBuilder(
oldText.length() + replacement.length());
int start = 0;
int index = searchText.indexOf(text);
while (index >= 0) {
sb.append(oldText.substring(start, index));
sb.append(replacement);
start = index + text.length();
index = searchText.indexOf(text, start);
}
if (start < oldText.length()) {
sb.append(oldText.substring(start));
}
String newText = sb.toString();
if (!newText.equals(oldText)) {
builder.add(new ModifyTitleTextCommand(t, newText),
true);
}
}
builder.addSource(t, true);
}
}
builder.end();
}
}
}