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

org.nuiton.jaxx.widgets.extra.datatips.DataTipManager Maven / Gradle / Ivy

Go to download

Widgets graphiques utiles pour tous les développements (pour le moment sans lien avec JAXX).

There is a newer version: 3.0-alpha-17
Show newest version
/*
 * %%Ignore-License
 * 
 * Copyright (c) 2002 - 2005, Stephen Kelvin Friedrich. All rights reserved.
 *
 * 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 of the copyright holder 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.nuiton.jaxx.widgets.extra.datatips;

import javax.swing.JList;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.security.AccessControlException;

/**
 * DataTipManager provides data tips for tree, table and list components. Whenever the mouse cursor is
 * over a cell whose content is partially hidden a popup with the complete cell content is shown.
 * The cell content can be hidden because it is clipped at either the parent component bounds (e.g. scrollpane) or at
 * the cell bounds (e.g. table row height is too small).
 */
public class DataTipManager {
    private static DataTipManager instance;

    private final ListDataTipListener listMouseListener = new ListDataTipListener();
    private final TableDataTipListener tableMouseListener = new TableDataTipListener();
    private final TreeDataTipListener treeMouseListener = new TreeDataTipListener();
    private Component parentComponent;
    private Window tipComponentWindow;
    private MouseEvent lastMouseEvent;
    private static boolean allowUntrustedUsage;

    private DataTipManager() {
        try {
            long eventMask = AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_WHEEL_EVENT_MASK;
            Toolkit.getDefaultToolkit().addAWTEventListener(new MouseEventModifier(), eventMask);
        } catch (AccessControlException e) {
            if (!allowUntrustedUsage) {
                throw new RuntimeException("DataTipManager needs to run in a trusted application", e);
            }
        }
    }

    static void enableUntrustedUsage(boolean enable) {
        allowUntrustedUsage = enable;
    }

    /**
     * @return the single, shared instance of the DataTipmanager
     */
    public static synchronized DataTipManager get() {
        if (instance == null) {
            instance = new DataTipManager();
        }
        return instance;
    }

    /**
     * Enable data tips for a list component.
     *
     * @param list the list which should be enhanced with data tips.
     */
    public synchronized void register(JList list) {
        list.addMouseListener(listMouseListener);
        list.addMouseMotionListener(listMouseListener);
        list.addComponentListener(listMouseListener);
    }

    /**
     * Enable data tips for a tree component.
     *
     * @param tree the tree which should be enhanced with data tips.
     */
    public synchronized void register(JTree tree) {
        tree.addMouseListener(treeMouseListener);
        tree.addMouseMotionListener(treeMouseListener);
        tree.addComponentListener(treeMouseListener);
    }

    /**
     * Enable data tips for a list component.
     *
     * @param table the table which should be enhanced with data tips.
     */
    public synchronized void register(JTable table) {
        table.addMouseListener(tableMouseListener);
        table.addMouseMotionListener(tableMouseListener);
        table.addComponentListener(tableMouseListener);
    }

    void setTipWindow(Component parentComponent, Window dataTipComponent) {
        this.parentComponent = parentComponent;
        tipComponentWindow = dataTipComponent;
    }

    public boolean handleEventFromParentComponent(MouseEvent mouseEvent) {
        // filter out events that come from client explicitly calling this method, but we have already handled in awt event listener
        if (mouseEvent == lastMouseEvent) {
            return false;
        }
        Object source = mouseEvent.getSource();
        if (source != parentComponent) {
            return false;
        }
        int id = mouseEvent.getID();
        int x = mouseEvent.getX();
        int y = mouseEvent.getY();
        long when = mouseEvent.getWhen();
        int modifiers = mouseEvent.getModifiers();
        int clickCount = mouseEvent.getClickCount();
        boolean isPopupTrigger = mouseEvent.isPopupTrigger();
        if (id == MouseEvent.MOUSE_EXITED) {
            Point point = SwingUtilities.convertPoint(parentComponent, x, y, tipComponentWindow);
            if (tipComponentWindow.contains(point)) {
                MouseEvent newEvent = new MouseEvent(parentComponent, MouseEvent.MOUSE_MOVED, when, modifiers,
                                                     x, y, clickCount, isPopupTrigger);
                parentComponent.dispatchEvent(newEvent);
                // If the datatip has been hidden as a result, then process the exit event, too, so that
                // e.g. tooltips will hide.
                return parentComponent != null;
            }
        }
        return false;
    }

    public void handleEventFromDataTipComponent(MouseEvent mouseEvent) {
        mouseEvent.consume();
        int id = mouseEvent.getID();
        if (id != MouseEvent.MOUSE_ENTERED) {
            int x = mouseEvent.getX();
            int y = mouseEvent.getY();
            Point point = SwingUtilities.convertPoint(mouseEvent.getComponent(), x, y, parentComponent);

            if (id == MouseEvent.MOUSE_EXITED && parentComponent.contains(point)) {
                return;
            }
            long when = mouseEvent.getWhen();
            int modifiers = mouseEvent.getModifiers();
            int clickCount = mouseEvent.getClickCount();
            boolean isPopupTrigger = mouseEvent.isPopupTrigger();
            MouseEvent newEvent;
            if (id == MouseEvent.MOUSE_WHEEL) {
                MouseWheelEvent mouseWheelEvent = (MouseWheelEvent) mouseEvent;
                int scrollType = mouseWheelEvent.getScrollType();
                int scrollAmount = mouseWheelEvent.getScrollAmount();
                int wheelRotation = mouseWheelEvent.getWheelRotation();
                newEvent = new MouseWheelEvent(parentComponent, id, when, modifiers, point.x, point.y,
                                               clickCount, isPopupTrigger, scrollType, scrollAmount,
                                               wheelRotation);
            } else {
                newEvent = new MouseEvent(parentComponent, id, when, modifiers, point.x, point.y,
                                          clickCount, isPopupTrigger);
            }
            Component parentComponentBackup = parentComponent;
            parentComponent.dispatchEvent(newEvent);
            if (parentComponent == null && id != MouseEvent.MOUSE_EXITED) {
                MouseEvent exitEvent = new MouseEvent(parentComponentBackup, MouseEvent.MOUSE_EXITED, when,
                                                      modifiers, point.x, point.y, clickCount, isPopupTrigger);
                parentComponentBackup.dispatchEvent(exitEvent);
            }
            if (tipComponentWindow != null && id != MouseEvent.MOUSE_MOVED) {
                // mouse click might have changed appearance (e.g. selection color)
                tipComponentWindow.repaint();
            }
        }
    }

    private class MouseEventModifier implements AWTEventListener {
        private MouseEventModifier() {
        }

        public void eventDispatched(AWTEvent event) {
            if (tipComponentWindow == null) {
                return;
            }
            Object source = event.getSource();

            if (source == parentComponent) {
                MouseEvent mouseEvent = (MouseEvent) event;
                boolean filter = handleEventFromParentComponent(mouseEvent);
                if (filter) {
                    mouseEvent.consume();
                } else {
                    lastMouseEvent = mouseEvent;
                }
            }
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy