1// BEGIN LICENSE BLOCK 2// Version: CMPL 1.1 3// 4// The contents of this file are subject to the Cisco-style Mozilla Public 5// License Version 1.1 (the "License"); you may not use this file except 6// in compliance with the License. You may obtain a copy of the License 7// at www.eclipse-clp.org/license. 8// 9// Software distributed under the License is distributed on an "AS IS" 10// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 11// the License for the specific language governing rights and limitations 12// under the License. 13// 14// The Original Code is The ECLiPSe Constraint Logic Programming System. 15// The Initial Developer of the Original Code is Cisco Systems, Inc. 16// Portions created by the Initial Developer are 17// Copyright (C) 2006 Cisco Systems, Inc. All Rights Reserved. 18// 19// Contributor(s): 20// 21// END LICENSE BLOCK 22 23package com.parctechnologies.eclipse.visualisation; 24 25import javax.swing.*; 26import java.beans.*; 27import java.lang.reflect.*; 28 29/** 30 * This is a "bridging" class between some java beans classes 31 * (PropertyChangeSupport, PropertyDescriptor etc) and the swing JToggleButton 32 * class. The idea is to have a clean way of providing toggle buttons that 33 * accurately control and reflect the state of a named boolean property of some 34 * object.<p> 35 * The way it works is that the "propertyHolder" has a boolean property such 36 * that: 37 * <ul> 38 * <li> The property has a name propertyName (such as "autoResume") 39 * <li> The propertyHolder has public get/set methods which obey the conventional 40 * get/set naming pattern e.g. (public boolean getAutoResume(); public void 41 * setAutoResume(boolean)). 42 * <li> There is a PropertyChangeSupport object which "observes" the boolean 43 * property, in that a PropertyChangeEvent is sent to all its listeners when 44 * the boolean property changes value. 45 * </ul> 46 * We can then construct a BooleanPropertyModel given the property's name, and 47 * references to the propertyHolder and the observing PropertyChangeSupport. 48 * This BooleanPropertyModel is a subclass of JToggleButton.ToggleButtonModel 49 * and so can be used as the underlying model of any swing JToggleButton. 50 */ 51public class BooleanGroupPropertyModel extends JToggleButton.ToggleButtonModel 52 implements PropertyChangeListener 53{ 54 // PropertyDescriptor is a beans class which handles the necessary 55 // reflection to work with the get/set methods of the property. 56 private PropertyDescriptor propertyDescriptor; 57 private Object propertyHolder; 58 59 // Hold the value of the property which this model should consider true 60 private Object match; 61 62 public BooleanGroupPropertyModel(String propertyName, Object propertyHolder, 63 PropertyChangeSupport propertyChangeSupport, 64 Object match) 65 { 66 super(); 67 this.match = match; 68 PropertyDescriptor pd; 69 try 70 { 71 pd = new PropertyDescriptor(propertyName, 72 propertyHolder.getClass()); 73 } 74 catch(IntrospectionException ie) 75 { 76 throw(new RuntimeException("Exception thrown: "+ie)); 77 } 78 this.propertyHolder = propertyHolder; 79 setSelected(match.equals(getValue(pd))); 80 this.propertyDescriptor = pd; 81 propertyChangeSupport.addPropertyChangeListener(propertyName, this); 82 } 83 84 /** 85 * This propertyChange method means that the ButtonModel's setSelected method 86 * will be invoked if anything changes the property setting. 87 */ 88 public void propertyChange(PropertyChangeEvent event) 89 { 90 Object newValue = event.getNewValue(); 91 boolean isMatch = (newValue.equals(match)); 92 if(isSelected() != isMatch) 93 { 94 setSelected(isMatch); 95 } 96 } 97 98 /** 99 * setSelected extends the behaviour of the parent class by invoking the 100 * propertyHolder's writeMethod. 101 */ 102 public void setSelected(boolean newValue) 103 { 104 super.setSelected(newValue); 105 // check that it has been initialised 106 if((propertyDescriptor != null) && newValue) 107 { 108 Method writeMethod = propertyDescriptor.getWriteMethod(); 109 Object[] args = new Object[1]; 110 111 args[0] = match; 112 try 113 { 114 if (DebuggingSupport.logMessages) { 115 DebuggingSupport.logMessage(this, "BooleanGroupPropertyModel invoking " + writeMethod); 116 } 117 writeMethod.invoke(propertyHolder, args); 118 } 119 catch(IllegalAccessException iae) 120 {throw (new RuntimeException("Exception thrown: "+iae));} 121 catch(InvocationTargetException ite) 122 { 123 ite.printStackTrace(); 124 throw (new RuntimeException("Exception thrown: "+ite.getTargetException()));} 125 } 126 } 127 128 /** 129 * The getValue method is used when the BooleanPropertyModel is first 130 * initialised. It is invoked in order to discover the initial value of the 131 * property, which is done by invoking the getMethod. 132 */ 133 private Object getValue(PropertyDescriptor pd) 134 { 135 Method readMethod = pd.getReadMethod(); 136 Object[] args = new Object[0]; 137 138 Object result; 139 140 try 141 { 142 result = readMethod.invoke(propertyHolder, args); 143 } 144 catch(IllegalAccessException iae) 145 {throw (new RuntimeException("Exception thrown: "+iae));} 146 catch(InvocationTargetException ite) 147 {throw (new RuntimeException("Exception thrown: "+ite));} 148 return(result); 149 } 150 151} 152