[openrtm-commit:00763] r282 - in trunk/rtmtools/jp.go.aist.rtm.systemeditor: . src/jp/go/aist/rtm/systemeditor/manager src/jp/go/aist/rtm/systemeditor/nl src/jp/go/aist/rtm/systemeditor/ui/dialog src/jp/go/aist/rtm/systemeditor/ui/editor/editpart src/jp/go/aist/rtm/systemeditor/ui/preference test/jp/go/aist/rtm/systemeditor test/jp/go/aist/rtm/systemeditor/manager

openrtm @ openrtm.org openrtm @ openrtm.org
2012年 3月 13日 (火) 00:06:20 JST


Author: sakamoto
Date: 2012-03-13 00:06:20 +0900 (Tue, 13 Mar 2012)
New Revision: 282

Added:
   trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/manager/ComponentIconStore.java
   trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/dialog/IconPreferenceDialog.java
   trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/preference/IconPreferencePage.java
   trunk/rtmtools/jp.go.aist.rtm.systemeditor/test/jp/go/aist/rtm/systemeditor/manager/
   trunk/rtmtools/jp.go.aist.rtm.systemeditor/test/jp/go/aist/rtm/systemeditor/manager/ComponentIconStoreTest.java
Modified:
   trunk/rtmtools/jp.go.aist.rtm.systemeditor/plugin.properties
   trunk/rtmtools/jp.go.aist.rtm.systemeditor/plugin.xml
   trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/manager/SystemEditorPreferenceManager.java
   trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/nl/messages.properties
   trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/editor/editpart/ComponentEditPart.java
Log:
Modification of the RTC inside icon indication #2293

Modified: trunk/rtmtools/jp.go.aist.rtm.systemeditor/plugin.properties
===================================================================
--- trunk/rtmtools/jp.go.aist.rtm.systemeditor/plugin.properties	2012-03-12 15:06:02 UTC (rev 281)
+++ trunk/rtmtools/jp.go.aist.rtm.systemeditor/plugin.properties	2012-03-12 15:06:20 UTC (rev 282)
@@ -38,6 +38,7 @@
 # preferencePages
 Connection =Connection 
 DisplayColor =Display Color 
+IconPreference.name =Icon
 OfflineEditor =Offline Editor 
 OnlineEditor =Online Editor 
 

Modified: trunk/rtmtools/jp.go.aist.rtm.systemeditor/plugin.xml
===================================================================
--- trunk/rtmtools/jp.go.aist.rtm.systemeditor/plugin.xml	2012-03-12 15:06:02 UTC (rev 281)
+++ trunk/rtmtools/jp.go.aist.rtm.systemeditor/plugin.xml	2012-03-12 15:06:20 UTC (rev 282)
@@ -527,6 +527,12 @@
 			category="jp.go.aist.rtm.systemeditor.ui.preference.MainPreferencePage">
 		</page>
 		<page
+			id="jp.go.aist.rtm.systemeditor.ui.preference.IconPreferencePage"
+			class="jp.go.aist.rtm.systemeditor.ui.preference.IconPreferencePage"
+			name="%IconPreference.name"
+			category="jp.go.aist.rtm.systemeditor.ui.preference.MainPreferencePage">
+		</page>
+		<page
 			id="jp.go.aist.rtm.systemeditor.ui.preference.OfflineEditorPreferencePage"
 			class="jp.go.aist.rtm.systemeditor.ui.preference.OfflineEditorPreferencePage"
 			name="%OfflineEditor"

Added: trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/manager/ComponentIconStore.java
===================================================================
--- trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/manager/ComponentIconStore.java	                        (rev 0)
+++ trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/manager/ComponentIconStore.java	2012-03-12 15:06:20 UTC (rev 282)
@@ -0,0 +1,430 @@
+package jp.go.aist.rtm.systemeditor.manager;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.URI;
+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 javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import jp.go.aist.rtm.toolscommon.model.component.Component;
+
+public class ComponentIconStore {
+
+	public static ComponentIconStore eINSTANCE;
+
+	static {
+		eINSTANCE = new ComponentIconStore();
+		SystemEditorPreferenceManager.getInstance().loadComponentIconStore(
+				eINSTANCE);
+	}
+
+	Map<String, ImageDescriptor> path2DescripterMap;
+	Map<String, String> type2PathMap;
+	Map<String, String> category2PathMap;
+
+	ComponentIconStore() {
+		path2DescripterMap = new HashMap<String, ImageDescriptor>();
+		type2PathMap = new HashMap<String, String>();
+		category2PathMap = new HashMap<String, String>();
+	}
+
+	/** コンポーネントタイプに対するアイコンパスを登録 */
+	public void registTypeImage(String type, String path) {
+		if (type == null || type.isEmpty()) {
+			return;
+		}
+		File file = new File(path);
+		if (!file.exists()) {
+			return;
+		}
+		String absPath = file.getAbsolutePath();
+		if (path2DescripterMap.get(absPath) == null) {
+			ImageDescriptor desc = createDescriptorByFile(file);
+			if (desc == null) {
+				return;
+			}
+			path2DescripterMap.put(absPath, desc);
+		}
+		type2PathMap.put(type, absPath);
+	}
+
+	/** コンポーネントカテゴリに対するアイコンパスを登録 */
+	public void registCategoryImage(String category, String path) {
+		if (category == null || category.isEmpty()) {
+			return;
+		}
+		File file = new File(path);
+		if (!file.exists()) {
+			return;
+		}
+		String absPath = file.getAbsolutePath();
+		if (path2DescripterMap.get(absPath) == null) {
+			ImageDescriptor desc = createDescriptorByFile(file);
+			if (desc == null) {
+				return;
+			}
+			path2DescripterMap.put(absPath, desc);
+		}
+		category2PathMap.put(category, absPath);
+	}
+
+	ImageDescriptor createDescriptorByFile(File file) {
+		try {
+			URL url = file.toURI().toURL();
+			return ImageDescriptor.createFromURL(url);
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	/** コンポーネントに対するアイコンを検索 */
+	public Image findImageByComp(Component comp) {
+		String type = comp.getTypeNameL();
+		String category = comp.getCategoryL();
+		String path = null;
+		for (String p : type2PathMap.keySet()) {
+			if (type != null && type.indexOf(p) != -1) {
+				path = type2PathMap.get(p);
+				break;
+			}
+		}
+		if (path != null) {
+			ImageDescriptor desc = path2DescripterMap.get(path);
+			return (desc == null) ? null : desc.createImage();
+		}
+		for (String p : category2PathMap.keySet()) {
+			if (category != null && category.indexOf(p) != -1) {
+				path = category2PathMap.get(p);
+				break;
+			}
+		}
+		if (path != null) {
+			ImageDescriptor desc = path2DescripterMap.get(path);
+			return (desc == null) ? null : desc.createImage();
+		}
+		return null;
+	}
+
+	/** アイコン設定リストとして取得 */
+	public List<Entry> toEntries() {
+		List<Entry> result = new ArrayList<Entry>();
+		for (String p : type2PathMap.keySet()) {
+			String path = type2PathMap.get(p);
+			ImageDescriptor desc = path2DescripterMap.get(path);
+			if (path == null || desc == null) {
+				continue;
+			}
+			Entry e = Entry.createType(p, path, desc);
+			result.add(e);
+		}
+		for (String p : category2PathMap.keySet()) {
+			String path = category2PathMap.get(p);
+			ImageDescriptor desc = path2DescripterMap.get(path);
+			if (path == null || desc == null) {
+				continue;
+			}
+			Entry e = Entry.createCategory(p, path, desc);
+			result.add(e);
+		}
+		return result;
+	}
+
+	/** アイコン設定リストから変換 */
+	public static ComponentIconStore getByEntries(List<Entry> entries) {
+		ComponentIconStore result = new ComponentIconStore();
+		for (ComponentIconStore.Entry entry : entries) {
+			if (entry.isType()) {
+				String type = entry.getType();
+				result.registTypeImage(type, entry.getPath());
+			} else {
+				String category = entry.getCategory();
+				result.registCategoryImage(category, entry.getPath());
+			}
+		}
+		return result;
+	}
+
+	/** アイコン設定リストをクリア */
+	public void clearAllImages() {
+		type2PathMap.clear();
+		category2PathMap.clear();
+		path2DescripterMap.clear();
+	}
+
+	/** アイコン設定をプロファイル(XML)へ保存 */
+	public void saveProfile(String fileName) throws Exception {
+		IconProfileHandler handler = new IconProfileHandler();
+		String xml = handler.save(this);
+		IPath path = new Path(fileName);
+		if (!path.toFile().exists()) {
+			path.toFile().createNewFile();
+		}
+		String xmlSplit[] = xml.split("\n");
+		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
+				new FileOutputStream(path.toOSString()), "UTF-8"));
+		for (String s : xmlSplit) {
+			writer.write(s);
+			writer.newLine();
+		}
+		writer.close();
+	}
+
+	/** アイコン設定をプロファイル(XML)から読込 */
+	public static ComponentIconStore loadProfile(String fileName)
+			throws Exception {
+		IPath path = new Path(fileName);
+		if (!path.toFile().exists()) {
+			return null;
+		}
+		BufferedReader reader = new BufferedReader(new InputStreamReader(
+				new FileInputStream(path.toOSString()), "UTF-8"));
+		String xmlString = "";
+		while (true) {
+			String s = reader.readLine();
+			if (s == null) {
+				break;
+			}
+			xmlString += s;
+		}
+		IconProfileHandler handler = new IconProfileHandler();
+		ComponentIconStore result = handler.parse(xmlString);
+		return result;
+	}
+
+	public void parsePreference(String pref) {
+		if (pref == null || pref.isEmpty()) {
+			return;
+		}
+		for (String s : pref.split("\\|")) {
+			if (s == null || s.isEmpty()) {
+				continue;
+			}
+			String[] ss = s.split(";");
+			if (ss.length != 3) {
+				continue;
+			}
+			if (Entry.KIND_TYPE.equals(ss[0])) {
+				registTypeImage(ss[1], ss[2]);
+			} else if (Entry.KIND_CATEGORY.equals(ss[0])) {
+				registCategoryImage(ss[1], ss[2]);
+			}
+		}
+	}
+
+	public String toPreference() {
+		String result = "";
+		for (String s : type2PathMap.keySet()) {
+			if (!result.isEmpty()) {
+				result += "|";
+			}
+			result += Entry.KIND_TYPE + ";" + s + ";" + type2PathMap.get(s);
+		}
+		for (String s : category2PathMap.keySet()) {
+			if (!result.isEmpty()) {
+				result += "|";
+			}
+			result += Entry.KIND_CATEGORY + ";" + s + ";"
+					+ category2PathMap.get(s);
+		}
+		return result;
+	}
+
+	/** アイコン設定のエントリを表す */
+	public static class Entry {
+		public static final String KIND_TYPE = "type";
+		public static final String KIND_CATEGORY = "category";
+		public static List<String> KINDS;
+
+		static {
+			KINDS = new ArrayList<String>();
+			KINDS.add(KIND_TYPE);
+			KINDS.add(KIND_CATEGORY);
+		}
+
+		String type;
+		String category;
+		String path;
+		ImageDescriptor desc;
+
+		public static Entry createType(String type, String path,
+				ImageDescriptor desc) {
+			Entry entry = new Entry();
+			entry.type = type;
+			entry.path = path;
+			entry.desc = desc;
+			return entry;
+		}
+
+		public static Entry createCategory(String category, String path,
+				ImageDescriptor desc) {
+			Entry entry = new Entry();
+			entry.category = category;
+			entry.path = path;
+			entry.desc = desc;
+			return entry;
+		}
+
+		Entry() {
+		}
+
+		public void setType(String type) {
+			this.type = type;
+			this.category = null;
+		}
+
+		public void setCategory(String category) {
+			this.type = null;
+			this.category = category;
+		}
+
+		public void setPath(String path) {
+			this.path = path;
+		}
+
+		public void setImageDescriptor(ImageDescriptor desc) {
+			this.desc = desc;
+		}
+
+		public String getKind() {
+			return (isType()) ? KIND_TYPE : KIND_CATEGORY;
+		}
+
+		public String getType() {
+			return type;
+		}
+
+		public String getCategory() {
+			return category;
+		}
+
+		public boolean isType() {
+			return type != null;
+		}
+
+		public boolean isCategory() {
+			return category != null;
+		}
+
+		public String getPath() {
+			return path;
+		}
+
+		public ImageDescriptor getImageDescriptor() {
+			return desc;
+		}
+	}
+
+	/** アイコン設定プロファイルの読み書きを実施 */
+	public static class IconProfileHandler {
+
+		/** アイコン設定(XML)の読込 */
+		public ComponentIconStore parse(String xmlString) throws Exception {
+			ComponentIconStore result = new ComponentIconStore();
+			DocumentBuilderFactory factory = DocumentBuilderFactory
+					.newInstance();
+			DocumentBuilder builder = factory.newDocumentBuilder();
+			InputStream in = new ByteArrayInputStream(xmlString.getBytes());
+			Document dc = builder.parse(in);
+			NodeList prefs = dc.getElementsByTagName("iconPreference");
+			Node attr = null;
+			for (int i = 0; i < prefs.getLength(); i++) {
+				Node n = prefs.item(i);
+				for (Node img : findByName(n.getChildNodes(), "image")) {
+					attr = img.getAttributes().getNamedItem("path");
+					if (attr == null) {
+						continue;
+					}
+					// 画像ファイルをURI形式、もしくはパスから読込
+					String pathUri = attr.getTextContent();
+					String path = null;
+					try {
+						URI uri = new URI(pathUri);
+						path = uri.getPath();
+					} catch (URISyntaxException e) {
+						File f = new File(pathUri);
+						path = f.getAbsolutePath();
+					}
+					for (Node pat : findByName(img.getChildNodes(), "pattern")) {
+						attr = pat.getAttributes().getNamedItem("kind");
+						if (attr == null) {
+							continue;
+						}
+						String kind = attr.getTextContent();
+						String pattern = pat.getTextContent();
+						//
+						if (kind != null && kind.equals("type")) {
+							result.registTypeImage(pattern, path);
+						} else if (kind != null && kind.equals("category")) {
+							result.registCategoryImage(pattern, path);
+						}
+					}
+				}
+			}
+			return result;
+		}
+
+		/** アイコン設定(XML)の保存 */
+		public String save(ComponentIconStore store) {
+			String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+			result += "<iconPreference>\n";
+			for (String path : store.path2DescripterMap.keySet()) {
+				File f = new File(path);
+				// 画像ファイルをURI形式で保存
+				result += "  <image path=\"" + f.toURI() + "\">\n";
+				for (String key : store.type2PathMap.keySet()) {
+					String value = store.type2PathMap.get(key);
+					if (value == null || !value.equals(path)) {
+						continue;
+					}
+					result += "    <pattern kind=\"type\">";
+					result += key + "</pattern>\n";
+				}
+				for (String key : store.category2PathMap.keySet()) {
+					String value = store.category2PathMap.get(key);
+					if (value == null || !value.equals(path)) {
+						continue;
+					}
+					result += "    <pattern kind=\"category\">";
+					result += key + "</pattern>\n";
+				}
+				result += "  </image>\n";
+			}
+			result += "</iconPreference>";
+			return result;
+		}
+
+		List<Node> findByName(NodeList list, String name) {
+			List<Node> result = new ArrayList<Node>();
+			for (int i = 0; i < list.getLength(); i++) {
+				Node n = list.item(i);
+				if (n.getNodeName().equals(name)) {
+					result.add(n);
+				}
+			}
+			return result;
+		}
+	}
+
+}

