OSDN Git Service

#30244 Visual Studio 2012 Express for Windows Desktop, StyleCop 4.7, WiX 3.6 に合わせたソース...
[wptscs/wpts.git] / Wptscs / MainForm.cs
index 8662a13..b71612b 100644 (file)
@@ -13,10 +13,9 @@ namespace Honememo.Wptscs
     using System;
     using System.Collections.Generic;
     using System.ComponentModel;
-    using System.Data;
-    using System.Drawing;
     using System.IO;
-    using System.Text;
+    using System.Net;
+    using System.Threading;
     using System.Windows.Forms;
     using Honememo.Utilities;
     using Honememo.Wptscs.Logics;
@@ -47,6 +46,11 @@ namespace Honememo.Wptscs
         /// </summary>
         private int logLength;
 
+        /// <summary>
+        /// ステータス管理用オブジェクト。
+        /// </summary>
+        private StatusManager<string> statusManager;
+
         #endregion
 
         #region コンストラクタ
@@ -62,7 +66,7 @@ namespace Honememo.Wptscs
 
         #endregion
 
-        #region 各イベントのメソッド
+        #region フォームの各イベントのメソッド
 
         /// <summary>
         /// フォームロード時の処理。初期化。
@@ -71,27 +75,20 @@ namespace Honememo.Wptscs
         /// <param name="e">発生したイベント。</param>
         private void MainForm_Load(object sender, EventArgs e)
         {
-            // 設定ファイルの読み込み
-            if (!this.LoadConfig())
-            {
-                // 読み込み失敗時はどうしようもないのでそのまま終了
-                this.Close();
-            }
+            // フォームの初期設定
+            this.statusManager = new StatusManager<string>();
+            this.statusManager.Changed += new EventHandler(
+                delegate { this.toolStripStatusLabelStatus.Text = StringUtils.DefaultString(this.statusManager.Status); });
 
-            this.translator = null;
-            Control.CheckForIllegalCrossThreadCalls = false;
+            // 表示言語選択メニュー、設定選択メニューの初期設定
+            this.InitializeDropDownButtonLanguage();
+            this.InitializeDropDownButtonConfig();
 
-            // コンボボックス設定
-            this.Initialize();
+            // 設定ファイルの読み込みと関連項目の初期設定
+            this.InitializeByConfig();
 
-            // å\89\8då\9b\9eã\81®å\87¦ç\90\86ç\8a¶æ\85\8bを復元
+            // å\87ºå\8a\9bå\85\88ã\83\95ã\82©ã\83«ã\83\80ã\81®è¨­å®\9aを復元
             this.textBoxSaveDirectory.Text = Settings.Default.SaveDirectory;
-            this.comboBoxSource.SelectedText = Settings.Default.LastSelectedSource;
-            this.comboBoxTarget.SelectedText = Settings.Default.LastSelectedTarget;
-
-            // コンボボックス変更時の処理をコール
-            this.ComboBoxSource_SelectedIndexChanged(sender, e);
-            this.ComboBoxTarget_SelectedIndexChanged(sender, e);
         }
 
         /// <summary>
@@ -101,13 +98,16 @@ namespace Honememo.Wptscs
         /// <param name="e">発生したイベント。</param>
         private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
         {
-            // 現在の作業フォルダ、絞込み文字列を保存
-            Settings.Default.SaveDirectory = this.textBoxSaveDirectory.Text;
-            Settings.Default.LastSelectedSource = this.comboBoxSource.Text;
-            Settings.Default.LastSelectedTarget = this.comboBoxTarget.Text;
+            // 現在の出力先フォルダ、翻訳元/先言語、
+            // また更新されていれば表示言語や設定ファイルの選択を保存
+            this.SetSettings();
             Settings.Default.Save();
         }
 
+        #endregion
+
+        #region 翻訳元/先言語グループのイベントのメソッド
+
         /// <summary>
         /// 翻訳元コンボボックス変更時の処理。
         /// </summary>
