/* ****************************************************************************** * 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.mindmap; import static org.xmind.core.ISheetSettings.INFO_ITEM; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.LayoutManager; import org.eclipse.draw2d.geometry.Point; import org.eclipse.jface.action.IAction; import org.xmind.core.Core; import org.xmind.core.IImage; import org.xmind.core.INumbering; import org.xmind.core.IRelationship; import org.xmind.core.ISettingEntry; import org.xmind.core.ISheet; import org.xmind.core.ISheetSettings; import org.xmind.core.ITopic; import org.xmind.core.event.CoreEvent; import org.xmind.core.event.ICoreEventRegister; import org.xmind.core.marker.IMarker; import org.xmind.core.marker.IMarkerGroup; import org.xmind.core.marker.IMarkerRef; import org.xmind.core.marker.IMarkerSheet; import org.xmind.gef.GEF; import org.xmind.gef.IViewer; import org.xmind.gef.draw2d.IAnchor; import org.xmind.gef.draw2d.IAnchorListener; import org.xmind.gef.draw2d.ITitledFigure; import org.xmind.gef.draw2d.decoration.IConnectionDecoration; import org.xmind.gef.draw2d.decoration.IDecoration; import org.xmind.gef.part.IGraphicalPart; import org.xmind.gef.part.IPart; import org.xmind.gef.part.IRequestHandler; import org.xmind.gef.policy.NullEditPolicy; import org.xmind.gef.ui.actions.ActionRegistry; import org.xmind.gef.ui.actions.IActionRegistry; import org.xmind.ui.internal.IconTipContributorManager; import org.xmind.ui.internal.InfoItemContributorManager; import org.xmind.ui.internal.decorators.TopicDecorator; import org.xmind.ui.internal.figures.TopicFigure; import org.xmind.ui.internal.graphicalpolicies.TopicGraphicalPolicy; import org.xmind.ui.internal.layouts.TopicLayout; import org.xmind.ui.mindmap.IBranchPart; import org.xmind.ui.mindmap.IConnectionPart; import org.xmind.ui.mindmap.IIconTipContributor; import org.xmind.ui.mindmap.IIconTipPart; import org.xmind.ui.mindmap.IImagePart; import org.xmind.ui.mindmap.IInfoItemContributor; import org.xmind.ui.mindmap.IMarkerPart; import org.xmind.ui.mindmap.IMindMapViewer; import org.xmind.ui.mindmap.INumberingPart; import org.xmind.ui.mindmap.IRelationshipPart; import org.xmind.ui.mindmap.ISelectionFeedbackHelper; import org.xmind.ui.mindmap.ISheetPart; import org.xmind.ui.mindmap.ITitleTextPart; import org.xmind.ui.mindmap.ITopicPart; import org.xmind.ui.mindmap.MindMapUI; import org.xmind.ui.util.MindMapUtils; /** * @author MANGOSOFT */ public class TopicPart extends NodePart implements ITopicPart { private static Comparator<IMarkerRef> MARKER_REF_COMPARATOR = new Comparator<IMarkerRef>() { public int compare(IMarkerRef p, IMarkerRef q) { IMarker pMarker = p.getMarker(); IMarker qMarker = q.getMarker(); if (pMarker == null && qMarker == null) return 0; IMarkerSheet pSheet; List<IMarkerGroup> grouplist; IMarkerGroup pMarkerGroup; if (qMarker == null && pMarker != null) { pSheet = pMarker.getOwnedSheet(); grouplist = pSheet.getMarkerGroups(); pMarkerGroup = pMarker.getParent(); return -10000 - 2000 + grouplist.indexOf(pMarkerGroup) * 100 + pMarkerGroup.getMarkers().indexOf(pMarker); } IMarkerSheet qSheet; IMarkerGroup qMarkerGroup; if (pMarker == null && qMarker != null) { qSheet = qMarker.getOwnedSheet(); grouplist = qSheet.getMarkerGroups(); qMarkerGroup = qMarker.getParent(); return 10000 + 2000 - grouplist.indexOf(qMarkerGroup) * 100 - qMarkerGroup.getMarkers().indexOf(qMarker); } pSheet = pMarker.getOwnedSheet(); qSheet = qMarker.getOwnedSheet(); grouplist = pSheet.getMarkerGroups(); pMarkerGroup = pMarker.getParent(); qMarkerGroup = qMarker.getParent(); if (pSheet.equals(qSheet)) { if (pMarkerGroup.equals(qMarkerGroup)) { List<IMarker> nosingle = pMarkerGroup.getMarkers(); return nosingle.indexOf(pMarker) - nosingle.indexOf(qMarker); } return (grouplist.indexOf(pMarkerGroup) - grouplist.indexOf(qMarkerGroup)) * 100 + pMarkerGroup.getMarkers().indexOf(pMarker) - qMarkerGroup.getMarkers().indexOf(qMarker); } else { if (MindMapUI.getResourceManager().getSystemMarkerSheet() .equals(pSheet)) return -2000 + (grouplist.indexOf(pMarkerGroup) - qSheet .getMarkerGroups().indexOf(qMarkerGroup)) * 100 + pMarkerGroup.getMarkers().indexOf(pMarker) - qMarkerGroup.getMarkers().indexOf(qMarker); return 2000 + (grouplist.indexOf(pMarkerGroup) - qSheet .getMarkerGroups().indexOf(qMarkerGroup)) * 100 + pMarkerGroup.getMarkers().indexOf(pMarker) - qMarkerGroup.getMarkers().indexOf(qMarker); } } }; private ITitleTextPart title = null; private List<IMarkerPart> markers = null; private List<IIconTipPart> iconTips = null; private IImagePart image = null; private INumberingPart numbering = null; private final ChildSorter sorter = new ChildSorter(this); private IActionRegistry actionRegistry = null; private IAnchor anchor = null; private IAnchorListener anchorListener = null; public TopicPart() { setDecorator(TopicDecorator.getInstance()); setGraphicalPolicy(TopicGraphicalPolicy.getInstance()); } public ITopic getTopic() { return (ITopic) getRealModel(); } public IBranchPart getOwnerBranch() { if (getParent() instanceof IBranchPart) return (IBranchPart) getParent(); return null; } public void setParent(IPart parent) { if (getParent() instanceof BranchPart) { BranchPart branch = (BranchPart) getParent(); if (branch.getTopicPart() == this) { branch.setTopicPart(null); } } super.setParent(parent); if (getParent() instanceof BranchPart) { BranchPart branch = (BranchPart) getParent(); branch.setTopicPart(this); } } protected LayoutManager createLayoutManager() { return new TopicLayout(this); } protected void declareEditPolicies(IRequestHandler reqHandler) { super.declareEditPolicies(reqHandler); reqHandler.installEditPolicy(GEF.ROLE_SELECTABLE, NullEditPolicy.getInstance()); reqHandler.installEditPolicy(GEF.ROLE_NAVIGABLE, MindMapUI.POLICY_TOPIC_NAVIGABLE); reqHandler.installEditPolicy(GEF.ROLE_EDITABLE, MindMapUI.POLICY_EDITABLE); reqHandler.installEditPolicy(GEF.ROLE_MODIFIABLE, MindMapUI.POLICY_MODIFIABLE); reqHandler.installEditPolicy(GEF.ROLE_TRAVERSABLE, MindMapUI.POLICY_TOPIC_TRAVERSABLE); reqHandler.installEditPolicy(GEF.ROLE_DROP_TARGET, MindMapUI.POLICY_DROP_TARGET); reqHandler.installEditPolicy(GEF.ROLE_SORTABLE, MindMapUI.POLICY_SORTABLE); if (!isCentral() && !ITopic.SUMMARY.equals(getTopic().getType())) { reqHandler.installEditPolicy(GEF.ROLE_MOVABLE, MindMapUI.POLICY_TOPIC_MOVABLE); } if (isCentral()) { reqHandler.installEditPolicy(GEF.ROLE_MAP_MOVABLE, MindMapUI.POLICY_MAP_MOVABLE); } } private boolean isCentral() { IBranchPart branch = getOwnerBranch(); return branch != null && branch.isCentral(); } // protected void uninstallPolicies(IRequestProcessor reqProc) { // if (reqProc.hasRole(GEF.ROLE_MOVABLE)) // reqProc.uninstallPolicy(GEF.ROLE_MOVABLE); // reqProc.uninstallPolicy(GEF.ROLE_MODIFIABLE); // reqProc.uninstallPolicy(GEF.ROLE_EDITABLE); // reqProc.uninstallPolicy(GEF.ROLE_NAVIGABLE); // reqProc.uninstallPolicy(GEF.ROLE_SELECTABLE); // super.uninstallPolicies(reqProc); // } /* * (non-Javadoc) * @see * org.xmind.gef.part.GraphicalEditPart#containsPoint(org.eclipse.draw2d * .geometry.Point) */ @Override public boolean containsPoint(Point position) { // TODO Auto-generated method stub return super.containsPoint(position); } public ITitleTextPart getTitle() { return title; } public void setTitle(ITitleTextPart title) { this.title = title; } public List<IMarkerPart> getMarkers() { if (markers == null) { markers = new ArrayList<IMarkerPart>(); } return markers; } public void addMarker(IMarkerPart marker) { getMarkers().add(marker); sorter.sort(getMarkers()); } public void removeMarker(IMarkerPart marker) { getMarkers().remove(marker); } public List<IIconTipPart> getIconTips() { if (iconTips == null) { iconTips = new ArrayList<IIconTipPart>(); } return iconTips; } public void addIconTip(IIconTipPart iconTip) { getIconTips().add(iconTip); sorter.sort(getIconTips()); } public void removeIconTip(IIconTipPart iconTip) { getIconTips().remove(iconTip); } public IImagePart getImagePart() { return image; } public void setImagePart(IImagePart image) { this.image = image; } public INumberingPart getNumberingPart() { return numbering; } public void setNumberingPart(INumberingPart numbering) { this.numbering = numbering; } protected IFigure createFigure() { return new TopicFigure(); } protected ISelectionFeedbackHelper createSelectionFeedbackHelper() { return new DefaultSelectionFeedbackHelper(); } protected void register() { registerModel(getTopic()); super.register(); } protected void unregister() { super.unregister(); unregisterModel(getTopic()); } protected Object[] getModelChildren(Object model) { List<Object> list = new ArrayList<Object>(); ITopic topic = getTopic(); list.add(new ViewerModel(TopicTitleTextPart.class, topic)); if (getNumberingText() != null) { list.add(new ViewerModel(NumberingPart.class, topic)); } addIconTips(topic, list); addMarkers(topic, list); if (topic.getImage().getSource() != null) { list.add(new ViewerModel(ImagePart.class, topic.getImage())); } return list.toArray(); } private void addMarkers(ITopic topic, List<Object> list) { Set<IMarkerRef> markerRefs = topic.getMarkerRefs(); if (markerRefs.isEmpty()) return; List<IMarkerRef> markerRefsToSort = new ArrayList<IMarkerRef>( markerRefs); Collections.sort(markerRefsToSort, MARKER_REF_COMPARATOR); for (IMarkerRef ref : markerRefsToSort) { list.add(new ViewerModel(MarkerPart.class, ref)); } } private void addIconTips(ITopic topic, List<Object> list) { List<IIconTipContributor> contributors = IconTipContributorManager .getInstance().getContributors(); if (!contributors.isEmpty()) { for (IIconTipContributor contributor : contributors) { IAction action = contributor.createAction(this, topic); if (action != null) { list.add(new IconTip(topic, contributor, action)); } } } List<IInfoItemContributor> contributors2 = InfoItemContributorManager .getInstance().getContributors(); if (!contributors2.isEmpty()) { for (IInfoItemContributor contributor : contributors2) { IAction action = contributor.createAction(this, topic); if (action != null) list.add(new IconTip(topic, contributor, action)); } } List<IInfoItemContributor> bothContributors = InfoItemContributorManager .getInstance().getBothContributors(); if (!bothContributors.isEmpty()) { ISheet sheet = topic.getOwnedSheet(); if (sheet != null) { for (IInfoItemContributor c : bothContributors) { String infoItemMode = null; String type = c.getId(); if (type != null && !"".equals(type)) { //$NON-NLS-1$ List<ISettingEntry> entries = sheet.getSettings() .getEntries(INFO_ITEM); for (ISettingEntry entry : entries) { String t = entry .getAttribute(ISheetSettings.ATTR_TYPE); if (type.equals(t)) infoItemMode = entry .getAttribute(ISheetSettings.ATTR_MODE); } } if (infoItemMode == null || "".equals(infoItemMode)) //$NON-NLS-1$ infoItemMode = c.getDefaultMode(); if (ISheetSettings.MODE_ICON.equals(infoItemMode) || !c.isCardModeAvailable(topic, this)) { IAction action = c.createAction(this, topic); if (action != null) list.add(new IconTip(topic, c, action)); } } } } } public IPart findAt(Point position) { IPart ret = super.findAt(position); if (ret != null) { if (ret == title || ret == numbering) { if (containsPoint(position)) { // Prevent title exceeding topic bounds return this; } else { ret = null; } } } return ret; } public <T> T getAdapter(Class<T> adapter) { if (adapter.isAssignableFrom(ITopic.class)) return adapter.cast(getTopic()); if (adapter == TitleTextPart.class || adapter == ITitleTextPart.class) return adapter.cast(getTitle()); if (adapter == IBranchPart.class) return adapter.cast(getOwnerBranch()); if (adapter == IActionRegistry.class) return adapter.cast(getActionRegistry()); return super.getAdapter(adapter); } public IActionRegistry getActionRegistry() { if (actionRegistry == null) { actionRegistry = new ActionRegistry(); IViewer viewer = getSite().getViewer(); if (viewer != null) { actionRegistry.setParent((IActionRegistry) viewer .getProperties().get(IMindMapViewer.VIEWER_ACTIONS)); } } return actionRegistry; } protected void registerCoreEvents(Object source, ICoreEventRegister register) { super.registerCoreEvents(source, register); register.register(Core.MarkerRefAdd); register.register(Core.MarkerRefRemove); if (source instanceof ITopic) { ITopic parent = ((ITopic) source).getParent(); if (parent != null) { register.setNextSourceFrom(parent); register.register(Core.TopicAdd); register.register(Core.TopicRemove); INumbering parentNumbering = parent.getNumbering(); register.setNextSourceFrom(parentNumbering); register.register(Core.NumberFormat); register.register(Core.NumberingPrefix); register.register(Core.NumberingSuffix); register.register(Core.NumberPrepending); register.register(Core.NumberingSeparator); register.register(Core.NumberingDepth); } } IImage imageModel = getTopic().getImage(); register.setNextSourceFrom(imageModel); register.register(Core.ImageSource); } public void handleCoreEvent(CoreEvent event) { String type = event.getType(); if (Core.MarkerRefAdd.equals(type) || Core.MarkerRefRemove.equals(type)) { refresh(); } else if (Core.ImageSource.equals(type)) { boolean hasNoImage = event.getNewValue() == null; boolean hadNoImage = event.getOldValue() == null; if ((hasNoImage && !hadNoImage) || (hadNoImage && !hasNoImage)) { refresh(); } } else if (Core.TopicAdd.equals(type) || Core.TopicRemove.equals(type)) { if (ITopic.ATTACHED.equals(event.getData())) { treeRefresh(); } } else if (Core.NumberFormat.equals(type) || Core.NumberingPrefix.equals(type) || Core.NumberingSuffix.equals(type) || Core.NumberPrepending.equals(type) || Core.NumberingSeparator.equals(type) || Core.NumberingDepth.equals(type)) { treeRefresh(); } else { super.handleCoreEvent(event); } } protected void treeRefresh() { refresh(); IBranchPart branch = getOwnerBranch(); if (branch != null) { for (IBranchPart sub : branch.getSubBranches()) { ITopicPart child = sub.getTopicPart(); if (child instanceof TopicPart) { ((TopicPart) child).treeRefresh(); } } for (IBranchPart sub : branch.getCalloutBranches()) { ITopicPart child = sub.getTopicPart(); if (child instanceof TopicPart) { ((TopicPart) child).treeRefresh(); } } } } protected void onActivated() { super.onActivated(); for (IIconTipContributor iconTipCont : IconTipContributorManager .getInstance().getContributors()) { iconTipCont.topicActivated(this); } for (IInfoItemContributor infoItemCont : InfoItemContributorManager .getInstance().getContributors()) infoItemCont.topicActivated(this); for (IInfoItemContributor infoItemCont : InfoItemContributorManager .getInstance().getBothContributors()) infoItemCont.topicActivated(this); } protected void onDeactivated() { for (IInfoItemContributor infoItemCont : InfoItemContributorManager .getInstance().getContributors()) infoItemCont.topicDeactivated(this); for (IInfoItemContributor infoItemCont : InfoItemContributorManager .getInstance().getBothContributors()) infoItemCont.topicDeactivated(this); for (IIconTipContributor iconTipCont : IconTipContributorManager .getInstance().getContributors()) { iconTipCont.topicDeactivated(this); } super.onDeactivated(); } public void refresh() { super.refresh(); for (IIconTipPart iconTip : getIconTips()) { iconTip.refresh(); } if (getParent() instanceof BranchPart) { BranchPart branch = (BranchPart) getParent(); if (branch.getInfoPart() != null) branch.getInfoPart().refresh(); } } public void update() { super.update(); for (IIconTipPart iconTip : getIconTips()) { iconTip.update(); } if (getParent() instanceof BranchPart) { BranchPart branch = (BranchPart) getParent(); if (branch.getInfoPart() != null) branch.getInfoPart().update(); } } protected void updateChildren() { super.updateChildren(); if (title != null) { title.update(); } if (numbering != null) { numbering.update(); } if (image != null) { image.update(); } } protected void fillSourceConnections(List<IConnectionPart> list) { IViewer viewer = getSite().getViewer(); if (viewer != null) { ISheetPart sheet = (ISheetPart) viewer.getAdapter(ISheetPart.class); if (sheet != null) { String id = getTopic().getId(); for (IRelationshipPart rel : sheet.getRelationships()) { IRelationship r = rel.getRelationship(); if (r != null) { if (id.equals(r.getEnd1Id())) list.add(rel); } } } } } protected void fillTargetConnections(List<IConnectionPart> list) { IViewer viewer = getSite().getViewer(); if (viewer != null) { ISheetPart sheet = (ISheetPart) viewer.getAdapter(ISheetPart.class); if (sheet != null) { String id = getTopic().getId(); for (IRelationshipPart rel : sheet.getRelationships()) { IRelationship r = rel.getRelationship(); if (r != null) { if (id.equals(r.getEnd2Id())) list.add(rel); } } } } } @Override public void setModel(Object model) { super.setModel(model); setAccessible(new TopicAccessible(this)); } @Override protected void addChild(IPart child, int index) { super.addChild(child, index); update(); } @Override protected void removeChild(IPart child) { super.removeChild(child); update(); } protected void reorderChild(IPart child, int index) { super.reorderChild(child, index); if (getMarkers().contains(child)) { sorter.sort(getMarkers()); } else if (getIconTips().contains(child)) { sorter.sort(getIconTips()); } update(); } protected void addChildView(IPart child, int index) { super.addChildView(child, index); if (getFigure() instanceof ITitledFigure) { if (child instanceof ITitleTextPart) { ((ITitledFigure) getFigure()) .setTitle(((ITitleTextPart) child).getTextFigure()); } } } protected void removeChildView(IPart child) { super.removeChildView(child); if (getFigure() instanceof ITitledFigure) { if (child instanceof ITitleTextPart) { ((ITitledFigure) getFigure()).setTitle(null); } } } public IAnchor getSourceAnchor(IGraphicalPart connection) { return getTopicAnchor(); } public IAnchor getTargetAnchor(IGraphicalPart connection) { return getTopicAnchor(); } protected IAnchor getTopicAnchor() { if (anchor == null) { anchor = new DecoratedAnchor(getFigure()); if (anchorListener == null) { anchorListener = new IAnchorListener() { public void anchorMoved(IAnchor anchor) { topicAnchorMoved(); } }; } anchor.addAnchorListener(anchorListener); } return anchor; } private void topicAnchorMoved() { IBranchPart branch = getOwnerBranch(); if (branch != null) { branch.getConnections().rerouteAll(branch.getFigure()); branch.getCalloutConnections().rerouteAll(branch.getFigure()); IBranchPart parentBranch = branch.getParentBranch(); if (parentBranch != null) { IDecoration decoration = null; if (MindMapUI.BRANCH_CALLOUT.equals(branch.getBranchType())) { decoration = parentBranch.getCalloutConnections() .getDecoration(branch.getBranchIndex()); } else decoration = parentBranch.getConnections() .getDecoration(branch.getBranchIndex()); if (decoration instanceof IConnectionDecoration) { ((IConnectionDecoration) decoration) .reroute(parentBranch.getFigure()); } } } } @Override protected IFigure getShadowSource() { return getFigure(); } public String getNumberingText() { return MindMapUtils.getNumberingText(getTopic(), null, null); } public String getFullNumberingText() { return MindMapUtils.getFullNumberingText(getTopic(), null, null); } }