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

org.netbeans.swing.tabcontrol.plaf.AbstractTabDisplayerUI Maven / Gradle / Ivy

There is a newer version: RELEASE230
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * AbstractTabDisplayerUI.java
 *
 * Created on March 16, 2004, 6:16 PM
 */

package org.netbeans.swing.tabcontrol.plaf;

import org.netbeans.swing.tabcontrol.TabDisplayer;
import org.netbeans.swing.tabcontrol.TabDisplayerUI;
import org.netbeans.swing.tabcontrol.event.ComplexListDataEvent;
import org.netbeans.swing.tabcontrol.event.ComplexListDataListener;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListDataEvent;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

/**
 * Base class for the implementations of TabDisplayerUI in this package. Uses
 * TabLayoutModel for managing the layout of the tabs.  Defines an SPI for 
 * UI delegates for TabDisplayer.
 * 

* For most use cases, it will make more sense to subclass BasicTabDisplayerUI or * BasicScrollingTabDisplayerUI, which handle most of the logic any implementation * will need. * * * @see BasicTabDisplayerUI * @see BasicScrollingTabDisplayerUI * * @author Tim Boudreau */ public abstract class AbstractTabDisplayerUI extends TabDisplayerUI { /** * Layout model, which will be initialized in installUI() by calling * createLayoutModel. The layout model provides tab coordinates. */ protected TabLayoutModel layoutModel = null; /** * Mouse listener (which may optionally implement MouseWheelListener and MouseMotionListener), * which handles mouse events over the tab, triggering selection model changes, repaints, etc. */ protected MouseListener mouseListener = null; /** * Component listener - mainly used to detach listeners when the component is hidden, * and reattach them when it is shown. Also used by BasicScrollingTabDisplayerUI to * trigger re-layouts of scrolled tabs when the size of the component changes. */ protected ComponentListener componentListener = null; /** * A property change listener to listen on any changes from the component which should * trigger repainting or other operations. The default implementation simply listens for * changes in the active property to trigger a repaint. */ protected PropertyChangeListener propertyChangeListener = null; /** * Listener on the TabDataModel. Responsible for repainting on model changes. Note that * DefaultTabSelectionModel also listens on the model and automatically updates the * selected index if, say, tabs are inserted before the currently selected tab. */ protected ModelListener modelListener = null; /** * A change listener which listens on the selection model and repaints as needed when * the selection changes. */ protected ChangeListener selectionListener = null; protected HierarchyListener hierarchyListener = null; /** * Creates a new instance of AbstractTabDisplayerUI */ public AbstractTabDisplayerUI(TabDisplayer displayer) { super(displayer); } /** installUI is final to ensure listeners, etc. are created and attached. Subclasses that * need to perform initialization on install should override install(), * and refer to the displayer instance field, which will be initialized here. * * @param c An instance of TabDisplayer */ public final void installUI(JComponent c) { assert c == displayer; super.installUI(c); //installs the selection model ToolTipManager.sharedInstance().registerComponent(displayer); layoutModel = createLayoutModel(); mouseListener = createMouseListener(); componentListener = createComponentListener(); modelListener = createModelListener(); propertyChangeListener = createPropertyChangeListener(); selectionListener = createSelectionListener(); hierarchyListener = createHierarchyListener(); install(); installListeners(); displayer.setFont(createFont()); } /** This method is final - subclasses that need to deinitialize should override * uninstall(), and remove any listeners, null any unneeded references, etc. * * @param c */ public final void uninstallUI(JComponent c) { assert c == displayer; ToolTipManager.sharedInstance().unregisterComponent(displayer); super.uninstallUI(c); // #47644 - first uninstallListeners, then uninstall, so that tabState can't be null while // listeners are active. Only probable fix, but certainly right thing to do. uninstallListeners(); uninstall(); layoutModel = null; mouseListener = null; selectionModel = null; componentListener = null; selectionListener = null; } /** * Called after creating the layout model, selection model and mouse * listener, but before installing the mouse listener and selection model. * Subclasses may use this method to do anything they need to do at ui * install time. */ protected void install() { //do nothing } /** * Called after uninstalling the mouse listener and selection model, but * before references to that or the layout model or displayer have been * nulled. Subclasses may use this method to do any cleanup they need to do * at uninstall time. */ protected void uninstall() { //do nothing } /** * Installs the mouse listener returned by createMouseListener into the * control. If the mouse listener implements MouseMotionListener or * MouseWheelListener, it will be installed as such as well. */ protected final void installListeners() { displayer.addHierarchyListener (hierarchyListener); displayer.addPropertyChangeListener(propertyChangeListener); if (componentListener != null) { displayer.addComponentListener(componentListener); } displayer.getModel().addComplexListDataListener(modelListener); displayer.getModel().addChangeListener(modelListener); if (mouseListener != null) { displayer.addMouseListener(mouseListener); if (mouseListener instanceof MouseMotionListener) { displayer.addMouseMotionListener( (MouseMotionListener) mouseListener); } if (mouseListener instanceof MouseWheelListener) { displayer.addMouseWheelListener((MouseWheelListener) mouseListener); } } selectionModel.addChangeListener(selectionListener); } /** * Installs the mouse listener returned by createMouseListener into the * control. If the mouse listener implements MouseMotionListener or * MouseWheelListener, it will be removed as such as well. */ protected final void uninstallListeners() { if (mouseListener instanceof MouseMotionListener) { displayer.removeMouseMotionListener( (MouseMotionListener) mouseListener); } if (mouseListener instanceof MouseWheelListener) { displayer.removeMouseWheelListener( (MouseWheelListener) mouseListener); } if (mouseListener != null) { displayer.removeMouseListener(mouseListener); } if (componentListener != null) { displayer.removeComponentListener(componentListener); } displayer.getModel().removeComplexListDataListener(modelListener); displayer.getModel().removeChangeListener(modelListener); displayer.removePropertyChangeListener(propertyChangeListener); displayer.removeHierarchyListener(hierarchyListener); selectionModel.removeChangeListener(selectionListener); mouseListener = null; componentListener = null; propertyChangeListener = null; selectionListener = null; modelListener = null; hierarchyListener = null; } protected HierarchyListener createHierarchyListener() { return new DisplayerHierarchyListener(); } /** * Create an instance of TabLayoutModel which will provide coordinates for * tabs */ protected abstract TabLayoutModel createLayoutModel(); //XXX move this to BasicTabDisplayerUI /** * Create the mouse listener that will be responsible for changing the * selection on mouse events, triggering repaints on mouse enter/exit/motion, etc. * The installation code will detect if the resulting listener also implements * MouseWheelListener or MouseMotionListener, and if so, will add it as such. * * @return A mouse listener, which may also implement MouseMotionListener and/or * MouseWheelListener */ protected abstract MouseListener createMouseListener(); /** * Create a ChangeListener to be attached to the selection model. This * listener will be responsible for repainting the appropriate areas on selection changes. * * @return A changeListener that will be notified of selection changes */ protected abstract ChangeListener createSelectionListener(); protected Font createFont() { return UIManager.getFont("controlFont"); //NOI18N } /** * Create a listener on the data model that triggers repaints on appropriate * changes. */ protected ModelListener createModelListener() { return new ModelListener(); } /** * Create a ComponentListener that may be needed to handle resize, show, * hide, etc. Returns null by default. */ protected ComponentListener createComponentListener() { return null; } /** * Create a PropertyChangeListener which listens on any interesting * properties of the control */ protected PropertyChangeListener createPropertyChangeListener() { return new DisplayerPropertyChangeListener(); } /** Creates an instance of DefaultTabSelectionModel */ protected SingleSelectionModel createSelectionModel() { return new DefaultTabSelectionModel(displayer.getModel()); } /** * A very basic implementation of dropIndexOfPoint, which simply iterates * all of the tab rectangles to see if they contain the point. It is * preferred to override this and provide a more efficient implementation * unless the UI is not designed to display more than a few tabs. * * @param p A point * @return The index, or -1 if none */ public int dropIndexOfPoint(Point p) { Point p2 = toDropPoint(p); int max = displayer.getModel().size(); for (int i=0; i < max; i++) { Rectangle r = getTabRect (i, null); if (r.contains(p2)) { return i; } } return -1; } /** Convenience method called by ModelListener.stateChanged() when the data model changes. * Eliminates the need for custom subclasses where the only purpose is to discard some * small amount of cached data. The default implementation simply calls displayer.repaint(). */ protected void modelChanged() { displayer.repaint(); } private Point scratchPoint = new Point(); /** Converts a point into a point in the coordinate space of the tabs area, for * determining what index a drop operation should affect. * * @param location A point in the coordinate space of the container * @return A point in the coordinate space of the tab display area */ protected Point toDropPoint (Point location) { //Construct a point within the tabs area retaining the relevant coordinate that //will allow it to work if (displayer.getWidth() > displayer.getHeight()) { //horizontal tabs area scratchPoint.setLocation(location.x, (displayer.getHeight() / 2)); } else { //vertical tabs area scratchPoint.setLocation (displayer.getWidth() / 2, location.y); } return scratchPoint; } /** Does nothing, no shortcuts */ public void unregisterShortcuts(JComponent comp) { // no operation } /** Does nothing, no shortcuts */ public void registerShortcuts(JComponent comp) { // no operation } /** * A property change listener which will repaint the selected tab when the * "active" property changes on the tab displayer */ protected class DisplayerPropertyChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent e) { if (displayer.isShowing() && TabDisplayer.PROP_ACTIVE.equals(e.getPropertyName())) { activationChanged(); } } /** * Called if PROP_ACTIVE on the displayer changes */ protected void activationChanged() { int i = selectionModel.getSelectedIndex(); if (i != -1) { Rectangle r = new Rectangle(); getTabRect(i, r); if (r.width != 0 && r.height != 0) { displayer.repaint(r.x, r.y, r.width, r.height); } } } } /** * A hierarchy listener which registers the component with ToolTipManager * when displayed, and de-registers it when hidden */ protected class DisplayerHierarchyListener implements HierarchyListener { public DisplayerHierarchyListener() { } public void hierarchyChanged(HierarchyEvent e) { if (e.getChanged() == displayer && (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) { if (displayer.isShowing()) { ToolTipManager.sharedInstance().registerComponent(displayer); } else { ToolTipManager.sharedInstance().unregisterComponent(displayer); } } } } /** * Simple implementation of a listener on a TabDataModel. The default implementation * simply does a full repaint of the tabs area on a ChangeEvent. More optimized * implementations are possible by handling ListDataEvents. */ protected class ModelListener implements ComplexListDataListener, ChangeListener { private boolean checkVisible = false; /** * No-op implementation */ public void contentsChanged(ListDataEvent e) { //do nothing } /** * No-op implementation */ public void indicesAdded(ComplexListDataEvent e) { //do nothing } /** * No-op implementation */ public void indicesChanged(ComplexListDataEvent e) { //do nothing } /** * No-op implementation */ public void indicesRemoved(ComplexListDataEvent e) { //do nothing } /** * No-op implementation */ public void intervalAdded(ListDataEvent e) { //do nothing } /** * No-op implementation */ public void intervalRemoved(ListDataEvent e) { //do nothing } /** * Called whenever any change happens in the data model (one of the above methods will also * be called with specific data about the change). This method is final, and simply calls * modelChanged(). To discard some cached data when the model changes, simply * override that. */ public final void stateChanged(ChangeEvent e) { modelChanged(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy