001/* 002 * jDTAUS Core Utilities 003 * Copyright (C) 2005 Christian Schulte 004 * <cs@schulte.it> 005 * 006 * This library is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 2.1 of the License, or any later version. 010 * 011 * This library is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with this library; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 019 * 020 */ 021package org.jdtaus.core.swing.util; 022 023import java.awt.Component; 024import java.awt.Cursor; 025import java.awt.KeyEventDispatcher; 026import java.awt.KeyboardFocusManager; 027import java.awt.event.KeyEvent; 028import java.awt.event.MouseAdapter; 029import java.awt.event.MouseEvent; 030import java.io.Serializable; 031import javax.swing.JComponent; 032import javax.swing.RootPaneContainer; 033import javax.swing.SwingUtilities; 034import javax.swing.UIManager; 035import org.jdtaus.core.container.ContainerFactory; 036 037/** 038 * {@code JComponent} for use as a blocking glasspane. 039 * <p>Blocking is controlled by property {@code visible}. If {@code true}, 040 * the current look and feel's 041 * {@link javax.swing.LookAndFeel#provideErrorFeedback(Component) 042 * provideErrorFeedback} method is called whenever a mouse clicked 043 * {@code MouseEvent}, or a {@code KeyEvent} of type 044 * {@link KeyEvent#KEY_TYPED KEY_TYPED}, whose source is not {@code null} and 045 * descending from the parent of this component, is received. Also the cursor is 046 * set to the cursor to use when blocking is in effect. If {@code false}, the 047 * cursor is reset to the system's default cursor and no more blocking is 048 * performed. Property {@code visible} defaults to {@code false}.</p> 049 * 050 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 051 * @version $JDTAUS: BlockingGlassPane.java 8641 2012-09-27 06:45:17Z schulte $ 052 */ 053public final class BlockingGlassPane extends JComponent 054{ 055 //--Properties-------------------------------------------------------------- 056 057// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausProperties 058 // This section is managed by jdtaus-container-mojo. 059 060 /** 061 * Gets the value of property <code>defaultCursorType</code>. 062 * 063 * @return Default cursor used when blocking is in effect. 064 */ 065 private java.lang.Integer getDefaultCursorType() 066 { 067 return (java.lang.Integer) ContainerFactory.getContainer(). 068 getProperty( this, "defaultCursorType" ); 069 070 } 071 072// </editor-fold>//GEN-END:jdtausProperties 073 074 //--------------------------------------------------------------Properties-- 075 //--JComponent-------------------------------------------------------------- 076 077 /** 078 * Enables or disables blocking. 079 * <p>This method registers a {@code KeyEventDispatcher} with AWT's current 080 * {@code KeyboardFocusManager} blocking the keyboard for any user 081 * interaction and updates the cursor to the cursor to use when blocking is 082 * in effect if {@code visible} is {@code true}. If {@code visible} is 083 * {@code false} the {@code KeyEventDispatcher} is removed and the cursor is 084 * reset to the system's default cursor.</p> 085 * 086 * @param visible {@code true} to enable blocking; {@code false} to disable 087 * blocking. 088 */ 089 public void setVisible( final boolean visible ) 090 { 091 final Runnable runnable = new Runnable() 092 { 093 094 public void run() 095 { 096 if ( visible ) 097 { 098 BlockingGlassPane.super.setVisible( true ); 099 setCursor( getBlockingCursor() ); 100 KeyboardFocusManager.getCurrentKeyboardFocusManager(). 101 addKeyEventDispatcher( keyDispatcher ); 102 103 } 104 else 105 { 106 KeyboardFocusManager.getCurrentKeyboardFocusManager(). 107 removeKeyEventDispatcher( keyDispatcher ); 108 109 setCursor( Cursor.getDefaultCursor() ); 110 BlockingGlassPane.super.setVisible( false ); 111 container.getContentPane().validate(); 112 } 113 } 114 }; 115 116 if ( !SwingUtilities.isEventDispatchThread() ) 117 { 118 SwingUtilities.invokeLater( runnable ); 119 } 120 else 121 { 122 runnable.run(); 123 } 124 } 125 126 //--------------------------------------------------------------JComponent-- 127 //--BlockingGlassPane------------------------------------------------------- 128 129 /** {@code KeyEventDispatcher} used for blocking. */ 130 private class BlockingDispatcher implements Serializable, 131 KeyEventDispatcher 132 { 133 134 public boolean dispatchKeyEvent( final KeyEvent e ) 135 { 136 final Component source = e.getComponent(); 137 138 if ( source != null && 139 SwingUtilities.isDescendingFrom( source, getParent() ) && 140 e.getID() == KeyEvent.KEY_TYPED ) 141 { 142 UIManager.getLookAndFeel().provideErrorFeedback( getParent() ); 143 e.consume(); 144 } 145 146 return e.isConsumed(); 147 } 148 } 149 /** 150 * Container this component is registered as the glasspane with. 151 * @serial 152 */ 153 private final RootPaneContainer container; 154 155 /** 156 * {@code KeyEventDispatcher} used for blocking keyboard interaction. 157 * @serial 158 */ 159 private final KeyEventDispatcher keyDispatcher; 160 161 /** 162 * Cursor to use when blocking is in effect. 163 * @serial 164 */ 165 private Cursor cursor; 166 167 /** 168 * Creates a new {@code BlockingGlassPane} instance taking the container 169 * this component is registered with. 170 * 171 * @param container the container this component is registered with. 172 * 173 * @throws NullPointerException if {@code container} is {@code null}. 174 */ 175 public BlockingGlassPane( final RootPaneContainer container ) 176 { 177 super(); 178 179 if ( container == null ) 180 { 181 throw new NullPointerException( "container" ); 182 } 183 184 this.container = container; 185 this.keyDispatcher = new BlockingDispatcher(); 186 super.setVisible( false ); 187 this.setOpaque( false ); 188 this.addMouseListener( 189 new MouseAdapter() 190 { 191 192 public void mouseClicked( final MouseEvent e ) 193 { 194 UIManager.getLookAndFeel(). 195 provideErrorFeedback( getParent() ); 196 197 } 198 } ); 199 200 } 201 202 /** 203 * Creates a new {@code BlockingGlassPane} instance taking the container 204 * this component is registered with and the cursor to use when blocking is 205 * in effect. 206 * 207 * @param container the container this component is registered with. 208 * @param cursor the cursor to use when blocking is in effect. 209 * 210 * @throws NullPointerException if either {@code container} or 211 * {@code cursor} is {@code null}. 212 */ 213 public BlockingGlassPane( final RootPaneContainer container, 214 final Cursor cursor ) 215 { 216 this( container ); 217 218 if ( cursor == null ) 219 { 220 throw new NullPointerException( "cursor" ); 221 } 222 223 this.cursor = cursor; 224 } 225 226 /** 227 * Gets the cursor used when blocking is in effect. 228 * @return the cursor used when blocking is in effect. 229 */ 230 private Cursor getBlockingCursor() 231 { 232 if ( this.cursor == null ) 233 { 234 this.cursor = Cursor.getPredefinedCursor( 235 this.getDefaultCursorType().intValue() ); 236 237 } 238 239 return this.cursor; 240 } 241 242 //-------------------------------------------------------BlockingGlassPane-- 243}