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 8743 2012-10-07 03:06:20Z 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 final class BlockingDispatcher 131 implements Serializable, KeyEventDispatcher 132 { 133 134 /** Creates a new {@code BlockingDispatcher} instance. */ 135 private BlockingDispatcher() 136 { 137 super(); 138 } 139 140 public boolean dispatchKeyEvent( final KeyEvent e ) 141 { 142 final Component source = e.getComponent(); 143 144 if ( source != null && 145 SwingUtilities.isDescendingFrom( source, getParent() ) && 146 e.getID() == KeyEvent.KEY_TYPED ) 147 { 148 UIManager.getLookAndFeel().provideErrorFeedback( getParent() ); 149 e.consume(); 150 } 151 152 return e.isConsumed(); 153 } 154 } 155 /** 156 * Container this component is registered as the glasspane with. 157 * @serial 158 */ 159 private final RootPaneContainer container; 160 161 /** 162 * {@code KeyEventDispatcher} used for blocking keyboard interaction. 163 * @serial 164 */ 165 private final KeyEventDispatcher keyDispatcher; 166 167 /** 168 * Cursor to use when blocking is in effect. 169 * @serial 170 */ 171 private Cursor cursor; 172 173 /** 174 * Creates a new {@code BlockingGlassPane} instance taking the container 175 * this component is registered with. 176 * 177 * @param container the container this component is registered with. 178 * 179 * @throws NullPointerException if {@code container} is {@code null}. 180 */ 181 public BlockingGlassPane( final RootPaneContainer container ) 182 { 183 super(); 184 185 if ( container == null ) 186 { 187 throw new NullPointerException( "container" ); 188 } 189 190 this.container = container; 191 this.keyDispatcher = new BlockingDispatcher(); 192 super.setVisible( false ); 193 this.setOpaque( false ); 194 this.addMouseListener( 195 new MouseAdapter() 196 { 197 198 public void mouseClicked( final MouseEvent e ) 199 { 200 UIManager.getLookAndFeel(). 201 provideErrorFeedback( getParent() ); 202 203 } 204 } ); 205 206 } 207 208 /** 209 * Creates a new {@code BlockingGlassPane} instance taking the container 210 * this component is registered with and the cursor to use when blocking is 211 * in effect. 212 * 213 * @param container the container this component is registered with. 214 * @param cursor the cursor to use when blocking is in effect. 215 * 216 * @throws NullPointerException if either {@code container} or 217 * {@code cursor} is {@code null}. 218 */ 219 public BlockingGlassPane( final RootPaneContainer container, 220 final Cursor cursor ) 221 { 222 this( container ); 223 224 if ( cursor == null ) 225 { 226 throw new NullPointerException( "cursor" ); 227 } 228 229 this.cursor = cursor; 230 } 231 232 /** 233 * Gets the cursor used when blocking is in effect. 234 * @return the cursor used when blocking is in effect. 235 */ 236 private Cursor getBlockingCursor() 237 { 238 if ( this.cursor == null ) 239 { 240 this.cursor = Cursor.getPredefinedCursor( 241 this.getDefaultCursorType().intValue() ); 242 243 } 244 245 return this.cursor; 246 } 247 248 //-------------------------------------------------------BlockingGlassPane-- 249}