Skip to content

Commit

Permalink
CellHintPopup: Ensure component are children of their respective cell…
Browse files Browse the repository at this point in the history
… containers/renderer panes, when calculating their preferred/minimum size or during painting.

This ensures they have the correct GraphicsConfiguration set, which is used e.g. when retrieving the FontRendererContext/FontMetrics.
  • Loading branch information
weisJ committed Mar 3, 2021
1 parent 53ebf4e commit b077e3f
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* MIT License
*
* Copyright (c) 2021 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package com.github.weisj.darklaf.ui;

import java.awt.Container;

public interface HasRendererPane {

Container getRendererPane();
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,16 @@ public DarkBooleanCellRenderer(final boolean opaque) {
@Override
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected,
final boolean hasFocus, final int row, final int column) {
return getBooleanRenderer(table).getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
return getBooleanRenderer(table)
.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}

@Override
public Component getTreeCellRendererComponent(final JTree tree, final Object value, final boolean selected,
final boolean expanded,
final boolean leaf, final int row, final boolean hasFocus) {
return getBooleanRenderer(tree).getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row,
hasFocus);
return getBooleanRenderer(tree)
.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
}

protected ComponentBasedTableCellRenderer getBooleanRenderer(final JTable table) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* MIT License
*
* Copyright (c) 2021 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package com.github.weisj.darklaf.ui.cell.hint;

import java.awt.Component;
import java.awt.Dimension;

import javax.swing.JComponent;

import com.github.weisj.darklaf.ui.HasRendererPane;

