
org.jooq.debug.console.misc.TreeDataTip Maven / Gradle / Ivy
The newest version!
/**
* Copyright (c) 2009-2013, Lukas Eder, [email protected]
* Christopher Deckers, [email protected]
* All rights reserved.
*
* This software is licensed to you under the Apache License, Version 2.0
* (the "License"); You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name "jOOQ" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jooq.debug.console.misc;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.MouseEvent;
import javax.swing.CellRendererPane;
import javax.swing.JComponent;
import javax.swing.JToolTip;
import javax.swing.JTree;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
@SuppressWarnings("serial")
public class TreeDataTip {
private TreeDataTip() {}
public static void activate(final JTree tree) {
MouseInputListener dataTipListener = new MouseInputAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
showTip(e.getPoint());
}
@Override
public void mouseMoved(MouseEvent e) {
showTip(e.getPoint());
}
@Override
public void mouseExited(MouseEvent e) {
hideTip();
}
@Override
public void mousePressed(MouseEvent e) {
hideTip();
}
private Popup popup;
private int currentRow = -1;
private void hideTip() {
if(popup != null) {
popup.hide();
popup = null;
}
}
private void showTip(Point mousePosition) {
int row = tree.getRowForLocation(mousePosition.x, mousePosition.y);
if(row != currentRow) {
hideTip();
currentRow = row;
if(row >= 0) {
TreePath treePath = tree.getPathForRow(row);
TreeCellRenderer renderer = tree.getCellRenderer();
boolean isSelected = false;//breakpointTree.isPathSelected(treePath);
boolean isExpanded = tree.isExpanded(treePath);
boolean hasFocus = false;//tree.hasFocus() && rowIndex == tree.getLeadSelectionRow();
Object item = treePath.getLastPathComponent();
boolean isLeaf = tree.getModel().isLeaf(item);
final JComponent rendererComponent = (JComponent)renderer.getTreeCellRendererComponent(tree, item, isSelected, isExpanded, isLeaf, row, hasFocus);
rendererComponent.setFont(tree.getFont());
Rectangle visRect = tree.getVisibleRect();
Rectangle cellBounds = tree.getPathBounds(treePath);
Rectangle visibleCellRectangle = cellBounds.intersection(visRect);
if (!visibleCellRectangle.contains(mousePosition)) {
return;
}
Dimension rendCompDim = rendererComponent.getMinimumSize();
Rectangle rendCompBounds = new Rectangle(cellBounds.getLocation(), rendCompDim);
visRect.x -= 1000;
visRect.width += 1000;
visRect.y -= 1000;
visRect.height += 2000;
// We do not care about vertical visibility.
rendCompBounds.height = 1;
if(cellBounds.contains(rendCompBounds) && visRect.contains(rendCompBounds)) {
return;
}
Dimension preferredSize = rendererComponent.getPreferredSize();
Point tipPosition = cellBounds.getLocation();
int width = Math.max(cellBounds.width, preferredSize.width);
int height = cellBounds.height;//Math.max(cellBounds.height, preferredSize.height); // We don't care about vertical visibility
Dimension tipDimension = new Dimension(width, height);
final Color backgroundColor = tree.getBackground();
class DataTipComponent extends JToolTip {
private CellRendererPane rendererPane = new CellRendererPane();
private boolean isHeavyWeight;
public DataTipComponent() {
add(rendererPane);
setFocusable(false);
setBorder(null);
enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_WHEEL_EVENT_MASK);
}
@Override
public void updateUI() {
}
@Override
public boolean contains(int x, int y) {
return isHeavyWeight;
}
@SuppressWarnings("hiding")
@Override
public void paintComponent(Graphics g) {
// Leave the component's opacity settings as is, just paint the background myself.
// This seems to be the only viable solution: DefaultTableCellRenderer overrides isOpaque() and returns
// true only if renderer color does not equal parent color. The problem is that rendererPane.paintComponent()
// re-parents the renderer.
g.setColor(backgroundColor);
int width = getWidth();
int height = getHeight();
g.fillRect(0, 0, width, height);
g.setColor(Color.black);
g.drawRect(0, 0, width - 1, height - 1);
g.setClip(1, 1, width - 2, height - 2);
int row = currentRow;
TreePath treePath = tree.getPathForRow(row);
boolean isSelected = false;//breakpointTree.isPathSelected(treePath);
boolean isExpanded = tree.isExpanded(treePath);
boolean hasFocus = false;//tree.hasFocus() && rowIndex == tree.getLeadSelectionRow();
Object item = treePath.getLastPathComponent();
boolean isLeaf = tree.getModel().isLeaf(item);
TreeCellRenderer renderer = tree.getCellRenderer();
JComponent rendererComponent = (JComponent)renderer.getTreeCellRendererComponent(tree, item, isSelected, isExpanded, isLeaf, row, hasFocus);
rendererComponent.setFont(tree.getFont());
rendererPane.paintComponent(g, rendererComponent, this, 1, 1, width - 1, height - 1);
}
public void setHeavyWeight(boolean isHeavyWeight) {
this.isHeavyWeight = isHeavyWeight;
}
}
DataTipComponent dataTipComponent = new DataTipComponent();
Dimension tipDimensionClipped = new Dimension(tipDimension.width, tipDimension.height);
Window windowAncestor = SwingUtilities.getWindowAncestor(tree);
GraphicsConfiguration gc = windowAncestor.getGraphicsConfiguration();
Rectangle screenBounds = gc.getBounds();
// Chrriis: we add the border around, not in
Point tipScreenPosition = new Point(tipPosition.x, tipPosition.y);
SwingUtilities.convertPointToScreen(tipScreenPosition, tree);
Point tipPositionClipped = new Point();
tipPositionClipped.x = Math.max(tipScreenPosition.x - 1, screenBounds.x);
tipPositionClipped.y = Math.max(tipScreenPosition.y - 1, screenBounds.y);
// Chrriis: we add the border around, not in
tipDimensionClipped.width = Math.min(screenBounds.x + screenBounds.width - tipPositionClipped.x, tipDimensionClipped.width + 2);
tipDimensionClipped.height = Math.min(screenBounds.y + screenBounds.height - tipPositionClipped.y, tipDimensionClipped.height + 2);
SwingUtilities.convertPointFromScreen(tipPositionClipped, tree);
dataTipComponent.setPreferredSize(tipDimensionClipped);
SwingUtilities.convertPointToScreen(tipPosition, tree);
PopupFactory popupFactory = PopupFactory.getSharedInstance();
popup = popupFactory.getPopup(tree, dataTipComponent, tipPosition.x - 1, tipPosition.y - 1);
popup.show();
Window componentWindow = SwingUtilities.windowForComponent(tree);
Window tipWindow = SwingUtilities.windowForComponent(dataTipComponent);
boolean isHeavyWeight = tipWindow != null && tipWindow != componentWindow;
dataTipComponent.setHeavyWeight(isHeavyWeight);
}
}
}
};
tree.addMouseListener(dataTipListener);
tree.addMouseMotionListener(dataTipListener);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy