OSDN Git Service

#30244 Visual Studio 2012 Express for Windows Desktop, StyleCop 4.7, WiX 3.6 に合わせたソース...
[wptscs/wpts.git] / Wptscs / MainForm.cs
1 // ================================================================================================
2 // <summary>
3 //      Wikipedia翻訳支援ツール主画面クラスソース</summary>
4 //
5 // <copyright file="MainForm.cs" company="honeplusのメモ帳">
6 //      Copyright (C) 2012 Honeplus. All rights reserved.</copyright>
7 // <author>
8 //      Honeplus</author>
9 // ================================================================================================
10
11 namespace Honememo.Wptscs
12 {
13     using System;
14     using System.Collections.Generic;
15     using System.ComponentModel;
16     using System.IO;
17     using System.Net;
18     using System.Threading;
19     using System.Windows.Forms;
20     using Honememo.Utilities;
21     using Honememo.Wptscs.Logics;
22     using Honememo.Wptscs.Models;
23     using Honememo.Wptscs.Properties;
24     using Honememo.Wptscs.Utilities;
25     using Honememo.Wptscs.Websites;
26
27     /// <summary>
28     /// Wikipedia翻訳支援ツール主画面のクラスです。
29     /// </summary>
30     public partial class MainForm : Form
31     {
32         #region private変数
33
34         /// <summary>
35         /// 現在読み込んでいるアプリケーションの設定。
36         /// </summary>
37         private Config config;
38
39         /// <summary>
40         /// 検索支援処理クラスのオブジェクト。
41         /// </summary>
42         private Translator translator;
43
44         /// <summary>
45         /// 表示済みログ文字列長。
46         /// </summary>
47         private int logLength;
48
49         /// <summary>
50         /// ステータス管理用オブジェクト。
51         /// </summary>
52         private StatusManager<string> statusManager;
53
54         #endregion
55
56         #region コンストラクタ
57
58         /// <summary>
59         /// コンストラクタ。初期化メソッド呼び出しのみ。
60         /// </summary>
61         public MainForm()
62         {
63             // Windows フォーム デザイナで生成されたコード
64             this.InitializeComponent();
65         }
66
67         #endregion
68
69         #region フォームの各イベントのメソッド
70
71         /// <summary>
72         /// フォームロード時の処理。初期化。
73         /// </summary>
74         /// <param name="sender">イベント発生オブジェクト。</param>
75         /// <param name="e">発生したイベント。</param>
76         private void MainForm_Load(object sender, EventArgs e)
77         {
78             // フォームの初期設定
79             this.statusManager = new StatusManager<string>();
80             this.statusManager.Changed += new EventHandler(
81                 delegate { this.toolStripStatusLabelStatus.Text = StringUtils.DefaultString(this.statusManager.Status); });
82
83             // 表示言語選択メニュー、設定選択メニューの初期設定
84             this.InitializeDropDownButtonLanguage();
85             this.InitializeDropDownButtonConfig();
86
87             // 設定ファイルの読み込みと関連項目の初期設定
88             this.InitializeByConfig();
89
90             // 出力先フォルダの設定を復元
91             this.textBoxSaveDirectory.Text = Settings.Default.SaveDirectory;
92         }
93
94         /// <summary>
95         /// フォームクローズ時の処理。処理状態を保存。
96         /// </summary>
97         /// <param name="sender">イベント発生オブジェクト。</param>
98         /// <param name="e">発生したイベント。</param>
99         private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
100         {
101             // 現在の出力先フォルダ、翻訳元/先言語、
102             // また更新されていれば表示言語や設定ファイルの選択を保存
103             this.SetSettings();
104             Settings.Default.Save();
105         }
106
107         #endregion
108
109         #region 翻訳元/先言語グループのイベントのメソッド
110
111         /// <summary>
112         /// 翻訳元コンボボックス変更時の処理。
113         /// </summary>
114         /// <param name="sender">イベント発生オブジェクト。</param>
115         /// <param name="e">発生したイベント。</param>
116         private void ComboBoxSource_SelectedIndexChanged(object sender, EventArgs e)
117         {
118             // ラベルに言語名を表示する
119             Website site = this.config.GetWebsite(this.comboBoxSource.Text);
120             this.SetLanguageNameLabel(this.labelSource, site);
121
122             // サーバーURLの表示
123             this.linkLabelSourceURL.Text = "http://";
124             if (site != null)
125             {
126                 this.linkLabelSourceURL.Text = site.Location;
127             }
128         }
129
130         /// <summary>
131         /// リンクラベルのリンククリック時の処理。
132         /// </summary>
133         /// <param name="sender">イベント発生オブジェクト。</param>
134         /// <param name="e">発生したイベント。</param>
135         private void LinkLabelSourceURL_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
136         {
137             // リンクを開く
138             System.Diagnostics.Process.Start(((LinkLabel)sender).Text);
139         }
140
141         /// <summary>
142         /// 翻訳先コンボボックス変更時の処理。
143         /// </summary>
144         /// <param name="sender">イベント発生オブジェクト。</param>
145         /// <param name="e">発生したイベント。</param>
146         private void ComboBoxTarget_SelectedIndexChanged(object sender, EventArgs e)
147         {
148             // ラベルに言語名を表示する
149             this.SetLanguageNameLabel(this.labelTarget, this.config.GetWebsite(this.comboBoxTarget.Text));
150         }
151
152         /// <summary>
153         /// 設定ボタン押下時の処理。
154         /// </summary>
155         /// <param name="sender">イベント発生オブジェクト。</param>
156         /// <param name="e">発生したイベント。</param>
157         private void ButtonConfig_Click(object sender, EventArgs e)
158         {
159             // 現在の画面の表示状態を保存
160             this.SetSettings();
161
162             // 設定画面を開く
163             using (ConfigForm form = new ConfigForm(this.config))
164             {
165                 form.ShowDialog();
166             }
167
168             // 戻ってきたら設定ファイルを再読み込みして表示を更新
169             // ※ キャンセル時もインスタンスは更新されてしまうので
170             this.InitializeByConfig();
171         }
172
173         #region イベント実装支援用メソッド
174
175         /// <summary>
176         /// 翻訳元/先言語コンボボックスの初期化処理。
177         /// </summary>
178         private void InitializeComboBox()
179         {
180             // コンボボックス設定
181             this.comboBoxSource.Items.Clear();
182             this.comboBoxTarget.Items.Clear();
183
184             // 設定ファイルに存在する全言語を選択肢として登録する
185             foreach (Website site in this.config.Websites)
186             {
187                 this.comboBoxSource.Items.Add(site.Language.Code);
188                 this.comboBoxTarget.Items.Add(site.Language.Code);
189             }
190
191             // 選択されていた項目を選択中に復元
192             this.comboBoxSource.SelectedItem = Settings.Default.LastSelectedSource;
193             this.comboBoxTarget.SelectedItem = Settings.Default.LastSelectedTarget;
194
195             // コンボボックス変更時の処理をコール
196             // ※ 項目が存在する場合は↑で自動的に呼ばれるが、無い場合は呼ばれないため
197             this.ComboBoxSource_SelectedIndexChanged(this.comboBoxSource, new EventArgs());
198             this.ComboBoxTarget_SelectedIndexChanged(this.comboBoxTarget, new EventArgs());
199         }
200
201         /// <summary>
202         /// ウェブサイトの言語の表示名ラベルの表示を設定する。
203         /// </summary>
204         /// <param name="label">言語の表示名用ラベル。</param>
205         /// <param name="site">選択されている言語のウェブサイト。</param>
206         private void SetLanguageNameLabel(Label label, Website site)
207         {
208             // ラベルを初期化
209             label.Text = string.Empty;
210             if (site == null)
211             {
212                 return;
213             }
214
215             // ウェブサイトが空でない場合、その言語の、ユーザーが使用している言語での表示名を表示
216             // (日本語環境だったら日本語を、英語環境だったら英語を)
217             Language.LanguageName name;
218             if (site.Language.Names.TryGetValue(
219                 Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName,
220                 out name))
221             {
222                 label.Text = name.Name;
223             }
224         }
225
226         #endregion
227
228         #endregion
229
230         #region フォルダの選択グループのイベントのメソッド
231
232         /// <summary>
233         /// 参照ボタン押下時の処理。
234         /// </summary>
235         /// <param name="sender">イベント発生オブジェクト。</param>
236         /// <param name="e">発生したイベント。</param>
237         private void ButtonSaveDirectory_Click(object sender, EventArgs e)
238         {
239             // フォルダ名が入力されている場合、それを初期位置に設定
240             if (!string.IsNullOrEmpty(this.textBoxSaveDirectory.Text))
241             {
242                 this.folderBrowserDialogSaveDirectory.SelectedPath = this.textBoxSaveDirectory.Text;
243             }
244
245             // フォルダ選択画面をオープン
246             if (this.folderBrowserDialogSaveDirectory.ShowDialog() == System.Windows.Forms.DialogResult.OK)
247             {
248                 // フォルダが選択された場合、フォルダ名に選択されたフォルダを設定
249                 this.textBoxSaveDirectory.Text = this.folderBrowserDialogSaveDirectory.SelectedPath;
250             }
251         }
252
253         /// <summary>
254         /// 出力先テキストボックスフォーカス喪失時の処理。
255         /// </summary>
256         /// <param name="sender">イベント発生オブジェクト。</param>
257         /// <param name="e">発生したイベント。</param>
258         private void TextBoxSaveDirectory_Leave(object sender, EventArgs e)
259         {
260             // 空白を削除
261             this.textBoxSaveDirectory.Text = this.textBoxSaveDirectory.Text.Trim();
262         }
263
264         #endregion
265
266         #region 記事を指定して実行グループのイベントのメソッド
267
268         /// <summary>
269         /// 実行ボタン押下時の処理。
270         /// </summary>
271         /// <param name="sender">イベント発生オブジェクト。</param>
272         /// <param name="e">発生したイベント。</param>
273         private void ButtonRun_Click(object sender, EventArgs e)
274         {
275             // フォーム入力値をチェック
276             if (string.IsNullOrWhiteSpace(this.comboBoxSource.Text))
277             {
278                 FormUtils.WarningDialog(Resources.WarningMessageNotSelectedSource);
279                 this.comboBoxSource.Focus();
280                 return;
281             }
282             else if (string.IsNullOrWhiteSpace(this.comboBoxTarget.Text))
283             {
284                 FormUtils.WarningDialog(Resources.WarningMessageNotSelectedTarget);
285                 this.comboBoxTarget.Focus();
286                 return;
287             }
288             else if (!string.IsNullOrWhiteSpace(this.comboBoxSource.Text)
289                 && this.comboBoxSource.Text == this.comboBoxTarget.Text)
290             {
291                 FormUtils.WarningDialog(Resources.WarningMessageEqualsSourceAndTarget);
292                 this.comboBoxTarget.Focus();
293                 return;
294             }
295             else if (string.IsNullOrWhiteSpace(this.textBoxSaveDirectory.Text))
296             {
297                 FormUtils.WarningDialog(Resources.WarningMessageEmptySaveDirectory);
298                 this.textBoxSaveDirectory.Focus();
299                 return;
300             }
301             else if (!Directory.Exists(this.textBoxSaveDirectory.Text))
302             {
303                 FormUtils.WarningDialog(Resources.WarningMessageIgnoreSaveDirectory);
304                 this.textBoxSaveDirectory.Focus();
305                 return;
306             }
307             else if (string.IsNullOrWhiteSpace(this.textBoxArticle.Text))
308             {
309                 FormUtils.WarningDialog(Resources.WarningMessageEmptyArticle);
310                 this.textBoxArticle.Focus();
311                 return;
312             }
313
314             // 画面をロック
315             this.LockOperation();
316
317             // 表示領域を初期化、処理時間更新用にタイマーを起動
318             this.textBoxLog.Clear();
319             this.logLength = 0;
320             this.textBoxLog.AppendText(string.Format(Resources.LogMessageStart, FormUtils.ApplicationName(), DateTime.Now));
321             this.toolStripStatusLabelStopwatch.Text = string.Format(Resources.ElapsedTime, TimeSpan.Zero);
322             this.timerStatusStopwatch.Start();
323
324             // バックグラウンド処理を実行
325             this.backgroundWorkerRun.RunWorkerAsync();
326         }
327
328         /// <summary>
329         /// 中止ボタン押下時の処理。
330         /// </summary>
331         /// <param name="sender">イベント発生オブジェクト。</param>
332         /// <param name="e">発生したイベント。</param>
333         private void ButtonStop_Click(object sender, EventArgs e)
334         {
335             // 処理を中断
336             this.buttonStop.Enabled = false;
337             if (this.backgroundWorkerRun.IsBusy)
338             {
339                 // ※ CancelAsyncだけにしたいが、それをTranslatorに伝播させる方法
340                 //    がないため直接そちらにも設定
341                 System.Diagnostics.Debug.WriteLine("MainForm.-Stop_Click > 処理中断");
342                 this.backgroundWorkerRun.CancelAsync();
343                 if (this.translator != null)
344                 {
345                     this.translator.CancellationPending = true;
346                 }
347             }
348         }
349
350         /// <summary>
351         /// 実行ボタン バックグラウンド処理(スレッド)。
352         /// </summary>
353         /// <param name="sender">イベント発生オブジェクト。</param>
354         /// <param name="e">発生したイベント。</param>
355         private void BackgroundWorkerRun_DoWork(object sender, DoWorkEventArgs e)
356         {
357             // 戻り値を失敗で初期化
358             e.Result = false;
359
360             // 別スレッドになるので表示言語を再度設定
361             Program.LoadSelectedCulture();
362
363             // フォーム要素から必要なパラメータ一式を取得
364             string source = null;
365             string target = null;
366             string title = null;
367             this.Invoke((MethodInvoker)delegate
368             {
369                 source = this.comboBoxSource.Text;
370                 target = this.comboBoxTarget.Text;
371                 title = this.textBoxArticle.Text.Trim();
372             });
373
374             // 翻訳支援処理ロジックのオブジェクトを生成
375             this.translator = Translator.Create(this.config, source, target);
376
377             // ログ・処理状態更新通知を受け取るためのイベント登録
378             this.translator.LogUpdated += new EventHandler(
379                 delegate { this.Invoke((MethodInvoker)delegate { this.UpdateLog(); }); });
380             this.translator.StatusUpdated += new EventHandler(
381                 delegate { this.Invoke((MethodInvoker)delegate { this.statusManager.Status = this.translator.Status; }); });
382
383             // 翻訳支援処理を実行
384             try
385             {
386                 this.translator.Run(title);
387             }
388             catch (ApplicationException)
389             {
390                 // 中止要求で停止した場合、その旨イベントに格納する
391                 e.Cancel = this.backgroundWorkerRun.CancellationPending;
392                 return;
393             }
394
395             // ここまで成功した場合のみ処理結果を成功とする
396             e.Result = true;
397         }
398
399         /// <summary>
400         /// 実行ボタン バックグラウンド処理(終了時)。
401         /// </summary>
402         /// <param name="sender">イベント発生オブジェクト。</param>
403         /// <param name="e">発生したイベント。</param>
404         private void BackgroundWorkerRun_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
405         {
406             // 中止ボタンをロック、処理時間更新用のタイマーを終了
407             this.buttonStop.Enabled = false;
408             this.timerStatusStopwatch.Stop();
409
410             if (e.Error != null)
411             {
412                 // 処理中で想定外のエラーが発生していた場合ここで通知
413                 if (e.Error is WebException)
414                 {
415                     // 想定外の通信エラー(↓とまとめてもよいが、こちらはサーバーの状況などで発生しやすいので)
416                     WebException ex = (WebException)e.Error;
417                     this.textBoxLog.AppendText(Environment.NewLine + string.Format(Resources.ErrorMessageConnectionFailed, ex.Message) + Environment.NewLine);
418                     if (ex.Response != null)
419                     {
420                         // 出せるならエラーとなったURLも出力
421                         this.textBoxLog.AppendText(Resources.RightArrow + " " + string.Format(Resources.LogMessageErrorURL, ex.Response.ResponseUri) + Environment.NewLine);
422                     }
423                 }
424                 else
425                 {
426                     // 想定外のエラー
427                     this.textBoxLog.AppendText(Environment.NewLine + string.Format(Resources.ErrorMessageDevelopmentError, e.Error.Message, e.Error.StackTrace) + Environment.NewLine);
428                 }
429             }
430             else
431             {
432                 // 実行結果から、ログと変換後テキストをファイル出力
433                 this.WriteResult(!e.Cancelled && (bool)e.Result);
434
435                 // 設定ファイルのキャッシュ情報を更新
436                 try
437                 {
438                     // ※ 微妙に時間がかかるので、ステータスバーに通知
439                     using (var sm = this.statusManager.Switch(Resources.StatusCacheUpdating))
440                     {
441                         this.config.Save();
442                     }
443                 }
444                 catch (Exception ex)
445                 {
446                     FormUtils.WarningDialog(Resources.WarningMessageCacheSaveFailed, ex.Message);
447                 }
448             }
449
450             // 画面をロック中から戻す、トランスレータを解放
451             this.Release();
452             this.translator = null;
453         }
454
455         #region イベント実装支援用メソッド
456
457         /// <summary>
458         /// 画面をロック中に移行。
459         /// </summary>
460         private void LockOperation()
461         {
462             // 各種ボタンなどを入力不可に変更
463             this.groupBoxTransfer.Enabled = false;
464             this.groupBoxSaveDirectory.Enabled = false;
465             this.textBoxArticle.Enabled = false;
466             this.buttonRun.Enabled = false;
467             this.toolStripDropDownButtonLanguage.Enabled = false;
468             this.toolStripDropDownButtonConfig.Enabled = false;
469
470             // 中止ボタンを有効に変更
471             this.buttonStop.Enabled = true;
472         }
473
474         /// <summary>
475         /// 画面をロック中から解放。
476         /// </summary>
477         private void Release()
478         {
479             // 中止ボタンを入力不可に変更
480             this.buttonStop.Enabled = false;
481
482             // 各種ボタンなどを有効に変更
483             this.groupBoxTransfer.Enabled = true;
484             this.groupBoxSaveDirectory.Enabled = true;
485             this.textBoxArticle.Enabled = true;
486             this.buttonRun.Enabled = true;
487             this.toolStripDropDownButtonLanguage.Enabled = true;
488             this.toolStripDropDownButtonConfig.Enabled = true;
489         }
490
491         /// <summary>
492         /// 翻訳支援処理のログ・変換後テキストをファイル出力。
493         /// </summary>
494         /// <param name="success">翻訳支援処理が成功した場合<c>true</c>。</param>
495         private void WriteResult(bool success)
496         {
497             // 若干時間がかかるのでステータスバーに通知
498             using (var sm = this.statusManager.Switch(Resources.StatusFileWriting))
499             {
500                 // 使用可能な出力ファイル名を生成
501                 string fileName;
502                 string logName;
503                 this.MakeFileName(out fileName, out logName, this.textBoxArticle.Text.Trim(), this.textBoxSaveDirectory.Text);
504
505                 if (success)
506                 {
507                     // 翻訳支援処理成功時は変換後テキストを出力
508                     try
509                     {
510                         File.WriteAllText(Path.Combine(this.textBoxSaveDirectory.Text, fileName), this.translator.Text);
511                         this.textBoxLog.AppendText(string.Format(Resources.LogMessageEnd, fileName, logName));
512                     }
513                     catch (Exception ex)
514                     {
515                         this.textBoxLog.AppendText(string.Format(Resources.LogMessageFileSaveFailed, Path.Combine(this.textBoxSaveDirectory.Text, fileName), ex.Message));
516                         this.textBoxLog.AppendText(string.Format(Resources.LogMessageStop, logName));
517                     }
518                 }
519                 else
520                 {
521                     this.textBoxLog.AppendText(string.Format(Resources.LogMessageStop, logName));
522                 }
523
524                 // ログを出力
525                 try
526                 {
527                     File.WriteAllText(Path.Combine(this.textBoxSaveDirectory.Text, logName), this.textBoxLog.Text);
528                 }
529                 catch (Exception ex)
530                 {
531                     this.textBoxLog.AppendText(string.Format(Resources.LogMessageFileSaveFailed, Path.Combine(this.textBoxSaveDirectory.Text, logName), ex.Message));
532                 }
533             }
534         }
535
536         /// <summary>
537         /// 渡された文字列から.txtと.logの重複していないファイル名を作成。
538         /// </summary>
539         /// <param name="fileName">出力結果ファイル名。</param>
540         /// <param name="logName">出力ログファイル名。</param>
541         /// <param name="text">出力する結果テキスト。</param>
542         /// <param name="dir">出力先ディレクトリ。</param>
543         /// <returns>出力成功の場合<c>true</c>。</returns>
544         private bool MakeFileName(out string fileName, out string logName, string text, string dir)
545         {
546             // 出力先フォルダに存在しないファイル名(の拡張子より前)を作成
547             // ※渡されたWikipedia等の記事名にファイル名に使えない文字が含まれている場合、_ に置き換える
548             //   また、ファイル名が重複している場合、xx[0].txtのように連番を付ける
549             string fileNameBase = FormUtils.ReplaceInvalidFileNameChars(text);
550             fileName = fileNameBase + ".txt";
551             logName = fileNameBase + ".log";
552             bool success = false;
553             for (int i = 0; i < 100000; i++)
554             {
555                 // ※ 100000まで試して空きが見つからないことは無いはず、もし見つからなかったら最後のを上書き
556                 if (!File.Exists(Path.Combine(dir, fileName))
557                     && !File.Exists(Path.Combine(dir, logName)))
558                 {
559                     success = true;
560                     break;
561                 }
562
563                 fileName = fileNameBase + "[" + i + "]" + ".txt";
564                 logName = fileNameBase + "[" + i + "]" + ".log";
565             }
566
567             // 結果設定
568             return success;
569         }
570
571         /// <summary>
572         /// 翻訳支援処理クラスのログ更新反映。
573         /// </summary>
574         private void UpdateLog()
575         {
576             // 前回以降に追加されたログをテキストボックスに出力
577             int length = this.translator.Log.Length;
578             if (length > this.logLength)
579             {
580                 this.textBoxLog.AppendText(this.translator.Log.Substring(this.logLength, length - this.logLength));
581             }
582
583             this.logLength = length;
584         }
585
586         #endregion
587
588         #endregion
589
590         #region ステータスバーのイベントのメソッド
591
592         /// <summary>
593         /// ステータスバー処理時間更新タイマー処理。
594         /// </summary>
595         /// <param name="sender">イベント発生オブジェクト。</param>
596         /// <param name="e">発生したイベント。</param>
597         private void TimerStatusStopwatch_Tick(object sender, EventArgs e)
598         {
599             if (this.translator != null)
600             {
601                 // 処理時間をステータスバーに反映
602                 this.toolStripStatusLabelStopwatch.Text = string.Format(Resources.ElapsedTime, this.translator.Stopwatch.Elapsed);
603             }
604         }
605
606         /// <summary>
607         /// 表示言語選択メニュー日本語クリック時の処理。
608         /// </summary>
609         /// <param name="sender">イベント発生オブジェクト。</param>
610         /// <param name="e">発生したイベント。</param>
611         private void ToolStripMenuItemJapanese_Click(object sender, EventArgs e)
612         {
613             // 表示言語を日本語に設定し再起動する
614             this.ChangeCultureAndRestart("ja-JP");
615         }
616
617         /// <summary>
618         /// 表示言語選択メニュー英語(US)クリック時の処理。
619         /// </summary>
620         /// <param name="sender">イベント発生オブジェクト。</param>
621         /// <param name="e">発生したイベント。</param>
622         private void ToolStripMenuItemEnglishUS_Click(object sender, EventArgs e)
623         {
624             // 表示言語を英語(US)に設定し再起動する
625             this.ChangeCultureAndRestart("en-US");
626         }
627
628         /// <summary>
629         /// 表示言語選択メニュー英語(GB)クリック時の処理。
630         /// </summary>
631         /// <param name="sender">イベント発生オブジェクト。</param>
632         /// <param name="e">発生したイベント。</param>
633         private void ToolStripMenuItemEnglishGB_Click(object sender, EventArgs e)
634         {
635             // 表示言語を英語(GB)に設定し再起動する
636             this.ChangeCultureAndRestart("en-GB");
637         }
638
639         /// <summary>
640         /// 表示言語選択メニュー自動クリック時の処理。
641         /// </summary>
642         /// <param name="sender">イベント発生オブジェクト。</param>
643         /// <param name="e">発生したイベント。</param>
644         private void ToolStripMenuItemAuto_Click(object sender, EventArgs e)
645         {
646             // 表示言語を空欄に設定し再起動する
647             this.ChangeCultureAndRestart(string.Empty);
648         }
649
650         /// <summary>
651         /// 設定選択メニュークリック時の処理。
652         /// </summary>
653         /// <param name="sender">イベント発生オブジェクト。</param>
654         /// <param name="e">発生したイベント。</param>
655         private void ToolStripMenuItemConfig_Click(object sender, EventArgs e)
656         {
657             // メニュー項目を一旦全て未選択状態に更新
658             foreach (ToolStripMenuItem i in this.toolStripDropDownButtonConfig.DropDownItems)
659             {
660                 i.Checked = false;
661                 i.Enabled = true;
662             }
663
664             // メニュー項目名から設定ファイル名を作成、再読み込みする
665             ToolStripMenuItem item = (ToolStripMenuItem)sender;
666             Settings.Default.LastSelectedConfiguration = item.Text;
667             this.SetSettings();
668             this.InitializeByConfig();
669         }
670
671         /// <summary>
672         /// 設定選択メニュー追加クリック時の処理。
673         /// </summary>
674         /// <param name="sender">イベント発生オブジェクト。</param>
675         /// <param name="e">発生したイベント。</param>
676         private void ToolStripMenuItemNew_Click(object sender, EventArgs e)
677         {
678             // 重複チェック用の登録済みの設定一覧を用意
679             IList<string> configNames = new List<string>();
680             foreach (ToolStripMenuItem item in this.toolStripDropDownButtonConfig.DropDownItems)
681             {
682                 if (item != this.toolStripMenuItemNew)
683                 {
684                     configNames.Add(item.Text);
685                 }
686             }
687
688             // 設定追加用ダイアログで言語コードを入力
689             using (AddConfigDialog form = new AddConfigDialog(configNames))
690             {
691                 if (form.ShowDialog() == DialogResult.OK)
692                 {
693                     // 設定選択メニューに新しい設定を追加。
694                     // 設定ファイルが作成されているため、それを読み込みなおす。
695                     this.ToolStripMenuItemConfig_Click(
696                         this.AddToolStripDropDownButtonConfigItem(form.ConfigName),
697                         e);
698                 }
699             }
700         }
701
702         #region イベント実装支援用メソッド
703
704         /// <summary>
705         /// 表示言語選択メニューの初期化処理。
706         /// </summary>
707         private void InitializeDropDownButtonLanguage()
708         {
709             // 選択中の言語のメニュー項目を抽出
710             ToolStripMenuItem item;
711             switch (Settings.Default.LastSelectedLanguage)
712             {
713                 case "en-US":
714                     item = this.toolStripMenuItemEnglishUS;
715                     break;
716                 case "en-GB":
717                     item = this.toolStripMenuItemEnglishGB;
718                     break;
719                 case "ja-JP":
720                     item = this.toolStripMenuItemJapanese;
721                     break;
722                 default:
723                     item = this.toolStripMenuItemAuto;
724                     break;
725             }
726
727             // 選択中の項目をチェック状態&押下不能とする
728             item.Checked = true;
729             item.Enabled = false;
730             if (item != this.toolStripMenuItemAuto)
731             {
732                 // 自動以外の場合、ステータスバーの表示も更新
733                 this.toolStripDropDownButtonLanguage.Text = item.Text;
734             }
735         }
736
737         /// <summary>
738         /// 設定ファイル選択メニューの初期化処理。
739         /// </summary>
740         private void InitializeDropDownButtonConfig()
741         {
742             // exeまたはユーザーフォルダにある設定ファイルをメニュー項目としてリストアップ
743             foreach (string file in FormUtils.GetFilesAtUserAppData(
744                 "*" + Settings.Default.ConfigurationExtension,
745                 Settings.Default.ConfigurationCompatible))
746             {
747                 try
748                 {
749                     // 関係ないXMLファイルを除外するため、読み込めるフォーマットかをチェック
750                     // ※ ちょっと時間がかかるが・・・
751                     Config.GetInstance(file);
752
753                     // 問題なければファイル名を見出しにメニューに追加
754                     this.AddToolStripDropDownButtonConfigItem(Path.GetFileNameWithoutExtension(file));
755                 }
756                 catch (Exception ex)
757                 {
758                     System.Diagnostics.Debug.WriteLine(
759                         "MainForm.InitializeDropDownButtonConfig : " + ex.Message);
760                 }
761             }
762         }
763
764         /// <summary>
765         /// 設定選択メニューに新しい設定を追加する。
766         /// </summary>
767         /// <param name="name">設定名。</param>
768         /// <returns>追加したメニュー。</returns>
769         /// <remarks>追加メニューがあるのでその後ろに登録する。</remarks>
770         private ToolStripMenuItem AddToolStripDropDownButtonConfigItem(string name)
771         {
772             // 設定変更のイベントを設定する
773             ToolStripMenuItem item = new ToolStripMenuItem();
774             item.Text = name;
775             item.Click += new EventHandler(this.ToolStripMenuItemConfig_Click);
776             this.toolStripDropDownButtonConfig.DropDownItems.Insert(
777                 this.toolStripDropDownButtonConfig.DropDownItems.Count - 1,
778                 item);
779             return item;
780         }
781
782         /// <summary>
783         /// アプリケーションの現在の表示言語を変更、再起動する。
784         /// </summary>
785         /// <param name="name">変更先カルチャ名。</param>
786         /// <remarks>このメソッドを呼び出すとアプリケーションが一旦終了します。</remarks>
787         private void ChangeCultureAndRestart(string name)
788         {
789             // 現在の画面表示と表示言語設定を保存した後、アプリケーションを再起動
790             this.SetSettings();
791             Settings.Default.LastSelectedLanguage = name;
792             Settings.Default.Save();
793             Application.Restart();
794             this.Close();
795         }
796
797         #endregion
798
799         #endregion
800
801         #region その他のメソッド
802
803         /// <summary>
804         /// 設定ファイルによる初期化処理。
805         /// </summary>
806         /// <remarks>
807         /// 読み込みに失敗した場合、空の設定を登録し、操作の大半をロックする
808         /// (設定変更メニューから正しい設定に変更されることを期待)。
809         /// </remarks>
810         private void InitializeByConfig()
811         {
812             // 設定ファイルの読み込み
813             this.LoadConfig();
814             if (this.config == null)
815             {
816                 // 読み込みに失敗した場合、空の設定を作成(設定値には適当な値を設定)
817                 // 設定選択メニューの表示を更新し、画面をほぼ操作不可に変更
818                 this.config = new Config();
819                 this.groupBoxTransfer.Enabled = false;
820                 this.groupBoxSaveDirectory.Enabled = false;
821                 this.groupBoxRun.Enabled = false;
822                 this.toolStripDropDownButtonConfig.Text = Resources.DropDownConfigLoadConfigFailed;
823             }
824             else
825             {
826                 // 設定選択メニューの表示を更新し、画面を操作可能な状態に戻す
827                 this.groupBoxTransfer.Enabled = true;
828                 this.groupBoxSaveDirectory.Enabled = true;
829                 this.groupBoxRun.Enabled = true;
830                 this.toolStripDropDownButtonConfig.Text = Path.GetFileNameWithoutExtension(this.config.File);
831                 foreach (ToolStripMenuItem item in this.toolStripDropDownButtonConfig.DropDownItems)
832                 {
833                     // 読み込んだ設定を選択中(チェック状態&押下不能)に更新
834                     if (item != this.toolStripMenuItemNew
835                         && item.Text == this.toolStripDropDownButtonConfig.Text)
836                     {
837                         item.Checked = true;
838                         item.Enabled = false;
839                     }
840                 }
841             }
842
843             // コンボボックスを読み込んだ設定で初期化
844             this.InitializeComboBox();
845         }
846
847         /// <summary>
848         /// 設定ファイル読み込み。
849         /// </summary>
850         private void LoadConfig()
851         {
852             // 設定ファイルの読み込み
853             string file = Settings.Default.LastSelectedConfiguration + Settings.Default.ConfigurationExtension;
854             try
855             {
856                 // ※ 微妙に時間がかかるので、ステータスバーに通知
857                 using (var sm = this.statusManager.Switch(Resources.StatusConfigReading))
858                 {
859                     this.config = Config.GetInstance(file);
860                 }
861             }
862             catch (FileNotFoundException ex)
863             {
864                 // 設定ファイルが見つからない場合、エラーメッセージを表示
865                 System.Diagnostics.Debug.WriteLine(
866                     "MainForm.LoadConfig > 設定ファイル読み込み失敗 : " + ex.Message);
867                 FormUtils.ErrorDialog(Resources.ErrorMessageConfigNotFound, file);
868             }
869             catch (Exception ex)
870             {
871                 // その他の例外(権限が無いとかファイルが壊れているとか)
872                 System.Diagnostics.Debug.WriteLine(
873                     "MainForm.LoadConfig > 設定ファイル読み込み時エラー : " + ex.ToString());
874                 FormUtils.ErrorDialog(Resources.ErrorMessageConfigLordFailed, ex.Message);
875             }
876         }
877
878         /// <summary>
879         /// 現在の出力先フォルダ、翻訳元/先言語をアプリケーション設定に反映。
880         /// </summary>
881         /// <remarks>表示言語や設定ファイルの選択については必要な場合のみ別途実施。</remarks>
882         private void SetSettings()
883         {
884             Settings.Default.SaveDirectory = this.textBoxSaveDirectory.Text;
885             Settings.Default.LastSelectedSource = this.comboBoxSource.Text;
886             Settings.Default.LastSelectedTarget = this.comboBoxTarget.Text;
887         }
888
889         #endregion
890     }
891 }