/** * * Copyright * 2009-2015 Jayway Products AB * 2016-2017 Föreningen Sambruk * * Licensed under AGPL, Version 3.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.gnu.org/licenses/agpl.txt * * 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. */ package se.streamsource.streamflow.client.util; import org.jdesktop.application.ResourceMap; import org.jdesktop.swingx.JXDatePicker; import org.jdesktop.swingx.JXDialog; import org.jdesktop.swingx.util.WindowUtils; import org.qi4j.api.constraint.ConstraintViolationException; import org.qi4j.api.injection.scope.Uses; import se.streamsource.streamflow.client.ui.administration.AdministrationResources; import se.streamsource.streamflow.client.ui.workspace.cases.general.RemovableLabel; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.InputVerifier; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPasswordField; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.text.JTextComponent; import java.awt.Component; import java.awt.Dialog; import java.awt.Frame; import java.awt.Window; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.ResourceBundle; /** * Bind components to actions, which are invoked when the components state is updated */ public class ActionBinder { ResourceBundle errorMessages; List<Binder> binders = new ArrayList<Binder>(); private final ActionMap actionMap; public ActionBinder( @Uses ActionMap actionMap ) { this.actionMap = actionMap; Binder defaultBinder = new DefaultBinder( ); registerBinder( defaultBinder); errorMessages = ResourceBundle.getBundle( getClass().getName() ); } public void setResourceMap( final ResourceMap resourceMap ) { errorMessages = new ResourceBundle() { protected Object handleGetObject( String key ) { return resourceMap.getString( key ); } public Enumeration<String> getKeys() { return Collections.enumeration( resourceMap.keySet() ); } }; } public void registerBinder( Binder binder ) { binders.add( binder ); } public <T extends Component> T bind( String name, T component ) { Component boundComponent = component; if (boundComponent instanceof JScrollPane) { boundComponent = ((JScrollPane)boundComponent).getViewport().getView(); } Action action = actionMap.get( name ); if (action == null) throw new IllegalArgumentException( "No action named '" + name + "' in action map" ); for (Binder binder : binders) { if (binder.bind( boundComponent, action )) { return component; } } throw new IllegalArgumentException( "No binder registered for component type:" + component.getClass().getSimpleName() ); } public interface Binder { boolean bind( Component component, Action action ); } private class DefaultBinder implements Binder { public DefaultBinder() { } public boolean bind( Component component, final Action action ) { if (component instanceof JPasswordField) { final JPasswordField passwordField = (JPasswordField) component; passwordField.setInputVerifier( new ActionInputVerifier( action ) ); } else if (component instanceof JTextField) { final JTextField textField = (JTextField) component; textField.setInputVerifier( new ActionInputVerifier( action ) ); } else if (component instanceof JTextComponent) { final JTextComponent textComponent = (JTextComponent) component; textComponent.setInputVerifier( new ActionInputVerifier( action ) ); } else if (component instanceof AbstractButton) { final AbstractButton button = (AbstractButton) component; if (component instanceof StreamflowJXColorSelectionButton) { button.addPropertyChangeListener( "background", new PropertyChangeListener() { public void propertyChange( PropertyChangeEvent e ) { action.actionPerformed( new ActionEvent(button, ActionEvent.ACTION_PERFORMED, action.getValue( Action.NAME ).toString()) ); } } ); } else { button.addActionListener( action ); } } else if (component instanceof JXDatePicker) { final JXDatePicker datePicker = (JXDatePicker) component; datePicker.addPropertyChangeListener( new PropertyChangeListener() { public void propertyChange( PropertyChangeEvent e ) { if ("date".equals( e.getPropertyName() )) { action.actionPerformed( new ActionEvent(datePicker, ActionEvent.ACTION_PERFORMED, action.getValue( Action.NAME ).toString()) ); } } } ); }else if (component instanceof JComboBox) { final JComboBox comboBox = (JComboBox) component; comboBox.addActionListener( action ); } else if (component instanceof RemovableLabel) { final RemovableLabel removableLabel = (RemovableLabel) component; removableLabel.getButton().addActionListener( action ); } else return false; return true; } } class ActionInputVerifier extends InputVerifier { private final Action action; ActionInputVerifier( Action action ) { this.action = action; } Exception exception; public boolean verify( JComponent input ) { try { action.actionPerformed( new ActionEvent(input, ActionEvent.ACTION_PERFORMED, action.getValue( Action.NAME ).toString()) ); return true; } catch (Exception e) { exception = e; return false; } } @Override public boolean shouldYieldFocus( JComponent input ) { boolean result = super.shouldYieldFocus( input ); if (!result) { Window window = WindowUtils.findWindow( input ); StringBuilder message = new StringBuilder( i18n.text( AdministrationResources.invalid_value ) ); if (exception instanceof ConstraintViolationException) { ConstraintViolationException ex = (ConstraintViolationException) exception; String[] messages = ex.getLocalizedMessages( errorMessages ); message = new StringBuilder( "<html>" ); for (String s : messages) { message.append( "<p>" ).append( s ).append( "</p>" ); } message.append( "</html>" ); } else { message.append( exception.getMessage() ); } JLabel main = new JLabel( message.toString() ); JXDialog dialog; if (window instanceof Frame) dialog = new JXDialog( (Frame) window, main ); else dialog = new JXDialog( (Dialog) window, main ); dialog.setModal( true ); dialog.pack(); dialog.setLocationRelativeTo( SwingUtilities.windowForComponent( input ) ); dialog.setVisible( true ); } return result; } } }