alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.editor;

import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import javax.swing.JComponent;
import javax.swing.event.DocumentEvent;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import javax.swing.text.Position;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import org.netbeans.editor.ext.ExtEditorUI;
import org.netbeans.editor.ext.ToolTipSupport;
import org.netbeans.editor.view.spi.LockView;

/**
 * View over collapsed area of the fold.
 * 
* The collapsed area spans one or more lines and it is presented as three dots. * * @author Martin Roskanin */ class CollapsedView extends View implements SettingsChangeListener { private Position startPos; private Position endPos; private String foldDescription; private Font font; private Color foreColor; private Color backColor; /** Creates a new instance of CollapsedView */ public CollapsedView(Element elem, Position startPos, Position endPos, String foldDescription) { super(elem); this.startPos = startPos; this.endPos = endPos; this.foldDescription = foldDescription; Settings.addSettingsChangeListener(this); } private JTextComponent getComponent() { return (JTextComponent)getContainer(); } private BaseTextUI getBaseTextUI(){ JTextComponent comp = getComponent(); return (comp!=null)?(BaseTextUI)comp.getUI():null; } private EditorUI getEditorUI(){ BaseTextUI btui = getBaseTextUI(); return (btui!=null) ? btui.getEditorUI() : null; } public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) { } public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) { } public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) { } public Document getDocument() { View parent = getParent(); return (parent == null) ? null : parent.getDocument(); } public int getStartOffset() { return startPos.getOffset(); } public int getEndOffset() { return endPos.getOffset(); } protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e, Shape a, ViewFactory f) { } protected void forwardUpdateToView(View v, DocumentEvent e, Shape a, ViewFactory f) { } public float getAlignment(int axis) { return 0f; } public float getPreferredSpan(int axis){ switch (axis) { case Y_AXIS: return getEditorUI().getLineHeight(); case X_AXIS: return getCollapsedFoldStringWidth(); } return 1f; } private int getCollapsedFoldStringWidth() { JTextComponent comp = getComponent(); if (comp==null) return 0; FontMetrics fm = FontMetricsCache.getFontMetrics(getColoringFont(), comp); if (fm==null) return 0; return fm.stringWidth(foldDescription); } public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { return new Rectangle(a.getBounds().x, a.getBounds().y, getCollapsedFoldStringWidth(), getEditorUI().getLineHeight()); } public int viewToModel(float x, float y, Shape a, Position.Bias[] biasReturn) { return getStartOffset(); } public void paint(Graphics g, Shape allocation){ Rectangle allocRect = allocation.getBounds(); g.setColor(getBackColor()); int x = allocRect.x+2; int y = allocRect.y; int width = allocRect.width-1; int height = allocRect.height-1; g.fillRect(x, y, width, height); g.setColor(getForeColor()); g.setFont(getColoringFont()); g.drawRect(x, y, width, height); g.drawString(foldDescription, x, y + getEditorUI().getLineAscent()-1); } public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, int direction, Position.Bias[] biasRet) throws BadLocationException { biasRet[0] = Position.Bias.Forward; switch (direction) { case NORTH: case SOUTH: { JTextComponent target = (JTextComponent) getContainer(); Caret c = (target != null) ? target.getCaret() : null; // YECK! Ideally, the x location from the magic caret position // would be passed in. Point mcp; if (c != null) { mcp = c.getMagicCaretPosition(); } else { mcp = null; } int x; if (mcp == null) { Rectangle loc = target.modelToView(pos); x = (loc == null) ? 0 : loc.x; } else { x = mcp.x; } if (direction == NORTH) { pos = Utilities.getPositionAbove(target, pos, x); } else { pos = Utilities.getPositionBelow(target, pos, x); } } break; case WEST: if(pos == -1) { pos = Math.max(0, getStartOffset()); } else { if (b == Position.Bias.Backward){ pos = Math.max(0, getStartOffset()); }else{ pos = Math.max(0, getStartOffset() - 1); } } break; case EAST: if(pos == -1) { pos = getStartOffset(); } else { pos = Math.min(getEndOffset(), getDocument().getLength()); //JTextComponent target = (JTextComponent) getContainer(); //if (target!=null && Utilities.getRowEnd(target, pos) == pos) pos = Math.min(pos+1, getDocument().getLength()); } break; default: throw new IllegalArgumentException("Bad direction: " + direction); // NOI18N } return pos; } private View getExpandedView(){ Element parentElem = getElement().getParentElement(); int sei = parentElem.getElementIndex(getStartOffset()); int so = parentElem.getElement(sei).getStartOffset(); int eei = parentElem.getElementIndex(getEndOffset()); int eo = parentElem.getElement(eei).getEndOffset(); LockView fakeView = new LockView( new DrawEngineFakeDocView(parentElem, so, eo, false) ); RootView rootView = new RootView(); rootView.setView(fakeView); return fakeView; } public String getToolTipText(float x, float y, Shape allocation){ ToolTipSupport tts = ((ExtEditorUI)getEditorUI()).getToolTipSupport(); JComponent toolTip = new FoldingToolTip(getExpandedView(), getEditorUI()); tts.setToolTip(toolTip, PopupManager.ScrollBarBounds, PopupManager.BelowPreferred, -FoldingToolTip.BORDER_WIDTH, 0); return ""; } public void settingsChange(SettingsChangeEvent evt) { if (evt == null || org.netbeans.editor.Utilities.getKitClass(getComponent()) != evt.getKitClass()) return; String defaultColoringName = SettingsNames.DEFAULT_COLORING+SettingsNames.COLORING_NAME_SUFFIX; String foldingColoringName = SettingsNames.CODE_FOLDING_COLORING+SettingsNames.COLORING_NAME_SUFFIX; EditorUI editorUI = getEditorUI(); if (editorUI==null) return; Coloring foldingColoring = editorUI.getColoring(SettingsNames.CODE_FOLDING_COLORING); Coloring defaultColoring = editorUI.getDefaultColoring(); Font foldingFont = null; Color foldingForeColor = null; Color foldingBackColor = null; if (foldingColoring!=null){ foldingFont = foldingColoring.getFont(); foldingForeColor = foldingColoring.getForeColor(); foldingBackColor = foldingColoring.getBackColor(); } if (defaultColoringName.equals(evt.getSettingName())){ if (foldingForeColor == null){ // inherited fore color Color tempColor = getDefaultForeColor(); if (!tempColor.equals(foreColor)){ foreColor = tempColor; } } if (foldingBackColor == null){ // inherited back color Color tempColor = getDefaultBackColor(); if (!tempColor.equals(backColor)){ backColor = tempColor; } } // Font size change Font tempFont = getDefaultColoringFont(); if (!tempFont.equals(font) && foldingFont==null){ // if different font and foldingFont is inherited font = tempFont; //setPreferredSize(new Dimension(font.getSize(), component.getHeight())); } //repaint(); }else if (foldingColoringName.equals(evt.getSettingName())){ // Code folding coloring change if (foldingColoring == null) return; Color tempColor = foldingColoring.getForeColor(); foreColor = (tempColor!=null) ? tempColor : getDefaultForeColor(); tempColor = foldingColoring.getBackColor(); backColor = (tempColor!=null) ? tempColor : getDefaultBackColor(); if (foldingFont == null){ //inherit Font tempFont = getDefaultColoringFont(); if (!tempFont.equals(font)){ font = tempFont; //setPreferredSize(new Dimension(font.getSize(), component.getHeight())); } }else{ if (!foldingFont.equals(font)){ font = foldingFont; //setPreferredSize(new Dimension(font.getSize(), component.getHeight())); } } //repaint(); } } private Font getDefaultColoringFont(){ // font in folding coloring not available, get default (or inherited) EditorUI editorUI = getEditorUI(); if (editorUI!=null){ Coloring defaultColoring = editorUI.getDefaultColoring(); if (defaultColoring!=null){ if (defaultColoring.getFont() != null){ return defaultColoring.getFont(); } } } return SettingsDefaults.defaultFont; } protected Font getColoringFont(){ if (font != null) return font; EditorUI editorUI = getEditorUI(); if (editorUI!=null){ Coloring foldColoring = editorUI.getColoring(SettingsNames.CODE_FOLDING_COLORING); if (foldColoring != null){ if (foldColoring.getFont()!=null){ font = foldColoring.getFont(); return font; } } } font = getDefaultColoringFont(); return font; } protected Color getForeColor(){ if (foreColor != null) return foreColor; EditorUI editorUI = getEditorUI(); if (editorUI!=null){ Coloring foldColoring = editorUI.getColoring(SettingsNames.CODE_FOLDING_COLORING); if (foldColoring != null && foldColoring.getForeColor()!=null){ foreColor = foldColoring.getForeColor(); return foreColor; } } foreColor = getDefaultForeColor(); return foreColor; } private Color getDefaultForeColor(){ EditorUI editorUI = getEditorUI(); if (editorUI!=null){ // font in folding coloring not available, get default (or inherited) Coloring defaultColoring = editorUI.getDefaultColoring(); if (defaultColoring!=null && defaultColoring.getForeColor()!=null){ return defaultColoring.getForeColor(); } } return SettingsDefaults.defaultForeColor; } private Color getDefaultBackColor(){ EditorUI editorUI = getEditorUI(); if (editorUI!=null){ // font in folding coloring not available, get default (or inherited) Coloring defaultColoring = editorUI.getDefaultColoring(); if (defaultColoring!=null){ return defaultColoring.getBackColor(); } } return SettingsDefaults.defaultBackColor; } protected Color getBackColor(){ if (backColor != null) return backColor; EditorUI editorUI = getEditorUI(); if (editorUI!=null){ Coloring foldColoring = editorUI.getColoring(SettingsNames.CODE_FOLDING_COLORING); if (foldColoring != null && foldColoring.getBackColor()!=null){ backColor = foldColoring.getBackColor(); return backColor; } } backColor = getDefaultBackColor(); return backColor; } class RootView extends View { RootView() { super(null); } void setView(View v) { if (view != null) { // get rid of back reference so that the old // hierarchy can be garbage collected. view.setParent(null); } view = v; if (view != null) { view.setParent(this); } } /** * Fetches the attributes to use when rendering. At the root * level there are no attributes. If an attribute is resolved * up the view hierarchy this is the end of the line. */ public AttributeSet getAttributes() { return null; } /** * Determines the preferred span for this view along an axis. * * @param axis may be either X_AXIS or 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. */ public float getPreferredSpan(int axis) { if (view != null) { return view.getPreferredSpan(axis); } return 10; } /** * Determines the minimum span for this view along an axis. * * @param axis may be either X_AXIS or 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. */ public float getMinimumSpan(int axis) { if (view != null) { return view.getMinimumSpan(axis); } return 10; } /** * Determines the maximum span for this view along an axis. * * @param axis may be either X_AXIS or 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. */ public float getMaximumSpan(int axis) { return Integer.MAX_VALUE; } /** * Specifies that a preference has changed. * Child views can call this on the parent to indicate that * the preference has changed. The root view routes this to * invalidate on the hosting component. *

* This can be called on a different thread from the * event dispatching thread and is basically unsafe to * propagate into the component. To make this safe, * the operation is transferred over to the event dispatching * thread for completion. It is a design goal that all view * methods be safe to call without concern for concurrency, * and this behavior helps make that true. * * @param child the child view * @param width true if the width preference has changed * @param height true if the height preference has changed */ public void preferenceChanged(View child, boolean width, boolean height) { } /** * Determines the desired alignment for this view along an axis. * * @param axis may be either X_AXIS or Y_AXIS * @return the desired alignment, where 0.0 indicates the origin * and 1.0 the full span away from the origin */ public float getAlignment(int axis) { if (view != null) { return view.getAlignment(axis); } return 0; } /** * Renders the view. * * @param g the graphics context * @param allocation the region to render into */ public void paint(Graphics g, Shape allocation) { if (view != null) { Rectangle alloc = (allocation instanceof Rectangle) ? (Rectangle)allocation : allocation.getBounds(); setSize(alloc.width, alloc.height); view.paint(g, allocation); } } /** * Sets the view parent. * * @param parent the parent view */ public void setParent(View parent) { throw new Error("Can't set parent on root view"); // NOI18N } /** * Returns the number of views in this view. Since * this view simply wraps the root of the view hierarchy * it has exactly one child. * * @return the number of views * @see #getView */ public int getViewCount() { return 1; } /** * Gets the n-th view in this container. * * @param n the number of the view to get * @return the view */ public View getView(int n) { return view; } /** * Returns the child view index representing the given position in * the model. This is implemented to return the index of the only * child. * * @param pos the position >= 0 * @return index of the view representing the given position, or * -1 if no view represents that position * @since 1.3 */ public int getViewIndex(int pos, Position.Bias b) { return 0; } /** * Fetches the allocation for the given child view. * This enables finding out where various views * are located, without assuming the views store * their location. This returns the given allocation * since this view simply acts as a gateway between * the view hierarchy and the associated component. * * @param index the index of the child * @param a the allocation to this view. * @return the allocation to the child */ public Shape getChildAllocation(int index, Shape a) { return a; } /** * 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 * @param a the allocated region to render into * @return the bounding box of the given position */ public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { if (view != null) { return view.modelToView(pos, a, b); } return null; } /** * 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. * @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 (view != null) { return view.modelToView(p0, b0, p1, b1, a); } return null; } /** * 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 * @param y y coordinate of the view location to convert * @param a the allocated region to render into * @return the location within the model that best represents the * given point in the view */ public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) { if (view != null) { int retValue = view.viewToModel(x, y, a, bias); return retValue; } return -1; } /** * Provides a way to determine the next visually represented model * location that one might place a caret. Some views may not be visible, * they might not be in the same order found in the model, or they just * might not allow access to some of the locations in the model. * * @param pos the position to convert >= 0 * @param a the allocated region to render into * @param direction the direction from the current position that can * be thought of as the arrow keys typically found on a keyboard. * This may be SwingConstants.WEST, SwingConstants.EAST, * SwingConstants.NORTH, or SwingConstants.SOUTH. * @return the location within the model that best represents the next * location visual position. * @exception BadLocationException * @exception IllegalArgumentException for an invalid direction */ public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, int direction, Position.Bias[] biasRet) throws BadLocationException { if( view != null ) { int nextPos = view.getNextVisualPositionFrom(pos, b, a, direction, biasRet); if(nextPos != -1) { pos = nextPos; } else { biasRet[0] = b; } } return pos; } /** * Gives notification that something was inserted into the document * in a location that this view is responsible for. * * @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 */ public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) { if (view != null) { view.insertUpdate(e, a, f); } } /** * Gives notification that something was removed from the document * in a location that this view is responsible for. * * @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 */ public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) { if (view != null) { view.removeUpdate(e, a, f); } } /** * Gives notification from the document that attributes were changed * in a location that this view is responsible for. * * @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 */ public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) { if (view != null) { view.changedUpdate(e, a, f); } } /** * Returns the document model underlying the view. * * @return the model */ public Document getDocument() { EditorUI editorUI = getEditorUI(); return (editorUI==null) ? null : editorUI.getDocument(); } /** * Returns the starting offset into the model for this view. * * @return the starting offset */ public int getStartOffset() { if (view != null) { return view.getStartOffset(); } return getElement().getStartOffset(); } /** * Returns the ending offset into the model for this view. * * @return the ending offset */ public int getEndOffset() { if (view != null) { return view.getEndOffset(); } return getElement().getEndOffset(); } /** * Gets the element that this view is mapped to. * * @return the view */ public Element getElement() { if (view != null) { return view.getElement(); } return view.getDocument().getDefaultRootElement(); } /** * Breaks this view on the given axis at the given length. * * @param axis may be either X_AXIS or Y_AXIS * @param len specifies where a break is desired in the span * @param the current allocation of the view * @return the fragment of the view that represents the given span * if the view can be broken, otherwise null */ public View breakView(int axis, float len, Shape a) { throw new Error("Can't break root view"); // NOI18N } /** * Determines the resizability of the view along the * given axis. A value of 0 or less is not resizable. * * @param axis may be either X_AXIS or Y_AXIS * @return the weight */ public int getResizeWeight(int axis) { if (view != null) { return view.getResizeWeight(axis); } return 0; } /** * Sets the view size. * * @param width the width * @param height the height */ public void setSize(float width, float height) { if (view != null) { view.setSize(width, height); } } /** * 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 */ public Container getContainer() { EditorUI editorUI = getEditorUI(); return (editorUI==null) ? null : editorUI.getComponent(); } /** * Fetches the factory to be used for building the * various view fragments that make up the view that * represents the model. This is what determines * how the model will be represented. This is implemented * to fetch the factory provided by the associated * EditorKit unless that is null, in which case this * simply returns the BasicTextUI itself which allows * subclasses to implement a simple factory directly without * creating extra objects. * * @return the factory */ public ViewFactory getViewFactory() { EditorUI editorUI = getEditorUI(); if (editorUI!=null){ BaseKit kit = Utilities.getKit(editorUI.getComponent()); ViewFactory f = kit.getViewFactory(); if (f != null) { return f; } } return getBaseTextUI(); } private View view; } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.