I'm thrilled to announce the next release of Metawidget will be fully compatible with Oracle Mojarra, the Java Server Faces Reference Implementation.
The Metawidget and Mojarra teams have been working hard to resolve long-standing issues (1313, 1383, 1402, 1414, 1717, 1826, 1972, 2231 and 2283) and ensure dynamic component manipulation is reliable and robust.
Here's a screenshot of Metawidget 2.4 running with Mojarra 2.1.7 and RichFaces 4:
Of course, these fixes will also benefit other component developers looking to use dynamic component manipulation in Mojarra. I blogged about the 'best practice' way to implement this here.
Huge thanks to everybody involved over the years, especially Ed Burns, Ryan Lubke, Roger Kitain and Manfred Riem!
Tuesday, July 24, 2012
Wednesday, July 4, 2012
Forge and Metawidget: Now With Added Prettiness
I've just refreshed the JBoss Forge Scaffolding Look & Feel (which uses Metawidget) based on work done by Cheyenne Weaver. We're now using Bootstrap to get lots of visual goodies with minimal additional code.
Thanks Cheyenne!
You can download a WAR for JBoss AS 7 here, or full source code here.
You can also compare to the previous Look & Feel here.
Thanks Cheyenne!
Tuesday, July 3, 2012
Metawidget: Collections Support (Nested Metawidgets)
A recent post on the forum started:
"I've written a WidgetBuilder to handle collections... [by using] Metawidget to produce a [nested Metawidget] component for each object in the collection..."
We've covered something like this before, but this time things were complicated by the need to support BeansBindingProcessor with both save and rebind.
Here's what we came up with (needs Metawidget 2.3):
package com.myapp;
import static org.metawidget.inspector.InspectionResultConstants.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.swing.*;
import org.metawidget.inspector.annotation.UiComesAfter;
import org.metawidget.swing.SwingMetawidget;
import org.metawidget.swing.widgetbuilder.SwingWidgetBuilder;
import org.metawidget.swing.widgetprocessor.binding.beansbinding.BeansBindingProcessor;
import org.metawidget.util.*;
import org.metawidget.widgetbuilder.composite.*;
import org.metawidget.widgetbuilder.iface.WidgetBuilder;
public class Application {
public static void main( final String[] args ) {
// Model
final Person homerSimpson = new Person( "Homer Simpson", "Bart", "Lisa",
"Maggie" );
final Person nedFlanders = new Person( "Ned Flanders", "Rod", "Todd" );
// UI
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
// Metawidget
final SwingMetawidget metawidget = new SwingMetawidget();
metawidget.setBorder( BorderFactory.createEmptyBorder( 5, 5, 5, 5 ) );
CompositeWidgetBuilderConfig<JComponent, SwingMetawidget> config = new CompositeWidgetBuilderConfig<JComponent, SwingMetawidget>();
config.setWidgetBuilders( new CollectionWidgetBuilder(),
new SwingWidgetBuilder() );
metawidget
.setWidgetBuilder( new CompositeWidgetBuilder<JComponent, SwingMetawidget>(
config ) );
metawidget.addWidgetProcessor( new CollectionBeansBindingProcessor() );
metawidget.setToInspect( homerSimpson );
frame.add( metawidget, BorderLayout.CENTER );
// Buttons
JButton rebindButton = new JButton( "Rebind" );
rebindButton.addActionListener( new ActionListener() {
@Override
public void actionPerformed( ActionEvent e ) {
try {
BeansBindingProcessor beansBindingProcessor = metawidget
.getWidgetProcessor( BeansBindingProcessor.class );
beansBindingProcessor.save( metawidget );
JOptionPane.showMessageDialog(
frame,
"Saved children as "
+ ( (Person) metawidget.getToInspect() )
.getChildren() );
beansBindingProcessor.rebind( nedFlanders, metawidget );
} catch ( Exception ex ) {
JOptionPane.showMessageDialog( frame, ex.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE );
return;
}
}
} );
JPanel buttonPanel = new JPanel();
buttonPanel.add( rebindButton );
frame.add( buttonPanel, BorderLayout.SOUTH );
frame.setSize( 400, 200 );
frame.setVisible( true );
}
//
// Model
//
public static class Person {
private String mName;
private List<Person> mChildren = CollectionUtils.newArrayList();
public Person( String name, String... children ) {
mName = name;
for ( String child : children ) {
mChildren.add( new Person( child ) );
}
}
public String getName() {
return mName;
}
public void setName( String name ) {
mName = name;
}
@UiComesAfter( "name" )
public List<Person> getChildren() {
return mChildren;
}
@Override
public String toString() {
return mName;
}
}
//
// Widget Builder
//
public static class CollectionWidgetBuilder
implements WidgetBuilder<JComponent, SwingMetawidget> {
@Override
public JComponent buildWidget( String elementName,
Map<String, String> attributes, SwingMetawidget metawidget ) {
// Not for us?
Class<?> clazz = WidgetBuilderUtils.getActualClassOrType(
attributes, null );
if ( clazz == null ) {
return null;
}
if ( !Collection.class.isAssignableFrom( clazz ) ) {
return null;
}
// Create nested Metawidgets
List<?> list = (List<?>) ClassUtils.getProperty(
metawidget.getToInspect(), attributes.get( NAME ) );
if ( list == null || list.isEmpty() ) {
return null;
}
JPanel panel = new JPanel();
panel.setLayout( new BoxLayout( panel, javax.swing.BoxLayout.Y_AXIS ) );
for ( Object child : list ) {
SwingMetawidget nestedMetawidget = new SwingMetawidget();
Map<String, String> emptyAttributes = Collections.emptyMap();
metawidget.initNestedMetawidget( nestedMetawidget,
emptyAttributes );
nestedMetawidget.setToInspect( child );
nestedMetawidget.setPath( child.getClass().getName() );
panel.add( nestedMetawidget );
}
return panel;
}
}
//
// Widget Processor
//
public static class CollectionBeansBindingProcessor
extends BeansBindingProcessor {
@Override
public JComponent processWidget( JComponent component,
String elementName, Map<String, String> attributes,
SwingMetawidget metawidget ) {
// Support nested widgets from the CollectionWidgetBuilder
if ( component instanceof JPanel ) {
getNestedPanels( metawidget ).put( attributes.get( NAME ),
(JPanel) component );
return component;
}
return super.processWidget( component, elementName, attributes,
metawidget );
}
@Override
public void save( SwingMetawidget metawidget ) {
super.save( metawidget );
// Nested save
for ( JPanel nestedPanel : getNestedPanels( metawidget ).values() ) {
for ( Component nestedComponent : nestedPanel.getComponents() ) {
if ( nestedComponent instanceof SwingMetawidget ) {
SwingMetawidget nestedMetawidget = (SwingMetawidget) nestedComponent;
save( nestedMetawidget );
}
}
}
}
@Override
public void rebind( Object toRebind, SwingMetawidget metawidget ) {
super.rebind( toRebind, metawidget );
// Cannot expect to rebind nestedPanels, so rebuild them instead
for ( Map.Entry<String, JPanel> entry : getNestedPanels( metawidget )
.entrySet() ) {
// Clear the panel
JPanel panel = entry.getValue();
panel.removeAll();
// Use a dummy Metawidget to create just the child Metawidgets
// of the Collection
SwingMetawidget dummyMetawidget = new SwingMetawidget();
Map<String, String> attributes = CollectionUtils.newHashMap();
attributes.put( NAME, entry.getKey() );
metawidget.initNestedMetawidget( dummyMetawidget, attributes );
// Copy them into our real Metawidget
for ( Component child : ( (JPanel) dummyMetawidget
.getComponent( 1 ) ).getComponents() ) {
panel.add( child );
}
}
metawidget.validate();
}
private Map<String, JPanel> getNestedPanels( SwingMetawidget metawidget ) {
Map<String, JPanel> nestedPanels = (Map<String, JPanel>) metawidget
.getClientProperty( CollectionBeansBindingProcessor.class );
if ( nestedPanels == null ) {
nestedPanels = CollectionUtils.newHashMap();
metawidget.putClientProperty(
CollectionBeansBindingProcessor.class, nestedPanels );
}
return nestedPanels;
}
}
}
import static org.metawidget.inspector.InspectionResultConstants.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.swing.*;
import org.metawidget.inspector.annotation.UiComesAfter;
import org.metawidget.swing.SwingMetawidget;
import org.metawidget.swing.widgetbuilder.SwingWidgetBuilder;
import org.metawidget.swing.widgetprocessor.binding.beansbinding.BeansBindingProcessor;
import org.metawidget.util.*;
import org.metawidget.widgetbuilder.composite.*;
import org.metawidget.widgetbuilder.iface.WidgetBuilder;
public class Application {
public static void main( final String[] args ) {
// Model
final Person homerSimpson = new Person( "Homer Simpson", "Bart", "Lisa",
"Maggie" );
final Person nedFlanders = new Person( "Ned Flanders", "Rod", "Todd" );
// UI
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
// Metawidget
final SwingMetawidget metawidget = new SwingMetawidget();
metawidget.setBorder( BorderFactory.createEmptyBorder( 5, 5, 5, 5 ) );
CompositeWidgetBuilderConfig<JComponent, SwingMetawidget> config = new CompositeWidgetBuilderConfig<JComponent, SwingMetawidget>();
config.setWidgetBuilders( new CollectionWidgetBuilder(),
new SwingWidgetBuilder() );
metawidget
.setWidgetBuilder( new CompositeWidgetBuilder<JComponent, SwingMetawidget>(
config ) );
metawidget.addWidgetProcessor( new CollectionBeansBindingProcessor() );
metawidget.setToInspect( homerSimpson );
frame.add( metawidget, BorderLayout.CENTER );
// Buttons
JButton rebindButton = new JButton( "Rebind" );
rebindButton.addActionListener( new ActionListener() {
@Override
public void actionPerformed( ActionEvent e ) {
try {
BeansBindingProcessor beansBindingProcessor = metawidget
.getWidgetProcessor( BeansBindingProcessor.class );
beansBindingProcessor.save( metawidget );
JOptionPane.showMessageDialog(
frame,
"Saved children as "
+ ( (Person) metawidget.getToInspect() )
.getChildren() );
beansBindingProcessor.rebind( nedFlanders, metawidget );
} catch ( Exception ex ) {
JOptionPane.showMessageDialog( frame, ex.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE );
return;
}
}
} );
JPanel buttonPanel = new JPanel();
buttonPanel.add( rebindButton );
frame.add( buttonPanel, BorderLayout.SOUTH );
frame.setSize( 400, 200 );
frame.setVisible( true );
}
//
// Model
//
public static class Person {
private String mName;
private List<Person> mChildren = CollectionUtils.newArrayList();
public Person( String name, String... children ) {
mName = name;
for ( String child : children ) {
mChildren.add( new Person( child ) );
}
}
public String getName() {
return mName;
}
public void setName( String name ) {
mName = name;
}
@UiComesAfter( "name" )
public List<Person> getChildren() {
return mChildren;
}
@Override
public String toString() {
return mName;
}
}
//
// Widget Builder
//
public static class CollectionWidgetBuilder
implements WidgetBuilder<JComponent, SwingMetawidget> {
@Override
public JComponent buildWidget( String elementName,
Map<String, String> attributes, SwingMetawidget metawidget ) {
// Not for us?
Class<?> clazz = WidgetBuilderUtils.getActualClassOrType(
attributes, null );
if ( clazz == null ) {
return null;
}
if ( !Collection.class.isAssignableFrom( clazz ) ) {
return null;
}
// Create nested Metawidgets
List<?> list = (List<?>) ClassUtils.getProperty(
metawidget.getToInspect(), attributes.get( NAME ) );
if ( list == null || list.isEmpty() ) {
return null;
}
JPanel panel = new JPanel();
panel.setLayout( new BoxLayout( panel, javax.swing.BoxLayout.Y_AXIS ) );
for ( Object child : list ) {
SwingMetawidget nestedMetawidget = new SwingMetawidget();
Map<String, String> emptyAttributes = Collections.emptyMap();
metawidget.initNestedMetawidget( nestedMetawidget,
emptyAttributes );
nestedMetawidget.setToInspect( child );
nestedMetawidget.setPath( child.getClass().getName() );
panel.add( nestedMetawidget );
}
return panel;
}
}
//
// Widget Processor
//
public static class CollectionBeansBindingProcessor
extends BeansBindingProcessor {
@Override
public JComponent processWidget( JComponent component,
String elementName, Map<String, String> attributes,
SwingMetawidget metawidget ) {
// Support nested widgets from the CollectionWidgetBuilder
if ( component instanceof JPanel ) {
getNestedPanels( metawidget ).put( attributes.get( NAME ),
(JPanel) component );
return component;
}
return super.processWidget( component, elementName, attributes,
metawidget );
}
@Override
public void save( SwingMetawidget metawidget ) {
super.save( metawidget );
// Nested save
for ( JPanel nestedPanel : getNestedPanels( metawidget ).values() ) {
for ( Component nestedComponent : nestedPanel.getComponents() ) {
if ( nestedComponent instanceof SwingMetawidget ) {
SwingMetawidget nestedMetawidget = (SwingMetawidget) nestedComponent;
save( nestedMetawidget );
}
}
}
}
@Override
public void rebind( Object toRebind, SwingMetawidget metawidget ) {
super.rebind( toRebind, metawidget );
// Cannot expect to rebind nestedPanels, so rebuild them instead
for ( Map.Entry<String, JPanel> entry : getNestedPanels( metawidget )
.entrySet() ) {
// Clear the panel
JPanel panel = entry.getValue();
panel.removeAll();
// Use a dummy Metawidget to create just the child Metawidgets
// of the Collection
SwingMetawidget dummyMetawidget = new SwingMetawidget();
Map<String, String> attributes = CollectionUtils.newHashMap();
attributes.put( NAME, entry.getKey() );
metawidget.initNestedMetawidget( dummyMetawidget, attributes );
// Copy them into our real Metawidget
for ( Component child : ( (JPanel) dummyMetawidget
.getComponent( 1 ) ).getComponents() ) {
panel.add( child );
}
}
metawidget.validate();
}
private Map<String, JPanel> getNestedPanels( SwingMetawidget metawidget ) {
Map<String, JPanel> nestedPanels = (Map<String, JPanel>) metawidget
.getClientProperty( CollectionBeansBindingProcessor.class );
if ( nestedPanels == null ) {
nestedPanels = CollectionUtils.newHashMap();
metawidget.putClientProperty(
CollectionBeansBindingProcessor.class, nestedPanels );
}
return nestedPanels;
}
}
}
Subscribe to:
Posts (Atom)