Modified: trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/manager/SystemEditorPreferenceManager.java
===================================================================
--- trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/manager/SystemEditorPreferenceManager.java	2012-03-12 15:06:02 UTC (rev 281)
+++ trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/manager/SystemEditorPreferenceManager.java	2012-03-12 15:06:20 UTC (rev 282)
@@ -161,6 +161,12 @@
 			.getName()
 			+ ".CONFIRM_COMPONENT_ACTION";
 
+	// アイコン
+	/** コンポーネントアイコン設定 */
+	public static final String COMPONENT_ICONS = SystemEditorPreferenceManager.class
+			.getName()
+			+ ".COMPONENT_ICONS";
+
 	/**
 	 * デフォルトの色を管理するマップ
 	 */
@@ -543,4 +549,40 @@
 		}
 		return result;
 	}
+
+	/** コンポーネントアイコンの設定を読込 */
+	public ComponentIconStore loadComponentIconStore(
+			ComponentIconStore iconStore) {
+		if (iconStore == null) {
+			return null;
+		}
+		store.setDefault(COMPONENT_ICONS, "");
+		String value = store.getString(COMPONENT_ICONS);
+		iconStore.parsePreference(value);
+		return iconStore;
+
+	}
+
+	public ComponentIconStore loadComponentIconStore() {
+		return loadComponentIconStore(ComponentIconStore.eINSTANCE);
+	}
+
+	/** コンポーネントアイコンの設定を保存 */
+	public void saveComponentIconStore(ComponentIconStore iconStore) {
+		if (iconStore == null) {
+			return;
+		}
+		String value = iconStore.toPreference();
+		store.setValue(COMPONENT_ICONS, value);
+	}
+
+	public void saveComponentIconStore() {
+		saveComponentIconStore(ComponentIconStore.eINSTANCE);
+	}
+
+	/** コンポーネントアイコンの設定をリセット */
+	public void resetComponentIconStore() {
+		store.setValue(COMPONENT_ICONS, "");
+	}
+
 }

