OSDN Git Service

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