package com.xoetrope.svgscanner;
import java.awt.HeadlessException;
import java.awt.Component;
import java.awt.Color;
import java.awt.Point;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.File;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.FileWriter;
import java.util.EventObject;
import java.util.Vector;
import java.util.Collection;
import java.util.Collections;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JFileChooser;
import javax.swing.JColorChooser;
import javax.swing.JDialog;
import javax.swing.JPopupMenu;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
import javax.swing.colorchooser.AbstractColorChooserPanel;
import com.xoetrope.swing.XCheckCombo;
import com.xoetrope.svgscanner.model.SynthModel;
import com.xoetrope.svgscanner.model.SynthElementHandler;
import com.xoetrope.svgscanner.wizard.BindingWizard;
import com.xoetrope.swing.wizard.XWizard;
import com.xoetrope.swing.list.XAltListCellRenderer;
import net.xoetrope.xui.XPage;
import net.xoetrope.xui.style.XStyle;
import net.xoetrope.swing.XEdit;
import net.xoetrope.swing.XCheckbox;
import net.xoetrope.swing.XComboBox;
import net.xoetrope.swing.XList;
import net.xoetrope.swing.XLabel;
import net.xoetrope.swing.XPanel;
import net.xoetrope.swing.XScrollPane;
import net.xoetrope.xui.data.XModel;
import net.xoetrope.xml.XmlElement;
import com.xoetrope.helper.AFileFilter;
import net.xoetrope.xui.data.XModelHelper;
import net.xoetrope.xui.helper.XuiUtilities;
import net.xoetrope.editor.color.ColorWheelPanel;
import net.xoetrope.editor.XEditorUtilities;
import net.xoetrope.optional.annotation.Find;
import net.xoetrope.xml.XmlElement;
import net.xoetrope.xml.nanoxml.NanoXmlElement;
import net.xoetrope.xml.nanoxml.NanoXmlWriter;
/**
*
* <p> Copyright (c) Xoetrope Ltd., 2001-2007, This software is licensed under
* the GNU Public License (GPL), please see license.txt for more details. If
* you make commercial use of this software you must purchase a commercial
* license from Xoetrope.</p>
* <p>$Revision: 1.7 $</p>
*/
public class SynthBindings extends XPage implements ActionListener
{
@Find
private XList bindingList, stateList, propertiesList;
@Find
private XScrollPane propertiesScroller;
@Find
private XLabel propertiesLabel;
@Find
private XEdit styleNameEdit;
@Find
private XCheckCombo stateValueCombo;
@Find
private XPanel cardPanel;
private SynthModel synthModel;
private XmlElement bindingElement;
private XmlElement styleElement; // List 1 selection
private XmlElement stateElement; // List 2 selection
private XmlElement propertyElement; // List 3 selection
private XmlElement objectElement; // Property sheet object
private SynthElementHandler synthElementHandler;
private JComponent focusObject;
private Footer footer;
private String[] styleElements = { "property", "defaultsProperty", "state", "font", "graphicsUtils", "insets", "painter", "imagePainter", "opaque", "inputMap", "iamgeIcon", "beansPersistence" };
private String[] stateElements = { "font", "color", "painter", "imagePainter", "beansPersistence" };
private String[] defaultList = { "default" };
private XList sourceList;
public SynthBindings()
{
synthModel = (SynthModel)((XModel)rootModel.get( "SynthModel" )).get();
}
public void pageCreated()
{
XStyle style = project.getStyleManager().getStyle( "list/alt" );
XAltListCellRenderer renderer = new XAltListCellRenderer();
renderer.setAltUnselectedColors( style.getStyleAsColor( XStyle.COLOR_FORE ), style.getStyleAsColor( XStyle.COLOR_BACK ));
bindingList.setCellRenderer( renderer );
stateList.setCellRenderer( renderer );
propertiesList.setCellRenderer( renderer );
}
public void pageActivated( )
{
footer = (Footer)pageMgr.getPage( "Footer" );
footer.setNext( "ImageViewer" );
}
public void bindingChanged()
{
// Store the style name in case it has chnaged
styleNameChanged();
stateList.removeAll();
bindingElement = styleElement = stateElement = null;
String selection = (String)bindingList.getSelectedObject();
if ( selection != null ) {
bindingElement = synthModel.getBinding( selection );
if ( bindingElement == null ) {
JOptionPane.showMessageDialog( this, "The selected binding key is not in use in the current look and feel" );
styleNameEdit.setText( "" );
propertiesScroller.setEnabled( false );
propertiesLabel.setEnabled( false );
stateValueCombo.setEnabled( false );
objectElement = null;
updateObjectEditor();
return;
}
else {
String styleName = bindingElement.getAttribute( "style" );
styleElement = synthModel.getStyle( styleName ).element;
styleNameEdit.setText( styleElement.getAttribute( "id" ));
SynthModel.CrossReferenceElement styleXref = synthModel.getStyle( styleName );
Vector styleElements = styleXref.element.getChildren();
for ( Object obj : styleElements ) {
XmlElement xmlElement = (XmlElement)obj;
String name = xmlElement.getName();
SynthElementHandler seh = synthModel.getElementHandler( name );
String styleElementName = seh.getName( xmlElement );
stateList.addItem( styleElementName );
}
stateList.setSelectedIndex( 0 );
}
}
}
public void stateChanged()
{
// Store the state value in case it has changed
stateValueChanged();
propertiesList.removeAll();
stateElement = propertyElement = null;
int selIdx = stateList.getSelectedIndex();
if ( selIdx >= 0 ) {
stateElement = (XmlElement)styleElement.getChildren().elementAt( selIdx );
String propertyName = stateElement.getName();
boolean isState = propertyName.equals( "state" );
propertiesScroller.setEnabled( isState );
propertiesList.setEnabled( isState );
propertiesLabel.setEnabled( isState );
stateValueCombo.setEnabled( isState );
if ( isState ) {
stateValueCombo.setSelectedItem( stateElement.getAttribute( "value" ));
Vector propertyElements = stateElement.getChildren();
for ( Object sobj : propertyElements ) {
XmlElement sxmlElement = (XmlElement)sobj;
propertiesList.addItem( sxmlElement.getName());
}
propertiesList.setSelectedIndex( 0 );
}
else {
objectElement = stateElement;
stateElement = null;
stateValueCombo.clearSelection();
}
}
else
stateValueCombo.clearSelection();
updateObjectEditor();
}
public void propertyChanged()
{
int selIdx = propertiesList.getSelectedIndex();
if ( selIdx >= 0 )
objectElement = propertyElement = (XmlElement)stateElement.getChildren().elementAt( selIdx );
updateObjectEditor();
}
public void updateObjectEditor()
{
// If we are switching components the last edit field being edited may not have saved its value
if ( focusObject != null ) {
String compName = focusObject.getName();
String attribName = getAttribute( "attrib", compName ).toString();
if ( attribName == null )
return;
if ( focusObject instanceof XEdit )
synthElementHandler.setAttribute( attribName, ((XEdit)focusObject).getText());
focusObject = null;
}
synthElementHandler = null;
CardLayout cm = (CardLayout)cardPanel.getLayout();
if ( objectElement == null )
cm.show( cardPanel, "none" );
else {
String objectType = objectElement.getName();
String objectTypeLwr = objectType.toLowerCase();
cm.show( cardPanel, objectType );
synthElementHandler = SynthModel.getElementHandler( objectType );
if ( synthElementHandler != null ) {
synthElementHandler.setObject( objectElement );
synthElementHandler.updateUI( this );
}
else
cm.show( cardPanel, "none" );
}
}
/**
* Find an image
*/
public void imageFinder()
{
try {
String compName = ((Component)getCurrentEvent().getSource()).getName();
compName = getAttribute( "edit", compName ).toString();
XEdit edit = (XEdit)findComponent( compName );
String currentRes = edit.getText();
JFileChooser chooser = new JFileChooser();
AFileFilter myFilter = new AFileFilter( "svg", "SVG files" );
myFilter.setDirMustExist( true );
myFilter.setFileMustExist( true );
chooser.setDialogTitle( "Please specify the location of the SVG file" );
chooser.setFileFilter( myFilter );
chooser.setFileSelectionMode( chooser.FILES_ONLY );
chooser.setMultiSelectionEnabled( false );
String sourceFolder = XModelHelper.getString( rootModel, "sourceFolder" );
if ( sourceFolder.length() > 0 )
chooser.setCurrentDirectory( new File( sourceFolder ));
if ( chooser.showOpenDialog( this ) == JFileChooser.APPROVE_OPTION ) {
File selectedFile = chooser.getSelectedFile();
String canonicalPath = chooser.getSelectedFile().getCanonicalPath();
String parentPath = selectedFile.getParent();
if ( canonicalPath.contains( sourceFolder )) {
String fileName = canonicalPath.substring( parentPath.length() + 1 );
edit.setText( fileName );
String attribName = getAttribute( "attrib", compName ).toString();
synthElementHandler.setAttribute( attribName, fileName );
}
}
}
catch ( Exception ex )
{
ex.printStackTrace();
}
}
/**
* Find a color
*/
public void colorFinder()
{
try {
String compName = ((Component)getCurrentEvent().getSource()).getName();
compName = getAttribute( "edit", compName ).toString();
final XEdit edit = (XEdit)findComponent( compName );
final String attribName = getAttribute( "attrib", compName ).toString();
String selectedColor = edit.getText();
if ( selectedColor.startsWith( "#" ))
selectedColor = selectedColor.substring( 1 );
Color clr = (Color)XStyle.parseColor( selectedColor );
final JColorChooser colorChooser = new JColorChooser();
AbstractColorChooserPanel[] oldPanels = colorChooser.getChooserPanels();
AbstractColorChooserPanel[] newPanels = new AbstractColorChooserPanel[ oldPanels.length + 1 ];
System.arraycopy( oldPanels, 0, newPanels, 1, oldPanels.length );
newPanels[ 0 ] = new ColorWheelPanel();
colorChooser.setChooserPanels( newPanels );
//colorChooser.addChooserPanel( new ColorWheelPanel());
colorChooser.setColor( clr );
XEditorUtilities.setDefaultFont( colorChooser );
JDialog dialog = JColorChooser.createDialog(
this,
"Choose the new Color",
true,
colorChooser,
new ActionListener()
{
public void actionPerformed( ActionEvent e )
{
Color newColor = colorChooser.getColor();
String colorValue = "#" + XuiUtilities.colorToHexString( newColor );
// int r = newColor.getRed();
// int g = newColor.getGreen();
// int b = newColor.getBlue();
// int a = newColor.getAlpha();
// String colorValue = "#" +
// (( r < 16 ) ? "0" : "" ) + Integer.toString( r, 16 ) +
// (( g < 16 ) ? "0" : "" ) + Integer.toString( g, 16 ) +
// (( b < 16 ) ? "0" : "" ) + Integer.toString( b, 16 ) +
// (( a < 16 ) ? "0" : "" ) + ( a != 255 ? Integer.toString( a, 16 ) : "" );
edit.setText( colorValue );
synthElementHandler.setAttribute( attribName, colorValue );
}
}, null
);
XuiUtilities.centerOnScreen( dialog );
dialog.setVisible( true );
}
catch ( Exception ex )
{
ex.printStackTrace();
}
}
/**
* Store the value of the field associated with the event
*/
public void storeValue()
{
focusObject = null;
if ( synthElementHandler == null )
return;
EventObject eo = getCurrentEvent();
Component comp = (Component)eo.getSource();
String compName = comp.getName();
String attribName = getAttribute( "attrib", compName ).toString();
if ( attribName == null )
return;
if ( comp instanceof XEdit ) {
if (( eo instanceof FocusEvent ) && (((FocusEvent)eo).getID() == FocusEvent.FOCUS_LOST ))
synthElementHandler.setAttribute( attribName, ((XEdit)comp).getText());
else
focusObject = (JComponent)comp;
}
else if ( comp instanceof XCheckbox )
synthElementHandler.setAttribute( attribName, ((XCheckbox)comp).isSelected() ? "true" : "false" );
else if ( comp instanceof XComboBox ) {
Object selObj = ((XComboBox)comp).getSelectedItem();
if ( selObj != null )
synthElementHandler.setAttribute( attribName, selObj.toString());
}
}
/**
* The style name has changed
*/
public void styleNameChanged()
{
EventObject eo = getCurrentEvent();
if ( styleElement != null ) {
if ( !( eo instanceof FocusEvent ) || (((FocusEvent)eo).getID() == FocusEvent.FOCUS_LOST )) {
String oldStyleName = styleElement.getAttribute( "id" );
String value = styleNameEdit.getText();
if ( !value.equals( oldStyleName )) {
styleElement.setAttribute( "id", value );
bindingElement.setAttribute( "style", value );
// Update all usages
SynthModel.CrossReferenceElement styleXref = synthModel.getStyle( oldStyleName );
styleXref.id = value;
for ( String usage : styleXref.usages ) {
XmlElement binding = synthModel.getBinding( usage );
binding.setAttribute( "style", value );
}
}
}
}
}
/**
* The style name has changed
*/
public void stateValueChanged()
{
EventObject eo = getCurrentEvent();
if ( stateElement != null ) {
Object selObj = stateValueCombo.getEditor().getItem();
String newValue = selObj == null ? null : selObj.toString();
String oldValue = stateElement.getAttribute( "value" );
if ( newValue != null ) {
if ( !newValue.equals( oldValue ))
stateElement.setAttribute( "value", newValue );
}
else {
if ( oldValue != null )
stateElement.setAttribute( "value", null );
}
}
}
public void generateXml()
{
try {
String outputFolder = XModelHelper.getString( project, rootModel, "outputFolder" );
FileWriter fw = new FileWriter( new File( outputFolder + File.separator + "test.synth" ));
Writer writer = new BufferedWriter( fw );
NanoXmlWriter xmlWriter = new NanoXmlWriter( writer );
XmlElement synthElement = synthModel.getXml();
xmlWriter.write( synthElement, true, 4 );
writer.flush();
writer.close();
fw.close();
showMessage( "XML Generated", "You can find the generated XML at: " + outputFolder + File.separator + "test.synth" );
return;
}
catch ( IOException ex ) {
System.out.println( "Error generating file" );
}
}
public void showBindingsMenu()
{
sourceList = bindingList;
MouseEvent me = (MouseEvent)getCurrentEvent();
if ( me.isPopupTrigger()) {
JPopupMenu popupMenu = new JPopupMenu( "Bindings" );
JMenuItem mi = new JMenuItem( "Add binding key..." );
mi.addActionListener( this );
popupMenu.add( mi );
if ( bindingList.getSelectedIndex() >= 0 ){
popupMenu.addSeparator();
mi = new JMenuItem( "Delete" );
mi.addActionListener( this );
popupMenu.add( mi );
}
Point pt = me.getPoint();
Point vp = bindingList.getLocation();
vp = SwingUtilities.convertPoint( (Component)me.getSource(), 0, 0, bindingList );
popupMenu.show( bindingList, pt.x + vp.x, pt.y + vp.y );
}
}
public void showStylesMenu()
{
sourceList = stateList;
MouseEvent me = (MouseEvent)getCurrentEvent();
if ( me.isPopupTrigger()) {
JPopupMenu popupMenu = new JPopupMenu( "Styles" );
JMenuItem mi = null;
for ( String s : styleElements ) {
mi = new JMenuItem( "Add " + s + "..." );
mi.addActionListener( this );
mi.setActionCommand( s );
popupMenu.add( mi );
}
if ( stateList.getSelectedIndex() >= 0 ){
popupMenu.addSeparator();
mi = new JMenuItem( "Delete" );
mi.addActionListener( this );
popupMenu.add( mi );
}
Point pt = me.getPoint();
Point vp = stateList.getLocation();
vp = SwingUtilities.convertPoint( (Component)me.getSource(), 0, 0, stateList );
popupMenu.show( stateList, pt.x + vp.x, pt.y + vp.y );
}
}
public void showStatesMenu()
{
sourceList = propertiesList;
MouseEvent me = (MouseEvent)getCurrentEvent();
if ( me.isPopupTrigger() && sourceList.isEnabled()) {
JPopupMenu popupMenu = new JPopupMenu( "Properties" );
JMenuItem mi = null;
for ( String s : stateElements ) {
mi = new JMenuItem( "Add " + s + "..." );
mi.addActionListener( this );
mi.setActionCommand( s );
popupMenu.add( mi );
}
if ( propertiesList.getSelectedIndex() >= 0 ){
popupMenu.addSeparator();
mi = new JMenuItem( "Delete" );
mi.addActionListener( this );
popupMenu.add( mi );
}
Point pt = me.getPoint();
Point vp = propertiesList.getLocation();
vp = SwingUtilities.convertPoint( (Component)me.getSource(), 0, 0, propertiesList );
popupMenu.show( propertiesList, pt.x + vp.x, pt.y + vp.y );
}
}
public void actionPerformed( ActionEvent ae )
{
String cmd = ae.getActionCommand();
if ( cmd.equals( "Add binding key..." )) {
String[] pages = { "wizard/bindingKeyWizard", "wizard/stylesWizard" };
BindingWizard wizard = new BindingWizard( project, pages, true );
wizard.setCaption( "<html><b>New binding wizard</b></html>");
wizard.setSize( 600, 300 );
wizard.showDialog( this );
updateBoundComponentValues();
}
else if ( cmd.equals( "Delete" )) {
}
else {
String binding = bindingElement.getAttribute( "key" );
String[] options = getOptions( binding, cmd );
String res = null;
if (( options == null ) || ( options.length == 0 ))
options = defaultList;
res = (String)JOptionPane.showInputDialog( sourceList,
"Choose your options",
"Available " + cmd + " options",
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[ 0 ] );
if ( res == null )
return;
if ( res.equals( options[ 0 ] ))
res = null;
if ( sourceList == stateList ) {
addState( styleElement, binding, cmd, res );
bindingChanged();
}
else if ( sourceList == propertiesList ) {
addState( stateElement, binding, cmd, res );
stateChanged();
}
}
}
private String[] getOptions( String bindingKey, String type )
{
XModel options = (XModel)rootModel.get( "bindingKeys/" + bindingKey + "/" + type );
String attrib = XModelHelper.getAttrib( options, "key" );
if ( attrib == null )
return new String[ 0 ];
if ( attrib.length() == 0 )
attrib = "value";
int numChildren = options.getNumChildren();
String[] res = new String[ numChildren ];
for ( int i = 0; i < numChildren; i++ ) {
res[ i ] = (String)XModelHelper.getAttrib( options.get( i ), attrib );
}
return res;
}
private void addState( XmlElement parent, String bindingKey, String type, String value )
{
XModel options = (XModel)rootModel.get( "bindingKeys/" + bindingKey + "/" + type );
NanoXmlElement newStateElement = new NanoXmlElement( type );
parent.addChild( newStateElement );
if ( value == null )
return;
String attrib = XModelHelper.getAttrib( options, "key" );
if ( attrib == null )
return;
if ( attrib.length() == 0 )
attrib = "value";
int numChildren = options.getNumChildren();
for ( int i = 0; i < numChildren; i++ ) {
XModel childNode = options.get( i );
String keyValue = (String)XModelHelper.getAttrib( childNode, attrib );
if ( value.equals( keyValue )) {
int numAttribs = childNode.getNumAttributes();
for ( int j = 0; j < numAttribs; j++ )
newStateElement.setAttribute( childNode.getAttribName( j ), childNode.getAttribValue( j ).toString());
return;
}
}
return;
}
}
|