OSDN Git Service

ワーキングセットをXMLで出力できるようにした。(読み込みは未対応)
authorseraphy <seraphy@5b6e9025-a2e8-4882-b233-f889982098c5>
Wed, 4 Dec 2013 16:33:26 +0000 (16:33 +0000)
committerseraphy <seraphy@5b6e9025-a2e8-4882-b233-f889982098c5>
Wed, 4 Dec 2013 16:33:26 +0000 (16:33 +0000)
git-svn-id: https://svn.sourceforge.jp/svnroot/charactermanaj/trunk@89 5b6e9025-a2e8-4882-b233-f889982098c5

src/charactermanaj/model/CharacterData.java
src/charactermanaj/model/WorkingSet.java
src/charactermanaj/model/io/CharacterDataXMLWriter.java
src/charactermanaj/model/io/WorkingSetXMLWriter.java [new file with mode: 0644]
src/charactermanaj/ui/MainFrame.java
src/charactermanaj/util/UserDataFactory.java

index 657c0ff..31c717e 100644 (file)
@@ -400,6 +400,60 @@ public class CharacterData implements Serializable, PartsSpecResolver {
        }\r
        \r
        /**\r
+        * キャラクターデータの構造を表す文字列を返す.<br>\r
+        * カテゴリ、レイヤー、色グループのみで構成される.<br>\r
+        * id, revなどは含まない.<br>\r
+        * @return キャラクターデータの構造を表す文字列\r
+        */\r
+       public String toStructureString() {\r
+               // カラーグループ\r
+               StringBuilder buf = new StringBuilder();\r
+               buf.append("{colorGroup:[");\r
+               for (ColorGroup colorGroup : getColorGroups()) {\r
+                       buf.append(colorGroup.getId());\r
+                       buf.append(",");\r
+               }\r
+               buf.append("],");\r
+               \r
+               // カテゴリ\r
+               buf.append("category:[");\r
+               for (PartsCategory category : getPartsCategories()) {\r
+                       buf.append("{id:");\r
+                       buf.append(category.getCategoryId());\r
+\r
+                       buf.append(",layer:[");\r
+                       for (Layer layer : category.getLayers()) {\r
+                               buf.append("{id:");\r
+                               buf.append(layer.getId());\r
+                               buf.append(",dir:");\r
+                               buf.append(layer.getDir());\r
+                               buf.append("},");\r
+                       }\r
+                       buf.append("]},");\r
+               }\r
+               buf.append("]}");\r
+               \r
+               return buf.toString();\r
+       }\r
+\r
+       /**\r
+        * キャラクターデータのID, REVと構造を識別するシグネチャの文字列を返す.<br>\r
+        * (構造はカテゴリ、レイヤー、色グループのみ).<br>\r
+        * @return シグネチャの文字列\r
+        */\r
+       public String toSignatureString() {\r
+               StringBuilder buf = new StringBuilder();\r
+               buf.append("{id:");\r
+               buf.append(getId());\r
+               buf.append(",rev:");\r
+               buf.append(getRev());\r
+               buf.append(",structure:");\r
+               buf.append(toStructureString());\r
+               buf.append("}");\r
+               return buf.toString();\r
+       }\r
+       \r
+       /**\r
         * デシリアライズする.\r
         * @param stream 入力もと\r
         * @throws IOException 失敗\r
index e444839..1489122 100644 (file)
@@ -3,9 +3,9 @@ package charactermanaj.model;
 import java.io.File;\r
 import java.io.IOException;\r
 import java.io.ObjectInputStream;\r
+import java.io.ObjectInputStream.GetField;\r
 import java.io.ObjectStreamClass;\r
 import java.io.Serializable;\r
-import java.io.ObjectInputStream.GetField;\r
 import java.net.URI;\r
 import java.net.URL;\r
 import java.util.Map;\r
@@ -92,6 +92,12 @@ public class WorkingSet implements Serializable {
                this.characterDataRev = characterDataRev;\r
        }\r
        \r
+       /**\r
+        * REV情報.<br>\r
+        * キャラクターデータが設定されていない場合に使用される.<br>\r
+        * (ver0.96以前旧シリアライズデータ互換用)<br>\r
+        * @return\r
+        */\r
        public String getCharacterDataRev() {\r
                return characterDataRev;\r
        }\r
