1 // ================================================================================================
3 // アプリケーションの設定を保持するクラスソース</summary>
5 // <copyright file="Config.cs" company="honeplusのメモ帳">
6 // Copyright (C) 2010 Honeplus. All rights reserved.</copyright>
9 // ================================================================================================
11 namespace Honememo.Wptscs.Models
14 using System.Collections.Generic;
16 using System.Windows.Forms;
18 using System.Xml.Serialization;
19 using Honememo.Utilities;
20 using Honememo.Wptscs.Logics;
21 using Honememo.Wptscs.Properties;
24 /// アプリケーションの設定を保持するクラスです。
26 public class Config : IXmlSerializable
31 /// アプリケーション内でのインスタンス保持変数。
33 private static IDictionary<string, Config> configs = new Dictionary<string, Config>();
42 private IList<Language> languages = new List<Language>();
47 private IList<Website> websites = new List<Website>();
52 private IList<TranslationDictionary> itemTables = new List<TranslationDictionary>();
57 private TranslationTable headingTable = new TranslationTable();
66 /// <remarks>通常は<see cref="GetInstance(string)"/>を使用する。</remarks>
76 /// 翻訳支援処理で使用するロジッククラス名。
78 public Type Translator
87 /// <remarks>空でもオブジェクトは存在。</remarks>
88 public IList<Website> Websites
97 // ※必須な情報が設定されていない場合、例外を返す
98 this.websites = Validate.NotNull(value, "websites");
105 /// <remarks>空でもオブジェクトは存在。</remarks>
106 public IList<TranslationDictionary> ItemTables
110 return this.itemTables;
115 // ※必須な情報が設定されていない場合、例外を返す
116 this.itemTables = Validate.NotNull(value, "itemTables");
123 /// <remarks>空でもオブジェクトは存在。</remarks>
124 public TranslationTable HeadingTable
128 return this.headingTable;
133 // ※必須な情報が設定されていない場合、例外を返す
134 this.headingTable = Validate.NotNull(value, "headingTable");
143 /// アプリケーションの設定を取得する。
144 /// ユーザーごとの設定ファイルがあればその内容を、
145 /// なければアプリケーション標準の設定ファイルの内容を
146 /// 読み込んで、インスタンスを作成する。
148 /// <param name="file">設定ファイル名。</param>
149 /// <returns>作成した/既に存在するインスタンス。</returns>
150 public static Config GetInstance(string file)
152 // シングルトンとするため、処理をロック
155 // 既に作成済みのインスタンスがあればその値を使用
156 // (設定ファイルのタイムスタンプとか確認して再読み込みした方がよい?)
157 if (Config.configs.ContainsKey(file))
159 return Config.configs[file];
162 // 無い場合はユーザーごと・または初期設定用の設定ファイルを読み込み
163 string path = FormUtils.SearchUserAppData(file, Settings.Default.ConfigurationCompatible);
164 if (String.IsNullOrEmpty(path))
167 // (空でnewしてもよいが、ユーザーが勘違いすると思うので。)
168 throw new FileNotFoundException(file + " is not found");
172 System.Diagnostics.Debug.WriteLine("Config.GetInstance > " + path + " を読み込み");
173 using (Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
175 Config.configs[file] = new XmlSerializer(typeof(Config)).Deserialize(stream) as Config;
179 return Config.configs[file];
187 /// 設定をユーザーごとの設定ファイルに書き出し。
189 /// <param name="file">設定ファイル名。</param>
190 public void Save(string file)
192 // ファイル出力のため、競合しないよう一応ロック
193 lock (Config.configs)
195 // 最初にディレクトリの有無を確認し作成
196 string path = Application.UserAppDataPath;
197 if (!Directory.Exists(path))
199 Directory.CreateDirectory(path);
203 using (Stream stream = new FileStream(
204 Path.Combine(path, file),
207 new XmlSerializer(typeof(Config)).Serialize(stream, this);
214 #region 設定値取得用インスタンスメソッド
217 /// 設定から、現在の処理対象・指定された言語のウェブサイトを取得する。
219 /// <param name="lang">言語コード。</param>
220 /// <returns>ウェブサイトの情報。存在しない場合は<c>null</c>返す。</returns>
221 public Website GetWebsite(string lang)
224 foreach (Website s in this.Websites)
226 if (s.Language.Code == lang)
233 // ※ こっちがNeedCreateじゃないのは、何をnewすればいいのか判らないため
238 /// 設定から、現在の処理対象・指定された言語の対訳表(項目)を取得する。
240 /// <param name="from">翻訳元言語。</param>
241 /// <param name="to">翻訳先言語。</param>
242 /// <returns>対訳表の情報。存在しない場合は新たに作成した対訳表を返す。</returns>
243 public TranslationDictionary GetItemTableNeedCreate(string from, string to)
245 // オブジェクトに用意されている共通メソッドをコール
246 return TranslationDictionary.GetDictionaryNeedCreate(this.ItemTables, from, to);
251 #region XMLシリアライズ用メソッド
254 /// シリアライズするXMLのスキーマ定義を返す。
256 /// <returns>XML表現を記述するXmlSchema。</returns>
257 public System.Xml.Schema.XmlSchema GetSchema()
263 /// XMLからオブジェクトを読み込む。
265 /// <param name="reader">読込元のXmlReader</param>
266 public void ReadXml(XmlReader reader)
268 XmlDocument xml = new XmlDocument();
272 // ※ 以下、基本的に無かったらNGの部分はいちいちチェックしない。例外飛ばす
273 XmlElement rootElement = xml.DocumentElement;
276 this.Translator = this.ParseTranslator(rootElement.SelectSingleNode("Translator").InnerText);
279 foreach (XmlNode siteNode in rootElement.SelectSingleNode("Websites").ChildNodes)
281 // ノードに指定された内容に応じたインスタンスを取得する
282 this.Websites.Add(this.ParseWebsite(siteNode, reader.Settings));
286 XmlSerializer serializer = new XmlSerializer(typeof(TranslationDictionary), new XmlRootAttribute("ItemTable"));
287 foreach (XmlNode itemNode in rootElement.SelectSingleNode("ItemTables").ChildNodes)
289 using (XmlReader r = XmlReader.Create(new StringReader(itemNode.OuterXml), reader.Settings))
291 this.ItemTables.Add(serializer.Deserialize(r) as TranslationDictionary);
296 using (XmlReader r = XmlReader.Create(
297 new StringReader(rootElement.SelectSingleNode("HeadingTable").OuterXml),
300 this.HeadingTable = new XmlSerializer(typeof(TranslationTable), new XmlRootAttribute("HeadingTable"))
301 .Deserialize(r) as TranslationTable;
308 /// <param name="writer">出力先のXmlWriter</param>
309 public void WriteXml(XmlWriter writer)
312 string translator = this.Translator.FullName;
313 if (translator.StartsWith(typeof(Translator).Namespace))
315 // 自前のエンジンの場合、クラス名だけを出力
316 translator = this.Translator.Name;
319 writer.WriteElementString("Translator", translator);
322 writer.WriteStartElement("Websites");
323 foreach (Website site in this.Websites)
325 // 通常はサイトのパッケージ名も含めたフル名を要素名とする
326 string siteName = site.GetType().FullName;
327 if (siteName.StartsWith(typeof(Website).Namespace))
329 // 自前のサイトの場合、クラス名だけを出力
330 siteName = site.GetType().Name;
333 new XmlSerializer(site.GetType(), new XmlRootAttribute(siteName)).Serialize(writer, site);
336 writer.WriteEndElement();
339 XmlSerializer serializer = new XmlSerializer(typeof(TranslationDictionary), new XmlRootAttribute("ItemTable"));
340 writer.WriteStartElement("ItemTables");
341 foreach (TranslationDictionary trans in this.ItemTables)
343 serializer.Serialize(writer, trans);
346 writer.WriteEndElement();
349 new XmlSerializer(this.HeadingTable.GetType(), new XmlRootAttribute("HeadingTable"))
350 .Serialize(writer, this.HeadingTable);
354 /// 指定されたXML値からTranslatorのクラスを取得するる。
356 /// <param name="name">XMLのクラス名情報。</param>
357 /// <returns>Translatorクラス。</returns>
358 /// <remarks>クラスは動的に判定する。クラスが存在しない場合などは随時状況に応じた例外を投げる。</remarks>
359 private Type ParseTranslator(string name)
361 // Translateと同じパッケージに指定された名前のクラスがあるかを探す
362 Type type = Type.GetType(typeof(Translator).Namespace + "." + name, false, true);
365 // 存在しない場合、そのままの名前でクラスを探索、無ければ例外スロー
366 type = Type.GetType(name, true, true);
373 /// XMLノードからWebSiteインスタンスをデシリアライズする。
375 /// <param name="node">WebSiteをシリアライズしたノード。</param>
376 /// <param name="setting">XML読み込み時の設定。</param>
377 /// <returns>デシリアライズしたインスタンス。</returns>
378 /// <remarks>クラスはノード名から動的に判定する。クラスが存在しない場合などは随時状況に応じた例外を投げる。</remarks>
379 private Website ParseWebsite(XmlNode node, XmlReaderSettings setting)
381 // WebSiteと同じパッケージに指定された名前のクラスがあるかを探す
382 Type type = Type.GetType(typeof(Website).Namespace + "." + node.Name, false, true);
385 // 存在しない場合、そのままの名前でクラスを探索、無ければ例外スロー
386 type = Type.GetType(node.Name, true, true);
389 using (XmlReader r = XmlReader.Create(new StringReader(node.OuterXml), setting))
391 return new XmlSerializer(type).Deserialize(r) as Website;