@@ -116,42 +116,18 @@ namespace Honememo.Wptscs
         private void ComboBoxSource_SelectedIndexChanged(object sender, EventArgs e)
         {
             // ラベルに言語名を表示する
-            this.labelSource.Text = String.Empty;
-            this.linkLabelSourceURL.Text = "http://";
-            if (!String.IsNullOrWhiteSpace(this.comboBoxSource.Text))
-            {
-                this.comboBoxSource.Text = this.comboBoxSource.Text.Trim().ToLower();
-
-                // その言語の、ユーザーが使用している言語での表示名を表示
-                // (日本語環境だったら日本語を、英語だったら英語を)
-                Language.LanguageName name;
-                this.labelSource.Text = String.Empty;
-                if (this.config.GetWebsite(this.comboBoxSource.Text) != null &&
-                    this.config.GetWebsite(this.comboBoxSource.Text).Language.Names.TryGetValue(
-                    System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName,
-                    out name))
-                {
-                    this.labelSource.Text = name.Name;
-                }
+            Website site = this.config.GetWebsite(this.comboBoxSource.Text);
+            this.SetLanguageNameLabel(this.labelSource, site);
 
-                // サーバーURLの表示
-                this.linkLabelSourceURL.Text = this.config.GetWebsite(
-                    this.comboBoxSource.Text).Location;
+            // サーバーURLの表示
+            this.linkLabelSourceURL.Text = "http://";
+            if (site != null)
+            {
+                this.linkLabelSourceURL.Text = site.Location;
             }
         }
 
         /// <summary>
-        /// 翻訳元コンボボックスフォーカス喪失時の処理。
-        /// </summary>
-        /// <param name="sender">イベント発生オブジェクト。</param>
-        /// <param name="e">発生したイベント。</param>
-        private void ComboBoxSource_Leave(object sender, EventArgs e)
-        {
-            // 直接入力された場合の対策、変更時の処理をコール
-            this.ComboBoxSource_SelectedIndexChanged(sender, e);
-        }
-
-        /// <summary>
         /// リンクラベルのリンククリック時の処理。
         /// </summary>
         /// <param name="sender">イベント発生オブジェクト。</param>
@@ -170,60 +146,89 @@ namespace Honememo.Wptscs
         private void ComboBoxTarget_SelectedIndexChanged(object sender, EventArgs e)
         {
             // ラベルに言語名を表示する
-            this.labelTarget.Text = String.Empty;
-            if (!String.IsNullOrWhiteSpace(this.comboBoxTarget.Text))
-            {
-                this.comboBoxTarget.Text = this.comboBoxTarget.Text.Trim().ToLower();
-
-                // その言語の、ユーザーが使用している言語での表示名を表示
-                // (日本語環境だったら日本語を、英語だったら英語を)
-                if (this.config.GetWebsite(
-                    this.comboBoxTarget.Text) != null)
-                {
-                    this.labelTarget.Text = this.config.GetWebsite(
-                        this.comboBoxTarget.Text).Language.Names[System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName].Name;
-                }
-            }
+            this.SetLanguageNameLabel(this.labelTarget, this.config.GetWebsite(this.comboBoxTarget.Text));
         }
 
         /// <summary>
-        /// 翻訳先コンボボックスフォーカス喪失時の処理。
+        /// 設定ボタン押下時の処理。
         /// </summary>
         /// <param name="sender">イベント発生オブジェクト。</param>
         /// <param name="e">発生したイベント。</param>
-        private void ComboBoxTarget_Leave(object sender, EventArgs e)
+        private void ButtonConfig_Click(object sender, EventArgs e)
         {
-            // 直接入力された場合の対策、変更時の処理をコール
-            this.ComboBoxTarget_SelectedIndexChanged(sender, e);
+            // 現在の画面の表示状態を保存
+            this.SetSettings();
+
+            // 設定画面を開く
+            using (ConfigForm form = new ConfigForm(this.config))
+            {
+                form.ShowDialog();
+            }
+
+            // 戻ってきたら設定ファイルを再読み込みして表示を更新
+            // ※ キャンセル時もインスタンスは更新されてしまうので
+            this.InitializeByConfig();
         }
 
+        #region イベント実装支援用メソッド
+
         /// <summary>
-        /// 設定ボタン押下時の処理。
+        /// 翻訳元/先言語コンボボックスの初期化処理。
         /// </summary>
-        /// <param name="sender">イベント発生オブジェクト。</param>
-        /// <param name="e">発生したイベント。</param>
-        private void ButtonConfig_Click(object sender, EventArgs e)
+        private void InitializeComboBox()
         {
-            // 設定画面を開く
-            ConfigForm form = new ConfigForm(this.config);
-            form.ShowDialog();
+            // コンボボックス設定
+            this.comboBoxSource.Items.Clear();
+            this.comboBoxTarget.Items.Clear();
 
-            // 戻ってきたら設定ファイルを再読み込み
-            // ※ 万が一エラーでもとりあえず続行
-            this.LoadConfig();
+            // 設定ファイルに存在する全言語を選択肢として登録する
+            foreach (Website site in this.config.Websites)
+            {
+                this.comboBoxSource.Items.Add(site.Language.Code);
+                this.comboBoxTarget.Items.Add(site.Language.Code);
+            }
 
-            // コンボボックス設定
-            string backupSourceSelected = this.comboBoxSource.SelectedText;
-            string backupSourceTarget = this.comboBoxTarget.SelectedText;
-            this.Initialize();
-            this.comboBoxSource.SelectedText = backupSourceSelected;
-            this.comboBoxTarget.SelectedText = backupSourceTarget;
+            // 選択されていた項目を選択中に復元
+            this.comboBoxSource.SelectedItem = Settings.Default.LastSelectedSource;
+            this.comboBoxTarget.SelectedItem = Settings.Default.LastSelectedTarget;
 
             // コンボボックス変更時の処理をコール
-            this.ComboBoxSource_SelectedIndexChanged(sender, e);
-            this.ComboBoxTarget_SelectedIndexChanged(sender, e);
+            // ※ 項目が存在する場合は↑で自動的に呼ばれるが、無い場合は呼ばれないため
+            this.ComboBoxSource_SelectedIndexChanged(this.comboBoxSource, new EventArgs());
+            this.ComboBoxTarget_SelectedIndexChanged(this.comboBoxTarget, new EventArgs());
+        }
+
+        /// <summary>
+        /// ウェブサイトの言語の表示名ラベルの表示を設定する。
+        /// </summary>
+        /// <param name="label">言語の表示名用ラベル。</param>
+        /// <param name="site">選択されている言語のウェブサイト。</param>
+        private void SetLanguageNameLabel(Label label, Website site)
+        {
+            // ラベルを初期化
+            label.Text = string.Empty;
+            if (site == null)
+            {
+                return;
+            }
+
+            // ウェブサイトが空でない場合、その言語の、ユーザーが使用している言語での表示名を表示
+            // (日本語環境だったら日本語を、英語環境だったら英語を)
+            Language.LanguageName name;
+            if (site.Language.Names.TryGetValue(
+                Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName,
+                out name))
+            {
+                label.Text = name.Name;
+            }
         }
 
+        #endregion
+
+        #endregion
+
+        #region フォルダの選択グループのイベントのメソッド
+
         /// <summary>
         /// 参照ボタン押下時の処理。
         /// </summary>
@@ -232,7 +237,7 @@ namespace Honememo.Wptscs
         private void ButtonSaveDirectory_Click(object sender, EventArgs e)
         {
             // フォルダ名が入力されている場合、それを初期位置に設定
-            if (!String.IsNullOrEmpty(this.textBoxSaveDirectory.Text))
+            if (!string.IsNullOrEmpty(this.textBoxSaveDirectory.Text))
             {
                 this.folderBrowserDialogSaveDirectory.SelectedPath = this.textBoxSaveDirectory.Text;
             }
@@ -256,6 +261,10 @@ namespace Honememo.Wptscs
             this.textBoxSaveDirectory.Text = this.textBoxSaveDirectory.Text.Trim();
         }
 
+        #endregion
+
+        #region 記事を指定して実行グループのイベントのメソッド
+
         /// <summary>
         /// 実行ボタン押下時の処理。
         /// </summary>
@@ -264,26 +273,26 @@ namespace Honememo.Wptscs
         private void ButtonRun_Click(object sender, EventArgs e)
         {
             // フォーム入力値をチェック
-            if (String.IsNullOrWhiteSpace(this.comboBoxSource.Text))
+            if (string.IsNullOrWhiteSpace(this.comboBoxSource.Text))
             {
                 FormUtils.WarningDialog(Resources.WarningMessageNotSelectedSource);
                 this.comboBoxSource.Focus();
                 return;
             }
-            else if (String.IsNullOrWhiteSpace(this.comboBoxTarget.Text))
+            else if (string.IsNullOrWhiteSpace(this.comboBoxTarget.Text))
             {
                 FormUtils.WarningDialog(Resources.WarningMessageNotSelectedTarget);
                 this.comboBoxTarget.Focus();
                 return;
             }
-            else if (!String.IsNullOrWhiteSpace(this.comboBoxSource.Text)
+            else if (!string.IsNullOrWhiteSpace(this.comboBoxSource.Text)
                 && this.comboBoxSource.Text == this.comboBoxTarget.Text)
             {
                 FormUtils.WarningDialog(Resources.WarningMessageEqualsSourceAndTarget);
                 this.comboBoxTarget.Focus();
                 return;
             }
-            else if (String.IsNullOrWhiteSpace(this.textBoxSaveDirectory.Text))
+            else if (string.IsNullOrWhiteSpace(this.textBoxSaveDirectory.Text))
             {
                 FormUtils.WarningDialog(Resources.WarningMessageEmptySaveDirectory);
                 this.textBoxSaveDirectory.Focus();
@@ -295,7 +304,7 @@ namespace Honememo.Wptscs
                 this.textBoxSaveDirectory.Focus();
                 return;
             }
-            else if (String.IsNullOrWhiteSpace(this.textBoxArticle.Text))
+            else if (string.IsNullOrWhiteSpace(this.textBoxArticle.Text))
             {
                 FormUtils.WarningDialog(Resources.WarningMessageEmptyArticle);
                 this.textBoxArticle.Focus();
@@ -305,6 +314,13 @@ namespace Honememo.Wptscs
             // 画面をロック
             this.LockOperation();
 
+            // 表示領域を初期化、処理時間更新用にタイマーを起動
+            this.textBoxLog.Clear();
+            this.logLength = 0;
+            this.textBoxLog.AppendText(string.Format(Resources.LogMessageStart, FormUtils.ApplicationName(), DateTime.Now));
+            this.toolStripStatusLabelStopwatch.Text = string.Format(Resources.ElapsedTime, TimeSpan.Zero);
+            this.timerStatusStopwatch.Start();
+
             // バックグラウンド処理を実行
             this.backgroundWorkerRun.RunWorkerAsync();
         }
@@ -318,8 +334,10 @@ namespace Honememo.Wptscs
         {
             // 処理を中断
             this.buttonStop.Enabled = false;
-            if (this.backgroundWorkerRun.IsBusy == true)
+            if (this.backgroundWorkerRun.IsBusy)
             {
+                // ※ CancelAsyncだけにしたいが、それをTranslatorに伝播させる方法
+                //    がないため直接そちらにも設定
                 System.Diagnostics.Debug.WriteLine("MainForm.-Stop_Click > 処理中断");
                 this.backgroundWorkerRun.CancelAsync();
                 if (this.translator != null)
@@ -336,57 +354,46 @@ namespace Honememo.Wptscs
         /// <param name="e">発生したイベント。</param>
         private void BackgroundWorkerRun_DoWork(object sender, DoWorkEventArgs e)
         {
-            try
-            {
-                // 初期化と開始メッセージ
-                this.textBoxLog.Clear();
-                this.logLength = 0;
-                this.textBoxLog.AppendText(String.Format(Resources.LogMessageStart, FormUtils.ApplicationName(), DateTime.Now.ToString("F")));
+            // 戻り値を失敗で初期化
+            e.Result = false;
 
-                // 翻訳支援処理ロジックのオブジェクトを生成
-                try
-                {
-                    this.translator = Translator.Create(this.config, this.comboBoxSource.Text, this.comboBoxTarget.Text);
-                }
-                catch (NotImplementedException)
-                {
-                    // 設定ファイルに対応していないパターンが書かれている場合の例外、将来の拡張用
-                    this.textBoxLog.AppendText(String.Format(Resources.InformationMessageDevelopingMethod, "Wikipedia以外の処理"));
-                    FormUtils.InformationDialog(Resources.InformationMessageDevelopingMethod, "Wikipedia以外の処理");
-                    return;
-                }
+            // 別スレッドになるので表示言語を再度設定
+            Program.LoadSelectedCulture();
 
-                // ログ・処理状態更新通知を受け取るためのイベント登録
-                // 処理時間更新用にタイマーを起動
-                this.translator.LogUpdate += new EventHandler(this.GetLogUpdate);
-                this.translator.StatusUpdate += new EventHandler(this.GetStatusUpdate);
-                this.Invoke((MethodInvoker)delegate { this.timerStatusStopwatch.Start(); });
+            // フォーム要素から必要なパラメータ一式を取得
+            string source = null;
+            string target = null;
+            string title = null;
+            this.Invoke((MethodInvoker)delegate
+            {
+                source = this.comboBoxSource.Text;
+                target = this.comboBoxTarget.Text;
+                title = this.textBoxArticle.Text.Trim();
+            });
 
-                // 翻訳支援処理を実行
-                bool success = true;
-                try
-                {
-                    this.translator.Run(this.textBoxArticle.Text.Trim());
-                }
-                catch (ApplicationException)
-                {
-                    // 中止要求で停止した場合、その旨イベントに格納する
-                    e.Cancel = this.backgroundWorkerRun.CancellationPending;
-                    success = false;
-                }
-                finally
-                {
-                    // 処理時間更新用のタイマーを終了
-                    this.Invoke((MethodInvoker)delegate { this.timerStatusStopwatch.Stop(); });
-                }
+            // 翻訳支援処理ロジックのオブジェクトを生成
+            this.translator = Translator.Create(this.config, source, target);
 
-                // 実行結果から、ログと変換後テキストをファイル出力
-                this.WriteResult(success);
+            // ログ・処理状態更新通知を受け取るためのイベント登録
+            this.translator.LogUpdated += new EventHandler(
+                delegate { this.Invoke((MethodInvoker)delegate { this.UpdateLog(); }); });
+            this.translator.StatusUpdated += new EventHandler(
+                delegate { this.Invoke((MethodInvoker)delegate { this.statusManager.Status = this.translator.Status; }); });
+
+            // 翻訳支援処理を実行
+            try
+            {
+                this.translator.Run(title);
             }
-            catch (Exception ex)
+            catch (ApplicationException)
             {
-                this.textBoxLog.AppendText("\r\n" + String.Format(Resources.ErrorMessageDevelopmentError, ex.Message, ex.StackTrace) + "\r\n");
+                // 中止要求で停止した場合、その旨イベントに格納する
+                e.Cancel = this.backgroundWorkerRun.CancellationPending;
+                return;
             }
+
+            // ここまで成功した場合のみ処理結果を成功とする
+            e.Result = true;
         }
 
         /// <summary>
@@ -396,108 +403,57 @@ namespace Honememo.Wptscs
         /// <param name="e">発生したイベント。</param>
         private void BackgroundWorkerRun_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
         {
-            // 設定ファイルのキャッシュ情報を更新
-            // ※ 微妙に時間がかかるので、ステータスバーに通知
-            try
+            // 中止ボタンをロック、処理時間更新用のタイマーを終了
+            this.buttonStop.Enabled = false;
+            this.timerStatusStopwatch.Stop();
+
+            if (e.Error != null)
             {
-                this.toolStripStatusLabelStatus.Text = Resources.StatusCacheUpdating;
-                try
+                // 処理中で想定外のエラーが発生していた場合ここで通知
+                if (e.Error is WebException)
                 {
-                    this.config.Save(Settings.Default.ConfigurationFile);
+                    // 想定外の通信エラー(↓とまとめてもよいが、こちらはサーバーの状況などで発生しやすいので)
+                    WebException ex = (WebException)e.Error;
+                    this.textBoxLog.AppendText(Environment.NewLine + string.Format(Resources.ErrorMessageConnectionFailed, ex.Message) + Environment.NewLine);
+                    if (ex.Response != null)
+                    {
+                        // 出せるならエラーとなったURLも出力
+                        this.textBoxLog.AppendText(Resources.RightArrow + " " + string.Format(Resources.LogMessageErrorURL, ex.Response.ResponseUri) + Environment.NewLine);
+                    }
                 }
-                finally
+                else
                 {
-                    this.toolStripStatusLabelStatus.Text = String.Empty;
+                    // 想定外のエラー
+                    this.textBoxLog.AppendText(Environment.NewLine + string.Format(Resources.ErrorMessageDevelopmentError, e.Error.Message, e.Error.StackTrace) + Environment.NewLine);
                 }
             }
-            catch (Exception ex)
-            {
-                FormUtils.WarningDialog(
-                    Resources.WarningMessageCacheSaveFailed,
-                    ex.Message);
-            }
-
-            // 画面をロック中から解放
-            this.Release();
-        }
-
-        /// <summary>
-        /// ステータスバー処理時間更新タイマー処理。
-        /// </summary>
-        /// <param name="sender">イベント発生オブジェクト。</param>
-        /// <param name="e">発生したイベント。</param>
-        private void TimerStatusStopwatch_Tick(object sender, EventArgs e)
-        {
-            // 処理時間をステータスバーに反映
-            this.toolStripStatusLabelStopwatch.Text = String.Format(Resources.ElapsedTime, this.translator.Stopwatch.Elapsed);
-        }
-
-        #endregion
-
-        #region それ以外のメソッド
-
-        /// <summary>
-        /// 画面初期化処理。
-        /// </summary>
-        private void Initialize()
-        {
-            // コンボボックス設定
-            this.comboBoxSource.Items.Clear();
-            this.comboBoxTarget.Items.Clear();
-
-            // 設定ファイルに存在する全言語を選択肢として登録する
-            foreach (Website site in this.config.Websites)
+            else
             {
-                this.comboBoxSource.Items.Add(site.Language.Code);
-                this.comboBoxTarget.Items.Add(site.Language.Code);
-            }
-        }
+                // 実行結果から、ログと変換後テキストをファイル出力
+                this.WriteResult(!e.Cancelled && (bool)e.Result);
 
-        /// <summary>
-        /// 設定ファイル読み込み。
-        /// </summary>
-        /// <returns>読み込み成功時は<c>true</c>。</returns>
-        private bool LoadConfig()
-        {
-            // 設定ファイルの読み込み
-            // ※ 微妙に時間がかかるので、ステータスバーに通知
-            try
-            {
-                this.toolStripStatusLabelStatus.Text = Resources.StatusConfigReading;
+                // 設定ファイルのキャッシュ情報を更新
                 try
                 {
-                    this.config = Config.GetInstance(Settings.Default.ConfigurationFile);
+                    // ※ 微妙に時間がかかるので、ステータスバーに通知
+                    using (var sm = this.statusManager.Switch(Resources.StatusCacheUpdating))
+                    {
+                        this.config.Save();
+                    }
                 }
-                finally
+                catch (Exception ex)
                 {
-                    this.toolStripStatusLabelStatus.Text = String.Empty;
+                    FormUtils.WarningDialog(Resources.WarningMessageCacheSaveFailed, ex.Message);
                 }
             }
-            catch (FileNotFoundException ex)
-            {
-                // 設定ファイルが見つからない場合
-                System.Diagnostics.Debug.WriteLine(
-                    "MainForm.LoadConfig > 設定ファイル読み込み失敗 : " + ex.Message);
-                FormUtils.ErrorDialog(
-                    Resources.ErrorMessageConfigNotFound,
-                    Settings.Default.ConfigurationFile);
-
-                return false;
-            }
-            catch (Exception ex)
-            {
-                System.Diagnostics.Debug.WriteLine(
-                    "MainForm.LoadConfig > 設定ファイル読み込み時エラー : " + ex.StackTrace);
-                FormUtils.ErrorDialog(
-                    Resources.ErrorMessageConfigLordFailed,
-                    ex.Message);
-
-                return false;
-            }
 
-            return true;
+            // 画面をロック中から戻す、トランスレータを解放
+            this.Release();
+            this.translator = null;
         }
 
+        #region イベント実装支援用メソッド
+
         /// <summary>
         /// 画面をロック中に移行。
         /// </summary>
@@ -508,6 +464,8 @@ namespace Honememo.Wptscs
             this.groupBoxSaveDirectory.Enabled = false;
             this.textBoxArticle.Enabled = false;
             this.buttonRun.Enabled = false;
+            this.toolStripDropDownButtonLanguage.Enabled = false;
+            this.toolStripDropDownButtonConfig.Enabled = false;
 
             // 中止ボタンを有効に変更
             this.buttonStop.Enabled = true;
@@ -526,6 +484,8 @@ namespace Honememo.Wptscs
             this.groupBoxSaveDirectory.Enabled = true;
             this.textBoxArticle.Enabled = true;
             this.buttonRun.Enabled = true;
+            this.toolStripDropDownButtonLanguage.Enabled = true;
+            this.toolStripDropDownButtonConfig.Enabled = true;
         }
 
         /// <summary>
@@ -535,8 +495,7 @@ namespace Honememo.Wptscs
         private void WriteResult(bool success)
         {
             // 若干時間がかかるのでステータスバーに通知
-            this.toolStripStatusLabelStatus.Text = Resources.StatusFileWriting;
-            try
+            using (var sm = this.statusManager.Switch(Resources.StatusFileWriting))
             {
                 // 使用可能な出力ファイル名を生成
                 string fileName;
@@ -549,17 +508,17 @@ namespace Honememo.Wptscs
                     try
                     {
                         File.WriteAllText(Path.Combine(this.textBoxSaveDirectory.Text, fileName), this.translator.Text);
-                        this.textBoxLog.AppendText(String.Format(Resources.LogMessageEnd, fileName, logName));
+                        this.textBoxLog.AppendText(string.Format(Resources.LogMessageEnd, fileName, logName));
                     }
                     catch (Exception ex)
                     {
-                        this.textBoxLog.AppendText(String.Format(Resources.LogMessageFileSaveFailed, Path.Combine(this.textBoxSaveDirectory.Text, fileName), ex.Message));
-                        this.textBoxLog.AppendText(String.Format(Resources.LogMessageStop, logName));
+                        this.textBoxLog.AppendText(string.Format(Resources.LogMessageFileSaveFailed, Path.Combine(this.textBoxSaveDirectory.Text, fileName), ex.Message));
+                        this.textBoxLog.AppendText(string.Format(Resources.LogMessageStop, logName));
                     }
                 }
                 else
                 {
-                    this.textBoxLog.AppendText(String.Format(Resources.LogMessageStop, logName));
+                    this.textBoxLog.AppendText(string.Format(Resources.LogMessageStop, logName));
                 }
 
                 // ログを出力
@@ -569,14 +528,9 @@ namespace Honememo.Wptscs
                 }
                 catch (Exception ex)
                 {
-                    this.textBoxLog.AppendText(String.Format(Resources.LogMessageFileSaveFailed, Path.Combine(this.textBoxSaveDirectory.Text, logName), ex.Message));
+                    this.textBoxLog.AppendText(string.Format(Resources.LogMessageFileSaveFailed, Path.Combine(this.textBoxSaveDirectory.Text, logName), ex.Message));
                 }
             }
-            finally
-            {
-                // ステータスバーをクリア
-                this.toolStripStatusLabelStatus.Text = String.Empty;
-            }
         }
 
         /// <summary>
@@ -586,7 +540,7 @@ namespace Honememo.Wptscs
         /// <param name="logName">出力ログファイル名。</param>
         /// <param name="text">出力する結果テキスト。</param>
         /// <param name="dir">出力先ディレクトリ。</param>
-        /// <returns><c>true</c> 出力成功</returns>
+        /// <returns>出力成功の場合<c>true</c>。</returns>
         private bool MakeFileName(out string fileName, out string logName, string text, string dir)
         {
             // 出力先フォルダに存在しないファイル名(の拡張子より前)を作成
@@ -598,7 +552,7 @@ namespace Honememo.Wptscs
             bool success = false;
             for (int i = 0; i < 100000; i++)
             {
-                // ※100000まで試して空きが見つからないことは無いはず、もし見つからなかったら最後のを上書き
+                // ※ 100000まで試して空きが見つからないことは無いはず、もし見つからなかったら最後のを上書き
                 if (!File.Exists(Path.Combine(dir, fileName))
                     && !File.Exists(Path.Combine(dir, logName)))
                 {
@@ -615,11 +569,9 @@ namespace Honememo.Wptscs
         }
 
         /// <summary>
-        /// 翻訳支援処理クラスのログ更新イベント用
+        /// 翻訳支援処理クラスのログ更新反映
         /// </summary>
-        /// <param name="sender">イベント発生オブジェクト。</param>
-        /// <param name="e">発生したイベント。</param>
-        private void GetLogUpdate(object sender, EventArgs e)
+        private void UpdateLog()
         {
             // 前回以降に追加されたログをテキストボックスに出力
             int length = this.translator.Log.Length;
@@ -631,15 +583,307 @@ namespace Honememo.Wptscs
             this.logLength = length;
         }
 
+        #endregion
+
+        #endregion
+
+        #region ステータスバーのイベントのメソッド
+
+        /// <summary>
+        /// ステータスバー処理時間更新タイマー処理。
+        /// </summary>
+        /// <param name="sender">イベント発生オブジェクト。</param>
+        /// <param name="e">発生したイベント。</param>
+        private void TimerStatusStopwatch_Tick(object sender, EventArgs e)
+        {
+            if (this.translator != null)
+            {
+                // 処理時間をステータスバーに反映
+                this.toolStripStatusLabelStopwatch.Text = string.Format(Resources.ElapsedTime, this.translator.Stopwatch.Elapsed);
+            }
+        }
+
+        /// <summary>
+        /// 表示言語選択メニュー日本語クリック時の処理。
+        /// </summary>
+        /// <param name="sender">イベント発生オブジェクト。</param>
+        /// <param name="e">発生したイベント。</param>
+        private void ToolStripMenuItemJapanese_Click(object sender, EventArgs e)
+        {
+            // 表示言語を日本語に設定し再起動する
+            this.ChangeCultureAndRestart("ja-JP");
+        }
+
+        /// <summary>
+        /// 表示言語選択メニュー英語(US)クリック時の処理。
+        /// </summary>
+        /// <param name="sender">イベント発生オブジェクト。</param>
+        /// <param name="e">発生したイベント。</param>
+        private void ToolStripMenuItemEnglishUS_Click(object sender, EventArgs e)
+        {
+            // 表示言語を英語(US)に設定し再起動する
+            this.ChangeCultureAndRestart("en-US");
+        }
+
+        /// <summary>
+        /// 表示言語選択メニュー英語(GB)クリック時の処理。
+        /// </summary>
+        /// <param name="sender">イベント発生オブジェクト。</param>
+        /// <param name="e">発生したイベント。</param>
+        private void ToolStripMenuItemEnglishGB_Click(object sender, EventArgs e)
+        {
+            // 表示言語を英語(GB)に設定し再起動する
+            this.ChangeCultureAndRestart("en-GB");
+        }
+
+        /// <summary>
+        /// 表示言語選択メニュー自動クリック時の処理。
+        /// </summary>
+        /// <param name="sender">イベント発生オブジェクト。</param>
+        /// <param name="e">発生したイベント。</param>
+        private void ToolStripMenuItemAuto_Click(object sender, EventArgs e)
+        {
+            // 表示言語を空欄に設定し再起動する
+            this.ChangeCultureAndRestart(string.Empty);
+        }
+
+        /// <summary>
+        /// 設定選択メニュークリック時の処理。
+        /// </summary>
+        /// <param name="sender">イベント発生オブジェクト。</param>
+        /// <param name="e">発生したイベント。</param>
+        private void ToolStripMenuItemConfig_Click(object sender, EventArgs e)
+        {
+            // メニュー項目を一旦全て未選択状態に更新
+            foreach (ToolStripMenuItem i in this.toolStripDropDownButtonConfig.DropDownItems)
+            {
+                i.Checked = false;
+                i.Enabled = true;
+            }
+
+            // メニュー項目名から設定ファイル名を作成、再読み込みする
+            ToolStripMenuItem item = (ToolStripMenuItem)sender;
+            Settings.Default.LastSelectedConfiguration = item.Text;
+            this.SetSettings();
+            this.InitializeByConfig();
+        }
+
         /// <summary>
-        /// 翻訳支援処理クラスの処理状態更新イベント用
+        /// 設定選択メニュー追加クリック時の処理
         /// </summary>
         /// <param name="sender">イベント発生オブジェクト。</param>
         /// <param name="e">発生したイベント。</param>
-        private void GetStatusUpdate(object sender, EventArgs e)
+        private void ToolStripMenuItemNew_Click(object sender, EventArgs e)
+        {
+            // 重複チェック用の登録済みの設定一覧を用意
+            IList<string> configNames = new List<string>();
+            foreach (ToolStripMenuItem item in this.toolStripDropDownButtonConfig.DropDownItems)
+            {
+                if (item != this.toolStripMenuItemNew)
+                {
+                    configNames.Add(item.Text);
+                }
+            }
+
+            // 設定追加用ダイアログで言語コードを入力
+            using (AddConfigDialog form = new AddConfigDialog(configNames))
+            {
+                if (form.ShowDialog() == DialogResult.OK)
+                {
+                    // 設定選択メニューに新しい設定を追加。
+                    // 設定ファイルが作成されているため、それを読み込みなおす。
+                    this.ToolStripMenuItemConfig_Click(
+                        this.AddToolStripDropDownButtonConfigItem(form.ConfigName),
+                        e);
+                }
+            }
+        }
+
+        #region イベント実装支援用メソッド
+
+        /// <summary>
+        /// 表示言語選択メニューの初期化処理。
+        /// </summary>
+        private void InitializeDropDownButtonLanguage()
+        {
+            // 選択中の言語のメニュー項目を抽出
+            ToolStripMenuItem item;
+            switch (Settings.Default.LastSelectedLanguage)
+            {
+                case "en-US":
+                    item = this.toolStripMenuItemEnglishUS;
+                    break;
+                case "en-GB":
+                    item = this.toolStripMenuItemEnglishGB;
+                    break;
+                case "ja-JP":
+                    item = this.toolStripMenuItemJapanese;
+                    break;
+                default:
+                    item = this.toolStripMenuItemAuto;
+                    break;
+            }
+
+            // 選択中の項目をチェック状態&押下不能とする
+            item.Checked = true;
+            item.Enabled = false;
+            if (item != this.toolStripMenuItemAuto)
+            {
+                // 自動以外の場合、ステータスバーの表示も更新
+                this.toolStripDropDownButtonLanguage.Text = item.Text;
+            }
+        }
+
+        /// <summary>
+        /// 設定ファイル選択メニューの初期化処理。
+        /// </summary>
+        private void InitializeDropDownButtonConfig()
+        {
+            // exeまたはユーザーフォルダにある設定ファイルをメニュー項目としてリストアップ
+            foreach (string file in FormUtils.GetFilesAtUserAppData(
+                "*" + Settings.Default.ConfigurationExtension,
+                Settings.Default.ConfigurationCompatible))
+            {
+                try
+                {
+                    // 関係ないXMLファイルを除外するため、読み込めるフォーマットかをチェック
+                    // ※ ちょっと時間がかかるが・・・
+                    Config.GetInstance(file);
+
+                    // 問題なければファイル名を見出しにメニューに追加
+                    this.AddToolStripDropDownButtonConfigItem(Path.GetFileNameWithoutExtension(file));
+                }
+                catch (Exception ex)
+                {
+                    System.Diagnostics.Debug.WriteLine(
+                        "MainForm.InitializeDropDownButtonConfig : " + ex.Message);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 設定選択メニューに新しい設定を追加する。
+        /// </summary>
+        /// <param name="name">設定名。</param>
+        /// <returns>追加したメニュー。</returns>
+        /// <remarks>追加メニューがあるのでその後ろに登録する。</remarks>
+        private ToolStripMenuItem AddToolStripDropDownButtonConfigItem(string name)
+        {
+            // 設定変更のイベントを設定する
+            ToolStripMenuItem item = new ToolStripMenuItem();
+            item.Text = name;
+            item.Click += new EventHandler(this.ToolStripMenuItemConfig_Click);
+            this.toolStripDropDownButtonConfig.DropDownItems.Insert(
+                this.toolStripDropDownButtonConfig.DropDownItems.Count - 1,
+                item);
+            return item;
+        }
+
+        /// <summary>
+        /// アプリケーションの現在の表示言語を変更、再起動する。
+        /// </summary>
+        /// <param name="name">変更先カルチャ名。</param>
+        /// <remarks>このメソッドを呼び出すとアプリケーションが一旦終了します。</remarks>
+        private void ChangeCultureAndRestart(string name)
+        {
+            // 現在の画面表示と表示言語設定を保存した後、アプリケーションを再起動
+            this.SetSettings();
+            Settings.Default.LastSelectedLanguage = name;
+            Settings.Default.Save();
+            Application.Restart();
+            this.Close();
+        }
+
+        #endregion
+
+        #endregion
+
+        #region その他のメソッド
+
+        /// <summary>
+        /// 設定ファイルによる初期化処理。
+        /// </summary>
+        /// <remarks>
+        /// 読み込みに失敗した場合、空の設定を登録し、操作の大半をロックする
+        /// (設定変更メニューから正しい設定に変更されることを期待)。
+        /// </remarks>
+        private void InitializeByConfig()
         {
-            // 処理状態をステータスバーに通知
-            this.toolStripStatusLabelStatus.Text = this.translator.Status;
+            // 設定ファイルの読み込み
+            this.LoadConfig();
+            if (this.config == null)
+            {
+                // 読み込みに失敗した場合、空の設定を作成(設定値には適当な値を設定)
+                // 設定選択メニューの表示を更新し、画面をほぼ操作不可に変更
+                this.config = new Config();
+                this.groupBoxTransfer.Enabled = false;
+                this.groupBoxSaveDirectory.Enabled = false;
+                this.groupBoxRun.Enabled = false;
+                this.toolStripDropDownButtonConfig.Text = Resources.DropDownConfigLoadConfigFailed;
+            }
+            else
+            {
+                // 設定選択メニューの表示を更新し、画面を操作可能な状態に戻す
+                this.groupBoxTransfer.Enabled = true;
+                this.groupBoxSaveDirectory.Enabled = true;
+                this.groupBoxRun.Enabled = true;
+                this.toolStripDropDownButtonConfig.Text = Path.GetFileNameWithoutExtension(this.config.File);
+                foreach (ToolStripMenuItem item in this.toolStripDropDownButtonConfig.DropDownItems)
+                {
+                    // 読み込んだ設定を選択中(チェック状態&押下不能)に更新
+                    if (item != this.toolStripMenuItemNew
+                        && item.Text == this.toolStripDropDownButtonConfig.Text)
+                    {
+                        item.Checked = true;
+                        item.Enabled = false;
+                    }
+                }
+            }
+
+            // コンボボックスを読み込んだ設定で初期化
+            this.InitializeComboBox();
+        }
+
+        /// <summary>
+        /// 設定ファイル読み込み。
+        /// </summary>
+        private void LoadConfig()
+        {
+            // 設定ファイルの読み込み
+            string file = Settings.Default.LastSelectedConfiguration + Settings.Default.ConfigurationExtension;
+            try
+            {
+                // ※ 微妙に時間がかかるので、ステータスバーに通知
+                using (var sm = this.statusManager.Switch(Resources.StatusConfigReading))
+                {
+                    this.config = Config.GetInstance(file);
+                }
+            }
+            catch (FileNotFoundException ex)
+            {
+                // 設定ファイルが見つからない場合、エラーメッセージを表示
+                System.Diagnostics.Debug.WriteLine(
+                    "MainForm.LoadConfig > 設定ファイル読み込み失敗 : " + ex.Message);
+                FormUtils.ErrorDialog(Resources.ErrorMessageConfigNotFound, file);
+            }
+            catch (Exception ex)
+            {
+                // その他の例外(権限が無いとかファイルが壊れているとか)
+                System.Diagnostics.Debug.WriteLine(
+                    "MainForm.LoadConfig > 設定ファイル読み込み時エラー : " + ex.ToString());
+                FormUtils.ErrorDialog(Resources.ErrorMessageConfigLordFailed, ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// 現在の出力先フォルダ、翻訳元/先言語をアプリケーション設定に反映。
+        /// </summary>
+        /// <remarks>表示言語や設定ファイルの選択については必要な場合のみ別途実施。</remarks>
+        private void SetSettings()
+        {
+            Settings.Default.SaveDirectory = this.textBoxSaveDirectory.Text;
+            Settings.Default.LastSelectedSource = this.comboBoxSource.Text;
+            Settings.Default.LastSelectedTarget = this.comboBoxTarget.Text;
         }
 
         #endregion