r1560 - in branches/jaxx-2.X: jaxx-compiler/src/main/java/jaxx/tags/swing jaxx-demo/src/main/java/jaxx/demo/component/jaxx jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree jaxx-runtime/src/main/java/jaxx/runtime jaxx-runtime/src/main/java/jaxx/runtime/decorator jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing jaxx-runtime/src/main/java/jaxx/runtime/swing jaxx-runtime/src/main/java/jaxx/runtime/swing/tree jaxx-runtime/src/test/java/jaxx/runtime jaxx-runtime/src/test/java/jaxx/runti
Author: tchemit Date: 2009-10-05 21:16:52 +0200 (Mon, 05 Oct 2009) New Revision: 1560 Added: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/tags/swing/JAXXComboBoxHandler.java branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/ branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/BaseContent.jaxx branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/FullNavigationTreeDemo.jaxx branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/FullNavigationTreeHelper.java branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/Movie.java branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/People.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/Decorator.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/DecoratorUtils.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/JXPathDecorator.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/MultiJXPathDecorator.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/PropertyDecorator.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing/ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing/DecoratorListCellRenderer.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing/DecoratorTableCellRenderer.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeContextHelper.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHandler.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHandlerWithCardLayout.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHelper.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeModel.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeModelBuilder.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNode.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRenderer.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRendererDecoratorImpl.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRendererI18nImpl.java branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/package.html branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/ branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/Data.java branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/JXPathDecoratorTest.java branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/MultiJXPathDecoratorTest.java branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/swing/tree/ branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/swing/tree/NavigationTreeModelTest.java branches/jaxx-2.X/jaxx-widgets/src/main/resources/i18n/jaxx-widgets-en_GB.properties branches/jaxx-2.X/jaxx-widgets/src/main/resources/i18n/jaxx-widgets-fr_FR.properties branches/jaxx-2.X/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/plugin/ComboBoxTest.java branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/error.xml branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/error/ branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/error/swingcombo.jaxx branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok.xml branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok/ branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok/jaxxcombo.jaxx branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok/swingcombo.jaxx Log: simplify modules + refactor NavigationTree and Decorator api + add real JComboBox tag handler (incompatible with JAXX 1.X) Added: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/tags/swing/JAXXComboBoxHandler.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/tags/swing/JAXXComboBoxHandler.java (rev 0) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/tags/swing/JAXXComboBoxHandler.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,62 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.Item; +import jaxx.runtime.swing.JAXXComboBox; +import jaxx.tags.DefaultComponentHandler; +import jaxx.types.TypeManager; +import org.w3c.dom.Element; + +import java.awt.event.ItemListener; +import java.io.IOException; +import java.util.List; + +public class JAXXComboBoxHandler extends DefaultComponentHandler { + + public JAXXComboBoxHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JAXXComboBox.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getSelectedIndex", ItemListener.class); + addProxyEventInfo("getSelectedItem", ItemListener.class); + } + + @Override + protected CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledItemContainer(id, getBeanClass(), compiler); + } + + @Override + public void compileChildrenSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + super.compileChildrenSecondPass(tag, compiler); + CompiledItemContainer list = (CompiledItemContainer) compiler.getOpenComponent(); + List<Item> items = list.getItems(); + if (items != null && !items.isEmpty()) { + String listName = list.getId() + "$items"; + list.appendAdditionCode("java.util.List<jaxx.runtime.swing.Item> " + listName + " = new java.util.ArrayList<jaxx.runtime.swing.Item>();"); + for (Item item : items) { + String id = item.getId(); + CompiledObject compiledItem = new CompiledObject(id, ClassDescriptorLoader.getClassDescriptor(Item.class), compiler); + compiledItem.setConstructorParams(TypeManager.getJavaCode(id) + ", " + TypeManager.getJavaCode(item.getLabel()) + ", " + TypeManager.getJavaCode(item.getValue()) + ", " + item.isSelected()); + compiler.registerCompiledObject(compiledItem); + list.appendAdditionCode(listName + ".add(" + id + ");"); + } + list.appendAdditionCode(list.getId() + ".setItems(" + listName + ");"); + } + } +} + + + Property changes on: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/tags/swing/JAXXComboBoxHandler.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/BaseContent.jaxx =================================================================== --- branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/BaseContent.jaxx (rev 0) +++ branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/BaseContent.jaxx 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,99 @@ +<!-- + *##% + jaxx-demo + Copyright (C) 2008 - 2009 CodeLutin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + ##%* +--> +<JPanel layout='{new BorderLayout()}'> + + <Object id='data' javaBean='helper.getSelectedBean(this)'/> + + <script><![CDATA[ +import jaxx.runtime.SwingUtil; + +private final FullNavigationTreeHelper helper = new FullNavigationTreeHelper(); + +String getType(Object data) { + if (data == null) { + return "no type"; + } + if (data instanceof java.util.List<?>) { + java.util.List<?> l = (java.util.List<?>) data; + if (l.isEmpty()) { + return "Empty collection"; + } + return "Collection of " + l.size() + " " + l.get(0).getClass().getSimpleName() + "(s)"; + } + return data.getClass().getSimpleName(); +} + +String getContent(Object data) { + if (data == null) { + return "no content"; + } + StringBuilder buffer = new StringBuilder(); + if (data instanceof java.util.List) { + for (Object o : ((java.util.List)data)) { + buffer.append(o).append("\n"); + } + } else { + buffer.append(data); + } + return buffer.toString(); +} + +ImageIcon getImage(Object data) { + if (data == null) { + return null; + } + if (data instanceof Movie) { + return SwingUtil.createIcon(((Movie)data).getImage()); + } + if (data instanceof People) { + return SwingUtil.createIcon(((People)data).getImage()); + } + return null; +} + ]]> + </script> + + <JSplitPane id='splitPane' + orientation='{JSplitPane.VERTICAL_SPLIT}' + resizeWeight='0.5' + constraints='BorderLayout.CENTER' + oneTouchExpandable='true'> + + <JScrollPane border='{null}' + horizontalScrollBarPolicy='{JScrollPane.HORIZONTAL_SCROLLBAR_NEVER}' + verticalScrollBarPolicy='{JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED}'> + <JTextPane border='{new TitledBorder("Content Type : " + getType(getData()))}' + editable='false' + font-size='11' + text='{getContent(getData())}'/> + </JScrollPane> + + <JScrollPane border='{new TitledBorder("Picture")}' + horizontalScrollBarPolicy='{JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED}' + verticalScrollBarPolicy='{JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED}' + minimumSize='{SwingUtil.newMinDimension()}'> + + <JLabel horizontalAlignment='center' icon='{getImage(getData())}'/> + + </JScrollPane> + + </JSplitPane> +</JPanel> \ No newline at end of file Added: branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/FullNavigationTreeDemo.jaxx =================================================================== --- branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/FullNavigationTreeDemo.jaxx (rev 0) +++ branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/FullNavigationTreeDemo.jaxx 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,82 @@ +<!-- + *##% + jaxx-demo + Copyright (C) 2008 - 2009 CodeLutin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + ##%* +--> + +<jaxx.demo.DemoPanel> + + <jaxx.runtime.swing.CardLayout2 id='contentLayout' + useOnlyVisibleComponentDimension='true'/> + + <script><![CDATA[ +import jaxx.runtime.SwingUtil; + +private final FullNavigationTreeHelper helper = new FullNavigationTreeHelper(); + +helper.createModel(this); + +@Override +protected String[] getSources() { + return new String[]{ getDefaultSource(), "BaseContent.jaxx", "FullNavigationTreeHelper.java", "Movie.java", "People.java" }; +} + +private void $afterCompleteSetup() { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + navigation.setSelectionInterval(0, 0); + splitPane.resetToPreferredSizes(); + } + }); + // expand the tree + SwingUtil.expandTree(navigation); + // auto-expand node when selected + SwingUtil.addExpandOnClickListener(navigation); +} + ]]> + </script> + + <JPanel id='demoPanel' layout='{new BorderLayout()}'> + + <JSplitPane id='splitPane' + constraints='BorderLayout.CENTER' + oneTouchExpandable='true'> + + <JScrollPane border='{null}' + horizontalScrollBarPolicy='{JScrollPane.HORIZONTAL_SCROLLBAR_NEVER}' + verticalScrollBarPolicy='{JScrollPane.VERTICAL_SCROLLBAR_NEVER}'> + + <JTree id="navigation" + font-size='11' + rootVisible='false' + showsRootHandles='false' + model='{helper.createTreeModel(this)}' + selectionModel="{helper.createTreeHandler(this)}"/> + <!--cellRenderer='{new NavigationTreeCellRenderer(this, 150)}' />--> + + </JScrollPane> + + <JPanel id="content" layout="{contentLayout}" /> + + </JSplitPane> + + </JPanel> + +</jaxx.demo.DemoPanel> Added: branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/FullNavigationTreeHelper.java =================================================================== --- branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/FullNavigationTreeHelper.java (rev 0) +++ branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/FullNavigationTreeHelper.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,244 @@ +/* + * *##% + * jaxx-demo + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * ##%* + */ +package jaxx.demo.component.jaxx.tree; + +import java.util.Arrays; + +import static jaxx.runtime.JAXXContextEntryDef.newListDef; +import static org.nuiton.i18n.I18n._; + +import java.util.List; +import jaxx.runtime.decorator.Decorator; +import jaxx.runtime.JAXXContext; + + +import javax.swing.JPanel; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.decorator.DecoratorUtils; +import jaxx.runtime.swing.CardLayout2; +import jaxx.runtime.swing.ErrorDialogUI; +import jaxx.runtime.swing.tree.NavigationTreeHandler; +import jaxx.runtime.swing.tree.NavigationTreeHandler.Strategy; +import jaxx.runtime.swing.tree.NavigationTreeHandlerWithCardLayout; +import jaxx.runtime.swing.tree.NavigationTreeHelper; +import jaxx.runtime.swing.tree.NavigationTreeModelBuilder; +import jaxx.runtime.swing.tree.NavigationTreeNode; +import jaxx.runtime.swing.tree.NavigationTreeModel; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author chemit + * @since 1.7.2 + */ +public class FullNavigationTreeHelper extends NavigationTreeHelper { + + static { + // register decorator one for all + + DecoratorUtils.register( + Movie.class.getSimpleName(), + DecoratorUtils.newMultiJXPathDecorator(Movie.class, "${title}$s##${year}$s", "##", " - ")); + + DecoratorUtils.register( + People.class.getSimpleName(), + DecoratorUtils.newMultiJXPathDecorator(People.class, "${firstName}$s##${lastName}$s", "##", " ")); + } + /** + * Logger + */ + static private final Log log = LogFactory.getLog(FullNavigationTreeHelper.class); + /** + * where the movies are hold in context + */ + static public final JAXXContextEntryDef<List<Movie>> MOVIES = JAXXContextEntryDef.newListDef("movies"); + /** + * where the actors are hold in context + */ + static public final JAXXContextEntryDef<List<People>> ACTORS = JAXXContextEntryDef.newListDef("actors"); + + public FullNavigationTreeHelper() { + super("full"); + } + + /** + * Create the model and store it in the given context. + * + * @param context the context where to hold the model + */ + public void createModel(JAXXContext context) { + People a = new People("0", "Jack", "Black", 0, "/jaxx/demo/images/jack.jpg"); + People a2 = new People("1", "Héctor", "Jiménez", 0, "/jaxx/demo/images/hector.jpg"); + People a3 = new People("2", "Ana", "de la Reguera", 0, "/jaxx/demo/images/ana.jpg"); + + Movie m = new Movie("0", "Nacho libre", 1996, "/jaxx/demo/images/nacho.jpg"); + m.addActor(a); + m.addActor(a2); + m.addActor(a3); + + Movie m2 = new Movie("1", "Nacho 2", 2009, "/jaxx/demo/images/nacho2.png"); + m2.addActor(a); + m2.addActor(a2); + + MOVIES.setContextValue(context, Arrays.asList(m, m2)); + ACTORS.setContextValue(context, Arrays.asList(a, a2, a3)); + } + + @Override + public NavigationTreeModel createTreeModel(JAXXContext context) { + + List<Movie> movies = MOVIES.getContextValue(context); + List<People> actors = ACTORS.getContextValue(context); + + if (log.isDebugEnabled()) { + log.debug("for " + movies.size() + " movie(s)"); + } + + NavigationTreeModelBuilder builder = new NavigationTreeModelBuilder("/", context, BaseContent.class, + null); + + Decorator<Movie> mDecorator = DecoratorUtils.get(Movie.class.getSimpleName()); + Decorator<People> pDecorator = DecoratorUtils.get(People.class.getSimpleName()); + + // construction du noeud root + // il ne contient pas de context et ne sera pas visible + NavigationTreeNode rootNode = builder.buildEmptyRoot(null, "$root"); + + // construction du noeud avec les films recupere la liste des films + // dans le context avec la clef movies + // navigation path = $root/movies + NavigationTreeNode moviesNode = builder.build( + rootNode, + _("movies"), + newListDef("movies"), + "movies", + null, + null); + + for (Movie m : movies) { + + // navigation path = $root/movies/m.id + NavigationTreeNode movieNode = builder.build( + moviesNode, + mDecorator, + "..[@id=\"" + m.getId() + "\"]", + m.getId(), + null, + null); + + // navigation path = $root/movies/m.id/actors + NavigationTreeNode actorsNode = builder.build( + movieNode, + _("actors"), + "../actors", + "actors", + null, + null); + + for (People p : m.getActors()) { + // navigation path = $root/movies/m.id/actors/p.id + builder.build( + actorsNode, + pDecorator, + "..[@id=\"" + p.getId() + "\"]", + p.getId(), + null, + null); + } + } + + // construction du noeud avec les acteurs + NavigationTreeNode actorsNode = builder.build(rootNode, _("actors"), + newListDef("actors"), + "actors", null, null); + + for (People p : actors) { + // navigation path = $root/actors/p.id + builder.build( + actorsNode, + pDecorator, + "..[@id=\"" + p.getId() + "\"]", + p.getId(), + null, + null); + } + NavigationTreeModel model = builder.getModel(); + + if (log.isDebugEnabled()) { + builder.printModel(model.getRoot()); + } + + // save tree model in context + setTreeModel(context, model); + return model; + } + + @Override + public NavigationTreeHandler createTreeHandler(JAXXObject context) { + + if (log.isDebugEnabled()) { + log.debug("create handler"); + } + + NavigationTreeHandler handler; + + handler = new NavigationTreeHandlerWithCardLayout( + getPrefix(), + context, + Strategy.PER_NODE) { + + private static final long serialVersionUID = 1L; + + @Override + protected NavigationTreeModel getNavigationTreeModel() { + return getSafeTreeModel(getContext()); + } + + @Override + protected JPanel getContentContainer() { + return getContext().getContent(); + } + + @Override + protected CardLayout2 getContentLayout() { + return getContext().getContentLayout(); + } + + @Override + protected void treateError(Exception e) { + ErrorDialogUI.showError(e); + } + + @Override + public FullNavigationTreeDemo getContext() { + return (FullNavigationTreeDemo) this.context; + } + }; + // on ne peut selectionner qu'un seul noeud a la fois + handler.setSelectionMode(NavigationTreeHandler.SINGLE_TREE_SELECTION); + + // save handler in ui context + setTreeHandler(context, handler); + return handler; + } +} Property changes on: branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/FullNavigationTreeHelper.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/Movie.java =================================================================== --- branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/Movie.java (rev 0) +++ branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/Movie.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,128 @@ +/* + * *##% + * jaxx-demo + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * ##%* + */ +package jaxx.demo.component.jaxx.tree; + +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; + +/** + * + * @author chemit + * @since 1.7.2 + */ +public class Movie { + + protected String id; + protected String title; + protected String image; + protected int year; + protected List<People> actors; + + public Movie(String id, String title, int year,String image) { + this(); + this.id = id; + this.title = title; + this.year = year; + this.image=image; + } + + public Movie() { + actors = new ArrayList<People>(); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public List<People> getActors() { + return actors; + } + + public void setActors(List<People> actors) { + this.actors = actors; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getYear() { + return year; + } + + public void setYear(int year) { + this.year = year; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + public void addActor(People actor) { + actors.add(actor); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Movie other = (Movie) obj; + if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 41 * hash + (this.id != null ? this.id.hashCode() : 0); + return hash; + } + + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE); + b.append("id", id); + b.append("title", title); + b.append("year", year); + b.append("actors", actors); + return b.toString(); + } +} Property changes on: branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/Movie.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/People.java =================================================================== --- branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/People.java (rev 0) +++ branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/People.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,118 @@ +/* + * *##% + * jaxx-demo + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * ##%* + */ +package jaxx.demo.component.jaxx.tree; + +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; + +/** + * + * @author chemit + * @since 1.7.2 + */ +public class People { + + protected String id; + protected String image; + protected String firstName; + protected String lastName; + protected int age; + + public People(String id, String firstName, String lastName, int age, String image) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + this.image = image; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final People other = (People) obj; + if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + (this.id != null ? this.id.hashCode() : 0); + return hash; + } + + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE); + b.append("id", id); + b.append("firstName", firstName); + b.append("lastName", lastName); + b.append("age", age); + return b.toString(); + } +} Property changes on: branches/jaxx-2.X/jaxx-demo/src/main/java/jaxx/demo/component/jaxx/tree/People.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/Decorator.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/Decorator.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/Decorator.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,34 @@ +package jaxx.runtime.decorator; + +/** + * A simple contract to define a String decorator on any java objet. + * + * @param <O> the type of data to decorate + * @author chemit + * @since 1.7.2 (was previously {@code jaxx.runtime.Decorator}) + */ +public abstract class Decorator<O> implements java.io.Serializable { + + private static final long serialVersionUID = -1L; + /** + * Type of the data to decorate + */ + protected final Class<O> internalClass; + + public Decorator(Class<O> internalClass) throws NullPointerException { + if (internalClass == null) { + throw new NullPointerException("internalClass can not be null."); + } + this.internalClass = internalClass; + } + + /** + * @param bean the bean to decorate + * @return the string value of the given bean + */ + public abstract String toString(Object bean); + + public Class<O> getInternalClass() { + return internalClass; + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/Decorator.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/DecoratorUtils.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/DecoratorUtils.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/DecoratorUtils.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,294 @@ +package jaxx.runtime.decorator; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.StringTokenizer; +import jaxx.runtime.decorator.JXPathDecorator.JXPathComparator; +import jaxx.runtime.decorator.JXPathDecorator.Context; + +/** + * + * Some usefull methods on {@link Decorator} to create, decorators and obtain decorators. + * + * To create a new decorator, use one of the methods : + * <ul> + * <li>{@link #newPropertyDecorator(Class, String)}</li> + * <li>{@link #newJXPathDecorator(Class, String)}</li> + * <li>{@link #newMultiJXPathDecorator(Class, String, String)})</li> + * <li>{@link #newMultiJXPathDecorator(Class, String, String, String)})</li> + * </ul> + * <p/> + * + * To register a new decorator, use the method {@link #register(String, Decorator)}. + * <p/> + * To obtain a registred decorator, use the method {@link #get(String)} + * (get the decorator based on his registred name). or the method {@link #get(Class, tring)} + * (get the decorator based on the type of decorator and the registred name). + * <p/> + * To sort a list of data, using a {@link JXPathDecorator}, use the method + * {@link #sort(JXPathDecorator, java.util.List, int)}. + * <p/> + * + * @author tony + * @since 1.7.2 (was previously {@code jaxx.runtime.DecoratorUtils}) + */ +public class DecoratorUtils { + + /** + * Registred decorators. + */ + protected static List<DecoratorContext<?>> decorators; + + /** + * Factory method to instanciate a new {@link PropertyDecorator} for the + * given class {@link O} and a readable property name. + * + * @param internalClass the class of the objects decorated by the new decorator + * @param property the property + * @param <O> the generic type of class to be decorated by the new decorator + * @return the new instanciated decorator + * @throws IllegalArgumentException if the expression is not valid, says: + * <p/> + * - a missing right brace was detected. + * <p/> + * - a ${ was found in a jxpath token. + * @throws NullPointerException if internalClass parameter is null. + */ + public static <O> PropertyDecorator<O> newPropertyDecorator(Class<O> internalClass, String property) + throws IllegalArgumentException, NullPointerException { + return new PropertyDecorator<O>(internalClass, property); + } + + /** + * Factory method to instanciate a new {@link JXPathDecorator} for the + * given class {@link O} and expression. + * + * @param internalClass the class of the objects decorated by the new decorator + * @param expression the expression to use to decorated objects + * @param <O> the generic type of class to be decorated by the new decorator + * @return the new instanciated decorator + * @throws IllegalArgumentException if the expression is not valid, says: + * <p/> + * - a missing right brace was detected. + * <p/> + * - a ${ was found in a jxpath token. + * @throws NullPointerException if internalClass parameter is null. + */ + public static <O> JXPathDecorator<O> newJXPathDecorator(Class<O> internalClass, String expression) + throws IllegalArgumentException, NullPointerException { + + Context<O> context = createJXPathContext(expression); + return new JXPathDecorator<O>(internalClass, expression, context); + } + + public static <O> MultiJXPathDecorator<O> newMultiJXPathDecorator(Class<O> internalClass, + String expression, + String separator) + throws IllegalArgumentException, NullPointerException { + + return newMultiJXPathDecorator(internalClass, expression, separator, separator); + } + + public static <O> MultiJXPathDecorator<O> newMultiJXPathDecorator(Class<O> internalClass, + String expression, + String separator, + String separatorReplacement) + throws IllegalArgumentException, NullPointerException { + + Context<O>[] contexts = createMultiJXPathContext(expression, separator, separatorReplacement); + + return new MultiJXPathDecorator<O>(internalClass, expression, separator, separatorReplacement, contexts); + } + + public static <T> Decorator<T> get(String context) { + Decorator<T> result = get(null, context); + return result; + } + + public static <T> Decorator<T> get(Class<T> type, String context) { + DecoratorContext<T> decoratorContext = getDecoratorContext(type, context); + Decorator<T> result = decoratorContext == null ? null : decoratorContext.getDecorator(); + return result; + } + + /** + * Register a new decorator in the cache. + * + * @param <T> type of data decorated + * @param context the name decorator + * @param decorator the decorator to register + */ + public static <T> void register(String context, Decorator<T> decorator) { + + DecoratorContext<T> result = getDecoratorContext(decorator.getInternalClass(), context); + + if (result != null) { + throw new IllegalArgumentException("there is an already register decorator " + result); + } + + if (decorators == null) { + decorators = new java.util.ArrayList<DecoratorContext<?>>(); + } + decorators.add(new DecoratorContext<T>(context, decorator)); + } + + public static void clear() { + if (decorators != null) { + decorators.clear(); + } + } + + /** + * Sort a list of data based on the first token property of a given context + * in a given decorator. + * + * @param <O> type of data to sort + * @param decorator the decorator to use to sort + * @param datas the list of data to sort + * @param pos the index of context to used in decorator to obtain sorted property. + */ + public static <O> void sort(JXPathDecorator<O> decorator, List<O> datas, int pos) { + Comparator<O> c = null; + boolean cachedComparator = false; + try { + c = decorator.getComparator(pos); + cachedComparator = c instanceof JXPathComparator<?>; + + if (cachedComparator) { + ((JXPathComparator<O>) c).init(decorator, datas); + } + Collections.sort(datas, c); + } finally { + if (cachedComparator) { + ((JXPathComparator<?>) c).clear(); + } + } + } + + @SuppressWarnings({"unchecked"}) + protected static <T> DecoratorContext<T> getDecoratorContext(Class<T> type, String context) { + DecoratorContext<T> result = null; + if (decorators != null) { + for (DecoratorContext<?> d : decorators) { + if (type == null) { + if (d.accept(context)) { + result = (DecoratorContext<T>) d; + break; + } + continue; + } + if (d.accept(type, context)) { + result = (DecoratorContext<T>) d; + break; + } + } + } + return result; + } + + public static class DecoratorContext<T> { + + final String context; + final Decorator<T> decorator; + + public DecoratorContext(String context, Decorator<T> decorator) { + this.context = context; + this.decorator = decorator; + } + + public String getContext() { + return context; + } + + public Decorator<T> getDecorator() { + return decorator; + } + + public Class<T> getType() { + return decorator.getInternalClass(); + } + + public boolean accept(Class<?> type, String context) { + return getType().isAssignableFrom(type) && accept(context); + } + + public boolean accept(String context) { + return ((this.context == null && context == null) || (this.context != null && this.context.equals(context))); + } + + @Override + public String toString() { + return super.toString() + "<type: " + getType().getName() + ", context :" + context + ">"; + } + } + + public static <O> Context<O> createJXPathContext(String expression) { + List<String> lTokens = new ArrayList<String>(); + StringBuilder buffer = new StringBuilder(); + int size = expression.length(); + int end = -1; + int start; + while ((start = expression.indexOf("${", end + 1)) > -1) { + if (start > end + 1) { + // prefix of next jxpath token + buffer.append(expression.substring(end + 1, start)); + } + // seek end of jxpath + end = expression.indexOf("}", start + 1); + if (end == -1) { + throw new IllegalArgumentException("could not find the rigth brace starting at car " + start + " : " + expression.substring(start + 2)); + } + String jxpath = expression.substring(start + 2, end); + // not allowed ${ inside a jxpath token + if (jxpath.indexOf("${") > -1) { + throw new IllegalArgumentException("could not find a ${ inside a jxpath expression at car " + (start + 2) + " : " + jxpath); + } + // save the jxpath token + lTokens.add(jxpath); + // replace jxpath token in expresion with a string format variable + buffer.append("%").append(lTokens.size()); + } + if (size > (end + 1)) { + // suffix after end jxpath (or all expression if no jxpath) + buffer.append(expression.substring(end + 1)); + } + return new Context<O>(buffer.toString(), lTokens.toArray(new String[lTokens.size()])); + } + + public static <O> Context<O>[] createMultiJXPathContext(String expression, String separator, String separatorReplacement) { + int sep = expression.indexOf(separator); + if (sep == -1) { + Context<O>[] result = newInstance(1); + result[0] = createJXPathContext(expression); + return result; + } + + List<String> tokens = new ArrayList<String>(); + StringTokenizer stk = new StringTokenizer(expression, separator); + while (stk.hasMoreTokens()) { + tokens.add(stk.nextToken()); + } + + int nbTokens = tokens.size(); + Context<O>[] contexts = newInstance(nbTokens); + for (int i = 0; i < nbTokens; i++) { + StringBuilder buffer = new StringBuilder(expression.length()); + for (int j = 0; j < nbTokens; j++) { + int index = (i + j) % nbTokens; + String str = tokens.get(index); + //todo replace %index with %j + buffer.append(separatorReplacement).append(str); + } + contexts[i] = createJXPathContext(buffer.substring(separatorReplacement.length())); + } + return contexts; + } + + @SuppressWarnings("unchecked") + protected static <O> Context<O>[] newInstance(int size) { + // fixme how to instanciate a typed array with no checking warning ? + return new Context[size]; + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/DecoratorUtils.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/JXPathDecorator.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/JXPathDecorator.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/JXPathDecorator.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,197 @@ +package jaxx.runtime.decorator; + +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * JXPath decorator based on {@link String#format(String, Object[])} method. + * <p/> + * To use it, give to him a expression where all jxpath to apply on bean are boxed in <code>${}</code>. + * <p/> + * After the jxpath token you must specifiy the formatter to apply of the jxpath token. + * <p/> + * For example : + * <pre> + * Decorator<Object> d = DecoratorUtils.newJXPathDecorator(JXPathDecorator.class,"expr = ${expressions}$s"); + * assert "expr = %1$s" == d.getExpression(); + * assert 1 == d.getNbToken(); + * assert java.util.Arrays.asList("expression") == d.getTokens(); + * assert "expr = %1$s" == d.toString(d); + * </pre> + * + * @param <O> type of data to decorate + * @author chemit + * @see Decorator + * @since 1.7.2 (was previously {@code jaxx.runtime.JXPathDecorat}) + */ +public class JXPathDecorator<O> extends Decorator<O> { + + private static final long serialVersionUID = 1L; + /** + * Logger + */ + private static final Log log = LogFactory.getLog(JXPathDecorator.class); + /** the computed context of the decorator */ + protected Context<O> context; + /** nb jxpath tokens to compute */ + protected int nbToken; + /** the initial expression used to compute the decorator context. */ + protected String initialExpression; + + protected JXPathDecorator(Class<O> internalClass, String expression, Context<O> context) throws IllegalArgumentException, NullPointerException { + super(internalClass); + this.initialExpression = expression; + if (context != null) { + setContext(context); + } + } + + @Override + public String toString(Object bean) { + if (bean == null) { + return null; + } + JXPathContext jxcontext = JXPathContext.newContext(bean); + Object[] args = new Object[nbToken]; + + for (int i = 0; i < nbToken; i++) { + try { + args[i] = getTokenValue(jxcontext, context.tokens[i]); + } catch (Exception e) { + log.error("can not obtain token " + context.tokens[i] + "on object " + bean + " for reason " + e.getMessage(), e); + + } + } + + return String.format(context.expression, args); + } + + public String getProperty(int pos) { + return getTokens()[pos]; + } + + public String getExpression() { + return context.expression; + } + + public String[] getTokens() { + return context.tokens; + } + + public int getNbToken() { + return nbToken; + } + + public String getInitialExpression() { + return initialExpression; + } + + @Override + public String toString() { + return super.toString() + "<" + context + ">"; + } + + public void setContext(Context<O> context) { + this.context = context; + this.nbToken = context.tokens.length; + // always reset comparator + //this.context.comparator = null; + if (log.isDebugEnabled()) { + log.debug(context); + } + } + + @SuppressWarnings({"unchecked"}) + protected Comparator<O> getComparator(int pos) { + ensureTokenIndex(this, pos); + return context.getComparator(pos); + } + + @SuppressWarnings({"unchecked"}) + protected Comparable<Comparable<?>> getTokenValue(JXPathContext jxcontext, String token) { + // assume all values are comparable + return (Comparable<Comparable<?>>) jxcontext.getValue(token); + } + + public static class JXPathComparator<O> implements Comparator<O> { + + protected Map<O, Comparable<Comparable<?>>> valueCache; + private final String expression; + + public JXPathComparator(String expression) { + this.expression = expression; + this.valueCache = new HashMap<O, Comparable<Comparable<?>>>(); + } + + @Override + public int compare(O o1, O o2) { + Comparable<Comparable<?>> c1 = valueCache.get(o1); + Comparable<Comparable<?>> c2 = valueCache.get(o2); + return c1.compareTo(c2); + } + + public void clear() { + valueCache.clear(); + } + + public void init(JXPathDecorator<O> decorator, List<O> datas) { + clear(); + for (O data : datas) { + JXPathContext jxcontext = JXPathContext.newContext(data); + Comparable<Comparable<?>> key = decorator.getTokenValue(jxcontext, expression); + valueCache.put(data, key); + } + } + } + + public static class Context<O> implements java.io.Serializable { + + /** + * expression to format using {@link String#format(String, Object[])}, all variables are compute + * using using the jxpath tokens. + */ + protected String expression; + /** list of jxpath tokens to apply on expression */ + protected String[] tokens; + protected transient Comparator<O> comparator; + private static final long serialVersionUID = 1L; + + public Context(String expression, String[] tokens) { + this.expression = expression; + this.tokens = tokens; + } + + public String getFirstProperty() { + return tokens[0]; + } + + public Comparator<O> getComparator(int pos) { + if (comparator == null) { + comparator = new JXPathComparator<O>(tokens[pos]); + } + return comparator; + } + + public void setComparator(Comparator<O> comparator) { + this.comparator = comparator; + } + + @Override + public String toString() { + return "<expression:" + expression + ", tokens:" + Arrays.toString(tokens) + ">"; + } + } + + protected static void ensureTokenIndex(JXPathDecorator<?> decorator, int pos) { + if (pos < -1 || pos > decorator.getNbToken()) { + throw new ArrayIndexOutOfBoundsException("token index " + pos + " is out of bound, can be inside [" + 0 + "," + decorator.nbToken + "]"); + } + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/JXPathDecorator.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/MultiJXPathDecorator.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/MultiJXPathDecorator.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/MultiJXPathDecorator.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,80 @@ +package jaxx.runtime.decorator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.Comparator; + +/** + * TODO + * + * @param <O> type of data to decorate + * @author chemit + * @see Decorator + * @since 1.7.2 (was previously {@code jaxx.runtime.MultiJXPathDecorator}) + */ +public class MultiJXPathDecorator<O> extends JXPathDecorator<O> { + + private static final long serialVersionUID = 1L; + /** + * Logger + */ + private static final Log log = LogFactory.getLog(MultiJXPathDecorator.class); + /** + * Contexts of the decorator + */ + protected Context<O>[] contexts; + /** + * context separator + */ + protected String separator; + /** + * context separator replacement + */ + protected String separatorReplacement; + + protected MultiJXPathDecorator(Class<O> internalClass, String expression, + String separator, String separatorReplacement, + Context<O>[] contexts) throws IllegalArgumentException, NullPointerException { + super(internalClass, expression, null); + this.separator = separator; + this.separatorReplacement = separatorReplacement; + this.contexts = contexts; + + setContextIndex(0); + + if (log.isDebugEnabled()) { + log.debug(expression + " --> " + this.context); + } + } + + public void setContextIndex(int index) { + ensureContextIndex(this, index); + setContext(contexts[index]); + } + + public int getNbContext() { + return contexts.length; + } + + public String getSeparator() { + return separator; + } + + public String getSeparatorReplacement() { + return separatorReplacement; + } + + @Override + protected Comparator<O> getComparator(int pos) { + ensureContextIndex(this, pos); + Context<O> context1 = contexts[pos]; + return context1.getComparator(0); + } + + protected void ensureContextIndex(MultiJXPathDecorator<?> decorator, int pos) { + if (pos < -1 || pos > decorator.contexts.length) { + throw new ArrayIndexOutOfBoundsException("context index " + pos + " is out of bound, can be inside [" + 0 + "," + decorator.contexts.length + "]"); + } + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/MultiJXPathDecorator.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/PropertyDecorator.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/PropertyDecorator.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/PropertyDecorator.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,76 @@ +package jaxx.runtime.decorator; + +import org.apache.commons.beanutils.PropertyUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; + +/** + * Simple property decorator based on {@link String#format(String, Object[])} method. + * <p/> + * To use it, give him a class and the property name to render. + * <p/> + * For example : + * <pre> + * Decorator<Object> d = DecoratorUtils.newPropertyDecorator(PropertyDecorator.class,"expressions"); + * </pre> + * + * @param <O> type of data to decorate + * @author chemit + * @see Decorator + * @since 1.7.2 (was previously {@code jaxx.runtime.PropertyDecorator}) + */ +public class PropertyDecorator<O> extends Decorator<O> { + + private static final long serialVersionUID = 1L; + /** + * Logger + */ + static private final Log log = LogFactory.getLog(PropertyDecorator.class); + /** + * name of property + */ + protected String property; + protected transient Method m; + + @Override + public String toString(Object bean) { + try { + return getM().invoke(bean) + ""; + } catch (Exception e) { + log.error("could not convert for reason : " + e, e); + return ""; + } + } + + public String getProperty() { + return property; + } + + protected PropertyDecorator(Class<O> internalClass, String property) throws NullPointerException { + super(internalClass); + if (property == null) { + throw new NullPointerException("property can not be null."); + } + this.property = property; + // init method + getM(); + } + + protected Method getM() { + if (m == null) { + for (PropertyDescriptor propertyDescriptor : PropertyUtils.getPropertyDescriptors(internalClass)) { + if (propertyDescriptor.getName().equals(property)) { + this.m = propertyDescriptor.getReadMethod(); + break; + } + } + if (m == null) { + throw new IllegalArgumentException("could not find the property " + property + " in " + internalClass); + } + } + return m; + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/PropertyDecorator.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing/DecoratorListCellRenderer.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing/DecoratorListCellRenderer.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing/DecoratorListCellRenderer.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,47 @@ +package jaxx.runtime.decorator.swing; + +import jaxx.runtime.decorator.*; +import java.awt.Component; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +/** + * A {@link ListCellRenderer} which compute text with the given {@link #decorator} + * and leave the hand to the {@link #delegate} to perform the visual renderer. + * + * @author chemit + * @since 1.7.2 + */ +public class DecoratorListCellRenderer implements ListCellRenderer { + + /** + * Delegate cell renderer + */ + protected ListCellRenderer delegate; + /** + * Decorator to produce text to render + */ + protected Decorator<?> decorator; + + public DecoratorListCellRenderer(Decorator<?> decorator) { + this(new DefaultListCellRenderer(), decorator); + } + + public DecoratorListCellRenderer(ListCellRenderer delegate, Decorator<?> decorator) { + this.delegate = delegate; + this.decorator = decorator; + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + if (value != null) { + if (value instanceof String) { + value = (String) value; + } else { + value = decorator.toString(value); + } + } + return delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing/DecoratorListCellRenderer.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing/DecoratorTableCellRenderer.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing/DecoratorTableCellRenderer.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing/DecoratorTableCellRenderer.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,43 @@ +package jaxx.runtime.decorator.swing; + +import jaxx.runtime.decorator.*; +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import java.awt.Component; +import javax.swing.table.DefaultTableCellRenderer; + +/** + * A {@link TableCellRenderer} which compute text with the given {@link #decorator} + * and leave the hand to the {@link #delegate} to perform the visual renderer. + * + * @author chemit + * @since 1.7.2 (was previously {@code jaxx.runtime.swing.DecoratorTableCellRenderer}). + */ +public class DecoratorTableCellRenderer implements TableCellRenderer { + + /** + * Delegate cell renderer + */ + protected TableCellRenderer delegate; + /** + * Decorator to produce text to render + */ + protected Decorator<?> decorator; + + public DecoratorTableCellRenderer(Decorator<?> decorator) { + this(new DefaultTableCellRenderer(), decorator); + } + + public DecoratorTableCellRenderer(TableCellRenderer delegate, Decorator<?> decorator) { + this.delegate = delegate; + this.decorator = decorator; + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasfocus, int row, int column) { + if (value != null) { + value = decorator.toString(value); + } + return delegate.getTableCellRendererComponent(table, value, isSelected, hasfocus, row, column); + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/decorator/swing/DecoratorTableCellRenderer.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeContextHelper.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeContextHelper.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeContextHelper.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,150 @@ +package jaxx.runtime.swing.tree; + +import javax.swing.JTree; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXContextEntryDef; + +/** + * To help getting and setting navigation tree objects from a {@link JAXXContext}. + * <p/> + * There is six types of data which can be hold in a context : + * <ul> + * <li>tree : the tree </li> + * <li>tree model : the navigation tree model</li> + * <li>tree handler : the navigation tree handler</li> + * <li>selected path : the navigation path of the selected node</li> + * <li>selected node : the selected node</li> + * <li>selected bean : the selected bean</li> + * </ul> + * + * To make possible the use of more than one navigation tree system in a same + * context, we <b>MUST</b> distinguish the context entries definition. For this + * purpose, entries definition are normalized and prefixed by a unique {@link #prefix}. + * <p/> + * Here is the keys mapping : + * <ul> + * <li>tree : {@code prefix + "-tree"}</li> + * <li>tree model : {@code prefix + "-tree-model"}</li> + * <li>tree handler : {@code prefix + "-tree-handler"}</li> + * <li>selected path : {@code prefix + "-selected-path"}</li> + * <li>selected node : {@code prefix + "-selected-node"}</li> + * <li>selected bean : {@code prefix + "-selected-bean"}</li> + * </ul> + * + * @author chemit + * @since 1.7.2 + */ +public class NavigationTreeContextHelper { + + protected final String prefix; + protected JAXXContextEntryDef<String> selectedPathContextEntry; + protected JAXXContextEntryDef<Object> selectedBeanContextEntry; + protected JAXXContextEntryDef<NavigationTreeNode> selectedNodeContextEntry; + protected JAXXContextEntryDef<NavigationTreeModel> treeModelContextEntry; + protected JAXXContextEntryDef<NavigationTreeHandler> treeHandlerContextEntry; + protected JAXXContextEntryDef<JTree> treeContextEntry; + + public NavigationTreeContextHelper(String prefix) { + this.prefix = prefix; + treeContextEntry = JAXXContextEntryDef.newDef(prefix + "-tree", JTree.class); + treeModelContextEntry = JAXXContextEntryDef.newDef(prefix + "-tree-model", NavigationTreeModel.class); + treeHandlerContextEntry = JAXXContextEntryDef.newDef(prefix + "-tree-handler", NavigationTreeHandler.class); + selectedBeanContextEntry = JAXXContextEntryDef.newDef(prefix + "-selected-bean", Object.class); + selectedNodeContextEntry = JAXXContextEntryDef.newDef(prefix + "-selected-node", NavigationTreeNode.class); + selectedPathContextEntry = JAXXContextEntryDef.newDef(prefix + "-selected-path", String.class); + } + + public String getPrefix() { + return prefix; + } + + public JTree getTree(JAXXContext context) { + JTree r = getTreeContextEntry().getContextValue(context); + return r; + } + + public NavigationTreeModel getTreeModel(JAXXContext context) { + NavigationTreeModel r = getTreeModelContextEntry().getContextValue(context); + return r; + } + + public NavigationTreeHandler getTreeHandler(JAXXContext context) { + NavigationTreeHandler r = getTreeHandlerContextEntry().getContextValue(context); + return r; + } + + public String getSelectedPath(JAXXContext context) { + String r = getSelectedPathContextEntry().getContextValue(context); + return r; + } + + public NavigationTreeNode getSelectedNode(JAXXContext context) { + NavigationTreeNode r = getSelectedNodeContextEntry().getContextValue(context); + return r; + } + + public Object getSelectedBean(JAXXContext context) { + Object r = getSelectedBeanContextEntry().getContextValue(context); + return r; + } + + public void setTreeModel(JAXXContext context, NavigationTreeModel model) { + getTreeModelContextEntry().setContextValue(context, model); + } + + public void setTree(JAXXContext context, JTree tree) { + getTreeContextEntry().setContextValue(context, tree); + } + + public void setTreeHandler(JAXXContext context, NavigationTreeHandler handler) { + getTreeHandlerContextEntry().setContextValue(context, handler); + } + + public void setSelectedPath(JAXXContext context, String path) { + if (path == null) { + getSelectedPathContextEntry().removeContextValue(context); + } else { + getSelectedPathContextEntry().setContextValue(context, path); + } + } + + public void setSelectedNode(JAXXContext context, NavigationTreeNode node) { + if (node == null) { + getSelectedNodeContextEntry().removeContextValue(context); + } else { + getSelectedNodeContextEntry().setContextValue(context, node); + } + } + + public void setSelectedBean(JAXXContext context, Object bean) { + if (bean == null) { + getSelectedBeanContextEntry().removeContextValue(context); + } else { + getSelectedBeanContextEntry().setContextValue(context, bean); + } + } + + protected JAXXContextEntryDef<NavigationTreeModel> getTreeModelContextEntry() { + return treeModelContextEntry; + } + + protected JAXXContextEntryDef<NavigationTreeHandler> getTreeHandlerContextEntry() { + return treeHandlerContextEntry; + } + + protected JAXXContextEntryDef<Object> getSelectedBeanContextEntry() { + return selectedBeanContextEntry; + } + + protected JAXXContextEntryDef<NavigationTreeNode> getSelectedNodeContextEntry() { + return selectedNodeContextEntry; + } + + protected JAXXContextEntryDef<String> getSelectedPathContextEntry() { + return selectedPathContextEntry; + } + + protected JAXXContextEntryDef<JTree> getTreeContextEntry() { + return treeContextEntry; + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeContextHelper.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHandler.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHandler.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHandler.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,275 @@ +package jaxx.runtime.swing.tree; + +import java.awt.Component; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultTreeSelectionModel; +import javax.swing.tree.TreePath; +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXInitialContext; +import jaxx.runtime.JAXXObject; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * The handler of a navigation tree. + * + * This is also the selection model to use, since we must check before moving + * from a node we can not just listen selection model changed, we must control + * it. + * + * @author tony + * @since 1.7.2 + */ +public abstract class NavigationTreeHandler extends DefaultTreeSelectionModel { + + private static final long serialVersionUID = 1L; + /** + * Logger + */ + static private final Log log = LogFactory.getLog(NavigationTreeHandler.class); + + /** + * Strategy of instanciation of ui. + * <p/> + * For a given {@code node}, the method {@link #getId(NavigationTreeNode)} + * returns the id of ui to use. + */ + public enum Strategy { + + /** + * instanciate a ui for a node + */ + PER_NODE { + + @Override + public String getId(NavigationTreeNode node) { + return node.getFullPath(); + } + }, + /** + * instanciate only one a ui for a type,nodes will share the instanciation + */ + PER_UI_TYPE { + + @Override + public String getId(NavigationTreeNode node) { + return node.getUIClass().getName(); + } + }; + + public abstract String getId(NavigationTreeNode node); + } + /** + * UI which contains navigation tree + */ + protected JAXXContext context; + /** + * UI Instanciation strategy + */ + protected Strategy strategy; + /** + * JAXXContext access helper. + * + * @since 1.7.2 + */ + protected NavigationTreeContextHelper contextHelper; + + protected NavigationTreeHandler(String contextPrefix, JAXXObject context, Strategy strategy) { + this.contextHelper = new NavigationTreeContextHelper(contextPrefix); + this.context = context; + this.strategy = strategy; + addTreeSelectionListener(new TreeSelectionListener() { + + @Override + public void valueChanged(TreeSelectionEvent event) { + if (event.getOldLeadSelectionPath() != null && event.getOldLeadSelectionPath().equals(event.getPath())) { + // do not treate this if no path changed + return; + } + NavigationTreeNode node = (NavigationTreeNode) event.getPath().getLastPathComponent(); + selectNodeUI(node); + } + }); + } + + /** + * @return le modèle de navigation associé + */ + protected abstract NavigationTreeModel getNavigationTreeModel(); + + /** + * @return le composent actuellement visible associé au noeud courant ou + * au noeud précédent lors d'un changement de noeud. + */ + protected abstract Component getCurrentUI(); + + /** + * @param node le noeud associé à l'ui à retrouver + * @return l'ui associé au novueau noeud sélectionné + */ + protected abstract Component getUI(NavigationTreeNode node); + + /** + * @param component le composent actuellement visible + * @return <code>true</code> si le composent a bien été fermé, <code>false</code> sinon + * @throws Exception if any + */ + protected abstract boolean closeUI(Component component) throws Exception; + + /** + * Instancie une nouvelle ui associé à un noeud de l'arbre de navigation + * + * @param node le noeud associé à l'ui à créer + * @return la nouvelle ui associée au noeud + * @throws Exception if any + */ + protected abstract Component createUI(NavigationTreeNode node) throws Exception; + + /** + * Ouvre l'ui associée au noeud sélectionné dans l'arbre de navigation. + * + * @param newUI l'ui associé au noeud sélectionné à ouvrir + * @param node le node de l'ui a ouvrir + * @throws Exception if any + */ + protected abstract void openUI(Component newUI, NavigationTreeNode node) throws Exception; + + /** + * Traitement des exceptions. + * + * @param e l'erreur recontrée (ou null si pas d"erreur) + */ + protected abstract void treateError(Exception e); + + public JAXXContext getContext() { + return context; + } + + public NavigationTreeContextHelper getContextHelper() { + return contextHelper; + } + + @Override + public void setSelectionPath(TreePath path) { + if (path.equals(getSelectionPath())) { + // stay on same node, can skip + if (log.isDebugEnabled()) { + log.debug("skip stay on path " + path); + } + return; + } + Component component = getCurrentUI(); + + try { + if (!closeUI(component)) { + if (log.isDebugEnabled()) { + log.debug("changing node canceled!"); + } + // can not changed current node + return; + } + } catch (Exception ex) { + treateError(ex); + return; + } + if (log.isDebugEnabled()) { + log.debug("will select path " + path); + } + // ok can safely select the new path + super.setSelectionPath(path); + } + + protected void selectNodeUI(NavigationTreeNode node) { + + try { + + String path = node.getFullPath(); + + if (log.isTraceEnabled()) { + log.trace(path); + } + + Component newUI = getUI(node); + + // now, we are free to open the ui associated with the selected node in navigation + + // get the bean associated with the node + Object data = getNavigationTreeModel().getBean(path); + + // save it in context (must be done before init ui) + addSelectedBeanInContext(node, data); + + if (newUI == null) { + + // a new ui instance is required + newUI = createUI(node); + } + + JAXXContext ctxt = getContext(); + NavigationTreeContextHelper helper = getContextHelper(); + + // save in context current node context path + helper.setSelectedPath(ctxt, node.getFullPath()); + + // save in context current node + helper.setSelectedNode(ctxt, node); + + // really open the ui associated with the selected node + openUI(newUI, node); + + } catch (Exception e) { + // remove data from context + + // if any error, go back to previvous node + treateError(e); + } + } + + /** + * Prepare le context a utiliser pour initialiser une nouvelle ui. + * + * @param node le noeud associé à l'ui à créer + * @return le context à utiliser pour instancier l'ui + * @throws Exception if any + */ + protected JAXXContext createUIContext(NavigationTreeNode node) throws Exception { + + if (node.getUIHandlerClass() == null) { + if (log.isWarnEnabled()) { + log.warn("no action associated with ui " + node.getUIClass()); + } + // no action associated, just + return getContext(); + } + + JAXXAction action = node.getUIHandlerClass().newInstance(); + + // init context with + JAXXInitialContext uiContext = action.init(getContext()); + return uiContext; + } + + protected void addSelectedBeanInContext(NavigationTreeNode node, Object data) { + + if (log.isDebugEnabled()) { + log.debug("find data for contextPath <" + node.getFullPath() + "> : " + (data == null ? null : data.getClass())); + } + JAXXContext ctxt = getContext(); + NavigationTreeContextHelper helper = getContextHelper(); + + // remove previous selected bean + //TODO-TC-20091004 should have an automatic clean context method while + // quiting a node ? + helper.setSelectedBean(ctxt, null); + + if (data != null) { + + helper.setSelectedBean(ctxt, data); + //FIXME-TC-20091004 : should really remove this, this is not context safe + //todo should we not use this to avoid conflict in context ? + //context.setContextValue(data); + } + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHandler.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHandlerWithCardLayout.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHandlerWithCardLayout.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHandlerWithCardLayout.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,100 @@ +package jaxx.runtime.swing.tree; + +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.swing.CardLayout2; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JPanel; +import java.awt.Component; + +/** + * Simple {@link NavigationTreeHandler} implementation with a {@link CardLayout2} to manage components to + * associated with tree's nodes. + * <p/> + * For each node, the ui associated has a constraints in a cardlayout which is the node context path. + * <p/> + * A single container managed by the cardlayout is used to display the components associated with tree's nodes. + * + * @author chemit + */ +public abstract class NavigationTreeHandlerWithCardLayout extends NavigationTreeHandler { + + /** + * Logger + */ + static private final Log log = LogFactory.getLog(NavigationTreeHandlerWithCardLayout.class); + + /** + * All components associated with a tree's node is displayed in a single container. + * + * @return the containter of components + */ + protected abstract JPanel getContentContainer(); + + /** + * the cardlayout managing components associated with tree node. The constraints + * of each component is the node contextPath. + * + * @return the layout used to display components associated with tree's nodes. + */ + protected abstract CardLayout2 getContentLayout(); + + public NavigationTreeHandlerWithCardLayout(String contextPrefix, JAXXObject context, Strategy strategy) { + super(contextPrefix, context, strategy); + if (getContentContainer() == null) { + throw new IllegalArgumentException("could not have a null 'contentContainer' in ui " + context); + } + if (getContentLayout() == null) { + throw new IllegalArgumentException("could not have a null 'contentLayout' in ui " + context); + } + } + + @Override + protected Component getCurrentUI() { + CardLayout2 layout = getContentLayout(); + JPanel container = getContentContainer(); + return layout.getVisibleComponent(container); + } + + @Override + protected Component getUI(NavigationTreeNode node) { + CardLayout2 layout = getContentLayout(); + JPanel container = getContentContainer(); + String constraints = strategy.getId(node); + return layout.contains(constraints) ? layout.getComponent(container, constraints) : null; + } + + @Override + protected void openUI(Component newUI, NavigationTreeNode node) throws Exception { + + CardLayout2 layout = getContentLayout(); + JPanel container = getContentContainer(); + // switch layout + String constraints = strategy.getId(node); + layout.show(container, constraints); + } + + @Override + protected boolean closeUI(Component component) throws Exception { + // by default, we says that component was succesfull closed + return true; + } + + @Override + protected Component createUI(NavigationTreeNode node) throws Exception { + + JAXXContext uiContext = createUIContext(node); + + JAXXObject newUI = node.getUIClass().getConstructor(JAXXContext.class).newInstance(uiContext); + + if (log.isDebugEnabled()) { + log.debug("instanciate new ui " + newUI); + } + String constraints = strategy.getId(node); + getContentContainer().add((Component) newUI, constraints); + return (Component) newUI; + } +} + Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHandlerWithCardLayout.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHelper.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHelper.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHelper.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,141 @@ +package jaxx.runtime.swing.tree; + +import java.lang.reflect.InvocationTargetException; +import java.util.regex.Pattern; +import javax.swing.JTree; +import javax.swing.tree.TreePath; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXObject; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Helper object associated to a given navigation tree system. + * + * To helper is context safe (base on a {@link NavigationTreeContextHelper}. + * + * @author chemit + * @since 1.7.2 + * @see NavigationTreeModel + */ +public abstract class NavigationTreeHelper extends NavigationTreeContextHelper { + + /** + * Logger + */ + static private final Log log = LogFactory.getLog(NavigationTreeHelper.class); + + /** + * Create the tree model. + * + * @param context the context to associate with fresh model + * @return the new model build with data from the given context + */ + public abstract NavigationTreeModel createTreeModel(JAXXContext context); + + /** + * Create the tree handler. + * + * @param context the context to associate with fresh handler + * @return the new handler + */ + public abstract NavigationTreeHandler createTreeHandler(JAXXObject context); + + public NavigationTreeHelper(String contextPrefix) { + super(contextPrefix); + } + + public Object getContextValue(JAXXContext context, String path) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + NavigationTreeModel treeModel = getSafeTreeModel(context); + return treeModel.getBean(path); + } + + public NavigationTreeNode findNode(JAXXContext context, String path) { + NavigationTreeModel treeModel = getSafeTreeModel(context); + return treeModel.findNode(path); + } + + public NavigationTreeNode findNode(JAXXContext context, String path, String regex) { + NavigationTreeModel treeModel = getSafeTreeModel(context); + return treeModel.findNode(path, regex); + } + + public NavigationTreeNode findNode(JAXXContext context, String path, Pattern regex) { + + NavigationTreeModel treeModel = getSafeTreeModel(context); + return treeModel.findNode(path, regex); + } + + public NavigationTreeNode findNode(JAXXContext context, String path, String regex, String suffix) { + + NavigationTreeModel treeModel = getSafeTreeModel(context); + + NavigationTreeNode navigationTreeNode = treeModel.findNode(path, regex); + if (navigationTreeNode != null && suffix != null) { + navigationTreeNode = treeModel.findNode(navigationTreeNode, suffix); + } + return navigationTreeNode; + } + + public NavigationTreeNode findNode(JAXXContext context, String path, Pattern regex, String suffix) { + + NavigationTreeModel treeModel = getSafeTreeModel(context); + + NavigationTreeNode navigationTreeNode = treeModel.findNode(path, regex); + if (navigationTreeNode != null && suffix != null) { + navigationTreeNode = treeModel.findNode(navigationTreeNode, suffix); + } + return navigationTreeNode; + } + + /** + * Sélection d'un noeud dans l'arbre de navigation à partir de son path. + * + * @param context le contexte applicatif + * @param path le path absolue du noeud dans l'arbre + */ + public void selectNode(JAXXContext context, String path) { + NavigationTreeNode node = findNode(context, path); + if (log.isDebugEnabled()) { + log.debug(path + " :: " + node); + } + if (node != null) { + selectNode(context, node); + } + } + + /** + * Sélection d'un noeud dans l'arbre de navigation. + * + * @param context le contexte applicatif + * @param node le noeud à sélectionner dans l'arbre + */ + public void selectNode(JAXXContext context, NavigationTreeNode node) { + + + NavigationTreeModel navigationModel = getSafeTreeModel(context); + if (log.isDebugEnabled()) { + log.debug(node); + } + TreePath path = new TreePath(navigationModel.getPathToRoot(node)); + JTree tree = getSafeTree(context); + tree.setSelectionPath(path); + tree.scrollPathToVisible(path); + } + + public NavigationTreeModel getSafeTreeModel(JAXXContext context) throws NullPointerException { + NavigationTreeModel treeModel = getTreeModel(context); + if (treeModel == null) { + throw new NullPointerException("could not find tree model with key " + getTreeModelContextEntry() + " in context " + context); + } + return treeModel; + } + + public JTree getSafeTree(JAXXContext context) throws NullPointerException { + JTree tree = getTree(context); + if (tree == null) { + throw new NullPointerException("could not find tree with key " + getTreeContextEntry() + " in context " + context); + } + return tree; + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeHelper.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeModel.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeModel.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeModel.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,246 @@ +package jaxx.runtime.swing.tree; + +import jaxx.runtime.JAXXContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Model of the tree used for a navigation tree. + * <p/> + * Il est composé de {@link NavigationTreeNode} + * + * @author chemit + * @since 1.7.2 + */ +public class NavigationTreeModel extends DefaultTreeModel { + + static private final long serialVersionUID = 1L; + /** + * Logger + */ + static private final Log log = LogFactory.getLog(NavigationTreeModel.class); + /** + * The path separator used to build the {@link #fullPath}. + * + * @see NavigationTreeNode#getNodePath() + * @see NavigationTreeNode#getFullPath() + */ + protected final String pathSeparator; + /** + * Context to retrieve beans + */ + private JAXXContext context; + + public NavigationTreeModel(String pathSeparator, JAXXContext context) { + super(null); + this.pathSeparator = pathSeparator; + this.context = context; + } + + @Override + public NavigationTreeNode getRoot() { + return (NavigationTreeNode) super.getRoot(); + } + + /** + * Search from the root node a node named by his fully path (concatenation of nodes + * {@link NavigationTreeNode#navigationPath} valued separated by dot. + * <p/> + * Example : + * <p/> + * <pre>$root.child1.leaf1</pre> + * + * @param path the fully path of the searched node. + * @return the node matching the fully context from the root node, or <code>null</code> if not find. + */ + public NavigationTreeNode findNode(String path) { + return findNode(getRoot(), path, (Pattern) null); + } + + /** + * Apply first the regex pattern to obtain the searched node fi the given <code>regex</code> is not null. + * <p/> + * Search then from the root node a node named by his fully path (concatenation of nodes + * {@link NavigationTreeNode#navigationPath} valued separated by {@link #pathSeparator}. + * <p/> + * <p/> + * Example : + * <p/> + * <pre>$root.child1.leaf1</pre> + * + * @param path the fully path of the searched node. + * @param regex a optional regex to apply to path before searching + * @return the node matching the fully context from the root node, or <code>null</code> if not found. + */ + public NavigationTreeNode findNode(String path, String regex) { + return findNode(getRoot(), path, regex); + } + + /** + * Apply first the regex pattern to obtain the searched node. + * <p/> + * Search then from the root node a node named by his fully path (concatenation of nodes + * {@link NavigationTreeNode#navigationPath} valued separated by {@link #pathSeparator}. + * <p/> + * Example : + * <p/> + * <pre>$root.child1.leaf1</pre> + * + * @param path the fully path of the searched node. + * @param regex a optional regex to apply to path before searching + * @return the node matching the fully context from the root node, or <code>null</code> if not found. + */ + public NavigationTreeNode findNode(String path, Pattern regex) { + return findNode(getRoot(), path, regex); + } + + /** + * Search from a given root node a node named by his fully path (concatenation of nodes + * {@link NavigationTreeNode#navigationPath} valued separated by {@link #pathSeparator}. + * + * @param root root node to be used + * @param path the fully path of the searched node. + * @return the node matching the fully context from the given root node, or <code>null</code> if not found. + */ + public NavigationTreeNode findNode(NavigationTreeNode root, String path) { + return findNode(root, path, (Pattern) null); + } + + /** + * Apply first the regex pattern to obtain the searched node. + * <p/> + * Search then from a given root node a node named by his fully path (concatenation of nodes) + * {@link NavigationTreeNode#navigationPath} valued separated by {@link #pathSeparator}. + * + * @param root root node to be used + * @param path the fully path of the searched node. + * @param regex a previous regex to apply to path : must have a matches + * @return the node matching the fully context from the given root node, or <code>null</code> if not found. + */ + public NavigationTreeNode findNode(NavigationTreeNode root, String path, String regex) { + return findNode(root, path, regex == null ? null : Pattern.compile(regex)); + } + + /** + * Apply first the regex pattern to obtain the searched node. + * <p/> + * Search then from a given root node a node named by his fully path (concatenation of nodes + * {@link NavigationTreeNode#path} valued separated by {@link #pathSeparator}. + * + * @param root root node to be used + * @param path the fully path of the searched node. + * @param regex a previous regex to apply to path : must have a matches + * @return the node matching the fully context from the given root node, or <code>null</code> if not found. + */ + public NavigationTreeNode findNode(NavigationTreeNode root, String path, Pattern regex) { + if (regex != null) { + Matcher matcher = regex.matcher(path); + if (!matcher.matches() || matcher.groupCount() < 1) { + log.warn("no matching regex " + regex + " to " + path); + return null; + } + path = matcher.group(1); + if (log.isDebugEnabled()) { + log.debug("matching regex " + regex + " : " + path); + } + } + StringTokenizer stk = new StringTokenizer(path, pathSeparator); + NavigationTreeNode result = root; + // pas the first token (matches the root node) + if (root.isRoot() && stk.hasMoreTokens()) { + String rootPath = stk.nextToken(); + if (!rootPath.equals(root.getNodePath())) { + return null; + } + } + while (stk.hasMoreTokens()) { + result = result.getChild(stk.nextToken()); + } + return result; + } + + public JAXXContext getContext() { + return context; + } + + /** + * Obtain the associated bean value from context corresponding to node from given navigation path. + * + * @param navigationPath the current context path of the node + * @return the value associated in context with the given navigation path + */ + public Object getBean(String navigationPath) { + Object result; + NavigationTreeNode node = findNode(navigationPath, (Pattern) null); + result = getBean(node); + return result; + } + + /** + * Obtain the associated bean value from context corresponding to node + * + * @param node the current node + * @return the value associated in context with the given node. + */ + public Object getBean(NavigationTreeNode node) { + if (node == null) { + return null; + //fixme should throw a NPE exception + //throw new NullPointerException("node can not be null"); + } + return node.getBean(getContext()); + } + + @Override + public void nodeChanged(TreeNode node) { + nodeChanged(node, false); + if (log.isDebugEnabled()) { + log.debug(node); + } + } + + @Override + public void nodeStructureChanged(TreeNode node) { + NavigationTreeNode n = (NavigationTreeNode) node; + //TC-20091004 never launch a deep reload + reload(n, true); + super.nodeStructureChanged(node); + if (log.isDebugEnabled()) { + log.debug(node); + } + } + + public void nodeChanged(TreeNode node, boolean deep) { + + NavigationTreeNode n = (NavigationTreeNode) node; + //TC-20091004 never launch a deep clean, since we do a deep nodeChanged. + reload(n, deep); + super.nodeChanged(node); + } + + protected void reload(NavigationTreeNode node) { + reload(node, false); + } + + protected void reload(NavigationTreeNode node, boolean deep) { + if (node == null) { + return; + } + node.reload(getContext()); + + if (deep) { + Enumeration<?> childs = node.children(); + while (childs.hasMoreElements()) { + NavigationTreeNode o = (NavigationTreeNode) childs.nextElement(); + reload(o, true); + } + } + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeModel.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeModelBuilder.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeModelBuilder.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeModelBuilder.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,242 @@ +package jaxx.runtime.swing.tree; + +import java.util.Enumeration; +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.decorator.Decorator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This object is design to build a {@link NavigationTreeModel}. + * + * @author chemit + * @since 17.2 + */ +public class NavigationTreeModelBuilder { + + /** + * Logger + */ + static private final Log log = LogFactory.getLog(NavigationTreeModelBuilder.class); + /** + * The model dealed by the builder. + * + * <b>Note:</b> It is a good idea to keep only one instance of the model. + * If reset is required, should empty the model but not reinstanciate it. + */ + protected NavigationTreeModel model; + /** + * default ui class to use if node does not define an ui class + */ + protected Class<? extends JAXXObject> defaultUIClass; + /** + * [optional] default action class + */ + protected Class<? extends JAXXAction> defaultUIHandlerClass; + + public NavigationTreeModelBuilder(String pathSeparator, JAXXContext context, Class<? extends JAXXObject> defaultUIClass, Class<? extends JAXXAction> defaultUIHandlerClass) { + this(defaultUIClass, defaultUIHandlerClass, new NavigationTreeModel(pathSeparator, context)); + } + + public NavigationTreeModelBuilder(Class<? extends JAXXObject> defaultUIClass, Class<? extends JAXXAction> defaultUIHandlerClass, NavigationTreeModel model) { + this.defaultUIClass = defaultUIClass; + this.defaultUIHandlerClass = defaultUIHandlerClass; + this.model = model; + } + + public NavigationTreeModel getModel() { + return model; + } + + public NavigationTreeNode buildEmptyRoot(JAXXContextEntryDef<?> entryDef, String contextName) { + NavigationTreeNode node = new NavigationTreeNode(model.pathSeparator, contextName, entryDef, null); + addI18nNodeRenderer(node, ""); + return addChildNode(null, node); + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, String libelle, + JAXXContextEntryDef<?> entryDef, + String entryPath, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = new NavigationTreeNode(model.pathSeparator, contextName, entryDef, entryPath); + addI18nNodeRenderer(node, libelle); + addNodeJaxxClasses(node, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, String libelle, + JAXXContextEntryDef<?> entryDef, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = new NavigationTreeNode(model.pathSeparator, contextName, entryDef); + addI18nNodeRenderer(node, libelle); + addNodeJaxxClasses(node, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, String libelle, + String entryPath, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = new NavigationTreeNode(model.pathSeparator, contextName, entryPath); + addI18nNodeRenderer(node, libelle); + addNodeJaxxClasses(node, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, Decorator<?> decorator, + JAXXContextEntryDef<?> entryDef, + String entryPath, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = new NavigationTreeNode(model.pathSeparator, contextName, entryDef, entryPath); + addDecoratorNodeRenderer(node, decorator); + addNodeJaxxClasses(node, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, Decorator<?> decorator, + JAXXContextEntryDef<?> entryDef, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = new NavigationTreeNode(model.pathSeparator, contextName, entryDef); + addDecoratorNodeRenderer(node, decorator); + addNodeJaxxClasses(node, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, Decorator<?> decorator, + String entryPath, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = new NavigationTreeNode(model.pathSeparator, contextName, null, entryPath); + addDecoratorNodeRenderer(node, decorator); + addNodeJaxxClasses(node, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + protected NavigationTreeNode addChildNode(NavigationTreeNode parentNode, NavigationTreeNode node) { + + if (node.getUIClass() == null) { + // no ui is associated with this node, use the default one + node.setUIClass(defaultUIClass); + } + + if (node.getUIHandlerClass() == null) { + // no ui handler associated with this node, use the default one + node.setUIHandlerClass(defaultUIHandlerClass); + } + if (parentNode == null) { + model.setRoot(node); + } else { + parentNode.add(node); + } + model.nodeStructureChanged(parentNode); + return node; + } + + public NavigationTreeNode removeChildNode(NavigationTreeNode node) { + NavigationTreeNode parentNode = node.getParent(); + model.removeNodeFromParent(node); + return parentNode; + } + + public void addI18nNodeRenderer(NavigationTreeNode node, String libelle) { + node.setRenderer(new NavigationTreeNodeRendererI18nImpl(libelle)); + } + + public void addDecoratorNodeRenderer(NavigationTreeNode node, Decorator<?> decorator) { + node.setRenderer(new NavigationTreeNodeRendererDecoratorImpl(decorator)); + } + + public void addNodeJaxxClasses( + NavigationTreeNode node, + Class<? extends JAXXObject> uIClass, + Class<? extends JAXXAction> uIHandlerClass) { + node.setUIClass(uIClass); + node.setUIHandlerClass(uIHandlerClass); + } + + public void printModel(NavigationTreeNode node) { + if (node == null) { + return; + } + log.info("node " + node.getFullPath() + ", jxpath: " + node.getJaxxContextEntryPath() + ", entryContextDef: " + node.getJaxxContextEntryDef()); + if (log.isDebugEnabled()) { + log.debug("node userObject" + node.getUserObject()); + log.debug("value from node " + node.getBean(getModel().getContext())); + log.debug("value from model " + getModel().getBean(node)); + } + Enumeration<?> children = node.children(); + while (children.hasMoreElements()) { + printModel((NavigationTreeNode) children.nextElement()); + } + } + + public static abstract class ChildBuilder<O> { + + protected NavigationTreeModelBuilder builder; + + protected ChildBuilder(NavigationTreeModelBuilder builder) { + this.builder = builder; + } + + protected abstract void init(Class<? extends O> klass); + + protected abstract Decorator<? extends O> getDecorator(O child); + + protected abstract String getJXPath(O child); + + protected abstract String getNavigationPath(O child); + + public void build(NavigationTreeNode parent, boolean cacheValues, Class<? extends O> klass, java.util.Collection<? extends O> beans, Class<? extends JAXXObject> ui, Class<? extends JAXXAction> actionClass) { + + if (beans == null || beans.isEmpty()) { + // no bean to treate + return; + } + + init(klass); + + NavigationTreeNode node; + + for (O o : beans) { + node = builder.build(parent, getDecorator(o), getJXPath(o), getNavigationPath(o), ui, actionClass); + if (cacheValues) { + // cache the bean value to improve performance + node.setBean(o); + } + } + } + + public void build(NavigationTreeNode parent, boolean cacheValues, Class<? extends O> klass, O[] beans, Class<? extends JAXXObject> ui, Class<? extends JAXXAction> actionClass) { + + if (beans == null || beans.length == 0) { + // no bean to treate + return; + } + + init(klass); + + NavigationTreeNode node; + + for (O o : beans) { + node = builder.build(parent, getDecorator(o), getJXPath(o), getNavigationPath(o), ui, actionClass); + if (cacheValues) { + // cache the bean value to improve performance + node.setBean(o); + } + } + } + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeModelBuilder.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNode.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNode.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNode.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,424 @@ +package jaxx.runtime.swing.tree; + +import java.util.Enumeration; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeNode; +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.JAXXObject; +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Node of the {@link NavigationTreeModel}. + * + * Each node is associated with : + * <ul> + * <li> a {@code bean} coming from a {@link JAXXContext} </li> + * <li> a {@code uiClass} to build the associated ui </li> + * </ul> + * <p/> + * To retrieve the bean from the context, there is a huge logic in the + * method {@link #getBean(JAXXContext)}. + * + * In few words, if the {@link #jaxxContextEntryDef} is defined, it means + * that the object is taken from the {@code context}. + * <p/> + * Otherwise, find the first ancestor with an context entry and retrieve from + * here the bean. + * <p/> + * Then go down to the initial node by applying the jxpath expressions + * {@link #jaxxContextEntryPath} of each node on road back. + * <p/> + * + * To identify easly a node, each node has a {@link #path} and a + * {@link #fullPath} (full path from root node). + * <p/> + * + * To display the node we use a {@link NavigationTreeNodeRenderer} which is in + * fact the {@link #userObject}, the object can be synch with the bean via the + * {@link NavigationTreeNodeRenderer#reload(java.lang.Object)} method. + * + * @author chemit + * @see NavigationTreeModel + * @see NavigationTreeNodeRenderer + * @since 1.7.2 + */ +public class NavigationTreeNode extends DefaultMutableTreeNode { + + private static final long serialVersionUID = 1L; + /** + * Logger + */ + static private final Log log = LogFactory.getLog(NavigationTreeNode.class); + /** + * The path separator used to build the {@link #fullPath}. + * + * @see #path + * @see #fullPath + */ + protected final String pathSeparator; + /** + * The node path. + * <p/> + * Used to build the {@link #fullPath} which gives a unique identifier of the + * node. + * @see #pathSeparator + * @see #fullPath + */ + protected String path; + /** + * The full path for the node from the rood node. + * <p/> + * This path is build by appending nodes {@link #path} from the root node + * to this node, between each path we introduce the {@link #pathSeparator}. + * <p> + * Exemple : + * <pre> + * root + * $root + * `-- child1 + * `-- child2 + * </pre> + * will given {@code $root/child1/child2}. + * @see #pathSeparator + * @see #path + */ + protected String fullPath; + /** + * The UI class associated with the node. + * <p/> + * This class can be {@code null}, in that case, the + * {@link NavigationTreeModelBuilder#defaultUIClass} will be used while + * building the model. + */ + protected Class<? extends JAXXObject> uIClass; + /** + * The UI handler class associated with the node. + * <p/> + * This class can be {@code null}, in that case, the + * {@link NavigationTreeModelBuilder#defaultUIHandlerClass} will be used + * while building the model. + */ + protected Class<? extends JAXXAction> uIHandlerClass; + /** + * The context entry definition to retrieve the bean. + * + * <b>Note:</b> If not set - the {@code bean} will be retrieve on a ancestor + * node. + */ + protected JAXXContextEntryDef<?> jaxxContextEntryDef; + /** + * The jxPath to process to obtain real {@code bean} from the data retrieve + * in the context. + * + * <b>Note:</b> If not set -no jxpath will be apply on the bean from context. + */ + protected String jaxxContextEntryPath; + /** + * The bean associated with the node ( the value can be obtain via the + * method {@link #getBean(JAXXContext)} or directly set via method + * {@link #setBean(Object)}. + * <p/> + * cache of bean associated with bean to improve performance + */ + protected transient Object bean; + /** + * The type of the related bean associated with the node. + * <p/> + * Note: This type is here to override the NodeRenderer internalClass, since + * we could need to override this data. + * <p/> + * If this property is let to null, then we will use the NodeRenderer one + */ + protected Class<?> internalClass; + + public NavigationTreeNode(String pathSeparator, String navigationPath, Object jaxxContextEntryDef) { + super(); + this.pathSeparator = pathSeparator; + this.path = navigationPath; + if (jaxxContextEntryDef instanceof JAXXContextEntryDef<?>) { + this.jaxxContextEntryDef = ((JAXXContextEntryDef<?>) jaxxContextEntryDef); + } else if (jaxxContextEntryDef instanceof String) { + this.jaxxContextEntryPath = (String) jaxxContextEntryDef; + } else if (jaxxContextEntryDef != null) { + // wrong context definition type + throw new IllegalArgumentException("to define a context link, must be a String (jxpath) or a " + JAXXContextEntryDef.class + ", but was " + jaxxContextEntryDef); + } + } + + public NavigationTreeNode(String pathSeparator, String navigationPath, JAXXContextEntryDef<?> jaxxContextEntryDef, String jaxxContextEntryPath) { + super(); + this.pathSeparator = pathSeparator; + this.path = navigationPath; + this.jaxxContextEntryDef = jaxxContextEntryDef; + this.jaxxContextEntryPath = jaxxContextEntryPath; + } + + /** + * + * @return the text node renderer (store in {@link #userObject} property. + */ + public NavigationTreeNodeRenderer getRenderer() { + NavigationTreeNodeRenderer render = null; + Object o = getUserObject(); + if (o != null && o instanceof NavigationTreeNodeRenderer) { + render = (NavigationTreeNodeRenderer) o; + } + return render; + } + + public void setRenderer(NavigationTreeNodeRenderer renderer) { + // clear all cache + bean = null; + setUserObject(renderer); + } + + public String getPathSeparator() { + return pathSeparator; + } + + public String getNodePath() { + return path; + } + + public void setNodePath(String navigationPath) { + this.path = navigationPath; + } + + public Class<? extends JAXXObject> getUIClass() { + return uIClass; + } + + public void setUIClass(Class<? extends JAXXObject> uIClass) { + this.uIClass = uIClass; + } + + public void setInternalClass(Class<?> internalClass) { + this.internalClass = internalClass; + } + + public Class<? extends JAXXAction> getUIHandlerClass() { + return uIHandlerClass; + } + + public void setUIHandlerClass(Class<? extends JAXXAction> uIHandlerClass) { + this.uIHandlerClass = uIHandlerClass; + } + + public JAXXContextEntryDef<?> getJaxxContextEntryDef() { + return jaxxContextEntryDef; + } + + public void setJaxxContextEntryDef(JAXXContextEntryDef<?> jaxxContextEntryDef) { + this.jaxxContextEntryDef = jaxxContextEntryDef; + } + + public String getJaxxContextEntryPath() { + return jaxxContextEntryPath; + } + + public void setJaxxContextEntryPath(String jaxxContextEntryPath) { + this.jaxxContextEntryPath = jaxxContextEntryPath; + } + + public Class<?> getInternalClass() { + if (internalClass == null && getRenderer() != null) { + return getRenderer().getInternalClass(); + } + return internalClass; + } + + /** @return the fully context path of the node from the root node to this. */ + public String getFullPath() { + if (fullPath == null) { + StringBuilder sb = new StringBuilder(); + for (TreeNode treeNode : getPath()) { + NavigationTreeNode myNode = (NavigationTreeNode) treeNode; + sb.append(pathSeparator).append(myNode.getNodePath()); + } + fullPath = sb.substring(1); + } + return fullPath; + } + + @Override + public NavigationTreeNode getChildAt(int index) { + return (NavigationTreeNode) super.getChildAt(index); + } + + @Override + public NavigationTreeNode getParent() { + return (NavigationTreeNode) super.getParent(); + } + + /** + * @param path the name of the {@link #path} to be matched in the cild of this node. + * @return the child of this node with given {@link # path} value. + */ + public NavigationTreeNode getChild(String path) { + Enumeration<?> childs = children(); + while (childs.hasMoreElements()) { + NavigationTreeNode son = (NavigationTreeNode) childs.nextElement(); + if (path.equals(son.getNodePath())) { + return son; + } + } + return null; + } + + public Object getBean() { + return bean; + } + + public void setBean(Object bean) { + this.bean = bean; + } + + public void reload(JAXXContext context) { + + // clear bean cache + bean = null; + + // clear context navigation cache + fullPath = null; + + NavigationTreeNodeRenderer renderer = getRenderer(); + if (renderer == null) { + // this can't be ! + throw new NullPointerException("could not find the renderer for node " + this); + } + + Object b = getBean(context); + + renderer.reload(b); + } + + /** + * Obtain the associated bean value from context corresponding to node + * + * @param context the context to seek + * @return the value associated in context with the given context path + */ + public Object getBean(JAXXContext context) { + if (bean != null) { + // use cached bean + return bean; + } + Object result; + if (getJaxxContextEntryDef() != null && jaxxContextEntryPath == null) { + // the node maps directly a value in context, with no jxpath resolving + result = getJaxxContextEntryDef().getContextValue(context); + // save in cache + setBean(result); + return result; + } + // find the first ancestor node with a context def + NavigationTreeNode parentNode = getFirstAncestorWithDef(); + if (parentNode == null) { + log.warn("could not find a ancestor node with a definition of a context entry from node (" + this + ")"); + // todo must be an error + // no parent found + return null; + } + Object parentBean = parentNode.getJaxxContextEntryDef().getContextValue(context); + if (parentBean == null) { + // must be an error no bean found + log.warn("could not find a bean attached in context from context entry definition " + parentNode.getJaxxContextEntryDef()); + return null; + } + if (parentNode.jaxxContextEntryPath != null) { + // apply the jxpath on parentBean + JXPathContext jxcontext = JXPathContext.newContext(parentBean); + parentBean = jxcontext.getValue(parentNode.jaxxContextEntryPath); + } + // save in cache + parentNode.setBean(parentBean); + if (this == parentNode) { + // current node is the node matching the context entry value and no jxpath is found + return parentBean; + } + if (jaxxContextEntryPath == null) { + // todo must be an error + log.warn("must find a jaxxContextEntryPath on node (" + this + ")"); + return null; + } + String jxpathExpression = computeJXPath(jaxxContextEntryPath, parentNode); + if (jxpathExpression == null) { + /// todo must be an error + log.warn("could not build jxpath from node " + parentNode + " to " + this); + // could not retreave the jxpath... + return null; + } + if (jxpathExpression.startsWith("[")) { + // special case when we want to access a collection + jxpathExpression = '.' + jxpathExpression; + } + if (log.isDebugEnabled()) { + log.debug("jxpath : " + jxpathExpression); + } + JXPathContext jxcontext = JXPathContext.newContext(parentBean); + result = jxcontext.getValue(jxpathExpression); + // save in cache + setBean(result); + return result; + } + + /** + * @return the first ancestor with a none null {@link #jaxxContextEntryDef} + * or <code>null</code> if none find.. + */ + protected NavigationTreeNode getFirstAncestorWithDef() { + if (jaxxContextEntryDef != null) { + // find a node with a direct link with the context + return this; + } + // the node is not linked to context + // seek in his parent + NavigationTreeNode ancestor = getParent(); + return ancestor == null ? null : ancestor.getFirstAncestorWithDef(); + } + + protected String computeJXPath(String expr, NavigationTreeNode parentNode) { + if (parentNode == this) { + // reach the parent limit node, return the expr computed + return expr; + } + int firstIndex = expr.indexOf(".."); + int lastIndex = expr.lastIndexOf(".."); + if (firstIndex == -1) { + // this is a error, since current node is not parent limit node, + // we must find somewhere a way to go up in nodes + throw new IllegalArgumentException(expr + " should contains at least one \"..\""); + } + if (firstIndex != 0) { + // this is a error, the ../ must be at the beginning of the expression + throw new IllegalArgumentException("\"..\" must be at the beginning but was : " + expr); + } + NavigationTreeNode ancestor = getParent(); + if (firstIndex == lastIndex) { + // found only one go up, so must be substitute by the parent node context + String newExpr = expr.substring(2); + //String newExpr = expr.substring(expr.startsWith("../") ? 3 : 2); + if (getParent().equals(parentNode)) { + // parent node is the final parent node, so no substitution needed + return newExpr; + } + // ancestor must have a jaxxContextEntryPath + if (ancestor.jaxxContextEntryPath == null) { + throw new IllegalArgumentException("with the expression " + expr + ", the ancestor node (" + ancestor + ") must have a jaxxContextEntryPath definition, but was not "); + } + newExpr = ancestor.jaxxContextEntryPath + newExpr; + return ancestor.computeJXPath(newExpr, parentNode); + } + // have more than one go up, so the ancestor node can not have a jaxxContextEntryPath + if (ancestor.jaxxContextEntryPath != null) { + throw new IllegalArgumentException("with the expression " + expr + ", the ancestor node can not have a jaxxContextEntryPath definition"); + } + // substitute the last ..[/] and delegate to ancestor + String newExpr = expr.substring(0, lastIndex - 1) + expr.substring(lastIndex + (expr.charAt(lastIndex + 3) == '/' ? 3 : 2)); + return ancestor.computeJXPath(newExpr, parentNode); + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNode.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRenderer.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRenderer.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRenderer.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,44 @@ +package jaxx.runtime.swing.tree; + +import javax.swing.tree.TreeCellRenderer; + +/** + * Text Renderer of a {@link NavigationTreeNode}. + * <p/> + * This object will be placed as the {@link NavigationTreeNode#userObject} of + * nodes. + * <p/> + * + * In that way, we can use the {@link #toString()} value to render the node + * without writing any {@link TreeCellRenderer}. + * <p/> + * To rebuild the renderer text of a node use the method {@link #reload(Object)} + * with the {@code bean} provides by the model for the node. + * + * @author chemit + * @since 1.7.2, replace {@code NavigationUtil#NodeRenderer} which disappear soon... + */ +public interface NavigationTreeNodeRenderer extends java.io.Serializable { + + /** + * + * @return the render value of the node + */ + @Override + String toString(); + + /** + * + * Can override the the node internal class for display purpose. + * + * @return the type of data to be displayed. + */ + Class<?> getInternalClass(); + + /** + * Reload the render value from the {@code bean} of node. + * + * @param bean the bean associated to the node to render + */ + void reload(Object bean); +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRenderer.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRendererDecoratorImpl.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRendererDecoratorImpl.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRendererDecoratorImpl.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,53 @@ +package jaxx.runtime.swing.tree; + +import jaxx.runtime.decorator.Decorator; + +/** + * Decorator Renderer of a {@link NavigationTreeNode}. + * + * Apply a {@link Decorator} to the {@code bean} associated to the node. + * + * @author chemit + * @since 1.7.2, replace {@code NavigationUtil#NodeRenderer} which disappear soon... + */ +public class NavigationTreeNodeRendererDecoratorImpl implements NavigationTreeNodeRenderer { + + private static final long serialVersionUID = -1L; + /** + * Decorator + */ + protected final Decorator<?> decorator; + /** + * internal class of representing data + */ + protected final Class<?> internalClass; + /** + * last renderered value + */ + protected String text; + + public NavigationTreeNodeRendererDecoratorImpl(Decorator<?> decorator) { + this.internalClass = decorator.getInternalClass(); + this.decorator = decorator; + } + + @Override + public String toString() { + return text; + } + + @Override + public void reload(Object bean) { + try { + text = decorator.toString(bean); + + } catch (Exception e) { + text = ""; + } + } + + @Override + public Class<?> getInternalClass() { + return internalClass; + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRendererDecoratorImpl.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRendererI18nImpl.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRendererI18nImpl.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRendererI18nImpl.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,48 @@ +package jaxx.runtime.swing.tree; + +import static org.nuiton.i18n.I18n._; + +/** + * I18n label Renderer of a {@link NavigationTreeNode}. + * + * Just apply a i18n translation on the given {@link #libelle}. + * + * @author chemit + * @since 1.7.2, replace {@code NavigationUtil#NodeRenderer} which disappear soon... + */ +public class NavigationTreeNodeRendererI18nImpl implements NavigationTreeNodeRenderer { + + private static final long serialVersionUID = -1L; + /** + * Static i18n label to render + */ + protected final String libelle; + /** + * internal class of representing data + */ + protected final Class<?> internalClass; + /** + * last renderered value + */ + protected String text; + + public NavigationTreeNodeRendererI18nImpl(String libelle) { + this.libelle = libelle; + this.internalClass = String.class; + } + + @Override + public String toString() { + return text; + } + + @Override + public void reload(Object data) { + text = _(libelle); + } + + @Override + public Class<?> getInternalClass() { + return internalClass; + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/NavigationTreeNodeRendererI18nImpl.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/package.html =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/package.html (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/package.html 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,12 @@ +<html> + <body> + <h1>JAXX - tree utilities</h1> + + This package contains all the classes of the navigation tree framework. + + <p> + Replace the previous framework from package + <code>jaxx.runtime.swing.navigation</code> + </p> + </body> +</html> \ No newline at end of file Added: branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/Data.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/Data.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/Data.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,37 @@ +package jaxx.runtime.decorator; + +import java.util.ArrayList; +import java.util.List; + +public class Data { + + int pos; + String name; + + protected static List<Data> generate(int nb) { + List<Data> datas = new ArrayList<Data>(nb); + for (int i = 0; i < nb; i++) { + datas.add(new Data(i, "name_" + (nb - i))); + } + return datas; + } + + Data(int pos, String name) { + super(); + this.pos = pos; + this.name = name; + } + + public int getPos() { + return pos; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "Data{pos=" + pos + ", name=\'" + name + '\'' + '}'; + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/Data.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/JXPathDecoratorTest.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/JXPathDecoratorTest.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/JXPathDecoratorTest.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,136 @@ +package jaxx.runtime.decorator; + +import jaxx.runtime.decorator.JXPathDecorator.Context; +import org.junit.After; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * @author chemit + * @since 1.7.2 (was previously {@code jaxx.runtime.JXPathDecoratorTest}). + */ +public class JXPathDecoratorTest { + + + protected JXPathDecorator<?> decorator; + protected String expected; + protected String result; + + @After + public void after() { + decorator = null; + } + + @Test(expected = NullPointerException.class) + public void testNullInternalClass() throws Exception { + decorator = DecoratorUtils.newJXPathDecorator(null, "hello"); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingRightBrace() throws Exception { + decorator = DecoratorUtils.newJXPathDecorator(Object.class, "${haha"); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingRightBrace2() throws Exception { + decorator = DecoratorUtils.newJXPathDecorator(Object.class, "${haha${hum}"); + } + + @Test + public void testNullBean() throws Exception { + decorator = DecoratorUtils.newJXPathDecorator(Object.class, "hello"); + expected = "hello"; + assertEquals(expected, decorator.getExpression()); + assertEquals(0, decorator.nbToken); + assertEquals(0, decorator.getTokens().length); + + result = decorator.toString(null); + assertEquals(null, result); + } + + @Test + public void testNoJXPath() throws Exception { + decorator = DecoratorUtils.newJXPathDecorator(Object.class, "hello"); + expected = "hello"; + assertEquals(expected, decorator.getExpression()); + assertEquals(0, decorator.nbToken); + assertEquals(0, decorator.getTokens().length); + + result = decorator.toString(this); + assertEquals(expected, result); + } + + @Test + public void testDecorator() throws Exception { + + decorator = DecoratorUtils.newJXPathDecorator(JXPathDecorator.class, "${expression}$s - ${nbToken}$d"); + assertEquals("%1$s - %2$d", decorator.getExpression()); + assertDecoratorInternal(); + + decorator = DecoratorUtils.newJXPathDecorator(JXPathDecorator.class, "${expression}${nbToken}"); + assertEquals("%1%2", decorator.getExpression()); + assertDecoratorInternal(); + + decorator = DecoratorUtils.newJXPathDecorator(JXPathDecorator.class, "before ${expression}$s - ${nbToken}$d after"); + assertEquals("before %1$s - %2$d after", decorator.getExpression()); + assertDecoratorInternal(); + + decorator = DecoratorUtils.newJXPathDecorator(JXPathDecorator.class, "before${expression}$s-${nbToken}$dafter"); + assertEquals("before%1$s-%2$dafter", decorator.getExpression()); + assertDecoratorInternal(); + } + + @Test + public void testSort() throws Exception { + + List<Data> datas = Data.generate(10); + + JXPathDecorator<Data> d = DecoratorUtils.newJXPathDecorator(Data.class, "${pos}$d ${name}$s"); + + List<Data> sortData = new ArrayList<Data>(datas); + DecoratorUtils.sort(d, sortData, 0); + for (int i = 0; i < datas.size(); i++) { + Data data = datas.get(i); + Data sData = sortData.get(i); + assertEquals(data, sData); + } + Collections.sort(datas, new Comparator<Data>() { + @Override + public int compare(Data o1, Data o2) { + return o1.name.compareTo(o2.name); + } + }); + Context<Data> context = d.context; + context.setComparator(null); + DecoratorUtils.sort(d, sortData, 1); + for (int i = 0; i < datas.size(); i++) { + Data data = datas.get(i); + Data sData = sortData.get(i); + assertEquals(data, sData); + } + } + + + public void assertDecoratorInternal(String... tokens) { + assertTokens(tokens); + expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken()); + result = decorator.toString(decorator); + assertEquals(expected, result); + } + + private void assertTokens(String... tokens) { + if (tokens.length == 0) { + tokens = new String[]{"expression", "nbToken"}; + } + assertEquals(2, decorator.nbToken); + assertEquals(2, decorator.getTokens().length); + assertEquals(tokens[0], decorator.getTokens()[0]); + assertEquals(tokens[1], decorator.getTokens()[1]); + } + +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/JXPathDecoratorTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/MultiJXPathDecoratorTest.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/MultiJXPathDecoratorTest.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/MultiJXPathDecoratorTest.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,185 @@ +package jaxx.runtime.decorator; + +import org.junit.After; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * @author chemit + * @since 1.7.2 (was previously {@code jaxx.runtime.MultiJXPathDecoratorTest}). + */ +public class MultiJXPathDecoratorTest { + + protected MultiJXPathDecorator<?> decorator; + protected String expected; + protected String result; + + @After + public void after() { + decorator = null; + } + + @Test(expected = NullPointerException.class) + public void testNullInternalClass() throws Exception { + decorator = DecoratorUtils.newMultiJXPathDecorator(null, "hello", "#"); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingRightBrace() throws Exception { + decorator = DecoratorUtils.newMultiJXPathDecorator(Object.class, "${haha", "#"); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingRightBrace2() throws Exception { + decorator = DecoratorUtils.newMultiJXPathDecorator(Object.class, "${haha${hum}", "#"); + } + + @Test + public void testNullBean() throws Exception { + decorator = DecoratorUtils.newMultiJXPathDecorator(Object.class, "hello", ""); + expected = "hello"; + assertEquals(expected, decorator.getExpression()); + assertEquals(0, decorator.nbToken); + assertEquals(0, decorator.getTokens().length); + + result = decorator.toString(null); + assertEquals(null, result); + } + + @Test + public void testMultiDecorator() throws Exception { + + decorator = DecoratorUtils.newMultiJXPathDecorator(JXPathDecorator.class, "${expression}$s#${nbToken}$d", "#", " - "); + assertEquals("%1$s - %2$d", decorator.getExpression()); + assertDecoratorInternal(); + assertEquals(2, decorator.contexts.length); + decorator.setContextIndex(1); + assertEquals("%1$d - %2$s", decorator.getExpression()); + assertTokens("nbToken", "expression"); + expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getExpression()); + result = decorator.toString(decorator); + assertEquals(expected, result); + + decorator = DecoratorUtils.newMultiJXPathDecorator(JXPathDecorator.class, "${expression}$s ## ${nbToken}$d", " ## ", " - "); + assertEquals("%1$s - %2$d", decorator.getExpression()); + assertDecoratorInternal(); + assertEquals(2, decorator.contexts.length); + decorator.setContextIndex(1); + assertEquals("%1$d - %2$s", decorator.getExpression()); + assertTokens("nbToken", "expression"); + expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getExpression()); + result = decorator.toString(decorator); + assertEquals(expected, result); + } + + @Test + public void testMultiDecorator2() throws Exception { + + decorator = DecoratorUtils.newMultiJXPathDecorator(JXPathDecorator.class, "${expression}$s#${nbToken}$d#${separator}$s", "#", " - "); + + assertEquals("%1$s - %2$d - %3$s", decorator.getExpression()); + assertTokens("expression", "nbToken", "separator"); + assertEquals(3, decorator.contexts.length); + + expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator()); + result = decorator.toString(decorator); + assertEquals(expected, result); + + decorator.setContextIndex(1); + assertEquals("%1$d - %2$s - %3$s", decorator.getExpression()); + assertTokens("nbToken", "separator", "expression"); + expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator(), decorator.getExpression()); + result = decorator.toString(decorator); + assertEquals(expected, result); + + decorator.setContextIndex(2); + assertEquals("%1$s - %2$s - %3$d", decorator.getExpression()); + assertTokens("separator", "expression", "nbToken"); + + expected = String.format(decorator.getExpression(), decorator.getSeparator(), decorator.getExpression(), decorator.getNbToken()); + result = decorator.toString(decorator); + assertEquals(expected, result); + } + + @Test + public void testMultiDecoratorWithMultiRef() throws Exception { + + decorator = DecoratorUtils.newMultiJXPathDecorator(JXPathDecorator.class, "${expression}$s#${nbToken}$d#${separator}$s %3$s", "#", " - "); + + assertEquals("%1$s - %2$d - %3$s %3$s", decorator.getExpression()); + assertTokens("expression", "nbToken", "separator"); + assertEquals(3, decorator.contexts.length); + + expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator()); + result = decorator.toString(decorator); + assertEquals(expected, result); + + decorator.setContextIndex(1); + assertEquals("%1$d - %2$s %3$s - %3$s", decorator.getExpression()); + assertTokens("nbToken", "separator", "expression"); + expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator(), decorator.getExpression()); + result = decorator.toString(decorator); + assertEquals(expected, result); + + decorator.setContextIndex(2); + assertEquals("%1$s %3$s - %2$s - %3$d", decorator.getExpression()); + assertTokens("separator", "expression", "nbToken"); + + expected = String.format(decorator.getExpression(), decorator.getSeparator(), decorator.getExpression(), decorator.getNbToken()); + result = decorator.toString(decorator); + assertEquals(expected, result); + } + + @Test + public void testSort() throws Exception { + + List<Data> datas = Data.generate(10); + + MultiJXPathDecorator<Data> d = DecoratorUtils.newMultiJXPathDecorator(Data.class, "${pos}$d-${name}$s", "-"); + + List<Data> sortData = new ArrayList<Data>(datas); + DecoratorUtils.sort(d, sortData, 0); + for (int i = 0; i < datas.size(); i++) { + Data data = datas.get(i); + Data sData = sortData.get(i); + assertEquals(data, sData); + } + Collections.sort(datas, new Comparator<Data>() { + + @Override + public int compare(Data o1, Data o2) { + return o1.name.compareTo(o2.name); + } + }); + d.setContextIndex(1); + DecoratorUtils.sort(d, sortData, 1); + for (int i = 0; i < datas.size(); i++) { + Data data = datas.get(i); + Data sData = sortData.get(i); + assertEquals(data, sData); + } + } + + public void assertDecoratorInternal(String... tokens) { + assertTokens(tokens); + expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken()); + result = decorator.toString(decorator); + assertEquals(expected, result); + } + + private void assertTokens(String... tokens) { + if (tokens.length == 0) { + tokens = new String[]{"expression", "nbToken"}; + } + assertEquals(tokens.length, decorator.nbToken); + assertEquals(tokens.length, decorator.getTokens().length); + for (int i = 0; i < tokens.length; i++) { + assertEquals(tokens[i], decorator.getTokens()[i]); + } + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/decorator/MultiJXPathDecoratorTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/swing/tree/NavigationTreeModelTest.java =================================================================== --- branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/swing/tree/NavigationTreeModelTest.java (rev 0) +++ branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/swing/tree/NavigationTreeModelTest.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,377 @@ +package jaxx.runtime.swing.tree; + +import jaxx.runtime.DefaultJAXXContext; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXContextEntryDef; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Test du model de navigation. + * + * @author chemit + */ +public class NavigationTreeModelTest { + + private static final String ROOT_CONTEXT = "$root"; + private static final String FAKE = "-fake"; + private static final String separator = "/"; + + @Test + public void testFindNode() throws Exception { + + NavigationTreeModelBuilder builder = new NavigationTreeModelBuilder(separator, new DefaultJAXXContext(), null, null); + + NavigationTreeNode rootNode = builder.build(null, (String) null, (String) null, ROOT_CONTEXT, null, null); + + for (int i = 0; i < 4; i++) { + NavigationTreeNode sonNode = builder.build(rootNode, (String) null, (String) null, getNodeContext(i), null, null); + for (int j = 0; j < 4; j++) { + NavigationTreeNode sonSonNode = builder.build(sonNode, (String) null, (String) null, getNodeContext(i, j), null, null); + for (int k = 0; k < 4; k++) { + builder.build(sonSonNode, (String) null, (String) null, getNodeContext(i, j, k), null, null); + } + } + } + + NavigationTreeModel model = builder.getModel(); + + NavigationTreeNode node; + String contextPath; + String currentNode; + + contextPath = ROOT_CONTEXT; + node = model.findNode(contextPath); + assertNodeEquals(contextPath, ROOT_CONTEXT, 0, node, true); + + node = model.findNode(ROOT_CONTEXT + FAKE); + Assert.assertNull(node); + + for (int i = 0; i < 4; i++) { + currentNode = getNodeContext(i); + contextPath = ROOT_CONTEXT + separator + currentNode; + node = model.findNode(contextPath); + assertNodeEquals(contextPath, currentNode, 1, node, false); + + for (int j = 0; j < 4; j++) { + currentNode = getNodeContext(i, j); + contextPath = ROOT_CONTEXT + separator + getNodeContext(i) + separator + currentNode; + node = model.findNode(contextPath); + assertNodeEquals(contextPath, currentNode, 2, node, false); + + for (int k = 0; k < 4; k++) { + currentNode = getNodeContext(i, j, k); + contextPath = ROOT_CONTEXT + separator + getNodeContext(i) + separator + getNodeContext(i, j) + separator + currentNode; + node = model.findNode(contextPath); + assertNodeEquals(contextPath, currentNode, 3, node, false); + } + + node = model.findNode(ROOT_CONTEXT + separator + getNodeContext(i) + separator + getNodeContext(i, j) + separator + currentNode + FAKE); + Assert.assertNull(node); + } + + node = model.findNode(ROOT_CONTEXT + separator + getNodeContext(i) + separator + currentNode + FAKE); + Assert.assertNull(node); + + } + + } + + /** + * Test the {@link NavigationTreeModel#getJAXXContextValue(jaxx.runtime.JAXXContext, String)} with an entry point + * as a bean. + * <p/> + * Tree is like this + * <pre> + * $root + + * - name <-- attached to context entry : java.lang.String.class,"name" + * - name2 <-- attached to context entry : java.lang.String.class,"name2" + * - model + <-- attached to context entry : Model.class,null + * - name + * -integerValue + * - sons + + * - 0 + + * - name + * - integerValue + * - sons + * - 1 + + * - name + * - integerValue + * - sons + * - 2 + + * - name + * - integerValue + * - sons + * </pre> + * <p/> + * With this tree, we will have to results : + * <pre> + * $root.name => context.get(String.class,"name") + * $root.name2 => context.get(String.class,"name2") + * $root.model => context.get(Model.class) + * $root.model.name => context.get(Model.class).getName() + * $root.model.integerValue => context.get(Model.class).getIntegerValue() + * $root.model.sons => context.get(Model.class).getSons() + * $root.model.sons.0 => context.get(Model.class).getSons().get(0) + * </pre> + * + * @throws Exception if any pb + */ + @Test + public void testGetJAXXContextValue() throws Exception { + + JAXXContext context = new DefaultJAXXContext(); + context.setContextValue("the name", "name"); + context.setContextValue("the name2", "name2"); + + + context.setContextValue( + new Model("modelName", 10, + Arrays.asList( + new Model("one", 1, Collections.<Model>emptyList()), + new Model("two", 2, Collections.<Model>emptyList()), + new Model("three", 3, Collections.<Model>emptyList())))); + + NavigationTreeModelBuilder builder = new NavigationTreeModelBuilder(separator, context, null, null); + + NavigationTreeNode rootNode = builder.build(null, (String) null, (String) null, ROOT_CONTEXT, null, null); + + NavigationTreeNode sonNode; + NavigationTreeNode sonSonNode; + NavigationTreeNode sonSonSonNode; + + builder.build(rootNode, (String) null, JAXXContextEntryDef.newDef("name", String.class), "name", null, null); + builder.build(rootNode, (String) null, JAXXContextEntryDef.newDef("name2", String.class), "name2", null, null); + + sonNode = builder.build(rootNode, (String) null, JAXXContextEntryDef.newDef(Model.class), "model", null, null); + + builder.build(sonNode, (String) null, "../name", "name", null, null); + builder.build(sonNode, (String) null, "../integerValue", "integerValue", null, null); + + sonSonNode = builder.build(sonNode, (String) null, "../sons", "sons", null, null); + + sonSonSonNode = builder.build(sonSonNode, (String) null, "..[1]", 0 + "", null, null); + + builder.build(sonSonSonNode, (String) null, "../name", "name", null, null); + builder.build(sonSonSonNode, (String) null, "../integerValue", "integerValue", null, null); + builder.build(sonSonSonNode, (String) null, "../sons", "sons", null, null); + + sonSonSonNode = builder.build(sonSonNode, (String) null, "..[2]", 1 + "", null, null); + + builder.build(sonSonSonNode, (String) null, "../name", "name", null, null); + builder.build(sonSonSonNode, (String) null, "../integerValue", "integerValue", null, null); + builder.build(sonSonSonNode, (String) null, "../sons", "sons", null, null); + + sonSonSonNode = builder.build(sonSonNode, (String) null, (String) null, 2 + "", null, null); + //sonSonSonNode = model.new NavigationTreeNode(null, "..[3]", 2 + "", null, null); + sonSonNode.insert(sonSonSonNode, 2); + builder.build(sonSonSonNode, (String) null, "../..[3]/name", "name", null, null); + builder.build(sonSonSonNode, (String) null, "../..[3]/integerValue", "integerValue", null, null); + builder.build(sonSonSonNode, (String) null, "../..[3]/sons", "sons", null, null); + + NavigationTreeModel model = builder.getModel(); + + Assert.assertNull(model.getBean("$root.name" + FAKE)); + + testBinding(model, context, "$root/name", context.getContextValue(String.class, "name")); + testBinding(model, context, "$root/name2", context.getContextValue(String.class, "name2")); + + Model bean = context.getContextValue(Model.class); + + testBinding(model, context, "$root/model", bean); + testBinding(model, context, "$root/model/name", bean.getName()); + testBinding(model, context, "$root/model/integerValue", bean.getIntegerValue()); + testBinding(model, context, "$root/model/sons", bean.getSons()); + + testBinding(model, context, "$root/model/sons/0/name", bean.getSons().get(0).getName()); + testBinding(model, context, "$root/model/sons/0/integerValue", bean.getSons().get(0).getIntegerValue()); + testBinding(model, context, "$root/model/sons/0/sons", bean.getSons().get(0).getSons()); + + + testBinding(model, context, "$root/model/sons/1/name", bean.getSons().get(1).getName()); + testBinding(model, context, "$root/model/sons/1/integerValue", bean.getSons().get(1).getIntegerValue()); + testBinding(model, context, "$root/model/sons/1/sons", bean.getSons().get(1).getSons()); + + testBinding(model, context, "$root/model/sons/2/name", bean.getSons().get(2).getName()); + testBinding(model, context, "$root/model/sons/2/integerValue", bean.getSons().get(2).getIntegerValue()); + testBinding(model, context, "$root/model/sons/2/sons", bean.getSons().get(2).getSons()); + } + + /** + * Test the {@link NavigationTreeModel#getJAXXContextValue(jaxx.runtime.JAXXContext, String)} with an entry point + * as a list. + * <p/> + * Tree is like this + * <pre> + * $root + + * - models + <-- attached to context entry : java.util.List.class,"models" + * - 0 + + * - name + * -integerValue + * - sons + + * - 0 + + * - name + * - 1 + + * - name + * - integerValue + * - sons + * - 2 + + * - name + * - integerValue + * - sons + * </pre> + * <p/> + * With this tree, we will have to results : + * <pre> + * $root.models => context.get(List.class,"models") + * $root.models.0 => context.get(List.class,"models").get(0) + * $root.models.0.name => context.get(List.class,"models").get(0).getName() + * </pre> + * + * @throws Exception if any pb + */ + @Test + public void testGetBeanFromList() throws Exception { + + List<Model> list = Arrays.asList( + new Model("entryOne", 10, + Arrays.asList( + new Model("one", 1, Collections.<Model>emptyList()), + new Model("two", 2, Collections.<Model>emptyList()), + new Model("three", 3, Collections.<Model>emptyList()))), + new Model("entryTwo", 20, + Arrays.asList( + new Model("2one", 1, Collections.<Model>emptyList()), + new Model("2two", 2, Collections.<Model>emptyList()), + new Model("2three", 3, Collections.<Model>emptyList()))), + new Model("entryThree", 30, + Arrays.asList( + new Model("3one", 1, Collections.<Model>emptyList()), + new Model("3two", 2, Collections.<Model>emptyList()), + new Model("3three", 3, Collections.<Model>emptyList())))); + JAXXContext context = new DefaultJAXXContext(); + context.setContextValue(list, "models"); + + + NavigationTreeModelBuilder builder = new NavigationTreeModelBuilder(separator, context, null, null); + + NavigationTreeNode rootNode = builder.build(null, (String) null, (String) null, ROOT_CONTEXT, null, null); + + NavigationTreeNode sonNode; + NavigationTreeNode sonSonNode; + NavigationTreeNode sonSonSonNode; + + // first son is a list of models + sonNode = builder.build(rootNode, (String) null, JAXXContextEntryDef.newListDef("models"), "models", null, null); + + // first son son is a model + sonSonNode = builder.build(sonNode, (String) null, "..[1]", "0", null, null); + + builder.build(sonSonNode, (String) null, "../name", "name", null, null); + builder.build(sonSonNode, (String) null, "../integerValue", "integerValue", null, null); + sonSonNode = builder.build(sonSonNode, (String) null, "../sons", "sons", null, null); + + sonSonSonNode = builder.build(sonSonNode, (String) null, "..[1]", "0", null, null); + builder.build(sonSonSonNode, (String) null, "../name", "name", null, null); + + // second son son is a model + sonSonNode = builder.build(sonNode, (String) null, "..[2]", "1", null, null); + + builder.build(sonSonNode, (String) null, "../name", "name", null, null); + builder.build(sonSonNode, (String) null, "../integerValue", "integerValue", null, null); + builder.build(sonSonNode, (String) null, "../sons", "sons", null, null); + + // third son son is a model + sonSonNode = builder.build(sonNode, (String) null, "..[3]", "2", null, null); + + builder.build(sonSonNode, (String) null, "../name", "name", null, null); + builder.build(sonSonNode, (String) null, "../integerValue", "integerValue", null, null); + builder.build(sonSonNode, (String) null, "../sons", "sons", null, null); + + NavigationTreeModel model = builder.getModel(); + + Model bean; + + testBinding(model, context, "$root/models", list); + + bean = list.get(0); + testBinding(model, context, "$root/models/0", bean); + testBinding(model, context, "$root/models/0/name", bean.getName()); + testBinding(model, context, "$root/models/0/integerValue", bean.getIntegerValue()); + testBinding(model, context, "$root/models/0/sons", bean.getSons()); + testBinding(model, context, "$root/models/0/sons/0", bean.getSons().get(0)); + testBinding(model, context, "$root/models/0/sons/0/name", bean.getSons().get(0).getName()); + + bean = list.get(1); + testBinding(model, context, "$root/models/1", bean); + testBinding(model, context, "$root/models/1/name", bean.getName()); + testBinding(model, context, "$root/models/1/integerValue", bean.getIntegerValue()); + testBinding(model, context, "$root/models/1/sons", bean.getSons()); + + bean = list.get(2); + testBinding(model, context, "$root/models/2", bean); + testBinding(model, context, "$root/models/2/name", bean.getName()); + testBinding(model, context, "$root/models/2/integerValue", bean.getIntegerValue()); + testBinding(model, context, "$root/models/2/sons", bean.getSons()); + + } + + protected void testBinding(NavigationTreeModel model, JAXXContext context, String contextPath, Object expected) throws Exception { + + Object value; + value = model.getBean(contextPath); + Assert.assertNotNull(value); + Assert.assertEquals(expected, value); + } + + protected String getNodeContext(int... context) { + String result = ""; + for (int i : context) { + result += i; + } + return result; + } + + protected void assertNodeEquals(String contextPath, String nodeContext, int level, NavigationTreeNode node, boolean root) { + //System.out.println(contextPath + " : " + (node == null ? null : node.getContextPath())); + Assert.assertNotNull(node); + Assert.assertEquals(root, node.isRoot()); + Assert.assertEquals(level, node.getLevel()); + Assert.assertEquals(nodeContext, node.getNodePath()); + Assert.assertEquals(contextPath, node.getFullPath()); + } + + public static class Model { + + protected String name; + protected int integerValue; + protected List<Model> sons; + + public Model(String name, int integerValue, List<Model> sons) { + this.name = name; + this.integerValue = integerValue; + this.sons = sons; + } + + public String getName() { + return name; + } + + public int getIntegerValue() { + return integerValue; + } + + public List<Model> getSons() { + return sons; + } + + @Override + public String toString() { + return super.toString() + "<name:" + name + ",integerValue:" + integerValue + ",sons: " + sons + ">"; + } + } +} Property changes on: branches/jaxx-2.X/jaxx-runtime/src/test/java/jaxx/runtime/swing/tree/NavigationTreeModelTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/jaxx-widgets/src/main/resources/i18n/jaxx-widgets-en_GB.properties =================================================================== --- branches/jaxx-2.X/jaxx-widgets/src/main/resources/i18n/jaxx-widgets-en_GB.properties (rev 0) +++ branches/jaxx-2.X/jaxx-widgets/src/main/resources/i18n/jaxx-widgets-en_GB.properties 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,70 @@ +aboutframe.about= +aboutframe.license= +aboutframe.ok= +aboutframe.thirdparty= +columnselector.action.tip= +config.action.quit= +config.action.quit.tip= +config.action.reset= +config.action.reset.tip= +config.action.save= +config.action.save.tip= +config.category.saved= +config.choice.cancel= +config.choice.continue= +config.choice.doNotSave= +config.choice.ok= +config.choice.save= +config.defaultValue= +config.defaultValue.tip= +config.descrition= +config.error.category.already.exists= +config.error.category.not.found= +config.key= +config.key.tip= +config.message.quit.invalid.category= +config.message.quit.valid.and.modified.category= +config.modified= +config.no.option.selected= +config.option.final= +config.option.label= +config.option.modified= +config.title= +config.title.need.confirm= +config.title.will.reload.application= +config.unmodifiable= +config.unvalid= +config.value= +config.value.tip= +entitycombobox.action.reset.tip= +entitycombobox.action.sort.tip= +entitycombobox.popup.label= +entitycombobox.popup.title= +entitycombobox.sort.off= +entitycombobox.sort.on= +entitycombobox.unknown.type= +errorUI.action.close= +errorUI.message= +errorUI.title= +i18neditor.empty.locales= +i18neditor.popup.title= +i18neditor.selected= +i18neditor.unselected= +memorywidget.memory= +numbereditor..= +numbereditor.0= +numbereditor.1= +numbereditor.2= +numbereditor.3= +numbereditor.4= +numbereditor.5= +numbereditor.6= +numbereditor.7= +numbereditor.8= +numbereditor.9= +numbereditor.action.reset.tip= +numbereditor.action.show.tip= +numbereditor.clearAll= +numbereditor.clearOne= +numbereditor.toggleSign= +timeeditor.H= Added: branches/jaxx-2.X/jaxx-widgets/src/main/resources/i18n/jaxx-widgets-fr_FR.properties =================================================================== --- branches/jaxx-2.X/jaxx-widgets/src/main/resources/i18n/jaxx-widgets-fr_FR.properties (rev 0) +++ branches/jaxx-2.X/jaxx-widgets/src/main/resources/i18n/jaxx-widgets-fr_FR.properties 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,70 @@ +aboutframe.about= +aboutframe.license= +aboutframe.ok= +aboutframe.thirdparty= +columnselector.action.tip= +config.action.quit= +config.action.quit.tip= +config.action.reset= +config.action.reset.tip= +config.action.save= +config.action.save.tip= +config.category.saved= +config.choice.cancel= +config.choice.continue= +config.choice.doNotSave= +config.choice.ok= +config.choice.save= +config.defaultValue= +config.defaultValue.tip= +config.descrition= +config.error.category.already.exists= +config.error.category.not.found= +config.key= +config.key.tip= +config.message.quit.invalid.category= +config.message.quit.valid.and.modified.category= +config.modified= +config.no.option.selected= +config.option.final= +config.option.label= +config.option.modified= +config.title= +config.title.need.confirm= +config.title.will.reload.application= +config.unmodifiable= +config.unvalid= +config.value= +config.value.tip= +entitycombobox.action.reset.tip= +entitycombobox.action.sort.tip= +entitycombobox.popup.label= +entitycombobox.popup.title= +entitycombobox.sort.off= +entitycombobox.sort.on= +entitycombobox.unknown.type= +errorUI.action.close= +errorUI.message= +errorUI.title= +i18neditor.empty.locales= +i18neditor.popup.title= +i18neditor.selected= +i18neditor.unselected= +memorywidget.memory= +numbereditor..= +numbereditor.0= +numbereditor.1= +numbereditor.2= +numbereditor.3= +numbereditor.4= +numbereditor.5= +numbereditor.6= +numbereditor.7= +numbereditor.8= +numbereditor.9= +numbereditor.action.reset.tip= +numbereditor.action.show.tip= +numbereditor.clearAll= +numbereditor.clearOne= +numbereditor.toggleSign= +timeeditor.H= Added: branches/jaxx-2.X/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/plugin/ComboBoxTest.java =================================================================== --- branches/jaxx-2.X/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/plugin/ComboBoxTest.java (rev 0) +++ branches/jaxx-2.X/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/plugin/ComboBoxTest.java 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,84 @@ +package org.nuiton.jaxx.plugin; + +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXCompilerLaunchor; +import org.apache.maven.plugin.MojoExecutionException; + +import java.lang.reflect.Field; +import java.util.Map; + +import org.apache.maven.plugin.logging.SystemStreamLog; +import org.junit.Test; +import static org.junit.Assert.*; + +public class ComboBoxTest extends JaxxBaseTest { + + @Test + public void ok() throws Exception { + JaxxGeneratorMojo mojo = getMojo(); + mojo.execute(); + checkPattern(mojo, "swingComboBox", true, "org/nuiton/jaxx/plugin/ComboBoxTest/ok/swingcombo.java"); + assertNumberJaxxFiles(2); + } + + @SuppressWarnings({"unchecked"}) + @Test + public void error() throws Exception { + JaxxGeneratorMojo mojo = getMojo(); + // init mojo to get alls files to treate + mojo.init(); + + assertNumberJaxxFiles(1); + + mojo.setLog(new SystemStreamLog() { + + @Override + public boolean isErrorEnabled() { + return false; + } + + @Override + public void error(Throwable error) { + //do nothing + } + + @Override + public void error(CharSequence content) { + //do nothing + } + + @Override + public void error(CharSequence content, Throwable error) { + //do nothing + } + }); + Field fieldCompilers = JAXXCompilerLaunchor.class.getDeclaredField("compilers"); + Field fieldErrorCount = JAXXCompilerLaunchor.class.getDeclaredField("errorCount"); + + fieldCompilers.setAccessible(true); + fieldErrorCount.setAccessible(true); + + + // execute mjo on each jaxx file to produce the error + for (String file : mojo.files) { + log.info("test bad file " + file); + mojo.files = new String[]{file}; + try { + mojo.doAction(); + // should never pass + fail(); + } catch (MojoExecutionException e) { + // ok jaxx compiler failed + assertTrue(true); + + JAXXCompilerLaunchor launchor = JAXXCompilerLaunchor.get(); + Map<String, JAXXCompiler> compilers = (Map<String, JAXXCompiler>) fieldCompilers.get(launchor); + assertEquals(1, compilers.size()); + //JAXXCompiler compiler; + //compiler = compilers.values().iterator().next(); + Integer nberrors = (Integer) fieldErrorCount.get(launchor); + assertTrue(nberrors != null && nberrors > 0); + } + } + } +} Property changes on: branches/jaxx-2.X/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/plugin/ComboBoxTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/error/swingcombo.jaxx =================================================================== --- branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/error/swingcombo.jaxx (rev 0) +++ branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/error/swingcombo.jaxx 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,4 @@ + +<JComboBox id='comboBox'> + <item value='{_("OK")}' selected='true'/> +</JComboBox> \ No newline at end of file Added: branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/error.xml =================================================================== --- branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/error.xml (rev 0) +++ branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/error.xml 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.nuiton.jaxx.test</groupId> + <artifactId>test</artifactId> + <version>0</version> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/target/test-classes</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <verbose>true</verbose> + <includes> + <value>**/ComboBoxTest/error/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file Added: branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok/jaxxcombo.jaxx =================================================================== --- branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok/jaxxcombo.jaxx (rev 0) +++ branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok/jaxxcombo.jaxx 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,4 @@ + +<JAXXComboBox id='comboBox'> + <item value='OK' selected='true'/> +</JAXXComboBox> \ No newline at end of file Added: branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok/swingcombo.jaxx =================================================================== --- branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok/swingcombo.jaxx (rev 0) +++ branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok/swingcombo.jaxx 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,2 @@ + +<JComboBox id='swingComboBox'/> \ No newline at end of file Added: branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok.xml =================================================================== --- branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok.xml (rev 0) +++ branches/jaxx-2.X/maven-jaxx-plugin/src/test/resources/org/nuiton/jaxx/plugin/ComboBoxTest/ok.xml 2009-10-05 19:16:52 UTC (rev 1560) @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.nuiton.jaxx.test</groupId> + <artifactId>test</artifactId> + <version>0</version> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/target/test-classes</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <includes> + <value>**/ComboBoxTest/ok/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file
participants (1)
-
tchemit@users.nuiton.org