All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.cuf.ui.SwingMapping Maven / Gradle / Ivy

The newest version!
/**************************************************************************
 *  P A C K A G E                                                         *
 **************************************************************************/

package net.sf.cuf.ui;

/**************************************************************************/

/**************************************************************************
 *  I M P O R T S                                                         *
 **************************************************************************/

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.awt.Component;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.JViewport;

/**************************************************************************/

/**************************************************************************
 *  C L A S S E S                                                         *
 **************************************************************************/

/**************************************************************************/
/**
 * SwingMapping generates a string mapping for a tree of JComponent's.
 * 

* This mapping is build upon the name property: starting from the root, * all elements in the component tree that have a a non-null name property * (all their parents must also have a non-null name property!) are * mapped to name by concatenating the names of all components on the * path separated with a "/".
* As a special case, a Viewport inside a ScrollPane is silently skipped
* After a mapping was constructed, components can be accessed by name, e.g. * "myPanel/subPanel/okButton".
*

* As a very useful feature ".." can be used inside a name to navigate to * another component, e.g. * "myPanel/subPanel/okButton/../textField" can be used to access a * the component "textField" that is also a child of "subPanel". * With this feature, it is very easy to access the "needed" components * inside an ActionEvent callback. * In addition to the hierarcical namespace a flat (but not uniq) namespace * is provided. * * @author Jürgen Zeller, [email protected] */ public class SwingMapping { /** Separator of component names. */ private static final String SEPARATOR= "/"; /** Non-null root of our mapped tree. */ private JComponent mRoot; /** * mNameToComponent maps the full qualified name to a JComponent. * key : SEPARATOR separated String of JComponent name's * value: the matching JComponent */ private Map mNameToComponent; /** * mShortNameToComponent maps the non-hierarchical (short) name * to a component. * key: name * value: the matching JComponent */ private Map mShortNameToComponent; /** * mComponentToName does the reverse mapping of mNameToComponent. * key : a JComponent inside mRoot * value: the matching SEPARATOR separated String */ private Map mComponentToName; /** * This factory method creates a new SwingMapping, starting from the handed * root component. * * @param pRoot the root component * @return a new SwingMapping * @throws IllegalArgumentException if the names inside the component are not * uniq or pRoot is null */ public static SwingMapping createMapping(final JComponent pRoot) { if (pRoot==null) { throw new IllegalArgumentException( "SwingMapping.createMapping(): pRoot must not be null"); } SwingMapping mapping= new SwingMapping(pRoot); mapping.addMapping("", pRoot); return mapping; } /** * This method returns null or the component matching the handed name * after resolving ".." shortcuts. * * @param pName component name (may be null), inside the * name all ".."'s are resolved first, so it is o.k. to * use "somePanel/someButton/../someTextField" to get * from any component to any other. * @return null or the component that matches the (resolved) name * @throws IllegalArgumentException the name is not resolvable due too many ".."'s */ public JComponent getComponentByName(final String pName) { // null maps always to null if (pName==null) { return null; } String name; // check if we need the ".." resolving at all if (!pName.contains("..")) { name= pName; } else { // the following code does the ".." resolving StringTokenizer tokenizer = new StringTokenizer(pName, SEPARATOR); List list = new ArrayList(tokenizer.countTokens()); int stackCount= 0; while (tokenizer.hasMoreTokens()) { String token= tokenizer.nextToken(); if ("..".equals(token)) { // pop stackCount--; if (stackCount<0) { throw new IllegalArgumentException( pName + ": contains more ..'s than elements"); } list.remove(stackCount); } else { // push list.add(token); stackCount++; } } StringBuilder nameBuffer = new StringBuilder(); for (int i= 0, n= list.size(); i < n; i++) { nameBuffer.append(list.get(i)); if (i < n-1) { nameBuffer.append(SEPARATOR); } } name= nameBuffer.toString(); } // name now contains the resolved name, the Map will either return // null or the matching compontent return mNameToComponent.get(name); } /** * This method returns null or the component matching the handed * short name. If there is more than one component with that short * name, it is undefined which is return. * @param pName component short name (may be null) * @return null or the component that matches the (resolved) name */ public JComponent getByShortName(final String pName) { return mShortNameToComponent.get(pName); } /** * This method returns the full qualified name of the handed component. * * @param pComponent the component we want the name for * @return null or the full qualified name of the component. * @throws IllegalArgumentException if pComponent is not inside the hierarchy * the SwingMapping object was created with */ public String getNameByComponent(final JComponent pComponent) { if (!SwingUtilities.isDescendingFrom(pComponent, mRoot)) { throw new IllegalArgumentException(pComponent + " doesn't descend from " + mRoot); } return mComponentToName.get(pComponent); } /** * toString() generates a line-by-line description of all mappings, * separated with " = " and containing first the full mapping name * and second the class name of the mapped to object. * * @return complete map that is described with this mapping object */ public String toString() { StringBuilder sb = new StringBuilder(); for (final Map.Entry entry : mNameToComponent.entrySet()) { sb.append(entry.getKey()); sb.append(" = "); sb.append(entry.getValue().getClass().getName()); sb.append(System.getProperty("line.separator")); } return sb.toString(); } /** * SwingMapping has a private constructor, because all instances are * provided by the createMapping() factory methods, that also does the * error checking. * * @param pRoot the (non-null!) component tree root */ private SwingMapping(final JComponent pRoot) { super(); mRoot = pRoot; mNameToComponent = new HashMap<>(); mShortNameToComponent= new HashMap<>(); mComponentToName = new HashMap<>(); } /** * This method recursivly adds all named components. * * @param pPrefix the concatenate name of our parents * @param pNode the current examined node * @throws IllegalArgumentException if the names inside the component are not * uniq after concatenating them together */ private void addMapping(final String pPrefix, final JComponent pNode) { String myName = pNode.getName(); Component[] children= pNode.getComponents(); boolean hasName = (myName!=null); boolean isScrollPane= (pNode instanceof JViewport); if ((hasName || isScrollPane) && children!=null) { String newPrefix; if (isScrollPane) { newPrefix= pPrefix; } else { String fullName= pPrefix+myName; if (mNameToComponent.containsKey(fullName)) { throw new IllegalArgumentException( "SwingMapping: name inconsistancy detected for " + fullName); } mNameToComponent. put(fullName, pNode); mShortNameToComponent.put(myName, pNode); mComponentToName. put(pNode, fullName); newPrefix= fullName+SEPARATOR; } for (final Component aChildren : children) { if (aChildren instanceof JComponent) { addMapping(newPrefix, (JComponent) aChildren); } } } } } /**************************************************************************/





© 2015 - 2025 Weber Informatics LLC | Privacy Policy