1 // ================================================================================================
3 // アプリケーションの設定を保持するクラスソース</summary>
5 // <copyright file="Config.cs" company="honeplusのメモ帳">
6 // Copyright (C) 2011 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;
22 using Honememo.Wptscs.Utilities;
23 using Honememo.Wptscs.Websites;
26 /// アプリケーションの設定を保持するクラスです。
28 public class Config : IXmlSerializable
33 /// アプリケーション内でのインスタンス保持変数。
35 private static IDictionary<string, Config> configs = new Dictionary<string, Config>();
44 private IList<Language> languages = new List<Language>();
49 private IList<Website> websites = new List<Website>();
54 private IList<TranslationDictionary> itemTables = new List<TranslationDictionary>();
59 private TranslationTable headingTable = new TranslationTable();
68 /// <remarks>通常は<see cref="GetInstance(string)"/>を使用する。</remarks>
78 /// 翻訳支援処理で使用するロジッククラス名。
80 public Type Translator
89 /// <remarks>空でもオブジェクトは存在。</remarks>
90 public IList<Website> Websites
99 // ※必須な情報が設定されていない場合、例外を返す
100 this.websites = Validate.NotNull(value, "websites");
107 /// <remarks>空でもオブジェクトは存在。</remarks>
108 public IList<TranslationDictionary> ItemTables
112 return this.itemTables;
117 // ※必須な情報が設定されていない場合、例外を返す
118 this.itemTables = Validate.NotNull(value, "itemTables");
125 /// <remarks>空でもオブジェクトは存在。</remarks>
126 public TranslationTable HeadingTable
130 return this.headingTable;
135 // ※必須な情報が設定されていない場合、例外を返す
136 this.headingTable = Validate.NotNull(value, "headingTable");
145 /// アプリケーションの設定を取得する。
146 /// ユーザーごとの設定ファイルがあればその内容を、
147 /// なければアプリケーション標準の設定ファイルの内容を
148 /// 読み込んで、インスタンスを作成する。
150 /// <param name="file">設定ファイル名。</param>
151 /// <returns>作成した/既に存在するインスタンス。</returns>
152 public static Config GetInstance(string file)
154 // シングルトンとするため、処理をロック
157 // 既に作成済みのインスタンスがあればその値を使用
158 // (設定ファイルのタイムスタンプとか確認して再読み込みした方がよい?)
159 if (Config.configs.ContainsKey(file))
161 return Config.configs[file];
164 // 無い場合はユーザーごと・または初期設定用の設定ファイルを読み込み
165 string path = FormUtils.SearchUserAppData(file, Settings.Default.ConfigurationCompatible);
166 if (String.IsNullOrEmpty(path))
169 // (空でnewしてもよいが、ユーザーが勘違いすると思うので。)
170 throw new FileNotFoundException(file + " is not found");
174 System.Diagnostics.Debug.WriteLine("Config.GetInstance > " + path + " を読み込み");
175 using (Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
177 Config.configs[file] = new XmlSerializer(typeof(Config)).Deserialize(stream) as Config;
181 return Config.configs[file];
189 /// 設定をユーザーごとの設定ファイルに書き出し。
191 /// <param name="file">設定ファイル名。</param>
192 public void Save(string file)
194 // ファイル出力のため、競合しないよう一応ロック
195 lock (Config.configs)
197 // 最初にディレクトリの有無を確認し作成
198 string path = Application.UserAppDataPath;
199 if (!Directory.Exists(path))
201 Directory.CreateDirectory(path);
205 using (Stream stream = new FileStream(
206 Path.Combine(path, file),
209 new XmlSerializer(typeof(Config)).Serialize(stream, this);
216 #region 設定値取得用インスタンスメソッド
219 /// 設定から、現在の処理対象・指定された言語のウェブサイトを取得する。
221 /// <param name="lang">言語コード。</param>
222 /// <returns>ウェブサイトの情報。存在しない場合は<c>null</c>返す。</returns>
223 public Website GetWebsite(string lang)
226 foreach (Website s in this.Websites)
228 if (s.Language.Code == lang)
235 // ※ こっちがNeedCreateじゃないのは、何をnewすればいいのか判らないため
240 /// 設定から、現在の処理対象・指定された言語の対訳表(項目)を取得する。
242 /// <param name="from">翻訳元言語。</param>
243 /// <param name="to">翻訳先言語。</param>
244 /// <returns>対訳表の情報。存在しない場合は新たに作成した対訳表を返す。</returns>
245 public TranslationDictionary GetItemTableNeedCreate(string from, string to)
247 // オブジェクトに用意されている共通メソッドをコール
248 return TranslationDictionary.GetDictionaryNeedCreate(this.ItemTables, from, to);
253 #region XMLシリアライズ用メソッド
256 /// シリアライズするXMLのスキーマ定義を返す。
258 /// <returns>XML表現を記述するXmlSchema。</returns>
259 public System.Xml.Schema.XmlSchema GetSchema()
265 /// XMLからオブジェクトを読み込む。
267 /// <param name="reader">読込元のXmlReader</param>
268 public void ReadXml(XmlReader reader)
270 XmlDocument xml = new XmlDocument();
274 // ※ 以下、基本的に無かったらNGの部分はいちいちチェックしない。例外飛ばす
275 XmlElement rootElement = xml.DocumentElement;
278 this.Translator = this.ParseTranslator(rootElement.SelectSingleNode("Translator").InnerText);
281 foreach (XmlNode siteNode in rootElement.SelectSingleNode("Websites").ChildNodes)
283 // ノードに指定された内容に応じたインスタンスを取得する
284 this.Websites.Add(this.ParseWebsite(siteNode, reader.Settings));
288 XmlSerializer serializer = new XmlSerializer(typeof(TranslationDictionary), new XmlRootAttribute("ItemTable"));
289 foreach (XmlNode itemNode in rootElement.SelectSingleNode("ItemTables").ChildNodes)
291 using (XmlReader r = XmlReader.Create(new StringReader(itemNode.OuterXml), reader.Settings))
293 this.ItemTables.Add(serializer.Deserialize(r) as TranslationDictionary);
298 using (XmlReader r = XmlReader.Create(
299 new StringReader(rootElement.SelectSingleNode("HeadingTable").OuterXml),
302 this.HeadingTable = new XmlSerializer(typeof(TranslationTable), new XmlRootAttribute("HeadingTable"))
303 .Deserialize(r) as TranslationTable;
310 /// <param name="writer">出力先のXmlWriter</param>
311 public void WriteXml(XmlWriter writer)
314 string translator = this.Translator.FullName;
315 if (translator.StartsWith(typeof(Translator).Namespace))
317 // 自前のエンジンの場合、クラス名だけを出力
318 translator = this.Translator.Name;
321 writer.WriteElementString("Translator", translator);
324 writer.WriteStartElement("Websites");
325 foreach (Website site in this.Websites)
327 // 通常はサイトのパッケージ名も含めたフル名を要素名とする
328 string siteName = site.GetType().FullName;
329 if (siteName.StartsWith(typeof(Website).Namespace))
331 // 自前のサイトの場合、クラス名だけを出力
332 siteName = site.GetType().Name;
335 new XmlSerializer(site.GetType(), new XmlRootAttribute(siteName)).Serialize(writer, site);
338 writer.WriteEndElement();
341 XmlSerializer serializer = new XmlSerializer(typeof(TranslationDictionary), new XmlRootAttribute("ItemTable"));
342 writer.WriteStartElement("ItemTables");
343 foreach (TranslationDictionary trans in this.ItemTables)
345 serializer.Serialize(writer, trans);
348 writer.WriteEndElement();
351 new XmlSerializer(this.HeadingTable.GetType(), new XmlRootAttribute("HeadingTable"))
352 .Serialize(writer, this.HeadingTable);
356 /// 指定されたXML値からTranslatorのクラスを取得するる。
358 /// <param name="name">XMLのクラス名情報。</param>
359 /// <returns>Translatorクラス。</returns>
360 /// <remarks>クラスは動的に判定する。クラスが存在しない場合などは随時状況に応じた例外を投げる。</remarks>
361 private Type ParseTranslator(string name)
363 // Translateと同じパッケージに指定された名前のクラスがあるかを探す
364 Type type = Type.GetType(typeof(Translator).Namespace + "." + name, false, true);
367 // 存在しない場合、そのままの名前でクラスを探索、無ければ例外スロー
368 type = Type.GetType(name, true, true);
375 /// XMLノードからWebSiteインスタンスをデシリアライズする。
377 /// <param name="node">WebSiteをシリアライズしたノード。</param>
378 /// <param name="setting">XML読み込み時の設定。</param>
379 /// <returns>デシリアライズしたインスタンス。</returns>
380 /// <remarks>クラスはノード名から動的に判定する。クラスが存在しない場合などは随時状況に応じた例外を投げる。</remarks>
381 private Website ParseWebsite(XmlNode node, XmlReaderSettings setting)
383 // WebSiteと同じパッケージに指定された名前のクラスがあるかを探す
384 Type type = Type.GetType(typeof(Website).Namespace + "." + node.Name, false, true);
387 // 存在しない場合、そのままの名前でクラスを探索、無ければ例外スロー
388 type = Type.GetType(node.Name, true, true);
391 using (XmlReader r = XmlReader.Create(new StringReader(node.OuterXml), setting))
393 return new XmlSerializer(type).Deserialize(r) as Website;