/* ****************************************************************************** * 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.ui.util.MindMapUtils.findBranch; import java.util.ArrayList; import java.util.List; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.Label; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Point; import org.eclipse.swt.graphics.Cursor; import org.xmind.core.Core; import org.xmind.core.IBoundary; import org.xmind.core.IRelationship; import org.xmind.core.ITitled; import org.xmind.core.ITopic; import org.xmind.core.event.CoreEvent; import org.xmind.core.event.ICoreEventRegister; import org.xmind.gef.GEF; import org.xmind.gef.IViewer; import org.xmind.gef.draw2d.IAnchor; import org.xmind.gef.part.IGraphicalEditPart; import org.xmind.gef.part.IGraphicalPart; import org.xmind.gef.part.IPart; import org.xmind.gef.part.IPartListener; import org.xmind.gef.part.IRequestHandler; import org.xmind.gef.part.PartEvent; import org.xmind.gef.policy.NullEditPolicy; import org.xmind.gef.service.IFeedback; import org.xmind.gef.util.GEFUtils; import org.xmind.ui.decorations.IBoundaryDecoration; import org.xmind.ui.internal.decorators.BoundaryDecorator; import org.xmind.ui.internal.figures.BoundaryFigure; import org.xmind.ui.internal.graphicalpolicies.BoundaryGraphicalPolicy; import org.xmind.ui.mindmap.IBoundaryPart; import org.xmind.ui.mindmap.IBranchPart; import org.xmind.ui.mindmap.IConnectionPart; import org.xmind.ui.mindmap.IRangeListener; 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.MindMapUI; import org.xmind.ui.mindmap.RangeEvent; import org.xmind.ui.style.Styles; public class BoundaryPart extends NodePart implements IBoundaryPart { private List<IBranchPart> enclosingBranches = null; private ITitleTextPart title = null; private IAnchor anchor = null; private List<IRangeListener> rangeListeners = null; private IPartListener parentListener = new IPartListener() { public void childRemoving(PartEvent event) { if (event.child instanceof IBranchPart) clearBranchesCache(); } public void childAdded(PartEvent event) { if (event.child instanceof IBranchPart) clearBranchesCache(); } }; public BoundaryPart() { setDecorator(BoundaryDecorator.getInstance()); setGraphicalPolicy(BoundaryGraphicalPolicy.getInstance()); } public IBoundary getBoundary() { return (IBoundary) getRealModel(); } public IBranchPart getOwnedBranch() { if (getParent() instanceof IBranchPart) return (IBranchPart) getParent(); return null; } protected void register() { registerModel(getBoundary()); super.register(); } protected void unregister() { super.unregister(); unregisterModel(getBoundary()); } protected Object[] getModelChildren(Object model) { if (hasTitle() && !isPolygonShape(getFigure())) { return new Object[] { new ViewerModel(BoundaryTitleTextPart.class, getBoundary()) }; } return super.getModelChildren(model); } public ITitleTextPart getTitle() { return title; } public void setTitle(ITitleTextPart title) { this.title = title; ((BoundaryFigure) getFigure()) .setTitle(title == null ? null : title.getTextFigure()); } private boolean hasTitle() { ITitled titled = getBoundary(); return titled.hasTitle() && !"".equals(titled.getTitleText()); //$NON-NLS-1$ } public boolean isPolygonShape(IFigure figure) { if (figure == null || !(figure instanceof BoundaryFigure)) return false; IBoundaryDecoration decoration = ((BoundaryFigure) figure) .getDecoration(); if (decoration == null) return false; return Styles.BOUNDARY_SHAPE_POLYGON.equals(decoration.getId()) || Styles.BOUNDARY_SHAPE_ROUNDEDPOLYGON .equals(decoration.getId()); } @SuppressWarnings("unchecked") public Object getAdapter(Class adapter) { if (adapter.isAssignableFrom(IBoundary.class)) return getBoundary(); if (adapter == TitleTextPart.class || adapter == ITitleTextPart.class) return getTitle(); return super.getAdapter(adapter); } 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 = getBoundary().getId(); for (IRelationshipPart rel : sheet.getRelationships()) { IRelationship r = rel.getRelationship(); if (r != null) { if (id.equals(r.getEnd2Id())) 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 = getBoundary().getId(); for (IRelationshipPart rel : sheet.getRelationships()) { IRelationship r = rel.getRelationship(); if (r != null) { if (id.equals(r.getEnd1Id())) list.add(rel); } } } } } protected void declareEditPolicies(IRequestHandler reqHandler) { super.declareEditPolicies(reqHandler); reqHandler.installEditPolicy(GEF.ROLE_SELECTABLE, NullEditPolicy.getInstance()); reqHandler.installEditPolicy(GEF.ROLE_DELETABLE, MindMapUI.POLICY_DELETABLE); reqHandler.installEditPolicy(GEF.ROLE_EDITABLE, MindMapUI.POLICY_EDITABLE); reqHandler.installEditPolicy(GEF.ROLE_MODIFIABLE, MindMapUI.POLICY_MODIFIABLE); reqHandler.installEditPolicy(GEF.ROLE_MOVABLE, NullEditPolicy.getInstance()); reqHandler.installEditPolicy(GEF.ROLE_NAVIGABLE, MindMapUI.POLICY_TOPIC_NAVIGABLE); } protected void registerCoreEvents(Object source, ICoreEventRegister register) { super.registerCoreEvents(source, register); register.register(Core.StartIndex); register.register(Core.EndIndex); register.register(Core.Range); register.register(Core.TitleText); register.register(Core.Style); } public void handleCoreEvent(CoreEvent event) { String type = event.getType(); if (Core.StartIndex.equals(type) || Core.EndIndex.equals(type)) { refresh(); getFigure().revalidate(); IBranchPart branch = getOwnedBranch(); if (branch != null) { branch.treeUpdate(true); } fireRangeChanged(); } else if (Core.TitleText.equals(type)) { ((BoundaryFigure) getFigure()).setTitleVisible( hasTitle() && !isPolygonShape(getFigure())); refresh(); getFigure().revalidate(); } else if (Core.Style.equals(type)) { update(); ((BoundaryFigure) getFigure()).setTitleVisible( hasTitle() && !isPolygonShape(getFigure())); refresh(); getFigure().revalidate(); } else { super.handleCoreEvent(event); } } public List<IBranchPart> getEnclosingBranches() { if (enclosingBranches == null) { enclosingBranches = fillEnclosingBranches( new ArrayList<IBranchPart>()); } return enclosingBranches; } private List<IBranchPart> fillEnclosingBranches(List<IBranchPart> list) { IBoundary b = getBoundary(); List<ITopic> subtopics = b.getEnclosingTopics(); if (!subtopics.isEmpty()) { IViewer viewer = getSite().getViewer(); for (ITopic t : subtopics) { IBranchPart branch = findBranch(viewer.findPart(t)); if (branch != null) list.add(branch); } } return list; } /* * (non-Javadoc) * * @seeorg.xmind.ui.mindmap.IBranchRangePart#encloses(org.xmind.ui.mindmap. * IBranchPart) */ public boolean encloses(IBranchPart subbranch) { return getBoundary().encloses(subbranch.getTopic()); } private void clearBranchesCache() { enclosingBranches = null; } public void setParent(IPart parent) { if (getParent() instanceof BranchPart) { getParent().removePartListener(parentListener); ((BranchPart) getParent()).removeBoundary(this); } super.setParent(parent); if (getParent() instanceof BranchPart) { ((BranchPart) getParent()).addBoundary(this); getParent().addPartListener(parentListener); } } public void refresh() { clearBranchesCache(); super.refresh(); ITitleTextPart title = getTitle(); if (title != null) { title.refresh(); } } public void update() { super.update(); ITitleTextPart title = getTitle(); if (title != null) { title.update(); } } protected IFigure createFigure() { BoundaryFigure figure = new BoundaryFigure(); figure.setTitleVisible(hasTitle() && !isPolygonShape(figure)); return figure; } public IPart findAt(Point position) { IPart ret; ITitleTextPart title = getTitle(); if (title != null) { ret = ((IGraphicalEditPart) title).findAt(position); if (ret != null) return this; } ret = super.findAt(position); return ret; } protected ISelectionFeedbackHelper createSelectionFeedbackHelper() { return new BoundarySelectionFeedbackHelper(); } protected IFeedback createFeedback() { return new BoundaryFeedback(this); } public IFigure findTooltipAt(Point position) { if (hasTitle() && !isPolygonShape(getFigure()) && title != null && title.getFigure().containsPoint(position)) { return new Label(getBoundary().getTitleText()); } return super.findTooltipAt(position); } public Cursor getCursor(Point pos) { int orientation = ((BoundaryFeedback) getFeedback()) .getOrientation(pos); if (orientation != PositionConstants.NONE) return GEFUtils.getPositionCursor(orientation); return super.getCursor(pos); } public boolean containsPoint(Point position) { return super.containsPoint(position) || ((BoundaryFeedback) getFeedback()) .getOrientation(position) != PositionConstants.NONE; } public IAnchor getSourceAnchor(IGraphicalPart connection) { return getAnchor(); } public IAnchor getTargetAnchor(IGraphicalPart connection) { return getAnchor(); } protected IAnchor getAnchor() { if (anchor == null) { anchor = new DecoratedAnchor(getFigure()); } return anchor; } public void addRangeListener(IRangeListener listener) { if (rangeListeners == null) rangeListeners = new ArrayList<IRangeListener>(); rangeListeners.add(listener); } public void removeRangeListener(IRangeListener listener) { if (rangeListeners != null) rangeListeners.remove(listener); } protected void fireRangeChanged() { if (rangeListeners == null) return; RangeEvent event = new RangeEvent(this); for (Object o : rangeListeners.toArray()) { ((IRangeListener) o).rangeChanged(event); } } }