@@ -139,13 +145,21 @@ public class WorkingSet implements Serializable {
 \r
        /**\r
         * 最後に使用したお気に入りの情報.<br>\r
+        * 一度もプリセットを使ってなければnull.<br>\r
         * ver0.94以前には存在しなかったため、nullになりえます。\r
         * @return\r
         */\r
        public PartsSet getLastUsePresetParts() {\r
                return lastUsePresetParts;\r
        }\r
-       \r
+\r
+       /**\r
+       /**\r
+        * 最後に使用したお気に入りの情報.<br>\r
+        * 一度もプリセットを使ってなければnull.<br>\r
+        * (ver0.94以前には存在しなかったため、nullになりえます。)\r
+        * @param lastUsePresetParts\r
+        */\r
        public void setLastUsePresetParts(PartsSet lastUsePresetParts) {\r
                this.lastUsePresetParts = lastUsePresetParts;\r
        }\r
index e8d7863..2692a9b 100644 (file)
@@ -54,8 +54,18 @@ public class CharacterDataXMLWriter {
        /**\r
         * キャラクター定義XMLファイルの名前空間\r
         */\r
-       private static final String NS = "http://charactermanaj.sourceforge.jp/schema/charactermanaj";\r
+       private static final String DEFAULT_NS = "http://charactermanaj.sourceforge.jp/schema/charactermanaj";\r
 \r
+       private final String NS;\r
+       \r
+       public CharacterDataXMLWriter() {\r
+               this(DEFAULT_NS);\r
+       }\r
+       \r
+       public CharacterDataXMLWriter(String ns) {\r
+               this.NS = ns;\r
+       }\r
+       \r
        /**\r
         * キャラクターデータのXMLの書き込み.\r
         * \r
@@ -87,8 +97,7 @@ public class CharacterDataXMLWriter {
                root.setAttribute("version", VERSION_SIG_1_0);\r
 \r
                root.setAttribute("xmlns:xml", XMLConstants.XML_NS_URI);\r
-               root.setAttribute("xmlns:xsi",\r
-                               "http://www.w3.org/2001/XMLSchema-instance");\r
+               root.setAttribute("xmlns:xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);\r
                root.setAttribute("xsi:schemaLocation", NS + " character.xsd");\r
                root.setAttribute("id", characterData.getId());\r
                root.setAttribute("rev", characterData.getRev());\r
@@ -316,6 +325,7 @@ public class CharacterDataXMLWriter {
                }\r
                tfmr.setOutputProperty(OutputKeys.INDENT, "yes");\r
 \r
+               // JDK-4504745 : javax.xml.transform.Transformer encoding does not work properly\r
                // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4504745\r
                final String encoding = "UTF-8";\r
                tfmr.setOutputProperty("encoding", encoding);\r
@@ -370,161 +380,9 @@ public class CharacterDataXMLWriter {
                                continue;\r
                        }\r
 \r
-                       String partsSetId = partsSet.getPartsSetId();\r
-                       String localizedName = partsSet.getLocalizedName();\r
-\r
-                       Element nodePreset = doc.createElementNS(NS, "preset");\r
-                       nodePreset.setAttribute("id", partsSetId);\r
+                       Element nodePreset = createPartsSetXML(doc, lang, partsSet);\r
                        baseElement.appendChild(nodePreset);\r
                        registeredPartsSetMap.put(partsSet.getPartsSetId(), partsSet);\r
-\r
-                       // display-name\r
-                       Element nodeName = doc.createElementNS(NS, "display-name");\r
-                       Attr attrLang = doc.createAttributeNS(XMLConstants.XML_NS_URI,\r
-                                       "lang");\r
-                       attrLang.setValue(lang);\r
-                       nodeName.setAttributeNode(attrLang);\r
-                       nodeName.setTextContent(localizedName);\r
-                       nodePreset.appendChild(nodeName);\r
-\r
-                       // bgColor\r
-                       Color bgColor = partsSet.getBgColor();\r
-                       if (bgColor != null) {\r
-                               Element nodeBgColor = doc.createElementNS(NS,\r
-                                               "background-color");\r
-                               nodeBgColor.setAttribute("color",\r
-                                               "#" + Integer.toHexString(bgColor.getRGB() & 0xffffff));\r
-                               nodePreset.appendChild(nodeBgColor);\r
-                       }\r
-\r
-                       // affine transform parameter\r
-                       double[] affineTransformParameter = partsSet\r
-                                       .getAffineTransformParameter();\r
-                       if (affineTransformParameter != null) {\r
-                               Element nodeAffineTransform = doc.createElementNS(NS,\r
-                                               "affine-transform-parameter");\r
-                               StringBuilder tmp = new StringBuilder();\r
-                               for (double affineItem : affineTransformParameter) {\r
-                                       if (tmp.length() > 0) {\r
-                                               tmp.append(" ");\r
-                                       }\r
-                                       tmp.append(Double.toString(affineItem));\r
-                               }\r
-                               nodeAffineTransform.setTextContent(tmp.toString());\r
-                               nodePreset.appendChild(nodeAffineTransform);\r
-                       }\r
-\r
-                       // categories\r
-                       for (Map.Entry<PartsCategory, List<PartsIdentifier>> entry : partsSet\r
-                                       .entrySet()) {\r
-                               PartsCategory partsCategory = entry.getKey();\r
-\r
-                               // category\r
-                               Element nodeCategory = doc.createElementNS(NS, "category");\r
-                               nodeCategory.setAttribute("refid",\r
-                                               partsCategory.getCategoryId());\r
-                               nodePreset.appendChild(nodeCategory);\r
-\r
-                               List<PartsIdentifier> partsIdentifiers = entry.getValue();\r
-                               for (PartsIdentifier partsIdentifier : partsIdentifiers) {\r
-                                       String partsName = partsIdentifier.getPartsName();\r
-                                       Element nodeParts = doc.createElementNS(NS, "parts");\r
-                                       nodeParts.setAttribute("name", partsName);\r
-                                       nodeCategory.appendChild(nodeParts);\r
-\r
-                                       PartsColorInfo partsColorInfo = partsSet\r
-                                                       .getColorInfo(partsIdentifier);\r
-                                       if (partsColorInfo != null) {\r
-                                               Element nodeColor = doc.createElementNS(NS, "color");\r
-                                               nodeParts.appendChild(nodeColor);\r
-\r
-                                               for (Map.Entry<Layer, ColorInfo> colorInfoEntry : partsColorInfo\r
-                                                               .entrySet()) {\r
-                                                       Layer layer = colorInfoEntry.getKey();\r
-                                                       ColorInfo colorInfo = colorInfoEntry.getValue();\r
-\r
-                                                       Element nodeLayer = doc\r
-                                                                       .createElementNS(NS, "layer");\r
-                                                       nodeLayer.setAttribute("refid", layer.getId());\r
-                                                       nodeColor.appendChild(nodeLayer);\r
-\r
-                                                       // ColorGroup\r
-                                                       ColorGroup colorGroup = colorInfo.getColorGroup();\r
-                                                       boolean colorSync = colorInfo.isSyncColorGroup();\r
-\r
-                                                       if (colorGroup.isEnabled()) {\r
-                                                               Element nodeColorGroup = doc.createElementNS(\r
-                                                                               NS, "color-group");\r
-                                                               nodeColorGroup.setAttribute("group",\r
-                                                                               colorGroup.getId());\r
-                                                               nodeColorGroup.setAttribute("synchronized",\r
-                                                                               colorSync ? "true" : "false");\r
-                                                               nodeLayer.appendChild(nodeColorGroup);\r
-                                                       }\r
-\r
-                                                       // RGB\r
-                                                       ColorConvertParameter param = colorInfo\r
-                                                                       .getColorParameter();\r
-\r
-                                                       Element nodeRGB = doc.createElementNS(NS, "rgb");\r
-                                                       Object[][] rgbArgss = {\r
-                                                                       {"red", param.getOffsetR(),\r
-                                                                                       param.getFactorR(),\r
-                                                                                       param.getGammaR()},\r
-                                                                       {"green", param.getOffsetG(),\r
-                                                                                       param.getFactorG(),\r
-                                                                                       param.getGammaG()},\r
-                                                                       {"blue", param.getOffsetB(),\r
-                                                                                       param.getFactorB(),\r
-                                                                                       param.getGammaB()},\r
-                                                                       {"alpha", param.getOffsetA(),\r
-                                                                                       param.getFactorA(),\r
-                                                                                       param.getGammaA()},};\r
-                                                       for (Object[] rgbArgs : rgbArgss) {\r
-                                                               Element nodeRGBItem = doc.createElementNS(NS,\r
-                                                                               rgbArgs[0].toString());\r
-                                                               nodeRGBItem.setAttribute("offset",\r
-                                                                               rgbArgs[1].toString());\r
-                                                               nodeRGBItem.setAttribute("factor",\r
-                                                                               rgbArgs[2].toString());\r
-                                                               nodeRGBItem.setAttribute("gamma",\r
-                                                                               rgbArgs[3].toString());\r
-                                                               nodeRGB.appendChild(nodeRGBItem);\r
-                                                       }\r
-                                                       nodeLayer.appendChild(nodeRGB);\r
-\r
-                                                       // HSB\r
-                                                       Element nodeHSB = doc.createElementNS(NS, "hsb");\r
-                                                       nodeHSB.setAttribute("hue",\r
-                                                                       Float.toString(param.getHue()));\r
-                                                       nodeHSB.setAttribute("saturation",\r
-                                                                       Float.toString(param.getSaturation()));\r
-                                                       nodeHSB.setAttribute("brightness",\r
-                                                                       Float.toString(param.getBrightness()));\r
-                                                       if (param.getContrast() != 0.f) {\r
-                                                               // ver0.96追加、optional\r
-                                                               // ぴったり0.0fだったら省略する.\r
-                                                               nodeHSB.setAttribute("contrast",\r
-                                                                               Float.toString(param.getContrast()));\r
-                                                       }\r
-                                                       nodeLayer.appendChild(nodeHSB);\r
-\r
-                                                       // RGB Replace\r
-                                                       Element nodeRGBReplace = doc.createElementNS(NS,\r
-                                                                       "rgb-replace");\r
-                                                       ColorConv colorConv = param.getColorReplace();\r
-                                                       if (colorConv == null) {\r
-                                                               colorConv = ColorConv.NONE;\r
-                                                       }\r
-                                                       nodeRGBReplace.setAttribute("replace-type",\r
-                                                                       colorConv.name());\r
-                                                       nodeRGBReplace.setAttribute("gray",\r
-                                                                       Float.toString(param.getGrayLevel()));\r
-                                                       nodeLayer.appendChild(nodeRGBReplace);\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
                }\r
 \r
                // プリセット登録時はデフォルトのプリセットIDがあれば、それも登録する.\r
@@ -542,6 +400,197 @@ public class CharacterDataXMLWriter {
 \r
                return registeredPartsSetMap.size();\r
        }\r
+       \r
+       /**\r
+        * パーツセットのXM要素を生成して返す.\r
+        * @param doc ノードを生成するためのファクトリ\r
+        * @param lang 言語識別用(パーツセット名などの登録時のlang属性に必要)\r
+        * @param partsSet パーツセット、nullの場合はxsi:nul="true"が返される.\r
+        * @return パーツセット1つ分のXML要素\r
+        */\r
+       public Element createPartsSetXML(Document doc, String lang, PartsSet partsSet) {\r
+               if (doc == null || lang == null) {\r
+                       throw new IllegalArgumentException();\r
+               }\r
+\r
+               String partsSetId = partsSet.getPartsSetId();\r
+               String localizedName = partsSet.getLocalizedName();\r
+\r
+               Element nodePreset = doc.createElementNS(NS, "preset");\r
+               if (partsSet == null || partsSet.isEmpty()) {\r
+                       // 指定されていないか有効でない場合は無しとみなす.\r
+                       nodePreset.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:nil", "true");\r
+                       return nodePreset;\r
+               }\r
+\r
+               nodePreset.setAttribute("id", partsSetId);\r
+\r
+               // display-name\r
+               Element nodeName = doc.createElementNS(NS, "display-name");\r
+               Attr attrLang = doc.createAttributeNS(XMLConstants.XML_NS_URI,\r
+                               "lang");\r
+               attrLang.setValue(lang);\r
+               nodeName.setAttributeNode(attrLang);\r
+               nodeName.setTextContent(localizedName);\r
+               nodePreset.appendChild(nodeName);\r
+\r
+               // bgColor\r
+               Color bgColor = partsSet.getBgColor();\r
+               if (bgColor != null) {\r
+                       Element nodeBgColor = doc.createElementNS(NS,\r
+                                       "background-color");\r
+                       nodeBgColor.setAttribute("color",\r
+                                       "#" + Integer.toHexString(bgColor.getRGB() & 0xffffff));\r
+                       nodePreset.appendChild(nodeBgColor);\r
+               }\r
+\r
+               // affine transform parameter\r
+               double[] affineTransformParameter = partsSet\r
+                               .getAffineTransformParameter();\r
+               if (affineTransformParameter != null) {\r
+                       Element nodeAffineTransform = doc.createElementNS(NS,\r
+                                       "affine-transform-parameter");\r
+                       StringBuilder tmp = new StringBuilder();\r
+                       for (double affineItem : affineTransformParameter) {\r
+                               if (tmp.length() > 0) {\r
+                                       tmp.append(" ");\r
+                               }\r
+                               tmp.append(Double.toString(affineItem));\r
+                       }\r
+                       nodeAffineTransform.setTextContent(tmp.toString());\r
+                       nodePreset.appendChild(nodeAffineTransform);\r
+               }\r
+\r
+               // categories\r
+               for (Map.Entry<PartsCategory, List<PartsIdentifier>> entry : partsSet\r
+                               .entrySet()) {\r
+                       PartsCategory partsCategory = entry.getKey();\r
+\r
+                       // category\r
+                       Element nodeCategory = doc.createElementNS(NS, "category");\r
+                       nodeCategory.setAttribute("refid",\r
+                                       partsCategory.getCategoryId());\r
+                       nodePreset.appendChild(nodeCategory);\r
+\r
+                       List<PartsIdentifier> partsIdentifiers = entry.getValue();\r
+                       for (PartsIdentifier partsIdentifier : partsIdentifiers) {\r
+                               String partsName = partsIdentifier.getPartsName();\r
+                               Element nodeParts = doc.createElementNS(NS, "parts");\r
+                               nodeParts.setAttribute("name", partsName);\r
+                               nodeCategory.appendChild(nodeParts);\r
+\r
+                               PartsColorInfo partsColorInfo = partsSet\r
+                                               .getColorInfo(partsIdentifier);\r
+                               if (partsColorInfo != null) {\r
+                                       Element nodeColor = createPartsColorInfoXML(doc, partsColorInfo);\r
+                                       nodeParts.appendChild(nodeColor);\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               return nodePreset;\r
+       }\r
+       \r
+       /**\r
+        * パーツカラー情報のXML要素を生成して返す.<br>\r
+        * @param doc 要素を作成するためのファクトリ\r
+        * @param partsColorInfo パーツカラー情報\r
+        * @return パーツカラー情報の要素\r
+        */\r
+       public Element createPartsColorInfoXML(Document doc, PartsColorInfo partsColorInfo) {\r
+               if (doc == null || partsColorInfo == null) {\r
+                       throw new IllegalArgumentException();\r
+               }\r
+\r
+               Element nodeColor = doc.createElementNS(NS, "color");\r
+\r
+               for (Map.Entry<Layer, ColorInfo> colorInfoEntry : partsColorInfo\r
+                               .entrySet()) {\r
+                       Layer layer = colorInfoEntry.getKey();\r
+                       ColorInfo colorInfo = colorInfoEntry.getValue();\r
+\r
+                       Element nodeLayer = doc\r
+                                       .createElementNS(NS, "layer");\r
+                       nodeLayer.setAttribute("refid", layer.getId());\r
+                       nodeColor.appendChild(nodeLayer);\r
+\r
+                       // ColorGroup\r
+                       ColorGroup colorGroup = colorInfo.getColorGroup();\r
+                       boolean colorSync = colorInfo.isSyncColorGroup();\r
+\r
+                       if (colorGroup.isEnabled()) {\r
+                               Element nodeColorGroup = doc.createElementNS(\r
+                                               NS, "color-group");\r
+                               nodeColorGroup.setAttribute("group",\r
+                                               colorGroup.getId());\r
+                               nodeColorGroup.setAttribute("synchronized",\r
+                                               colorSync ? "true" : "false");\r
+                               nodeLayer.appendChild(nodeColorGroup);\r
+                       }\r
+\r
+                       // RGB\r
+                       ColorConvertParameter param = colorInfo\r
+                                       .getColorParameter();\r
+\r
+                       Element nodeRGB = doc.createElementNS(NS, "rgb");\r
+                       Object[][] rgbArgss = {\r
+                                       {"red", param.getOffsetR(),\r
+                                                       param.getFactorR(),\r
+                                                       param.getGammaR()},\r
+                                       {"green", param.getOffsetG(),\r
+                                                       param.getFactorG(),\r
+                                                       param.getGammaG()},\r
+                                       {"blue", param.getOffsetB(),\r
+                                                       param.getFactorB(),\r
+                                                       param.getGammaB()},\r
+                                       {"alpha", param.getOffsetA(),\r
+                                                       param.getFactorA(),\r
+                                                       param.getGammaA()},};\r
+                       for (Object[] rgbArgs : rgbArgss) {\r
+                               Element nodeRGBItem = doc.createElementNS(NS,\r
+                                               rgbArgs[0].toString());\r
+                               nodeRGBItem.setAttribute("offset",\r
+                                               rgbArgs[1].toString());\r
+                               nodeRGBItem.setAttribute("factor",\r
+                                               rgbArgs[2].toString());\r
+                               nodeRGBItem.setAttribute("gamma",\r
+                                               rgbArgs[3].toString());\r
+                               nodeRGB.appendChild(nodeRGBItem);\r
+                       }\r
+                       nodeLayer.appendChild(nodeRGB);\r
+\r
+                       // HSB\r
+                       Element nodeHSB = doc.createElementNS(NS, "hsb");\r
+                       nodeHSB.setAttribute("hue",\r
+                                       Float.toString(param.getHue()));\r
+                       nodeHSB.setAttribute("saturation",\r
+                                       Float.toString(param.getSaturation()));\r
+                       nodeHSB.setAttribute("brightness",\r
+                                       Float.toString(param.getBrightness()));\r
+                       if (param.getContrast() != 0.f) {\r
+                               // ver0.96追加、optional\r
+                               // ぴったり0.0fだったら省略する.\r
+                               nodeHSB.setAttribute("contrast",\r
+                                               Float.toString(param.getContrast()));\r
+                       }\r
+                       nodeLayer.appendChild(nodeHSB);\r
+\r
+                       // RGB Replace\r
+                       Element nodeRGBReplace = doc.createElementNS(NS,\r
+                                       "rgb-replace");\r
+                       ColorConv colorConv = param.getColorReplace();\r
+                       if (colorConv == null) {\r
+                               colorConv = ColorConv.NONE;\r
+                       }\r
+                       nodeRGBReplace.setAttribute("replace-type",\r
+                                       colorConv.name());\r
+                       nodeRGBReplace.setAttribute("gray",\r
+                                       Float.toString(param.getGrayLevel()));\r
+                       nodeLayer.appendChild(nodeRGBReplace);\r
+               }\r
+               \r
+               return nodeColor;\r
+       }\r
 \r
        public void saveFavorites(CharacterData characterData,\r
                        OutputStream outstm) throws IOException {\r
diff --git a/src/charactermanaj/model/io/WorkingSetXMLWriter.java b/src/charactermanaj/model/io/WorkingSetXMLWriter.java
new file mode 100644 (file)
index 0000000..9e84abd
--- /dev/null
@@ -0,0 +1,311 @@
+package charactermanaj.model.io;
+
+import java.awt.Color;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import charactermanaj.model.CharacterData;
+import charactermanaj.model.PartsColorInfo;
+import charactermanaj.model.PartsIdentifier;
+import charactermanaj.model.PartsSet;
+import charactermanaj.model.WorkingSet;
+import charactermanaj.ui.model.WallpaperInfo;
+import charactermanaj.ui.model.WallpaperInfo.WallpaperResourceType;
+
+/**
+ * WorkingSetのXMLへの書き込み
+ */
+public class WorkingSetXMLWriter {
+       
+       /**
+        * WorkingSetのバージョン
+        */
+       private static final String VERSION_SIG_1_0 = "1.0";
+
+       /**
+        * WorkingSetのXMLファイルの名前空間
+        */
+       private static final String NS = "http://charactermanaj.sourceforge.jp/schema/charactermanaj-workingset";
+
+       /**
+        * キャラクターデータのXML化
+        */
+       private CharacterDataXMLWriter characterDataXmlWriter =
+                       new CharacterDataXMLWriter(NS);
+
+       /**
+        * ワーキングセットをXML表現で出力ストリームに出力します.<br>
+        * @param ws ワーキングセット
+        * @param outstm 出力先ストリーム
+        * @throws IOException 失敗
+        */
+       public void writeWorkingSet(WorkingSet ws, OutputStream outstm) throws IOException {
+               if (ws == null || outstm == null) {
+                       throw new IllegalArgumentException();
+               }
+               
+               Document doc = createWorkingSetXML(ws);
+
+               // output xml
+               TransformerFactory txFactory = TransformerFactory.newInstance();
+               txFactory.setAttribute("indent-number", Integer.valueOf(4));
+               Transformer tfmr;
+               try {
+                       tfmr = txFactory.newTransformer();
+               } catch (TransformerConfigurationException ex) {
+                       throw new RuntimeException("JAXP Configuration Failed.", ex);
+               }
+               tfmr.setOutputProperty(OutputKeys.INDENT, "yes");
+
+               // JDK-4504745 : javax.xml.transform.Transformer encoding does not work properly
+               // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4504745
+               final String encoding = "UTF-8";
+               tfmr.setOutputProperty("encoding", encoding);
+               try {
+                       tfmr.transform(new DOMSource(doc), new StreamResult(
+                                       new OutputStreamWriter(outstm, Charset.forName(encoding))));
+
+               } catch (TransformerException ex) {
+                       IOException ex2 = new IOException("XML Convert failed.");
+                       ex2.initCause(ex);
+                       throw ex2;
+               }
+       }
+       
+       /**
+        * ワーキングセットのXMLドキュメントを生成します.
+        * @param ws ワーキングセット
+        * @return XMLドキュメント
+        */
+       public Document createWorkingSetXML(WorkingSet ws) {
+               if (ws == null) {
+                       throw new IllegalArgumentException();
+               }
+
+               Document doc;
+               try {
+                       DocumentBuilderFactory factory = DocumentBuilderFactory
+                                       .newInstance();
+                       factory.setNamespaceAware(true);
+                       DocumentBuilder builder = factory.newDocumentBuilder();
+                       doc = builder.newDocument();
+               } catch (ParserConfigurationException ex) {
+                       throw new RuntimeException("JAXP Configuration failed.", ex);
+               }
+
+               Locale locale = Locale.getDefault();
+               String lang = locale.getLanguage();
+
+               Element root = doc.createElementNS(NS, "character-workingset");
+               root.setAttribute("version", VERSION_SIG_1_0);
+
+               root.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns:xsi",
+                               XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);           
+               root.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns:xml",
+                               XMLConstants.XML_NS_URI);               
+               root.setAttribute("xsi:schemaLocation", NS + " character_ws.xsd");
+
+               // ドキュメントベース
+               URI docbase = ws.getCharacterDocBase();
+               root.setAttribute("characterDocBase", docbase == null ? "" : docbase.toString());
+               
+               // キャラクターデータのシグネチャ
+               CharacterData cd = ws.getCharacterData();
+               Element characterDataSigElm = doc.createElementNS(NS, "characterDataSig");
+               if (cd == null || !cd.isValid()) {
+                       // 指定されていないか有効でない場合は無しとみなす.
+                       characterDataSigElm.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:nil", "true");
+               } else {
+                       characterDataSigElm.setTextContent(cd.toSignatureString());
+               }
+               root.appendChild(characterDataSigElm);
+
+               // パーツカラー情報
+               root.appendChild(writePartsColorInfoMap(doc, ws.getPartsColorInfoMap()));
+               
+               // パーツセット
+               PartsSet partsSet = ws.getPartsSet();
+               Element partsSetElm = doc.createElementNS(NS, "partsSet");
+               if (partsSet == null || partsSet.isEmpty()) {
+                       partsSetElm.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:nil", "true");
+                       
+               } else {
+                       Element elm = characterDataXmlWriter.createPartsSetXML(doc, lang, partsSet);
+                       partsSetElm.appendChild(elm);
+               }
+               root.appendChild(partsSetElm);
+               
+               // 最後に使用した保存先ディレクトリ
+               Element lastUsedSaveDirElm = doc.createElementNS(NS, "lastUsedSaveDir");
+               File lastUsedSaveDir = ws.getLastUsedSaveDir();
+               if (lastUsedSaveDir == null) {
+                       lastUsedSaveDirElm.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:nil", "true");
+                       
+               } else {
+                       lastUsedSaveDirElm.setTextContent(lastUsedSaveDir.getPath());
+               }
+               root.appendChild(lastUsedSaveDirElm);
+               
+               // 最後に使用したエクスポート先ディレクトリ
+               Element lastUsedExportDirElm = doc.createElementNS(NS, "lastUsedExportDir");
+               File lastUsedExportDir = ws.getLastUsedExportDir();
+               if (lastUsedExportDir == null) {
+                       lastUsedExportDirElm.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:nil", "true");
+                       
+               } else {
+                       lastUsedExportDirElm.setTextContent(lastUsedExportDir.getPath());
+               }
+               root.appendChild(lastUsedExportDirElm);
+               
+               // 最後に使用したパーツセット情報、なければnull
+               PartsSet lastUsePresetParts = ws.getLastUsePresetParts();
+               Element lastUsePresetPartsElm = doc.createElementNS(NS, "lastUsePresetParts");
+               if (lastUsePresetParts == null || lastUsePresetParts.isEmpty()) {
+                       lastUsePresetPartsElm.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:nil", "true");
+                       
+               } else {
+                       Element elm = characterDataXmlWriter.createPartsSetXML(doc, lang, lastUsePresetParts);
+                       lastUsePresetPartsElm.appendChild(elm);
+               }
+               root.appendChild(lastUsePresetPartsElm);
+               
+               // 壁紙情報
+               root.appendChild(writeWallpaper(doc, ws.getWallpaperInfo()));
+               
+               doc.appendChild(root);
+               return doc;
+       }
+       
+       /**
+        * パーツごとのカラー情報のXML要素を生成して返します.
+        * @param doc 要素のファクトリ
+        * @param partsColorMap パーツごとのカラー情報のマップ
+        * @return パーツごとのカラー情報のXML要素
+        */
+       public Element writePartsColorInfoMap(Document doc, Map<PartsIdentifier, PartsColorInfo> partsColorMap) {
+               Element partsColorInfoMapElm = doc.createElementNS(NS, "partsColorInfoMap");
+               if (partsColorMap != null) {
+                       // 使用しているカラーの設定ごとに番号を振る
+                       // (同じカラー設定であれば同じ番号とする.)
+                       LinkedHashMap<PartsColorInfo, String> colorMap = new LinkedHashMap<PartsColorInfo, String>();
+                       for (Map.Entry<PartsIdentifier, PartsColorInfo> partsColorEntry : partsColorMap.entrySet()) {
+                               PartsColorInfo partsColorInfo = partsColorEntry.getValue();
+                               if (partsColorInfo != null && !partsColorInfo.isEmpty()) {
+                                       if (!colorMap.containsKey(partsColorInfo)) {
+                                               colorMap.put(partsColorInfo, Integer.toString(colorMap.size() + 1));
+                                       }
+                               }
+                       }
+                       
+                       // すべてのカラー設定を出力する.
+                       Element colorsElm = doc.createElementNS(NS, "colors");
+                       for (Map.Entry<PartsColorInfo, String> colorMapEntry : colorMap.entrySet()) {
+                               PartsColorInfo partsColorInfo = colorMapEntry.getKey();
+                               String id = colorMapEntry.getValue();
+                               Element partsColorElm = characterDataXmlWriter.createPartsColorInfoXML(doc, partsColorInfo);
+                               partsColorElm.setAttribute("id", id);
+                               colorsElm.appendChild(partsColorElm);
+                       }
+                       partsColorInfoMapElm.appendChild(colorsElm);
+                       
+                       // パーツと、そのパーツのカラー設定番号の一覧を出力する.
+                       Element partsListElm = doc.createElementNS(NS, "partsList");
+                       for (Map.Entry<PartsIdentifier, PartsColorInfo> partsColorEntry : partsColorMap.entrySet()) {
+                               PartsIdentifier partsIdentifier = partsColorEntry.getKey();
+                               PartsColorInfo partsColorInfo = partsColorEntry.getValue();
+                               if (partsColorInfo != null && !partsColorInfo.isEmpty()) {
+                                       String colorId = colorMap.get(partsColorInfo);
+                                       if (colorId == null) {
+                                               throw new RuntimeException("colorMapが不整合です");
+                                       }
+                                       Element partsElm = doc.createElementNS(NS, "partsIdentifier");
+                                       String categoryId = partsIdentifier.getPartsCategory().getCategoryId();
+                                       partsElm.setAttribute("categoryId", categoryId);
+                                       partsElm.setAttribute("name", partsIdentifier.getPartsName());
+                                       partsElm.setAttribute("colorId", colorId);
+                                       partsListElm.appendChild(partsElm);
+                               }
+                       }
+                       partsColorInfoMapElm.appendChild(partsListElm);
+               }
+               return partsColorInfoMapElm;
+       }
+       
+       /**
+        * 壁紙情報をXML要素として生成する.
+        * @param doc XML要素のファクトリ
+        * @param wallpaperInfo 壁紙情報
+        * @return 壁紙情報のXML要素
+        */
+       public Element writeWallpaper(Document doc, WallpaperInfo wallpaperInfo) {
+               Element elm = doc.createElementNS(NS, "wallpaperInfo");
+               
+               if (wallpaperInfo == null) {
+                       elm.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:nil", "true");
+
+               } else {
+                       // タイプ
+                       WallpaperResourceType typ = wallpaperInfo.getType();
+                       Element typElm = doc.createElementNS(NS, "type");
+                       typElm.setTextContent(typ.name());
+                       elm.appendChild(typElm);
+                       
+                       // リソース
+                       String res = wallpaperInfo.getResource();
+                       Element resElm = doc.createElementNS(NS, "resource");
+                       if (res == null || res.trim().length() == 0) {
+                               resElm.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:nil", "true");
+                       } else {
+                               resElm.setTextContent(res);
+                       }
+                       elm.appendChild(resElm);
+                       
+                       // ファイル
+                       File file = wallpaperInfo.getFile();
+                       Element fileElm = doc.createElementNS(NS, "file");
+                       if (file == null) {
+                               fileElm.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:nil", "true");
+                       } else {
+                               fileElm.setTextContent(file.getPath());
+                       }
+                       elm.appendChild(fileElm);
+                       
+                       // アルファ
+                       float alpha = wallpaperInfo.getAlpha();
+                       Element alphaElm = doc.createElementNS(NS, "alpha");
+                       alphaElm.setTextContent(Float.toString(alpha));
+                       elm.appendChild(alphaElm);
+                       
+                       // 背景色
+                       Color backgroundColor = wallpaperInfo.getBackgroundColor();
+                       Element bgColorElm = doc.createElementNS(NS, "backgroundColor");
+                       bgColorElm.setTextContent("#" + Integer.toHexString(backgroundColor.getRGB() & 0xffffff));
+                       elm.appendChild(bgColorElm);
+               }
+               
+               return elm;
+       }
+       
+}
index a26331d..f9365c1 100644 (file)
@@ -1,7 +1,6 @@
 package charactermanaj.ui;\r
 \r
-import static java.lang.Math.max;\r
-import static java.lang.Math.min;\r
+import static java.lang.Math.*;\r
 \r
 import java.awt.BorderLayout;\r
 import java.awt.Color;\r
@@ -23,6 +22,7 @@ import java.awt.event.WindowEvent;
 import java.awt.image.BufferedImage;\r
 import java.io.File;\r
 import java.io.IOException;\r
+import java.io.OutputStream;\r
 import java.lang.reflect.InvocationTargetException;\r
 import java.util.ArrayList;\r
 import java.util.Collections;\r
@@ -80,6 +80,7 @@ import charactermanaj.model.io.PartsImageDirectoryWatchAgentFactory;
 import charactermanaj.model.io.PartsImageDirectoryWatchEvent;\r
 import charactermanaj.model.io.PartsImageDirectoryWatchListener;\r
 import charactermanaj.model.io.RecentDataPersistent;\r
+import charactermanaj.model.io.WorkingSetXMLWriter;\r
 import charactermanaj.ui.ImageSelectPanel.ImageSelectPanelEvent;\r
 import charactermanaj.ui.ImageSelectPanel.ImageSelectPanelListener;\r
 import charactermanaj.ui.ManageFavoriteDialog.FavoriteManageCallback;\r
@@ -1865,6 +1866,17 @@ public class MainFrame extends JFrame {
                        UserData workingSetStore = getWorkingSetUserData(false);\r
                        workingSetStore.save(workingSet);\r
 \r
+                       // XML形式でのワーキングセットの保存\r
+                       UserDataFactory userDataFactory = UserDataFactory.getInstance();\r
+                       UserData xmlData = userDataFactory.getMangledNamedUserData(characterData.getDocBase(), "workingset.xml");\r
+                       OutputStream outstm = xmlData.getOutputStream();\r
+                       try {\r
+                               WorkingSetXMLWriter workingSetXmlWriter = new WorkingSetXMLWriter();\r
+                               workingSetXmlWriter.writeWorkingSet(workingSet, outstm);\r
+                       } finally {\r
+                               outstm.close();\r
+                       }\r
+                       \r
                } catch (Exception ex) {\r
                        ErrorMessageHelper.showErrorDialog(this, ex);\r
                }\r
index 55e49d2..770b8a4 100644 (file)
@@ -53,14 +53,25 @@ public class UserDataFactory {
                File userDataDir = ConfigurationDirUtilities.getUserDataDir();\r
                \r
                if (name != null && name.length() > 0) {\r
-                       int pos = name.lastIndexOf('.');\r
-                       if (pos >= 0) {\r
-                               String ext = name.substring(pos + 1);\r
-                               if (ext.length() > 0) {\r
-                                       if ("ser".equals(ext)) {\r
-                                               userDataDir = new File(userDataDir, "caches");\r
-                                       } else {\r
-                                               userDataDir = new File(userDataDir, ext + "s");\r
+                       int seppos = name.lastIndexOf('-');\r
+                       if (name.endsWith(".xml") && seppos >= 0) {\r
+                               // 「foo-????.xml」形式の場合は「????」でグループ化する\r
+                               String groupName = name.substring(seppos + 1, name.length() - 4);\r
+                               if (groupName.length() > 0) {\r
+                                       userDataDir = new File(userDataDir, groupName);\r
+                               }\r
+\r
+                       } else {\r
+                               // 拡張子によるグループ化\r
+                               int pos = name.lastIndexOf('.');\r
+                               if (pos >= 0) {\r
+                                       String ext = name.substring(pos + 1);\r
+                                       if (ext.length() > 0) {\r
+                                               if ("ser".equals(ext)) {\r
+                                                       userDataDir = new File(userDataDir, "caches");\r
+                                               } else {\r
+                                                       userDataDir = new File(userDataDir, ext + "s");\r
+                                               }\r
                                        }\r
                                }\r
                        }\r