Modified: trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/nl/messages.properties
===================================================================
--- trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/nl/messages.properties	2012-03-12 15:06:02 UTC (rev 281)
+++ trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/nl/messages.properties	2012-03-12 15:06:20 UTC (rev 282)
@@ -2,6 +2,10 @@
 Common.dialog.error_title=Error
 Common.button.add=Add
 Common.button.delete=Delete
+Common.button.edit=Edit
+Common.button.import=Import
+Common.button.export=Export
+Common.button.browse=Browse..
 
 Restoration.0=Failed to restore RTC configuration:[
 Restoration.4=Failed to Activate RTC. [
@@ -336,3 +340,9 @@
 ConnectPortActionDelegate.error.2=Disconnect failure. [{0}]
 DisconnectDialog.title=Disconnect Profile
 DisconnectDialog.explain=Select the connection for disconnect, apply with OK.
+IconPreferenceDialog.title=Icon Preference
+IconPreferenceDialog.label.pattern=Pattern: 
+IconPreferenceDialog.label.path=Icon path: 
+IconPreferenceDialog.filter.name=Icon image
+IconPreferencePage.error.import=Icon profile import failure.
+IconPreferencePage.error.export=Icon profile export failure.

Added: trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/dialog/IconPreferenceDialog.java
===================================================================
--- trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/dialog/IconPreferenceDialog.java	                        (rev 0)
+++ trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/dialog/IconPreferenceDialog.java	2012-03-12 15:06:20 UTC (rev 282)
@@ -0,0 +1,273 @@
+package jp.go.aist.rtm.systemeditor.ui.dialog;
+
+import java.io.File;
+import java.net.URL;
+import java.util.List;
+
+import jp.go.aist.rtm.systemeditor.manager.ComponentIconStore;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import static jp.go.aist.rtm.systemeditor.nl.Messages.*;
+
+public class IconPreferenceDialog extends TitleAreaDialog {
+
+	static final int EXEC_BUTTON_WIDTH = 70;
+
+	static final String DIALOG_TITLE = getString("IconPreferenceDialog.title");
+
+	static final String LABEL_PATTERN = getString("IconPreferenceDialog.label.pattern");
+	static final String LABEL_ICON_PATH = getString("IconPreferenceDialog.label.path");
+
+	static final String BUTTON_LABEL_BROWSE = getString("Common.button.browse");
+
+	static final String ICON_EXTENSION = "*.ico; *.bmp; *.png; *.gif";
+	static final String FILTER_EXTENSIONS[] = new String[] { ICON_EXTENSION };
+	static final String FILTER_NAMES[] = new String[] { getString("IconPreferenceDialog.filter.name")
+			+ " (" + ICON_EXTENSION + ")" };
+
+	Combo kindCombo;
+	Text patternText;
+	Text pathText;
+	Button browseButton;
+	Label imageLabel;
+
+	boolean isType = true;
+	String pattern = "";
+	String path = "";
+	ImageDescriptor desc;
+	ComponentIconStore.Entry iconEntry;
+
+	public IconPreferenceDialog(Shell parentShell) {
+		super(parentShell);
+		setHelpAvailable(false);
+		setShellStyle(getShellStyle() | SWT.CENTER | SWT.RESIZE);
+	}
+
+	public void setIconEntry(ComponentIconStore.Entry iconEntry) {
+		this.iconEntry = iconEntry;
+	}
+
+	public ComponentIconStore.Entry getIconEntry() {
+		return iconEntry;
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		GridLayout gl;
+		GridData gd;
+
+		Composite mainComposite = new Composite((Composite) super
+				.createDialogArea(parent), SWT.NONE);
+		gl = new GridLayout(4, false);
+		gd = new GridData(GridData.FILL_BOTH);
+		mainComposite.setLayout(gl);
+		mainComposite.setLayoutData(gd);
+		mainComposite.setFont(parent.getFont());
+
+		Label label = new Label(mainComposite, SWT.NONE);
+		label.setText(LABEL_PATTERN);
+		gd = new GridData();
+		label.setLayoutData(gd);
+
+		kindCombo = new Combo(mainComposite, SWT.READ_ONLY);
+		gd = new GridData();
+		kindCombo.setLayoutData(gd);
+		List<String> kinds = ComponentIconStore.Entry.KINDS;
+		kindCombo.setItems(kinds.toArray(new String[0]));
+		kindCombo.addModifyListener(new ModifyListener() {
+			@Override
+			public void modifyText(ModifyEvent e) {
+				isType = ComponentIconStore.Entry.KIND_TYPE.equals(kindCombo
+						.getText());
+				notifyModified();
+			}
+		});
+
+		patternText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER);
+		gd = new GridData();
+		gd.horizontalSpan = 2;
+		gd.horizontalAlignment = GridData.FILL;
+		gd.grabExcessHorizontalSpace = true;
+		patternText.setLayoutData(gd);
+		patternText.addModifyListener(new ModifyListener() {
+			@Override
+			public void modifyText(ModifyEvent e) {
+				pattern = (patternText.getText() == null) ? "" : patternText
+						.getText();
+				notifyModified();
+			}
+		});
+
+		label = new Label(mainComposite, SWT.NONE);
+		label.setText(LABEL_ICON_PATH);
+		gd = new GridData();
+		label.setLayoutData(gd);
+
+		pathText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER);
+		gd = new GridData();
+		gd.horizontalSpan = 2;
+		gd.horizontalAlignment = GridData.FILL;
+		gd.grabExcessHorizontalSpace = true;
+		pathText.setLayoutData(gd);
+		pathText.setEditable(false);
+		pathText.addFocusListener(new FocusListener() {
+			@Override
+			public void focusGained(FocusEvent e) {
+			}
+
+			@Override
+			public void focusLost(FocusEvent e) {
+				imageLabel.setBackgroundImage(null);
+				if (pathText.getText() == null) {
+					path = "";
+					desc = null;
+					notifyModified();
+					return;
+				}
+				try {
+					path = pathText.getText();
+					File file = new File(path);
+					path = file.getAbsolutePath();
+					URL url = file.toURI().toURL();
+					desc = ImageDescriptor.createFromURL(url);
+					if (desc != null) {
+						imageLabel.setImage(desc.createImage());
+					}
+				} catch (Exception exp) {
+					path = "";
+					desc = null;
+				}
+				notifyModified();
+			}
+		});
+
+		browseButton = new Button(mainComposite, SWT.NONE);
+		browseButton.setText(BUTTON_LABEL_BROWSE);
+		gd = new GridData();
+		gd.widthHint = EXEC_BUTTON_WIDTH;
+		browseButton.setLayoutData(gd);
+		browseButton.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				FileDialog dialog = new FileDialog(getShell());
+				dialog.setFilterExtensions(FILTER_EXTENSIONS);
+				dialog.setFilterNames(FILTER_NAMES);
+				if (path != null && !path.isEmpty()) {
+					dialog.setFileName(path);
+				}
+				String s = dialog.open();
+				if (s != null) {
+					pathText.setFocus();
+					pathText.setText(s);
+					browseButton.setFocus();
+				}
+			}
+		});
+
+		label = new Label(mainComposite, SWT.NONE);
+
+		imageLabel = new Label(mainComposite, SWT.BORDER);
+		gd = new GridData();
+		gd.horizontalSpan = 3;
+		gd.heightHint = 64;
+		gd.widthHint = 64;
+		imageLabel.setLayoutData(gd);
+
+		buildData();
+
+		return mainComposite;
+	}
+
+	@Override
+	protected Control createButtonBar(Composite parent) {
+		Control composite = super.createButtonBar(parent);
+		notifyModified();
+		return composite;
+	}
+
+	@Override
+	protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+		shell.setText(DIALOG_TITLE);
+	}
+
+	/** 表示内容を構築 */
+	void buildData() {
+		List<String> kinds = ComponentIconStore.Entry.KINDS;
+		if (iconEntry != null) {
+			int index = kinds.indexOf(iconEntry.getKind());
+			if (index != -1) {
+				kindCombo.select(index);
+			}
+			if (iconEntry.isType() && iconEntry.getType() != null) {
+				patternText.setText(iconEntry.getType());
+			} else if (iconEntry.isCategory()
+					&& iconEntry.getCategory() != null) {
+				patternText.setText(iconEntry.getCategory());
+			}
+			if (iconEntry.getPath() != null) {
+				path = iconEntry.getPath();
+				pathText.setText(path);
+			}
+			if (iconEntry.getImageDescriptor() != null) {
+				desc = iconEntry.getImageDescriptor();
+				imageLabel.setImage(desc.createImage());
+			}
+		}
+	}
+
+	/** 変更を通知します */
+	void notifyModified() {
+		Button okButton = getButton(IDialogConstants.OK_ID);
+		if (okButton != null) {
+			okButton.setEnabled(false);
+			if (kindCombo.getText() != null && !kindCombo.getText().isEmpty()
+					&& !pattern.isEmpty() && !path.isEmpty() && desc != null) {
+				okButton.setEnabled(true);
+			}
+		}
+	}
+
+	@Override
+	protected void okPressed() {
+		if (iconEntry != null) {
+			if (isType) {
+				iconEntry.setType(pattern);
+			} else {
+				iconEntry.setCategory(pattern);
+			}
+			iconEntry.setPath(path);
+			iconEntry.setImageDescriptor(desc);
+		} else {
+			if (isType) {
+				iconEntry = ComponentIconStore.Entry.createType(pattern, path,
+						desc);
+			} else {
+				iconEntry = ComponentIconStore.Entry.createCategory(pattern,
+						path, desc);
+			}
+		}
+		super.okPressed();
+	}
+
+}

