OSDN Git Service

7feda5df6579b0590d880c75525b394cb9fbc8be
[charactermanaj/CharacterManaJ.git] / src / charactermanaj / model / io / ImportModel.java
1 package charactermanaj.model.io;\r
2 \r
3 import java.awt.image.BufferedImage;\r
4 import java.io.BufferedInputStream;\r
5 import java.io.BufferedOutputStream;\r
6 import java.io.File;\r
7 import java.io.FileOutputStream;\r
8 import java.io.IOException;\r
9 import java.io.InputStream;\r
10 import java.io.OutputStream;\r
11 import java.net.URI;\r
12 import java.util.Collection;\r
13 import java.util.logging.Level;\r
14 import java.util.logging.Logger;\r
15 \r
16 import charactermanaj.model.AppConfig;\r
17 import charactermanaj.model.CharacterData;\r
18 import charactermanaj.model.PartsAuthorInfo;\r
19 import charactermanaj.model.PartsCategory;\r
20 import charactermanaj.model.PartsManageData;\r
21 import charactermanaj.model.io.AbstractCharacterDataArchiveFile.CategoryLayerPair;\r
22 import charactermanaj.model.io.AbstractCharacterDataArchiveFile.PartsImageContent;\r
23 import charactermanaj.ui.progress.ProgressHandle;\r
24 \r
25 public class ImportModel {\r
26 \r
27         /**\r
28          * ロガー.<br>\r
29          */\r
30         private static final Logger logger = Logger.getLogger(ImportModel.class.getName());\r
31 \r
32         /**\r
33          * インポートもとファイル\r
34          */\r
35         private URI importSource;\r
36         \r
37         /**\r
38          * プロファイル先のキャラクター定義、新規の場合はnull\r
39          */\r
40         private CharacterData currentCharacterData;\r
41         \r
42         \r
43         /**\r
44          * インポートもとアーカイブ. ロードされた場合に非nullとなる.\r
45          */\r
46         private CharacterDataArchiveFile archiveFile;\r
47         \r
48         \r
49         /**\r
50          * インポートされたキャラクター定義、なければnull\r
51          */\r
52         private CharacterData sourceCharacterData;\r
53         \r
54         /**\r
55          * インポートされたサンプルピクチャ、なければnull\r
56          */\r
57         private BufferedImage samplePicture;\r
58         \r
59         /**\r
60          * インポートされたreadme\r
61          */\r
62         private String readme;\r
63         \r
64         /**\r
65          * インポート先のキャラクター定義、もしくは現在のキャラクター定義のディレクトリ構成から 読み取ることのできるパーツのコレクション、なければ空.<br>\r
66          */\r
67         private Collection<PartsImageContent> partsImageContentsMap;\r
68         \r
69         /**\r
70          * パーツ管理データ、なければ空\r
71          */\r
72         private PartsManageData partsManageData;\r
73         \r
74 \r
75         public void openImportSource(URI importSource, CharacterData currentCharacterData) throws IOException {\r
76                 if (archiveFile != null || importSource == null) {\r
77                         throw new IllegalStateException("既にアーカイブがオープンされています。");\r
78                 }\r
79                 this.importSource = importSource;\r
80                 this.currentCharacterData = currentCharacterData;\r
81         }\r
82         \r
83         public void closeImportSource() throws IOException {\r
84                 if (archiveFile != null) {\r
85                         try {\r
86                                 archiveFile.close();\r
87                         } finally {\r
88                                 // クローズに失敗しても閉じたことにする.\r
89                                 reset();\r
90                         }\r
91                 }\r
92         }\r
93         \r
94         public void loadContents(ProgressHandle progressHandle) throws IOException {\r
95                 if (archiveFile != null) {\r
96                         throw new IllegalStateException("既にアーカイブがオープンされています。");\r
97                 }\r
98                 if (importSource == null) {\r
99                         throw new IllegalStateException("インポートファィルが指定されていません。");\r
100                 }\r
101 \r
102                 CharacterDataFileReaderWriterFactory factory = CharacterDataFileReaderWriterFactory.getInstance();\r
103                 \r
104                 progressHandle.setCaption("open archive...");\r
105                 archiveFile = factory.openArchive(importSource);\r
106 \r
107                 readme = archiveFile.readReadMe();\r
108 \r
109                 progressHandle.setCaption("search the character definition...");\r
110                 sourceCharacterData = archiveFile.readCharacterData();\r
111                 if (sourceCharacterData == null) {\r
112                         // character.xmlがない場合は、character.iniで試行する.\r
113 \r
114                         sourceCharacterData = archiveFile.readCharacterINI();\r
115                         if (sourceCharacterData != null) {\r
116                                 // readmeがあれば、それを説明として登録しておく\r
117                                 if (readme != null && readme.trim().length() > 0) {\r
118                                         sourceCharacterData.setDescription(readme);\r
119                                 }\r
120                         }\r
121                         \r
122                 } else {\r
123                         // character.xmlがあった場合、favorites.xmlもあれば読み込む.\r
124                         archiveFile.readFavorites(sourceCharacterData);\r
125                 }\r
126 \r
127                 // サンプルピクチャの読み込み、なければnull\r
128                 progressHandle.setCaption("load sample picture...");\r
129                 samplePicture = archiveFile.readSamplePicture();\r
130                 \r
131                 // パーツセットの読み込み、なければ空\r
132                 progressHandle.setCaption("load partssets...");\r
133                 if (currentCharacterData != null) {\r
134                         // 既存のキャラクターセットの定義をもとにパーツディレクトリを探索する場合\r
135                         // (インポートもと・インポート先が同一であればパーツは除外される.)\r
136                         partsImageContentsMap = archiveFile.getPartsImageContents(currentCharacterData, false);\r
137                 } else {\r
138                         // インポート元にあるキャラクター定義をもとにパーツディレクトリを探索する場合\r
139                         partsImageContentsMap = archiveFile.getPartsImageContents(sourceCharacterData, true);\r
140                 }\r
141                 \r
142                 // パーツ管理データの読み込み\r
143                 progressHandle.setCaption("load parts definitions...");\r
144                 partsManageData = archiveFile.getPartsManageData();\r
145         }\r
146 \r
147         protected void reset() {\r
148                 importSource = null;\r
149                 archiveFile = null;\r
150                 sourceCharacterData = null;\r
151                 samplePicture = null;\r
152                 readme = null;\r
153                 partsImageContentsMap = null;\r
154                 partsManageData = null;\r
155         }\r
156         \r
157 \r
158 \r
159         public URI getImportSource() {\r
160                 return importSource;\r
161         }\r
162         \r
163         protected void checkArchiveOpened() {\r
164                 if (archiveFile == null) {\r
165                         throw new IllegalStateException("アーカイブはオープンされていません。");\r
166                 }\r
167         }\r
168         \r
169         public CharacterData getCharacterData() {\r
170                 checkArchiveOpened();\r
171                 return sourceCharacterData;\r
172         }\r
173 \r
174         public BufferedImage getSamplePicture() {\r
175                 checkArchiveOpened();\r
176                 return samplePicture;\r
177         }\r
178 \r
179         public String getReadme() {\r
180                 checkArchiveOpened();\r
181                 return readme;\r
182         }\r
183 \r
184         public Collection<PartsImageContent> getPartsImageContents() {\r
185                 checkArchiveOpened();\r
186                 return partsImageContentsMap;\r
187         }\r
188 \r
189         public PartsManageData getPartsManageData() {\r
190                 checkArchiveOpened();\r
191                 return partsManageData;\r
192         }\r
193 \r
194         \r
195         \r
196         /**\r
197          * パーツデータをプロファイルの画像ディレクトリに一括コピーする.<br>\r
198          * \r
199          * @param partsImageContents\r
200          *            コピー対象のパーツデータ\r
201          * @param cd\r
202          *            コピー先のプロファイル\r
203          * @throws IOException\r
204          *             失敗\r
205          */\r
206         public void copyPartsImageContents(\r
207                         Collection<PartsImageContent> partsImageContents, CharacterData cd)\r
208                         throws IOException {\r
209                 if (cd == null || cd.getDocBase() == null) {\r
210                         throw new IllegalArgumentException("invalid character data");\r
211                 }\r
212 \r
213                 // コピー先ディレクトリの確定\r
214                 URI docbase = cd.getDocBase();\r
215                 if ( !"file".equals(docbase.getScheme())) {\r
216                         throw new IOException("ファイル以外はサポートしていません: " + docbase);\r
217                 }\r
218                 File configFile = new File(docbase);\r
219                 File baseDir = configFile.getParentFile();\r
220                 if (baseDir == null || !baseDir.isDirectory()) {\r
221                         throw new IOException("親フォルダがディレクトリではありません: " + baseDir);\r
222                 }\r
223 \r
224                 AppConfig appConfig = AppConfig.getInstance();\r
225                 byte[] stmbuf = new byte[appConfig.getFileTransferBufferSize()];\r
226                 \r
227                 // ファイルコピー\r
228                 for (PartsImageContent content : partsImageContents) {\r
229                         InputStream is = new BufferedInputStream(content.openStream());\r
230                         try {\r
231                                 File outDir = new File(baseDir, content.getDirName());\r
232                                 if (!outDir.exists()) {\r
233                                         if (!outDir.mkdirs()) {\r
234                                                 logger.log(Level.WARNING, "can't create the directory. " + outDir);\r
235                                         }\r
236                                 }\r
237                                 File outFile = new File(outDir, content.getFileName());\r
238                                 OutputStream os = new BufferedOutputStream(new FileOutputStream(outFile));\r
239                                 try {\r
240                                         for (;;) {\r
241                                                 int rd = is.read(stmbuf);\r
242                                                 if (rd < 0) {\r
243                                                         break;\r
244                                                 }\r
245                                                 os.write(stmbuf, 0, rd);\r
246                                         }\r
247                                 } finally {\r
248                                         os.close();\r
249                                 }\r
250                                 \r
251                                 if (!outFile.setLastModified(content.lastModified())) {\r
252                                         logger.log(Level.WARNING, "can't change the modified-date: " + outFile);\r
253                                 }\r
254                                 \r
255                         } finally {\r
256                                 is.close();\r
257                         }\r
258                 }\r
259         }\r
260 \r
261         /**\r
262          * パーツ管理情報を更新または作成する.<br>\r
263          * パーツ管理情報がnullまたは空であれば何もしない.<br>\r
264          * そうでなければインポートするパーツに該当するパーツ管理情報を、現在のプロファイルのパーツ管理情報に追記・更新し、 それを書き出す.<br>\r
265          * インポートもとにパーツ管理情報がなく、既存にある場合、インポートしても管理情報は削除されません.(上書きセマンティクスのため)\r
266          * \r
267          * @param partsImageContents\r
268          *            インポートするパーツ\r
269          * @param partsManageData\r
270          *            パーツ管理データ\r
271          * @param current\r
272          *            現在のパーツ管理データを保持しているプロファイル、新規の場合はnull\r
273          * @param target\r
274          *            書き込み先のプロファイル\r
275          * @throws IOException\r
276          *             書き込みに失敗した場合\r
277          */\r
278         public void updatePartsManageData(\r
279                         Collection<PartsImageContent> partsImageContents,\r
280                         PartsManageData partsManageData, CharacterData current,\r
281                         CharacterData target) throws IOException {\r
282                 if (target == null || !target.isValid()) {\r
283                         throw new IllegalArgumentException();\r
284                 }\r
285                 \r
286                 if (partsImageContents == null || partsImageContents.isEmpty()\r
287                                 || partsManageData == null || partsManageData.isEmpty()) {\r
288                         // インポートするパーツが存在しないか、管理情報がない場合は更新しようがないので何もしないで戻る.\r
289                         return;\r
290                 }\r
291 \r
292                 PartsInfoXMLReader xmlReader = new PartsInfoXMLReader();\r
293                 \r
294                 PartsManageData mergedPartsManagedData;\r
295                 if (current != null && current.isValid()) {\r
296                         // 現在のプロファイルからパーツ管理情報を取得する.\r
297                         mergedPartsManagedData = xmlReader.loadPartsManageData(current.getDocBase());\r
298                 } else {\r
299                         // 新規の場合は空\r
300                         mergedPartsManagedData = new PartsManageData();\r
301                 }\r
302                 \r
303                 // インポート対象のパーツに該当するパーツ管理情報のみを取り出して追記する.\r
304                 for (PartsImageContent partsImageContent : partsImageContents) {\r
305                         String partsName = partsImageContent.getPartsName();\r
306                         for (CategoryLayerPair catLayerPair : partsImageContent.getCategoryLayerPairs()) {\r
307                                 PartsCategory partsCategory = catLayerPair.getPartsCategory();\r
308                                 String categoryId = partsCategory.getCategoryId();\r
309                                 \r
310                                 PartsManageData.PartsKey partsKey = new PartsManageData.PartsKey(partsName, categoryId);\r
311                                 \r
312                                 PartsAuthorInfo partsAuthorInfo = partsManageData.getPartsAuthorInfo(partsKey);\r
313                                 PartsManageData.PartsVersionInfo versionInfo = partsManageData.getVersion(partsKey);\r
314                                 String localizedName = partsManageData.getLocalizedName(partsKey);\r
315                                 \r
316                                 if (partsAuthorInfo != null || versionInfo != null || localizedName != null) {\r
317                                         // いずれかの情報の登録がある場合、パーツ管理情報として追記する.\r
318                                         mergedPartsManagedData.putPartsInfo(partsKey, localizedName, partsAuthorInfo, versionInfo);\r
319                                 }\r
320                         }\r
321                 }\r
322 \r
323                 // パーツ管理情報を更新する.\r
324                 PartsInfoXMLWriter partsInfoXMLWriter = new PartsInfoXMLWriter();\r
325                 partsInfoXMLWriter.savePartsManageData(target.getDocBase(),\r
326                                 mergedPartsManagedData);\r
327         }\r
328 }\r