--- /dev/null
+<?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>
+ <groupId>jp.ac.aiit.xdf</groupId>
+ <artifactId>xdf-all</artifactId>
+ <packaging>pom</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <name>xdf-all</name>
+ <url>http://maven.apache.org</url>
+
+ <modules>
+ <module>xdf</module>
+ <module>xdf-swing</module>
+ <module>xdf-swingx</module>
+ <module>xdf-spring</module>
+ </modules>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.5.6</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>0.9.13</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>0.9.13</version>
+ <optional>true</optional>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+<?xml version="1.0"?>
+<project>
+ <parent>
+ <artifactId>xdf-all</artifactId>
+ <groupId>jp.ac.aiit.xdf</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>jp.ac.aiit.xdf.spring</groupId>
+ <artifactId>xdf-spring</artifactId>
+ <name>xdf-spring</name>
+ <version>1.0-SNAPSHOT</version>
+ <url>http://maven.apache.org</url>
+ <dependencies>
+ <dependency>
+ <groupId>jp.ac.aiit.xdf</groupId>
+ <artifactId>xdf</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring</artifactId>
+ <version>2.5.6</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package jp.ac.aiit.xdf.spring;
+
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.core.action.factory.ActionFactory;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * Spring Frameworkによってインスタンス化されたアクションを読み込むクラス
+ * アプリケーションにこのアクションファクトリを指定することで、Springのマネージドビーンをアクションとして利用できる。
+ *
+ * @author Shunichi Takagi
+ *
+ */
+public class SpringActionFactory implements ActionFactory {
+ private ApplicationContext context;
+
+ private SpringActionFactory(ApplicationContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public Action createAction(String name) {
+ return (Action) context.getBean(name);
+ }
+
+ public static SpringActionFactory fromClasspath(String configLocation) {
+ return new SpringActionFactory(new ClassPathXmlApplicationContext(configLocation));
+ }
+}
--- /dev/null
+<?xml version="1.0"?>
+<project>
+ <parent>
+ <artifactId>xdf-all</artifactId>
+ <groupId>jp.ac.aiit.xdf</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>jp.ac.aiit.xdf.component.swing
+ </groupId>
+ <artifactId>xdf-swing</artifactId>
+ <name>xdf-swing</name>
+ <version>1.0-SNAPSHOT</version>
+ <url>http://maven.apache.org</url>
+ <dependencies>
+ <dependency>
+ <groupId>jp.ac.aiit.xdf</groupId>
+ <artifactId>xdf</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package jp.ac.aiit.xdf.component.swing;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Map;
+
+import jp.ac.aiit.xdf.application.TagReferences;
+import jp.ac.aiit.xdf.core.exceptions.UnexpectedBehaviorException;
+import jp.ac.aiit.xdf.core.tags.TagLoader;
+import jp.ac.aiit.xdf.core.tags.Tagdef.Tag;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * xdf-swingプラグインが提供するSwing用XDFタグセットをロードするためのクラス。
+ * このクラスのインスタンスをApplicationに与えることで、このクラスが提供するタグセットをアプリケーション上で利用することが出来る。
+ *
+ * @see jp.ac.aiit.xdf.application.Application
+ * @see jp.ac.aiit.xdf.application.TagReferences
+ *
+ * @author Shunichi Takagi
+ */
+public class SwingTagReferences implements TagReferences {
+ private static final Logger log = LoggerFactory.getLogger(SwingTagReferences.class);
+ private static final String SWING_TAGS = "xdf-swingtags.xml";
+
+ @Override
+ public Map<String, Tag> getDefinedTags() {
+ try {
+ URL url = ClassLoader.getSystemResource(SWING_TAGS);
+
+ TagLoader loader = new TagLoader();
+ return loader.load(new File(url.toURI()));
+ } catch(URISyntaxException e) {
+ log.error("Swing用タグ定義ファイルがロードできません。", e);
+ throw new UnexpectedBehaviorException("Swing用タグ定義ファイルがロードできません。", e);
+ }
+ }
+
+ @Override
+ public String getReferenceId() {
+ return "swing";
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing;
+
+import javax.swing.Icon;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * タブ1つ分のコンポネント。
+ * <br><tab />で表される。内容は<group />と同様に記述されるべきである。
+ * @author kodama
+ */
+@SuppressWarnings("serial")
+public class Tabpanel extends JPanel{
+
+ private static final Logger log = LoggerFactory.getLogger(Tabpanel.class);
+
+ /** このタブを含んでいるタブ区画。 */
+ private JTabbedPane container = null;
+
+ /** このタブの標題。 →コンポネントのnameが目的を果たす。*/
+// private String title;
+
+ /** このタブのアイコン。 */
+ private Icon icon = null;
+
+ /** このタブのツールヒント。 */
+ private String tooltip = null;
+
+ /** このタブへのキーショートカット(Alt-「1」など) */
+ private int accesskey = -1;
+
+ /**
+ * タブ区画との関連付けを行う。
+ * @param tabbedPane このタブを含んでいるタブ区画。
+ */
+ public void setContainer(JTabbedPane tabbedPane){
+ container = tabbedPane;
+ tabbedPane.addTab(this.getName(), icon, this, tooltip);
+ setAccessKey(accesskey);
+ }
+
+ /**
+ * このタブにアイコンを設定する。
+ * @param icon アイコン
+ */
+ public void setIcon(final Icon icon){
+ if(container == null){
+ log.info("tabpanel : Container not exists yet. Monitoring..");
+ new Thread(){
+ @Override public void run() {
+ while(container == null){
+ try{
+ Thread.sleep(100);
+ } catch(InterruptedException e){
+ return;
+ }
+ }
+ container.setIconAt(index(), icon);
+ log.info("tabpanel : Container found.");
+ }
+ }.start();
+ } else{
+ container.setIconAt(index(), icon);
+ }
+ }
+
+ /**
+ * ツールヒントのテキストをこのタブに設定する。<br>
+ * なお、タブ(つまみ部)にのみ設定し、タブ内容部には設定しない。
+ * @param text ツールヒントのテキスト
+ */
+ @Override
+ public void setToolTipText(String text){
+ //タブ(つまみ部)のToolTipText
+ tooltip = text;
+ if(container != null)
+ container.setToolTipTextAt(index(), text);
+ }
+
+ /**
+ * このタブにキーショートカット(Alt-「1」など)を割当てる。
+ * @param mnemonic ショートカットキー。KeyEvent定数を参照のこと。
+ */
+ public void setAccessKey(int mnemonic){
+ if(container != null)
+ container.setMnemonicAt(index(), mnemonic);
+ }
+
+ /**
+ * このタブにキーショートカット(Alt-「1」など)を割当てる。<br>
+ * キーショートカットの属性値は「Alt-英数」「Alt英数」又は単に「英数」のように指定する。
+ * @param value キーショートカットの文字列表現。
+ */
+ public void setAccessKey(String value){
+ accesskey = toKeyEvent(value);
+ setAccessKey(accesskey);
+ }
+ /**
+ * access属性値をKeyEventに変換する。
+ * <br>【暫定】本来Converterで実現すべきと思われる。
+ * <br>※ char x = [0-9A-Z] に関して、たまたま
+ * (int)x = KeyEvent.VK_x が成り立つという事実に現状は依存している。
+ * @param access access属性値
+ * @return 対応するKeyEvent値。
+ */
+ private static int toKeyEvent(String access){
+// if(access == null || access.isEmpty()) return -1;
+ try{
+ int key = keyOf(access);
+ if(key < '0'){
+ } else if(key <= '9'){ //from '0' to '9'
+ return key;
+ } else if(key < 'A'){
+ } else if(key <= 'Z'){ //from 'A' to 'Z'
+ return key;
+ }
+ } catch(Exception e){
+ }
+ return -1;
+ }
+ private static char keyOf(String access){
+ return
+ access.replaceFirst("[aA][lL][tT]-?", "").toUpperCase().charAt(0);
+ }
+
+ /**
+ * このタブの、タブ区画における位置を返す。
+ * @return タブ区画における位置。
+ */
+ private int index(){
+ return
+ container == null ? -1
+// : container.indexOfTabComponent(this);
+ : container.indexOfComponent(this);
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+/**
+ * 実コンポーネントから属性値を取得するための処理を記述するクラス
+ *
+ * @author Shunichi Takagi
+ */
+public interface AttributeGetProcessor {
+
+ /**
+ * 実際にtargetコンポーネントが保持している属性値を取得する
+ *
+ * @param target 属性値を取得する対象
+ * @param name 取得する属性の名前
+ * @return 実際の属性値
+ */
+ public Object invokeGet(Object target, String name);
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+import jp.ac.aiit.xdf.core.typeconvert.TypeConverter;
+
+/**
+ * 実コンポーネントに対する属性の処理方法(型変換、設定、取得)の組み合わせを保持するクラス
+ *
+ * @author Shunichi Takagi
+ */
+public class AttributeProcessingUnit {
+ private AttributeGetProcessor attributeGetProcessor;
+ private AttributeSetProcessor attributeSetProcessor;
+ private TypeConverter<?> typeConverter;
+
+ /**
+ * 実コンポーネントに対する属性の処理方法
+ * @param attributeProcessor 設定プロセサー
+ * @param typeConverter 型変換
+ */
+ public AttributeProcessingUnit(AttributeProcessor attributeProcessor, TypeConverter<?> typeConverter) {
+ this(attributeProcessor, attributeProcessor, typeConverter);
+ }
+
+ /**
+ * 実コンポーネントに対する属性の処理方法
+ * @param attributeSetProcessor 設定プロセサー
+ * @param attributeGetProcessor 取得プロセサー
+ * @param typeConverter 型変換
+ */
+ public AttributeProcessingUnit(AttributeSetProcessor attributeSetProcessor, AttributeGetProcessor attributeGetProcessor, TypeConverter<?> typeConverter) {
+ this.attributeSetProcessor = attributeSetProcessor;
+ this.attributeGetProcessor = attributeGetProcessor;
+ this.typeConverter = typeConverter;
+ }
+
+ /**
+ * 設定プロセサーの処理
+ * @param target
+ * @param name
+ * @param value
+ */
+ public void invokeSet(Object target, String name, Object value) {
+ attributeSetProcessor.invokeSet(target, name, value);
+ }
+
+ /**
+ * 取得プロセサーの処理
+ * @param target
+ * @param name
+ * @return 取得した値
+ */
+ public Object invokeGet(Object target, String name) {
+ return attributeGetProcessor.invokeGet(target, name);
+ }
+
+ /**
+ * 型変換の処理
+ * @param value
+ * @return 変換後値
+ */
+ public Object typeConvert(String value) {
+ if( typeConverter.isAppliable(value) ) {
+ return typeConverter.apply(value);
+ }
+ return null;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+/**
+ * @author Takagi
+ * 実コンポーネントに対する属性の処理インターフェース
+ *
+ */
+public interface AttributeProcessor extends AttributeGetProcessor, AttributeSetProcessor {
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+/**
+ * 属性値を実コンポーネントに反映する処理を記述するクラス
+ *
+ * @author Shunichi Takagi
+ */
+public interface AttributeSetProcessor {
+ /**
+ * 指定された属性値をtargetコンポーネントに反映する
+ * @param target 属性の設定対象コンポーネント
+ * @param name 設定する属性の名前
+ * @param value 設定する属性値
+ */
+ public void invokeSet(Object target, String name, Object value);
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+import javax.swing.JComponent;
+
+/**
+ * bgcolor属性の為のAttributeProcessor。
+ * @author kodama
+ */
+public class BgcolorProcessor extends SetterAttributeProcessor{
+
+ /**
+ * コンストラクター
+ */
+ public BgcolorProcessor(){
+ super("setBackground", false);
+ }
+
+ @Override
+ public void invokeSet(Object target, String name, Object value) {
+ //まず、強制的に不透明化する。
+ try{
+// Reflections.invokeMethod(target, "setOpaque", true);
+ //└→ これは setOpaque(Boolean) と解されて NoSuchMethodException。
+ ((JComponent)target).setOpaque(true);
+ } catch(Exception e){
+ e.printStackTrace();
+ }
+ super.invokeSet(target, name, value);
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jp.ac.aiit.xdf.component.swing.typeconvert.ColorConverter;
+import jp.ac.aiit.xdf.component.swing.typeconvert.FontConverter;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+import jp.ac.aiit.xdf.core.typeconvert.PixelValueConverter;
+import jp.ac.aiit.xdf.core.typeconvert.StringConverter;
+
+/**
+ * @author Takagi Pin.Yuan
+ * 実コンポーネントに対する共通属性の処理方法を各マッパーへ提供する
+ *
+ */
+public class CommonAttributeStore {
+
+ /**
+ * 共通属性の処理方法を取得する
+ * @param model
+ * @return 共通属性の処理方法
+ */
+ public static Map<String, AttributeProcessingUnit> commonAttributes(ObjectModel model) {
+ Map<String, AttributeProcessingUnit> result = new HashMap<String, AttributeProcessingUnit>();
+
+ //コンポーネントの幅に関する共通属性
+ result.put("width", new AttributeProcessingUnit(new WidthProcessor(true,true,true), new GetterAttributeProcessor("getWidth"), new PixelValueConverter()));
+ result.put("min-width", new AttributeProcessingUnit(new WidthProcessor(true,false,false), new WidthHeightGetProcessor("width", "min"), new PixelValueConverter()));
+ result.put("pref-width", new AttributeProcessingUnit(new WidthProcessor(false,true,false), new WidthHeightGetProcessor("width", "pref"), new PixelValueConverter()));
+ result.put("max-width", new AttributeProcessingUnit(new WidthProcessor(false,false,true), new WidthHeightGetProcessor("width", "max"), new PixelValueConverter()));
+
+ //コンポーネントの高さに関する共通属性
+ result.put("height", new AttributeProcessingUnit(new HeightProcessor(true,true,true), new GetterAttributeProcessor("getHeight"), new PixelValueConverter()));
+ result.put("min-height", new AttributeProcessingUnit(new WidthProcessor(true,false,false), new WidthHeightGetProcessor("height", "min"), new PixelValueConverter()));
+ result.put("pref-height", new AttributeProcessingUnit(new WidthProcessor(false,true,false), new WidthHeightGetProcessor("height", "pref"), new PixelValueConverter()));
+ result.put("max-height", new AttributeProcessingUnit(new WidthProcessor(false,false,true), new WidthHeightGetProcessor("height", "max"), new PixelValueConverter()));
+
+ //コンポーネントの色に関する共通属性
+ result.put("bgcolor", new AttributeProcessingUnit(new BgcolorProcessor(), new GetterAttributeProcessor("getBackground"), new ColorConverter()));
+ result.put("fgcolor", new AttributeProcessingUnit(new SetterAttributeProcessor("setForeground", false), new GetterAttributeProcessor("getForeground"), new ColorConverter()));
+
+ //その他、見た目に関する共通属性
+ result.put("font", new AttributeProcessingUnit(new SetterAttributeProcessor("setFont", false), new GetterAttributeProcessor("getFont"), new FontConverter()));
+ result.put("tooltip", new AttributeProcessingUnit(new SetterAttributeProcessor("setToolTipText", false), new GetterAttributeProcessor("getToolTipText"), new StringConverter()));
+
+ return result;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+/**
+ * 対象とする属性に対する属性処理を何も行わないようにするためのダミークラス
+ *
+ * @author Shunichi Takagi
+ */
+public class DoNothingAttributeProcessor implements AttributeGetProcessor, AttributeSetProcessor {
+
+ @Override
+ public void invokeSet(Object target, String name, Object value) {
+ }
+
+ @Override
+ public Object invokeGet(Object target, String name) {
+ return null;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * @author Shunichi Takagi
+ */
+public class FixedAttributeProcessor implements AttributeProcessor {
+
+ @Override
+ public void invokeSet(Object target, String name, Object value) {
+ if( name.equals("fixed") ) {
+ Component c = (Component) target;
+ Dimension dim = c.getPreferredSize();
+
+ if( value.equals("vertical") ) {
+ c.setMinimumSize(new Dimension(c.getMinimumSize().width, dim.height));
+ c.setMaximumSize(new Dimension(c.getMaximumSize().width, dim.height));
+ } else if( value.equals("horizontal") ) {
+ c.setMinimumSize(new Dimension(dim.width, c.getMinimumSize().height));
+ c.setMaximumSize(new Dimension(dim.width, c.getMinimumSize().height));
+ } else if( value.equals("both") ) {
+ c.setMinimumSize(dim);
+ c.setMaximumSize(dim);
+ }
+ }
+ }
+
+ @Override
+ public Map<String, Dimension> invokeGet(Object target, String name) {
+ if( name.equals("fixed") ) {
+ Map<String, Dimension> map = new HashMap<String, Dimension>();
+ map.put("minimumsize", ((Component)target).getMinimumSize());
+ map.put("maximumsize", ((Component)target).getMaximumSize());
+ return map;
+ }
+ return null;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+
+import java.lang.reflect.Method;
+
+import jp.ac.aiit.xdf.utils.Reflections;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Pin.Yuan
+ *
+ */
+public class GetterAttributeProcessor implements AttributeGetProcessor {
+ private static final Logger log = LoggerFactory.getLogger(GetterAttributeProcessor.class);
+
+ private String method;
+
+ /**
+ * @param method
+ */
+ public GetterAttributeProcessor(String method) {
+ this.method = method;
+ }
+
+ @Override
+ public Object invokeGet(Object target, String name) {
+ Class<?> clazz = target.getClass();
+
+ try {
+ Method m = clazz.getMethod(method);
+ return Reflections.invokeMethod(target, m);
+ } catch (SecurityException e) {
+ log.warn("ゲッターの適用に失敗: target:"+target+", name:"+name, e);
+ } catch (NoSuchMethodException e) {
+ log.warn("ゲッターの適用に失敗: target:"+target+", name:"+name, e);
+ }
+ return null;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+import java.awt.Component;
+import java.awt.Dimension;
+
+
+/**
+ * コンポーネントの高さに関する属性値(min-height, pref-height, max-height)を反映するクラス
+ *
+ * @author Shunichi Takagi
+ */
+public class HeightProcessor implements AttributeSetProcessor {
+ private boolean min, pref, max;
+
+
+ public HeightProcessor(boolean min, boolean pref, boolean max) {
+ this.min = min;
+ this.pref = pref;
+ this.max = max;
+ }
+
+ @Override
+ public void invokeSet(Object target, String name, Object value) {
+ if( target instanceof Component ) {
+ if( min ) {
+ ((Component) target).setMinimumSize(new Dimension(((Component) target).getMinimumSize().width, ((Integer) value).intValue()));
+ }
+ if( pref ) {
+ ((Component) target).setPreferredSize(new Dimension(((Component) target).getPreferredSize().width, ((Integer) value).intValue()));
+ }
+ if( max ) {
+ ((Component) target).setMaximumSize(new Dimension(((Component) target).getMaximumSize().width, ((Integer) value).intValue()));
+ }
+ }
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+import javax.swing.ImageIcon;
+
+import jp.ac.aiit.xdf.utils.Reflections;
+
+/**
+ * @author kodama
+ */
+public class IconProcessor implements AttributeSetProcessor {
+
+ @Override
+ public void invokeSet(Object target, String name, Object value) {
+ try{
+ Reflections.invokeMethod(
+ target
+ , "setIcon"
+ , new ImageIcon(ClassLoader.getSystemResource((String)value))
+ );
+ } catch(NoSuchMethodException me){
+ me.printStackTrace();
+ } catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * @author Pin.Yuan
+ * 実コンポーネントに対する属性の処理方法の取得プロセサー
+ *
+ */
+public class ObjectModelAttributeGetProcessor implements AttributeGetProcessor {
+ private ObjectModel model;
+
+ /**
+ * @param model
+ */
+ public ObjectModelAttributeGetProcessor(ObjectModel model) {
+ this.model = model;
+ }
+
+ @Override
+ public Object invokeGet(Object target, String name) {
+ return model.attrFromModel(name);
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+import javax.swing.JComboBox;
+import javax.swing.JList;
+
+/**
+ * comboboxやlistのselected属性の為のAttributeProcessor。
+ * @author kodama
+ */
+public class SelectedIndexProcessor extends SetterAttributeProcessor{
+
+ /**
+ * コンストラクター
+ */
+ public SelectedIndexProcessor(){
+ super("setSelectedIndex", true);
+ }
+
+ @Override
+ public void invokeSet(Object target, final String name, final Object value) {
+ final int index = Integer.parseInt(value.toString());
+ if(target instanceof JComboBox){
+ final JComboBox t = (JComboBox)target;
+ if(t.getItemCount() > index){
+ super.invokeSet(t, name, value);
+ } else{
+ new Thread(){
+ public void run(){
+ while(t.getItemCount() <= index){
+ try{
+ Thread.sleep(100);
+ } catch(InterruptedException e){
+ return;
+ }
+ }
+ SelectedIndexProcessor.super.invokeSet(t, name, value);
+ }
+ }.start();
+ }
+ } else if(target instanceof JList){
+ final JList t = (JList)target;
+ if(t.getModel().getSize() > index){
+ super.invokeSet(t, name, value);
+ } else{
+ new Thread(){
+ public void run(){
+ while(t.getModel().getSize() <= index){
+ try{
+ Thread.sleep(100);
+ } catch(InterruptedException e){
+ return;
+ }
+ }
+ SelectedIndexProcessor.super.invokeSet(t, name, value);
+ }
+ }.start();
+ }
+ }
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+
+import java.lang.reflect.Method;
+
+import jp.ac.aiit.xdf.utils.Reflections;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * リフレクションを用い、指定されたメソッドを用いて属性を反映するクラス
+ *
+ *
+ * @author Shunichi Takagi
+ */
+public class SetterAttributeProcessor implements AttributeSetProcessor {
+ private static final Logger log = LoggerFactory.getLogger(SetterAttributeProcessor.class);
+
+ private String method;
+ private boolean isPrimitive;
+ private Class<?>[] params;
+
+ /**
+ * 指定されたメソッドによって属性値を反映するためのインスタンスを生成。
+ * また、指定したメソッドの引数がプリミティブな場合、第2引数のisPrimitiveをtrueにする必要がある。
+ *
+ * @param method 実コンポーネント属性の設定メソッド名
+ * @param isPrimitive プリミティブタイプか
+ */
+ public SetterAttributeProcessor(String method, boolean isPrimitive) {
+ this.method = method;
+ this.isPrimitive = isPrimitive;
+ }
+
+ /**
+ * 指定したメソッド名と引数を持つメソッドによって属性値を反映するインスタンスを生成
+ *
+ * @param method 呼び出すメソッドの名前
+ * @param params 呼び出すメソッドが持つ引数の型配列
+ */
+ public SetterAttributeProcessor(String method, Class<?> ...params) {
+ this.method = method;
+ this.params = params;
+ }
+
+ @Override
+ public void invokeSet(Object target, String name, Object value) {
+ Class<?> clazz = target.getClass();
+
+ try {
+ Method m = ( params == null ? clazz.getMethod(method, getType(value, isPrimitive)) : clazz.getMethod(method, params) );
+ Reflections.invokeMethod(target, m, value);
+ } catch (SecurityException e) {
+ log.warn("セッターの適用に失敗: target:"+target+", name:"+name+", value:"+value, e);
+ } catch (NoSuchMethodException e) {
+ log.warn("セッターの適用に失敗: target:"+target+", name:"+name+", value:"+value, e);
+ }
+
+ }
+
+ private Class<?> getType(Object value, boolean isPrimitive) {
+ if( isPrimitive ) {
+ if( value instanceof Short ) {
+ return short.class;
+ } else if( value instanceof Integer ) {
+ return int.class;
+ } else if( value instanceof Long ) {
+ return long.class;
+ } else if( value instanceof Float ) {
+ return float.class;
+ } else if( value instanceof Double ) {
+ return double.class;
+ } else if( value instanceof Byte ) {
+ return byte.class;
+ } else if( value instanceof Character ) {
+ return char.class;
+ } else if( value instanceof Boolean ) {
+ return boolean.class;
+ } else {
+ return value.getClass();
+ }
+ } else if( value instanceof String[]){
+ return Object[].class;
+ } else {
+ return value.getClass();
+ }
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+import java.awt.Component;
+import java.awt.Dimension;
+
+/**
+ * コンポーネントの高さや幅を取得するプロセッサの統合クラス
+ * インスタンスの生成方法によって、コンポーネントの最小幅、期待幅、最大幅、最小高、期待高、最大高のどれを取得するかを選択することが出来る。
+ *
+ * @author Shunichi Takagi
+ *
+ */
+public class WidthHeightGetProcessor implements AttributeGetProcessor {
+ private String widthOrHeight;
+ private String where;
+
+ /**
+ * コンポーネントの最小幅、期待幅、最大幅、最小高、期待高、最大高のどれを取得するか設定されたインスタンスの生成
+ *
+ * @param widthOrHeight 高さを取得するか幅を取得するか(幅を取得する場合はwidth、高さを取得する場合はheightを指定する)
+ * @param where 最小値、期待値、最大値のどれを取得するか(最小値を取得する場合はmin、期待値を取得する場合はpref、最大値を取得する場合はmaxを指定する)
+ */
+ public WidthHeightGetProcessor(String widthOrHeight, String where) {
+ this.widthOrHeight = widthOrHeight;
+ this.where = where;
+ }
+
+ @Override
+ public Object invokeGet(Object target, String name) {
+ if( target instanceof Component ) {
+ Dimension dim = getDimension((Component) target, where);
+ if( dim == null ) {
+ return null;
+ } else {
+ if( widthOrHeight.equals("width") ) {
+ return dim.getWidth();
+ } else if( widthOrHeight.equals("height") ) {
+ return dim.getHeight();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private Dimension getDimension(Component c, String where) {
+ if( where.equals("min") ) {
+ return c.getMinimumSize();
+ } else if( where.equals("pref") ) {
+ return c.getPreferredSize();
+ } else if( where.equals("max") ) {
+ return c.getMaximumSize();
+ } else {
+ return null;
+ }
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.attribute;
+
+import java.awt.Component;
+import java.awt.Dimension;
+
+
+/**
+ * コンポーネントの幅に関する属性値(min-width, pref-width, max-width)を反映するクラス
+ *
+ * @author Shunichi Takagi
+ */
+public class WidthProcessor implements AttributeSetProcessor {
+ private boolean min, pref, max;
+
+ public WidthProcessor(boolean min, boolean pref, boolean max) {
+ this.min = min;
+ this.pref = pref;
+ this.max = max;
+ }
+
+ @Override
+ public void invokeSet(Object target, String name, Object value) {
+ if( target instanceof Component ) {
+ if( min ) {
+ ((Component) target).setMinimumSize(new Dimension(((Integer) value).intValue(), ((Component) target).getMinimumSize().height));
+ }
+ if( pref ) {
+ ((Component) target).setPreferredSize(new Dimension(((Integer) value).intValue(), ((Component) target).getPreferredSize().height));
+ }
+ if( max ) {
+ ((Component) target).setMaximumSize(new Dimension(((Integer) value).intValue(), ((Component) target).getMaximumSize().height));
+ }
+ }
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.event;
+
+import javax.swing.AbstractButton;
+import javax.swing.JTextField;
+
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * アクション(一般)イベントハンドル
+ * Swing コンポーネントにActionEventにて、ユーザ定義アクションをバンディングする
+ * @author pin.Yuan
+ *
+ */
+public class ActionEventHandler extends SwingEventHandler{
+ private SwingEventType event;
+
+ /**
+ * コンストラクター
+ * @param eventtype イベントタイプ:ユーザガイドのアクションの実装にイベント名を示しているもの
+ */
+ public ActionEventHandler(SwingEventType eventtype){
+ this.event = eventtype;
+ }
+
+ @Override
+ public void setEvent(ObjectModel target, Object component, Action action) {
+ UIEventListener listener = new UIEventListener(target, event, action);
+ if (target.tagname().equals("textfield")){
+ ((JTextField)component).addActionListener(listener);
+ } else {
+ ((AbstractButton) component).addActionListener(listener);
+ }
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.event;
+
+import javax.swing.JComponent;
+
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * フォーカス関連アクションイベントハンドル
+ * Swing コンポーネントにFocusEvent、LostFocusEventにて、ユーザ定義アクションをバンディングする
+ * @author pin.Yuan
+ *
+ */
+
+public class FocusEventHandler extends SwingEventHandler{
+ private SwingEventType eventtype;
+
+ /**
+ * コンストラクター
+ * @param eventtype イベントタイプ:ユーザガイドのアクションの実装にイベント名を示しているもの
+ */
+ public FocusEventHandler(SwingEventType eventtype){
+ this.eventtype = eventtype;
+ }
+
+ @Override
+ public void setEvent(ObjectModel target, Object component, Action action) {
+ UIEventListener listener = new UIEventListener(target, eventtype, action);
+ // System.out.println(component.getClass().getName());
+ ((JComponent)component).addFocusListener(listener);
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.event;
+
+import java.awt.Component;
+
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * キー関連アクションイベントハンドル
+ * Swing コンポーネントにKeyEventにて、ユーザ定義アクションをバンディングする
+ * @author pin.Yuan
+ *
+ */
+
+public class KeyEventHandler extends SwingEventHandler{
+ private SwingEventType eventType;
+
+ /**
+ * コンストラクター
+ * @param eventType イベントタイプ:ユーザガイドのアクションの実装にイベント名を示しているもの
+ */
+ public KeyEventHandler(SwingEventType eventType){
+ this.eventType = eventType;
+ }
+
+ @Override
+ public void setEvent(ObjectModel target, Object component, Action action) {
+ UIEventListener listener = new UIEventListener(target, eventType, action);
+
+ ((Component)component).addKeyListener(listener);
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.event;
+
+import java.awt.Component;
+
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * マウス関連アクションイベントハンドル
+ * Swing コンポーネントにMouseEventにて、ユーザ定義アクションをバンディングする
+ * @author pin.Yuan
+ *
+ */
+public class MouseEventHandler extends SwingEventHandler{
+ private SwingEventType event;
+
+ /**
+ * コンストラクター
+ * @param eventtype イベントタイプ:ユーザガイドのアクションの実装にイベント名を示しているもの
+ */
+ public MouseEventHandler(SwingEventType eventtype){
+ this.event = eventtype;
+ }
+
+ @Override
+ public void setEvent(ObjectModel target, Object component, Action action) {
+ UIEventListener listener = new UIEventListener(target, this.event, action);
+
+ ((Component)component).addMouseListener(listener);
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.event;\r
+\r
+\r
+import jp.ac.aiit.xdf.core.action.Event;\r
+import jp.ac.aiit.xdf.core.model.ObjectModel;\r
+\r
+/**\r
+ * Swingイベント(framework共通イベントインタフェースによる継承)\r
+ * Swing コンポーネントにFocusEvent、LostFocusEventにて、ユーザ定義アクションをバンディングする\r
+ * @author pin.Yuan\r
+ *\r
+ */\r
+\r
+public class SwingEvent implements Event {\r
+ private SwingEventType eventType;\r
+ private ObjectModel objectModel;\r
+ private Object param;\r
+ \r
+ /**\r
+ * コンストラクター\r
+ * @param eventType イベントタイプ:ユーザガイドのアクションの実装にイベント名を示しているもの\r
+ * @param objectModel アクションバンディングされるオブジェクトモデル\r
+ * @param param\r
+ */\r
+ public SwingEvent(SwingEventType eventType, ObjectModel objectModel, Object param){\r
+ this.eventType = eventType;\r
+ this.objectModel = objectModel;\r
+ this.param = param;\r
+ }\r
+ \r
+\r
+ @Override\r
+ public String getEventType() {\r
+ return this.eventType.toString();\r
+ }\r
+\r
+ @Override\r
+ public ObjectModel getObjectModel() {\r
+ return this.objectModel;\r
+ }\r
+\r
+ @Override\r
+ public Object getParam() {\r
+ return this.param;\r
+ }\r
+\r
+}\r
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.event;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.action.EventType;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * @author Pin Yuan
+ *
+ */
+public class SwingEventHandler implements EventHandler{
+ public void setEvent(ObjectModel target, Object component, Action action) { }
+
+ protected static boolean hasAction(Map<EventType, Action> actions, EventType ...events) {
+ for(EventType event : events) {
+ if( actions.containsKey(event) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Swingの共通イベントバンディング方法を取得する
+ * @return 共通イベントバンディング方法
+ */
+ public static Map<String, EventHandler> commonEvent(){
+ Map<String, EventHandler> action = new HashMap<String, EventHandler>();
+ action.put("focus", new FocusEventHandler(SwingEventType.FOCUS));
+ action.put("focuslose", new FocusEventHandler(SwingEventType.FOCUSLOSE));
+ return action;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.event;
+
+import jp.ac.aiit.xdf.core.action.EventType;
+
+/**
+ * @author Pin.Yuan
+ * Swingアクションのイベントタイプ定義
+ *
+ */
+public enum SwingEventType implements EventType{
+
+ /**
+ * SwingコンポーネントActionイベント
+ */
+ ACTIONED("click"),
+ /**
+ * マウスクリックイベント
+ */
+ CLICK("click"),
+ /**
+ * マウスダブルクリックイベント
+ */
+ DOUBLECLICK("doubleclick"),
+ /**
+ * タブ変わったイベント
+ */
+ TAB_CHANGE("tabchange"),
+ /**
+ * Tabキーイベント
+ */
+ KEY_ENTER_TAB("keyenter"),
+ /**
+ * キーボード入力イベント
+ */
+ KEY_TYPED("keytype"),
+ /**
+ * txtfield編集イベント
+ */
+ EDIT("edit"),
+ /**
+ * Enterキーイベント
+ */
+ PRESSENTER("press-enter"),
+ /**
+ * フォーカス当たるイベント
+ */
+ FOCUS("focus"),
+ /**
+ * フォーカスはずれたイベント
+ */
+ FOCUSLOSE("focuslose"),
+ /**
+ * checkbox, radioのチェックイベント
+ */
+ CHECK("check"),
+ /**
+ * checkbox, radioのチェックを外すイベント
+ */
+ UNCHECK("uncheck"),
+ /**
+ * listのチェンジイベント
+ */
+ CHANGE("change");
+
+ private String attr;
+ private SwingEventType(String attr){
+ this.attr = attr;
+ }
+
+ public String toString(){
+ return attr;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.event;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.AbstractButton;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * @author Pin.Yuan
+ * 実コンポーネントにユーザ定義アクションをListenerにてバンディングする
+ *
+ */
+public class UIEventListener implements ActionListener, MouseListener, KeyListener, ChangeListener, FocusListener {
+ private ObjectModel model;
+ //private Map<String, Action> actions;
+ private SwingEventType event;
+ private Action action;
+ private Object param;
+
+ /**
+ * @param model
+ * @param event
+ * @param action
+ */
+ public UIEventListener(ObjectModel model, SwingEventType event, Action action) {
+ this.model = model;
+ //this.actions = model.getActions();
+ this.event = event;
+ this.action = action;
+ }
+
+ /**
+ * 発生したイベントに対応づけられたアクションを実行する
+ * @param e 発生したイベントの種類
+ */
+ public void invokeAction(SwingEventType e) {
+ /*
+ * TODO ここで発生したイベントに関する情報をアクションにセットする必要がある。(まずは仕様を決める)
+ * 例としてはKeyEventの場合にどのキーが押されたかや修飾キーが押されていたかどうかなど
+ */
+ //Action action = actions.get(event);
+ SwingEvent event = new SwingEvent(e, this.model, param);
+
+ if( this.action != null ) {
+ this.action.execute(event);
+ }
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (model.tagname().equals("checkbox")||model.tagname().equals("radio")){
+ AbstractButton checkbox = (AbstractButton)e.getSource();
+ // チェックボックスチェックされた際に、"check"イベントを発生する
+ if (checkbox.isSelected() && event.equals(SwingEventType.CHECK)){
+ this.action.execute(new SwingEvent(SwingEventType.CHECK, this.model, null));
+ }
+ // チェックボックスチェック外された際に、"uncheck"イベントを発生する
+ if ((!checkbox.isSelected()) && event.equals(SwingEventType.UNCHECK)){
+ this.action.execute(new SwingEvent(SwingEventType.UNCHECK, this.model, null));
+ }
+ }else {
+ this.action.execute(new SwingEvent(SwingEventType.ACTIONED, this.model, null));
+ }
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 1){
+ if (event.equals(SwingEventType.CLICK))
+ invokeAction(SwingEventType.CLICK);
+ } else if (e.getClickCount() == 2) {
+ if (event.equals(SwingEventType.DOUBLECLICK))
+ invokeAction(SwingEventType.DOUBLECLICK);
+ }
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent e) { }
+
+ @Override
+ public void mouseExited(MouseEvent e) { }
+
+ @Override
+ public void mousePressed(MouseEvent e) { }
+
+ @Override
+ public void mouseReleased(MouseEvent e) { }
+
+ @Override
+ public void keyTyped(KeyEvent e) {
+ if (model.tagname().equals("textfield")) {
+ switch(event){
+ case PRESSENTER:
+ if (e.getKeyCode() == KeyEvent.VK_ENTER ){
+ // System.out.println("Key press: enter");
+ invokeAction(event);
+ break;
+ }
+ break;
+ case EDIT:
+ invokeAction(event);
+ break;
+ }
+ } else if (model.tagname().equals("textarea")){
+ switch(event){
+ case EDIT:
+ invokeAction(event);
+ break;
+ }
+ }
+
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) { }
+
+ @Override
+ public void keyReleased(KeyEvent e) { }
+
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ invokeAction(SwingEventType.TAB_CHANGE);
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ if (event.equals(SwingEventType.FOCUS)) {
+ invokeAction(SwingEventType.FOCUS);
+ }
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (event.equals(SwingEventType.FOCUSLOSE)) {
+ invokeAction(SwingEventType.FOCUSLOSE);
+ }
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.util.Map;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.IconProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.ObjectModelAttributeGetProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.event.ActionEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventType;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.typeconvert.StringConverter;
+
+
+/**
+ * buttonタグをSwingのJButtonにマッピングするクラス
+ *
+ * @author Shunichi Takagi
+ */
+public class JButtonMapper extends SwingComponentMapperTemplate {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("text", new AttributeProcessingUnit(new SetterAttributeProcessor("setText", false), new GetterAttributeProcessor("getText"), new StringConverter()));
+ result.put("img", new AttributeProcessingUnit(new IconProcessor(), new ObjectModelAttributeGetProcessor(model), new StringConverter()));
+
+ return result;
+ }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ Map<String, EventHandler> action = SwingEventHandler.commonEvent();
+ action.put("click", new ActionEventHandler(SwingEventType.CLICK));
+ return action;
+ }
+
+ @SuppressWarnings("serial")
+ @Override
+ protected Object newComponent() {
+ return new JButton(){
+ @SuppressWarnings("unused")
+ public void setIcon(ImageIcon defaultIcon){setIcon((Icon)defaultIcon);}
+ };
+ }
+
+ @Override
+ protected void processingChildComponents() { }
+
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.util.Map;
+
+import javax.swing.JCheckBox;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.DoNothingAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.ObjectModelAttributeGetProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.event.ActionEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventType;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.typeconvert.BooleanConverter;
+import jp.ac.aiit.xdf.core.typeconvert.StringConverter;
+
+/**
+ * checkboxタグをSwingのJCheckBoxにマッピングする
+ * @author Shunichi Takagi
+ */
+public class JCheckboxMapper extends SwingComponentMapperTemplate {
+
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("text", new AttributeProcessingUnit(new SetterAttributeProcessor("setText", false), new GetterAttributeProcessor("getText"), new StringConverter()));
+ result.put("value", new AttributeProcessingUnit(new DoNothingAttributeProcessor(), new ObjectModelAttributeGetProcessor(model), new StringConverter()));
+ result.put("checked", new AttributeProcessingUnit(new SetterAttributeProcessor("setSelected", true), new GetterAttributeProcessor("isSelected"), new BooleanConverter()));
+
+ return result;
+ }
+
+ @Override
+ protected Object newComponent() {
+ return new JCheckBox();
+ }
+
+ @Override
+ protected void processingChildComponents() { }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ Map<String, EventHandler> action = SwingEventHandler.commonEvent();
+ action.put("check", new ActionEventHandler(SwingEventType.CHECK));
+ action.put("uncheck", new ActionEventHandler(SwingEventType.UNCHECK));
+ return action;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.awt.Component;
+import java.util.Map;
+
+import javax.swing.JComboBox;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeSetProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SelectedIndexProcessor;
+import jp.ac.aiit.xdf.component.swing.event.ActionEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventType;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.typeconvert.IntegerConverter;
+import jp.ac.aiit.xdf.core.typeconvert.StringValuesConverter;
+
+/**
+ * comboboxタグをSwingのJCombobBoxにマッピングする
+ * @author kodama
+ */
+public class JComboboxMapper extends SwingComponentMapperTemplate {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("values", new AttributeProcessingUnit(new ReplaceAllProcessor(), new GetValuesProcessor(), new StringValuesConverter()));
+ result.put("selected", new AttributeProcessingUnit(new SelectedIndexProcessor(), new GetterAttributeProcessor("getSelectedIndex"), new IntegerConverter()));
+
+ return result;
+ }
+
+ @Override
+ protected Object newComponent() {
+ return new JComboBox();
+ }
+
+ @Override
+ protected void processingChildComponents() { }
+
+ private class ReplaceAllProcessor implements AttributeSetProcessor {
+ @Override
+ public void invokeSet(Object target, String name, Object value) {
+ if(!value.getClass().isArray()) return;
+ JComboBox box = (JComboBox)component;
+ box.removeAllItems();
+ for(Object val : (Object[])value) box.addItem(val);
+ }
+ }
+
+ private class GetValuesProcessor extends GetterAttributeProcessor {
+ public GetValuesProcessor(){
+ super(null);
+ }
+ @Override
+ public Object invokeGet(Object target, String name) {
+ JComboBox box = (JComboBox)getComponent();
+ Component[] components = box.getComponents();
+ String[] values = new String[components.length];
+ System.arraycopy(components, 0, values, 0, components.length);
+ return values;
+ }
+ }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ Map<String, EventHandler> action = SwingEventHandler.commonEvent();
+ action.put("change", new ActionEventHandler(SwingEventType.CHANGE));
+ return action;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.Map;
+
+import javax.swing.JFrame;
+import javax.swing.JMenuBar;
+
+import jp.ac.aiit.xdf.application.Application;
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.typeconvert.StringConverter;
+
+/**
+ * frameタグをSwingのJFrameにマッピングする
+ *
+ * @author Shunichi Takagi
+ */
+public class JFrameMapper extends SwingLayoutingComponentMapperTemplate {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("title", new AttributeProcessingUnit(new SetterAttributeProcessor("setTitle", false), new GetterAttributeProcessor("getTitle"), new StringConverter()));
+
+ return result;
+ }
+
+ @Override
+ protected Object newComponent() {
+ JFrame frame = new JFrame();
+ frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+
+ frame.addWindowListener(new WindowAdapter() {
+ @Override public void windowClosing(WindowEvent e) {
+ Application.getInstance().close( (String) model.rootModel().attr("windowName") );
+ }
+ });
+
+ // メニューバーの追加
+ if (model.hasAttr("menubar")){
+ JMenuBar menubar = (JMenuBar)model.attr("menubar");
+ frame.setJMenuBar(menubar);
+ }
+
+ return frame;
+ }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.IconProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.ObjectModelAttributeGetProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.event.MouseEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventType;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.typeconvert.StringConverter;
+
+/**
+ * labelタグをSwingのJLabelにマッピングする
+ *
+ * @author Shunichi Takagi
+ */
+public class JLabelMapper extends SwingComponentMapperTemplate {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("text", new AttributeProcessingUnit(new SetterAttributeProcessor("setText", false), new GetterAttributeProcessor("getText"), new StringConverter()));
+ result.put("img", new AttributeProcessingUnit(new IconProcessor(), new ObjectModelAttributeGetProcessor(model), new StringConverter()));
+
+ return result;
+ }
+
+ @SuppressWarnings("serial")
+ @Override
+ protected Object newComponent() {
+ return new JLabel(){
+ @SuppressWarnings("unused")
+ public void setIcon(ImageIcon icon){setIcon((Icon)icon);}
+ };
+ }
+
+ @Override
+ protected void processingChildComponents() { }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ Map<String, EventHandler> action = new HashMap<String, EventHandler>();
+ action.put("click", new MouseEventHandler(SwingEventType.CLICK));
+ action.put("doubleclick", new MouseEventHandler(SwingEventType.DOUBLECLICK));
+ return action;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.awt.Component;
+import java.util.Map;
+
+import javax.swing.JList;
+import javax.swing.border.Border;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SelectedIndexProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.event.ActionEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventType;
+import jp.ac.aiit.xdf.component.swing.typeconvert.BorderConverter;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.typeconvert.IntegerConverter;
+import jp.ac.aiit.xdf.core.typeconvert.StringValuesConverter;
+
+/**
+ * listタグをSwingのJListにマッピングする
+ *
+ * @author kodama
+ */
+public class JListMapper extends SwingComponentMapperTemplate {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("values", new AttributeProcessingUnit(new SetterAttributeProcessor("setListData", false), new GetValuesProcessor(), new StringValuesConverter()));
+ result.put("border", new AttributeProcessingUnit(new SetterAttributeProcessor("setBorder", Border.class), new GetterAttributeProcessor("getBorder"), new BorderConverter()));
+ result.put("selected", new AttributeProcessingUnit(new SelectedIndexProcessor(), new GetterAttributeProcessor("getSelectedIndex"), new IntegerConverter()));
+
+ return result;
+ }
+
+ @Override
+ protected Object newComponent() {
+ return new JList();
+ }
+
+ @Override
+ protected void processingChildComponents() { }
+
+ private class GetValuesProcessor extends GetterAttributeProcessor{
+ public GetValuesProcessor(){
+ super(null);
+ }
+ @Override
+ public Object invokeGet(Object target, String name) {
+ JList list = (JList)getComponent();
+ Component[] components = list.getComponents();
+ String[] values = new String[components.length];
+ System.arraycopy(components, 0, values, 0, components.length);
+ return values;
+ }
+ }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ Map<String, EventHandler> action = SwingEventHandler.commonEvent();
+ action.put("change", new ActionEventHandler(SwingEventType.CHANGE));
+ return action;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.util.Map;
+
+import javax.swing.ImageIcon;
+import javax.swing.JMenuItem;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.event.KeyEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventType;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+
+/**
+ * menuitemタグをSwingのJMenuItemにマッピングする
+ *
+ * @author pin.Yuan
+ */
+public class JMenuItemMapper extends SwingComponentMapperTemplate {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ //result.put("access", new AttributeProcessingUnit(new ReplaceAllProcessor(), new GetValuesProcessor(), new StringValuesConverter()));
+
+ return result;
+ }
+
+ @Override
+ protected Object newComponent() {
+ JMenuItem menuitem = null;
+ if (model.hasAttr("image")){
+ menuitem = new JMenuItem(model.hasAttr("text")? (String)model.attr("text") : " ",
+ new ImageIcon(ClassLoader.getSystemResource((String)model.attr("image"))));
+ } else {
+ menuitem = new JMenuItem(model.hasAttr("text")? (String)model.attr("text") : " ");
+ }
+
+ return menuitem;
+ }
+
+ @Override
+ protected void processingChildComponents() { }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ Map<String, EventHandler> action = SwingEventHandler.commonEvent();
+ action.put("change", new KeyEventHandler(SwingEventType.ACTIONED));
+ return action;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.util.Map;
+
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.event.KeyEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventType;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+import jp.ac.aiit.xdf.core.typeconvert.IntegerConverter;
+
+/**
+ * menuタグをSwingのJMenuにマッピングする
+ *
+ * @author pin.Yuan
+ */
+public class JMenuMapper extends SwingComponentMapperTemplate {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("image", new AttributeProcessingUnit(new SetterAttributeProcessor("setSelectedIndex", true), new GetterAttributeProcessor("getSelectedIndex"), new IntegerConverter()));
+ result.put("access", new AttributeProcessingUnit(new SetterAttributeProcessor("setSelectedIndex", true), new GetterAttributeProcessor("getSelectedIndex"), new IntegerConverter()));
+
+ return result;
+ }
+
+ @Override
+ protected Object newComponent() {
+ JMenu menu = new JMenu((String)(model.hasAttr("text")? model.attr("text"):""), true);
+
+ // frameタグを検索し、menubarを新規作成
+ ObjectModel parent = null;
+
+ for (ObjectModel objectModel : model.parent().children()){
+ if (objectModel.tagname().equals("frame")){
+ parent = objectModel;
+ break;
+ }
+ }
+
+ if (parent.hasAttr("menubar")) {
+ JMenuBar menubar = (JMenuBar)parent.attr("menubar");
+ menubar.add(menu);
+ } else {
+ JMenuBar menubar = new JMenuBar();
+ menubar.add(menu);
+
+ parent.attr("menubar", menubar);
+ }
+
+ return menu;
+ }
+
+ @Override
+ protected void processingChildComponents() {
+ for(ObjectModel child : model.children()){
+ child.realize();
+
+ JMenuItem menuitem = (JMenuItem)child.getComponent();
+ ((JMenu)component).add(menuitem);
+ }
+ }
+
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ Map<String, EventHandler> action = SwingEventHandler.commonEvent();
+ action.put("change", new KeyEventHandler(SwingEventType.ACTIONED));
+ return action;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.awt.FlowLayout;
+import java.util.Map;
+
+import javax.swing.JPanel;
+import javax.swing.border.Border;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.typeconvert.BorderConverter;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+
+/**
+ * groupタグをSwingのJPanelにマッピングする
+ *
+ * @author Shunichi Takagi
+ */
+public class JPanelMapper extends SwingLayoutingComponentMapperTemplate {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("border", new AttributeProcessingUnit(new SetterAttributeProcessor("setBorder", Border.class), new GetterAttributeProcessor("getBorder"), new BorderConverter()));
+
+ return result;
+ }
+
+ @Override
+ protected Object newComponent() {
+ JPanel p = new JPanel();
+ p.setLayout(new FlowLayout());
+ p.setOpaque(false);
+
+ return p;
+ }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JRadioButton;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeSetProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.DoNothingAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.ObjectModelAttributeGetProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.event.ActionEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventType;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.typeconvert.BooleanConverter;
+import jp.ac.aiit.xdf.core.typeconvert.StringConverter;
+
+/**
+ * radioタグをSwingのJRadioButtonにマッピングする
+ *
+ * @author kodama
+ */
+public class JRadioButtonMapper extends SwingComponentMapperTemplate {
+
+ /**
+ * name属性の値からButtonGroupへの対応。
+ * TODO どこへ置くべきか・・
+ */
+ private static Map<String, ButtonGroup> buttonGroups
+ = new HashMap<String, ButtonGroup>();
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("name", new AttributeProcessingUnit(new ChangeGroupProcessor(), new ObjectModelAttributeGetProcessor(model), new StringConverter()));
+ result.put("value", new AttributeProcessingUnit(new DoNothingAttributeProcessor(), new ObjectModelAttributeGetProcessor(model), new StringConverter()));
+ result.put("text", new AttributeProcessingUnit(new SetterAttributeProcessor("setText", false), new GetterAttributeProcessor("getText"), new StringConverter()));
+ result.put("checked", new AttributeProcessingUnit(new SetterAttributeProcessor("setSelected", true), new GetterAttributeProcessor("isSelected"), new BooleanConverter()));
+
+ return result;
+ }
+
+
+ @Override
+ protected Object newComponent() {
+ return new JRadioButton();
+ }
+
+ @Override
+ protected void processingChildComponents() { }
+
+ /**
+ * radioタグのname属性の為のAttributeProcessor。
+ */
+ private class ChangeGroupProcessor implements AttributeSetProcessor {
+ @Override
+ public void invokeSet(Object target, String name, Object value) {
+ JRadioButton radio = (JRadioButton)getComponent();
+ //旧所属ButtonGroupからの引揚げ
+ for(ButtonGroup group : buttonGroups.values()){
+ group.remove(radio);
+ //ButtonGroupがすべてのラジオボタンを失っても、それを残しておく。
+ }
+ //新たなButtonGroupへの登録
+ ButtonGroup group = buttonGroups.get(value);
+ if(group == null) buttonGroups.put((String)value, group = new ButtonGroup());
+ group.add(radio);
+ }
+ }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ Map<String, EventHandler> action = SwingEventHandler.commonEvent();
+ action.put("check", new ActionEventHandler(SwingEventType.CHECK));
+ action.put("uncheck", new ActionEventHandler(SwingEventType.UNCHECK));
+ return action;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.util.Map;
+
+import javax.swing.JTabbedPane;
+
+import jp.ac.aiit.xdf.component.swing.Tabpanel;
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+import jp.ac.aiit.xdf.core.typeconvert.TypeConverter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * tabgroupをSwingのJTabbedPaneとしてマッピングするクラス
+ * @author kodama
+ */
+public class JTabbedPaneMapper extends SwingComponentMapperTemplate {
+
+ private static final Logger log
+ = LoggerFactory.getLogger(SwingComponentMapperTemplate.class);
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("tabplace", new AttributeProcessingUnit(new SetterAttributeProcessor("setTabPlacement", true), new GetterAttributeProcessor("getTabPlacement"), new TabplaceValueConverter()));
+
+ return result;
+ }
+
+ @Override
+ protected Object newComponent() {
+ return new JTabbedPane();
+ }
+
+ @Override
+ protected void processingChildComponents() {
+ for(ObjectModel child : model.children()){
+ child.realize();
+
+ try{
+ Tabpanel tab = (Tabpanel)child.getComponent();
+ tab.setContainer((JTabbedPane)this.component);
+ } catch(ClassCastException e){
+ log.warn("タブ区画の中にタブでないコンポネントが指定されている");
+ } catch(Exception e){
+ }
+ }
+ }
+
+ private static class TabplaceValueConverter implements TypeConverter<Integer>{
+ @Override
+ public Integer apply(String target) {
+ if( target == null ) {
+ return JTabbedPane.TOP;
+ } else {
+ String lowered = target.toLowerCase();
+ if( lowered.equals("top") ) {
+ return JTabbedPane.TOP;
+ } else if( lowered.equals("bottom") ) {
+ return JTabbedPane.BOTTOM;
+ } else if( lowered.equals("left") ) {
+ return JTabbedPane.LEFT;
+ } else if( lowered.equals("right") ) {
+ return JTabbedPane.RIGHT;
+ } else {
+ return JTabbedPane.TOP;
+ }
+ }
+ }
+
+ @Override
+ public boolean isAppliable(String target) {
+ return true;
+ }
+ }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ return null;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.JTextArea;
+import javax.swing.border.Border;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.event.KeyEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventType;
+import jp.ac.aiit.xdf.component.swing.typeconvert.BorderConverter;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.typeconvert.BooleanConverter;
+import jp.ac.aiit.xdf.core.typeconvert.IntegerConverter;
+import jp.ac.aiit.xdf.core.typeconvert.StringConverter;
+
+/**
+ * textareaタグをSwingのJTextAreaとしてマッピングするクラス
+ *
+ * @author kodama
+ */
+public class JTextAreaMapper extends SwingComponentMapperTemplate {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = new HashMap<String, AttributeProcessingUnit>();
+ result.put("value", new AttributeProcessingUnit(new SetterAttributeProcessor("setText", false), new GetterAttributeProcessor("getText"), new StringConverter()));
+ result.put("rows", new AttributeProcessingUnit(new SetterAttributeProcessor("setRows", true), new GetterAttributeProcessor("getRows"), new IntegerConverter()));
+ result.put("columns", new AttributeProcessingUnit(new SetterAttributeProcessor("setColumns", true), new GetterAttributeProcessor("getColumns"), new IntegerConverter()));
+ result.put("border", new AttributeProcessingUnit(new SetterAttributeProcessor("setBorder", Border.class), new GetterAttributeProcessor("getBorder"), new BorderConverter()));
+ result.put("editable", new AttributeProcessingUnit(new SetterAttributeProcessor("setEditable", true), new GetterAttributeProcessor("isEditable"), new BooleanConverter()));
+
+ return result;
+ }
+
+ @Override
+ protected Object newComponent() {
+ return new JTextArea();
+ }
+
+ @Override
+ protected void processingChildComponents() { }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ Map<String, EventHandler> action = SwingEventHandler.commonEvent();
+ action.put("edit", new KeyEventHandler(SwingEventType.EDIT));
+ return action;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.util.Map;
+
+import javax.swing.JTextField;
+import javax.swing.border.Border;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.event.KeyEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventHandler;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventType;
+import jp.ac.aiit.xdf.component.swing.typeconvert.BorderConverter;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.typeconvert.BooleanConverter;
+import jp.ac.aiit.xdf.core.typeconvert.StringConverter;
+
+/**
+ * textfieldタグをSwingのJTextFieldとしてマッピングするクラス
+ *
+ * @author Shunichi Takagi
+ */
+public class JTextFieldMapper extends SwingComponentMapperTemplate {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("value", new AttributeProcessingUnit(new SetterAttributeProcessor("setText", false), new GetterAttributeProcessor("getText"), new StringConverter()));
+ result.put("border", new AttributeProcessingUnit(new SetterAttributeProcessor("setBorder", Border.class), new GetterAttributeProcessor("getBorder"), new BorderConverter()));
+ result.put("editable", new AttributeProcessingUnit(new SetterAttributeProcessor("setEditable", true), new GetterAttributeProcessor("isEditable"), new BooleanConverter()));
+
+ return result;
+ }
+
+ @Override
+ protected Object newComponent() {
+ return new JTextField();
+ }
+
+ @Override
+ protected void processingChildComponents() { }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ Map<String, EventHandler> action = SwingEventHandler.commonEvent();
+ action.put("edit", new KeyEventHandler(SwingEventType.EDIT));
+ action.put("press-enter", new KeyEventHandler(SwingEventType.PRESSENTER));
+ return action;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import jp.ac.aiit.xdf.component.ComponentMapper;
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventHandler;
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Swing用のコンポーネントマッパのテンプレートクラス
+ * このテンプレートクラスでは、Swingコンポーネントを生成するために必要な共通部分をテンプレート化し、
+ * 非共通部分をサブクラスで実装させる構成(テンプレートメソッドパターン)になっている。
+ *
+ * @author Shunichi Takagi
+ */
+public abstract class SwingComponentMapperTemplate implements ComponentMapper {
+ private static final Logger log = LoggerFactory.getLogger(SwingComponentMapperTemplate.class);
+ protected Map<String, AttributeProcessingUnit> processingUnits;
+ protected Map<String, EventHandler> processingAction;
+
+ protected ObjectModel model;
+
+ private boolean realized;
+ protected Object component;
+
+ protected List<SwingEventHandler> eventhandlers;
+
+ /**
+ *
+ */
+ public SwingComponentMapperTemplate() {
+ this.processingUnits = initProcessingUnits();
+ this.processingAction = intiProcessingAction();
+ }
+
+ @Override
+ public void setModel(ObjectModel model) {
+ this.model = model;
+ }
+
+ @Override
+ public ObjectModel getModel() {
+ return model;
+ }
+
+ @Override
+ public Object getComponent() {
+ return component;
+ }
+
+ @Override
+ public boolean isRealized() {
+ return realized;
+ }
+
+ @Override
+ public void realize() {
+ this.component = newComponent();
+
+ //ObjectModelに設定された属性を実コンポーネントに反映
+ Map<String, Object> map = model.attrMaps();
+ for(Entry<String, Object> entry : map.entrySet()) {
+ AttributeProcessingUnit unit = processingUnits.get(entry.getKey());
+ if( unit != null ) {
+ unit.invokeSet(component, entry.getKey(), entry.getValue());
+ }
+ }
+
+ // アクションの実コンポーネントに反映
+ Map<String, Action> actions = model.getActions();
+ for (Entry<String, Action> action : actions.entrySet()){
+ EventHandler handler = processingAction.get(action.getKey());
+ if (handler != null){
+ handler.setEvent(this.model, this.component, action.getValue());
+ } else {
+ log.debug("アクション登録失敗です。 <タグ名:"+ this.model.tagname() + "> <ID:" + this.model.id() + "> <アクション:"+ action.getKey() +">");
+ }
+ }
+
+ processingChildComponents();
+ //SwingEventHandler.setEvent(model, (Component) component);
+
+ this.realized = true;
+ }
+
+ @Override
+ public Object typeConvert(String name, String value) {
+ AttributeProcessingUnit unit = processingUnits.get(name);
+ if( unit == null ) {
+ return value;
+ } else {
+ return unit.typeConvert(value);
+ }
+ }
+
+ @Override
+ public Object getAttr(String name) {
+ AttributeProcessingUnit unit = processingUnits.get(name);
+ if( unit == null ) {
+ return null;
+ } else {
+ return unit.invokeGet(this.component, name);
+ }
+ }
+
+ @Override
+ public void setAttr(String name, Object value){
+ AttributeProcessingUnit unit = processingUnits.get(name);
+ if( unit != null ) {
+ unit.invokeSet(component, name, value);
+ }
+ }
+
+ @Override
+ public void setRealize(boolean realize){
+ this.realized = realize;
+ }
+
+ protected abstract Object newComponent();
+ protected abstract void processingChildComponents();
+ protected abstract Map<String, AttributeProcessingUnit> initProcessingUnits();
+ protected abstract Map<String, EventHandler> intiProcessingAction();
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.util.List;
+
+import javax.swing.GroupLayout;
+import javax.swing.JFrame;
+import javax.swing.GroupLayout.Group;
+
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+
+/**
+ * @author Tagaki
+ * レイアウト管理マッパー<br>
+ * Swing環境における padding, margin, follows の各属性を実現する。<br>
+ * また、非公式に autogap 属性をサポートする。この属性の値を、本FWではtrueを既定と定めるが、
+ * padding, marginに厳しいレイアウトを望む場合、これをfalseに設定すると良い。<br>
+ * (例)スタイル記述において「group{autogap:false;}」
+ */
+public abstract class SwingLayoutingComponentMapperTemplate extends SwingComponentMapperTemplate {
+
+ @Override
+ protected void processingChildComponents() {
+ if( component instanceof Container ) {
+ for(ObjectModel child : model.children()) {
+ child.realize();
+ }
+
+ Container c = ( component instanceof JFrame ? ((JFrame) component).getContentPane() : (Container) component );
+
+ GroupLayout layout = new GroupLayout(c);
+ c.setLayout(layout);
+
+ //autogap属性の処理
+ if(model.hasAttr("autogap") && "false".equals(model.attr("autogap"))){
+ //明示的に「false」設定された場合に限りfalse。
+ layout.setAutoCreateContainerGaps(false);
+ } else{ //既定的には true。
+ layout.setAutoCreateContainerGaps(true);
+ }
+ layout.setVerticalGroup( createVerticalGroup(layout) );
+ layout.setHorizontalGroup( createHorizontalGroup(layout) );
+ }
+ }
+
+ private Group createVerticalGroup(GroupLayout layout) {
+ Group vGroup = layout.createSequentialGroup( );
+ Group followGroup = null;
+
+ int ptop = Integer.valueOf( model.hasAttr("padding-top") ? (String) model.attr("padding-top") : "0" );
+ int pbottom = Integer.valueOf( model.hasAttr("padding-bottom") ? (String) model.attr("padding-bottom") : "0" );
+
+ int maxRow = 0;
+ for(ObjectModel child : model.children()) {
+ String pfollows = (String) child.attr("follows");
+ if( pfollows == null || !pfollows.equals("right") ) {
+ maxRow++;
+ }
+ }
+
+ List<ObjectModel> children = model.children();
+ int rowIndex = 0;
+ for(int i=0; i<children.size(); i++) {
+ ObjectModel child = children.get(i);
+
+ child.setRealize(false);
+
+ String follows = (String) child.attr("follows");
+
+ if( follows != null && follows.equals("right") ) {
+ if( followGroup == null ) {
+ followGroup = layout.createParallelGroup();
+ vGroup.addGroup(followGroup);
+ }
+ addToVerticalGroup(followGroup, model, child, rowIndex == 0 ? ptop : 0, rowIndex == maxRow-1 ? pbottom : 0 );
+ } else if( followGroup != null ) {
+ addToVerticalGroup(followGroup, model, child, rowIndex == 0 ? ptop : 0, rowIndex == maxRow-1 ? pbottom : 0 );
+ followGroup = null;
+ } else {
+ addToVerticalGroup(vGroup, model, child, rowIndex == 0 ? ptop : 0, rowIndex == maxRow-1 ? pbottom : 0 );
+ rowIndex++;
+ }
+
+ child.setRealize(true);
+ }
+
+ return vGroup;
+ }
+
+ private void addToVerticalGroup(Group g, ObjectModel parent, ObjectModel model, int ptop, int pbottom) {
+ int mtop = Integer.valueOf( model.hasAttr("margin-top") ? (String) model.attr("margin-top") : "0" );
+ int mbottom = Integer.valueOf( model.hasAttr("margin-bottom") ? (String) model.attr("margin-bottom") : "0" );
+
+ // System.out.println("DebugInfo:layout mtop[" + String.valueOf(mtop) +"] mbottom[" + String.valueOf(mbottom));
+
+ g.addGap(mtop+ptop);
+ model.setRealize(true);
+ g.addComponent((Component) model.getComponent());
+ model.setRealize(false);
+ g.addGap(mbottom+pbottom);
+ }
+
+
+ private Group createHorizontalGroup(GroupLayout layout) {
+ Group hGroup = layout.createParallelGroup();
+ Group followGroup = null;
+
+ int pleft = Integer.valueOf( model.hasAttr("padding-left") ? (String) model.attr("padding-left") : "0" );
+ int pright = Integer.valueOf( model.hasAttr("padding-right") ? (String) model.attr("padding-right") : "0" );
+
+ for(ObjectModel child : model.children()) {
+ child.setRealize(false);
+ String follows = (String) child.attr("follows");
+
+ if( follows != null && follows.equals("right") ) {
+ //次の要素が右に並ぶ(ので、右パディングは適用しない)
+ int leftPad = 0;
+ if( followGroup == null ) {
+ //はじめてfollows=rightになった(左はじなので、左パディングを適用する)
+ followGroup = layout.createSequentialGroup();
+ hGroup.addGroup(followGroup);
+ leftPad = pleft;
+ }
+ addToHorizontalGroup(followGroup, model, child, leftPad, 0);
+ } else if( followGroup != null ) {
+ //follows=rightでなくなった(右はじ)ただ、followGroupがあるので左はじではない
+ addToHorizontalGroup(followGroup, model, child, 0, pright);
+ followGroup = null;
+ } else {
+ //follows=rightでなく、かつ左はじ
+ addToHorizontalGroup(hGroup, model, child, pleft, pright);
+ }
+ child.setRealize(true);
+ }
+
+ return hGroup;
+ }
+
+ private void addToHorizontalGroup(Group g, ObjectModel parent, ObjectModel model, int pleft, int pright) {
+ int mleft = Integer.valueOf( model.hasAttr("margin-left") ? (String) model.attr("margin-left") : "0" );
+ int mright = Integer.valueOf( model.hasAttr("margin-right") ? (String) model.attr("margin-right") : "0" );
+ // System.out.println("DebugInfo:layout "+ model.tagname() +" mleft[" + String.valueOf(mleft) +"] mright[" + String.valueOf(mright) +"] pleft["+pleft+"] pright["+pright+"]");
+
+ g.addGap(mleft+pleft);
+ model.setRealize(true);
+ g.addComponent((Component) model.getComponent());
+ model.setRealize(false);
+ g.addGap(mright+pright);
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.mappers;
+
+import java.awt.FlowLayout;
+import java.util.Map;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import jp.ac.aiit.xdf.component.swing.Tabpanel;
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.GetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.IconProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.ObjectModelAttributeGetProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.event.SwingEventHandler;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.typeconvert.StringConverter;
+
+/**
+ * <tab />のComponentMaper。<group>のもの(JPanelMapper)を基本とする。
+ * @author kodama
+ */
+public class TabpanelMapper extends JPanelMapper {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = super.initProcessingUnits();
+ result.put("title", new AttributeProcessingUnit(new SetterAttributeProcessor("setName", false), new GetterAttributeProcessor("getName"), new StringConverter()));
+ result.put("img", new AttributeProcessingUnit(new IconProcessor(), new ObjectModelAttributeGetProcessor(model), new StringConverter()));
+ result.put("access", new AttributeProcessingUnit(new SetterAttributeProcessor("setAccessKey", false), new GetterAttributeProcessor("getAccessKey"), new StringConverter()));
+
+ return result;
+ }
+
+ @SuppressWarnings("serial")
+ @Override
+ protected Object newComponent() {
+ Tabpanel tabpanel = new Tabpanel(){
+ @SuppressWarnings("unused")
+ public void setIcon(ImageIcon icon){setIcon((Icon)icon);}
+ };
+ tabpanel.setLayout(new FlowLayout());
+
+ return tabpanel;
+ }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ Map<String, EventHandler> action = SwingEventHandler.commonEvent();
+ return action;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.typeconvert;
+
+import java.awt.Color;
+import java.util.regex.Pattern;
+
+import javax.swing.border.BevelBorder;
+import javax.swing.border.Border;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.LineBorder;
+import javax.swing.border.SoftBevelBorder;
+
+import jp.ac.aiit.xdf.core.typeconvert.TypeConverter;
+
+/**
+ * Borderの名前からそれを表すjava.awt.Borderのサブクラスインスタンスへ変換する
+ *
+ * @author Shunichi Takagi
+ *
+ */
+public class BorderConverter implements TypeConverter<Border> {
+ private static final Pattern APPLIABLE_STRING = Pattern.compile("solid|groove|ridge|inset|outset");
+
+ @Override
+ public Border apply(String target) {
+ String trimmed = target.trim();
+
+ if( trimmed.equals("solid") ) {
+ return new LineBorder(Color.GRAY);
+ } else if( trimmed.equals("groove") ) {
+ return new EtchedBorder(EtchedBorder.LOWERED);
+ } else if( trimmed.equals("ridge") ) {
+ return new EtchedBorder(EtchedBorder.RAISED);
+ } else if( trimmed.equals("inset") ) {
+ return new SoftBevelBorder(BevelBorder.LOWERED);
+ } else if( trimmed.equals("outset") ) {
+ return new SoftBevelBorder(BevelBorder.RAISED);
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean isAppliable(String target) {
+ return APPLIABLE_STRING.matcher(target.trim()).matches();
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.typeconvert;
+
+import java.awt.Color;
+
+import jp.ac.aiit.xdf.core.typeconvert.TypeConverter;
+
+/**
+ * 16進カラーコードで記述された色をjava.awt.Colorに変換する
+ *
+ * @author kodama
+ */
+public class ColorConverter implements TypeConverter<Color> {
+
+ @Override
+ public Color apply(String target) {
+ try{
+ return new Color(Integer.parseInt(target.substring(1), 16));
+ } catch(Exception e){
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isAppliable(String target) {
+ return true;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swing.typeconvert;
+
+import java.awt.Font;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jp.ac.aiit.xdf.core.typeconvert.TypeConverter;
+
+/**
+ * フォント指定文字列からjava.awt.Fontのインスタンスへの変換を行う
+ *
+ * @author Takagi Pin.Yuan
+ *
+ */
+public class FontConverter implements TypeConverter<Font> {
+ private static final Pattern APPLIABLE_PATTERN = Pattern.compile("([^\\,]*)(\\,([1-9][0-9]*)pt)?(\\,(italic|bold|normal))?");
+
+ @Override
+ public Font apply(String target) {
+ Matcher m = APPLIABLE_PATTERN.matcher(target);
+
+ if( m.matches() ) {
+ // System.out.println("DebugInfo:1<" + m.group(1) + "> 3<" + m.group(3) + "> 3<" + m.group(5));
+ String name = m.group(1);
+ int size = Integer.valueOf(m.group(3));
+ int style = asStyle( m.group(5) );
+
+ return new Font(name, style, size);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean isAppliable(String target) {
+ return APPLIABLE_PATTERN.matcher(target).matches();
+ }
+
+ private int asStyle(String style) {
+ if( style == null ) {
+ return Font.PLAIN;
+ } else if( style.equals("italic") ) {
+ return Font.ITALIC;
+ } else if( style.equals("bold") ) {
+ return Font.BOLD;
+ } else if( style.equals("normal") ) {
+ return Font.PLAIN;
+ } else {
+ return Font.PLAIN;
+ }
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.swing;
+
+import javax.swing.JFrame;
+
+import jp.ac.aiit.xdf.core.model.ObjectModelSupport;
+
+/**
+ * JFrame用のObjectModel拡張クラス
+ * これはSwingに依存するウィンドウを開ける/閉じるための処理をXDFコア部分から切り出すために作成した
+ *
+ * @author Takagi
+ */
+public class JFrameModel extends ObjectModelSupport {
+
+ /**
+ * コンストラクター
+ * @param tagname
+ */
+ public JFrameModel(String tagname) {
+ super(tagname);
+ }
+
+ @Override
+ public void close() {
+ ((JFrame) getComponent()).setVisible(false);
+ }
+
+ @Override
+ public void open() {
+ JFrame frame = (JFrame) getComponent();
+
+ frame.pack();
+ frame.setVisible(true);
+ }
+
+}
--- /dev/null
+<tagdef>
+
+ <tag name="frame">
+ <modelclass>jp.ac.aiit.xdf.swing.JFrameModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JFrameMapper" />
+ </tag>
+
+ <tag name="group">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JPanelMapper" />
+ </tag>
+
+ <tag name="label">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JLabelMapper" />
+ </tag>
+
+ <tag name="button">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JButtonMapper" />
+ </tag>
+
+ <tag name="textfield">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JTextFieldMapper" />
+ </tag>
+
+ <tag name="checkbox">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JCheckboxMapper" />
+ </tag>
+
+ <tag name="textarea">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JTextAreaMapper" />
+ </tag>
+
+ <tag name="select">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ </tag>
+
+ <tag name="option">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ </tag>
+
+ <tag name="tabgroup">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JTabbedPaneMapper" />
+ </tag>
+
+ <tag name="tab">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.TabpanelMapper" />
+ </tag>
+
+ <tag name="combobox">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JComboboxMapper" />
+ </tag>
+
+ <tag name="radio">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JRadioButtonMapper" />
+ </tag>
+
+ <tag name="list">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JListMapper" />
+ </tag>
+ <tag name="menugroup">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JMenuMapper" />
+ </tag>
+ <tag name="menuitem">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.mappers.JMenuItemMapper" />
+ </tag>
+</tagdef>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<project>
+ <parent>
+ <artifactId>xdf-all</artifactId>
+ <groupId>jp.ac.aiit.xdf</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>jp.ac.aiit.xdf.component.swingx
+ </groupId>
+ <artifactId>xdf-swingx</artifactId>
+ <name>xdf-swingx</name>
+ <version>1.0-SNAPSHOT</version>
+ <url>http://maven.apache.org</url>
+ <dependencies>
+ <dependency>
+ <groupId>jp.ac.aiit.xdf</groupId>
+ <artifactId>xdf</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>jp.ac.aiit.xdf.component.swing</groupId>
+ <artifactId>xdf-swing</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.swinglabs</groupId>
+ <artifactId>swingx</artifactId>
+ <version>0.9.2</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package jp.ac.aiit.xdf.component.swingx;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Map;
+
+import jp.ac.aiit.xdf.application.TagReferences;
+import jp.ac.aiit.xdf.component.swing.SwingTagReferences;
+import jp.ac.aiit.xdf.core.exceptions.UnexpectedBehaviorException;
+import jp.ac.aiit.xdf.core.tags.TagLoader;
+import jp.ac.aiit.xdf.core.tags.Tagdef.Tag;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * SwingX用のタグセットを提供するクラス
+ *
+ * @author Shunichi Takagi
+ *
+ */
+public class SwingXTagReferences implements TagReferences {
+ private static final Logger log = LoggerFactory.getLogger(SwingTagReferences.class);
+ private static final String SWINGX_TAGS = "xdf-swingxtags.xml";
+
+ @Override
+ public Map<String, Tag> getDefinedTags() {
+ try {
+ URL url = ClassLoader.getSystemResource(SWINGX_TAGS);
+
+ TagLoader loader = new TagLoader();
+ Map<String, Tag> result = loader.load(new File(url.toURI()));
+
+ return result;
+ } catch(URISyntaxException e) {
+ log.error("SwingX用タグ定義ファイルがロードできません。", e);
+ throw new UnexpectedBehaviorException("SwingX用タグ定義ファイルがロードできません。", e);
+ }
+ }
+
+ @Override
+ public String getReferenceId() {
+ return "swingx";
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swingx.attribute;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessor;
+import jp.ac.aiit.xdf.component.swingx.datasource.DatasourceWrappedModel;
+import jp.ac.aiit.xdf.component.swingx.datasource.TreetableDataSource;
+
+import org.jdesktop.swingx.JXTreeTable;
+import org.jdesktop.swingx.treetable.TreeTableModel;
+
+
+public class TreetableDataSourceProcessor implements AttributeProcessor {
+
+ @Override
+ public void invokeSet(Object target, String name, Object value) {
+ if( target instanceof JXTreeTable && value instanceof TreetableDataSource ) {
+ JXTreeTable treetable = (JXTreeTable) target;
+ TreetableDataSource dataSource = (TreetableDataSource) value;
+
+ TreeTableModel model = new DatasourceWrappedModel(dataSource);
+ treetable.setTreeTableModel(model);
+ }
+ }
+
+ @Override
+ public Object invokeGet(Object target, String name) {
+ if( target instanceof JXTreeTable ) {
+ JXTreeTable treetable = (JXTreeTable) target;
+ TreeTableModel model = treetable.getTreeTableModel();
+
+ if( model instanceof DatasourceWrappedModel ) {
+ return ((DatasourceWrappedModel) model).getDataSource();
+ }
+ }
+
+ return null;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swingx.datasource;
+
+public class ColumnInfo {
+ private Class<?> columnClass;
+ private String columnName;
+
+ public ColumnInfo(Class<?> columnClass, String columnName) {
+ this.columnClass = columnClass;
+ this.columnName = columnName;
+ }
+
+ public Class<?> getColumnClass() {
+ return columnClass;
+ }
+
+ public String getColumnName() {
+ return columnName;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swingx.datasource;
+
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreePath;
+
+import org.jdesktop.swingx.treetable.TreeTableModel;
+
+public class DatasourceWrappedModel implements TreeTableModel {
+ private TreetableDataSource dataSource;
+
+ public DatasourceWrappedModel(TreetableDataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ public TreetableDataSource getDataSource() {
+ return dataSource;
+ }
+
+ @Override
+ public Class<?> getColumnClass(int columnIndex) {
+ return dataSource.getColumnInfo(columnIndex).getColumnClass();
+ }
+
+ @Override
+ public int getColumnCount() {
+ return dataSource.getColumnCount();
+ }
+
+ @Override
+ public String getColumnName(int column) {
+ return dataSource.getColumnInfo(column).getColumnName();
+ }
+
+ @Override
+ public int getHierarchicalColumn() {
+ return dataSource.getHierarchicalColumn();
+ }
+
+ @Override
+ public Object getValueAt(Object node, int column) {
+ return dataSource.getValueAt(node, column);
+ }
+
+ @Override
+ public boolean isCellEditable(Object node, int column) {
+ return dataSource.isCellEditable(node, column);
+ }
+
+ @Override
+ public void setValueAt(Object value, Object node, int column) {
+ dataSource.setValueAt(value, node, column);
+ }
+
+ @Override
+ public Object getChild(Object parent, int index) {
+ return dataSource.getChild(parent, index);
+ }
+
+ @Override
+ public int getChildCount(Object parent) {
+ return dataSource.getChildCount(parent);
+ }
+
+ @Override
+ public int getIndexOfChild(Object parent, Object child) {
+ return dataSource.getIndexOfChild(parent, child);
+ }
+
+ @Override
+ public Object getRoot() {
+ return dataSource.getRoot();
+ }
+
+ @Override
+ public boolean isLeaf(Object node) {
+ return dataSource.isLeaf(node);
+ }
+
+ @Override
+ public void addTreeModelListener(TreeModelListener l) {}
+
+ @Override
+ public void removeTreeModelListener(TreeModelListener l) {}
+
+ @Override
+ public void valueForPathChanged(TreePath path, Object newValue) {}
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swingx.datasource;
+
+
+public interface TreetableDataSource {
+ public ColumnInfo getColumnInfo(int column);
+ public int getColumnCount();
+ public int getHierarchicalColumn();
+
+ public Object getValueAt(Object node, int column);
+ public boolean isCellEditable(Object node, int column);
+ public void setValueAt(Object value, Object node, int column);
+
+ public Object getChild(Object parent, int index) ;
+ public int getChildCount(Object parent);
+ public int getIndexOfChild(Object parent, Object child);
+ public Object getRoot();
+ public boolean isLeaf(Object node);
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.swingx.mapper;
+
+import java.util.Map;
+
+import jp.ac.aiit.xdf.component.swing.attribute.AttributeProcessingUnit;
+import jp.ac.aiit.xdf.component.swing.attribute.CommonAttributeStore;
+import jp.ac.aiit.xdf.component.swing.attribute.ObjectModelAttributeGetProcessor;
+import jp.ac.aiit.xdf.component.swing.attribute.SetterAttributeProcessor;
+import jp.ac.aiit.xdf.component.swing.mappers.SwingComponentMapperTemplate;
+import jp.ac.aiit.xdf.component.swingx.datasource.TreetableDataSource;
+import jp.ac.aiit.xdf.core.action.EventHandler;
+import jp.ac.aiit.xdf.core.typeconvert.InstanciationConverter;
+
+import org.jdesktop.swingx.JXTreeTable;
+
+public class JXTreeTableMapper extends SwingComponentMapperTemplate {
+
+ @Override
+ protected Map<String, AttributeProcessingUnit> initProcessingUnits() {
+ Map<String, AttributeProcessingUnit> result = CommonAttributeStore.commonAttributes(model);
+ result.put("model", new AttributeProcessingUnit(new SetterAttributeProcessor("setTreeTableModel", false), new ObjectModelAttributeGetProcessor(model), new InstanciationConverter<TreetableDataSource>()));
+
+ return result;
+ }
+
+ @Override
+ protected Object newComponent() {
+ return new JXTreeTable();
+ }
+
+ @Override
+ protected void processingChildComponents() { }
+
+ @Override
+ protected Map<String, EventHandler> intiProcessingAction() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
--- /dev/null
+<tagdef>
+ <tag name="treetable">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swingx.mapper.JXTreeTableMapper" />
+ </tag>
+</tagdef>
\ No newline at end of file
--- /dev/null
+<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>
+ <groupId>jp.ac.aiit.xdf</groupId>
+ <artifactId>xdf</artifactId>
+ <packaging>jar</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <name>xdf</name>
+ <url>http://maven.apache.org</url>
+ <parent>
+ <groupId>jp.ac.aiit.xdf</groupId>
+ <artifactId>xdf-all</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <build>
+ <directory>target</directory>
+ <outputDirectory>target/classes</outputDirectory>
+ <finalName>${project.artifactId}-${project.version}</finalName>
+ <testOutputDirectory>target/test-classes</testOutputDirectory>
+ <sourceDirectory>src/main/java</sourceDirectory>
+ <testSourceDirectory>src/test/java</testSourceDirectory>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ </resources>
+ <testResources>
+ <testResource>
+ <directory>src/test/resources</directory>
+ </testResource>
+ </testResources>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>5.8</version>
+ <classifier>jdk15</classifier>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package jp.ac.aiit.xdf.application;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jp.ac.aiit.xdf.application.interceptors.UIDesignInterceptingManager;
+import jp.ac.aiit.xdf.application.interceptors.UIDesignResource;
+import jp.ac.aiit.xdf.component.common.CommonTagReferences;
+import jp.ac.aiit.xdf.core.action.factory.ActionFactory;
+import jp.ac.aiit.xdf.core.action.factory.DefaultActionFactory;
+import jp.ac.aiit.xdf.core.exceptions.UnexpectedBehaviorException;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+import jp.ac.aiit.xdf.core.selector.Selector;
+import jp.ac.aiit.xdf.core.tags.Tagdef.Tag;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 本フレームワークで作成されたアプリケーションを管理するクラス
+ * プラグイン提供されたコンポーネント群やアクションインスタンスの生成方法などを設定することができる
+ * なお、本クラスはSigletonになっているため、インスタンスの取得にはgetInstanceメソッドを用いること
+ *
+ * @author Shunichi Takagi
+ */
+public class Application {
+ private static final Logger log = LoggerFactory.getLogger(Application.class);
+
+ /**
+ * アプリケーションのインスタンス
+ */
+ public static final Application instance = new Application();
+
+ private Application(){
+ this.toolkit = "swing";
+ this.definedTags = new HashMap<String, Tag>();
+ this.factory = new DefaultActionFactory();
+ this.windows = new HashMap<String, InputStream>();
+
+ this.refs = new ArrayList<TagReferences>();
+ useTags(new CommonTagReferences());
+
+ this.openedWindows = new HashMap<String, ObjectModel>();
+ }
+
+ private LifeCycle lifeCycle = new DefaultLifeCycle();
+
+ private String toolkit;
+ private Map<String, Tag> definedTags;
+ private Map<String, InputStream> windows;
+
+ private ActionFactory factory;
+ private List<TagReferences> refs;
+
+ private Map<String, ObjectModel> openedWindows;
+
+ /**
+ * アプリケーションのインスタンス取得メソッド
+ * @return シングルトン化されたApplicationのインスタンス
+ */
+ public static Application getInstance() {
+ return instance;
+ }
+
+ /**
+ * アプリケーションのインスタンス取得メソッド
+ * 引数で与えられたタグ参照の読み込みをインスタンス取得と同時に行う
+ *
+ * @param refs このアプリケーションで利用するタグ参照の固まり。プラグインによって提供される
+ * @return アプリケーションのインスタンス
+ */
+ public static Application getInstance(TagReferences ...refs) {
+ for(TagReferences ref : refs) {
+ instance.useTags(ref);
+ }
+ return instance;
+ }
+
+ /**
+ * このアプリケーションに対するライフサイクルを設定
+ *
+ * @param lifeCycle このアプリケーションに設定されるライフサイクル
+ */
+ public void setLifeCycle(LifeCycle lifeCycle) {
+ this.lifeCycle = lifeCycle;
+ }
+ /**
+ * このアプリケーションを実行するツールキット環境を設定する
+ * @param toolkit
+ */
+ public void setToolkit(String toolkit) {
+ this.toolkit = toolkit;
+ }
+
+ /**
+ * このアプリケーションを実行するツールキット環境名を取得する
+ * @return ツールキット環境名
+ */
+ public String getToolkit() {
+ return toolkit;
+ }
+
+ /**
+ * アプリケーション内で使用するタグを追加する
+ * @param refs
+ */
+ public void useTags(TagReferences refs) {
+ this.refs.add(refs);
+ this.definedTags = mergeTags(definedTags, refs.getDefinedTags());
+ }
+
+ /**
+ * アプリケーション内で利用されるActionをインスタンス化するための方法を設定する
+ * @param factory アクションのインスタンス生成ファクトリ
+ */
+ public void setActionFactory(ActionFactory factory) {
+ this.factory = factory;
+ }
+
+ /**
+ * アプリケーション内でアクションのインスタンス化に使用されるファクトリを取得
+ * @return アクションファクトリのインスタンス
+ */
+ public ActionFactory getActionFactory() {
+ return factory;
+ }
+
+ /**
+ * アプリケーションにウィンドウを追加する
+ *
+ * @param name ウィンドウ名
+ * @param uidesign ウィンドウ定義ファイルへのClasspath上のパス
+ * @throws FileNotFoundException 指定されたファイルが見つからなかった場合にthrowされる
+ */
+ public void registWindow(String name, String uidesign) throws FileNotFoundException {
+ URL url = ClassLoader.getSystemResource(uidesign);
+
+ if( url == null ) {
+ log.warn("指定された画面定義XMLファイルが見つかりません file:"+uidesign);
+ throw new FileNotFoundException("指定された画面定義XMLファイルが見つかりません file:"+uidesign);
+ } else {
+ try {
+ windows.put(name, new FileInputStream( new File( url.toURI() ) ));
+ } catch (URISyntaxException e) {
+ log.warn("フレームワーク内部で予期しない例外が発生しました。", e);
+ throw new UnexpectedBehaviorException("フレームワーク内部で予期しない例外が発生しました。", e);
+ }
+ }
+ }
+
+ /**
+ * アプリケーションにウィンドウを追加する
+ *
+ * @param name ウィンドウ名
+ * @param uidesign ウィンドウ定義ファイルを読み込むためのストリーム
+ */
+ public void registWindow(String name, InputStream uidesign) {
+ windows.put(name, uidesign);
+ }
+
+ /**
+ * 指定した名前のウィンドウを起動する
+ *
+ * @param name 起動するウィンドウの名前
+ */
+ public void open(String name) {
+ if( windows.containsKey(name) ) {
+ if( openedWindows.size() == 0 ) {
+ lifeCycle.launch();
+ }
+ lifeCycle.beforeOpened(name);
+
+ InputStream inputStream = windows.get(name);
+
+ UIDesignResource resource = new UIDesignResource(inputStream, definedTags);
+ UIDesignInterceptingManager manager = UIDesignInterceptingManager.getDefaultManager();
+ manager.invoke(resource);
+
+ ObjectModel model = resource.getModel();
+ model.attr("windowName", name);
+
+ for (ObjectModel menuModel: new Selector("menugroup").find(model)){
+ menuModel.realize();
+ }
+
+ ObjectModel frameModel = new Selector("frame").find(model).get(0);
+ frameModel.realize();
+
+ frameModel.open();
+
+ openedWindows.put(name, model);
+
+ lifeCycle.afterOpened(name);
+ } else {
+ log.warn("指定された名前のウィンドウは登録されていません name:"+name);
+ }
+ }
+
+ /**
+ * 指定した名前のウィンドウを閉じる
+ *
+ * @param name 閉じるウィンドウの名前
+ */
+ public void close(String name) {
+ if( openedWindows.containsKey(name) ) {
+ lifeCycle.beforeClosed(name);
+
+ ObjectModel model = openedWindows.get(name);
+ openedWindows.remove(name);
+
+ ObjectModel frameModel = new Selector("frame").find(model).get(0);
+ frameModel.close();
+
+ lifeCycle.afterClosed(name);
+ if( openedWindows.size() == 0 ) {
+ lifeCycle.shutdown();
+ }
+ } else {
+ log.info("指定されたウィンドウは登録されていないか既に閉じられています。 name:"+name);
+ }
+ }
+
+ private Map<String,Tag> mergeTags(Map<String,Tag> arg0, Map<String,Tag> arg1) {
+ for(String tagname1 : arg1.keySet()) {
+ if( arg0.containsKey(tagname1) ) {
+ Tag tag0 = arg0.get(tagname1);
+ Tag tag1 = arg1.get(tagname1);
+
+ tag0.merge(tag1);
+ } else {
+ arg0.put(tagname1, arg1.get(tagname1));
+ log.info(tagname1+":"+arg1.get(tagname1));
+ }
+ }
+
+ return arg0;
+ }
+
+ /**
+ * アプリケーションインスタンスからウィンドウ登録名にてウィンドウオブジェクトモデルを取得する
+ * @param name
+ * @return オブジェクトモデル
+ */
+ public ObjectModel getWindow(String name){
+ return this.openedWindows.get(name);
+ }
+
+ /**
+ * 指定されたウィンドウにあるIDのコンポーネントを検索する
+ *
+ * @param window ウィンドウ登録名
+ * @param id コンポーネントID
+ * @return コンポーネントオブジェクト
+ */
+ public static ObjectModel findById(String window, String id){
+ return Selector.find("#" + id, Application.getInstance().getWindow(window)).get(0);
+ }
+
+ /**
+ * 指定されたウィンドウのコンポーネントをセレクタ構文を用いて検索する
+ *
+ * @param window ウィンドウ登録名
+ * @param selector コンポーネント検索用セレクタ
+ * @return コンポーネントオブジェクト
+ */
+ public static List<ObjectModel> findBySelector(String window, String selector) {
+ return Selector.find(selector, Application.getInstance().getWindow(window));
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.application;
+
+/**
+ * ライフサイクルのデフォルト実装を提供するクラス
+ *
+ * このライフサイクルを利用すると、アプリケーションが管理しているウィンドウが全て表示されなくなったとき、
+ * System.exit(0)によってアプリケーションが終了する。
+ *
+ * この動作が適さない場合はLifeCycleインターフェースを独自に実装するか、このクラスをオーバライドすること。
+ *
+ * @author Shunichi Takagi
+ */
+public class DefaultLifeCycle implements LifeCycle {
+ @Override public void afterClosed(String name) { }
+ @Override public void afterOpened(String name) { }
+ @Override public void beforeClosed(String name) { }
+ @Override public void beforeOpened(String name) { }
+ @Override public void launch() { }
+ @Override public void shutdown() { System.exit(0); }
+}
--- /dev/null
+package jp.ac.aiit.xdf.application;
+
+/**
+ * ライフサイクルインターフェース
+ * アプリケーションの生成から消滅まで一連のアクションインターフェースを提供する
+ *
+ * @author Shunichi Takagi
+ */
+public interface LifeCycle {
+
+ /**
+ * アプリケーションが管理するウィンドウのうち、最初の一つのウィンドウが表示されたときに起動される。
+ */
+ public void launch();
+
+ /**
+ * アプリケーションが管理するウィンドウが全て表示されなくなったときに、起動される。
+ */
+ public void shutdown();
+
+ /**
+ * アプリケーションが管理するウィンドウが開く直前に起動される。
+ * @param name ウィンドウ名
+ */
+ public void beforeOpened(String name);
+
+ /**
+ * アプリケーションが管理するウィンドウが開く直後に起動される。
+ * @param name ウィンドウ名
+ */
+ public void afterOpened(String name);
+
+ /**
+ * アプリケーションが管理するウィンドウが閉じる直前に起動される。
+ * @param name ウィンドウ名
+ */
+ public void beforeClosed(String name);
+
+ /**
+ * アプリケーションが管理するウィンドウが閉じた直後に起動される。
+ * @param name ウィンドウ名
+ */
+ public void afterClosed(String name);
+}
--- /dev/null
+package jp.ac.aiit.xdf.application;
+
+import java.util.Map;
+
+import jp.ac.aiit.xdf.core.tags.Tagdef.Tag;
+
+/**
+ * タグ提供インターフェース
+ *
+ * 稼働させるアプリケーションで利用するタグセットを提供するためのインターフェース。
+ * アプリケーションに設定されたTagReferencesの実装のメソッドgetDefinedTags()によって返されるものが
+ * そのアプリケーションで利用可能なタグセットとなる。
+ * また、このTagReferencesはツールキット切り替えのインターフェースとして扱うことも可能である。
+ *
+ * このインターフェースの実装例はxdf-swingプロジェクト内のjp.ac.aiit.xdf.component.swing.SwingTagReferencesを
+ * 参照のこと
+ *
+ * @author Shunichi Takagi
+ */
+public interface TagReferences {
+ /**
+ * 参照IDを取得する
+ * ツールキット定義名とする。ツールキットの切り替える際にアプリケーションの引用
+ * @return String 参照ID
+ */
+ public String getReferenceId();
+ /**
+ * タブセットを取得する
+ * @return Map<String, Tag>
+ */
+ public Map<String, Tag> getDefinedTags();
+}
--- /dev/null
+package jp.ac.aiit.xdf.application.interceptors;
+
+
+
+import jp.ac.aiit.xdf.application.Application;
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.core.action.factory.ActionFactory;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+import jp.ac.aiit.xdf.core.selector.Selector;
+
+/**
+ * 画面定義XMLに記述されたアクションの設定に基づき、コンポーネントとアクションの結びつけを行う。
+ *
+ * @author Pin Yuan
+ */
+public class ActionInterceptor implements UIDesignInterceptor {
+
+ @Override
+ public void intercept(UIDesignResource resource) {
+
+ ObjectModel om = resource.getModel();
+ parseAction(om);
+ }
+
+ private void parseAction(ObjectModel rootModel) {
+ ActionFactory factory = Application.getInstance().getActionFactory();
+
+ for(ObjectModel actionModel : Selector.find("action", rootModel)) {
+
+ if( actionModel.hasAttr("target") ) {
+ Action action = factory.createAction( (String) actionModel.attr("classname") );
+ String event = (String)actionModel.attr("event");
+
+ String targetSelector = (String) actionModel.attr("target");
+ for(ObjectModel target : Selector.find(targetSelector, rootModel) ) {
+ target.setAction(action, event);
+ }
+ }
+ }
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.application.interceptors;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+import jp.ac.aiit.xdf.core.selector.Selector;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 画面定義XMLに記述されたスタイルシートを読み込み、それに指定された情報に従い各コンポーネントに対する属性の設定を行う
+ *
+ * @author kodama
+ */
+public class StyleParseInterceptor implements UIDesignInterceptor {
+ private static final Logger log = LoggerFactory.getLogger(StyleParseInterceptor.class);
+ //「・・{・・}」という記述単位を抽出する正規表現
+ private static final Pattern STYLEUNIT_FINDER = Pattern.compile(".*?\\{.*?\\}");
+
+ @Override
+ public void intercept(UIDesignResource resource) {
+ ObjectModel modelRoot = resource.getModel();
+ List<ObjectModel> styleModels = Selector.find("style", modelRoot);
+
+ for(ObjectModel styleModel : styleModels) {
+ String src = (String) styleModel.attr("src");
+ try {
+ String style = extractStyleContents( new File( ClassLoader.getSystemResource(src).toURI() ) );
+
+ //スタイルシート内容全体上で上記スタイル記述単位を探索する。
+ Matcher m = STYLEUNIT_FINDER.matcher(style);
+ while(m.find()){
+ applyStyle(m.group(), modelRoot);
+ }
+ } catch(URISyntaxException e) {
+ log.warn("指定されたスタイルファイルの読み込みに失敗しました。file:"+src, e);
+ }
+ }
+ }
+
+ private String extractStyleContents(File file) {
+ BufferedReader reader = null;
+ StringBuilder builder = new StringBuilder();
+ try{
+ reader = new BufferedReader(new FileReader(file));
+ for(String line; (line = reader.readLine()) != null; ){
+ //(コメント行や「//」以降を無視する)
+ if(!(line = line.replaceFirst("//.*", "").trim()).isEmpty()){
+ builder.append(line);
+ }
+ }
+ } catch(IOException ioe){
+ return null;
+ } finally{
+ try{ reader.close(); } catch(Exception e){}
+ }
+ //(コメント( /* ・・ */ )を除いた)スタイルシート内容全体を返す
+ return builder.toString().replaceAll("/\\*.*?\\*/", "");
+ }
+
+ private static void applyStyle(String styleUnit, ObjectModel applyRoot){
+ String selector = styleUnit.replaceFirst("\\{.*", "").trim(); //「{」より左をセレクタ部として取出す
+
+ //属性の記述単位で分割
+ String[] defAttrs = styleUnit.replaceFirst("^.*?\\{", "").replaceFirst("\\}.*", "").split(";");
+
+ Map<String, String> attributes = new HashMap<String, String>();
+ for(String defAttr : defAttrs){
+ if( !( defAttr = defAttr.trim() ).isEmpty()){
+ //属性の名前と値の区切りは:と=の2種類
+ String[] attr = defAttr.split("[:=]");
+ attributes.put(attr[0], attr.length > 1 ? attr[1].replaceAll("\"", "").trim() : "");
+ }
+ }
+
+ List<ObjectModel> targets = Selector.find(selector, applyRoot);
+ for(ObjectModel target : targets) {
+ for(Map.Entry<String, String> entry : attributes.entrySet()) {
+ target.attrWeakly(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.application.interceptors;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * XMLParseInterceptorやStyleParaseInterceptorなど、XDFをどうささせるために必要なインターセプターの
+ * 関係(実行順など)を管理するクラスである。
+ *
+ * @author Shunichi Takagi
+ */
+public class UIDesignInterceptingManager {
+ private List<UIDesignInterceptor> interceptors;
+
+ /**
+ * コンストラクター
+ * @param interceptors
+ */
+ public UIDesignInterceptingManager(List<UIDesignInterceptor> interceptors) {
+ this.interceptors = interceptors;
+ }
+
+ /**
+ * デフォルトのインターセプタマネージャを取得する。
+ * デフォルトのマネージャはXMLParseInterceptr -> StyleParseInterceptro -> ActionInterceptorの順にインターセプト処理を動作させる。
+ *
+ * @return デフォルトのインターセプタ管理インスタンス
+ */
+ public static UIDesignInterceptingManager getDefaultManager() {
+ List<UIDesignInterceptor> list = new ArrayList<UIDesignInterceptor>();
+ list.add(new XMLParseInterceptor());
+ list.add(new StyleParseInterceptor());
+ list.add(new ActionInterceptor());
+
+ return new UIDesignInterceptingManager(list);
+ }
+
+ /**
+ * 管理しているインターセプタの処理を実行する。
+ *
+ * @param resource インターセプターの入出力インタフェース
+ */
+ public void invoke(UIDesignResource resource) {
+ for(UIDesignInterceptor interceptor : interceptors) {
+ interceptor.intercept(resource);
+ }
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.application.interceptors;
+
+/**
+ * GUI画面定義のパーサの機能を提供するため、インターセプターのインタフェースを定義する
+ * @author Shunichi Takagi
+ */
+public interface UIDesignInterceptor {
+ /**
+ * インターセプターの実行メソッド
+ * @param resource
+ */
+ public void intercept(UIDesignResource resource);
+}
--- /dev/null
+package jp.ac.aiit.xdf.application.interceptors;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+import jp.ac.aiit.xdf.core.tags.Tagdef.Tag;
+
+/**
+ * インターセプターの入出力インターフェース
+ * インターセプターの入出力インターフェースとして、入力インタフェースと出力インターフェースを提供する
+ * インターセプタの共通インタフェースとして、InputStreamを入力し、オブジェクトモデルを出力される
+ * @author Shunichi Takagi
+ */
+public class UIDesignResource {
+ private InputStream inputStream; // インターセプターの入力インターフェース
+ private ObjectModel model; // インターセプターの出力インターフェース
+
+ private Map<String,Tag> usableTags;
+
+ /**
+ * ファイルインプットによる、インターセプター入出力インタフェースの初期
+ * @param inputStream
+ */
+ public UIDesignResource(InputStream inputStream) {
+ this(inputStream, new HashMap<String,Tag>());
+ }
+
+ /**
+ * ファイルインプットとタブ定義群による、インターセプター入出力インタフェースの初期
+ * @param inputStream
+ * @param usableTags
+ */
+ public UIDesignResource(InputStream inputStream, Map<String,Tag> usableTags) {
+ this.inputStream = inputStream;
+ this.usableTags = usableTags;
+ }
+
+ /**
+ * 入出力インタフェースから、入力インタフェースを取得する
+ * @return 入力インタフェース
+ */
+ public InputStream getInputStream() {
+ return inputStream;
+ }
+
+ /**
+ * 入出力インタフェースに入力インタフェースをセットする
+ * @param inputStream
+ */
+ public void setInputStream(InputStream inputStream) {
+ this.inputStream = inputStream;
+ }
+
+ /**
+ * 入出力インタフェースから出力を取得する
+ * @return オブジェクトモデル
+ */
+ public ObjectModel getModel() {
+ return model;
+ }
+
+ /**
+ * 入出力インタフェースに出力をセットする
+ * @param model
+ */
+ public void setModel(ObjectModel model) {
+ this.model = model;
+ }
+
+ /**
+ * 入出力インタフェースから使用可能タグ定義を取得する
+ * @return タグ定義マップ
+ */
+ public Map<String, Tag> getUsableTags() {
+ return usableTags;
+ }
+
+ /**
+ * 入出力インタフェースに使用可能タグ定義をセットする
+ * @param usableTags
+ */
+ public void setUsableTags(Map<String, Tag> usableTags) {
+ this.usableTags = usableTags;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.application.interceptors;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import jp.ac.aiit.xdf.application.Application;
+import jp.ac.aiit.xdf.component.ComponentMapper;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+import jp.ac.aiit.xdf.core.tags.Tagdef.Tag;
+import jp.ac.aiit.xdf.utils.Reflections;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * 画面定義XMLインターセプター
+ * @author Shunichi Takagi
+ */
+public class XMLParseInterceptor implements UIDesignInterceptor {
+
+ @Override
+ public void intercept(UIDesignResource resource) {
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+
+ Document doc = builder.parse(resource.getInputStream());
+ Element elem = doc.getDocumentElement();
+
+ resource.setModel( parseElement(elem, resource.getUsableTags()) );
+
+ } catch (ParserConfigurationException e) {
+ e.printStackTrace();
+ } catch (SAXException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private ObjectModel parseElement(Element elem, Map<String,Tag> definedTags) {
+ Tag tag = definedTags.get(elem.getTagName().toLowerCase(Locale.ENGLISH));
+ String className = tag.getModelclass();
+
+ ObjectModel model = (ObjectModel) Reflections.getInstance(className, tag.getName());
+ ComponentMapper mapper = (ComponentMapper) Reflections.getInstance(getMapperClass(tag.getComponentMapper(), Application.getInstance().getToolkit()));
+ model.setComponentMapper(mapper);
+
+ NamedNodeMap map = elem.getAttributes();
+ for(int i=0; i<map.getLength(); i++) {
+ Node node = map.item(i);
+
+ //TODO node.getNodeType()の値に応じて処理を分岐しなければならない <label>あいうえお</label>の処理なども必要
+ if( node.getNodeName().toLowerCase() == "id" ) {
+ model.id(node.getNodeValue());
+ } else if( node.getNodeName().toLowerCase() == "class" ) {
+ model.addClass(node.getNodeValue());
+ } else {
+ model.attr(node.getNodeName(), mapper.typeConvert(node.getNodeName(), node.getNodeValue()));
+ }
+ }
+
+ NodeList children = elem.getChildNodes();
+ int numofElem = 0;
+ for(int i=0; i<children.getLength(); i++) {
+ Node child = children.item(i);
+ if( child instanceof Element ) {
+ model.append( parseElement((Element) child, definedTags) );
+ numofElem++;
+ }
+ }
+ //TODO 【暫定】タグの中身に子要素が全くない場合、中身をvalueとみなす。
+ if(numofElem < 1) {
+ model.attr("value", elem.getTextContent());
+ }
+ return model;
+ }
+
+ private String getMapperClass(List<jp.ac.aiit.xdf.core.tags.Tagdef.Tag.ComponentMapper> mapperClasses, String toolkit) {
+ for(jp.ac.aiit.xdf.core.tags.Tagdef.Tag.ComponentMapper mapper : mapperClasses) {
+ if( mapper.getEnv().equals(toolkit) || mapper.getEnv().equals("common") ) {
+ return mapper.getClazz();
+ }
+ }
+ return null;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.component;
+
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * 画面定義XMLとスタイルシートに定義した属性を実コンポーネントへ反映するマッパーインターフェースである
+ * @author Shunichi Takagi
+ */
+public interface ComponentMapper {
+
+ /**
+ * オブジェクトモデルセットメソッド
+ * @param model
+ */
+ public void setModel(ObjectModel model);
+
+ /**
+ * オブジェクトモデル取得メソッド
+ * @return オブジェクトモデル
+ */
+ public ObjectModel getModel();
+
+ /**
+ * 実コンポーネント化メソッド
+ */
+ public void realize();
+
+ /**
+ * @return 実コンポーネントかされるかどうか
+ */
+ public boolean isRealized();
+
+ /**
+ * @return 実コンポーネント
+ */
+ public Object getComponent();
+
+ /**
+ * タイプコンバータ
+ * @param name
+ * @param value
+ * @return コンバート結果
+ */
+ public Object typeConvert(String name, String value);
+
+ /**
+ * コンポーネントの属性値の取得メソッド
+ * @param name
+ * @return 属性値
+ */
+ public Object getAttr(String name);
+
+ /**
+ * 属性セットするメソッド
+ * @param name
+ * @param value
+ */
+ public void setAttr(String name, Object value);
+
+ /**
+ * 実コンポーネント化フラグ設定メソッド
+ * @param realize
+ */
+ public void setRealize(boolean realize);
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.common;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Map;
+
+import jp.ac.aiit.xdf.application.TagReferences;
+import jp.ac.aiit.xdf.core.exceptions.UnexpectedBehaviorException;
+import jp.ac.aiit.xdf.core.tags.TagLoader;
+import jp.ac.aiit.xdf.core.tags.Tagdef.Tag;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 共通タグ定義クラス
+ * @author Pin.Yuan
+ */
+public class CommonTagReferences implements TagReferences {
+ private static final Logger log = LoggerFactory.getLogger(CommonTagReferences.class);
+ private static final String COMMON_TAGS = "xdf-commontags.xml";
+
+ @Override
+ public Map<String, Tag> getDefinedTags() {
+ try {
+ URL url = ClassLoader.getSystemResource(COMMON_TAGS);
+
+ TagLoader loader = new TagLoader();
+ return loader.load(new File(url.toURI()));
+ } catch(URISyntaxException e) {
+ log.error("Common用タグ定義ファイルがロードできません。", e);
+ throw new UnexpectedBehaviorException("Common用タグ定義ファイルがロードできません。", e);
+ }
+ }
+
+ @Override
+ public String getReferenceId() {
+ return "common";
+ }
+
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.component.common.mappers;
+
+import jp.ac.aiit.xdf.component.ComponentMapper;
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * 空実装のコンポーネントマッパ。
+ * コンポーネントと対応関係にないモデルなど、実コンポーネントとのマッピング処理をさせたくない
+ * モデルで利用する。
+ *
+ * @author Shunichi Takagi
+ */
+public class DoNothingComponentMapper implements ComponentMapper {
+
+ @Override
+ public Object getComponent() {
+ return null;
+ }
+
+ @Override
+ public ObjectModel getModel() {
+ return null;
+ }
+
+ @Override
+ public boolean isRealized() {
+ return false;
+ }
+
+ @Override
+ public void realize() {
+ }
+
+ @Override
+ public void setModel(ObjectModel model) {
+ }
+
+ @Override
+ public Object typeConvert(String name, String value) {
+ return value;
+ }
+
+ @Override
+ public Object getAttr(String name) {
+ return null;
+ }
+
+ @Override
+ public void setRealize(boolean realize){}
+
+ @Override
+ public void setAttr(String name, Object value) {}
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.action;
+
+/**
+ * アプリケーション開発者がアクションを実装するためのインターフェース定義
+ * (あるイベントに対応づけられた)アプリケーション内で動作するアクションを実装する場合はこのインターフェースをimplementsする必要がある。
+ *
+ * @author Pin Yuan, Shunichi Takagi
+ *
+ */
+public interface Action {
+
+ /**
+ * アクションの実行メソッド
+ * @param e eventインタフェースによる定義
+ */
+ public void execute(Event e);
+}
\ No newline at end of file
--- /dev/null
+package jp.ac.aiit.xdf.core.action;
+
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+
+/**
+ * イベント情報を取得するためのインターフェース
+ * ユーザ定義アクションに対して、コンポーネント動作上で実際に発生したイベント情報を取得するために利用する。
+ *
+ * @author pin.Yuan
+ */
+public interface Event {
+
+ /**
+ * イベント対象のオブジェクトモデルを取得
+ *
+ * @return ObjectModel イベント発生したオブジェクトモデルを戻す
+ */
+ public ObjectModel getObjectModel();
+
+
+ /**
+ * 発生したイベントの種類を表す文字列を取得するメソッド
+ *
+ * @return Object(EventType)
+ */
+ public String getEventType();
+
+
+ /**
+ * プリミティブイベント情報返すメソッド、 プリミティブ情報を取得すること可能である。
+ *
+ * @return Object パラメータ
+ */
+ public Object getParam();
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.action;
+
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * オブジェクトモデルに対して、アクションを結びつける処理を一般化したインターフェース
+ * @author Pin Yuan, Shunichi Takagi
+ *
+ */
+public interface EventHandler {
+ /**
+ * GUIコンポーネントにユーザ定義アクションを登録するメソッド
+ * @param om
+ * @param object
+ * @param action
+ */
+ public void setEvent(ObjectModel om, Object object, Action action);
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.action;\r
+\r
+/**\r
+ * イベントタイプ種類インタフェース\r
+ * イベント種類の定義は各ツールキットによる定義すること。\r
+ * (参照:ユーザガイドのアクションの仕様に定義されたイベント種類\r
+ * 例外:列挙型に"-"を定義できないため、"-"を削除したものをタイプにて定義してある)\r
+ * @author pin.Yuan\r
+ */\r
+public interface EventType {\r
+\r
+}\r
--- /dev/null
+package jp.ac.aiit.xdf.core.action.factory;
+
+import jp.ac.aiit.xdf.core.action.Action;
+
+/**
+ * Actionクラスの生成方法をプラグイン化するためのインターフェース
+ * このインターフェースを実装したものをApplication#setActionFactoryの引数として設定することで、Actionの生成部分を指定されたActionFactoryに置き換えることができる。
+ *
+ * デフォルトのActionFactoryはjp.ac.aiit.xdf.core.action.factory.DefaultActionFactoryである。
+ *
+ * @author Shunichi Takagi
+ *
+ */
+public interface ActionFactory {
+ /**
+ * アクションクラス生成メソッド
+ * @param name アクション名称
+ * @return アクション
+ */
+ public Action createAction(String name);
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.action.factory;
+
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.utils.Reflections;
+
+/**
+ * ActionFactoryのデフォルト実装
+ * 与えられたアクション名をアクションの実装クラス名として解釈し、そのクラスのインスタンスを生成したものを返す。
+ *
+ * @author Shunichi Takagi
+ */
+public class DefaultActionFactory implements ActionFactory {
+
+ @Override
+ public Action createAction(String name) {
+ return (Action) Reflections.getInstance(name);
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.exceptions;
+
+/**
+ * フレームワーク内部において予期しない挙動を示したときに発生させる例外
+ *
+ * @author Shunichi Takagi
+ *
+ */
+public class UnexpectedBehaviorException extends RuntimeException {
+ private static final long serialVersionUID = 4014636513715006927L;
+
+ public UnexpectedBehaviorException() {
+ super();
+ }
+
+ public UnexpectedBehaviorException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public UnexpectedBehaviorException(String message) {
+ super(message);
+ }
+
+ public UnexpectedBehaviorException(Throwable cause) {
+ super(cause);
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.model;
+
+
+/**
+ * オブジェクトモデルのデフォルト実装(実装内容はObjectModelSupportと同一)
+ *
+ * このクラスは継承不可なため、もし継承によって機能拡張を行う場合はObjectModelSupportを継承して実装を行うこと。
+ *
+ * @author Shunichi Takagi
+ */
+public final class DefaultObjectModel extends ObjectModelSupport implements ObjectModel {
+
+ /**
+ * オブジェクトモデル実装クラス
+ *
+ * @param tagname
+ */
+ public DefaultObjectModel(String tagname) {
+ super(tagname);
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.model;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jp.ac.aiit.xdf.component.ComponentMapper;
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.core.action.EventType;
+
+/**
+ * GUI上のコンポーネントの包含関係を表現するオブジェクトモデルツリーを構築するためのツリーノードにあたるクラスである。
+ * また、このモデルツリーが実コンポーネントを操作するための統一されたインターフェースとなる。
+ * そのため、ObjectModelではそのツリー操作に必要なインターフェースを定義する。
+ *
+ * @author Shunichi Takagi
+ *
+ */
+public interface ObjectModel {
+
+ /**
+ * このオブジェクトモデルが参照するタグの名前を取得する
+ * @return タブ名前
+ */
+ public String tagname();
+
+ /**
+ * このオブジェクトモデルにIDを設定する。ObjectModel#id(id, false)の呼び出しと同一である。
+ * 設定されたIDはこのオブジェクトモデルを参照するために利用される。
+ *
+ * また、一つのモデルツリー上に同一のIDを持つオブジェクトモデルが存在してはならないため、
+ * このメソッドの実行時にツリーの他モデルが指定されたIDを持つ場合、このモデルに対してIDは設定されない。
+ * もし、強制的にIDを設定したい場合はObjectModel#id(String,boolean)を利用すること
+ *
+ * @param id 設定するID
+ * @return 指定されたIDを設定できた場合はtrue、設定できなかった場合はfalseを返す
+ */
+ public boolean id(String id);
+
+ /**
+ * このオブジェクトモデルにIDを設定する。
+ * もしforceがtrueだった場合は、このモデルが所属するツリー上に指定されたIDを持つモデルが存在した場合、
+ * そのモデルからIDを剥奪し、このモデルに対してそのIDを設定する。
+ * forceがfalseの場合は、このモデルが所属するツリー上に指定されたIDを持つモデルが存在した場合、このモデルに対してIDを設定しない。
+ *
+ * @param id 設定するID
+ * @param force 他モデルに設定されたIDの強奪を許可するか
+ * @return このモデルに対してIDを設定できた場合はtrue、できなかった場合はfalseを返す
+ */
+ public boolean id(String id, boolean force);
+
+ /**
+ * このオブジェクトモデルのIDを取得する。
+ *
+ * @return 設定されているID
+ */
+ public String id();
+
+ /**
+ * このオブジェクトモデルにクラス属性を設定する。
+ *
+ * @param clazz 設定するクラス
+ */
+ public void addClass(String clazz);
+
+ /**
+ * このオブジェクトモデルから指定されたクラス属性を取り除く。
+ *
+ * @param clazz 取り除くクラス
+ */
+ public void removeClass(String clazz);
+
+ /**
+ * このオブジェクトモデルが指定されたクラスを持っているかどうかを検査する。
+ *
+ * @param clazz 検査対象のクラス名
+ * @return このモデルにclazzが設定されていた場合true、されていなかった場合falseを返す
+ */
+ public boolean hasClass(String clazz);
+
+ /**
+ * このオブジェクトモデルが持つクラス名をすべて返す
+ *
+ * @return このモデルが保持するすべてのクラス名
+ */
+ public List<String> classes();
+
+ /**
+ * このモデルに対して指定した属性名&属性値を持つ属性を設定する。
+ * ここで設定された属性が処理されるかは実装次第である。また、処理できない属性が設定された場合、その属性は無視する。
+ *
+ * @param name 属性名
+ * @param value 属性値
+ */
+ public void attr(String name, Object value);
+
+ /**
+ * このモデルに対して指定した属性名&属性値を持つ属性を上書きせずに設定する
+ * ここで設定された属性が処理されるかは実装次第である。また、処理できない属性が設定された場合、その属性は無視する。
+ *
+ * 注意)このメソッドを用いて属性を適用した時、既に同じ属性名の属性が設定されていた場合は上書きせず、属性の設定も行わない。
+ *
+ * @param name 属性名
+ * @param value 属性値
+ */
+ public void attrWeakly(String name, String value);
+
+ /**
+ * このモデルが指定された名前の属性を持っているかを調べる
+ * @param name 調べる対象となる属性の名前
+ * @return 指定された名前の属性がある場合true, なかった場合はfalse
+ */
+ public boolean hasAttr(String name);
+
+ /**
+ * 指定された名前を持つ属性の属性値を取得する
+ *
+ * @param name 属性値を取得する属性の属性名
+ * @return nameで指定された属性の属性値
+ */
+ public Object attr(String name);
+
+ /**
+ * 指定された名前の属性をオブジェクトモデル内部に保持された値として取得する
+ *
+ * @param name 取得する属性名
+ * @return オブジェクトモデル内部に保持されている属性値
+ */
+ public Object attrFromModel(String name);
+
+ /**
+ * このモデルが保持するすべての属性値の名前を取得する
+ * @return 属性名称
+ */
+ public Set<String> attrNames();
+
+ /**
+ * このモデルが保持する属性値のマップを取得する。
+ * このメソッドによって取得されたマップは変更不可能である。
+ *
+ * @return モデル属性値のマップ
+ */
+ public Map<String, Object> attrMaps();
+
+ /**
+ * 指定された属性名を持つ属性を取り除く
+ *
+ * @param name 取り除く属性の名前
+ * @return 取り除かれた属性の属性値
+ */
+ public Object removeAttr(String name);
+
+ /**
+ * このオブジェクトモデルの子要素としてオブジェクトモデルを追加する
+ *
+ * @param model 子要素として追加するオブジェクトモデル
+ */
+ public void append(ObjectModel model);
+
+ /**
+ * このオブジェクトモデルと子要素をすべて削除する
+ */
+ public void remove();
+
+ /**
+ * このモデルの子要素から指定されたモデルを削除する。
+ * @param model
+ */
+ public void remove(ObjectModel model);
+
+ /**
+ * このオブジェクトもでるの子要素をすべて削除する
+ */
+ public void empty();
+
+ /**
+ * このオブジェクトモデルが持つ子要素を取得する。
+ * また、このメソッドの返り値のリストは編集不可能である。
+ * @return 子要素リスト
+ */
+ public List<ObjectModel> children();
+
+ /**
+ * このオブジェクトモデルの親要素を取得する。
+ * @return 親要素
+ */
+ public ObjectModel parent();
+
+ /**
+ * このオブジェクトモデルの親要素を設定する
+ * @param parent
+ */
+ public void parent(ObjectModel parent);
+
+ /**
+ * このオブジェクトモデルが所属するツリーのルートモデルを取得する
+ * @return ツリーのルートモデル
+ */
+ public ObjectModel rootModel();
+
+ /**
+ * コンポーネントマッパを登録する
+ *
+ * @param mapper
+ */
+ public void setComponentMapper(ComponentMapper mapper);
+
+ /**
+ * このオブジェクトモデルを基に実コンポーネントを生成する。
+ */
+ public void realize();
+
+ /**
+ * このオブジェクトモデルに対応づけられた実コンポーネントを取得する。
+ * @return 実コンポーネント
+ */
+ public Object getComponent();
+
+
+ /**
+ * オブジェクトモデルのアクション設定する
+ * @param action ユーザアクションクラス定義(XML画面定義ファイルによる)
+ * @param event イベントタイプ(ユーザガイドに参照:第3章)
+ */
+ public void setAction(Action action, String event);
+
+ /**
+ * オブジェクトモデルのイベントタイプによるアクションを取得する
+ * @param event
+ * @return ユーザ定義アクション
+ */
+ public Action getAction(EventType event);
+
+ /**
+ * オブジェクトモデルのすべてのアクションを取得する
+ * @return ユーザ定義アクションマップ、キーはイベントタイプである。
+ */
+ public Map<String, Action> getActions();
+
+ /**
+ *
+ */
+ public void open();
+
+ /**
+ *
+ */
+ public void close();
+
+ /**
+ * 実コンポーネントされたかどうかフラグを設定する
+ * @param realize true:実コンポーネント化された、false:されていない
+ */
+ public void setRealize(boolean realize);
+}
\ No newline at end of file
--- /dev/null
+package jp.ac.aiit.xdf.core.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jp.ac.aiit.xdf.component.ComponentMapper;
+import jp.ac.aiit.xdf.core.action.Action;
+import jp.ac.aiit.xdf.core.action.EventType;
+
+/**
+ * オブジェクトモデルのデフォルト実装を提供するクラス。
+ * オブジェクトモデル拡張のためのサポートクラスとして存在する。ただ実装として利用したい場合はDefaultObjectModelを利用すること。
+ *
+ * @author Shunichi Takagi
+ */
+public abstract class ObjectModelSupport implements ObjectModel {
+ private String tagname;
+ private ComponentMapper mapper;
+
+ private String id;
+ private List<String> classes;
+ private Map<String, Object> attrs;
+
+ private ObjectModel parent;
+ private List<ObjectModel> children;
+
+ // アクション情報保持する
+ private Map<String, Action> actions;
+
+ /**
+ * オブジェクトモデルの初期化
+ * @param tagname
+ */
+ public ObjectModelSupport(String tagname) {
+ this.tagname = tagname;
+
+ this.id = null;
+ this.classes = new ArrayList<String>();
+ this.attrs = new HashMap<String, Object>();
+
+ this.parent = null;
+ this.children = new ArrayList<ObjectModel>();
+
+ this.actions = new HashMap<String, Action>();
+ }
+
+ public String tagname() {
+ return tagname;
+ }
+
+ public void addClass(String clazz) {
+ classes.add(clazz);
+ }
+
+ public Map<String, Object> attrMaps() {
+ return Collections.unmodifiableMap(attrs);
+ }
+
+ public Set<String> attrNames() {
+ return Collections.unmodifiableSet(attrs.keySet());
+ }
+
+ public void append(ObjectModel model) {
+ model.parent(this);
+ children.add(model);
+ }
+
+ public void attr(String name, Object value) {
+ if (mapper.isRealized()){
+ mapper.setAttr(name, value);
+ }else {
+ attrs.put(name, value);
+ }
+ }
+
+ public boolean hasAttr(String name) {
+ return attrs.containsKey(name);
+ }
+
+ public Object attr(String name) {
+ return (mapper.isRealized() ? mapper.getAttr(name):attrs.get(name));
+ }
+
+ public Object attrFromModel(String name) {
+ return attrs.get(name);
+ }
+
+ public List<ObjectModel> children() {
+ return Collections.unmodifiableList(children);
+ }
+
+ public void empty() {
+ children.clear();
+ }
+
+ public boolean hasClass(String clazz) {
+ return classes.contains(clazz);
+ }
+
+ public boolean id(String id) {
+ //TODO 所属ツリー上で同一のIDが指定されていないか確認しなければならない
+ this.id = id;
+ return true;
+ }
+
+ public boolean id(String id, boolean force) {
+ //TODO 所属ツリー上で同一のIDが指定されていないか確認しなければならない
+ this.id = id;
+ return true;
+ }
+
+ public String id() {
+ return id;
+ }
+
+ public ObjectModel parent() {
+ return parent;
+ }
+
+ @Override
+ public void parent(ObjectModel parent) {
+ this.parent = parent;
+ }
+
+ public ObjectModel rootModel() {
+ ObjectModel m = this;
+ while( m.parent() != null ) {
+ m = m.parent();
+ }
+ return m;
+ }
+
+ public void remove() {
+ parent.remove(this);
+ }
+
+ public Object removeAttr(String name) {
+ return attrs.remove(name);
+ }
+
+ public void removeClass(String clazz) {
+ classes.remove(clazz);
+ }
+
+ public void remove(ObjectModel model) {
+ children.remove(model);
+ }
+
+ @Override
+ public void setComponentMapper(ComponentMapper mapper) {
+ this.mapper = mapper;
+ mapper.setModel(this);
+ }
+
+ @Override
+ public Object getComponent() {
+ return ( mapper.isRealized() ? mapper.getComponent() : null );
+ }
+
+ @Override
+ public void realize() {
+ mapper.realize();
+ }
+
+ @Override
+ public void setAction(Action action, String event){
+ actions.put(event, action);
+ }
+
+ @Override
+ public Action getAction(EventType event) {
+ return actions.get(event);
+ }
+
+ @Override
+ public Map<String, Action> getActions() {
+ return actions;
+ }
+
+ @Override
+ public void attrWeakly(String name, String value){
+ if( !hasAttr(name) && ( mapper != null )) {
+ attr(name, mapper.typeConvert(name, value));
+ }
+ }
+
+ @Override
+ public List<String> classes(){ return classes; }
+
+ @Override
+ public void close() { }
+
+ @Override
+ public void open() { }
+
+
+ @Override
+ public void setRealize(boolean realize){
+ mapper.setRealize(realize);
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.selector;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * セレクタ内ののルール記述の実装(ユーザガイドへ参照)
+ *
+ * @author Shunichi Takagi
+ */
+public class Rule {
+ private static final Pattern TAGNAME_EXTRACTOR = Pattern.compile("^([^.#]+).*");
+ private static final Pattern ID_EXTRACTOR = Pattern.compile(".*#([^.]+).*");
+ private static final Pattern CLASS_EXTRACTOR = Pattern.compile("\\.([^.#]+)");
+
+ private String tagName = null;
+ private String id = null;
+ private List<String> classes = null;
+
+ /**
+ * コンストラクター
+ * @param rule
+ */
+ public Rule(String rule) {
+ this(extract(rule, TAGNAME_EXTRACTOR), extract(rule, ID_EXTRACTOR), extractClasses(rule));
+ }
+
+ /**
+ * コンストラクター
+ * @param tagName タグ名
+ * @param id 画面定義XMLのid定義
+ * @param classes 画面定義XMLのclass定義
+ */
+ public Rule(String tagName, String id, List<String> classes) {
+ this.tagName = tagName;
+ this.id = id;
+ this.classes = classes;
+ }
+
+ private static String extract(String text, Pattern pattern) {
+ Matcher m = pattern.matcher(text);
+ if( m.matches() ) {
+ return m.group(1);
+ } else {
+ return null;
+ }
+ }
+
+ //TODO 指定されたクラス名の抽出がうまくいかない
+ private static List<String> extractClasses(String text) {
+ Matcher m = CLASS_EXTRACTOR.matcher(text);
+
+ if( m.matches() ) {
+ String classSentence = m.group(1);
+ String[] classes = classSentence.split(".");
+
+ return Arrays.asList(classes);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * ルートオブジェクトモデルを取得する
+ * @param findRoot
+ * @return オブジェクトモデルセット
+ */
+ public Set<ObjectModel> find(ObjectModel findRoot) {
+ return findImpl(findRoot, new HashSet<ObjectModel>());
+ }
+
+ private Set<ObjectModel> findImpl(ObjectModel findRoot, Set<ObjectModel> result) {
+ if( match(findRoot) ) {
+ result.add(findRoot);
+ }
+
+ for(ObjectModel child : findRoot.children()) {
+ findImpl(child, result);
+ }
+
+ return result;
+ }
+
+ /**
+ * ルールによるオブジェクトモデルをマッチングする
+ * @param model オブジェクトモデル
+ * @return マッチング結果
+ */
+ public boolean match(ObjectModel model) {
+ return matchTagName(model) && matchID(model) && matchClasses(model);
+ }
+
+ private boolean matchTagName(ObjectModel model) {
+ return ( tagName == null ? true : tagName.equals(model.tagname()) );
+ }
+
+ private boolean matchID(ObjectModel model) {
+ return ( id == null ? true : id.equals(model.id()) );
+ }
+
+ private boolean matchClasses(ObjectModel model) {
+ if( classes == null ) {
+ return true;
+ } else {
+ for(String clazz : classes) {
+ if( !model.hasClass(clazz) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.selector;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * @author Shunichi Takagi
+ * セレクターのルールシーケンス(ユーザガイドへ参照)
+ */
+public class RuleSequence {
+ private List<Rule> rules;
+
+ /**
+ * コンストラクター
+ * @param ruleSequence
+ */
+ public RuleSequence(String ruleSequence) {
+ this( extractRules(ruleSequence) );
+ }
+
+ /**
+ * コンストラクター
+ * @param rules
+ */
+ public RuleSequence(List<Rule> rules) {
+ this.rules = rules;
+ }
+
+ private static List<Rule> extractRules(String ruleSequence) {
+ List<Rule> rules = new ArrayList<Rule>();
+ String[] ruleStrings = ruleSequence.split(" ");
+
+ for(String ruleString : ruleStrings) {
+ rules.add( new Rule(ruleString.trim()) );
+ }
+
+ return rules;
+ }
+
+ /**
+ * オブジェクトモデルをマッチングする
+ * @param findRoot
+ * @return オブジェクトモデルセット
+ */
+ public Set<ObjectModel> find(ObjectModel findRoot) {
+ Set<ObjectModel> findRoots = new HashSet<ObjectModel>();
+ findRoots.add(findRoot);
+
+ return findImpl(findRoots, 0);
+ }
+
+ private Set<ObjectModel> findImpl(Set<ObjectModel> findRoots, int ruleIndex) {
+ try {
+ Rule rule = rules.get(ruleIndex);
+
+ Set<ObjectModel> result = new HashSet<ObjectModel>();
+ for(ObjectModel findRoot : findRoots) {
+ result.addAll( findImpl( rule.find(findRoot), ruleIndex+1 ) );
+ }
+
+ return result;
+ } catch(IndexOutOfBoundsException e) {
+ return findRoots;
+ }
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.selector;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jp.ac.aiit.xdf.core.model.ObjectModel;
+
+/**
+ * @author Shunichi Takagi
+ * セレクター定義(ユーザガイドへ参照)
+ */
+public class Selector {
+ private List<RuleSequence> ruleSequences;
+
+ /**
+ * コンストラクター
+ * @param selector
+ */
+ public Selector(String selector) {
+ this( extractRuleSequences(selector) );
+ }
+
+ /**
+ * コンストラクター
+ * @param ruleSequences
+ */
+ public Selector(List<RuleSequence> ruleSequences) {
+ this.ruleSequences = ruleSequences;
+ }
+
+ private static List<RuleSequence> extractRuleSequences(String selector) {
+ List<RuleSequence> ruleSequences = new ArrayList<RuleSequence>();
+ String[] ruleSeqStrings = selector.split(",");
+
+ for(String ruleSeqString : ruleSeqStrings) {
+ ruleSequences.add( new RuleSequence(ruleSeqString.trim()) );
+ }
+
+ return ruleSequences;
+ }
+
+ /**
+ * オブジェクトモデルをマッチングする
+ * @param findRoot
+ * @return オブジェクトモデルリスト
+ */
+ public List<ObjectModel> find(ObjectModel findRoot) {
+ List<ObjectModel> result = new ArrayList<ObjectModel>();
+ for(RuleSequence ruleSequence : ruleSequences) {
+ result.addAll( ruleSequence.find(findRoot) );
+ }
+
+ return result;
+ }
+
+ /**
+ * オブジェクトモデルをマッチングする
+ * @param selector
+ * @param findRoot
+ * @return オブジェクトモデルリスト
+ */
+ public static List<ObjectModel> find(String selector, ObjectModel findRoot) {
+ return new Selector(selector).find(findRoot);
+ }
+}
\ No newline at end of file
--- /dev/null
+package jp.ac.aiit.xdf.core.tags;
+import java.io.File;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import jp.ac.aiit.xdf.core.exceptions.UnexpectedBehaviorException;
+import jp.ac.aiit.xdf.core.tags.Tagdef.Tag;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * タグ定義ファイルのロード処理である。
+ * XDFフレームワークのタブの構造定義(Tagdef)を従って定義ファイルの取り込み機能を提供する、
+ * loadメソッドを実施後、Tagdefに定義されたすべてのタグ定義(tag)をマップとして返し、
+ * そのマップのキーはタグ定義のタブ名とする。
+ *
+ * Tagdef構造概要
+ * ルート:<tagdef>
+ * タグ定義:<tag name:タブ名>
+ * モデルクラス :<modelclass >value:モデルクラス
+ * マッパークラス:<component-mapper env:ツールキット定義 class:マッパークラス>
+ * サンプル:
+ * <tag name="xdf-window">
+ * <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ * <component-mapper env="common" class="jp.ac.aiit.xdf.component.common.mappers.DoNothingComponentMapper" />
+ * </tag>
+ *
+ * @author Pin.Yuan
+ */
+public class TagLoader {
+ private static final Logger log = LoggerFactory.getLogger(TagLoader.class);
+
+ /**
+ * タグ定義ファイルのロードを行う
+ * @param file タグ定義ファイル
+ * @return タグ定義
+ */
+ public Map<String, Tag> load(File file) {
+
+ try {
+ JAXBContext context = JAXBContext.newInstance(Tagdef.class);
+ Unmarshaller um = context.createUnmarshaller();
+
+ Tagdef tagdef = (Tagdef) um.unmarshal(file);
+
+ Map<String, Tag> tagMap = new HashMap<String, Tag>();
+
+ for (Tagdef.Tag tag : tagdef.getTag()){
+ // タブ定義のモデルクラスのチェック
+ if (checkClassNameExist(tag.getModelclass())){
+ // タブ定義の重複チェック
+ if (!tagMap.containsKey(tag.getName().toLowerCase(Locale.ENGLISH))){
+ boolean mappingclassexist = true;
+ // タグ定義のマッピング定義のチェック
+ for (Tagdef.Tag.ComponentMapper componentmapper: tag.getComponentMapper()){
+ if (!checkClassNameExist(componentmapper.getClazz())){
+ mappingclassexist = false;
+ log.warn("指定されたクラスが存在しません:"+componentmapper.getClazz());
+ }
+ }
+ if (mappingclassexist) {
+ tagMap.put(tag.getName().toLowerCase(Locale.ENGLISH), tag);
+ }
+
+ } else {
+ log.warn("タグ名の定義が重複しています:"+tag.getName());
+ }
+ } else {
+ log.warn("指定されたクラスが存在しません:"+tag.getModelclass());
+ }
+ }
+
+ return tagMap;
+ } catch(JAXBException e) {
+ log.error("JAXBを使用できません");
+ throw new UnexpectedBehaviorException("JAXBを使用できません", e);
+ }
+ }
+
+ // タブ定義のクラス名は存在しているかどうか
+ private boolean checkClassNameExist(String clazz) {
+ try {
+ Class.forName(clazz);
+ } catch (ClassNotFoundException e){
+ return false;
+ }
+ return true;
+ }
+}
--- /dev/null
+//\r
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6 \r
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> \r
+// Any modifications to this file will be lost upon recompilation of the source schema. \r
+\r
+package jp.ac.aiit.xdf.core.tags;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.xml.bind.annotation.XmlAccessType;\r
+import javax.xml.bind.annotation.XmlAccessorType;\r
+import javax.xml.bind.annotation.XmlAttribute;\r
+import javax.xml.bind.annotation.XmlElement;\r
+import javax.xml.bind.annotation.XmlRootElement;\r
+import javax.xml.bind.annotation.XmlType;\r
+\r
+import jp.ac.aiit.xdf.utils.CollectionUtils;\r
+import jp.ac.aiit.xdf.utils.CollectionUtils.CollectionToListProcess;\r
+\r
+\r
+/**\r
+ * <p>Java class for tagdef complex type.\r
+ * \r
+ * <p>The following schema fragment specifies the expected content contained within this class.\r
+ * \r
+ * <pre>\r
+ * <complexType name="tagdef">\r
+ * <complexContent>\r
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">\r
+ * <sequence>\r
+ * <element name="tag" maxOccurs="unbounded">\r
+ * <complexType>\r
+ * <complexContent>\r
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">\r
+ * <sequence>\r
+ * <element name="modelclass" type="{http://www.w3.org/2001/XMLSchema}string"/>\r
+ * <element name="component-mapping" maxOccurs="unbounded" minOccurs="0">\r
+ * <complexType>\r
+ * <complexContent>\r
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">\r
+ * <sequence>\r
+ * </sequence>\r
+ * <attribute name="env" type="{http://www.w3.org/2001/XMLSchema}string" />\r
+ * <attribute name="class" type="{http://www.w3.org/2001/XMLSchema}string" />\r
+ * </restriction>\r
+ * </complexContent>\r
+ * </complexType>\r
+ * </element>\r
+ * </sequence>\r
+ * <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />\r
+ * </restriction>\r
+ * </complexContent>\r
+ * </complexType>\r
+ * </element>\r
+ * </sequence>\r
+ * </restriction>\r
+ * </complexContent>\r
+ * </complexType>\r
+ * </pre>\r
+ * \r
+ * \r
+ */\r
+\r
+@XmlRootElement(name="tagdef")\r
+@XmlAccessorType(XmlAccessType.FIELD)\r
+@XmlType(name = "tagdef", propOrder = {\r
+ "tag"\r
+})\r
+public class Tagdef {\r
+\r
+ @XmlElement(required = true)\r
+ protected List<Tagdef.Tag> tag;\r
+\r
+ /**\r
+ * Gets the value of the tag property.\r
+ * \r
+ * <p>\r
+ * This accessor method returns a reference to the live list,\r
+ * not a snapshot. Therefore any modification you make to the\r
+ * returned list will be present inside the JAXB object.\r
+ * This is why there is not a <CODE>set</CODE> method for the tag property.\r
+ * \r
+ * <p>\r
+ * For example, to add a new item, do as follows:\r
+ * <pre>\r
+ * getTag().add(newItem);\r
+ * </pre>\r
+ * \r
+ * \r
+ * <p>\r
+ * Objects of the following type(s) are allowed in the list\r
+ * {@link Tagdef.Tag }\r
+ * \r
+ * \r
+ * @return list of Tag\r
+ */\r
+ public List<Tagdef.Tag> getTag() {\r
+ if (tag == null) {\r
+ tag = new ArrayList<Tagdef.Tag>();\r
+ }\r
+ return this.tag;\r
+ }\r
+\r
+\r
+ /**\r
+ * <p>Java class for anonymous complex type.\r
+ * \r
+ * <p>The following schema fragment specifies the expected content contained within this class.\r
+ * \r
+ * <pre>\r
+ * <complexType>\r
+ * <complexContent>\r
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">\r
+ * <sequence>\r
+ * <element name="modelclass" type="{http://www.w3.org/2001/XMLSchema}string"/>\r
+ * <element name="component-mapper" maxOccurs="unbounded" minOccurs="0">\r
+ * <complexType>\r
+ * <complexContent>\r
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">\r
+ * <sequence>\r
+ * </sequence>\r
+ * <attribute name="env" type="{http://www.w3.org/2001/XMLSchema}string" />\r
+ * <attribute name="class" type="{http://www.w3.org/2001/XMLSchema}string" />\r
+ * </restriction>\r
+ * </complexContent>\r
+ * </complexType>\r
+ * </element>\r
+ * </sequence>\r
+ * <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />\r
+ * </restriction>\r
+ * </complexContent>\r
+ * </complexType>\r
+ * </pre>\r
+ * \r
+ * \r
+ */\r
+ @XmlAccessorType(XmlAccessType.FIELD)\r
+ @XmlType(name = "", propOrder = {\r
+ "modelclass",\r
+ "componentMapper"\r
+ })\r
+ public static class Tag {\r
+\r
+ @XmlElement(required = true)\r
+ protected String modelclass;\r
+ @XmlElement(name = "component-mapper")\r
+ protected List<Tagdef.Tag.ComponentMapper> componentMapper;\r
+ @XmlAttribute\r
+ protected String name;\r
+\r
+ /**\r
+ * Gets the value of the modelclass property.\r
+ * \r
+ * @return\r
+ * possible object is\r
+ * {@link String }\r
+ * \r
+ */\r
+ public String getModelclass() {\r
+ return modelclass;\r
+ }\r
+\r
+ /**\r
+ * Sets the value of the modelclass property.\r
+ * \r
+ * @param value\r
+ * allowed object is\r
+ * {@link String }\r
+ * \r
+ */\r
+ public void setModelclass(String value) {\r
+ this.modelclass = value;\r
+ }\r
+\r
+ /**\r
+ * Gets the value of the componentMapper property.\r
+ * \r
+ * <p>\r
+ * This accessor method returns a reference to the live list,\r
+ * not a snapshot. Therefore any modification you make to the\r
+ * returned list will be present inside the JAXB object.\r
+ * This is why there is not a <CODE>set</CODE> method for the componentMapper property.\r
+ * \r
+ * <p>\r
+ * For example, to add a new item, do as follows:\r
+ * <pre>\r
+ * getComponentMapper().add(newItem);\r
+ * </pre>\r
+ * \r
+ * \r
+ * <p>\r
+ * Objects of the following type(s) are allowed in the list\r
+ * {@link Tagdef.Tag.ComponentMapper }\r
+ * \r
+ * \r
+ */\r
+ /**\r
+ * @return List of ComponentMapper\r
+ */\r
+ public List<Tagdef.Tag.ComponentMapper> getComponentMapper() {\r
+ if (componentMapper == null) {\r
+ componentMapper = new ArrayList<Tagdef.Tag.ComponentMapper>();\r
+ }\r
+ return this.componentMapper;\r
+ }\r
+ \r
+ /**\r
+ * @param mappers\r
+ */\r
+ public void setComponentMapper(List<Tagdef.Tag.ComponentMapper> mappers) {\r
+ this.componentMapper = mappers;\r
+ }\r
+\r
+ /**\r
+ * Gets the value of the name property.\r
+ * \r
+ * @return\r
+ * possible object is\r
+ * {@link String }\r
+ * \r
+ */\r
+ public String getName() {\r
+ return name;\r
+ }\r
+\r
+ /**\r
+ * Sets the value of the name property.\r
+ * \r
+ * @param value\r
+ * allowed object is\r
+ * {@link String }\r
+ * \r
+ */\r
+ public void setName(String value) {\r
+ this.name = value;\r
+ }\r
+ \r
+ /**\r
+ * タグ定義のマージ\r
+ * @param tag タグ定義\r
+ */\r
+ public void merge(Tag tag) {\r
+ if( name.equals(tag.getName()) ) {\r
+ List<String> exists = CollectionUtils.collectionToList(componentMapper, new CollectionToListProcess<ComponentMapper,String>() {\r
+ @Override public String extract(ComponentMapper target) {\r
+ return target.getEnv();\r
+ }\r
+ });\r
+ \r
+ for(ComponentMapper mapper : tag.getComponentMapper()) {\r
+ if( !exists.contains(mapper.getEnv()) ) {\r
+ componentMapper.add(mapper);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * <p>Java class for anonymous complex type.\r
+ * \r
+ * <p>The following schema fragment specifies the expected content contained within this class.\r
+ * \r
+ * <pre>\r
+ * <complexType>\r
+ * <complexContent>\r
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">\r
+ * <sequence>\r
+ * </sequence>\r
+ * <attribute name="env" type="{http://www.w3.org/2001/XMLSchema}string" />\r
+ * <attribute name="class" type="{http://www.w3.org/2001/XMLSchema}string" />\r
+ * </restriction>\r
+ * </complexContent>\r
+ * </complexType>\r
+ * </pre>\r
+ * \r
+ * \r
+ */\r
+ @XmlAccessorType(XmlAccessType.FIELD)\r
+ @XmlType(name = "")\r
+ public static class ComponentMapper {\r
+\r
+ @XmlAttribute\r
+ protected String env;\r
+ @XmlAttribute(name = "class")\r
+ protected String clazz;\r
+\r
+ /**\r
+ * Gets the value of the env property.\r
+ * \r
+ * @return\r
+ * possible object is\r
+ * {@link String }\r
+ * \r
+ */\r
+ public String getEnv() {\r
+ return env;\r
+ }\r
+\r
+ /**\r
+ * Sets the value of the env property.\r
+ * \r
+ * @param value\r
+ * allowed object is\r
+ * {@link String }\r
+ * \r
+ */\r
+ public void setEnv(String value) {\r
+ this.env = value;\r
+ }\r
+\r
+ /**\r
+ * Gets the value of the clazz property.\r
+ * \r
+ * @return\r
+ * possible object is\r
+ * {@link String }\r
+ * \r
+ */\r
+ public String getClazz() {\r
+ return clazz;\r
+ }\r
+\r
+ /**\r
+ * Sets the value of the clazz property.\r
+ * \r
+ * @param value\r
+ * allowed object is\r
+ * {@link String }\r
+ * \r
+ */\r
+ public void setClazz(String value) {\r
+ this.clazz = value;\r
+ }\r
+\r
+ }\r
+\r
+ }\r
+\r
+}\r
--- /dev/null
+package jp.ac.aiit.xdf.core.typeconvert;
+
+
+/**
+ * "true", "false"と記述された文字をBoolean値に変換する。
+ *
+ * 実際の変換例は以下の通り、ここでわかる様に"true","false"以外の文字列が指定された場合はfalseになる。
+ * 例)
+ * "true" -> true
+ * "false" -> false
+ * "error" -> false
+ * @author Shunichi Takagi
+ */
+public class BooleanConverter implements TypeConverter<Boolean> {
+ private static final String APPLIABLE_STRING = "true|false";
+
+ @Override
+ public Boolean apply(String target) {
+ String t = target.trim();
+
+ if( t.equals("true") ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean isAppliable(String target) {
+ return target.matches(APPLIABLE_STRING);
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.typeconvert;
+
+import jp.ac.aiit.xdf.utils.Reflections;
+
+/**
+ * 指定された文字列をFQCNとして扱い、デフォルトコンストラクタによってインスタンスを生成する。
+ *
+ * @author Tagaki
+ * @param <T> 生成されるインスタンスの型
+ */
+public class InstanciationConverter<T> implements TypeConverter<T> {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public T apply(String target) {
+ return (T) Reflections.getInstance(target);
+ }
+
+ @Override
+ public boolean isAppliable(String target) {
+ return true;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.typeconvert;
+
+
+/**
+ * 文字列を整数値に変換する
+ *
+ * @author Shunichi Takagi
+ */
+public class IntegerConverter implements TypeConverter<Integer> {
+ private static final String MATCHER = "^[-+]?[1-9][0-9]*$"; //前ゼロを許可してもよいと思う。
+
+ @Override
+ public Integer apply(String target) {
+ return Integer.valueOf(target);
+ }
+
+ @Override
+ public boolean isAppliable(String target) {
+ return target.matches(MATCHER);
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.typeconvert;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 文字列からピクセル値を示す整数値に変換する
+ * IntegerConverterとの違いは、文字列の最後にピクセル値であることを示す"px"を記述可能なこと。
+ *
+ * @author Kodama
+ */
+public class PixelValueConverter implements TypeConverter<Integer> {
+ private static final Pattern PIXEL_FORMAT = Pattern.compile("^([1-9][0-9]*)(px)?$");
+
+ @Override
+ public Integer apply(String target) {
+ Matcher m = PIXEL_FORMAT.matcher(target);
+ if( m.matches() ) {
+ return Integer.valueOf(m.group(1));
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isAppliable(String target) {
+ return PIXEL_FORMAT.matcher(target).matches();
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.typeconvert;
+
+/**
+ * 指定された文字列をそのまま返す。
+ * 変換処理が必要ない場合に利用する。
+ *
+ * @author Shunichi Takagi
+ */
+public class StringConverter implements TypeConverter<String> {
+
+ @Override
+ public String apply(String target) {
+ return target;
+ }
+
+ @Override
+ public boolean isAppliable(String target) {
+ return true;
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.typeconvert;
+
+/**
+ * @author kodama
+ * カンマ区きりの文字列のコンバータ(ListおよびComboboxのValues属性)
+ */
+public class StringValuesConverter implements TypeConverter<String[]> {
+
+ private static final String defaultSeparator = ",";
+ private String splitter;
+ /**
+ * コンストラクター
+ */
+ public StringValuesConverter(){
+ this(defaultSeparator);
+ }
+ /**
+ * コンストラクター
+ * @param separator 区きり
+ */
+ public StringValuesConverter(String separator){
+ this.splitter = " *" + separator + " *";
+ }
+ @Override
+ public String[] apply(String target) {
+ return
+ (target == null || target.isEmpty()) ? new String[]{}
+ : target.split(splitter);
+ }
+
+ @Override
+ public boolean isAppliable(String target) {
+ return true;
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.core.typeconvert;
+
+/**
+ * コンバータの共通インターフェース
+ * 画面定義XMLおよびスタイルシートから文字列をインプットとして、
+ * 実コンポーネント属性値へアウトプットするためコンバータのインターフェースである。
+ *
+ * @author Shunichi Takagi
+ * @param <T> 変換された値の型
+ */
+public interface TypeConverter<T> {
+
+ /**
+ * コンバート可能かどうかを取得する
+ *
+ * @param target
+ * @return コンバート可能かどうか。コンバート可能な場合true、不可能な場合falseが返る。
+ */
+ public boolean isAppliable(String target);
+
+ /**
+ * コンバータを適用する
+ *
+ * @param target
+ * @return タイプ
+ */
+ public T apply(String target);
+}
--- /dev/null
+package jp.ac.aiit.xdf.utils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+/**
+ * @author Shunichi Takagi
+ */
+public class CollectionUtils {
+
+ /**
+ * すべて集合体の取得
+ * @param <T>
+ * @param collection
+ * @param process
+ */
+ public static <T> void each(Collection<T> collection, UnitProcess<T> process) {
+ for(T elem : collection) {
+ process.invoke(elem);
+ }
+ }
+
+ /**
+ * @param <K>
+ * @param <V>
+ * @param map
+ * @param process
+ */
+ public static <K,V> void each(Map<K,V> map, UnitProcess<Entry<K,V>> process) {
+ for(Entry<K,V> entry : map.entrySet()) {
+ process.invoke(entry);
+ }
+ }
+
+ /**
+ * コンポーネントからマップへ変換メソッド
+ * @param <T>
+ * @param <K>
+ * @param <V>
+ * @param collection
+ * @param process
+ * @return 変換後マップ
+ */
+ public static <T,K,V> Map<K,V> collectionToMap(Collection<T> collection, CollectionToMapProcess<T,K,V> process) {
+ return collectionToMap(collection, process, new HashMap<K,V>());
+ }
+
+ /**
+ * コンポーネントからマップへ変換メソッド
+ * @param <T>
+ * @param <K>
+ * @param <V>
+ * @param collection
+ * @param process
+ * @param returnMap
+ * @return 変換後マップ
+ */
+ public static <T,K,V> Map<K,V> collectionToMap(Collection<T> collection, CollectionToMapProcess<T,K,V> process, Map<K,V> returnMap) {
+ for(T elem : collection) {
+ returnMap.put( process.extractKey(elem), process.extractValue(elem) );
+ }
+
+ return returnMap;
+ }
+
+ /**
+ * コンポーネントからリストへ変換メソッド
+ * @param <T1>
+ * @param <T2>
+ * @param collection
+ * @param process
+ * @return リスト
+ */
+ public static <T1,T2> List<T2> collectionToList(Collection<T1> collection, CollectionToListProcess<T1,T2> process) {
+ return collectionToList(collection, process, new ArrayList<T2>());
+ }
+
+ /**
+ * コンポーネントからリストへ変換メソッド
+ * @param <T1>
+ * @param <T2>
+ * @param collection
+ * @param process
+ * @param returnList
+ * @return リスト
+ */
+ public static <T1,T2> List<T2> collectionToList(Collection<T1> collection, CollectionToListProcess<T1,T2> process, List<T2> returnList) {
+ for(T1 elem : collection) {
+ returnList.add( process.extract(elem) );
+ }
+
+ return returnList;
+ }
+
+ /**
+ * マップからコンポーネントへ変換メソッド
+ * @param <K>
+ * @param <V>
+ * @param <T>
+ * @param map
+ * @param process
+ * @param returnCollection
+ * @return マップ
+ */
+ public static <K,V,T> Collection<T> mapToCollection(Map<K,V> map, MapToCollectionProcess<K,V,T> process, Collection<T> returnCollection) {
+ for(Entry<K,V> entry : map.entrySet()) {
+ returnCollection.add( process.extract(entry.getKey(), entry.getValue()) );
+ }
+ return returnCollection;
+ }
+
+ /**
+ * マップからArrayListへ変換メソッド
+ * @param <K>
+ * @param <V>
+ * @param <T>
+ * @param map
+ * @param process
+ * @return リスト
+ */
+ public static <K,V,T> List<T> mapToArrayList(Map<K,V> map, MapToCollectionProcess<K,V,T> process) {
+ return (List<T>) mapToCollection(map, process, new ArrayList<T>());
+ }
+
+ /**
+ * マップからハッシュセットへ変換メソッド
+ * @param <K>
+ * @param <V>
+ * @param <T>
+ * @param map
+ * @param process
+ * @return ハッシュセット
+ */
+ public static <K,V,T> Set<T> mapToHashSet(Map<K,V> map, MapToCollectionProcess<K,V,T> process) {
+ return (Set<T>) mapToCollection(map, process, new HashSet<T>());
+ }
+
+ /**
+ * 変換ユニットプロセス
+ * @author a0709pe
+ *
+ * @param <T>
+ */
+ public interface UnitProcess<T> {
+ /**
+ * 変換ユニット実行メソッド
+ * @param target
+ */
+ public void invoke(T target);
+ }
+
+ /**
+ * @author a0709pe
+ *
+ * @param <T>
+ * @param <K>
+ * @param <V>
+ */
+ public interface CollectionToMapProcess<T,K,V> {
+ /**
+ * @param target
+ * @return キー
+ */
+ public K extractKey(T target);
+ /**
+ * @param target
+ * @return value
+ */
+ public V extractValue(T target);
+ }
+
+ /**
+ * @author a0709pe
+ *
+ * @param <T1>
+ * @param <T2>
+ */
+ public interface CollectionToListProcess<T1,T2> {
+ /**
+ * @param target
+ * @return ターゲット
+ */
+ public T2 extract(T1 target);
+ }
+
+ /**
+ * @author a0709pe
+ *
+ * @param <K>
+ * @param <V>
+ * @param <T>
+ */
+ public interface MapToCollectionProcess<K,V,T> {
+ /**
+ * @param key
+ * @param value
+ * @return タイプ
+ */
+ public T extract(K key, V value);
+ }
+}
--- /dev/null
+package jp.ac.aiit.xdf.utils;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import jp.ac.aiit.xdf.core.exceptions.UnexpectedBehaviorException;
+
+/**
+ * @author Shunichi Takagi
+ */
+public class Reflections {
+
+ public static Object getInstance(String className) {
+ try {
+ return Reflections.getInstance(Class.forName(className));
+ } catch (ClassNotFoundException e) {
+ throw new UnexpectedBehaviorException("specified class is not exists : " + className);
+ }
+ }
+
+ public static <T> T getInstance(Class<T> clazz) {
+ try {
+ return clazz.newInstance();
+ } catch (InstantiationException e) {
+ throw new UnexpectedBehaviorException("class instantiation failed : "+clazz.getCanonicalName(), e);
+ } catch (IllegalAccessException e) {
+ throw new UnexpectedBehaviorException("access illegal constructor : "+clazz.getCanonicalName()+"()", e);
+ }
+ }
+
+ public static Object getInstance(String className, Object ...params) {
+ try {
+ return Reflections.getInstance(Class.forName(className), params);
+ } catch (ClassNotFoundException e) {
+ throw new UnexpectedBehaviorException("specified class is not exists : " + className);
+ }
+ }
+
+ public static <T> T getInstance(Class<T> clazz, Object ...params) {
+ Class<?>[] parameterTypes = new Class[params.length];
+ for(int i=0; i<params.length; i++) {
+ parameterTypes[i] = params[i].getClass();
+ }
+
+ try {
+ Constructor<T> constructor = clazz.getConstructor(parameterTypes);
+ return constructor.newInstance(params);
+ } catch (SecurityException e) {
+ throw new UnexpectedBehaviorException("security exception", e);
+ } catch (NoSuchMethodException e) {
+ throw new UnexpectedBehaviorException("no such method exception", e);
+ } catch (InstantiationException e) {
+ throw new UnexpectedBehaviorException("class instantiation failed : "+clazz.getCanonicalName(), e);
+ } catch (IllegalAccessException e) {
+ throw new UnexpectedBehaviorException("access illegal constructor : "+clazz.getCanonicalName(), e);
+ } catch (InvocationTargetException e) {
+ throw new UnexpectedBehaviorException("invocation target exception", e);
+ }
+ }
+
+ public static Object invokeMethod(Object obj, Method method, Object ...args) {
+ try {
+ Object result = null;
+
+ if( method.isAccessible() ) {
+ result = method.invoke(obj, args);
+ } else {
+ method.setAccessible(true);
+ result = method.invoke(obj, args);
+ method.setAccessible(false);
+ }
+
+ return result;
+
+ } catch(SecurityException e) {
+ throw new UnexpectedBehaviorException(e);
+ } catch(IllegalAccessException e) {
+ throw new UnexpectedBehaviorException(e);
+ } catch(InvocationTargetException e) {
+ throw new UnexpectedBehaviorException(e);
+ }
+ }
+
+ public static Object invokeMethod(Object obj, String methodName, Object ...args) throws NoSuchMethodException, IllegalArgumentException {
+ Class<?> clazz = obj.getClass();
+
+ Class<?>[] types = new Class[args.length];
+ for(int i=0; i<args.length; i++) {
+ types[i] = args[i].getClass();
+ }
+ Method method = clazz.getMethod(methodName, types);
+
+ return Reflections.invokeMethod(obj, method, args);
+
+ }
+
+ public static Object invokeMethod(Object obj, String methodName, Class<?> types, Object ...args) throws NoSuchMethodException, IllegalArgumentException {
+ Class<?> clazz = obj.getClass();
+
+ Method method = clazz.getMethod(methodName, types);
+
+ return Reflections.invokeMethod(obj, method, args);
+
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:tns="http://xml.netbeans.org/schema/Tagdef"
+ elementFormDefault="qualified">
+ <xsd:complexType name="tagdef">
+ <xsd:sequence>
+ <xsd:element name="tag" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="modelclass" type="xsd:string"></xsd:element>
+ <xsd:element name="component-mapper" maxOccurs="unbounded" minOccurs="0">
+ <xsd:complexType>
+ <xsd:sequence/>
+ <xsd:attribute name="env" type="xsd:string"/>
+ <xsd:attribute name="class" type="xsd:string"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+</xsd:schema>
--- /dev/null
+<configuration>
+ <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>xdf-logs/xdf.log</file>
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <FileNamePattern>xdf-%d{yyyy-MM-dd}.log</FileNamePattern>
+ <MaxHistory>30</MaxHistory>
+ </rollingPolicy>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</Pattern>
+ </layout>
+ </appender>
+ <logger name="jp.ac.aiit.xdf">
+ <level value="DEBUG" />
+ </logger>
+ <root>
+ <level value="INFO" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration>
\ No newline at end of file
--- /dev/null
+<tagdef>
+ <tag name="xdf-window">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="common" class="jp.ac.aiit.xdf.component.common.mappers.DoNothingComponentMapper" />
+ </tag>
+
+ <tag name="head">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="common" class="jp.ac.aiit.xdf.component.common.mappers.DoNothingComponentMapper" />
+ </tag>
+
+ <tag name="style">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="common" class="jp.ac.aiit.xdf.component.common.mappers.DoNothingComponentMapper" />
+ </tag>
+
+ <tag name="action">
+ <modelclass>jp.ac.aiit.xdf.core.model.DefaultObjectModel</modelclass>
+ <component-mapper env="common" class="jp.ac.aiit.xdf.component.common.mappers.DoNothingComponentMapper" />
+ </tag>
+</tagdef>
\ No newline at end of file
--- /dev/null
+package jp.ac.aiit.xdf.model;
+
+import java.util.Arrays;
+import java.util.List;
+
+import jp.ac.aiit.xdf.core.model.DefaultObjectModel;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * DefaultObjectModelがインターフェース仕様を満たしていることを確認するためのテスト
+ *
+ * @author stakagi
+ */
+public class DefaultObjectModelTest {
+ private static final String ID_FOR_TEST = "id-for-test";
+
+ private DefaultObjectModel model;
+
+ @BeforeMethod
+ public void beforeTest() {
+ this.model = new DefaultObjectModel("sample");
+ }
+
+ @Test
+ public void testSetAndGetID() {
+ model.id(ID_FOR_TEST);
+ Assert.assertEquals(model.id(), ID_FOR_TEST);
+ }
+
+ @DataProvider(name="classes")
+ public Object[][] classes() {
+ return new Object[][]{
+ { new String[]{ "aaa" }, "aaa", true },
+ { new String[]{ "bbb" }, "aaa", false },
+ { new String[]{ "aaa", "bbb" }, "aaaa", false },
+ { new String[]{ "aaa", "bbb", "ccc" }, "bbb", true },
+ { new String[]{ "aaa", "bbb", "ccc" }, "ddd", false }
+ };
+ }
+
+ @Test(groups="setclass", dataProvider="classes")
+ public void testAddAndHasClass(String[] classes, String check, boolean result) {
+ for(String clazz : classes) {
+ model.addClass(clazz);
+ }
+
+ Assert.assertEquals(model.hasClass(check), result);
+ }
+
+ @Test(dataProvider="classes", dependsOnGroups="setclass")
+ public void testRemoveClass(String[] classes, String remove, boolean x) {
+ for(String clazz : classes) {
+ model.addClass(clazz);
+ }
+ model.removeClass(remove);
+
+ Assert.assertFalse(model.hasClass(remove));
+ }
+
+ @Test
+ public void testSetAndGetAttr() {
+ model.attr("test", "testvalue");
+
+ Assert.assertEquals(model.attr("test"), "testvalue");
+ }
+
+ @Test
+ public void testSetDuplicateAttr() {
+ model.attr("test", "testval1");
+ model.attr("test", "testval2");
+
+ Assert.assertEquals(model.attr("test"), "testval2");
+ }
+
+ @DataProvider(name="attrs")
+ public Object[][] attrs() {
+ return new Object[][] {
+ { new String[][] { { "attr1", "1" }, { "attr2", "2" }, { "attr3", "3" } }, new String[] { "attr1", "attr3" } }
+ };
+ }
+
+ @Test(dataProvider="attrs")
+ public void testRemoveAttr(String[][] attrs, String[] deletes) {
+ for(String[] attr : attrs) {
+ model.attr(attr[0], attr[1]);
+ }
+ for(String del : deletes) { model.removeAttr(del); }
+
+ List<String> dels = Arrays.asList(deletes);
+ for(String[] attr : attrs) {
+ Assert.assertEquals(model.attr(attr[0]), ( dels.contains(attr[0]) ? null : attr[1]) );
+ }
+ }
+
+}
--- /dev/null
+package jp.ac.aiit.xdf.style;
+
+import java.io.File;
+
+public class StyleDefTest{
+ private final static String fn
+ = "D:/workspace/xdf/trunk/xdf/src/test/resources/uidesign/styles/main3.style";
+ private final static File f = new File(fn);
+ public static void main(String[] args){
+System.out.println("stylesheet exists? -> " + f.exists());
+
+ }
+}
\ No newline at end of file
--- /dev/null
+package jp.ac.aiit.xdf.uidesign;\r
+\r
+import static org.testng.Assert.assertEquals;\r
+\r
+import java.io.File;\r
+import java.util.Map;\r
+\r
+import jp.ac.aiit.xdf.core.tags.TagLoader;\r
+import jp.ac.aiit.xdf.core.tags.Tagdef.Tag;\r
+\r
+import org.testng.Assert;\r
+import org.testng.annotations.BeforeMethod;\r
+import org.testng.annotations.Test;\r
+\r
+public class TagLoaderTest {\r
+ private TagLoader tagLoader;\r
+ \r
+ static String testFileOK1 = "trunk/xdf/src/test/resources/Tagdef/tagloader_test_OK1.xml"; \r
+ static String testFileOK2 = "trunk/xdf/src/test/resources/Tagdef/tagloader_test_OK2.xml"; \r
+ static String testFileOK3 = "trunk/xdf/src/test/resources/Tagdef/tagloader_test_OK3.xml"; \r
+ static String testFileNG1 = "trunk/xdf/src/test/resources/Tagdef/tagloader_test_NG1.xml";\r
+ \r
+ @BeforeMethod\r
+ public void init() {\r
+ tagLoader = new TagLoader();\r
+ }\r
+ \r
+ /**\r
+ * テストケース① 正常テスト(一件正常取り込み)\r
+ */\r
+ @Test\r
+ public void verifyNormalOne(){\r
+ System.out.println("テストケース①:タブ定義取り込みテスト(一件)");\r
+ try {\r
+ File file = new File(testFileOK1);\r
+ \r
+ Map<String, Tag> result = tagLoader.load(file);\r
+ \r
+ // 実行結果のチェック\r
+ assertEquals(result.get("frame").getModelclass(), "javax.swing.JFrame");\r
+ assertEquals(result.size(), 1);\r
+ } catch (Exception e){\r
+ Assert.fail();\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * テストケース② 正常テスト(重複取り込み、最初のものだけを取り込み)\r
+ * (大文字/子文字の確認を一件修正 \r
+ * タブXML定義ファイルにButton -> button) 2008/10/22\r
+ */\r
+ @Test\r
+ public void verifyNormalCancelforOverlap(){\r
+ System.out.println("テストケース②:重複取り込み、最初のものだけを取り込み");\r
+ try {\r
+ File file = new File(testFileOK2);\r
+ \r
+ Map<String, Tag> result = tagLoader.load(file);\r
+ \r
+ // 実行結果のチェック\r
+ assertEquals(result.get("frame").getModelclass(), "javax.swing.JFrame");\r
+ assertEquals(result.get("button").getModelclass(), "javax.swing.JButton");\r
+ assertEquals(result.get("label").getModelclass(), "javax.swing.JLabel");\r
+ assertEquals(result.get("textfield").getModelclass(), "javax.swing.JTextField");\r
+ assertEquals(result.get("textarea").getModelclass(), "javax.swing.JTextArea");\r
+ assertEquals(result.get("combo").getModelclass(), "javax.swing.JComboBox");\r
+ assertEquals(result.size(), 6);\r
+ } catch (Exception e){\r
+ Assert.fail();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * テストケース③ 異常テスト(クラス定義存在していない\r
+ */\r
+ @Test\r
+ public void verifyClassNotExist(){\r
+ System.out.println("テストケース③ 異常テスト(クラス定義存在していない)");\r
+ try {\r
+ File file = new File(testFileNG1);\r
+ \r
+ Map<String, Tag> result = tagLoader.load(file);\r
+ \r
+ // 実行結果のチェック\r
+ assertEquals(result.size(), 0);\r
+ } catch (Exception e){\r
+ Assert.fail();\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * テストケース④ 正常テスト(タグ定義XML、コンポーネントマッピング機能\r
+ */\r
+ @Test\r
+ public void verifyNormalforMapping(){\r
+ System.out.println("テストケース④ 正常テスト(タグ定義XML、コンポーネントマッピング機能)");\r
+ try {\r
+ File file = new File(testFileOK3);\r
+ \r
+ Map<String, Tag> result = tagLoader.load(file);\r
+ \r
+ // 実行結果のチェック\r
+ assertEquals(result.size(), 1);\r
+ assertEquals(result.get("frame").getModelclass(), "jp.ac.aiit.xdf.model.DefaultObjectModel");\r
+ assertEquals(result.get("frame").getComponentMapper().get(0).getEnv(), "swing");\r
+ assertEquals(result.get("frame").getComponentMapper().get(0).getClazz(), "jp.ac.aiit.xdf.component.swing.JFrameMapper");\r
+\r
+ } catch (Exception e){\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ \r
+// @Test\r
+// public void verifyComponentMapperExists() {\r
+// File file = new File(FILE_EXISTS_COMPONENTMAPPER);\r
+// \r
+// Map<String, Tag> result = tagLoader.load(file);\r
+// assertEquals(result.size(), 1);\r
+// \r
+// Tag tag = result.get("frame");\r
+// assertNotNull(tag);\r
+// assertEquals(tag.getName(), "frame");\r
+// assertEquals(tag.getModelClass(), "jp.ac.aiit.xdf.model.DefaultObjectModel");\r
+// \r
+// Map<String, ComponentMapper> mappers = tag.getComponentMappers();\r
+// assertTrue(mappers.containsKey("swing"));\r
+// assertEquals(mappers.get("swing"), "jp.ac.aiit.xdf.modelmapper.swing.JFrameMapper");\r
+// }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<tagdef>
+ <tag name="frame">
+ <modelclass>javax.swing.JFrame.secccc</modelclass>
+ </tag>
+</tagdef>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<tagdef>
+ <tag name="frame">
+ <modelclass>javax.swing.JFrame</modelclass>
+ </tag>
+</tagdef>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<tagdef>
+ <tag name="frame">
+ <modelclass>javax.swing.JFrame</modelclass>
+ </tag>
+ <tag name="Button">
+ <modelclass>javax.swing.JButton</modelclass>
+ </tag>
+ <tag name="label">
+ <modelclass>javax.swing.JLabel</modelclass>
+ </tag>
+ <tag name="textfield">
+ <modelclass>javax.swing.JTextField</modelclass>
+ </tag>
+ <tag name="textarea">
+ <modelclass>javax.swing.JTextArea</modelclass>
+ </tag>
+ <tag name="combo">
+ <modelclass>javax.swing.JComboBox</modelclass>
+ </tag>
+ <tag name="frame">
+ <modelclass>javax.swing.JPanel</modelclass>
+ </tag>
+</tagdef>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<tagdef>
+ <tag name="frame">
+ <modelclass>jp.ac.aiit.xdf.model.DefaultObjectModel</modelclass>
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.component.swing.JFrameMapper"/>
+ </tag>
+</tagdef>
\ No newline at end of file
--- /dev/null
+<tagdef>
+ <tag name="frame">
+ <modelclass>jp.ac.aiit.xdf.model.DefaultObjectModel</modelclass>
+
+ <component-mapper env="swing" class="jp.ac.aiit.xdf.modelmapper.swing.JFrameMapper" />
+ </tag>
+</tagdef>
\ No newline at end of file
--- /dev/null
+<xdf-window>
+ <head>
+ <style src="simple-uidesign.style" />
+ </head>
+ <frame size="500,200" layout="border">
+ <group id="form" layoutArg="center" layout="border">
+ <group id="name" tooltip="名前を入力してください" layoutArg="north">
+ <label text="名前" />
+ <textfield value="高木俊一" />
+ </group>
+ <group id="age" tooltip="年齢を入力してください" layoutArg="center">
+ <label text="年齢" />
+ <textfield value="24" />
+ </group>
+ <group id="sex" tooltip="性別を入力してください" layoutArg="south">
+ <label text="性別" />
+ <textfield value="男" />
+ </group>
+ </group>
+
+ <button text="決定" layoutArg="south" />
+ </frame>
+</xdf-window>
\ No newline at end of file
--- /dev/null
+<frame size="500,200" layout="border">
+ <group id="form" layoutArg="center" layout="border">
+ <group id="name" tooltip="名前を入力してください" layoutArg="north">
+ <label text="名前" />
+ <textfield value="高木俊一" />
+ </group>
+ <group id="age" tooltip="年齢を入力してください" layoutArg="center">
+ <label text="年齢" />
+ <textfield value="24" />
+ </group>
+ <group id="sex" tooltip="性別を入力してください" layoutArg="south">
+ <label text="性別" />
+ <textfield value="男" />
+ </group>
+ </group>
+
+ <button text="決定" layoutArg="south" />
+</frame>
\ No newline at end of file