Modified: trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/editor/editpart/ComponentEditPart.java
===================================================================
--- trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/editor/editpart/ComponentEditPart.java	2012-03-12 15:06:02 UTC (rev 281)
+++ trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/editor/editpart/ComponentEditPart.java	2012-03-12 15:06:20 UTC (rev 282)
@@ -11,6 +11,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import jp.go.aist.rtm.systemeditor.manager.ComponentIconStore;
 import jp.go.aist.rtm.systemeditor.manager.SystemEditorPreferenceManager;
 import jp.go.aist.rtm.systemeditor.ui.action.OpenCompositeComponentAction;
 import jp.go.aist.rtm.systemeditor.ui.editor.AbstractSystemDiagramEditor;
@@ -52,6 +53,7 @@
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.viewers.TextCellEditor;
 import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
 import org.eclipse.ui.PlatformUI;
 
 /**
@@ -68,6 +70,9 @@
 	/** コンポーネントの周りとコンポーネントのボディまでのスペース(ポートなし) */
 	public static final int NONE_SPACE = 7;
 
+	/** コンポーネントアイコンのサイズ */
+	public static final int ICON_SIZE = 16;
+
 	private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(
 			this);
 
@@ -75,6 +80,8 @@
 
 	NameDirectEditManager directManager = null;
 
