All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.editor.CollapsedView Maven / Gradle / Ivy

/*
 *                 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; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy