public void paint(Graphics g, JComponent c) { AbstractButton b = (AbstractButton) c; ButtonModel model = b.getModel(); String text = layout(b, SwingUtilities2.getFontMetrics(b, g), b.getWidth(), b.getHeight()); clearTextShiftOffset(); // perform UI specific press action, e.g. Windows L&F shifts text if (model.isArmed() && model.isPressed()) { paintButtonPressed(g, b); } // Paint the Icon if (b.getIcon() != null) { paintIcon(g, c, iconRect); } if (text != null && !text.equals("")) { View v = (View) c.getClientProperty(BasicHTML.propertyKey); if (v != null) { v.paint(g, textRect); } else { paintText(g, b, textRect, text); } } if (b.isFocusPainted() && b.hasFocus()) { // paint UI specific focus paintFocus(g, b, viewRect, textRect, iconRect); } }
/** * Performs layout for the minor axis of the box (i.e. the axis orthogonal to the axis that it * represents). The results of the layout (the offset and span for each children) are placed in * the given arrays which represent the allocations to the children along the minor axis. * * @param targetSpan the total span given to the view, which would be used to layout the children. * @param axis the axis being layed out * @param offsets the offsets from the origin of the view for each of the child views; this is a * return value and is filled in by the implementation of this method * @param spans the span of each child view; this is a return value and is filled in by the * implementation of this method */ protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { int n = getViewCount(); Object key = (axis == X_AXIS) ? CSS.Attribute.WIDTH : CSS.Attribute.HEIGHT; for (int i = 0; i < n; i++) { View v = getView(i); int min = (int) v.getMinimumSpan(axis); int max; // check for percentage span AttributeSet a = v.getAttributes(); CSS.LengthValue lv = (CSS.LengthValue) a.getAttribute(key); if ((lv != null) && lv.isPercentage()) { // bound the span to the percentage specified min = Math.max((int) lv.getValue(targetSpan), min); max = min; } else { max = (int) v.getMaximumSpan(axis); } // assign the offset and span for the child if (max < targetSpan) { // can't make the child this wide, align it float align = v.getAlignment(axis); offsets[i] = (int) ((targetSpan - max) * align); spans[i] = max; } else { // make it the target width, or as small as it can get. offsets[i] = 0; spans[i] = Math.max(min, targetSpan); } } }
/** * Indicates whether or not this view should be displayed. If none of the children wish to be * displayed and the only visible child is the break that ends the paragraph, the paragraph will * not be considered visible. Otherwise, it will be considered visible and return true. * * @return true if the paragraph should be displayed */ public boolean isVisible() { int n = getLayoutViewCount() - 1; for (int i = 0; i < n; i++) { View v = getLayoutView(i); if (v.isVisible()) { return true; } } if (n > 0) { View v = getLayoutView(n); if ((v.getEndOffset() - v.getStartOffset()) == 1) { return false; } } // If it's the last paragraph and not editable, it shouldn't // be visible. if (getStartOffset() == getDocument().getLength()) { boolean editable = false; Component c = getContainer(); if (c instanceof JTextComponent) { editable = ((JTextComponent) c).isEditable(); } if (!editable) { return false; } } return true; }
/** * 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); }
@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; }
public Dimension getMaximumSize(JComponent c) { Dimension d = getPreferredSize(c); View v = (View) c.getClientProperty(BasicHTML.propertyKey); if (v != null) { d.width += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS); } return d; }
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; }
/** * Paints the View. * * @param g the rendering surface to use * @param a the allocated region to render into * @see View#paint */ @Override public void paint(Graphics g, Shape a) { sync(); Rectangle rect = (a instanceof Rectangle) ? (Rectangle) a : a.getBounds(); Image image = getImage(); Rectangle clip = g.getClipBounds(); fBounds.setBounds(rect); paintHighlights(g, a); paintBorder(g, rect); if (clip != null) { g.clipRect( rect.x + leftInset, rect.y + topInset, rect.width - leftInset - rightInset, rect.height - topInset - bottomInset); } if (image != null) { if (!hasPixels(image)) { // No pixels yet, use the default Icon icon = (image == null) ? getNoImageIcon() : getLoadingImageIcon(); if (icon != null) { icon.paintIcon(getContainer(), g, rect.x + leftInset, rect.y + topInset); } } else { // Draw the image g.drawImage(image, rect.x + leftInset, rect.y + topInset, width, height, imageObserver); } } else { Icon icon = getNoImageIcon(); if (icon != null) { icon.paintIcon(getContainer(), g, rect.x + leftInset, rect.y + topInset); } View view = getAltView(); // Paint the view representing the alt text, if its non-null if (view != null && ((state & WIDTH_FLAG) == 0 || width > DEFAULT_WIDTH)) { // Assume layout along the y direction Rectangle altRect = new Rectangle( rect.x + leftInset + DEFAULT_WIDTH, rect.y + topInset, rect.width - leftInset - rightInset - DEFAULT_WIDTH, rect.height - topInset - bottomInset); view.paint(g, altRect); } } if (clip != null) { // Reset clip. g.setClip(clip.x, clip.y, clip.width, clip.height); } }
/** * Returns the preferred span of the View used to display the alt text, or 0 if the view does not * exist. */ private float getPreferredSpanFromAltView(int axis) { if (getImage() == null) { View view = getAltView(); if (view != null) { return view.getPreferredSpan(axis); } } return 0f; }
/** * 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; } } }
/** Returns the view to use for alternate text. This may be null. */ private View getAltView() { View view; synchronized (this) { view = altView; } if (view != null && view.getParent() == null) { view.setParent(getParent()); } return view; }
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; }
@Override public Color getForeground() { View parent; if (fg == null && (parent = getParent()) != null) { Document doc = getDocument(); AttributeSet attr = parent.getAttributes(); if (attr != null && (doc instanceof StyledDocument)) { fg = ((StyledDocument) doc).getForeground(attr); } } return fg; }
/* */ public void removeUpdate( DocumentEvent paramDocumentEvent, Shape paramShape, ViewFactory paramViewFactory) /* */ { /* 485 */ updateChildren(paramDocumentEvent, paramShape); /* */ /* 487 */ Rectangle localRectangle = (paramShape != null) && (isAllocationValid()) ? getInsideAllocation(paramShape) : null; /* */ /* 489 */ int i = paramDocumentEvent.getOffset(); /* 490 */ View localView = getViewAtPosition(i, localRectangle); /* 491 */ if (localView != null) /* 492 */ localView.removeUpdate(paramDocumentEvent, localRectangle, paramViewFactory); /* */ }
/** {@inheritDoc} */ @Override public void paint(final Graphics2D g2d, final Rectangle bounds, final E label) { // Applying graphics settings final Composite oc = LafUtils.setupAlphaComposite(g2d, transparency, transparency != null); final Map textHints = drawShade ? StyleConstants.defaultTextRenderingHints : StyleConstants.textRenderingHints; final Font oldFont = LafUtils.setupFont(g2d, label.getFont()); final Map oldHints = SwingUtils.setupTextAntialias(g2d, textHints); // Retrieving icon & text final String text = label.getText(); final Icon icon = (label.isEnabled()) ? label.getIcon() : label.getDisabledIcon(); // Painting background if (backgroundPainter != null) { backgroundPainter.paint(g2d, bounds, label); } // We don't need to go futher if there is not icon/text if (icon == null && text == null) { return; } final FontMetrics fm = label.getFontMetrics(label.getFont()); final String clippedText = layout(label, fm, label.getWidth(), label.getHeight()); if (icon != null) { icon.paintIcon(label, g2d, paintIconR.x, paintIconR.y); } if (text != null) { final View v = (View) label.getClientProperty(BasicHTML.propertyKey); if (v != null) { // Painting HTML label view v.paint(g2d, paintTextR); } else { // Painting plain label view final int textX = paintTextR.x; final int textY = paintTextR.y + fm.getAscent(); if (label.isEnabled()) { paintEnabledText(label, g2d, clippedText, textX, textY); } else { paintDisabledText(label, g2d, clippedText, textX, textY); } } } SwingUtils.restoreTextAntialias(g2d, oldHints); LafUtils.restoreFont(g2d, oldFont); LafUtils.restoreComposite(g2d, oc, transparency != null); }
/** * Sets the size of the view. This should cause layout of the view if it has any layout duties. * * @param width the width >= 0 * @param height the height >= 0 */ @Override public void setSize(float width, float height) { sync(); if (getImage() == null) { View view = getAltView(); if (view != null) { view.setSize( Math.max(0f, width - (DEFAULT_WIDTH + leftInset + rightInset)), Math.max(0f, height - (topInset + bottomInset))); } } }
/** * 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; }
@Override protected void paintText( Graphics graphics, int tabPlacement, Font font, FontMetrics metrics, int tabIndex, String title, Rectangle textRect, boolean isSelected) { if (null == graphics) { return; } Graphics2D g = (Graphics2D) graphics; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setFont(font); View v = getTextViewForTab(tabIndex); if (v != null) { // html v.paint(g, textRect); } else { // plain text int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex); if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex)) { Color fg = tabPane.getForegroundAt(tabIndex); if (isSelected && (fg instanceof UIResource)) { Color selectedFG = TabColors.SELECTED_FOREGROUND; if (selectedFG != null) { fg = selectedFG; } } g.setColor(fg); SwingUtilities2.drawStringUnderlineCharAt( tabPane, g, title, mnemIndex, textRect.x, textRect.y + metrics.getAscent()); } else { // tab disabled g.setColor(tabPane.getBackgroundAt(tabIndex).brighter()); SwingUtilities2.drawStringUnderlineCharAt( tabPane, g, title, mnemIndex, textRect.x, textRect.y + metrics.getAscent()); g.setColor(tabPane.getBackgroundAt(tabIndex).darker()); SwingUtilities2.drawStringUnderlineCharAt( tabPane, g, title, mnemIndex, textRect.x - 1, textRect.y + metrics.getAscent() - 1); } } }
/** * 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); } } } }
/** * paintLayer * * @param g Graphics * @param offs0 the beginning * @param offs1 the end * @param bounds the bounds * @param c the text component where to paint * @param view the view to use * @return the shape containg the highlighted text */ public Shape paintLayer( Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c, View view) { try { Rectangle r = (Rectangle) view.modelToView( offs0, Position.Bias.Forward, offs1, Position.Bias.Backward, bounds); g.setColor(color); switch (type) { case UNDERLINED: g.drawLine(r.x, r.y + r.height - 1, r.x + r.width - 1, r.y + r.height - 1); return r; case FRAMED: g.drawRect(r.x, r.y, r.width - 1, r.height - 1); return r; case FILLED: default: g.fillRect(r.x, r.y, r.width, r.height); return r; } } catch (BadLocationException e) { return null; } }
/** * 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); } }
/** Paints one view that corresponds to a line (or multiple lines if folding takes effect). */ private void paintView(View view, Graphics g, int yBase) { JTextComponent component = editorUI.getComponent(); if (component == null) return; BaseTextUI textUI = (BaseTextUI) component.getUI(); Element rootElem = textUI.getRootView(component).getElement(); int line = rootElem.getElementIndex(view.getStartOffset()); String annotation = ""; // NOI18N AnnotateLine al = null; if (!elementAnnotations.isEmpty()) { al = getAnnotateLine(line); if (al != null) { annotation = getDisplayName(al); // NOI18N } } else { annotation = elementAnnotationsSubstitute; } if (al != null && al.getRevision().equals(recentRevision)) { g.setColor(selectedColor()); } else { g.setColor(foregroundColor()); } int texty = yBase + editorUI.getLineAscent(); int textx = 2; g.drawString(annotation, textx, texty); }
/** * 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; } }
/** @see javax.swing.plaf.basic.BasicTextUI#getPreferredSize(javax.swing.JComponent) */ public Dimension getPreferredSize(JComponent c) { // The following code has been derived from BasicTextUI. Document doc = ((JTextComponent) c).getDocument(); Insets i = c.getInsets(); Dimension d = c.getSize(); View rootView = getRootView((JTextComponent) c); if (doc instanceof AbstractDocument) { ((AbstractDocument) doc).readLock(); } try { if ((d.width > (i.left + i.right)) && (d.height > (i.top + i.bottom))) { rootView.setSize(d.width - i.left - i.right, d.height - i.top - i.bottom); } else if (d.width == 0 && d.height == 0) { // Probably haven't been layed out yet, force some sort of // initial sizing. rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE); } d.width = (int) Math.min( (long) rootView.getPreferredSpan(View.X_AXIS) + (long) i.left + (long) i.right, Integer.MAX_VALUE); d.height = (int) Math.min( (long) rootView.getPreferredSpan(View.Y_AXIS) + (long) i.top + (long) i.bottom, Integer.MAX_VALUE); } finally { if (doc instanceof AbstractDocument) { ((AbstractDocument) doc).readUnlock(); } } // Fix: The preferred width is always two pixels too small on a Mac. d.width += 2; // We'd like our heights to be odd by default. if ((d.height & 1) == 0) { d.height--; } return d; }
/** * Gets the alignment. * * @param axis may be either X_AXIS or Y_AXIS * @return the alignment */ public float getAlignment(int axis) { switch (axis) { case View.X_AXIS: return 0; case View.Y_AXIS: if (getViewCount() == 0) { return 0; } float span = getPreferredSpan(View.Y_AXIS); View v = getView(0); float above = v.getPreferredSpan(View.Y_AXIS); float a = (((int) span) != 0) ? (above * v.getAlignment(View.Y_AXIS)) / span : 0; return a; default: throw new IllegalArgumentException("Invalid axis: " + axis); } }
/** Returns the baseline for single line text components, like <code>JTextField</code>. */ private static int getSingleLineTextBaseline(JTextComponent textComponent, int h) { View rootView = textComponent.getUI().getRootView(textComponent); if (rootView.getViewCount() > 0) { Insets insets = textComponent.getInsets(); int height = h - insets.top - insets.bottom; int y = insets.top; View fieldView = rootView.getView(0); int vspan = (int) fieldView.getPreferredSpan(View.Y_AXIS); if (height != vspan) { int slop = height - vspan; y += slop / 2; } FontMetrics fm = textComponent.getFontMetrics(textComponent.getFont()); y += fm.getAscent(); return y; } return -1; }
/** * 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; }
/** * 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 */ @Override public float getPreferredSpan(int axis) { sync(); // If the attributes specified a width/height, always use it! if (axis == View.X_AXIS && (state & WIDTH_FLAG) == WIDTH_FLAG) { getPreferredSpanFromAltView(axis); return width + leftInset + rightInset; } if (axis == View.Y_AXIS && (state & HEIGHT_FLAG) == HEIGHT_FLAG) { getPreferredSpanFromAltView(axis); return height + topInset + bottomInset; } Image image = getImage(); if (image != null) { switch (axis) { case View.X_AXIS: return width + leftInset + rightInset; case View.Y_AXIS: return height + topInset + bottomInset; default: throw new IllegalArgumentException("Invalid axis: " + axis); } } else { View view = getAltView(); float retValue = 0f; if (view != null) { retValue = view.getPreferredSpan(axis); } switch (axis) { case View.X_AXIS: return retValue + (width + leftInset + rightInset); case View.Y_AXIS: return retValue + (height + topInset + bottomInset); default: throw new IllegalArgumentException("Invalid axis: " + axis); } } }