| /******************************************************************************* |
| * Copyright (c) 2006 Sybase, Inc. and others. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Sybase, Inc. - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.pagedesigner.commands.nav; |
| |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.draw2d.geometry.Rectangle; |
| import org.eclipse.gef.EditPart; |
| import org.eclipse.gef.commands.Command; |
| import org.eclipse.jst.jsf.common.ui.internal.logging.Logger; |
| import org.eclipse.jst.pagedesigner.PDPlugin; |
| import org.eclipse.jst.pagedesigner.dom.EditModelQuery; |
| import org.eclipse.jst.pagedesigner.validation.caret.ActionData; |
| import org.eclipse.jst.pagedesigner.validation.caret.IMovementMediator; |
| import org.eclipse.jst.pagedesigner.validation.caret.InlineEditingNavigationMediator; |
| import org.eclipse.jst.pagedesigner.validation.caret.Target; |
| import org.eclipse.jst.pagedesigner.viewer.DesignPosition; |
| import org.eclipse.jst.pagedesigner.viewer.DesignRange; |
| import org.eclipse.jst.pagedesigner.viewer.EditPartPositionHelper; |
| import org.eclipse.jst.pagedesigner.viewer.IHTMLGraphicalViewer; |
| import org.eclipse.swt.widgets.Caret; |
| |
| /** |
| * @author mengbo |
| */ |
| public class VerticalMoveCommand extends Command { |
| private static Logger _log = PDPlugin |
| .getLogger(HorizontalMoveCommand.class); |
| |
| IHTMLGraphicalViewer _viewer; |
| |
| boolean _up; |
| |
| boolean _onlyMoveEnd; |
| |
| /** |
| * @param viewer |
| * @param up |
| * @param c |
| */ |
| public VerticalMoveCommand(IHTMLGraphicalViewer viewer, boolean up, |
| boolean c) { |
| _viewer = viewer; |
| _up = up; |
| _onlyMoveEnd = c; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.gef.commands.Command#execute() |
| */ |
| public void execute() { |
| int OFFSET = 2; |
| DesignRange range = _viewer.getRangeSelection(); |
| if (range == null || !range.isValid()) { |
| _log.error("invalid range"); //$NON-NLS-1$ |
| return; |
| } |
| IMovementMediator moveMediator = new InlineEditingNavigationMediator( |
| new ActionData(ActionData.KEYBOARD_NAVAGATION, null)); |
| DesignPosition position = range.getEndPosition(); |
| Caret caret = _viewer.getCaret(); |
| Point point = null; |
| DesignPosition newPos = position; |
| EditPart containerpart = null, rootpart1; |
| if (_up) { |
| point = new Point(((CaretPositionTracker) _viewer).getXoffset(), |
| caret.getBounds().y); |
| } else { |
| point = new Point(((CaretPositionTracker) _viewer).getXoffset(), |
| caret.getBounds().y + caret.getBounds().height); |
| |
| } |
| rootpart1 = getRootEditablePart(position.getContainerPart(), |
| moveMediator);// position.getContainerPart(); |
| if (rootpart1 == null) { |
| return; |
| } |
| |
| point = adjustLocation(rootpart1, point); |
| Rectangle bound = EditPartPositionHelper.getAbsoluteBounds(rootpart1); |
| // get current according to the point. |
| // FlowBoxLine line = |
| // getCurrentLine(moveMediator.getEditableContainer(new |
| // Target(rootpart)), point, moveMediator); |
| while (true) { |
| // try to change offset and then to search for new point. |
| if (_up) { |
| point.y -= OFFSET; |
| if (point.y <= bound.y) { |
| newPos = position; |
| break; |
| } |
| } else { |
| point.y += OFFSET; |
| if (point.y >= bound.y + bound.height) { |
| newPos = position; |
| break; |
| } |
| } |
| containerpart = ((InlineEditingNavigationMediator) moveMediator) |
| .getConstainedEditableContainer(position, point, _viewer); |
| if (containerpart != null) { |
| if (!EditModelQuery.isChild(Target.resolveNode(rootpart1), |
| Target.resolveNode(containerpart))) { |
| containerpart = rootpart1; |
| } |
| bound = EditPartPositionHelper.getAbsoluteBounds(rootpart1); |
| newPos = EditPartPositionHelper |
| .findEditPartPositionConstrained(containerpart, point, |
| moveMediator); |
| } else { |
| newPos = position; |
| break; |
| } |
| if (newPos != null) { |
| if (found(newPos, position)) { |
| break; |
| } |
| } |
| } |
| setRange(position, newPos); |
| } |
| |
| private void setRange(DesignPosition position, DesignPosition newPos) { |
| if (!EditModelQuery.isSame(position, newPos)) { |
| { |
| if (_onlyMoveEnd) { |
| _viewer.setRangeEndPosition(newPos); |
| } else { |
| _viewer.setRange(newPos, newPos); |
| } |
| } |
| } |
| } |
| |
| /* |
| * We should change this, it is too tricky to do in this way. |
| */ |
| private Point adjustLocation(EditPart rootPart, Point point) { |
| Point result = point.getCopy(); |
| Rectangle bounds = EditPartPositionHelper.getAbsoluteBounds(rootPart); |
| if (!bounds.contains(point)) { |
| if (bounds.getLeft().x > point.x) { |
| result.x = bounds.getLeft().x; |
| } else if (bounds.getRight().x < point.x) { |
| result.x = bounds.getRight().x; |
| } |
| } |
| return result; |
| } |
| |
| private EditPart getRootEditablePart(EditPart part, |
| IMovementMediator moveMediator) { |
| EditPart rootpart = null; |
| if ((rootpart = ((InlineEditingNavigationMediator) moveMediator) |
| .getRootConstainedEditableContainer(new Target(part))) == null) { |
| rootpart = moveMediator.getEditableContainer(new Target(part)); |
| } |
| return rootpart; |
| } |
| |
| private boolean found(DesignPosition newPos, DesignPosition prevPos) { |
| Rectangle newRec = EditPartPositionHelper |
| .convertToAbsoluteCaretRect(newPos); |
| Rectangle prevRec = EditPartPositionHelper |
| .convertToAbsoluteCaretRect(prevPos); |
| if (_up) { |
| return getYDistance(newRec, prevRec, _up) < 0; |
| } |
| return getYDistance(newRec, prevRec, _up) > 0; |
| } |
| |
| /** |
| * Distance from rec1 to rec2 at y coordination, if top, compare top, |
| * otherwise compare bottom. |
| * |
| * @param rec1 |
| * @param rec2 |
| * @param up |
| * @return |
| */ |
| private int getYDistance(Rectangle rec1, Rectangle rec2, boolean top) { |
| if (rec1.getCopy().intersect(rec2).height > 0) { |
| return 0; |
| } |
| if (top) { |
| return rec1.getTop().y - rec2.getTop().y; |
| } |
| return rec1.getBottom().y - rec2.getBottom().y; |
| } |
| } |