public abstract class AbstractIndexedCellContainer<T extends JComponent, I, UI extends HasRendererPane>
implements IndexedCellContainer<T, I> {

protected final UI ui;

protected AbstractIndexedCellContainer(final UI ui) {
this.ui = ui;
}

@Override
public void addRenderer(final Component renderer) {
ui.getRendererPane().add(renderer);
}

@Override
public Dimension getRequiredCellSize(final I lastIndex, final Component comp) {
// Components without a parent may report incorrect preferred/minimum size as the
// associated FontMetrics have a missing default transform. This is bad for
// determining the actual needed size on screen.
// We add the component to the renderer pane to circumvent the issue.
boolean hasParent = comp.getParent() != null;
if (!hasParent) {
addRenderer(comp);
}
return comp.getMinimumSize();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ public interface CellContainer<T extends JComponent> {
default Rectangle getAllocation() {
return getComponent().getVisibleRect();
}

void addRenderer(final Component renderer);
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,12 @@ private boolean fitsInside(final Dimension size, final Rectangle bounds) {
}

private Dimension getPreferredSize(final boolean isEditing, final Component comp) {
final Dimension prefSize = isEditing ? comp.getBounds().getSize() : comp.getMinimumSize();
Dimension prefSize;
if (isEditing) {
prefSize = comp.getBounds().getSize();
} else {
prefSize = cellContainer.getRequiredCellSize(lastIndex, comp);
}
if (comp instanceof JComponent) {
// Avoid showing the popup if only the border is obscured.
Border border = ((JComponent) comp).getBorder();
Expand Down Expand Up @@ -245,7 +250,7 @@ public void repaint() {
}

private void enter(final I index, final Rectangle bounds, final Rectangle rendererBounds) {
LOGGER.log(popupComponent.isShowing() ? Level.FINER : Level.FINE, "Showing cell popup at index " + index);
LOGGER.log(popupComponent.isShowing() ? Level.FINEST : Level.FINE, "Showing cell popup at index " + index);
if (index != null) {
lastIndex = index;
popupComponent.setPreferredSize(bounds.getSize());
Expand Down Expand Up @@ -414,6 +419,11 @@ public void paint(final Graphics g) {
if (renderer instanceof JComponent) {
((JComponent) renderer).setDoubleBuffered(false);
}
if (!cellHintPopupListener.isCurrentCellEditing()) {
// Ensure correct parent. Without the component may use an incorrect
// font rendering context.
cellHintPopupListener.cellContainer.addRenderer(renderer);
}
renderer.setBounds(0, 0, rendererBounds.width, rendererBounds.height);
renderer.doLayout();
renderer.paint(g);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,6 @@ default Component getEffectiveCellRendererComponent(final I position, final bool
Component getCellRendererComponent(final I position);

Component getCellEditorComponent(final I position);

Dimension getRequiredCellSize(final I lastIndex, final Component comp);
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

import com.github.weisj.darklaf.components.OverlayScrollPane;
import com.github.weisj.darklaf.graphics.PaintUtil;
import com.github.weisj.darklaf.ui.HasRendererPane;
import com.github.weisj.darklaf.ui.cell.CellUtil;
import com.github.weisj.darklaf.ui.cell.DarkBooleanCellRenderer;
import com.github.weisj.darklaf.ui.cell.DarkCellRendererPane;
Expand All @@ -48,7 +49,7 @@
import com.github.weisj.darklaf.util.PropertyUtil;

/** @author Jannis Weis */
public class DarkTableUI extends DarkTableUIBridge implements TableConstants {
public class DarkTableUI extends DarkTableUIBridge implements TableConstants, HasRendererPane {

private static final int ROW_HEIGHT_FALLBACK = 22;
protected Color selectionBackgroundNoFocus;
Expand Down Expand Up @@ -451,6 +452,11 @@ public static int adjustDistance(final int distance, final Rectangle rect, final
return dist;
}

@Override
public Container getRendererPane() {
return rendererPane;
}

protected class DarkHandler extends Handler {

protected int lastIndex = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,16 @@

import javax.swing.*;

import com.github.weisj.darklaf.ui.cell.hint.IndexedCellContainer;
import com.github.weisj.darklaf.ui.cell.hint.AbstractIndexedCellContainer;
import com.github.weisj.darklaf.util.Pair;

public class TableCellContainer implements IndexedCellContainer<JTable, Pair<Integer, Integer>> {
public class TableCellContainer extends AbstractIndexedCellContainer<JTable, Pair<Integer, Integer>, DarkTableUI> {

private final JTable table;
private final DarkTableUI ui;

public TableCellContainer(final JTable table, final DarkTableUI ui) {
super(ui);
this.table = table;
this.ui = ui;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

import com.github.weisj.darklaf.graphics.PaintUtil;
import com.github.weisj.darklaf.icons.RotatableIcon;
import com.github.weisj.darklaf.ui.HasRendererPane;
import com.github.weisj.darklaf.ui.cell.CellConstants;
import com.github.weisj.darklaf.ui.cell.CellUtil;
import com.github.weisj.darklaf.ui.cell.DarkCellRendererPane;
Expand All @@ -51,7 +52,7 @@
* @author Konstantin Bulenkov
* @author Jannis Weis
*/
public class DarkTreeUI extends BasicTreeUI implements PropertyChangeListener, CellConstants {
public class DarkTreeUI extends BasicTreeUI implements PropertyChangeListener, CellConstants, HasRendererPane {

protected static final String KEY_PREFIX = "JTree.";
public static final String KEY_ALTERNATE_ROW_COLOR = KEY_PREFIX + "alternateRowColor";
Expand Down Expand Up @@ -606,6 +607,11 @@ protected static boolean isLeaf(final JTree tree, final int row) {
return true;
}

@Override
public Container getRendererPane() {
return rendererPane;
}

protected static class TreeUIAction extends AbstractAction implements UIResource {

private final ActionListener actionListener;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@
import javax.swing.tree.TreePath;

import com.github.weisj.darklaf.ui.cell.CellUtil;
import com.github.weisj.darklaf.ui.cell.hint.IndexedCellContainer;
import com.github.weisj.darklaf.ui.cell.hint.AbstractIndexedCellContainer;

public class TreeCellContainer implements IndexedCellContainer<JTree, Integer> {
public class TreeCellContainer extends AbstractIndexedCellContainer<JTree, Integer, DarkTreeUI> {

private final JTree tree;
private final DarkTreeUI ui;

public TreeCellContainer(final JTree tree, final DarkTreeUI ui) {
super(ui);
this.tree = tree;
this.ui = ui;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@

import javax.swing.*;

/** @author Jannis Weis */

/**
* Component which wraps a non standard cell renderer and provides it with the capability to display
* the nodes icon.
*
* @author Jannis Weis
*/
public class TreeRendererComponent extends Container {

private static final int PAD = 5;
Expand All @@ -47,6 +53,10 @@ public void setRenderComponent(final Component renderComponent) {
add(renderComponent);
}

public Component getRenderComponent() {
return renderComponent;
}

@Override
public boolean isShowing() {
return true;
Expand All @@ -56,7 +66,7 @@ public boolean isShowing() {
public void doLayout() {
if (renderComponent != null) {
int offset = getOffset();
int width = renderComponent.getPreferredSize().width;
int width = Math.min(renderComponent.getPreferredSize().width, getWidth());
int height = getHeight();
if (getComponentOrientation().isLeftToRight()) {
renderComponent.setBounds(offset, 0, width, height);
Expand All @@ -76,36 +86,37 @@ private int getOffset() {
@Override
public Dimension getPreferredSize() {
if (defaultRenderer != null) {
Dimension pSize = renderComponent.getPreferredSize();
pSize.width += getOffset() + PAD;
Dimension rSize = defaultRenderer.getPreferredSize();
Dimension actualRendererPreferredSize = renderComponent.getPreferredSize();
Dimension rendererSize = defaultRenderer.getPreferredSize();

addIconSize(pSize, rSize);
return pSize;
addIconSize(actualRendererPreferredSize, rendererSize);
return actualRendererPreferredSize;
}
return new Dimension(0, 0);
}

@Override
public Dimension getMinimumSize() {
if (defaultRenderer != null) {
Dimension pSize = renderComponent.getMinimumSize();
pSize.width += getOffset() + PAD;
Dimension rSize = defaultRenderer.getMinimumSize();
Dimension actualRendererMinimumSize = renderComponent.getMinimumSize();
Dimension renderSize = defaultRenderer.getMinimumSize();

addIconSize(pSize, rSize);
return pSize;
addIconSize(actualRendererMinimumSize, renderSize);
return actualRendererMinimumSize;
}
return new Dimension(0, 0);
}

private void addIconSize(final Dimension pSize, final Dimension rSize) {
private void addIconSize(final Dimension actualSize, final Dimension rendererSize) {
Icon icon = defaultRenderer.getIcon();
if (rSize != null) {
pSize.height = Math.max(pSize.height, rSize.height);
if (icon != null) {
actualSize.width += getOffset() + PAD;
}
if (rendererSize != null) {
actualSize.height = Math.max(actualSize.height, rendererSize.height);
}
if (icon != null) {
pSize.height = Math.max(pSize.height, icon.getIconHeight());
actualSize.height = Math.max(actualSize.height, icon.getIconHeight());
}
}

Expand Down

0 comments on commit b077e3f

Please sign in to comment.