/* GNU GENERAL LICENSE Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2017 Lobo Evolution This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either verion 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General License for more details. You should have received a copy of the GNU General Public along with this program. If not, see <http://www.gnu.org/licenses/>. Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it */ package org.lobobrowser.html.renderer; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.util.Iterator; import org.lobobrowser.html.dombl.ModelNode; /** * The Class BaseRCollection. */ public abstract class BaseRCollection extends BaseBoundableRenderable implements RCollection { /** * Instantiates a new base r collection. * * @param container * the container * @param modelNode * the model node */ public BaseRCollection(RenderableContainer container, ModelNode modelNode) { super(container, modelNode); } /* * (non-Javadoc) * @see org.lobobrowser.html.renderer.RCollection#focus() */ @Override public void focus() { this.container.focus(); // TODO: Plus local focus } /* * (non-Javadoc) * @see org.lobobrowser.html.renderer.RCollection#blur() */ @Override public void blur() { RCollection parent = this.parent; if (parent != null) { parent.focus(); } else { // TODO: Remove local focus } } /** * Updates bounds of all descendent's GUI components, based on root bounds. * * @param guiX * the gui x * @param guiY * the gui y */ @Override public void updateWidgetBounds(int guiX, int guiY) { Iterator i = this.getRenderables(); if (i != null) { while (i.hasNext()) { Object r = i.next(); if (r instanceof RCollection) { // RUIControl is a RCollection too. RCollection rc = (RCollection) r; rc.updateWidgetBounds(guiX + rc.getX(), guiY + rc.getY()); } } } } /** * Check start selection. * * @param bounds * the bounds * @param selectionPoint * the selection point * @return true, if successful */ private boolean checkStartSelection(Rectangle bounds, Point selectionPoint) { if (bounds.y > selectionPoint.y) { return true; } else if ((selectionPoint.y >= bounds.y) && (selectionPoint.y < (bounds.y + bounds.height)) && (bounds.x > selectionPoint.x)) { return true; } else { return false; } } /** * Check end selection. * * @param bounds * the bounds * @param selectionPoint * the selection point * @return true, if successful */ private boolean checkEndSelection(Rectangle bounds, Point selectionPoint) { if (bounds.y > selectionPoint.y) { return true; } else if ((selectionPoint.y >= bounds.y) && (selectionPoint.y < (bounds.y + bounds.height)) && (selectionPoint.x < bounds.x)) { return true; } else { return false; } } /* * (non-Javadoc) * @see * org.lobobrowser.html.renderer.BoundableRenderable#paintSelection(java.awt * .Graphics, boolean, org.lobobrowser.html.renderer.RenderableSpot, * org.lobobrowser.html.renderer.RenderableSpot) */ @Override public boolean paintSelection(Graphics g, boolean inSelection, RenderableSpot startPoint, RenderableSpot endPoint) { // TODO: Does this work with renderables that are absolutely positioned? Point checkPoint1 = null; Point checkPoint2 = null; if (!inSelection) { boolean isStart = startPoint.getRenderable() == this; boolean isEnd = endPoint.getRenderable() == this; if (isStart && isEnd) { checkPoint1 = startPoint.getPoint(); checkPoint2 = endPoint.getPoint(); } else if (isStart) { checkPoint1 = startPoint.getPoint(); } else if (isEnd) { checkPoint1 = endPoint.getPoint(); } } else { if (startPoint.getRenderable() == this) { checkPoint1 = startPoint.getPoint(); } else if (endPoint.getRenderable() == this) { checkPoint1 = endPoint.getPoint(); } } Iterator i = this.getRenderables(); if (i != null) { while (i.hasNext()) { Object robj = i.next(); if (robj instanceof BoundableRenderable) { BoundableRenderable renderable = (BoundableRenderable) robj; Rectangle bounds = renderable.getBounds(); if (!inSelection) { if ((checkPoint1 != null) && this.checkStartSelection(bounds, checkPoint1)) { if (checkPoint2 != null) { checkPoint1 = checkPoint2; checkPoint2 = null; } else { checkPoint1 = null; } inSelection = true; } else if ((checkPoint2 != null) && this.checkStartSelection(bounds, checkPoint2)) { checkPoint1 = null; checkPoint2 = null; inSelection = true; } } else if (inSelection && (checkPoint1 != null) && this.checkEndSelection(bounds, checkPoint1)) { return false; } int offsetX = bounds.x; int offsetY = bounds.y; g.translate(offsetX, offsetY); try { boolean newInSelection = renderable.paintSelection(g, inSelection, startPoint, endPoint); if (inSelection && !newInSelection) { return false; } inSelection = newInSelection; } finally { g.translate(-offsetX, -offsetY); } } } } if (inSelection && (checkPoint1 != null)) { return false; } else if (!inSelection && ((checkPoint1 != null) || (checkPoint2 != null)) && !((checkPoint1 != null) && (checkPoint2 != null))) { // Has to have started not being in selection, // but we must start selecting without having // selected anything in the block then. return true; } return inSelection; } /* * (non-Javadoc) * @see * org.lobobrowser.html.renderer.BoundableRenderable#extractSelectionText(java * .lang.StringBuffer, boolean, org.lobobrowser.html.renderer.RenderableSpot, * org.lobobrowser.html.renderer.RenderableSpot) */ @Override public boolean extractSelectionText(StringBuffer buffer, boolean inSelection, RenderableSpot startPoint, RenderableSpot endPoint) { Point checkPoint1 = null; Point checkPoint2 = null; if (!inSelection) { boolean isStart = startPoint.getRenderable() == this; boolean isEnd = endPoint.getRenderable() == this; if (isStart && isEnd) { checkPoint1 = startPoint.getPoint(); checkPoint2 = endPoint.getPoint(); } else if (isStart) { checkPoint1 = startPoint.getPoint(); } else if (isEnd) { checkPoint1 = endPoint.getPoint(); } } else { if (startPoint.getRenderable() == this) { checkPoint1 = startPoint.getPoint(); } else if (endPoint.getRenderable() == this) { checkPoint1 = endPoint.getPoint(); } } Iterator i = this.getRenderables(); if (i != null) { while (i.hasNext()) { Object robj = i.next(); if (robj instanceof BoundableRenderable) { BoundableRenderable renderable = (BoundableRenderable) robj; if (!inSelection) { Rectangle bounds = renderable.getBounds(); if ((checkPoint1 != null) && this.checkStartSelection(bounds, checkPoint1)) { if (checkPoint2 != null) { checkPoint1 = checkPoint2; checkPoint2 = null; } else { checkPoint1 = null; } inSelection = true; } else if ((checkPoint2 != null) && this.checkStartSelection(bounds, checkPoint2)) { checkPoint1 = null; checkPoint2 = null; inSelection = true; } } else if (inSelection && (checkPoint1 != null) && this.checkEndSelection(renderable.getBounds(), checkPoint1)) { return false; } boolean newInSelection = renderable.extractSelectionText( buffer, inSelection, startPoint, endPoint); if (inSelection && !newInSelection) { return false; } inSelection = newInSelection; } } } if (inSelection && (checkPoint1 != null)) { return false; } else if (!inSelection && ((checkPoint1 != null) || (checkPoint2 != null)) && !((checkPoint1 != null) && (checkPoint2 != null))) { // Has to have started not being in selection, // but we must start selecting without having // selected anything in the block then. return true; } return inSelection; } /* * (non-Javadoc) * @see org.lobobrowser.html.renderer.RCollection#invalidateLayoutDeep() */ @Override public void invalidateLayoutDeep() { // TODO: May be pretty inefficient in RLine's // if it's true that non-layable components // are not in RLine's anymore. this.invalidateLayoutLocal(); Iterator renderables = this.getRenderables(); if (renderables != null) { while (renderables.hasNext()) { Object r = renderables.next(); if (r instanceof RCollection) { ((RCollection) r).invalidateLayoutDeep(); } } } } /** The renderable with mouse. */ private BoundableRenderable renderableWithMouse = null; /* * (non-Javadoc) * @see * org.lobobrowser.html.renderer.BaseBoundableRenderable#onMouseMoved(java.awt * .event.MouseEvent, int, int, boolean, org.lobobrowser.html.dombl.ModelNode) */ @Override public void onMouseMoved(MouseEvent event, int x, int y, boolean triggerEvent, ModelNode limit) { super.onMouseMoved(event, x, y, triggerEvent, limit); BoundableRenderable oldRenderable = this.renderableWithMouse; Renderable r = this.getRenderable(x, y); BoundableRenderable newRenderable = r instanceof BoundableRenderable ? (BoundableRenderable) r : null; ModelNode newLimit; if (this.isContainedByNode()) { newLimit = this.modelNode; } else { newLimit = limit; } boolean changed = oldRenderable != newRenderable; if (changed) { if (oldRenderable != null) { oldRenderable.onMouseOut(event, x - oldRenderable.getX(), y - oldRenderable.getY(), newLimit); } this.renderableWithMouse = newRenderable; } // Must recurse always if (newRenderable != null) { newRenderable.onMouseMoved(event, x - newRenderable.getX(), y - newRenderable.getY(), changed, newLimit); } } /* * (non-Javadoc) * @see * org.lobobrowser.html.renderer.BaseBoundableRenderable#onMouseOut(java.awt * .event.MouseEvent, int, int, org.lobobrowser.html.dombl.ModelNode) */ @Override public void onMouseOut(MouseEvent event, int x, int y, ModelNode limit) { super.onMouseOut(event, x, y, limit); BoundableRenderable oldRenderable = this.renderableWithMouse; if (oldRenderable != null) { this.renderableWithMouse = null; ModelNode newLimit; if (this.isContainedByNode()) { newLimit = this.modelNode; } else { newLimit = limit; } oldRenderable.onMouseOut(event, x - oldRenderable.getX(), y - oldRenderable.getY(), newLimit); } } /** * Gets the renderable. * * @param x * the x * @param y * the y * @return the renderable */ public BoundableRenderable getRenderable(int x, int y) { Iterator i = this.getRenderables(); if (i != null) { while (i.hasNext()) { Object r = i.next(); if (r instanceof BoundableRenderable) { BoundableRenderable br = (BoundableRenderable) r; if (br instanceof RBlockViewport) { return br; } int bx = br.getX(); int by = br.getY(); if ((y >= by) && (y < (by + br.getHeight())) && (x >= bx) && (x < (bx + br.getWidth()))) { return br; } } } } return null; } /* * (non-Javadoc) * @see * org.lobobrowser.html.renderer.BoundableRenderable#onRightClick(java.awt.event * .MouseEvent, int, int) */ @Override public boolean onRightClick(MouseEvent event, int x, int y) { BoundableRenderable br = this.getRenderable(x, y); if (br == null) { return HtmlController.getInstance().onContextMenu(this.modelNode, event, x, y); } else { return br.onRightClick(event, x - br.getX(), y - br.getY()); } } }