@Override public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) { int offs = -1; if (!isAllocationValid()) { Rectangle alloc = a.getBounds(); setSize(alloc.width, alloc.height); } // Get the child view for the line at (x,y), and ask it for the // specific offset. Rectangle alloc = getInsideAllocation(a); View v = getViewAtPoint((int) x, (int) y, alloc); if (v != null) { offs = v.viewToModel(x, y, alloc, bias); } // Code folding may have hidden the last line. If so, return the last // visible offset instead of the last offset. if (host.isCodeFoldingEnabled() && v == getView(getViewCount() - 1) && offs == v.getEndOffset() - 1) { offs = host.getLastVisibleOffset(); } return offs; }
/** * Gives notification that something was inserted into the document in a location that this view * is responsible for. This is implemented to simply update the children. * * @param changes The change information from the associated document. * @param a the current allocation of the view * @param f the factory to use to rebuild if the view has children * @see View#insertUpdate */ public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) { updateChildren(changes, a); Rectangle alloc = ((a != null) && isAllocationValid()) ? getInsideAllocation(a) : null; int pos = changes.getOffset(); View v = getViewAtPosition(pos, alloc); if (v != null) v.insertUpdate(changes, alloc, f); }
private boolean contains(View logicalView, View v) { int n = logicalView.getViewCount(); for (int i = 0; i < n; i++) { if (logicalView.getView(i) == v) { return true; } } return false; }
/** * Forwards the <code>DocumentEvent</code> to the give child view. This simply messages the view * with a call to <code>insertUpdate</code>, <code>removeUpdate</code>, or <code>changedUpdate * </code> depending upon the type of the event. This is called by <a * href="#forwardUpdate">forwardUpdate</a> to forward the event to children that need it. * * @param v the child view to forward the event to * @param e the change information from the associated document * @param a the current allocation of the view * @param f the factory to use to rebuild if the view has children * @see #forwardUpdate * @since 1.3 */ protected void forwardUpdateToView(View v, DocumentEvent e, Shape a, ViewFactory f) { DocumentEvent.EventType type = e.getType(); if (type == DocumentEvent.EventType.INSERT) { v.insertUpdate(e, a, f); } else if (type == DocumentEvent.EventType.REMOVE) { v.removeUpdate(e, a, f); } else { v.changedUpdate(e, a, f); } }
/** * Update the flow on the given FlowView. By default, this causes all of the rows (child views) * to be rebuilt to match the given constraints for each row. This is called by a * FlowView.layout to update the child views in the flow. * * @param fv the view to reflow */ public void layout(FlowView fv) { int p0 = fv.getStartOffset(); int p1 = fv.getEndOffset(); // we want to preserve all views from the logicalView from being // removed View lv = getLogicalView(fv); int n = lv.getViewCount(); for (int i = 0; i < n; i++) { View v = lv.getView(i); v.setParent(lv); } fv.removeAll(); for (int rowIndex = 0; p0 < p1; rowIndex++) { View row = fv.createRow(); fv.append(row); // layout the row to the current span. If nothing fits, // force something. int next = layoutRow(fv, rowIndex, p0); if (row.getViewCount() == 0) { row.append(createView(fv, p0, Integer.MAX_VALUE, rowIndex)); next = row.getEndOffset(); } if (next <= p0) { throw new StateInvariantError("infinite loop in formatting"); } else { p0 = next; } } }
private void recursiveReparent(View v, View logicalView) { int n = v.getViewCount(); for (int i = 0; i < n; i++) { View tmpView = v.getView(i); if (contains(logicalView, tmpView)) { tmpView.setParent(logicalView); } else { recursiveReparent(tmpView, logicalView); } } }
/** * Fetches the child view index representing the given position in the model. * * @param pos the position >= 0 * @return index of the view representing the given position, or -1 if no view represents that * position */ protected int getViewIndexAtPosition(int pos) { if (pos >= getStartOffset() && (pos < getEndOffset())) { for (int counter = getViewCount() - 1; counter >= 0; counter--) { View v = getView(counter); if (pos >= v.getStartOffset() && pos < v.getEndOffset()) { return counter; } } } return -1; }
protected void doMoveAirspaceLaterally( WorldWindow wwd, Airspace airspace, Point mousePoint, Point previousMousePoint) { // Intersect a ray throuh each mouse point, with a geoid passing through the reference // elevation. Since // most airspace control points follow a fixed altitude, this will track close to the intended // mouse position. // If either ray fails to intersect the geoid, then ignore this event. Use the difference // between the two // intersected positions to move the control point's location. if (!(airspace instanceof Movable)) { return; } Movable movable = (Movable) airspace; View view = wwd.getView(); Globe globe = wwd.getModel().getGlobe(); Position refPos = movable.getReferencePosition(); if (refPos == null) return; // Convert the reference position into a cartesian point. This assumes that the reference // elevation is defined // by the airspace's lower altitude. Vec4 refPoint = null; if (airspace.isTerrainConforming()[LOWER_ALTITUDE]) refPoint = wwd.getSceneController().getTerrain().getSurfacePoint(refPos); if (refPoint == null) refPoint = globe.computePointFromPosition(refPos); // Convert back to a position. refPos = globe.computePositionFromPoint(refPoint); Line ray = view.computeRayFromScreenPoint(mousePoint.getX(), mousePoint.getY()); Line previousRay = view.computeRayFromScreenPoint(previousMousePoint.getX(), previousMousePoint.getY()); Vec4 vec = AirspaceEditorUtil.intersectGlobeAt(wwd, refPos.getElevation(), ray); Vec4 previousVec = AirspaceEditorUtil.intersectGlobeAt(wwd, refPos.getElevation(), previousRay); if (vec == null || previousVec == null) { return; } Position pos = globe.computePositionFromPoint(vec); Position previousPos = globe.computePositionFromPoint(previousVec); LatLon change = pos.subtract(previousPos); movable.move(new Position(change.getLatitude(), change.getLongitude(), 0.0)); this.fireAirspaceMoved(new AirspaceEditEvent(wwd, airspace, this)); }
/** * Determines the preferred span for this view along an axis. * * @param axis may be either View.X_AXIS or View.Y_AXIS * @return the span the view would like to be rendered into. Typically the view is told to * render into the span that is returned, although there is no guarantee. The parent may * choose to resize or break the view. * @see View#getPreferredSpan */ public float getPreferredSpan(int axis) { float maxpref = 0; float pref = 0; int n = getViewCount(); for (int i = 0; i < n; i++) { View v = getView(i); pref += v.getPreferredSpan(axis); if (v.getBreakWeight(axis, 0, Short.MAX_VALUE) >= ForcedBreakWeight) { maxpref = Math.max(maxpref, pref); pref = 0; } } maxpref = Math.max(maxpref, pref); return maxpref; }
/** * Forwards the given <code>DocumentEvent</code> to the child views that need to be notified of * the change to the model. If there were changes to the element this view is responsible for, * that should be considered when forwarding (i.e. new child views should not get notified). * * @param ec changes to the element this view is responsible for (may be <code>null</code> if * there were no changes). * @param e the change information from the associated document * @param a the current allocation of the view * @param f the factory to use to rebuild if the view has children * @see #insertUpdate * @see #removeUpdate * @see #changedUpdate * @since 1.3 */ protected void forwardUpdate( DocumentEvent.ElementChange ec, DocumentEvent e, Shape a, ViewFactory f) { Element elem = getElement(); int pos = e.getOffset(); int index0 = getViewIndex(pos, Position.Bias.Forward); if (index0 == -1 && e.getType() == DocumentEvent.EventType.REMOVE && pos >= getEndOffset()) { // Event beyond our offsets. We may have represented this, that is // the remove may have removed one of our child Elements that // represented this, so, we should foward to last element. index0 = getViewCount() - 1; } int index1 = index0; View v = (index0 >= 0) ? getView(index0) : null; if (v != null) { if ((v.getStartOffset() == pos) && (pos > 0)) { // If v is at a boundary, forward the event to the previous // view too. index0 = Math.max(index0 - 1, 0); } } if (e.getType() != DocumentEvent.EventType.REMOVE) { index1 = getViewIndex(pos + e.getLength(), Position.Bias.Forward); if (index1 < 0) { index1 = getViewCount() - 1; } } int hole0 = index1 + 1; int hole1 = hole0; Element[] addedElems = (ec != null) ? ec.getChildrenAdded() : null; if ((addedElems != null) && (addedElems.length > 0)) { hole0 = ec.getIndex(); hole1 = hole0 + addedElems.length - 1; } // forward to any view not in the forwarding hole // formed by added elements (i.e. they will be updated // by initialization. index0 = Math.max(index0, 0); for (int i = index0; i <= index1; i++) { if (!((i >= hole0) && (i <= hole1))) { v = getView(i); if (v != null) { Shape childAlloc = getChildAllocation(i, a); forwardUpdateToView(v, e, childAlloc, f); } } } }
/** * Sets the parent of the view. This is reimplemented to provide the superclass behavior as well * as calling the <code>loadChildren</code> method if this view does not already have children. * The children should not be loaded in the constructor because the act of setting the parent may * cause them to try to search up the hierarchy (to get the hosting <code>Container</code> for * example). If this view has children (the view is being moved from one place in the view * hierarchy to another), the <code>loadChildren</code> method will not be called. * * @param parent the parent of the view, <code>null</code> if none */ public void setParent(View parent) { super.setParent(parent); if ((parent != null) && (nchildren == 0)) { ViewFactory f = getViewFactory(); loadChildren(f); } }
/** * Establishes the parent view for this view. Seize this moment to cache the AWT Container I'm in. */ public void setParent(View parent) { super.setParent(parent); fContainer = parent != null ? getContainer() : null; if (parent == null && fComponent != null) { fComponent.getParent().remove(fComponent); fComponent = null; } }
/** * Determines the minimum span for this view along an axis. The is implemented to find the * minimum unbreakable span. * * @param axis may be either View.X_AXIS or View.Y_AXIS * @return the span the view would like to be rendered into. Typically the view is told to * render into the span that is returned, although there is no guarantee. The parent may * choose to resize or break the view. * @see View#getPreferredSpan */ public float getMinimumSpan(int axis) { float maxmin = 0; float min = 0; boolean nowrap = false; int n = getViewCount(); for (int i = 0; i < n; i++) { View v = getView(i); if (v.getBreakWeight(axis, 0, Short.MAX_VALUE) == BadBreakWeight) { min += v.getPreferredSpan(axis); nowrap = true; } else if (nowrap) { maxmin = Math.max(min, maxmin); nowrap = false; min = 0; } } maxmin = Math.max(maxmin, min); return maxmin; }
/** * Provides a mapping from the document model coordinate space to the coordinate space of the view * mapped to it. * * @param pos the position to convert >= 0 * @param a the allocated region to render into * @param b a bias value of either <code>Position.Bias.Forward</code> or <code> * Position.Bias.Backward</code> * @return the bounding box of the given position * @exception BadLocationException if the given position does not represent a valid location in * the associated document * @see View#modelToView */ public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { boolean isBackward = (b == Position.Bias.Backward); int testPos = (isBackward) ? Math.max(0, pos - 1) : pos; if (isBackward && testPos < getStartOffset()) { return null; } int vIndex = getViewIndexAtPosition(testPos); if ((vIndex != -1) && (vIndex < getViewCount())) { View v = getView(vIndex); if (v != null && testPos >= v.getStartOffset() && testPos < v.getEndOffset()) { Shape childShape = getChildAllocation(vIndex, a); if (childShape == null) { // We are likely invalid, fail. return null; } Shape retShape = v.modelToView(pos, childShape, b); if (retShape == null && v.getEndOffset() == pos) { if (++vIndex < getViewCount()) { v = getView(vIndex); retShape = v.modelToView(pos, getChildAllocation(vIndex, a), b); } } return retShape; } } throw new BadLocationException("Position not represented by view", pos); }
/** * Provides a mapping from the view coordinate space to the logical coordinate space of the model. * * @param x x coordinate of the view location to convert >= 0 * @param y y coordinate of the view location to convert >= 0 * @param a the allocated region to render into * @param bias either <code>Position.Bias.Forward</code> or <code>Position.Bias.Backward</code> * @return the location within the model that best represents the given point in the view >= 0 * @see View#viewToModel */ public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) { Rectangle alloc = getInsideAllocation(a); if (isBefore((int) x, (int) y, alloc)) { // point is before the range represented int retValue = -1; try { retValue = getNextVisualPositionFrom(-1, Position.Bias.Forward, a, EAST, bias); } catch (BadLocationException ble) { } catch (IllegalArgumentException iae) { } if (retValue == -1) { retValue = getStartOffset(); bias[0] = Position.Bias.Forward; } return retValue; } else if (isAfter((int) x, (int) y, alloc)) { // point is after the range represented. int retValue = -1; try { retValue = getNextVisualPositionFrom(-1, Position.Bias.Forward, a, WEST, bias); } catch (BadLocationException ble) { } catch (IllegalArgumentException iae) { } if (retValue == -1) { // NOTE: this could actually use end offset with backward. retValue = getEndOffset() - 1; bias[0] = Position.Bias.Forward; } return retValue; } else { // locate the child and pass along the request View v = getViewAtPoint((int) x, (int) y, alloc); if (v != null) { return v.viewToModel(x, y, alloc, bias); } } return -1; }
/** * Lays out the children. If the span along the flow axis has changed, layout is marked as invalid * which which will cause the superclass behavior to recalculate the layout along the box axis. * The FlowStrategy.layout method will be called to rebuild the flow rows as appropriate. If the * height of this view changes (determined by the perferred size along the box axis), a * preferenceChanged is called. Following all of that, the normal box layout of the superclass is * performed. * * @param width the width to lay out against >= 0. This is the width inside of the inset area. * @param height the height to lay out against >= 0 This is the height inside of the inset area. */ protected void layout(int width, int height) { final int faxis = getFlowAxis(); int newSpan; if (faxis == X_AXIS) { newSpan = (int) width; } else { newSpan = (int) height; } if (layoutSpan != newSpan) { layoutChanged(faxis); layoutChanged(getAxis()); layoutSpan = newSpan; } // repair the flow if necessary if (!isLayoutValid(faxis)) { final int heightAxis = getAxis(); int oldFlowHeight = (int) ((heightAxis == X_AXIS) ? getWidth() : getHeight()); strategy.layout(this); int newFlowHeight = (int) getPreferredSpan(heightAxis); if (oldFlowHeight != newFlowHeight) { View p = getParent(); if (p != null) { p.preferenceChanged(this, (heightAxis == X_AXIS), (heightAxis == Y_AXIS)); } // PENDING(shannonh) // Temporary fix for 4250847 // Can be removed when TraversalContext is added Component host = getContainer(); if (host != null) { // nb idk 12/12/2001 host should not be equal to null. We need to add assertion here host.repaint(); } } } super.layout(width, height); }
/** * Creates a view that can be used to represent the current piece of the flow. This can be * either an entire view from the logical view, or a fragment of the logical view. * * @param fv the view holding the flow * @param startOffset the start location for the view being created * @param spanLeft the about of span left to fill in the row * @param rowIndex the row the view will be placed into */ protected View createView(FlowView fv, int startOffset, int spanLeft, int rowIndex) { // Get the child view that contains the given starting position View lv = getLogicalView(fv); int childIndex = lv.getViewIndex(startOffset, Position.Bias.Forward); View v = lv.getView(childIndex); if (startOffset == v.getStartOffset()) { // return the entire view return v; } // return a fragment. v = v.createFragment(startOffset, v.getEndOffset()); return v; }
/** My attributes may have changed. */ public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) { if (DEBUG) System.out.println("ImageView: changedUpdate begin..."); super.changedUpdate(e, a, f); float align = getVerticalAlignment(); int height = fHeight; int width = fWidth; initialize(getElement()); boolean hChanged = fHeight != height; boolean wChanged = fWidth != width; if (hChanged || wChanged || getVerticalAlignment() != align) { if (DEBUG) System.out.println("ImageView: calling preferenceChanged"); getParent().preferenceChanged(this, hChanged, wChanged); } if (DEBUG) System.out.println("ImageView: changedUpdate end; valign=" + getVerticalAlignment()); }
/** * Provides a mapping from the document model coordinate space to the coordinate space of the view * mapped to it. * * @param p0 the position to convert >= 0 * @param b0 the bias toward the previous character or the next character represented by p0, in * case the position is a boundary of two views; either <code>Position.Bias.Forward</code> or * <code>Position.Bias.Backward</code> * @param p1 the position to convert >= 0 * @param b1 the bias toward the previous character or the next character represented by p1, in * case the position is a boundary of two views * @param a the allocated region to render into * @return the bounding box of the given position is returned * @exception BadLocationException if the given position does not represent a valid location in * the associated document * @exception IllegalArgumentException for an invalid bias argument * @see View#viewToModel */ public Shape modelToView(int p0, Position.Bias b0, int p1, Position.Bias b1, Shape a) throws BadLocationException { if (p0 == getStartOffset() && p1 == getEndOffset()) { return a; } Rectangle alloc = getInsideAllocation(a); Rectangle r0 = new Rectangle(alloc); View v0 = getViewAtPosition((b0 == Position.Bias.Backward) ? Math.max(0, p0 - 1) : p0, r0); Rectangle r1 = new Rectangle(alloc); View v1 = getViewAtPosition((b1 == Position.Bias.Backward) ? Math.max(0, p1 - 1) : p1, r1); if (v0 == v1) { if (v0 == null) { return a; } // Range contained in one view return v0.modelToView(p0, b0, p1, b1, r0); } // Straddles some views. int viewCount = getViewCount(); int counter = 0; while (counter < viewCount) { View v; // Views may not be in same order as model. // v0 or v1 may be null if there is a gap in the range this // view contains. if ((v = getView(counter)) == v0 || v == v1) { View endView; Rectangle retRect; Rectangle tempRect = new Rectangle(); if (v == v0) { retRect = v0.modelToView(p0, b0, v0.getEndOffset(), Position.Bias.Backward, r0).getBounds(); endView = v1; } else { retRect = v1.modelToView(v1.getStartOffset(), Position.Bias.Forward, p1, b1, r1).getBounds(); endView = v0; } // Views entirely covered by range. while (++counter < viewCount && (v = getView(counter)) != endView) { tempRect.setBounds(alloc); childAllocation(counter, tempRect); retRect.add(tempRect); } // End view. if (endView != null) { Shape endShape; if (endView == v1) { endShape = v1.modelToView(v1.getStartOffset(), Position.Bias.Forward, p1, b1, r1); } else { endShape = v0.modelToView(p0, b0, v0.getEndOffset(), Position.Bias.Backward, r0); } if (endShape instanceof Rectangle) { retRect.add((Rectangle) endShape); } else { retRect.add(endShape.getBounds()); } } return retRect; } counter++; } throw new BadLocationException("Position not represented by view", p0); }
/** * Creates a row of views that will fit within the layout span of the row. This is called by the * layout method. This is implemented to fill the row by repeatedly calling the createView * method until the available span has been exhausted, a forced break was encountered, or the * createView method returned null. If the remaining span was exhaused, the adjustRow method * will be called to perform adjustments to the row to try and make it fit into the given span. * * @param rowIndex the index of the row to fill in with views. The row is assumed to be empty on * entry. * @param pos The current position in the children of this views element from which to start. * @return the position to start the next row */ protected int layoutRow(FlowView fv, int rowIndex, int pos) { View row = fv.getView(rowIndex); int x = fv.getFlowStart(rowIndex); int spanLeft = fv.getFlowSpan(rowIndex); int end = fv.getEndOffset(); TabExpander te = (fv instanceof TabExpander) ? (TabExpander) fv : null; // Indentation. int preX = x; int availableSpan = spanLeft; preX = x; final int flowAxis = fv.getFlowAxis(); boolean forcedBreak = false; while (pos < end && spanLeft > 0) { View v = createView(fv, pos, spanLeft, rowIndex); if (v == null) { break; } int chunkSpan; if ((flowAxis == X_AXIS) && (v instanceof TabableView)) { chunkSpan = (int) ((TabableView) v).getTabbedSpan(x, te); } else { chunkSpan = (int) v.getPreferredSpan(flowAxis); } // If a forced break is necessary, break if (v.getBreakWeight(flowAxis, pos, spanLeft) >= ForcedBreakWeight) { int n = row.getViewCount(); if (n > 0) { /* If this is a forced break and it's not the only view * the view should be replaced with a call to breakView. * If it's it only view, it should be used directly. In * either case no more children should be added beyond this * view. */ v = v.breakView(flowAxis, pos, x, spanLeft); if (v != null) { if ((flowAxis == X_AXIS) && (v instanceof TabableView)) { chunkSpan = (int) ((TabableView) v).getTabbedSpan(x, te); } else { chunkSpan = (int) v.getPreferredSpan(flowAxis); } } else { chunkSpan = 0; } } forcedBreak = true; } spanLeft -= chunkSpan; x += chunkSpan; if (v != null) { row.append(v); pos = v.getEndOffset(); } if (forcedBreak) { break; } } if (spanLeft < 0) { // This row is too long and needs to be adjusted. adjustRow(fv, rowIndex, availableSpan, preX); } else if (row.getViewCount() == 0) { // Impossible spec... put in whatever is left. View v = createView(fv, pos, Integer.MAX_VALUE, rowIndex); row.append(v); } return row.getEndOffset(); }
/** * Draws a single view (i.e., a line of text for a wrapped view), wrapping the text onto multiple * lines if necessary. Any selected text is rendered with the editor's "selected text" color. * * @param painter The painter to use to render tokens. * @param g The graphics context in which to paint. * @param r The rectangle in which to paint. * @param view The <code>View</code> to paint. * @param fontHeight The height of the font being used. * @param y The y-coordinate at which to begin painting. * @param selStart The start of the selection. * @param selEnd The end of the selection. */ protected void drawViewWithSelection( TokenPainter painter, Graphics2D g, Rectangle r, View view, int fontHeight, int y, int selStart, int selEnd) { float x = r.x; LayeredHighlighter h = (LayeredHighlighter) host.getHighlighter(); RSyntaxDocument document = (RSyntaxDocument) getDocument(); Element map = getElement(); int p0 = view.getStartOffset(); int lineNumber = map.getElementIndex(p0); int p1 = view.getEndOffset(); // - 1; setSegment(p0, p1 - 1, document, drawSeg); // System.err.println("drawSeg=='" + drawSeg + "' (p0/p1==" + p0 + "/" + p1 + ")"); int start = p0 - drawSeg.offset; Token token = document.getTokenListForLine(lineNumber); // If this line is an empty line, then the token list is simply a // null token. In this case, the line highlight will be skipped in // the loop below, so unfortunately we must manually do it here. if (token != null && token.getType() == Token.NULL) { h.paintLayeredHighlights(g, p0, p1, r, host, this); return; } // Loop through all tokens in this view and paint them! while (token != null && token.isPaintable()) { int p = calculateBreakPosition(p0, token, x); x = r.x; h.paintLayeredHighlights(g, p0, p, r, host, this); while (token != null && token.isPaintable() && token.getEndOffset() - 1 < p) { // <=p) { // Selection starts in this token if (token.containsPosition(selStart)) { if (selStart > token.getOffset()) { tempToken.copyFrom(token); tempToken.textCount = selStart - tempToken.getOffset(); x = painter.paint(tempToken, g, x, y, host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(selStart); // Clone required since token and tempToken must be // different tokens for else statement below token = new TokenImpl(tempToken); } int selCount = Math.min(token.length(), selEnd - token.getOffset()); if (selCount == token.length()) { x = painter.paintSelected(token, g, x, y, host, this); } else { tempToken.copyFrom(token); tempToken.textCount = selCount; x = painter.paintSelected(tempToken, g, x, y, host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(token.getOffset() + selCount); token = tempToken; x = painter.paint(token, g, x, y, host, this); } } // Selection ends in this token else if (token.containsPosition(selEnd)) { tempToken.copyFrom(token); tempToken.textCount = selEnd - tempToken.getOffset(); x = painter.paintSelected(tempToken, g, x, y, host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(selEnd); token = tempToken; x = painter.paint(token, g, x, y, host, this); } // This token is entirely selected else if (token.getOffset() >= selStart && token.getEndOffset() <= selEnd) { x = painter.paintSelected(token, g, x, y, host, this); } // This token is entirely unselected else { x = painter.paint(token, g, x, y, host, this); } token = token.getNextToken(); } // If there's a token that's going to be split onto the next line if (token != null && token.isPaintable() && token.getOffset() < p) { int tokenOffset = token.getOffset(); Token orig = token; token = new TokenImpl( drawSeg, tokenOffset - start, p - 1 - start, tokenOffset, token.getType()); // Selection starts in this token if (token.containsPosition(selStart)) { if (selStart > token.getOffset()) { tempToken.copyFrom(token); tempToken.textCount = selStart - tempToken.getOffset(); x = painter.paint(tempToken, g, x, y, host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(selStart); // Clone required since token and tempToken must be // different tokens for else statement below token = new TokenImpl(tempToken); } int selCount = Math.min(token.length(), selEnd - token.getOffset()); if (selCount == token.length()) { x = painter.paintSelected(token, g, x, y, host, this); } else { tempToken.copyFrom(token); tempToken.textCount = selCount; x = painter.paintSelected(tempToken, g, x, y, host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(token.getOffset() + selCount); token = tempToken; x = painter.paint(token, g, x, y, host, this); } } // Selection ends in this token else if (token.containsPosition(selEnd)) { tempToken.copyFrom(token); tempToken.textCount = selEnd - tempToken.getOffset(); x = painter.paintSelected(tempToken, g, x, y, host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(selEnd); token = tempToken; x = painter.paint(token, g, x, y, host, this); } // This token is entirely selected else if (token.getOffset() >= selStart && token.getEndOffset() <= selEnd) { x = painter.paintSelected(token, g, x, y, host, this); } // This token is entirely unselected else { x = painter.paint(token, g, x, y, host, this); } token = new TokenImpl(orig); ((TokenImpl) token).makeStartAt(p); } p0 = (p == p0) ? p1 : p; y += fontHeight; } // End of while (token!=null && token.isPaintable()). // NOTE: We should re-use code from Token (paintBackground()) here, // but don't because I'm just too lazy. if (host.getEOLMarkersVisible()) { g.setColor(host.getForegroundForTokenType(Token.WHITESPACE)); g.setFont(host.getFontForTokenType(Token.WHITESPACE)); g.drawString("\u00B6", x, y - fontHeight); } }
/** * Draws a single view (i.e., a line of text for a wrapped view), wrapping the text onto multiple * lines if necessary. * * @param painter The painter to use to render tokens. * @param g The graphics context in which to paint. * @param r The rectangle in which to paint. * @param view The <code>View</code> to paint. * @param fontHeight The height of the font being used. * @param y The y-coordinate at which to begin painting. */ protected void drawView( TokenPainter painter, Graphics2D g, Rectangle r, View view, int fontHeight, int y) { float x = r.x; LayeredHighlighter h = (LayeredHighlighter) host.getHighlighter(); RSyntaxDocument document = (RSyntaxDocument) getDocument(); Element map = getElement(); int p0 = view.getStartOffset(); int lineNumber = map.getElementIndex(p0); int p1 = view.getEndOffset(); // - 1; setSegment(p0, p1 - 1, document, drawSeg); // System.err.println("drawSeg=='" + drawSeg + "' (p0/p1==" + p0 + "/" + p1 + ")"); int start = p0 - drawSeg.offset; Token token = document.getTokenListForLine(lineNumber); // If this line is an empty line, then the token list is simply a // null token. In this case, the line highlight will be skipped in // the loop below, so unfortunately we must manually do it here. if (token != null && token.getType() == Token.NULL) { h.paintLayeredHighlights(g, p0, p1, r, host, this); return; } // Loop through all tokens in this view and paint them! while (token != null && token.isPaintable()) { int p = calculateBreakPosition(p0, token, x); x = r.x; h.paintLayeredHighlights(g, p0, p, r, host, this); while (token != null && token.isPaintable() && token.getEndOffset() - 1 < p) { // <=p) { x = painter.paint(token, g, x, y, host, this); token = token.getNextToken(); } if (token != null && token.isPaintable() && token.getOffset() < p) { int tokenOffset = token.getOffset(); tempToken.set( drawSeg.array, tokenOffset - start, p - 1 - start, tokenOffset, token.getType()); painter.paint(tempToken, g, x, y, host, this); tempToken.copyFrom(token); tempToken.makeStartAt(p); token = new TokenImpl(tempToken); } p0 = (p == p0) ? p1 : p; y += fontHeight; } // End of while (token!=null && token.isPaintable()). // NOTE: We should re-use code from Token (paintBackground()) here, // but don't because I'm just too lazy. if (host.getEOLMarkersVisible()) { g.setColor(host.getForegroundForTokenType(Token.WHITESPACE)); g.setFont(host.getFontForTokenType(Token.WHITESPACE)); g.drawString("\u00B6", x, y - fontHeight); } }
/** * Forward the DocumentEvent to the given child view. This is implemented to reparent the child * to the logical view (the children may have been parented by a row in the flow if they fit * without breaking) and then execute the superclass behavior. * * @param v the child view to forward the event to. * @param e the change information from the associated document * @param a the current allocation of the view * @param f the factory to use to rebuild if the view has children * @see #forwardUpdate * @since 1.3 */ protected void forwardUpdateToView(View v, DocumentEvent e, Shape a, ViewFactory f) { v.setParent(this); super.forwardUpdateToView(v, e, a, f); }
/** * Fetches the <code>ViewFactory</code> implementation that is feeding the view hierarchy. * Normally the views are given this as an argument to updates from the model when they are most * likely to need the factory, but this method serves to provide it at other times. * * @return the factory, <code>null</code> if none */ public ViewFactory getViewFactory() { View v = getParent(); return (v != null) ? v.getViewFactory() : null; }
/** * Fetches the container hosting the view. This is useful for things like scheduling a repaint, * finding out the host components font, etc. The default implementation of this is to forward the * query to the parent view. * * @return the container, <code>null</code> if none */ public Container getContainer() { View v = getParent(); return (v != null) ? v.getContainer() : null; }
/** * Child views can call this on the parent to indicate that the preference has changed and should * be reconsidered for layout. By default this just propagates upward to the next parent. The root * view will call <code>revalidate</code> on the associated text component. * * @param child the child view * @param width true if the width preference has changed * @param height true if the height preference has changed * @see javax.swing.JComponent#revalidate */ public void preferenceChanged(View child, boolean width, boolean height) { View parent = getParent(); if (parent != null) { parent.preferenceChanged(this, width, height); } }
private void invoke() { String cmd; if (popup != null) cmd = popup.list.getSelectedValue().toString(); else { cmd = action.getText().trim(); int index = cmd.indexOf('='); if (index != -1) { action.addCurrentToHistory(); String propName = cmd.substring(0, index).trim(); String propValue = cmd.substring(index + 1).trim(); String code; if (propName.startsWith("buffer.")) { if (propName.equals("buffer.mode")) { code = "buffer.setMode(\"" + MiscUtilities.charsToEscapes(propValue) + "\");"; } else { code = "buffer.setStringProperty(\"" + MiscUtilities.charsToEscapes(propName.substring("buffer.".length())) + "\",\"" + MiscUtilities.charsToEscapes(propValue) + "\");"; } code += "\nbuffer.propertiesChanged();"; } else if (propName.startsWith("!buffer.")) { code = "jEdit.setProperty(\"" + MiscUtilities.charsToEscapes(propName.substring(1)) + "\",\"" + MiscUtilities.charsToEscapes(propValue) + "\");\n" + "jEdit.propertiesChanged();"; } else { code = "jEdit.setProperty(\"" + MiscUtilities.charsToEscapes(propName) + "\",\"" + MiscUtilities.charsToEscapes(propValue) + "\");\n" + "jEdit.propertiesChanged();"; } Macros.Recorder recorder = view.getMacroRecorder(); if (recorder != null) recorder.record(code); BeanShell.eval(view, namespace, code); cmd = null; } else if (cmd.length() != 0) { String[] completions = getCompletions(cmd); if (completions.length != 0) { cmd = completions[0]; } } else cmd = null; } if (popup != null) { popup.dispose(); popup = null; } final String finalCmd = cmd; final EditAction act = (finalCmd == null ? null : jEdit.getAction(finalCmd)); if (temp) view.removeToolBar(this); SwingUtilities.invokeLater( new Runnable() { public void run() { view.getTextArea().requestFocus(); if (act == null) { if (finalCmd != null) { view.getStatus() .setMessageAndClear(jEdit.getProperty("view.action.no-completions")); } } else { view.getInputHandler().setRepeatCount(repeatCount); view.getInputHandler().invokeAction(act); } } }); }
/** * Fetches the attributes to use when rendering. This view isn't directly responsible for an * element so it returns the outer classes attributes. */ public AttributeSet getAttributes() { View p = getParent(); return (p != null) ? p.getAttributes() : null; }
@Override public void setSize(float width, float height) { super.setSize(width, height); updateMetrics(); }
/** * Adjusts the given row if possible to fit within the layout span. By default this will try to * find the highest break weight possible nearest the end of the row. If a forced break is * encountered, the break will be positioned there. * * @param rowIndex the row to adjust to the current layout span. * @param desiredSpan the current layout span >= 0 * @param x the location r starts at. */ protected void adjustRow(FlowView fv, int rowIndex, int desiredSpan, int x) { final int flowAxis = fv.getFlowAxis(); View r = fv.getView(rowIndex); int n = r.getViewCount(); int span = 0; int bestWeight = BadBreakWeight; int bestSpan = 0; int bestIndex = -1; int bestOffset = 0; View v; for (int i = 0; i < n; i++) { v = r.getView(i); int spanLeft = desiredSpan - span; int w = v.getBreakWeight(flowAxis, x + span, spanLeft); if ((w >= bestWeight) && (w > BadBreakWeight)) { bestWeight = w; bestIndex = i; bestSpan = span; if (w >= ForcedBreakWeight) { // it's a forced break, so there is // no point in searching further. break; } } span += v.getPreferredSpan(flowAxis); } if (bestIndex < 0) { // there is nothing that can be broken, leave // it in it's current state. return; } // Break the best candidate view, and patch up the row. int spanLeft = desiredSpan - bestSpan; v = r.getView(bestIndex); v = v.breakView(flowAxis, v.getStartOffset(), x + bestSpan, spanLeft); View[] va = new View[1]; va[0] = v; View lv = getLogicalView(fv); for (int i = bestIndex; i < n; i++) { View tmpView = r.getView(i); if (contains(lv, tmpView)) { tmpView.setParent(lv); } else if (tmpView.getViewCount() > 0) { recursiveReparent(tmpView, lv); } } r.replace(bestIndex, n - bestIndex, va); }