/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. * * Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. */ package org.netbeans.modules.ruby.spi.project.support.rake.ui; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.swing.ButtonModel; import javax.swing.JToggleButton; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.PlainDocument; import org.netbeans.modules.ruby.spi.project.support.rake.PropertyEvaluator; import org.openide.util.EditableProperties; /** Serves as utility class for storing Swing models into project * properties. Usefull for creating project customizers. <CODE>StoreGroup</CODE> * is capable of doing two things: First create the representation of the project properties which * can be used in the GUI. Second at some time convert the objects back to the ANT properties form and * store them into the project properties.<br> * <b>For creating the object representation.</b> * <ol> * <li>Create new instance of StoreGroup for each group of properties you want to store later * e.g. project and private. Sometimes it might be useful to create temporary source group * which will only be used for creating the models without being used for storing. E.g. * for properties which need special handling.</li> * <li>Call the factory methods e.g. {@link #createToggleButtonModel}, {@link #createStringDocument}, etc. which * will create the swing models for you.</li> * <li>Use the models in your Swing controls by calling <CODE>setModel()</CODE> or <CODE>setDocument()</CODE></li> * </ol> * <b>For storing the models back to the proprties of project.</b> * <ol> * <li>Get the EditableProperties you want to store the model in e.g. private or project * properties</li> * <li>Call the store method on given <CODE>SourceGroup<CODE> with the {@link EditableProperties} as parameter</li> * <li>Manually store models which need some special handling.</li> * </ol> * * @author Petr Hrebejk */ public class StoreGroup { /** The object array serves as holder for various information about models * first is always the model. The rest depends on the model type * 1) Button model kind, inverted * 2) String model (not used) */ private Map<String,Object[]> models; private Set<Document> modifiedDocuments; private static final int BOOLEAN_KIND_TF = 0; private static final int BOOLEAN_KIND_YN = 1; private static final int BOOLEAN_KIND_ED = 2; private DocumentListener documentListener = new DocumentListener () { public void insertUpdate(DocumentEvent e) { documentModified (e.getDocument()); } public void removeUpdate(DocumentEvent e) { documentModified (e.getDocument()); } public void changedUpdate(DocumentEvent e) { documentModified (e.getDocument()); } }; public StoreGroup() { models = new HashMap<String,Object[]>(); modifiedDocuments = new HashSet<Document>(); } // Public methods ------------------------------------------------------------------------------------------ /** Stores all models created in the StoreGroup into given * EditableProperties. * @param editableProperties The properties where to store the * values. */ public void store( EditableProperties editableProperties ) { for (Map.Entry<String,Object[]> entry : models.entrySet()) { String key = entry.getKey(); Object[] params = entry.getValue(); if ( params[0] instanceof ButtonModel ) { ButtonModel model = (ButtonModel)params[0]; boolean value = model.isSelected(); if ( params[2] == Boolean.TRUE ) { value = !value; } editableProperties.setProperty( key, encodeBoolean( value, (Integer)params[1] ) ); } else if ( params[0] instanceof Document && modifiedDocuments.contains(params[0])) { Document doc = (Document)params[0]; String txt; try { txt = doc.getText(0, doc.getLength()); } catch (BadLocationException e) { txt = ""; // NOI18N } editableProperties.setProperty( key, txt ); } } } /** Creates toggle button model representing a boolean in the StoreGroup. <BR> * In case the value is one of "true", "yes" "on" the button model * will be "selected". If the property does not exist or is set * to some other value the result of isPressed will be false.<BR> * Call to the store() method stores the model in appropriate form * e.g "true/false", "yes/no", "on/off".<BR> * Method will throw <CODE>IllegalArgumentException</CODE> if you try to get more * than one model for one property. * @param evaluator The PropertyEvaluator to be used to evaluate given * property * @param propertyName Name of the ANT property * @return ButtonModel representing the value */ public final JToggleButton.ToggleButtonModel createToggleButtonModel( PropertyEvaluator evaluator, String propertyName ) { return createBooleanButtonModel( evaluator, propertyName, false ); } /** Creates toggle button model representing a boolean in the StoreGroup. <BR> * In case the value is one of "true", "yes" "on" the button model * will NOT be "selcted". If the property does not exist or is set * to some other value the result of isPressed will be true.<BR> * Call to the store() method stores the model in appropriate form * e.g "true/false", "yes/no", "on/off".<BR> * Method will throw <CODE>IllegalArgumentException</CODE> if you try to get more * than one model for one property. * @param evaluator The PropertyEvaluator to be used to evaluate given * property * @param propertyName Name of the ANT property * @return ButtonModel representing the value */ public final JToggleButton.ToggleButtonModel createInverseToggleButtonModel( PropertyEvaluator evaluator, String propertyName ) { return createBooleanButtonModel( evaluator, propertyName, true ); } /** Creates Document containing the string value of given property. * If the property does not extsts or the value of it is null the * resulting document will be empty.<BR> * Method will throw <CODE>IllegalArgumentException</CODE> if you try to get more * than one model for one property. * @param evaluator The PropertyEvaluator to be used to evaluate given * property * @param propertyName Name of the ANT property * @return ButtonModel representing the value */ public final Document createStringDocument( PropertyEvaluator evaluator, String propertyName ) { checkModelDoesNotExist( propertyName ); String value = evaluator.getProperty( propertyName ); if ( value == null ) { value = ""; // NOI18N } try { Document d = new PlainDocument(); d.remove(0, d.getLength()); d.insertString(0, value, null); d.addDocumentListener (documentListener); models.put( propertyName, new Object[] { d } ); return d; } catch ( BadLocationException e ) { assert false : "Bad location exception from new document."; // NOI18N return new PlainDocument(); } } // Private methods ----------------------------------------------------------------------------------------- private void checkModelDoesNotExist( String propertyName ) { if ( models.get( propertyName ) != null ) { throw new IllegalArgumentException( "Model for property " + propertyName + "already exists." ); } } private final JToggleButton.ToggleButtonModel createBooleanButtonModel( PropertyEvaluator evaluator, String propName, boolean invert ) { checkModelDoesNotExist( propName ); String value = evaluator.getProperty( propName ); boolean isSelected = false; Integer kind = BOOLEAN_KIND_TF; if ( value != null ) { String lowercaseValue = value.toLowerCase(); if ( lowercaseValue.equals( "yes" ) || lowercaseValue.equals( "no" ) ) { // NOI18N kind = BOOLEAN_KIND_YN; } else if ( lowercaseValue.equals( "on" ) || lowercaseValue.equals( "off" ) ) { // NOI18N kind = BOOLEAN_KIND_ED; } if ( lowercaseValue.equals( "true") || // NOI18N lowercaseValue.equals( "yes") || // NOI18N lowercaseValue.equals( "on") ) {// NOI18N isSelected = true; } } JToggleButton.ToggleButtonModel bm = new JToggleButton.ToggleButtonModel(); bm.setSelected( invert ? !isSelected : isSelected ); models.put(propName, new Object[] {bm, kind, invert}); return bm; } private static String encodeBoolean( boolean value, Integer kind ) { if ( kind == BOOLEAN_KIND_ED ) { return value ? "on" : "off"; // NOI18N } else if ( kind == BOOLEAN_KIND_YN ) { // NOI18N return value ? "yes" : "no"; } else { return value ? "true" : "false"; // NOI18N } } private void documentModified (Document d) { this.modifiedDocuments.add (d); } }