/* * ***************************************************************************** * * 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.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.IAdaptable; import org.xmind.core.Core; import org.xmind.core.IBoundary; import org.xmind.core.ILabeled; import org.xmind.core.IPositioned; import org.xmind.core.IRelationship; import org.xmind.core.ISheet; import org.xmind.core.ISummary; import org.xmind.core.ITitled; import org.xmind.core.ITopic; import org.xmind.core.ITopicRange; import org.xmind.core.style.IStyle; import org.xmind.core.style.IStyled; import org.xmind.core.util.HyperlinkUtils; import org.xmind.core.util.Point; import org.xmind.gef.GEF; import org.xmind.gef.Request; import org.xmind.gef.command.Command; import org.xmind.gef.command.CompoundCommand; import org.xmind.gef.part.IPart; import org.xmind.ui.commands.CommandMessages; import org.xmind.ui.commands.ModifyLabelCommand; import org.xmind.ui.commands.ModifyNumberPrependingCommand; import org.xmind.ui.commands.ModifyNumberingDepthCommand; import org.xmind.ui.commands.ModifyNumberingFormatCommand; import org.xmind.ui.commands.ModifyNumberingPrefixCommand; import org.xmind.ui.commands.ModifyNumberingSeparatorCommand; import org.xmind.ui.commands.ModifyNumberingSuffixCommand; import org.xmind.ui.commands.ModifyPositionCommand; import org.xmind.ui.commands.ModifyTitleTextCommand; import org.xmind.ui.commands.ModifyTopicHyperlinkCommand; import org.xmind.ui.commands.ModifyTopicRangeCommand; import org.xmind.ui.mindmap.IBranchPart; import org.xmind.ui.mindmap.IMindMapViewer; import org.xmind.ui.mindmap.ISheetPart; import org.xmind.ui.mindmap.MindMapUI; import org.xmind.ui.prefs.PrefConstants; import org.xmind.ui.util.MindMapUtils; public class ModifiablePolicy extends MindMapPolicyBase { // private static final String NULL = "$NULL$"; //$NON-NLS-1$ // // private static final Map<String, String> EMPTY_CONTENTS = Collections // .emptyMap(); public boolean understands(String requestType) { return super.understands(requestType) || GEF.REQ_MODIFY.equals(requestType) || MindMapUI.REQ_MODIFY_HYPERLINK.equals(requestType) || MindMapUI.REQ_MODIFY_STYLE.equals(requestType) || MindMapUI.REQ_MODIFY_LABEL.equals(requestType) || MindMapUI.REQ_MODIFY_RANGE.equals(requestType) || MindMapUI.REQ_MODIFY_NUMBERING.equals(requestType) || MindMapUI.REQ_RESET_POSITION.equals(requestType) || MindMapUI.REQ_MODIFY_THEME.equals(requestType) || MindMapUI.REQ_REMOVE_ALLSTYLES.equals(requestType); } public void handle(Request request) { String reqType = request.getType(); if (GEF.REQ_MODIFY.equals(reqType)) { modifyText(request); } else if (MindMapUI.REQ_MODIFY_HYPERLINK.equals(reqType)) { modifyHyperlink(request); } else if (MindMapUI.REQ_MODIFY_STYLE.equals(reqType)) { modifyStyle(request); } else if (MindMapUI.REQ_MODIFY_RANGE.equals(reqType)) { modifyRange(request); } else if (MindMapUI.REQ_MODIFY_LABEL.equals(reqType)) { modifyLabel(request); } else if (MindMapUI.REQ_MODIFY_NUMBERING.equals(reqType)) { modifyNumbering(request); } else if (MindMapUI.REQ_RESET_POSITION.equals(reqType)) { resetPosition(request); } else if (MindMapUI.REQ_MODIFY_THEME.equals(reqType)) { modifyTheme(request); } else if (MindMapUI.REQ_REMOVE_ALLSTYLES.equals(reqType)) { removeAllStyles(request); } } private void removeAllStyles(Request request) { ModifyStyleCommandBuilder builder = new ModifyStyleCommandBuilder( request); String commandLabel = (String) request .getParameter(MindMapUI.PARAM_COMMAND_LABEL); if (commandLabel == null) commandLabel = CommandMessages.Command_RemoveStyle; builder.setLabel(commandLabel); if (!builder.canStart()) return; builder.start(); List<IStyled> sources = getAllSources(request); for (IStyled source : sources) builder.removeStyle(source); builder.end(); } private List<IStyled> getAllSources(Request request) { List<IStyled> sources = new ArrayList<IStyled>(); ISheet sheet = (ISheet) request.getTargetViewer() .getAdapter(ISheet.class); if (sheet == null) return sources; if (sheet.getStyleId() != null) sources.add(sheet); List<ITopic> topics = MindMapUtils.getAllTopics(sheet, true, true); for (ITopic topic : topics) { if (topic.getStyleId() != null) sources.add(topic); Set<IBoundary> boundaries = topic.getBoundaries(); for (IBoundary boundary : boundaries) { if (boundary.getStyleId() != null) sources.add(boundary); } Set<ISummary> summaries = topic.getSummaries(); for (ISummary summary : summaries) { if (summary.getStyleId() != null) sources.add(summary); } } Set<IRelationship> relationships = sheet.getRelationships(); for (IRelationship relationship : relationships) { if (relationship.getStyleId() != null) sources.add(relationship); } return sources; } private void modifyTheme(Request request) { IPart target = request.getPrimaryTarget(); if (!(target instanceof ISheetPart)) return; if (!request.hasParameter(MindMapUI.PARAM_RESOURCE)) return; ISheetPart sheetPart = (ISheetPart) target; ISheet sheet = sheetPart.getSheet(); Object param = request.getParameter(MindMapUI.PARAM_RESOURCE); IStyle theme = (IStyle) param; ModifyThemeCommandBuilder builder = new ModifyThemeCommandBuilder( request.getTargetViewer(), request.getTargetCommandStack(), theme); builder.setLabel(CommandMessages.Command_ModifyTheme); if (!builder.canStart()) return; builder.start(); Object override = request.getParameter(MindMapUI.PARAM_OVERRIDE); if (PrefConstants.THEME_OVERRIDE.equals(override)) { List<IStyled> sources = getAllSources(request); for (IStyled source : sources) builder.removeStyle(source); } builder.modify(sheet); builder.end(); } private void resetPosition(Request request) { List<IPositioned> positionOwners = new ArrayList<IPositioned>(); List<IRelationship> rels = new ArrayList<IRelationship>(); IPart target = request.getPrimaryTarget(); if (target == null || target instanceof ISheetPart) { ISheetPart sheet; if (target == null) { sheet = ((IMindMapViewer) request.getTargetViewer()) .getSheetPart(); } else { sheet = (ISheetPart) target; } if (sheet != null) { IBranchPart centralBranch = sheet.getCentralBranch(); if (centralBranch != null && MindMapUtils.isSubBranchesFreeable(centralBranch)) { for (IBranchPart main : centralBranch.getSubBranches()) { if (MindMapUtils.isBranchFreeable(main)) { positionOwners.add(main.getTopic()); } } } } } else { List<IPart> targets = request.getTargets(); for (IPart p : targets) { Object o = MindMapUtils.getRealModel(p); if (o instanceof IPositioned) { IPositioned positionOwner = (IPositioned) o; Point position = positionOwner.getPosition(); if (position != null) // if (positionOwner.getPosition() != null) positionOwners.add(positionOwner); } else if (o instanceof IRelationship) { rels.add((IRelationship) o); } } } if (positionOwners.isEmpty() && rels.isEmpty()) return; List<Command> commands = new ArrayList<Command>( positionOwners.size() + rels.size() * 2); for (IPositioned p : positionOwners) { if (!(p instanceof ITopic && !((ITopic) p).isAttached())) { commands.add(new ModifyPositionCommand(p, null)); } } for (IRelationship r : rels) { commands.add(new ModifyPositionCommand(r.getControlPoint(0), null)); commands.add(new ModifyPositionCommand(r.getControlPoint(1), null)); // commands.add(new ResetRelationshipControlPointCommand(r, 0)); // commands.add(new ResetRelationshipControlPointCommand(r, 1)); } if (commands.isEmpty()) return; CompoundCommand cmd = new CompoundCommand(commands); cmd.setLabel(CommandMessages.Command_ResetPosition); saveAndRun(cmd, request.getTargetDomain()); } private void modifyNumbering(Request request) { List<IPart> targets = request.getTargets(); List<ITopic> topics = new ArrayList<ITopic>(targets.size()); for (IPart p : targets) { Object o = MindMapUtils.getRealModel(p); if (o instanceof ITopic) { ITopic t = ((ITopic) o).getParent(); if (t == null) t = (ITopic) o; if (!topics.contains(t)) { topics.add(t); } } } if (topics.isEmpty()) return; List<Command> commands = new ArrayList<Command>(4); if (request.hasParameter(MindMapUI.PARAM_NUMBERING_FORMAT)) { String newFormat = (String) request .getParameter(MindMapUI.PARAM_NUMBERING_FORMAT); commands.add(new ModifyNumberingFormatCommand(topics, newFormat)); } if (request.hasParameter(MindMapUI.PARAM_NUMBERING_SEPARATOR)) { String newSeparator = (String) request .getParameter(MindMapUI.PARAM_NUMBERING_SEPARATOR); commands.add( new ModifyNumberingSeparatorCommand(topics, newSeparator)); } if (request.hasParameter(MindMapUI.PARAM_NUMBERING_PREFIX)) { String newPrefix = (String) request .getParameter(MindMapUI.PARAM_NUMBERING_PREFIX); commands.add(new ModifyNumberingPrefixCommand(topics, newPrefix)); } if (request.hasParameter(MindMapUI.PARAM_NUMBERING_SUFFIX)) { String newSuffix = (String) request .getParameter(MindMapUI.PARAM_NUMBERING_SUFFIX); commands.add(new ModifyNumberingSuffixCommand(topics, newSuffix)); } if (request.hasParameter(MindMapUI.PARAM_NUMBERING_PREPENDING)) { Boolean newPrepending = (Boolean) request .getParameter(MindMapUI.PARAM_NUMBERING_PREPENDING); commands.add( new ModifyNumberPrependingCommand(topics, newPrepending)); } if (request.hasParameter(MindMapUI.PARAM_NUMBERING_DEPTH)) { String newDepth = (String) request .getParameter(MindMapUI.PARAM_NUMBERING_DEPTH); commands.add(new ModifyNumberingDepthCommand(topics, newDepth)); } if (commands.isEmpty()) return; CompoundCommand cmd = new CompoundCommand(commands); cmd.setLabel(CommandMessages.Command_ModifyNumbering); saveAndRun(cmd, request.getTargetDomain()); } private void modifyLabel(Request request) { if (!request.hasParameter(GEF.PARAM_TEXT)) return; String text = (String) request.getParameter(GEF.PARAM_TEXT); if (text == null) text = EMPTY; Collection<String> labels = MindMapUtils.getLabels(text); List<IPart> sources = request.getTargets(); List<Command> cmds = new ArrayList<Command>(sources.size()); for (IPart p : sources) { Object o = MindMapUtils.getRealModel(p); if (o instanceof ILabeled) { cmds.add(new ModifyLabelCommand((ILabeled) o, labels)); } } if (cmds.isEmpty()) return; CompoundCommand cmd = new CompoundCommand(cmds); cmd.setLabel(CommandMessages.Command_ModifyLabels); saveAndRun(cmd, request.getTargetDomain()); select(cmd.getSources(), request.getTargetViewer()); } private void modifyRange(Request request) { IPart target = request.getPrimaryTarget(); ITopicRange targetRange = (ITopicRange) target .getAdapter(ITopicRange.class); if (targetRange == null) return; Object param = request.getParameter(MindMapUI.PARAM_RANGE); if (param == null || !(param instanceof Object[])) return; Object[] newRange = (Object[]) param; if (newRange.length == 0) return; List<ITopic> topics = new ArrayList<ITopic>(newRange.length); ITopic parent = null; for (Object o : newRange) { ITopic t = findTopic(o); if (t != null && !topics.contains(t)) { ITopic p = t.getParent(); if (p != null) { if (parent == null) { parent = p; topics.add(t); } else if (parent == p) { topics.add(t); } } } } if (topics.isEmpty()) return; Collections.sort(topics, Core.getTopicComparator()); ITopic t1 = topics.get(0); ITopic t2 = topics.get(topics.size() - 1); int index1 = t1.getIndex(); int index2 = t2.getIndex(); Collection<? extends ITopicRange> existingRanges = getExistingRanges( parent, targetRange); if (existingRanges == null) return; for (ITopicRange r : existingRanges) { int start = r.getStartIndex(); int end = r.getEndIndex(); if (start == index1 && end == index2) return; } ModifyTopicRangeCommand cmd = new ModifyTopicRangeCommand(targetRange, t1, t2); cmd.setLabel(getModifyRangeLabel(targetRange, topics)); saveAndRun(cmd, request.getTargetDomain()); select(cmd.getSources(), request.getTargetViewer()); } private Collection<? extends ITopicRange> getExistingRanges(ITopic parent, ITopicRange source) { if (source instanceof IBoundary) return parent.getBoundaries(); if (source instanceof ISummary) return parent.getSummaries(); return null; } private String getModifyRangeLabel(ITopicRange rangeModel, List<ITopic> topics) { if (rangeModel instanceof IBoundary) return CommandMessages.Command_ModifyBoundaryRange; if (rangeModel instanceof ISummary) return CommandMessages.Command_ModifySummaryRange; return CommandMessages.Command_ModifyRange; } private ITopic findTopic(Object o) { if (o instanceof ITopic) return (ITopic) o; if (o instanceof IPart) { Object model = MindMapUtils.getRealModel((IPart) o); if (model instanceof ITopic) return (ITopic) model; } if (o instanceof IAdaptable) { return (ITopic) ((IAdaptable) o).getAdapter(ITopic.class); } return null; } private void modifyStyle(Request request) { ModifyStyleCommandBuilder builder = new ModifyStyleCommandBuilder( request); String commandLabel = (String) request .getParameter(MindMapUI.PARAM_COMMAND_LABEL); if (commandLabel == null) commandLabel = CommandMessages.Command_ModifyStyle; builder.setLabel(commandLabel); if (!builder.canStart()) return; builder.start(); List<IPart> targets = request.getTargets(); for (IPart target : targets) { IStyled source = getStyleSource(target); if (source != null) { builder.modify(source); } } builder.end(); } private IStyled getStyleSource(IPart part) { IStyled s = (IStyled) part.getAdapter(IStyled.class); if (s != null) return s; Object m = MindMapUtils.getRealModel(part); return m instanceof IStyled ? (IStyled) m : null; } private void modifyHyperlink(Request request) { String hyperlink = (String) request.getParameter(GEF.PARAM_TEXT); List<ITopic> topics = MindMapUtils.getTopics(request.getTargets()); if (topics.isEmpty()) return; // modifyHyperlinkRef(topics, hyperlink, request); ModifyTopicHyperlinkCommand cmd = new ModifyTopicHyperlinkCommand( topics, hyperlink); cmd.setLabel(CommandMessages.Command_ModifyTopicHyperlink); saveAndRun(cmd, request.getTargetDomain()); } // private void modifyHyperlinkRef(List<ITopic> topics, String newHref, // Request request) { // String newTargetId = null; // if (newHref != null && newHref.startsWith("xmind:#")) //$NON-NLS-1$ // newTargetId = newHref.substring(7); // // ModifyTopicLinkCommand command = new ModifyTopicLinkCommand(topics, // newTargetId); // saveAndRun(command, request.getTargetDomain()); // } // private void modifyHyperlinkRef(List<ITopic> topics, String newHref, // Request request) { //// ITopicHyperlinkRef topicLinkRef = null; // for (ITopic topic : topics) { //// if (topicLinkRef == null) { //// IWorkbook workbook = topic.getOwnedWorkbook(); //// topicLinkRef = (ITopicHyperlinkRef) workbook //// .getAdapter(ITopicHyperlinkRef.class); //// } // modifyTopicLinkRef(topic, newHref, request); // } // } // private void modifyTopicLinkRef(ITopic topic, String newHref, // Request request) { // String oldHref = topic.getHyperlink(); // // String oldTargetId = null; // if (oldHref != null && oldHref.startsWith("xmind:#")) //$NON-NLS-1$ // oldTargetId = oldHref.substring(7); // // String newTargetId = null; // if (newHref != null && newHref.startsWith("xmind:#")) //$NON-NLS-1$ // newTargetId = newHref.substring(7); //// //// topicLinkRef.modifyTopicLinks(oldTargetId, newTargetId, topic.getId()); // //TODO: // // ModifyTopicLinkCommand command = new ModifyTopicLinkCommand(topic, // newTargetId); // saveAndRun(command, request.getTargetDomain()); // } private void modifyText(Request request) { if (!request.hasParameter(GEF.PARAM_TEXT)) return; String text = (String) request.getParameter(GEF.PARAM_TEXT); if (text == null) text = EMPTY; List<IPart> targets = request.getTargets(); if (targets.isEmpty()) return; List<ITitled> ts = new ArrayList<ITitled>(targets.size()); for (IPart p : targets) { Object m = MindMapUtils.getRealModel(p); if (m instanceof ITitled && !ts.contains(m)) { ts.add((ITitled) m); } } if (ts.isEmpty()) return; PropertyCommandBuilder builder = new PropertyCommandBuilder(request); builder.setLabel(getModifyTitleTextLabel(ts)); builder.start(); builder.add(new ModifyTitleTextCommand(ts, text), true); builder.addSourcesFromRequest(false); ITitled titled = ts.get(0); if (titled instanceof ITopic) { ITopic topic = (ITopic) titled; String hyperlink = topic.getHyperlink(); if (hyperlink == null || hyperlink.isEmpty()) { if (HyperlinkUtils.isUrlAddress(text)) { hyperlink = text; } else if (HyperlinkUtils.isEmailAddress(text)) { hyperlink = "mailto:" + text; //$NON-NLS-1$ } builder.add(new ModifyTopicHyperlinkCommand(topic, hyperlink), true); } } builder.end(); } private String getModifyTitleTextLabel(List<ITitled> ts) { Object t = ts.get(0); if (t instanceof ITopic) { return CommandMessages.Command_ModifyTopicTitle; } else if (t instanceof ISheet) { return CommandMessages.Command_ModifySheetTitle; } else if (t instanceof IRelationship) { return CommandMessages.Command_ModifyRelationshipTitle; } else if (t instanceof IBoundary) { return CommandMessages.Command_ModifyBoundaryTitle; } return CommandMessages.Command_ModifyTitle; } }