+	Image iconImage;
+
 	/**
 	 * コンストラクタ
 	 * 
@@ -87,6 +94,8 @@
 
 	@Override
 	protected IFigure createFigure() {
+		iconImage = ComponentIconStore.eINSTANCE.findImageByComp(getModel());
+
 		Figure result = new Panel() {
 
 			@Override
@@ -112,6 +121,17 @@
 					Color saveForegroundColor = graphics.getForegroundColor();
 					graphics.drawRectangle(bound);
 					graphics.setForegroundColor(saveForegroundColor);
+
+					if (iconImage != null) {
+						org.eclipse.swt.graphics.Rectangle ir = iconImage
+								.getBounds();
+						Rectangle sr = new Rectangle(ir.x, ir.y, ir.width,
+								ir.height);
+						Rectangle dr = new Rectangle(bound.getCenter().x
+								- ICON_SIZE / 2, bound.getCenter().y
+								- ICON_SIZE / 2, ICON_SIZE, ICON_SIZE);
+						graphics.drawImage(iconImage, sr, dr);
+					}
 				}
 			}
 

Added: trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/preference/IconPreferencePage.java
===================================================================
--- trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/preference/IconPreferencePage.java	                        (rev 0)
+++ trunk/rtmtools/jp.go.aist.rtm.systemeditor/src/jp/go/aist/rtm/systemeditor/ui/preference/IconPreferencePage.java	2012-03-12 15:06:20 UTC (rev 282)
@@ -0,0 +1,334 @@
+package jp.go.aist.rtm.systemeditor.ui.preference;
+
+import static jp.go.aist.rtm.systemeditor.nl.Messages.getString;
+
+import java.io.File;
+import java.util.List;
+
+import jp.go.aist.rtm.systemeditor.manager.ComponentIconStore;
+import jp.go.aist.rtm.systemeditor.manager.SystemEditorPreferenceManager;
+import jp.go.aist.rtm.systemeditor.ui.dialog.IconPreferenceDialog;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ITableColorProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+public class IconPreferencePage extends PreferencePage implements
+		IWorkbenchPreferencePage {
+
+	static final int EXEC_BUTTON_WIDTH = 90;
+
+	static final String ERROR_IMPORT_PROFILE = getString("IconPreferencePage.error.import");
+	static final String ERROR_EXPORT_PROFILE = getString("IconPreferencePage.error.export");
+
+	static final String BUTTON_LABEL_ADD = getString("Common.button.add");
+	static final String BUTTON_LABEL_EDIT = getString("Common.button.edit");
+	static final String BUTTON_LABEL_DELETE = getString("Common.button.delete");
+	static final String BUTTON_LABEL_IMPORT = getString("Common.button.import");
+	static final String BUTTON_LABEL_EXPORT = getString("Common.button.export");
+
+	static final int PROPERTY_IMAGE = 0;
+	static final int PROPERTY_PATTERN = 1;
+	static final int PROPERTY_KIND = 2;
+	static final int PROPERTY_PATH = 3;
+
+	TableViewer iconTableViewer;
+
+	Button addButton;
+	Button editButton;
+	Button deleteButton;
+	Button importButton;
+	Button exportButton;
+
+	SystemEditorPreferenceManager manager;
+
+	List<ComponentIconStore.Entry> entryList;
+	ComponentIconStore.Entry selectedEntry;
+
+	@Override
+	protected Control createContents(Composite parent) {
+
+		manager = SystemEditorPreferenceManager.getInstance();
+
+		GridLayout gl;
+		GridData gd;
+
+		Composite composite = new Composite(parent, SWT.NULL);
+		composite.setLayout(new GridLayout(2, false));
+
+		iconTableViewer = new TableViewer(composite, SWT.FULL_SELECTION
+				| SWT.SINGLE | SWT.BORDER);
+		iconTableViewer.setContentProvider(new ArrayContentProvider());
+
+		Table table = iconTableViewer.getTable();
+		table.setLinesVisible(true);
+		table.setHeaderVisible(true);
+		gd = new GridData();
+		gd.verticalAlignment = SWT.FILL;
+		gd.horizontalAlignment = SWT.FILL;
+		gd.grabExcessVerticalSpace = true;
+		gd.grabExcessHorizontalSpace = true;
+		table.setLayoutData(gd);
+
+		createColumn(iconTableViewer, "icon", 64);
+		createColumn(iconTableViewer, "pattern", 90);
+		createColumn(iconTableViewer, "kind", 70);
+		createColumn(iconTableViewer, "path", 200);
+
+		iconTableViewer.setLabelProvider(new IconLabelProvider());
+		iconTableViewer
+				.addSelectionChangedListener(new ISelectionChangedListener() {
+					@Override
+					public void selectionChanged(SelectionChangedEvent event) {
+						StructuredSelection selection = (StructuredSelection) event
+								.getSelection();
+						selectedEntry = (ComponentIconStore.Entry) selection
+								.getFirstElement();
+						notifyModified();
+					}
+				});
+
+		Composite buttonComposite = new Composite(composite, SWT.NONE);
+		gl = new GridLayout(1, false);
+		gd = new GridData();
+		gd.verticalAlignment = SWT.TOP;
+		buttonComposite.setLayout(gl);
+		buttonComposite.setLayoutData(gd);
+
+		addButton = new Button(buttonComposite, SWT.PUSH);
+		addButton.setText(BUTTON_LABEL_ADD);
+		gd = new GridData();
+		gd.widthHint = EXEC_BUTTON_WIDTH;
+		addButton.setLayoutData(gd);
+		addButton.setEnabled(true);
+		addButton.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				IconPreferenceDialog dialog = new IconPreferenceDialog(
+						getShell());
+				if (dialog.open() != IDialogConstants.OK_ID) {
+					return;
+				}
+				entryList.add(dialog.getIconEntry());
+				notifyModified();
+			}
+		});
+
+		editButton = new Button(buttonComposite, SWT.PUSH);
+		editButton.setText(BUTTON_LABEL_EDIT);
+		gd = new GridData();
+		gd.widthHint = EXEC_BUTTON_WIDTH;
+		editButton.setLayoutData(gd);
+		editButton.setEnabled(false);
+		editButton.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (selectedEntry != null) {
+					IconPreferenceDialog dialog = new IconPreferenceDialog(
+							getShell());
+					dialog.setIconEntry(selectedEntry);
+					if (dialog.open() != IDialogConstants.OK_ID) {
+						return;
+					}
+				}
+				notifyModified();
+			}
+		});
+
+		deleteButton = new Button(buttonComposite, SWT.PUSH);
+		deleteButton.setText(BUTTON_LABEL_DELETE);
+		gd = new GridData();
+		gd.widthHint = EXEC_BUTTON_WIDTH;
+		deleteButton.setLayoutData(gd);
+		deleteButton.setEnabled(false);
+		deleteButton.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (selectedEntry != null) {
+					entryList.remove(selectedEntry);
+				}
+				notifyModified();
+			}
+		});
+
+		importButton = new Button(buttonComposite, SWT.PUSH);
+		importButton.setText(BUTTON_LABEL_IMPORT);
+		gd = new GridData();
+		gd.widthHint = EXEC_BUTTON_WIDTH;
+		importButton.setLayoutData(gd);
+		importButton.setEnabled(true);
+		importButton.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				setErrorMessage(null);
+				FileDialog dialog = new FileDialog(getShell());
+				dialog.setFilterExtensions(new String[] { "*.xml" });
+				String s = dialog.open();
+				if (s == null) {
+					return;
+				}
+				try {
+					File file = new File(s);
+					ComponentIconStore store = ComponentIconStore
+							.loadProfile(file.getAbsolutePath());
+					entryList = store.toEntries();
+					iconTableViewer.setInput(entryList);
+				} catch (Exception e1) {
+					setErrorMessage(ERROR_IMPORT_PROFILE);
+					e1.printStackTrace();
+				}
+			}
+		});
+
+		exportButton = new Button(buttonComposite, SWT.PUSH);
+		exportButton.setText(BUTTON_LABEL_EXPORT);
+		gd = new GridData();
+		gd.widthHint = EXEC_BUTTON_WIDTH;
+		exportButton.setLayoutData(gd);
+		exportButton.setEnabled(true);
+		exportButton.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				setErrorMessage(null);
+				FileDialog dialog = new FileDialog(getShell());
+				dialog.setFilterExtensions(new String[] { "*.xml" });
+				String s = dialog.open();
+				if (s == null) {
+					return;
+				}
+				ComponentIconStore store = ComponentIconStore
+						.getByEntries(entryList);
+				try {
+					File file = new File(s);
+					store.saveProfile(file.getAbsolutePath());
+				} catch (Exception e1) {
+					setErrorMessage(ERROR_EXPORT_PROFILE);
+					e1.printStackTrace();
+				}
+			}
+		});
+
+		buildData();
+
+		return composite;
+	}
+
+	TableViewerColumn createColumn(TableViewer viewer, String title, int width) {
+		TableViewerColumn col;
+		col = new TableViewerColumn(viewer, SWT.NONE);
+		col.getColumn().setText(title);
+		col.getColumn().setWidth(width);
+		return col;
+	}
+
+	@Override
+	public void init(IWorkbench workbench) {
+	}
+
+	@Override
+	public boolean performOk() {
+		ComponentIconStore store = ComponentIconStore.getByEntries(entryList);
+		manager.saveComponentIconStore(store);
+		buildData();
+		return super.performOk();
+	}
+
+	@Override
+	protected void performDefaults() {
+		manager.resetComponentIconStore();
+		buildData();
+		super.performDefaults();
+	}
+
+	void buildData() {
+		manager.loadComponentIconStore(ComponentIconStore.eINSTANCE);
+		entryList = ComponentIconStore.eINSTANCE.toEntries();
+		iconTableViewer.setInput(entryList);
+	}
+
+	void notifyModified() {
+		editButton.setEnabled(false);
+		deleteButton.setEnabled(false);
+		if (selectedEntry != null) {
+			editButton.setEnabled(true);
+			deleteButton.setEnabled(true);
+		}
+		iconTableViewer.refresh();
+	}
+
+	/** アイコン設定表示のLabelProvider */
+	public class IconLabelProvider extends LabelProvider implements
+			ITableLabelProvider, ITableColorProvider {
+
+		@Override
+		public Image getColumnImage(Object element, int columnIndex) {
+			ComponentIconStore.Entry entry = (ComponentIconStore.Entry) element;
+			switch (columnIndex) {
+			case PROPERTY_IMAGE:
+				ImageDescriptor desc = entry.getImageDescriptor();
+				if (desc == null) {
+					return null;
+				}
+				return desc.createImage();
+			default:
+				break;
+			}
+			return null;
+		}
+
+		@Override
+		public String getColumnText(Object element, int columnIndex) {
+			ComponentIconStore.Entry entry = (ComponentIconStore.Entry) element;
+			switch (columnIndex) {
+			case PROPERTY_PATTERN:
+				if (entry.isType()) {
+					return entry.getType();
+				} else {
+					return entry.getCategory();
+				}
+			case PROPERTY_KIND:
+				return (entry.isType()) ? ComponentIconStore.Entry.KIND_TYPE
+						: ComponentIconStore.Entry.KIND_CATEGORY;
+			case PROPERTY_PATH:
+				return entry.getPath();
+			default:
+				break;
+			}
+			return null;
+		}
+
+		@Override
+		public Color getBackground(Object element, int columnIndex) {
+			return null;
+		}
+
+		@Override
+		public Color getForeground(Object element, int columnIndex) {
+			return null;
+		}
+	}
+
+}

