OSDN Git Service

#27316 表示言語の切り替え機能・英語リソースの追加(ツールチップは除く),
[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             if (!this.LoadConfig())
78             {
79                 // 読み込み失敗時はどうしようもないのでそのまま終了
80                 this.Close();
81             }
82
83             this.translator = null;
84             Control.CheckForIllegalCrossThreadCalls = false;
85
86             // コンボボックス・表示言語選択メニューの初期設定
87             this.InitializeComboBox();
88             this.InitializeDropDownButtonLanguage();
89
90             // 前回の処理状態を復元
91             this.textBoxSaveDirectory.Text = Settings.Default.SaveDirectory;
92             this.comboBoxSource.SelectedItem = Settings.Default.LastSelectedSource;
93             this.comboBoxTarget.SelectedItem = Settings.Default.LastSelectedTarget;
94         }
95
96         /// <summary>
97         /// フォームクローズ時の処理。処理状態を保存。
98         /// </summary>
99         /// <param name="sender">イベント発生オブジェクト。</param>
100         /// <param name="e">発生したイベント。</param>
101         private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
102         {
103             // 現在の出力先フォルダ、翻訳元/先言語、また必要であれば表示言語を保存
104             this.SaveSettings();
105         }
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             this.labelSource.Text = String.Empty;
116             this.linkLabelSourceURL.Text = "http://";
117             if (!String.IsNullOrWhiteSpace(this.comboBoxSource.Text))
118             {
119                 // その言語の、ユーザーが使用している言語での表示名を表示
120                 // (日本語環境だったら日本語を、英語だったら英語を)
121                 Language.LanguageName name;
122                 this.labelSource.Text = String.Empty;
123                 if (this.config.GetWebsite(this.comboBoxSource.Text) != null &&
124                     this.config.GetWebsite(this.comboBoxSource.Text).Language.Names.TryGetValue(
125                     Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName,
126                     out name))
127                 {
128                     this.labelSource.Text = name.Name;
129                 }
130
131                 // サーバーURLの表示
132                 this.linkLabelSourceURL.Text = this.config.GetWebsite(
133                     this.comboBoxSource.Text).Location;
134             }
135         }
136
137         /// <summary>
138         /// リンクラベルのリンククリック時の処理。
139         /// </summary>
140         /// <param name="sender">イベント発生オブジェクト。</param>
141         /// <param name="e">発生したイベント。</param>
142         private void LinkLabelSourceURL_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
143         {
144             // リンクを開く
145             System.Diagnostics.Process.Start(((LinkLabel)sender).Text);
146         }
147
148         /// <summary>
149         /// 翻訳先コンボボックス変更時の処理。
150         /// </summary>
151         /// <param name="sender">イベント発生オブジェクト。</param>
152         /// <param name="e">発生したイベント。</param>
153         private void ComboBoxTarget_SelectedIndexChanged(object sender, EventArgs e)
154         {
155             // ラベルに言語名を表示する
156             this.labelTarget.Text = String.Empty;
157             if (!String.IsNullOrWhiteSpace(this.comboBoxTarget.Text))
158             {
159                 this.comboBoxTarget.Text = this.comboBoxTarget.Text.Trim().ToLower();
160
161                 // その言語の、ユーザーが使用している言語での表示名を表示
162                 // (日本語環境だったら日本語を、英語だったら英語を)
163                 if (this.config.GetWebsite(this.comboBoxTarget.Text) != null)
164                 {
165                     this.labelTarget.Text = this.config.GetWebsite(this.comboBoxTarget.Text)
166                         .Language.Names[Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName].Name;
167                 }
168             }
169         }
170
171         /// <summary>
172         /// 設定ボタン押下時の処理。
173         /// </summary>
174         /// <param name="sender">イベント発生オブジェクト。</param>
175         /// <param name="e">発生したイベント。</param>
176         private void ButtonConfig_Click(object sender, EventArgs e)
177         {
178             // 設定画面を開く
179             ConfigForm form = new ConfigForm(this.config);
180             form.ShowDialog();
181
182             // 戻ってきたら設定ファイルを再読み込み
183             // ※ キャンセル時もインスタンスは更新されてしまうので
184             this.LoadConfig();
185
186             // コンボボックス設定
187             string backupSourceSelected = this.comboBoxSource.Text;
188             string backupSourceTarget = this.comboBoxTarget.Text;
189             this.InitializeComboBox();
190             this.comboBoxSource.SelectedItem = backupSourceSelected;
191             this.comboBoxTarget.SelectedItem = backupSourceTarget;
192         }
193
194         /// <summary>
195         /// 参照ボタン押下時の処理。
196         /// </summary>
197         /// <param name="sender">イベント発生オブジェクト。</param>
198         /// <param name="e">発生したイベント。</param>
199         private void ButtonSaveDirectory_Click(object sender, EventArgs e)
200         {
201             // フォルダ名が入力されている場合、それを初期位置に設定
202             if (!String.IsNullOrEmpty(this.textBoxSaveDirectory.Text))
203             {
204                 this.folderBrowserDialogSaveDirectory.SelectedPath = this.textBoxSaveDirectory.Text;
205             }
206
207             // フォルダ選択画面をオープン
208             if (this.folderBrowserDialogSaveDirectory.ShowDialog() == System.Windows.Forms.DialogResult.OK)
209             {
210                 // フォルダが選択された場合、フォルダ名に選択されたフォルダを設定
211                 this.textBoxSaveDirectory.Text = this.folderBrowserDialogSaveDirectory.SelectedPath;
212             }
213         }
214
215         /// <summary>
216         /// 出力先テキストボックスフォーカス喪失時の処理。
217         /// </summary>
218         /// <param name="sender">イベント発生オブジェクト。</param>
219         /// <param name="e">発生したイベント。</param>
220         private void TextBoxSaveDirectory_Leave(object sender, EventArgs e)
221         {
222             // 空白を削除
223             this.textBoxSaveDirectory.Text = this.textBoxSaveDirectory.Text.Trim();
224         }
225
226         /// <summary>
227         /// 実行ボタン押下時の処理。
228         /// </summary>
229         /// <param name="sender">イベント発生オブジェクト。</param>
230         /// <param name="e">発生したイベント。</param>
231         private void ButtonRun_Click(object sender, EventArgs e)
232         {
233             // フォーム入力値をチェック
234             if (String.IsNullOrWhiteSpace(this.comboBoxSource.Text))
235             {
236                 FormUtils.WarningDialog(Resources.WarningMessageNotSelectedSource);
237                 this.comboBoxSource.Focus();
238                 return;
239             }
240             else if (String.IsNullOrWhiteSpace(this.comboBoxTarget.Text))
241             {
242                 FormUtils.WarningDialog(Resources.WarningMessageNotSelectedTarget);
243                 this.comboBoxTarget.Focus();
244                 return;
245             }
246             else if (!String.IsNullOrWhiteSpace(this.comboBoxSource.Text)
247                 && this.comboBoxSource.Text == this.comboBoxTarget.Text)
248             {
249                 FormUtils.WarningDialog(Resources.WarningMessageEqualsSourceAndTarget);
250                 this.comboBoxTarget.Focus();
251                 return;
252             }
253             else if (String.IsNullOrWhiteSpace(this.textBoxSaveDirectory.Text))
254             {
255                 FormUtils.WarningDialog(Resources.WarningMessageEmptySaveDirectory);
256                 this.textBoxSaveDirectory.Focus();
257                 return;
258             }
259             else if (!Directory.Exists(this.textBoxSaveDirectory.Text))
260             {
261                 FormUtils.WarningDialog(Resources.WarningMessageIgnoreSaveDirectory);
262                 this.textBoxSaveDirectory.Focus();
263                 return;
264             }
265             else if (String.IsNullOrWhiteSpace(this.textBoxArticle.Text))
266             {
267                 FormUtils.WarningDialog(Resources.WarningMessageEmptyArticle);
268                 this.textBoxArticle.Focus();
269                 return;
270             }
271
272             // 画面をロック
273             this.LockOperation();
274
275             // バックグラウンド処理を実行
276             this.backgroundWorkerRun.RunWorkerAsync();
277         }
278
279         /// <summary>
280         /// 中止ボタン押下時の処理。
281         /// </summary>
282         /// <param name="sender">イベント発生オブジェクト。</param>
283         /// <param name="e">発生したイベント。</param>
284         private void ButtonStop_Click(object sender, EventArgs e)
285         {
286             // 処理を中断
287             this.buttonStop.Enabled = false;
288             if (this.backgroundWorkerRun.IsBusy == true)
289             {
290                 System.Diagnostics.Debug.WriteLine("MainForm.-Stop_Click > 処理中断");
291                 this.backgroundWorkerRun.CancelAsync();
292                 if (this.translator != null)
293                 {
294                     this.translator.CancellationPending = true;
295                 }
296             }
297         }
298
299         /// <summary>
300         /// 実行ボタン バックグラウンド処理(スレッド)。
301         /// </summary>
302         /// <param name="sender">イベント発生オブジェクト。</param>
303         /// <param name="e">発生したイベント。</param>
304         private void BackgroundWorkerRun_DoWork(object sender, DoWorkEventArgs e)
305         {
306             try
307             {
308                 // 初期化と開始メッセージ、別スレッドになるので表示言語も再度設定
309                 Program.LoadSelectedCulture();
310                 this.textBoxLog.Clear();
311                 this.logLength = 0;
312                 this.textBoxLog.AppendText(String.Format(Resources.LogMessageStart, FormUtils.ApplicationName(), DateTime.Now));
313
314                 // 翻訳支援処理ロジックのオブジェクトを生成
315                 try
316                 {
317                     this.translator = Translator.Create(this.config, this.comboBoxSource.Text, this.comboBoxTarget.Text);
318                 }
319                 catch (NotImplementedException)
320                 {
321                     // 設定ファイルに対応していないパターンが書かれている場合の例外、将来の拡張用
322                     this.textBoxLog.AppendText(String.Format(Resources.InformationMessageDevelopingMethod, "MediaWiki以外の処理"));
323                     FormUtils.InformationDialog(Resources.InformationMessageDevelopingMethod, "MediaWiki以外の処理");
324                     return;
325                 }
326
327                 // ログ・処理状態更新通知を受け取るためのイベント登録
328                 // 処理時間更新用にタイマーを起動
329                 this.translator.LogUpdate += new EventHandler(this.GetLogUpdate);
330                 this.translator.StatusUpdate += new EventHandler(this.GetStatusUpdate);
331                 this.Invoke((MethodInvoker)delegate { this.timerStatusStopwatch.Start(); });
332
333                 // 翻訳支援処理を実行
334                 bool success = true;
335                 try
336                 {
337                     this.translator.Run(this.textBoxArticle.Text.Trim());
338                 }
339                 catch (ApplicationException)
340                 {
341                     // 中止要求で停止した場合、その旨イベントに格納する
342                     e.Cancel = this.backgroundWorkerRun.CancellationPending;
343                     success = false;
344                 }
345                 finally
346                 {
347                     // 処理時間更新用のタイマーを終了
348                     this.Invoke((MethodInvoker)delegate { this.timerStatusStopwatch.Stop(); });
349                 }
350
351                 // 実行結果から、ログと変換後テキストをファイル出力
352                 this.WriteResult(success);
353             }
354             catch (WebException ex)
355             {
356                 // 想定外の通信エラー(↓とまとめてもよいが、こちらはサーバーの状況などで発生しやすいので)
357                 this.textBoxLog.AppendText(Environment.NewLine + String.Format(Resources.ErrorMessageConnectionFailed, ex.Message) + Environment.NewLine);
358                 if (ex.Response != null)
359                 {
360                     // 出せるならエラーとなったURLも出力
361                     this.textBoxLog.AppendText(Resources.RightArrow + " " + String.Format(Resources.LogMessageErrorURL, ex.Response.ResponseUri) + Environment.NewLine);
362                 }
363             }
364             catch (Exception ex)
365             {
366                 // 想定外のエラー
367                 this.textBoxLog.AppendText(Environment.NewLine + String.Format(Resources.ErrorMessageDevelopmentError, ex.Message, ex.StackTrace) + Environment.NewLine);
368             }
369         }
370
371         /// <summary>
372         /// 実行ボタン バックグラウンド処理(終了時)。
373         /// </summary>
374         /// <param name="sender">イベント発生オブジェクト。</param>
375         /// <param name="e">発生したイベント。</param>
376         private void BackgroundWorkerRun_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
377         {
378             // 設定ファイルのキャッシュ情報を更新
379             // ※ 微妙に時間がかかるので、ステータスバーに通知
380             try
381             {
382                 this.toolStripStatusLabelStatus.Text = Resources.StatusCacheUpdating;
383                 try
384                 {
385                     this.config.Save();
386                 }
387                 finally
388                 {
389                     this.toolStripStatusLabelStatus.Text = String.Empty;
390                 }
391             }
392             catch (Exception ex)
393             {
394                 FormUtils.WarningDialog(
395                     Resources.WarningMessageCacheSaveFailed,
396                     ex.Message);
397             }
398
399             // 画面をロック中から解放
400             this.Release();
401         }
402
403         /// <summary>
404         /// ステータスバー処理時間更新タイマー処理。
405         /// </summary>
406         /// <param name="sender">イベント発生オブジェクト。</param>
407         /// <param name="e">発生したイベント。</param>
408         private void TimerStatusStopwatch_Tick(object sender, EventArgs e)
409         {
410             // 処理時間をステータスバーに反映
411             this.toolStripStatusLabelStopwatch.Text = String.Format(Resources.ElapsedTime, this.translator.Stopwatch.Elapsed);
412         }
413
414         /// <summary>
415         /// 表示言語選択メニュー日本語クリック時の処理。
416         /// </summary>
417         /// <param name="sender">イベント発生オブジェクト。</param>
418         /// <param name="e">発生したイベント。</param>
419         private void ToolStripMenuItemJapanese_Click(object sender, EventArgs e)
420         {
421             // 表示言語を日本語に設定し再起動する
422             this.ChangeCultureAndRestart("ja-JP");
423         }
424
425         /// <summary>
426         /// 表示言語選択メニュー英語(US)クリック時の処理。
427         /// </summary>
428         /// <param name="sender">イベント発生オブジェクト。</param>
429         /// <param name="e">発生したイベント。</param>
430         private void ToolStripMenuItemEnglishUS_Click(object sender, EventArgs e)
431         {
432             // 表示言語を英語(US)に設定し再起動する
433             this.ChangeCultureAndRestart("en-US");
434         }
435
436         /// <summary>
437         /// 表示言語選択メニュー英語(GB)クリック時の処理。
438         /// </summary>
439         /// <param name="sender">イベント発生オブジェクト。</param>
440         /// <param name="e">発生したイベント。</param>
441         private void ToolStripMenuItemEnglishGB_Click(object sender, EventArgs e)
442         {
443             // 表示言語を英語(GB)に設定し再起動する
444             this.ChangeCultureAndRestart("en-GB");
445         }
446
447         /// <summary>
448         /// 表示言語選択メニュー自動クリック時の処理。
449         /// </summary>
450         /// <param name="sender">イベント発生オブジェクト。</param>
451         /// <param name="e">発生したイベント。</param>
452         private void ToolStripMenuItemAuto_Click(object sender, EventArgs e)
453         {
454             // 表示言語を空欄に設定し再起動する
455             this.ChangeCultureAndRestart(String.Empty);
456         }
457
458         #endregion
459
460         #region それ以外のメソッド
461
462         /// <summary>
463         /// 翻訳元/先言語コンボボックスの初期化処理。
464         /// </summary>
465         private void InitializeComboBox()
466         {
467             // コンボボックス設定
468             this.comboBoxSource.Items.Clear();
469             this.comboBoxTarget.Items.Clear();
470
471             // 設定ファイルに存在する全言語を選択肢として登録する
472             foreach (Website site in this.config.Websites)
473             {
474                 this.comboBoxSource.Items.Add(site.Language.Code);
475                 this.comboBoxTarget.Items.Add(site.Language.Code);
476             }
477         }
478
479         /// <summary>
480         /// 表示言語選択メニューの初期化処理。
481         /// </summary>
482         private void InitializeDropDownButtonLanguage()
483         {
484             // 選択中の言語のメニュー項目を抽出
485             ToolStripMenuItem item;
486             switch (Settings.Default.LastSelectedLanguage)
487             {
488                 case "en-US":
489                     item = this.toolStripMenuItemEnglishUS;
490                     break;
491                 case "en-GB":
492                     item = this.toolStripMenuItemEnglishGB;
493                     break;
494                 case "ja-JP":
495                     item = this.toolStripMenuItemJapanese;
496                     break;
497                 default:
498                     item = this.toolStripMenuItemAuto;
499                     break;
500             }
501
502             // 選択中の項目をチェック状態&押下不能とする
503             item.Checked = true;
504             item.Enabled = false;
505             if (item != this.toolStripMenuItemAuto)
506             {
507                 // 自動以外の場合、ステータスバーの表示も更新
508                 this.toolStripDropDownButtonLanguage.Text = item.Text;
509             }
510         }
511
512         /// <summary>
513         /// 設定ファイル読み込み。
514         /// </summary>
515         /// <returns>読み込み成功時は<c>true</c>。</returns>
516         private bool LoadConfig()
517         {
518             // 設定ファイルの読み込み
519             // ※ 微妙に時間がかかるので、ステータスバーに通知
520             try
521             {
522                 this.toolStripStatusLabelStatus.Text = Resources.StatusConfigReading;
523                 try
524                 {
525                     this.config = Config.GetInstance(Settings.Default.ConfigurationFile);
526                 }
527                 finally
528                 {
529                     this.toolStripStatusLabelStatus.Text = String.Empty;
530                 }
531             }
532             catch (FileNotFoundException ex)
533             {
534                 // 設定ファイルが見つからない場合
535                 System.Diagnostics.Debug.WriteLine(
536                     "MainForm.LoadConfig > 設定ファイル読み込み失敗 : " + ex.Message);
537                 FormUtils.ErrorDialog(
538                     Resources.ErrorMessageConfigNotFound,
539                     Settings.Default.ConfigurationFile);
540
541                 return false;
542             }
543             catch (Exception ex)
544             {
545                 System.Diagnostics.Debug.WriteLine(
546                     "MainForm.LoadConfig > 設定ファイル読み込み時エラー : " + ex.ToString());
547                 FormUtils.ErrorDialog(
548                     Resources.ErrorMessageConfigLordFailed,
549                     ex.Message);
550
551                 return false;
552             }
553
554             return true;
555         }
556
557         /// <summary>
558         /// アプリケーション設定保存。
559         /// </summary>
560         private void SaveSettings()
561         {
562             // 現在の出力先フォルダ、翻訳元/先言語を保存
563             // ※ 表示言語については必要な場合のみ更新するため、変更したタイミングで更新、ここでは反映だけ
564             Settings.Default.SaveDirectory = this.textBoxSaveDirectory.Text;
565             Settings.Default.LastSelectedSource = this.comboBoxSource.Text;
566             Settings.Default.LastSelectedTarget = this.comboBoxTarget.Text;
567             Settings.Default.Save();
568         }
569
570         /// <summary>
571         /// 画面をロック中に移行。
572         /// </summary>
573         private void LockOperation()
574         {
575             // 各種ボタンなどを入力不可に変更
576             this.groupBoxTransfer.Enabled = false;
577             this.groupBoxSaveDirectory.Enabled = false;
578             this.textBoxArticle.Enabled = false;
579             this.buttonRun.Enabled = false;
580             this.toolStripDropDownButtonLanguage.Enabled = false;
581             this.toolStripDropDownButtonConfig.Enabled = false;
582
583             // 中止ボタンを有効に変更
584             this.buttonStop.Enabled = true;
585         }
586
587         /// <summary>
588         /// 画面をロック中から解放。
589         /// </summary>
590         private void Release()
591         {
592             // 中止ボタンを入力不可に変更
593             this.buttonStop.Enabled = false;
594
595             // 各種ボタンなどを有効に変更
596             this.groupBoxTransfer.Enabled = true;
597             this.groupBoxSaveDirectory.Enabled = true;
598             this.textBoxArticle.Enabled = true;
599             this.buttonRun.Enabled = true;
600             this.toolStripDropDownButtonLanguage.Enabled = true;
601             this.toolStripDropDownButtonConfig.Enabled = true;
602         }
603
604         /// <summary>
605         /// 翻訳支援処理のログ・変換後テキストをファイル出力。
606         /// </summary>
607         /// <param name="success">翻訳支援処理が成功した場合<c>true</c>。</param>
608         private void WriteResult(bool success)
609         {
610             // 若干時間がかかるのでステータスバーに通知
611             this.toolStripStatusLabelStatus.Text = Resources.StatusFileWriting;
612             try
613             {
614                 // 使用可能な出力ファイル名を生成
615                 string fileName;
616                 string logName;
617                 this.MakeFileName(out fileName, out logName, this.textBoxArticle.Text.Trim(), this.textBoxSaveDirectory.Text);
618
619                 if (success)
620                 {
621                     // 翻訳支援処理成功時は変換後テキストを出力
622                     try
623                     {
624                         File.WriteAllText(Path.Combine(this.textBoxSaveDirectory.Text, fileName), this.translator.Text);
625                         this.textBoxLog.AppendText(String.Format(Resources.LogMessageEnd, fileName, logName));
626                     }
627                     catch (Exception ex)
628                     {
629                         this.textBoxLog.AppendText(String.Format(Resources.LogMessageFileSaveFailed, Path.Combine(this.textBoxSaveDirectory.Text, fileName), ex.Message));
630                         this.textBoxLog.AppendText(String.Format(Resources.LogMessageStop, logName));
631                     }
632                 }
633                 else
634                 {
635                     this.textBoxLog.AppendText(String.Format(Resources.LogMessageStop, logName));
636                 }
637
638                 // ログを出力
639                 try
640                 {
641                     File.WriteAllText(Path.Combine(this.textBoxSaveDirectory.Text, logName), this.textBoxLog.Text);
642                 }
643                 catch (Exception ex)
644                 {
645                     this.textBoxLog.AppendText(String.Format(Resources.LogMessageFileSaveFailed, Path.Combine(this.textBoxSaveDirectory.Text, logName), ex.Message));
646                 }
647             }
648             finally
649             {
650                 // ステータスバーをクリア
651                 this.toolStripStatusLabelStatus.Text = String.Empty;
652             }
653         }
654
655         /// <summary>
656         /// 渡された文字列から.txtと.logの重複していないファイル名を作成。
657         /// </summary>
658         /// <param name="fileName">出力結果ファイル名。</param>
659         /// <param name="logName">出力ログファイル名。</param>
660         /// <param name="text">出力する結果テキスト。</param>
661         /// <param name="dir">出力先ディレクトリ。</param>
662         /// <returns><c>true</c> 出力成功</returns>
663         private bool MakeFileName(out string fileName, out string logName, string text, string dir)
664         {
665             // 出力先フォルダに存在しないファイル名(の拡張子より前)を作成
666             // ※渡されたWikipedia等の記事名にファイル名に使えない文字が含まれている場合、_ に置き換える
667             //   また、ファイル名が重複している場合、xx[0].txtのように連番を付ける
668             string fileNameBase = FormUtils.ReplaceInvalidFileNameChars(text);
669             fileName = fileNameBase + ".txt";
670             logName = fileNameBase + ".log";
671             bool success = false;
672             for (int i = 0; i < 100000; i++)
673             {
674                 // ※100000まで試して空きが見つからないことは無いはず、もし見つからなかったら最後のを上書き
675                 if (!File.Exists(Path.Combine(dir, fileName))
676                     && !File.Exists(Path.Combine(dir, logName)))
677                 {
678                     success = true;
679                     break;
680                 }
681
682                 fileName = fileNameBase + "[" + i + "]" + ".txt";
683                 logName = fileNameBase + "[" + i + "]" + ".log";
684             }
685
686             // 結果設定
687             return success;
688         }
689
690         /// <summary>
691         /// 翻訳支援処理クラスのログ更新イベント用。
692         /// </summary>
693         /// <param name="sender">イベント発生オブジェクト。</param>
694         /// <param name="e">発生したイベント。</param>
695         private void GetLogUpdate(object sender, EventArgs e)
696         {
697             // 前回以降に追加されたログをテキストボックスに出力
698             int length = this.translator.Log.Length;
699             if (length > this.logLength)
700             {
701                 this.textBoxLog.AppendText(this.translator.Log.Substring(this.logLength, length - this.logLength));
702             }
703
704             this.logLength = length;
705         }
706
707         /// <summary>
708         /// 翻訳支援処理クラスの処理状態更新イベント用。
709         /// </summary>
710         /// <param name="sender">イベント発生オブジェクト。</param>
711         /// <param name="e">発生したイベント。</param>
712         private void GetStatusUpdate(object sender, EventArgs e)
713         {
714             // 処理状態をステータスバーに通知
715             this.toolStripStatusLabelStatus.Text = this.translator.Status;
716         }
717
718         /// <summary>
719         /// アプリケーションの現在の表示言語を変更、再起動する。
720         /// </summary>
721         /// <param name="name">変更先カルチャ名。</param>
722         private void ChangeCultureAndRestart(string name)
723         {
724             // 表示言語設定を保存した後、アプリケーションを再起動
725             Settings.Default.LastSelectedLanguage = name;
726             this.SaveSettings();
727             Application.Restart();
728             this.Close();
729         }
730
731         #endregion
732     }
733 }