OSDN Git Service

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