Added: trunk/rtmtools/jp.go.aist.rtm.systemeditor/test/jp/go/aist/rtm/systemeditor/manager/ComponentIconStoreTest.java
===================================================================
--- trunk/rtmtools/jp.go.aist.rtm.systemeditor/test/jp/go/aist/rtm/systemeditor/manager/ComponentIconStoreTest.java	                        (rev 0)
+++ trunk/rtmtools/jp.go.aist.rtm.systemeditor/test/jp/go/aist/rtm/systemeditor/manager/ComponentIconStoreTest.java	2012-03-12 15:06:20 UTC (rev 282)
@@ -0,0 +1,51 @@
+package jp.go.aist.rtm.systemeditor.manager;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+
+public class ComponentIconStoreTest extends TestCase {
+
+	static String ICON_PATH;
+
+	ComponentIconStore store;
+
+	void setUpClass() {
+		File f = new File("icons").getAbsoluteFile();
+		ICON_PATH = f.getAbsolutePath();
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		if (ICON_PATH == null) {
+			setUpClass();
+		}
+		store = new ComponentIconStore();
+	}
+
+	public void testParsePreference() throws Exception {
+		String fon = new File(ICON_PATH + "/on.png").getAbsolutePath();
+		String foff = new File(ICON_PATH + "/off.png").getAbsolutePath();
+
+		store.parsePreference("type;T1;" + fon + "|category;C1;" + foff
+				+ "|category;C2;" + foff);
+
+		assertEquals(fon, store.type2PathMap.get("T1"));
+		assertEquals(foff, store.category2PathMap.get("C1"));
+		assertEquals(foff, store.category2PathMap.get("C2"));
+	}
+
+	public void testToPreference() throws Exception {
+		String fon = new File(ICON_PATH + "/on.png").getAbsolutePath();
+		String foff = new File(ICON_PATH + "/off.png").getAbsolutePath();
+
+		store.type2PathMap.put("T1", fon);
+		store.category2PathMap.put("C1", foff);
+		store.category2PathMap.put("C2", foff);
+
+		String act = store.toPreference();
+		assertEquals("type;T1;" + fon + "|category;C1;" + foff
+				+ "|category;C2;" + foff, act);
+	}
+
+}



openrtm-commit メーリングリストの案内