Commit 36671252 authored by Dumoulin Nicolas's avatar Dumoulin Nicolas
Browse files

swing basics moved to a dedicated module

parent 651f4209
......@@ -26,6 +26,7 @@
<module>core</module>
<module>ui-nodes</module>
<module>ui-swing</module>
<module>ui-swing-basiccontrols</module>
<module>demo</module>
</modules>
......
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>fr.cemagref.ohoui</groupId>
<artifactId>ohoui</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>ohoui-ui-swing-basiccontrols</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId} ${project.version}</name>
<dependencies>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-openide-util</artifactId>
</dependency>
<dependency>
<groupId>fr.cemagref.ohoui</groupId>
<artifactId>ohoui-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.sun</groupId>
<artifactId>jlfgr</artifactId>
</dependency>
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
</dependency>
</dependencies>
</project>
/*
* Copyright (C) 2010 Cemagref
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.cemagref.ohoui.ui.swing.basiccontrols;
import fr.cemagref.ohoui.structure.OhObject;
/**
* Defines common behavior for editors for an object.
*
* @author Nicolas Dumoulin <nicolas.dumoulin@cemagref.fr>
* @param <T> The type of the edited object
* @param <P> The type of graphical component used
*/
public abstract class AbstractOhEditor<T, P> {
protected OhObject<T> object;
protected P panel;
public AbstractOhEditor(OhObject object) {
this.object = object;
}
/**
* Gets the object edited. This method doesn't achieve any update relative
* to the edited value.
* @return
*/
public OhObject<T> getOhObject() {
return object;
}
public void setOhObject(OhObject<T> object) {
this.object = object;
}
/**
* Returns the value up-to-date of the edited object.
* @return The object edited
*/
public abstract T getValue();
public P getPanel() {
return panel;
}
public final void setEnabled(boolean enabled) {
enableComponent(enabled);
// recursively enable/disable container and its enclosing container and
// components
recursivelyEnableComponent(panel, enabled);
}
public abstract boolean isEnabled();
protected abstract void enableComponent(boolean enabled);
protected abstract void recursivelyEnableComponent(P container, boolean enabled);
}
/*
* Copyright (C) 2010 Cemagref
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.cemagref.ohoui.ui.swing.basiccontrols;
import java.awt.event.ActionListener;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JButton;
public class ControlsFactory {
public static JButton makeButton(String imageName, ActionListener listener, String toolTipText, String altText) {
// Look for the image.
String imgLocation = "toolbarButtonGraphics/" + imageName + ".gif";
URL imageURL = ControlsFactory.class.getClassLoader().getResource(imgLocation);
// Create and initialize the button.
JButton button = new JButton();
button.setToolTipText(toolTipText);
button.addActionListener(listener);
if (imageURL != null) {
// image found
button.setIcon(new ImageIcon(imageURL, altText));
} else {
// no image found
button.setText(altText);
System.err.println("Resource not found: " + imgLocation);
}
return button;
}
}
/*
* Copyright (C) 2010 Cemagref
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.cemagref.ohoui.ui.swing.basiccontrols;
import fr.cemagref.ohoui.structure.OhObject;
import fr.cemagref.ohoui.structure.OhObjectCollection;
import fr.cemagref.ohoui.structure.OhObjectComplex;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import org.objenesis.ObjenesisHelper;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
/**
* Default implementation of editor for an ohObjectComplex, it produces an editor by
* assembling editors for each field.
*
* @author Nicolas Dumoulin <nicolas.dumoulin@cemagref.fr>
*/
public class DefaultObjectEditor extends AbstractOhEditor<Object, JComponent> {
private List<AbstractOhEditor> childrenEditors = new ArrayList<AbstractOhEditor>();
private JPanel pagePanel = new JPanel();
public DefaultObjectEditor(OhObjectComplex<?> object) {
super(object);
panel = new JPanel();
panel.add(pagePanel, BorderLayout.NORTH);
pagePanel.setLayout(new BoxLayout(pagePanel, BoxLayout.PAGE_AXIS));
for (OhObject child : object) {
// No editors produced for collections, all edit features are provided
// by the tree view
if (child instanceof OhObjectCollection) {
continue;
}
// Editors retrieving for other types
List<Class> availableTypes = new ArrayList<Class>();
availableTypes.add(child.getDeclaredType());
availableTypes.addAll(Lookup.getDefault().lookupResult(child.getDeclaredType()).allClasses());
// TODO filter added types to retain only instanciable types
if (child.getValue() == null) {
// object has null value, so building specific panel for instanciating it
OhEditorPanel editor = new OhEditorPanel(object) {
@Override
public Object getValue() {
return null;
}
};
editor.setEnabled(false);
editor.addLabel(child.getName(), child.getDescription());
if (availableTypes.size() == 0) {
editor.addComponent(new JLabel("null"), "No type have been found to affect a new instance in this variable.");
} else {
editor.addComponent(ControlsFactory.makeButton("general/New16",
new EditTypeAction(this, editor, child, availableTypes.toArray(new Class[]{}), childrenEditors.size()),
"", "New"), "Create a new instance");
}
pagePanel.add((JComponent) editor.getPanel());
childrenEditors.add(editor);
} else if (EditorsProvider.hasEditorFor(child)) {
// adding provided editor
addEditorFor(child);
}
}
}
private void addEditorFor(OhObject object, int index) {
AbstractOhEditor<Object, JComponent> editor = EditorsProvider.createEditorFor(object);
if (editor != null) {
// TODO add button for reinstanciate object
pagePanel.add((JComponent) editor.getPanel(), index);
childrenEditors.add(editor);
} else {
// TODO it shouldn't occur, but as collections don't have editor, it can
pagePanel.add(new JPanel(), index);
}
pagePanel.revalidate();
}
private void addEditorFor(OhObject object) {
addEditorFor(object, childrenEditors.size());
}
@Override
public boolean isEnabled() {
return panel.isEnabled();
}
@Override
protected void enableComponent(boolean enabled) {
panel.setEnabled(enabled);
}
@Override
protected void recursivelyEnableComponent(JComponent component, boolean enabled) {
for (Component subComponent : component.getComponents()) {
if (subComponent instanceof JComponent) {
JComponent subJComponent = (JComponent) subComponent;
recursivelyEnableComponent(subJComponent, enabled);
}
subComponent.setEnabled(enabled);
}
}
@Override
public Object getValue() {
// update objects values for each registered editors
for (AbstractOhEditor editor : childrenEditors) {
if (editor.isEnabled()) {
try {
editor.getOhObject().setValue(editor.getValue());
} catch (IllegalArgumentException ex) {
Exceptions.printStackTrace(ex);
} catch (IllegalAccessException ex) {
Exceptions.printStackTrace(ex);
}
}
}
return getOhObject();
}
/**
* Action to edit the type of an object and update the editor.
*/
private final class EditTypeAction implements ActionListener {
private DefaultObjectEditor container;
private OhEditorPanel currentObjectEditor;
private OhObject ohObject;
private Class[] availableTypes;
private int editorIndex;
public EditTypeAction(DefaultObjectEditor container, OhEditorPanel currentObjectEditor, OhObject ohObject, Class[] availableTypes, int editorIndex) {
this.container = container;
this.currentObjectEditor = currentObjectEditor;
this.ohObject = ohObject;
this.availableTypes = availableTypes;
this.editorIndex = editorIndex;
}
@Override
public void actionPerformed(ActionEvent e) {
Class chosenType;
if (availableTypes.length == 1) {
chosenType = availableTypes[0];
} else {
// bring a dialog to choose the type
chosenType = (Class) JOptionPane.showInputDialog(panel,
"Choose the type you want to use", "Choose a type", JOptionPane.QUESTION_MESSAGE, null,
availableTypes, availableTypes[0]);
}
if (chosenType != null) {
try {
// instanciate
ohObject.setValue(ObjenesisHelper.newInstance(chosenType));
// remove current editor
childrenEditors.remove(currentObjectEditor);
pagePanel.remove(editorIndex);
// build the corresponding panel and add the panel in place
container.addEditorFor(ohObject, editorIndex);
// TODO notify the tree if a list is added for example
} catch (IllegalArgumentException ex) {
Exceptions.printStackTrace(ex);
} catch (IllegalAccessException ex) {
Exceptions.printStackTrace(ex);
}
}
}
}
}
/*
* Copyright (C) 2010 Cemagref
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.cemagref.ohoui.ui.swing.basiccontrols;
import fr.cemagref.ohoui.structure.OhObject;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import org.openide.util.Lookup;
/**
* Singleton class that provides graphical editors depending on the type
* of the object to edit.
*
* @author Nicolas Dumoulin <nicolas.dumoulin@cemagref.fr>
*/
public class EditorsProvider {
private static EditorsProvider instance;
private static final Logger LOGGER = Logger.getLogger(EditorsProvider.class.getName());
private Map<Class, OhEditorProducer> editorProducers;
private EditorsProvider() {
editorProducers = new HashMap<Class, OhEditorProducer>();
for (OhEditorProducer producer : Lookup.getDefault().lookupAll(OhEditorProducer.class)) {
for (Class type : producer.getCompatibleTypes()) {
OhEditorProducer old = editorProducers.put(type, producer);
if (old != null) {
StringBuilder buf = new StringBuilder("Editors conflicts for type ").append(type);
buf.append(", two editors found:\n ").append(old).append(" (removed)\n ");
buf.append(producer).append(" (retained)");
LOGGER.warning(buf.toString());
}
}
}
if (LOGGER.isLoggable(Level.INFO)) {
StringBuilder buf = new StringBuilder("Producers loaded: ");
for (Map.Entry<Class, OhEditorProducer> producer : editorProducers.entrySet()) {
buf.append(" ").append(producer.getKey()).append(" -> ").append(producer.getValue()).append("\n");
}
LOGGER.info(buf.toString());
}
}
private static EditorsProvider getDefault() {
if (instance == null) {
instance = new EditorsProvider();
}
return instance;
}
public static boolean hasEditorFor(OhObject ohObject) {
if (ohObject.getValue() != null) {
return getDefault().editorProducers.containsKey(ohObject.getValue().getClass());
}
return true;
}
public static AbstractOhEditor<Object, JComponent> createEditorFor(OhObject ohObject) {
OhEditorProducer editor = null;
if (ohObject.getValue() != null) {
editor = getDefault().editorProducers.get(ohObject.getValue().getClass());
}
if (editor == null) {
// TODO return an new DefaultObjectEditor ? should be avoided upstream
}
return (editor == null) ? null : editor.getEditor(ohObject);
}
}
package fr.cemagref.ohoui.ui.swing.basiccontrols;
import fr.cemagref.ohoui.structure.OhObject;
import java.awt.Component;
import java.awt.FlowLayout;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
* Default implementation for producing a Panel from an ohObject.
*
* @author Nicolas Dumoulin <nicolas.dumoulin@cemagref.fr>
*/
public abstract class OhEditorPanel<T> extends AbstractOhEditor<T, JComponent> {
protected OhEditorPanel(OhObject<T> object) {
super(object);
panel = new JPanel();
panel.setLayout(new FlowLayout(FlowLayout.LEFT));
this.object = object;
}
public JLabel addLabel(String label, String tooltip) {
JLabel jlabel = new JLabel(label);
jlabel.setPreferredSize(SwingDefaults.labelMinimumSize);
if ((tooltip != null) && (!"".equals(tooltip))) {
jlabel.setToolTipText(tooltip);
}
panel.add(jlabel);
return jlabel;
}
public void addComponent(JComponent component, String tooltip) {
component.setAlignmentX(SwingDefaults.labelAlignment);
if (!"".equals(tooltip)) {
component.setToolTipText(tooltip);
}
panel.add(component);
}
@Override
public boolean isEnabled() {
return panel.isEnabled();
}
@Override
protected void enableComponent(boolean enabled) {
panel.setEnabled(enabled);
}
@Override
protected void recursivelyEnableComponent(JComponent component, boolean enabled) {
for (Component subComponent : component.getComponents()) {
if (subComponent instanceof JComponent) {
JComponent subJComponent = (JComponent) subComponent;
recursivelyEnableComponent(subJComponent, enabled);
}
subComponent.setEnabled(enabled);
}
}
}
/*
* Copyright (C) 2010 Cemagref
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.cemagref.ohoui.ui.swing.basiccontrols;
import fr.cemagref.ohoui.structure.OhObject;
public interface OhEditorProducer<T, P> {
/**
* Gets the list of classes who can be edited by the editors produced by this object.
* @return the list of classes handled
*/
public Class[] getCompatibleTypes();
public AbstractOhEditor<T, P> getEditor(OhObject<T> object);
}
/*
* Copyright (C) 2010 Cemagref
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 Public License for more details.
*
* You should have received a copy of the GNU General Public License