/* ****************************************************************************** * 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.gef.service; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.draw2d.FigureListener; import org.eclipse.draw2d.IFigure; import org.eclipse.jface.viewers.IColorProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Path; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.xmind.gef.IGraphicalViewer; import org.xmind.gef.IZoomListener; import org.xmind.gef.ZoomManager; import org.xmind.gef.ZoomObject; import org.xmind.gef.draw2d.IRotatableFigure; import org.xmind.gef.draw2d.SelectionFigure; import org.xmind.gef.draw2d.geometry.PrecisionDimension; import org.xmind.gef.draw2d.geometry.PrecisionPoint; import org.xmind.gef.draw2d.geometry.PrecisionRectangle; import org.xmind.gef.draw2d.geometry.PrecisionRotator; public class FeedbackService extends GraphicalViewerService implements IZoomListener, FocusListener, FigureListener, IFeedbackService { private static final List<IFeedback> NO_FEEDBACK = Collections.emptyList(); private IFigure layer; private ZoomManager zoom; private List<IFeedback> feedbacks = null; private Map<IFigure, SelectionFigure> selections = new HashMap<IFigure, SelectionFigure>(); private IColorProvider selectionColorProvider = null; private int selectionLineWidth = 2; private int selectionCorner = 5; public FeedbackService(IGraphicalViewer viewer) { super(viewer); } public int getSelectionCorner() { return selectionCorner; } public void setSelectionCorner(int selectionCorner) { this.selectionCorner = selectionCorner; } public int getSelectionLineWidth() { return selectionLineWidth; } public void setSelectionLineWidth(int selectionLineWidth) { this.selectionLineWidth = selectionLineWidth; } public List<IFeedback> getFeedbackParts() { if (feedbacks == null) return NO_FEEDBACK; return feedbacks; } protected void activate() { setZoomManager(getViewer().getZoomManager()); } protected void deactivate() { setZoomManager(null); } protected void hookControl(Control control) { control.addFocusListener(this); } protected void unhookControl(Control canvas) { canvas.removeFocusListener(this); } public void setLayer(IFigure layer) { IFigure oldLayer = this.layer; this.layer = layer; if (feedbacks != null) { if (oldLayer == null && layer != null) { for (IFeedback part : feedbacks) { part.addToLayer(layer); part.update(); } } else if (oldLayer != null && layer == null) { for (IFeedback part : feedbacks) { part.removeFromLayer(oldLayer); } } } } public void focusGained(FocusEvent e) { if (getControl() != null && !getControl().isDisposed()) { Display display = getControl().getDisplay(); if (display != null) { display.asyncExec(new Runnable() { public void run() { if (getControl() != null && !getControl().isDisposed()) refresh(); } }); } } } public void focusLost(FocusEvent e) { if (getControl() != null && !getControl().isDisposed()) { Display display = getControl().getDisplay(); if (display != null) { display.asyncExec(new Runnable() { public void run() { if (getControl() != null && !getControl().isDisposed()) refresh(); } }); } } } private void setZoomManager(ZoomManager zoom) { if (this.zoom == zoom) return; if (this.zoom != null) this.zoom.removeZoomListener(this); this.zoom = zoom; if (this.zoom != null) this.zoom.addZoomListener(this); refresh(); } /** * @see cn.brainy.gef.core.IZoomListener#scaleChanged(cn.brainy.gef.core.ZoomObject, * double, double) */ public void scaleChanged(ZoomObject source, double oldValue, double newValue) { if (isActive() && !isDisposed()) { updateAllFeedback(); updateAllSelections(); } } public void refresh() { if (isActive() && !isDisposed()) { updateAllFeedback(); updateAllSelections(); updateSelectionColors(); } } private void updateAllFeedback() { if (feedbacks != null) { for (Object o : feedbacks.toArray()) { ((IFeedback) o).update(); } } } private void updateAllSelections() { for (IFigure source : selections.keySet()) { updateSelection(source); } } public void addFeedback(IFeedback feedback) { if (feedback == null) return; if (feedbacks != null && feedbacks.contains(feedback)) return; if (feedbacks == null) feedbacks = new ArrayList<IFeedback>(); feedbacks.add(feedback); feedback.setZoomManager(zoom); if (layer != null) feedback.addToLayer(layer); feedback.update(); } public void removeFeedback(IFeedback feedback) { if (feedback == null) return; if (feedbacks == null || !feedbacks.contains(feedback)) return; if (layer != null) feedback.removeFromLayer(layer); feedback.setZoomManager(null); feedbacks.remove(feedback); } /** * @param selectionColorProvider * the selectionColorProvider to set */ public void setSelectionColorProvider(IColorProvider selectionColorProvider) { this.selectionColorProvider = selectionColorProvider; } /** * @return the selectionColorProvider */ public IColorProvider getSelectionColorProvider() { return selectionColorProvider; } public SelectionFigure addSelection(IFigure source) { removeSelection(source); if (layer == null) return null; SelectionFigure selection = createSelectionFigure(); selections.put(source, selection); updateSelection(source); // updateSelectionColors(); layer.add(selection); source.addFigureListener(this); return selection; } private void updateSelectionColors() { IColorProvider colorProvider = getSelectionColorProvider(); if (colorProvider != null) { Color focusColor; Color selectionColor; Color preselectionColor; Color focusFillColor; Color selectionFillColor; Color preselectionFillColor; boolean disabled = getControl() != null && !getControl().isDisposed() && !getControl().isFocusControl(); if (disabled) { focusColor = colorProvider.getForeground(DisabledFocusColor); selectionColor = colorProvider .getForeground(DisabledSelectionColor); preselectionColor = colorProvider .getForeground(DisabledPreselectionColor); focusFillColor = colorProvider .getBackground(DisabledFocusColor); selectionFillColor = colorProvider .getBackground(DisabledSelectionColor); preselectionFillColor = colorProvider .getBackground(DisabledPreselectionColor); } else { focusColor = colorProvider.getForeground(FocusColor); selectionColor = colorProvider.getForeground(SelectionColor); preselectionColor = colorProvider .getForeground(PreselectionColor); focusFillColor = colorProvider.getBackground(FocusColor); selectionFillColor = colorProvider .getBackground(SelectionColor); preselectionFillColor = colorProvider .getBackground(PreselectionColor); } for (SelectionFigure f : selections.values()) { f.setFocusColor(focusColor); f.setSelectionColor(selectionColor); f.setPreselectionColor(preselectionColor); f.setFocusFillColor(focusFillColor); f.setSelectionFillColor(selectionFillColor); f.setPreselectionFillColor(preselectionFillColor); } } } /** * @return */ private SelectionFigure createSelectionFigure() { SelectionFigure f = new SelectionFigure(); IColorProvider colorProvider = getSelectionColorProvider(); if (colorProvider != null) { Color focusColor; Color selectionColor; Color preselectionColor; Color focusFillColor; Color selectionFillColor; Color preselectionFillColor; boolean disabled = getControl() != null && !getControl().isDisposed() && !getControl().isFocusControl(); if (disabled) { focusColor = colorProvider.getForeground(DisabledFocusColor); selectionColor = colorProvider .getForeground(DisabledSelectionColor); preselectionColor = colorProvider .getForeground(DisabledPreselectionColor); focusFillColor = colorProvider .getBackground(DisabledFocusColor); selectionFillColor = colorProvider .getBackground(DisabledSelectionColor); preselectionFillColor = colorProvider .getBackground(DisabledPreselectionColor); } else { focusColor = colorProvider.getForeground(FocusColor); selectionColor = colorProvider.getForeground(SelectionColor); preselectionColor = colorProvider .getForeground(PreselectionColor); focusFillColor = colorProvider.getBackground(FocusColor); selectionFillColor = colorProvider .getBackground(SelectionColor); preselectionFillColor = colorProvider .getBackground(PreselectionColor); } f.setFocusColor(focusColor); f.setSelectionColor(selectionColor); f.setPreselectionColor(preselectionColor); f.setFocusFillColor(focusFillColor); f.setSelectionFillColor(selectionFillColor); f.setPreselectionFillColor(preselectionFillColor); } f.setLineWidth(selectionLineWidth); return f; } public SelectionFigure removeSelection(IFigure source) { SelectionFigure old = selections.remove(source); if (old != null && old.getParent() == layer) { if (layer != null) layer.remove(old); disposeSelection(old); } source.removeFigureListener(this); return old; } /** * @param source * @return */ public SelectionFigure getSelectionFigure(IFigure source) { SelectionFigure figure = selections.get(source); return (figure == null) ? addSelection(source) : figure; } public SelectionFigure setSelected(IFigure source) { SelectionFigure figure = getSelectionFigure(source); if (figure != null) { figure.setFocused(false); figure.setPreselected(false); figure.setSelected(true); } return figure; } public SelectionFigure setPreselected(IFigure source) { SelectionFigure figure = getSelectionFigure(source); if (figure != null) { figure.setFocused(false); figure.setSelected(false); figure.setPreselected(true); } return figure; } public SelectionFigure setFocused(IFigure source) { SelectionFigure figure = getSelectionFigure(source); if (figure != null) { figure.setSelected(false); figure.setPreselected(false); figure.setFocused(true); } return figure; } /** * @see org.eclipse.draw2d.FigureListener#figureMoved(org.eclipse.draw2d.IFigure) */ public void figureMoved(IFigure source) { updateSelection(source); } private void updateSelection(IFigure source) { SelectionFigure selection = selections.get(source); if (selection != null) { disposeSelection(selection); org.xmind.gef.draw2d.graphics.Path p = new org.xmind.gef.draw2d.graphics.Path( Display.getCurrent()); int lineWidth = selectionLineWidth; if (zoom != null) { lineWidth *= zoom.getScale(); if (lineWidth < 2) lineWidth = 2; } selection.setLineWidth(lineWidth); int exp = lineWidth; double halfExp = aZoom(exp * 0.5 + 0.5); PrecisionRectangle bounds = new PrecisionRectangle(source .getBounds());//.resize(-1, -1); if ("win32".equals(SWT.getPlatform())) { //$NON-NLS-1$ bounds.resize(-1, -1); } if (source instanceof IRotatableFigure && ((IRotatableFigure) source).getRotationDegrees() != 0) { IRotatableFigure rf = (IRotatableFigure) source; PrecisionDimension size = rf.getNormalPreferredSize(-1, -1); PrecisionPoint c = bounds.getCenter(); PrecisionRotator r = new PrecisionRotator(c); r.setAngle(rf.getRotationDegrees()); PrecisionRectangle b = r.r(bounds, -1, size.height); b.expand(halfExp, halfExp); p.addRoundedPolygon(selectionCorner, zoom(r.t(b.getTopLeft())), zoom(r.t(b.getTopRight())), zoom(r .t(b.getBottomRight())), zoom(r.t(b .getBottomLeft()))); } else { p.addRoundedRectangle(zoom(bounds.expand(halfExp, halfExp)), selectionCorner); } selection.setPath(p); // selection.setBounds(selection.getPreferredBounds()); } } private double aZoom(double d) { return zoom == null ? d : d / zoom.getScale(); } private PrecisionPoint zoom(PrecisionPoint p) { return zoom == null ? p : p.scale(zoom.getScale()); } private PrecisionRectangle zoom(PrecisionRectangle r) { return zoom == null ? r : r.scale(zoom.getScale()); } private void disposeSelection(SelectionFigure s) { Path p = s.getPath(); if (p != null && !p.isDisposed()) { s.setPath(null); p.dispose(); } } public void dispose() { if (selections != null) { for (Object key : selections.keySet().toArray()) { removeSelection((IFigure) key); } selections.clear(); } super.dispose(); } public void addSkylight(IFigure figure) { } public void removeSkylight(IFigure figure) { } }