/* ****************************************************************************** * 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.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.internal.DPIUtil; import org.eclipse.swt.widgets.Display; import org.xmind.core.Core; import org.xmind.core.IBoundary; import org.xmind.core.ICloneData; import org.xmind.core.IFileEntry; import org.xmind.core.ISheet; import org.xmind.core.ISummary; import org.xmind.core.ITopic; import org.xmind.core.ITopicExtension; import org.xmind.core.ITopicExtensionElement; import org.xmind.core.IWorkbook; import org.xmind.core.marker.IMarker; import org.xmind.core.marker.IMarkerGroup; import org.xmind.core.marker.IMarkerSheet; import org.xmind.core.util.FileUtils; import org.xmind.core.util.HyperlinkUtils; import org.xmind.gef.GEF; import org.xmind.gef.GraphicalViewer; 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.command.CompoundCommand; import org.xmind.gef.draw2d.IMinimizable; import org.xmind.gef.draw2d.geometry.Geometry; import org.xmind.gef.graphicalpolicy.IStructure; import org.xmind.gef.graphicalpolicy.IStyleSelector; import org.xmind.gef.part.IGraphicalPart; import org.xmind.gef.part.IPart; import org.xmind.gef.service.IAnimationService; import org.xmind.ui.branch.IBranchStructureExtension; import org.xmind.ui.branch.ICreatableBranchStructureExtension; import org.xmind.ui.commands.AddBoundaryCommand; import org.xmind.ui.commands.AddMarkerCommand; import org.xmind.ui.commands.AddSummaryCommand; import org.xmind.ui.commands.AddTopicCommand; import org.xmind.ui.commands.CommandMessages; import org.xmind.ui.commands.CreateBoundaryCommand; import org.xmind.ui.commands.CreateSummaryCommand; import org.xmind.ui.commands.CreateTopicCommand; import org.xmind.ui.commands.DeleteMarkerCommand; import org.xmind.ui.commands.ModifyBoundaryMasterCommand; import org.xmind.ui.commands.ModifyImageSizeCommand; import org.xmind.ui.commands.ModifyImageSourceCommand; import org.xmind.ui.commands.ModifyRangeCommand; import org.xmind.ui.commands.ModifyRightNumberOfUnbalancedStructureCommand; import org.xmind.ui.commands.ModifySummaryTopicCommand; import org.xmind.ui.commands.ModifyTitleTextCommand; import org.xmind.ui.commands.ModifyTopicHyperlinkCommand; import org.xmind.ui.internal.MindMapMessages; import org.xmind.ui.internal.branch.UnbalancedData; import org.xmind.ui.mindmap.IBranchPart; import org.xmind.ui.mindmap.ITopicPart; import org.xmind.ui.mindmap.MindMapUI; import org.xmind.ui.style.Styles; import org.xmind.ui.util.ImageFormat; import org.xmind.ui.util.MindMapUtils; public class TopicCreatablePolicy extends MindMapPolicyBase { public boolean understands(String requestType) { return super.understands(requestType) || GEF.REQ_CREATE.equals(requestType) || MindMapUI.REQ_CREATE_BEFORE.equals(requestType) || MindMapUI.REQ_CREATE_CHILD.equals(requestType) || MindMapUI.REQ_CREATE_PARENT.equals(requestType) || MindMapUI.REQ_ADD_ATTACHMENT.equals(requestType) || MindMapUI.REQ_ADD_MARKER.equals(requestType) || MindMapUI.REQ_CREATE_BOUNDARY.equals(requestType) || MindMapUI.REQ_CREATE_SUMMARY.equals(requestType) || MindMapUI.REQ_ADD_IMAGE.equals(requestType) || MindMapUI.REQ_CREATE_SHEET.equals(requestType) || MindMapUI.REQ_DUPLICATE_TOPIC.equals(requestType) || MindMapUI.REQ_CREATE_CALLOUT.equals(requestType); } public void handle(Request request) { String reqType = request.getType(); if (GEF.REQ_CREATE.equals(reqType) // || MindMapUI.REQ_CREATE_CHILD.equals(reqType) // || MindMapUI.REQ_CREATE_BEFORE.equals(reqType) // || MindMapUI.REQ_CREATE_PARENT.equals(reqType) || MindMapUI.REQ_DUPLICATE_TOPIC.equals(reqType) || MindMapUI.REQ_CREATE_CALLOUT.equals(reqType)) { createTopic(request); } else if (MindMapUI.REQ_ADD_ATTACHMENT.equals(reqType)) { addAttachments(request); } else if (MindMapUI.REQ_ADD_MARKER.equals(reqType)) { addMarker(request); } else if (MindMapUI.REQ_CREATE_BOUNDARY.equals(reqType)) { createBoundary(request); } else if (MindMapUI.REQ_CREATE_SUMMARY.equals(reqType)) { createSummary(request); } else if (MindMapUI.REQ_ADD_IMAGE.equals(reqType)) { addImage(request); } else if (MindMapUI.REQ_CREATE_SHEET.equals(reqType)) { createSheetFromTopic(request); } } private void createSheetFromTopic(Request request) { List<IPart> targets = request.getTargets(); if (targets.isEmpty()) return; List<ITopic> topics = MindMapUtils.getTopics(targets); if (topics.isEmpty()) return; ITopic sourceTopic = topics.get(0); CreateSheetFromTopicCommandBuilder builder = new CreateSheetFromTopicCommandBuilder( request.getTargetViewer(), request.getTargetCommandStack(), sourceTopic); if (!builder.canStart()) return; builder.start(); builder.setLabel(CommandMessages.Command_CreateSheetFromTopic); builder.run(); builder.end(); } private void createSummary(Request request) { List<IPart> targets = request.getTargets(); Command cmd = createCreateSummaryCommand(request, targets); if (cmd != null) { cmd.setLabel(CommandMessages.Command_CreateSummary); saveAndRun(cmd, request.getTargetDomain()); if (cmd instanceof ISourceProvider) { select(((ISourceProvider) cmd).getSources(), request.getTargetViewer()); } } } private Command createCreateSummaryCommand(Request request, List<IPart> targets) { List<ITopic> topics = MindMapUtils.getTopics(targets); if (topics.isEmpty()) return null; Map<ITopic, Collection<ITopic>> map = categorize(topics, true); List<Command> cmds = new ArrayList<Command>(map.size() * 3); for (ITopic parent : map.keySet()) { Command cmd = createCreateSummariesCommand(parent, map.get(parent)); if (cmd != null) cmds.add(cmd); } if (cmds.isEmpty()) return null; return new CompoundCommand(cmds); } private Command createCreateSummariesCommand(ITopic parent, Collection<ITopic> topics) { if (topics.isEmpty()) return null; List<Range> ranges = getRanges(topics); List<Command> cmds = new ArrayList<Command>(ranges.size()); for (Range range : ranges) { if (!hasSameSummary(parent, range)) { Command cmd = createCreateSummaryCommand(parent, range); if (cmd != null) cmds.add(cmd); } } if (cmds.isEmpty()) return null; return new CompoundCommand(cmds); } private Command createCreateSummaryCommand(ITopic parent, Range range) { IWorkbook workbook = parent.getOwnedWorkbook(); CreateSummaryCommand createSummary = new CreateSummaryCommand(workbook); ModifyRangeCommand modifyStart = new ModifyRangeCommand(createSummary, range.start, true); ModifyRangeCommand modifyEnd = new ModifyRangeCommand(createSummary, range.end, false); CreateTopicCommand createSummaryTopic = new CreateTopicCommand( workbook); ModifyTitleTextCommand modifyTitle = new ModifyTitleTextCommand( createSummaryTopic, MindMapMessages.TitleText_SummaryTopic); ModifySummaryTopicCommand modifySummaryTopic = new ModifySummaryTopicCommand( createSummary, createSummaryTopic); AddSummaryCommand addSummary = new AddSummaryCommand(createSummary, parent); AddTopicCommand addSummaryTopic = new AddTopicCommand( createSummaryTopic, parent, -1, ITopic.SUMMARY); createSummary.setSourceCollectable(false); modifyStart.setSourceCollectable(false); modifyEnd.setSourceCollectable(false); modifySummaryTopic.setSourceCollectable(false); addSummary.setSourceCollectable(false); return new CompoundCommand(createSummary, modifyStart, modifyEnd, createSummaryTopic, modifyTitle, modifySummaryTopic, addSummary, addSummaryTopic); } private boolean hasSameSummary(ITopic parent, Range range) { for (ISummary b : parent.getSummaries()) { int s = b.getStartIndex(); int e = b.getEndIndex(); if (s == range.start && e == range.end) return true; } return false; } private void createBoundary(Request request) { List<IPart> sources = request.getTargets(); Command cmd = createCreateBoundariesCommand(request, sources); if (cmd != null) { cmd.setLabel(CommandMessages.Command_CreateBoundary); saveAndRun(cmd, request.getTargetDomain()); if (cmd instanceof ISourceProvider) { select(((ISourceProvider) cmd).getSources(), request.getTargetViewer()); } } } private Command createCreateBoundariesCommand(Request request, List<IPart> sources) { List<ITopic> topics = MindMapUtils.getTopics(sources); if (topics.isEmpty()) return null; Map<ITopic, Collection<ITopic>> map = categorize(topics, false); List<Command> cmds = new ArrayList<Command>(map.size() * 2); for (ITopic parent : map.keySet()) { Command cmd = createCreateBoundariesCommand(parent, map.get(parent)); if (cmd != null) cmds.add(cmd); } if (cmds.isEmpty()) return null; return new CompoundCommand(cmds); } private Command createCreateBoundariesCommand(ITopic parent, Collection<ITopic> topics) { if (topics.isEmpty()) return null; List<Range> ranges = getRanges(topics); List<Command> cmds = new ArrayList<Command>(ranges.size()); for (Range range : ranges) { if (!hasSameBoundary(parent, range)) { Command cmd = createCreateBoundaryCommand(parent, range); if (cmd != null) cmds.add(cmd); } } if (cmds.isEmpty()) return null; return new CompoundCommand(cmds); } private boolean hasSameBoundary(ITopic parent, Range range) { if (range.overTopic != null) { for (IBoundary b : range.overTopic.getBoundaries()) { if (b.isMasterBoundary()) return true; } } for (IBoundary b : parent.getBoundaries()) { int s = b.getStartIndex(); int e = b.getEndIndex(); if (s == range.start && e == range.end) return true; } return false; } private List<Range> getRanges(Collection<ITopic> topics) { ITopic[] ts = topics.toArray(new ITopic[topics.size()]); Arrays.sort(ts, Core.getTopicComparator()); List<Range> ranges = new ArrayList<Range>(ts.length); Range r = null; for (ITopic t : ts) { String topicType = t.getType(); if (ITopic.DETACHED.equals(topicType) || ITopic.CALLOUT.equals(topicType) || ITopic.SUMMARY.equals(topicType)) { if (r != null) ranges.add(r); r = null; ranges.add(new Range(t)); } else { int i = t.getIndex(); if (i >= 0) { if (r == null) { r = new Range(i); } else if (i == r.end + 1) { r.end = i; } else if (i > r.end + 1) { ranges.add(r); r = new Range(i); } } } } if (r != null) { ranges.add(r); } return ranges; } private Command createCreateBoundaryCommand(ITopic parent, Range range) { if (range.overTopic != null) { CreateBoundaryCommand create = new CreateBoundaryCommand( range.overTopic.getOwnedWorkbook()); ModifyBoundaryMasterCommand modify = new ModifyBoundaryMasterCommand( create, true); AddBoundaryCommand add = new AddBoundaryCommand(create, range.overTopic); return new CompoundCommand(create, modify, add); } CreateBoundaryCommand create = new CreateBoundaryCommand( parent.getOwnedWorkbook()); ModifyRangeCommand modify1 = new ModifyRangeCommand(create, range.start, true); ModifyRangeCommand modify2 = new ModifyRangeCommand(create, range.end, false); AddBoundaryCommand add = new AddBoundaryCommand(create, parent); return new CompoundCommand(create, modify1, modify2, add); } private Map<ITopic, Collection<ITopic>> categorize(List<ITopic> topics, boolean onlyAttachedTopics) { Map<ITopic, Collection<ITopic>> map = new HashMap<ITopic, Collection<ITopic>>(); for (ITopic t : topics) { ITopic p = t.getParent(); if (p != null && (!onlyAttachedTopics || t.isAttached()) && !isAncestorInCollection(p, topics)) { Collection<ITopic> c = map.get(p); if (c == null) { c = new HashSet<ITopic>(); map.put(p, c); } c.add(t); } } return map; } private boolean isAncestorInCollection(ITopic parent, Collection<ITopic> topics) { if (parent == null) return false; if (topics.contains(parent)) return true; return isAncestorInCollection(parent.getParent(), topics); } private void addMarker(Request request) { List<IPart> targets = request.getTargets(); Command cmd = createAddMarkerCommand(request, targets); if (cmd != null) { cmd.setLabel(CommandMessages.Command_AddMarker); saveAndRun(cmd, request.getTargetDomain()); if (cmd instanceof ISourceProvider) { select(((ISourceProvider) cmd).getSources(), request.getTargetViewer()); } } } private Command createAddMarkerCommand(Request request, List<IPart> targets) { String[] markerIds = getMarkerIds(request); if (markerIds == null || markerIds.length == 0) return null; List<Command> cmds = new ArrayList<Command>(targets.size()); createAddMarkerCommand(targets, cmds, markerIds); if (!cmds.isEmpty()) { return new CompoundCommand(cmds); } return null; } private String[] getMarkerIds(Request request) { Object param = request.getParameter(MindMapUI.PARAM_MARKER_ID); if (param instanceof String) return new String[] { (String) param }; if (param instanceof String[]) return (String[]) param; return null; } private void createAddMarkerCommand(List<IPart> targets, List<Command> cmds, String... markerIds) { for (IPart source : targets) { Object m = MindMapUtils.getRealModel(source); if (m instanceof ITopic) { ITopic t = (ITopic) m; for (String markerId : markerIds) { createAddMarkerCommand(t, markerId, cmds); } } } } private void createAddMarkerCommand(ITopic topic, String newMarkerId, List<Command> cmds) { if (topic.hasMarker(newMarkerId)) return; IMarker marker = findMarker(topic, newMarkerId); if (marker != null) { IMarkerGroup group = marker.getParent(); IMarkerSheet sheet = marker.getOwnedSheet(); if (!sheet.isPermanent()) { IMarkerSheet markerSheet = topic.getOwnedWorkbook() .getMarkerSheet(); IMarker existingMarker = markerSheet.findMarker(marker.getId()); if (existingMarker == null || !markerSheet .equals(existingMarker.getOwnedSheet())) { ICloneData cloneData = topic.getOwnedWorkbook() .clone(Arrays.asList(marker)); Object cloned = cloneData.get(marker); if (cloned instanceof IMarker) { marker = (IMarker) cloned; group = marker.getParent(); newMarkerId = marker.getId(); } } } if (group != null && group.isSingleton()) { removeSingletonMarkers(topic, newMarkerId, group, cmds); } cmds.add(new AddMarkerCommand(topic, newMarkerId)); } } private IMarker findMarker(ITopic topic, String markerId) { IWorkbook workbook = topic.getOwnedWorkbook(); if (workbook != null) { IMarkerSheet markerSheet = workbook.getMarkerSheet(); if (markerSheet != null) { IMarker ownedMarker = markerSheet.findMarker(markerId); if (ownedMarker == null) { ownedMarker = MindMapUI.getResourceManager() .getUserMarkerSheet().findMarker(markerId); } return ownedMarker; } } return null; } private void removeSingletonMarkers(ITopic topic, String newMarkerId, IMarkerGroup group, List<Command> cmds) { for (IMarker m : group.getMarkers()) { String markerId = m.getId(); if (!newMarkerId.equals(markerId)) { if (topic.hasMarker(markerId)) { cmds.add(new DeleteMarkerCommand(topic, markerId)); } } } } private void addImage(Request request) { List<ITopic> topics = MindMapUtils.getTopics(request.getTargets()); if (topics.isEmpty()) return; Command command = createAddImageCommand(request, topics); if (command != null) { command.setLabel(CommandMessages.Command_InsertImage); saveAndRun(command, request.getTargetDomain()); if (command instanceof ISourceProvider) { select(((ISourceProvider) command).getSources(), request.getTargetViewer()); } } } private Command createAddImageCommand(Request request, final List<ITopic> topics) { String[] paths = getPaths(request); if (paths == null || paths.length == 0) return null; IViewer viewer = request.getTargetViewer(); if (viewer == null) return null; ISheet sheet = (ISheet) viewer.getAdapter(ISheet.class); if (sheet == null) return null; final IWorkbook workbook = sheet.getOwnedWorkbook(); final String path = paths[0]; final List<Command> cmds = new ArrayList<Command>(paths.length); String errMsg = NLS.bind("Failed to copy file into this workbook: {0}", //$NON-NLS-1$ path); SafeRunner.run(new SafeRunnable(errMsg) { public void run() throws Exception { Command cmd = createAddImageCommand(workbook, path, topics); if (cmd != null) cmds.add(cmd); } }); if (cmds.isEmpty()) return null; return new CompoundCommand(cmds); } private Command createAddImageCommand(IWorkbook workbook, String path, List<ITopic> topics) throws Exception { Dimension size = getImageSize(path); ImageFormat format = ImageFormat .findByExtension(FileUtils.getExtension(path), ImageFormat.PNG); IFileEntry e = workbook.getManifest().createAttachmentFromFilePath(path, format.getMediaType()); if (e == null) return null; String entryPath = e.getPath(); String hyperlink = HyperlinkUtils.toAttachmentURL(entryPath); List<Command> cmds = new ArrayList<Command>(topics.size()); for (ITopic t : topics) { Command cmd = createAddImageCommand(t, hyperlink, size); if (cmd != null) cmds.add(cmd); } if (cmds.isEmpty()) return null; return new CompoundCommand(cmds); } private Dimension getImageSize(String path) { try { Image tempImage = new Image(Display.getCurrent(), path); Rectangle imageBounds = tempImage.getBounds(); tempImage.dispose(); boolean needZoom = DPIUtil.getDeviceZoom() > 100; int width = needZoom ? imageBounds.width / 2 : imageBounds.width; int height = needZoom ? imageBounds.height / 2 : imageBounds.height; return Geometry.getScaledConstrainedSize(width, height, MindMapUI.IMAGE_INIT_WIDTH, MindMapUI.IMAGE_INIT_HEIGHT); } catch (Throwable e) { } return null; } private Command createAddImageCommand(ITopic t, String hyperlink, Dimension size) { ModifyImageSourceCommand modifyImageSource = new ModifyImageSourceCommand( t, hyperlink); if (size != null) { ModifyImageSizeCommand modifySize = new ModifyImageSizeCommand(t, size.width, size.height); return new CompoundCommand(modifyImageSource, modifySize); } else { return new CompoundCommand(modifyImageSource); } } private void addAttachments(Request request) { String[] paths = getPaths(request); if (paths == null || paths.length == 0) return; List<ITopic> topics = MindMapUtils.getTopics(request.getTargets()); if (topics.isEmpty()) return; Command cmd = createAddAttachmentCommand(request, topics, paths); if (cmd != null) { cmd.setLabel(CommandMessages.Command_InsertAttachment); saveAndRun(cmd, request.getTargetDomain()); if (cmd instanceof ISourceProvider) { select(((ISourceProvider) cmd).getSources(), request.getTargetViewer()); } } } private Command createAddAttachmentCommand(Request request, final List<ITopic> topics, String[] paths) { IViewer viewer = request.getTargetViewer(); if (viewer == null) return null; ISheet sheet = (ISheet) viewer.getAdapter(ISheet.class); if (sheet == null) return null; final IWorkbook workbook = sheet.getOwnedWorkbook(); final List<Command> cmds = new ArrayList<Command>(paths.length); for (final String path : paths) { String errMsg = NLS .bind("Failed to copy file into this workbook: {0}", path); //$NON-NLS-1$ SafeRunner.run(new SafeRunnable(errMsg) { public void run() throws Exception { Command cmd = createAddAttachmentCommand(workbook, path, topics); if (cmd != null) cmds.add(cmd); } }); } if (cmds.isEmpty()) return null; return new CompoundCommand(cmds); } private Command createAddAttachmentCommand(IWorkbook workbook, String path, List<ITopic> topics) throws IOException { IFileEntry e = workbook.getManifest() .createAttachmentFromFilePath(path); if (e == null) return null; String hyperlink = HyperlinkUtils.toAttachmentURL(e.getPath()); String title = new File(path).getName(); List<Command> cmds = new ArrayList<Command>(topics.size()); for (ITopic t : topics) { Command cmd = createAddAttachmentCommand(t, title, hyperlink); if (cmd != null) cmds.add(cmd); } if (cmds.isEmpty()) return null; return new CompoundCommand(cmds); } private Command createAddAttachmentCommand(ITopic parent, String title, String hyperlink) { CreateTopicCommand create = new CreateTopicCommand( parent.getOwnedWorkbook()); AddTopicCommand insert = new AddTopicCommand(create, parent, -1, ITopic.ATTACHED); ModifyTitleTextCommand setTitle = new ModifyTitleTextCommand(create, title); ModifyTopicHyperlinkCommand setHyperlink = new ModifyTopicHyperlinkCommand( create, hyperlink); return new CompoundCommand(create, insert, setTitle, setHyperlink); } private String[] getPaths(Request request) { Object param = request.getParameter(GEF.PARAM_PATH); if (param instanceof String) return new String[] { (String) param }; if (param instanceof String[]) return (String[]) param; return null; } private void createTopic(Request request) { IPart source = request.getPrimaryTarget(); IBranchPart sourceBranch = MindMapUtils.findBranch(source); if (sourceBranch == null) return; ITopic sourceTopic = sourceBranch.getTopic(); String reqType = request.getType(); if (GEF.REQ_CREATE.equals(reqType)) { if (ITopic.SUMMARY.equals(sourceTopic.getType())) return; if (sourceBranch.isCentral()) { reqType = MindMapUI.REQ_CREATE_CHILD;// } } else if (MindMapUI.REQ_CREATE_BEFORE.equals(reqType) || MindMapUI.REQ_DUPLICATE_TOPIC.equals(reqType)) { if (ITopic.SUMMARY.equals(sourceTopic.getType())) return; } else if (MindMapUI.REQ_CREATE_PARENT.equals(reqType)) { if (sourceBranch.isCentral()) return; } IViewer viewer = request.getTargetViewer(); ITopic centralTopic = (ITopic) viewer.getAdapter(ITopic.class); if (centralTopic == null) return; CreateTopicCommandBuilder builder = null; List<ITopic> topics = null; if (MindMapUI.REQ_CREATE_PARENT.equals(reqType)) { topics = MindMapUtils.filterOutDescendents( MindMapUtils.getTopics(request.getTargets()), null); sort(topics); if (!topics.isEmpty()) sourceTopic = topics.get(0); builder = new CreateTopicCommandBuilder(viewer, request.getTargetCommandStack(), sourceTopic, reqType, topics); } else { builder = new CreateTopicCommandBuilder(viewer, request.getTargetCommandStack(), sourceTopic, reqType); } if (!builder.canStart()) return; if (ITopic.ATTACHED.equals(builder.getTargetType())) { IPart parentPart = viewer.findPart(builder.getTargetParent()); if (parentPart instanceof ITopicPart) { IBranchPart parentBranch = ((ITopicPart) parentPart) .getOwnerBranch(); if (parentBranch != null) { IBranchPart sourceChild; if (parentBranch.getSubBranches().contains(sourceBranch)) { sourceChild = sourceBranch; } else { sourceChild = null; } IStructure structure = parentBranch.getBranchPolicy() .getStructure(parentBranch); if (structure instanceof ICreatableBranchStructureExtension) { ((ICreatableBranchStructureExtension) structure) .decorateCreateRequest(parentBranch, sourceChild, request); } String centralTopicStructure = centralTopic .getStructureClass(); boolean isUnbalancedStructure = centralTopicStructure == null || UnbalancedData.STRUCTUREID_UNBALANCED .equalsIgnoreCase(centralTopicStructure); if (isUnbalancedStructure) { ITopicExtension extension = centralTopic .createExtension( UnbalancedData.EXTENTION_UNBALANCEDSTRUCTURE); ITopicExtensionElement element = extension.getContent() .getCreatedChild( UnbalancedData.EXTENTIONELEMENT_RIGHTNUMBER); String preCreateRightNum = element.getTextContent(); if (preCreateRightNum == null) preCreateRightNum = String.valueOf(0); int postCreateRightNum = Integer .valueOf(preCreateRightNum).intValue(); if (parentBranch.isCentral()) { int deletedRightNum = 0; if (MindMapUI.REQ_CREATE_PARENT.equals(reqType)) { if (topics != null && !topics.isEmpty()) { for (ITopic rightTopic : topics) { if (rightTopic .getParent() == centralTopic && rightTopic .getIndex() <= postCreateRightNum - 1) deletedRightNum++; } } } List<IBranchPart> mainBranches = parentBranch .getSubBranches(); int size = mainBranches.size(); if ((((IBranchStructureExtension) structure) .getChildTargetOrientation(parentBranch, sourceBranch) == PositionConstants.WEST && parentBranch != sourceBranch) || (parentBranch == sourceBranch && size <= 2 && postCreateRightNum == size)) { postCreateRightNum++; if (size > 2 && (mainBranches.indexOf( sourceBranch) == size - 1) && !MindMapUI.REQ_CREATE_PARENT .equals(reqType)) postCreateRightNum--; } postCreateRightNum = postCreateRightNum - deletedRightNum; if (!preCreateRightNum.equals(postCreateRightNum)) { ModifyRightNumberOfUnbalancedStructureCommand modifyRightNumberCommand = new ModifyRightNumberOfUnbalancedStructureCommand( centralTopic, preCreateRightNum, postCreateRightNum); builder.addPendingCommand( modifyRightNumberCommand, false); //if sourceCollectable is true,the operations of create and move topic //maybe lead to undo/redo error. } } } } } } PropertyCommandBuilder builder2 = new PropertyCommandBuilder(viewer, builder, request); builder.setLabel(CommandMessages.Command_CreateTopic); builder.start(); builder2.start(); if (MindMapUI.REQ_DUPLICATE_TOPIC.equals(reqType)) { builder.createDuplicateTopic(); } else { builder.createTopic(); } if (builder.getCreatedTopic() != null) { builder2.addSource(builder.getCreatedTopic(), true); } builder2.end(); builder.end(); Command command = builder.getCommand(); // Command cmd = createCreateTopicCommand(request, sourceTopic, // sourceBranch, request.getTargetViewer()); // if (cmd == null) // return; // // cmd.setLabel(CommandMessages.Command_CreateTopic); // saveAndRun(cmd, request.getTargetDomain()); if (command instanceof ISourceProvider) { Object creation = ((ISourceProvider) command).getSource(); if (creation != null) { boolean needSelect = true; if (creation instanceof ITopic) { ITopicPart topicPart = MindMapUtils .getTopicPart((ITopic) creation); IBranchPart branch = MindMapUtils.findBranch(topicPart); IStyleSelector styleSelector = branch.getBranchPolicy() .getStyleSelector(branch); if (styleSelector != null) { String hideCallout = styleSelector.getStyleValue(branch, Styles.HideCallout); needSelect = !(Boolean.parseBoolean(hideCallout) && ITopic.CALLOUT .equals(((ITopic) creation).getType())); } } if (needSelect) select(creation, request.getTargetViewer()); if (isAnimationRequired(request)) animateCommand(command, request.getTargetViewer()); } } } // private Command createCreateTopicCommand(Request request, // ITopic sourceTopic, IBranchPart sourceBranch, IViewer viewer) { // CreateTopicCommand create = new CreateTopicCommand(sourceTopic // .getOwnedWorkbook()); // // String reqType = request.getType(); // ITopic parent = null; // Command insert = null; // int index = -1; // String topicType = null; // if (MindMapUI.REQ_CREATE_CHILD.equals(reqType)) { // parent = sourceTopic; // topicType = ITopic.ATTACHED; // insert = new AddTopicCommand(create, parent, -1, topicType); // index = parent.getChildren(topicType).size(); // } else { // parent = sourceTopic.getParent(); // if (parent != null) { // if (GEF.REQ_CREATE.equals(reqType)) { // index = sourceTopic.getIndex() + 1; // topicType = sourceTopic.getType(); // insert = new AddTopicCommand(create, parent, index, // topicType); // } else if (MindMapUI.REQ_CREATE_BEFORE.equals(reqType) // || MindMapUI.REQ_CREATE_PARENT.equals(reqType)) { // index = sourceTopic.getIndex(); // topicType = sourceTopic.getType(); // insert = new AddTopicCommand(create, parent, index, // topicType); // } // } // } // if (insert == null || topicType == null) // return null; // // List<Command> cmds = new ArrayList<Command>(5); // cmds.add(create); // cmds.add(insert); // // if (parent != null && parent.isFolded()) { // ModifyFoldedCommand extend = new ModifyFoldedCommand(parent, false); // extend.setSourceCollectable(false); // cmds.add(extend); // } // // if (topicType != null) { // Command setTitle = createSetTitleTextCommand(parent, topicType, // create); // if (setTitle != null) { // cmds.add(setTitle); // } // } // // if (MindMapUI.REQ_CREATE_PARENT.equals(reqType)) { // if (ITopic.DETACHED.equals(topicType)) { // cmds.add(new ModifyPositionCommand(create, sourceTopic // .getPosition())); // cmds.add(new ModifyPositionCommand(sourceTopic, null)); // } // cmds.add(new DeleteTopicCommand(sourceTopic)); // cmds.add(new AddTopicCommand(sourceTopic, create)); // } else { // if (GEF.REQ_CREATE.equals(reqType)) { // if (ITopic.DETACHED.equals(topicType)) { // Point newPosition = calcNewPosition(sourceTopic, viewer); // cmds.add(new ModifyPositionCommand(create, // new org.xmind.core.util.Point(newPosition.x, // newPosition.y))); // } // } // if (parent != null && index >= 0 // && ITopic.ATTACHED.equals(topicType)) { // createModifyRangesCommand(reqType, parent, index, sourceTopic, // cmds); // } // } // // if (ITopic.ATTACHED.equals(topicType)) { // IPart parentPart = viewer.findPart(parent); // IBranchPart parentBranch = MindMapUtils.findBranch(parentPart); // if (parentBranch != null) { // IBranchPart sourceChild; // if (parentBranch.getSubBranches().contains(sourceBranch)) { // sourceChild = sourceBranch; // } else { // sourceChild = null; // } // IStructure structure = parentBranch.getBranchPolicy() // .getStructure(parentBranch); // if (structure instanceof ICreatableBranchStructureExtension) { // ((ICreatableBranchStructureExtension) structure) // .decorateCreateRequest(parentBranch, sourceChild, // request); // } // } // } // // PropertyCommandBuilder builder = new PropertyCommandBuilder(viewer, // create); // builder.addFromRequest(request, false); // if (!builder.isEmpty()) { // for (Command cmd : builder.getCommands()) { // cmds.add(cmd); // } // } // // return new CompoundCommand(cmds); // } // // private Point calcNewPosition(ITopic sourceTopic, IViewer viewer) { // IPart part = viewer.findPart(sourceTopic); // if (part instanceof IGraphicalPart) { // IFigure figure = ((IGraphicalPart) part).getFigure(); // if (figure instanceof IReferencedFigure) { // Point ref = ((IReferencedFigure) figure).getReference(); // return ref.getTranslated(0, // figure.getPreferredSize().height + 30); // } // } // org.xmind.core.util.Point position = sourceTopic.getPosition(); // return new Point(position.x, position.y + 60); // } // // private Command createSetTitleTextCommand(ITopic parent, String type, // ISourceProvider sourceProvider) { // if (parent == null) // return null; // // String newTitle; // if (ITopic.DETACHED.equals(type)) { // newTitle = MindMapMessages.TitleText_FloatingTopic; // } else { // int size = parent.getChildren(type).size(); // int index = size + 1; // if (parent.isRoot()) { // newTitle = String.format(MindMapMessages.TitleText_MainTopic, // index); // } else { // newTitle = String.format(MindMapMessages.TitleText_Subtopic, // index); // } // } // return new ModifyTitleTextCommand(sourceProvider, newTitle); // } // // private void createModifyRangesCommand(String reqType, ITopic parent, // int index, ITopic sourceTopic, List<Command> cmds) { // int sourceTopicIndex = sourceTopic == null ? -1 : sourceTopic // .getIndex(); // fillModifyRangeCommands(parent.getBoundaries(), reqType, // sourceTopicIndex, parent, index, cmds); // fillModifyRangeCommands(parent.getSummaries(), reqType, // sourceTopicIndex, parent, index, cmds); // } // // private void fillModifyRangeCommands(Set<? extends ITopicRange> ranges, // String reqType, int sourceTopicIndex, ITopic parent, int index, // List<Command> cmds) { // for (ITopicRange r : ranges) { // Command cmd = createModifyRangeCommand(r, reqType, // sourceTopicIndex, parent, index); // if (cmd != null) // cmds.add(cmd); // } // } // // private Command createModifyRangeCommand(ITopicRange r, String reqType, // int sourceTopicIndex, ITopic parent, int index) { // int startIndex = r.getStartIndex(); // int endIndex = r.getEndIndex(); // if ((GEF.REQ_CREATE.equals(reqType) && sourceTopicIndex == endIndex) // || (MindMapUI.REQ_CREATE_BEFORE.equals(reqType) && sourceTopicIndex == startIndex)) { // ModifyRangeCommand cmd = new ModifyRangeCommand(r, endIndex + 1, // false); // cmd.setSourceCollectable(false); // return cmd; // } // // if (startIndex >= index || endIndex >= index) { // List<ITopic> subtopics = r.getEnclosingTopics(); // if (!subtopics.isEmpty()) { // ITopic start = subtopics.get(0); // ITopic end = subtopics.get(subtopics.size() - 1); // return new ModifyTopicRangeCommand(r, start, end); // } // } // return null; // } private void sort(List<ITopic> topics) { if (topics == null || topics.size() == 0) { return; } Collections.sort(topics, new Comparator<ITopic>() { public int compare(ITopic o1, ITopic o2) { return o1.getIndex() - o2.getIndex(); } }); } protected void doAnimateCommand(Command cmd, IAnimationService anim, IViewer viewer) { Object source = ((ISourceProvider) cmd).getSource(); if (source != null) { IMinimizable min = getMinimizable(source, viewer); if (min != null) { min.setMinimized(true); ((GraphicalViewer) viewer).getLightweightSystem() .getUpdateManager().performValidation(); } } super.doAnimateCommand(cmd, anim, viewer); } protected void createAnimation(Command cmd, IViewer viewer) { Object source = ((ISourceProvider) cmd).getSource(); IMinimizable min = getMinimizable(source, viewer); if (min != null) { min.setMinimized(false); } } private IMinimizable getMinimizable(Object o, IViewer viewer) { IPart part = viewer.findPart(o); if (part instanceof IGraphicalPart) { IFigure figure = ((IGraphicalPart) part).getFigure(); if (figure instanceof IMinimizable) { return (IMinimizable) figure; } } return null; } }