/* ******************************************************************************
* 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.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import org.xmind.core.IBoundary;
import org.xmind.core.IImage;
import org.xmind.core.IRelationship;
import org.xmind.core.IRelationshipEnd;
import org.xmind.core.ISheet;
import org.xmind.core.ISummary;
import org.xmind.core.ITopic;
import org.xmind.core.ITopicRange;
import org.xmind.core.marker.IMarkerRef;
import org.xmind.gef.IViewer;
import org.xmind.gef.command.ICommandStack;
import org.xmind.ui.commands.CommandBuilder;
import org.xmind.ui.commands.DeleteBoundaryCommand;
import org.xmind.ui.commands.DeleteMarkerCommand;
import org.xmind.ui.commands.DeleteRelationshipCommand;
import org.xmind.ui.commands.DeleteSummaryCommand;
import org.xmind.ui.commands.DeleteTopicCommand;
import org.xmind.ui.commands.ModifyImageAlignmentCommand;
import org.xmind.ui.commands.ModifyImageSizeCommand;
import org.xmind.ui.commands.ModifyImageSourceCommand;
import org.xmind.ui.commands.ModifyRangeCommand;
import org.xmind.ui.util.MindMapUtils;
public class DeleteCommandBuilder extends CommandBuilder {
private static final Collection<Object> EMPTY = Collections.emptySet();
private Stack<Object> deleting = null;
private Set<IRelationship> relationships = null;
private Map<ITopic, Set<ITopicRange>> subRanges = null;
private Set<Object> deleted = null;
// private ITopicRefCounter topicLinkRef = null;
public DeleteCommandBuilder(IViewer viewer, CommandBuilder delegate) {
super(viewer, delegate);
}
public DeleteCommandBuilder(IViewer viewer, ICommandStack commandStack) {
super(viewer, commandStack);
}
public void delete(Object element) {
if (element instanceof ITopic) {
deleteTopic((ITopic) element, true);
} else if (element instanceof IBoundary) {
deleteBoundary((IBoundary) element, true);
} else if (element instanceof ISummary) {
deleteSummary((ISummary) element, true);
} else if (element instanceof IRelationship) {
deleteRelationship((IRelationship) element, true);
} else if (element instanceof IMarkerRef) {
deleteMarkerRef((IMarkerRef) element, true);
} else if (element instanceof IImage) {
deleteImage((IImage) element, true);
}
}
protected boolean startDeleting(Object element) {
if (isDeleting(element) || isDeleted(element))
return false;
if (deleting == null)
deleting = new Stack<Object>();
deleting.push(element);
return true;
}
protected boolean isDeleting(Object element) {
return deleting != null && deleting.contains(element);
}
protected void endDeleting() {
if (deleting != null) {
deleting.pop();
}
}
protected void addDeleted(Object element) {
if (deleted == null)
deleted = new HashSet<Object>();
deleted.add(element);
}
protected void removeDeleted(Object element) {
if (deleted != null) {
deleted.remove(element);
}
}
protected boolean isDeleted(Object element) {
return deleted != null && deleted.contains(element);
}
protected Collection<Object> getDeleted() {
return deleted == null ? EMPTY : deleted;
}
protected Collection<Object> getDeleting() {
return deleting == null ? EMPTY : deleting;
}
// protected void deleteTopic(ITopic topic, boolean isCutPrev,
// boolean sourceCollectable) {
//// modifyTopicLinkRef(topic, isCutPrev);
// deleteTopic(topic, sourceCollectable);
// }
protected void deleteTopic(ITopic topic, boolean sourceCollectable) {
if (!startDeleting(topic))
return;
deleteRelsByTopic(topic);
ITopic parent = topic.getParent();
if (parent != null) {
String topicType = topic.getType();
if (ITopic.ATTACHED.equals(topicType)) {
Set<ITopicRange> ranges = getSubRanges(parent);
deleteTopicInRanges(topic, ranges, parent);
} else if (ITopic.SUMMARY.equals(topicType)) {
ISummary summary = findSummaryBySummaryTopic(topic, parent);
if (summary != null) {
deleteSummary(summary, false);
}
}
}
add(new DeleteTopicCommand(topic), sourceCollectable);
addDeleted(topic);
endDeleting();
}
protected void deleteTopicInRanges(ITopic topic, Set<ITopicRange> ranges,
ITopic parent) {
if (ranges.isEmpty())
return;
int index = topic.getIndex();
if (index < 0)
return;
for (Object o : ranges.toArray()) {
ITopicRange range = (ITopicRange) o;
int start = range.getStartIndex();
int end = range.getEndIndex();
if (start == end && start == index) {
deleteTopicRange(range);
} else {
if (start > index) {
add(new ModifyRangeCommand(range, start - 1, true), false);
}
if (end >= index) {
add(new ModifyRangeCommand(range, end - 1, false), false);
}
}
}
}
protected void deleteTopicRange(ITopicRange range) {
if (range instanceof IBoundary) {
deleteBoundary((IBoundary) range, false);
} else if (range instanceof ISummary) {
deleteSummary((ISummary) range, false);
}
}
protected void deleteRelsByTopic(ITopic topic) {
deleteRelByRelEnd(topic);
for (ITopic child : topic.getAllChildren()) {
deleteRelsByTopic(child);
}
for (IBoundary boundary : topic.getBoundaries()) {
deleteRelByRelEnd(boundary);
}
}
// private void modifyTopicLinkRef(ITopic topic, boolean isCutPrev) {
// if (topicLinkRef == null) {
// IWorkbook workbook = topic.getOwnedWorkbook();
// topicLinkRef = (ITopicRefCounter) workbook
// .getAdapter(ITopicRefCounter.class);
// }
//
// String targetId = topic.getId();
// List<ITopic> linkedTopics = topicLinkRef.getLinkTopics(targetId);
// if (linkedTopics != null && !linkedTopics.isEmpty()) {
// ModifyTopicHyperlinkCommand command = new ModifyTopicHyperlinkCommand(
// linkedTopics, null);
// add(command, false);
//
// if (!isCutPrev) {
//// topicLinkRef.removeTopicLinks(targetId);
// ModifyTopicLinkCommand cmd = new ModifyTopicLinkCommand(
// linkedTopics, null);
// add(cmd, false);
// }
// }
//
// List<ITopic> children = topic.getAllChildren();
// if (children != null && !children.isEmpty()) {
// for (ITopic child : children) {
// modifyTopicLinkRef(child, isCutPrev);
// }
// }
// }
protected void deleteRelByRelEnd(IRelationshipEnd end) {
if (hasRelationship()) {
String id = end.getId();
for (Object o : getRelationships().toArray()) {
IRelationship r = (IRelationship) o;
if (id.equals(r.getEnd1Id()) || id.equals(r.getEnd2Id())) {
deleteRelationship(r, false);
}
}
}
}
protected boolean hasRelationship() {
return !getRelationships().isEmpty();
}
protected Set<IRelationship> getRelationships() {
if (relationships == null) {
relationships = new HashSet<IRelationship>();
ISheet sheet = (ISheet) getViewer().getAdapter(ISheet.class);
if (sheet != null) {
relationships.addAll(sheet.getRelationships());
}
}
return relationships;
}
protected ISummary findSummaryBySummaryTopic(ITopic topic, ITopic parent) {
return MindMapUtils.findSummaryBySummaryTopic(topic, parent,
getSubRanges(parent));
}
protected Set<ITopicRange> getSubRanges(ITopic parent) {
if (subRanges == null)
subRanges = new HashMap<ITopic, Set<ITopicRange>>();
Set<ITopicRange> ranges = subRanges.get(parent);
if (ranges == null) {
ranges = new HashSet<ITopicRange>();
if (parent != null) {
ranges.addAll(parent.getBoundaries());
ranges.addAll(parent.getSummaries());
subRanges.put(parent, ranges);
}
}
return ranges;
}
protected void removeSubRange(ITopicRange range, ITopic parent) {
if (subRanges != null) {
Set<ITopicRange> ranges = subRanges.get(parent);
if (ranges != null) {
ranges.remove(range);
}
}
}
protected void addSubRange(ITopicRange range, ITopic parent) {
if (subRanges == null)
subRanges = new HashMap<ITopic, Set<ITopicRange>>();
Set<ITopicRange> ranges = subRanges.get(parent);
if (ranges == null) {
ranges = new HashSet<ITopicRange>();
}
ranges.add(range);
}
protected void deleteBoundary(IBoundary boundary,
boolean sourceCollectable) {
if (!startDeleting(boundary))
return;
deleteRelByRelEnd(boundary);
ITopic parent = boundary.getParent();
add(new DeleteBoundaryCommand(boundary), sourceCollectable);
removeSubRange(boundary, parent);
endDeleting();
addDeleted(boundary);
}
protected void deleteSummary(ISummary summary, boolean sourceCollectable) {
if (!startDeleting(summary))
return;
ITopic parent = summary.getParent();
ITopic summaryTopic = summary.getTopic();
if (summaryTopic != null) {
deleteTopic(summaryTopic, false);
}
add(new DeleteSummaryCommand(summary), sourceCollectable);
removeSubRange(summary, parent);
endDeleting();
addDeleted(summary);
}
protected void deleteRelationship(IRelationship relationship,
boolean sourceCollectable) {
if (!startDeleting(relationship))
return;
add(new DeleteRelationshipCommand(relationship), sourceCollectable);
if (relationships != null) {
relationships.remove(relationship);
}
endDeleting();
addDeleted(relationship);
}
protected void deleteMarkerRef(IMarkerRef markerRef,
boolean sourceCollectable) {
if (!startDeleting(markerRef))
return;
add(new DeleteMarkerCommand(markerRef), sourceCollectable);
endDeleting();
addDeleted(markerRef);
}
protected void deleteImage(IImage image, boolean sourceCollectable) {
if (!startDeleting(image))
return;
add(new ModifyImageSourceCommand(image, null), sourceCollectable);
add(new ModifyImageAlignmentCommand(image, null), sourceCollectable);
add(new ModifyImageSizeCommand(image, IImage.UNSPECIFIED,
IImage.UNSPECIFIED), sourceCollectable);
endDeleting();
addDeleted(image);
}
}