1 // ================================================================================================
3 // Wikipedia翻訳支援ツール主画面クラスソース</summary>
5 // <copyright file="MainForm.cs" company="honeplusのメモ帳">
6 // Copyright (C) 2012 Honeplus. All rights reserved.</copyright>
9 // ================================================================================================
11 namespace Honememo.Wptscs
14 using System.Collections.Generic;
15 using System.ComponentModel;
20 using System.Windows.Forms;
21 using Honememo.Utilities;
22 using Honememo.Wptscs.Logics;
23 using Honememo.Wptscs.Models;
24 using Honememo.Wptscs.Properties;
25 using Honememo.Wptscs.Utilities;
26 using Honememo.Wptscs.Websites;
29 /// Wikipedia翻訳支援ツール主画面のクラスです。
31 public partial class MainForm : Form
36 /// 現在読み込んでいるアプリケーションの設定。
38 private Config config;
43 private Translator translator;
48 private int logLength;
55 /// コンストラクタ。初期化メソッド呼び出しのみ。
59 // Windows フォーム デザイナで生成されたコード
60 this.InitializeComponent();
70 /// <param name="sender">イベント発生オブジェクト。</param>
71 /// <param name="e">発生したイベント。</param>
72 private void MainForm_Load(object sender, EventArgs e)
75 if (!this.LoadConfig())
77 // 読み込み失敗時はどうしようもないのでそのまま終了
81 this.translator = null;
82 Control.CheckForIllegalCrossThreadCalls = false;
88 this.textBoxSaveDirectory.Text = Settings.Default.SaveDirectory;
89 this.comboBoxSource.SelectedText = Settings.Default.LastSelectedSource;
90 this.comboBoxTarget.SelectedText = Settings.Default.LastSelectedTarget;
93 this.ComboBoxSource_SelectedIndexChanged(sender, e);
94 this.ComboBoxTarget_SelectedIndexChanged(sender, e);
98 /// フォームクローズ時の処理。処理状態を保存。
100 /// <param name="sender">イベント発生オブジェクト。</param>
101 /// <param name="e">発生したイベント。</param>
102 private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
104 // 現在の作業フォルダ、絞込み文字列を保存
105 Settings.Default.SaveDirectory = this.textBoxSaveDirectory.Text;
106 Settings.Default.LastSelectedSource = this.comboBoxSource.Text;
107 Settings.Default.LastSelectedTarget = this.comboBoxTarget.Text;
108 Settings.Default.Save();
112 /// 翻訳元コンボボックス変更時の処理。
114 /// <param name="sender">イベント発生オブジェクト。</param>
115 /// <param name="e">発生したイベント。</param>
116 private void ComboBoxSource_SelectedIndexChanged(object sender, EventArgs e)
119 this.labelSource.Text = String.Empty;
120 this.linkLabelSourceURL.Text = "http://";
121 if (!String.IsNullOrWhiteSpace(this.comboBoxSource.Text))
123 this.comboBoxSource.Text = this.comboBoxSource.Text.Trim().ToLower();
125 // その言語の、ユーザーが使用している言語での表示名を表示
126 // (日本語環境だったら日本語を、英語だったら英語を)
127 Language.LanguageName name;
128 this.labelSource.Text = String.Empty;
129 if (this.config.GetWebsite(this.comboBoxSource.Text) != null &&
130 this.config.GetWebsite(this.comboBoxSource.Text).Language.Names.TryGetValue(
131 System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName,
134 this.labelSource.Text = name.Name;
138 this.linkLabelSourceURL.Text = this.config.GetWebsite(
139 this.comboBoxSource.Text).Location;
144 /// 翻訳元コンボボックスフォーカス喪失時の処理。
146 /// <param name="sender">イベント発生オブジェクト。</param>
147 /// <param name="e">発生したイベント。</param>
148 private void ComboBoxSource_Leave(object sender, EventArgs e)
150 // 直接入力された場合の対策、変更時の処理をコール
151 this.ComboBoxSource_SelectedIndexChanged(sender, e);
155 /// リンクラベルのリンククリック時の処理。
157 /// <param name="sender">イベント発生オブジェクト。</param>
158 /// <param name="e">発生したイベント。</param>
159 private void LinkLabelSourceURL_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
162 System.Diagnostics.Process.Start(((LinkLabel)sender).Text);
166 /// 翻訳先コンボボックス変更時の処理。
168 /// <param name="sender">イベント発生オブジェクト。</param>
169 /// <param name="e">発生したイベント。</param>
170 private void ComboBoxTarget_SelectedIndexChanged(object sender, EventArgs e)
173 this.labelTarget.Text = String.Empty;
174 if (!String.IsNullOrWhiteSpace(this.comboBoxTarget.Text))
176 this.comboBoxTarget.Text = this.comboBoxTarget.Text.Trim().ToLower();
178 // その言語の、ユーザーが使用している言語での表示名を表示
179 // (日本語環境だったら日本語を、英語だったら英語を)
180 if (this.config.GetWebsite(
181 this.comboBoxTarget.Text) != null)
183 this.labelTarget.Text = this.config.GetWebsite(
184 this.comboBoxTarget.Text).Language.Names[System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName].Name;
190 /// 翻訳先コンボボックスフォーカス喪失時の処理。
192 /// <param name="sender">イベント発生オブジェクト。</param>
193 /// <param name="e">発生したイベント。</param>
194 private void ComboBoxTarget_Leave(object sender, EventArgs e)
196 // 直接入力された場合の対策、変更時の処理をコール
197 this.ComboBoxTarget_SelectedIndexChanged(sender, e);
203 /// <param name="sender">イベント発生オブジェクト。</param>
204 /// <param name="e">発生したイベント。</param>
205 private void ButtonConfig_Click(object sender, EventArgs e)
208 ConfigForm form = new ConfigForm(this.config);
211 // 戻ってきたら設定ファイルを再読み込み
216 string backupSourceSelected = this.comboBoxSource.SelectedText;
217 string backupSourceTarget = this.comboBoxTarget.SelectedText;
219 this.comboBoxSource.SelectedText = backupSourceSelected;
220 this.comboBoxTarget.SelectedText = backupSourceTarget;
223 this.ComboBoxSource_SelectedIndexChanged(sender, e);
224 this.ComboBoxTarget_SelectedIndexChanged(sender, e);
230 /// <param name="sender">イベント発生オブジェクト。</param>
231 /// <param name="e">発生したイベント。</param>
232 private void ButtonSaveDirectory_Click(object sender, EventArgs e)
234 // フォルダ名が入力されている場合、それを初期位置に設定
235 if (!String.IsNullOrEmpty(this.textBoxSaveDirectory.Text))
237 this.folderBrowserDialogSaveDirectory.SelectedPath = this.textBoxSaveDirectory.Text;
241 if (this.folderBrowserDialogSaveDirectory.ShowDialog() == System.Windows.Forms.DialogResult.OK)
243 // フォルダが選択された場合、フォルダ名に選択されたフォルダを設定
244 this.textBoxSaveDirectory.Text = this.folderBrowserDialogSaveDirectory.SelectedPath;
249 /// 出力先テキストボックスフォーカス喪失時の処理。
251 /// <param name="sender">イベント発生オブジェクト。</param>
252 /// <param name="e">発生したイベント。</param>
253 private void TextBoxSaveDirectory_Leave(object sender, EventArgs e)
256 this.textBoxSaveDirectory.Text = this.textBoxSaveDirectory.Text.Trim();
262 /// <param name="sender">イベント発生オブジェクト。</param>
263 /// <param name="e">発生したイベント。</param>
264 private void ButtonRun_Click(object sender, EventArgs e)
267 if (String.IsNullOrWhiteSpace(this.comboBoxSource.Text))
269 FormUtils.WarningDialog(Resources.WarningMessageNotSelectedSource);
270 this.comboBoxSource.Focus();
273 else if (String.IsNullOrWhiteSpace(this.comboBoxTarget.Text))
275 FormUtils.WarningDialog(Resources.WarningMessageNotSelectedTarget);
276 this.comboBoxTarget.Focus();
279 else if (!String.IsNullOrWhiteSpace(this.comboBoxSource.Text)
280 && this.comboBoxSource.Text == this.comboBoxTarget.Text)
282 FormUtils.WarningDialog(Resources.WarningMessageEqualsSourceAndTarget);
283 this.comboBoxTarget.Focus();
286 else if (String.IsNullOrWhiteSpace(this.textBoxSaveDirectory.Text))
288 FormUtils.WarningDialog(Resources.WarningMessageEmptySaveDirectory);
289 this.textBoxSaveDirectory.Focus();
292 else if (!Directory.Exists(this.textBoxSaveDirectory.Text))
294 FormUtils.WarningDialog(Resources.WarningMessageIgnoreSaveDirectory);
295 this.textBoxSaveDirectory.Focus();
298 else if (String.IsNullOrWhiteSpace(this.textBoxArticle.Text))
300 FormUtils.WarningDialog(Resources.WarningMessageEmptyArticle);
301 this.textBoxArticle.Focus();
306 this.LockOperation();
309 this.backgroundWorkerRun.RunWorkerAsync();
315 /// <param name="sender">イベント発生オブジェクト。</param>
316 /// <param name="e">発生したイベント。</param>
317 private void ButtonStop_Click(object sender, EventArgs e)
320 this.buttonStop.Enabled = false;
321 if (this.backgroundWorkerRun.IsBusy == true)
323 System.Diagnostics.Debug.WriteLine("MainForm.-Stop_Click > 処理中断");
324 this.backgroundWorkerRun.CancelAsync();
325 if (this.translator != null)
327 this.translator.CancellationPending = true;
333 /// 実行ボタン バックグラウンド処理(スレッド)。
335 /// <param name="sender">イベント発生オブジェクト。</param>
336 /// <param name="e">発生したイベント。</param>
337 private void BackgroundWorkerRun_DoWork(object sender, DoWorkEventArgs e)
342 this.textBoxLog.Clear();
344 this.textBoxLog.AppendText(String.Format(Resources.LogMessageStart, FormUtils.ApplicationName(), DateTime.Now.ToString("F")));
346 // 翻訳支援処理ロジックのオブジェクトを生成
349 this.translator = Translator.Create(this.config, this.comboBoxSource.Text, this.comboBoxTarget.Text);
351 catch (NotImplementedException)
353 // 設定ファイルに対応していないパターンが書かれている場合の例外、将来の拡張用
354 this.textBoxLog.AppendText(String.Format(Resources.InformationMessageDevelopingMethod, "Wikipedia以外の処理"));
355 FormUtils.InformationDialog(Resources.InformationMessageDevelopingMethod, "Wikipedia以外の処理");
359 // ログ・処理状態更新通知を受け取るためのイベント登録
361 this.translator.LogUpdate += new EventHandler(this.GetLogUpdate);
362 this.translator.StatusUpdate += new EventHandler(this.GetStatusUpdate);
363 this.Invoke((MethodInvoker)delegate { this.timerStatusStopwatch.Start(); });
369 this.translator.Run(this.textBoxArticle.Text.Trim());
371 catch (ApplicationException)
373 // 中止要求で停止した場合、その旨イベントに格納する
374 e.Cancel = this.backgroundWorkerRun.CancellationPending;
380 this.Invoke((MethodInvoker)delegate { this.timerStatusStopwatch.Stop(); });
383 // 実行結果から、ログと変換後テキストをファイル出力
384 this.WriteResult(success);
388 this.textBoxLog.AppendText("\r\n" + String.Format(Resources.ErrorMessageDevelopmentError, ex.Message, ex.StackTrace) + "\r\n");
393 /// 実行ボタン バックグラウンド処理(終了時)。
395 /// <param name="sender">イベント発生オブジェクト。</param>
396 /// <param name="e">発生したイベント。</param>
397 private void BackgroundWorkerRun_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
400 // ※ 微妙に時間がかかるので、ステータスバーに通知
403 this.toolStripStatusLabelStatus.Text = Resources.StatusCacheUpdating;
406 this.config.Save(Settings.Default.ConfigurationFile);
410 this.toolStripStatusLabelStatus.Text = String.Empty;
415 FormUtils.WarningDialog(
416 Resources.WarningMessageCacheSaveFailed,
425 /// ステータスバー処理時間更新タイマー処理。
427 /// <param name="sender">イベント発生オブジェクト。</param>
428 /// <param name="e">発生したイベント。</param>
429 private void TimerStatusStopwatch_Tick(object sender, EventArgs e)
432 this.toolStripStatusLabelStopwatch.Text = String.Format(Resources.ElapsedTime, this.translator.Stopwatch.Elapsed);
442 private void Initialize()
445 this.comboBoxSource.Items.Clear();
446 this.comboBoxTarget.Items.Clear();
448 // 設定ファイルに存在する全言語を選択肢として登録する
449 foreach (Website site in this.config.Websites)
451 this.comboBoxSource.Items.Add(site.Language.Code);
452 this.comboBoxTarget.Items.Add(site.Language.Code);
459 /// <returns>読み込み成功時は<c>true</c>。</returns>
460 private bool LoadConfig()
463 // ※ 微妙に時間がかかるので、ステータスバーに通知
466 this.toolStripStatusLabelStatus.Text = Resources.StatusConfigReading;
469 this.config = Config.GetInstance(Settings.Default.ConfigurationFile);
473 this.toolStripStatusLabelStatus.Text = String.Empty;
476 catch (FileNotFoundException ex)
479 System.Diagnostics.Debug.WriteLine(
480 "MainForm.LoadConfig > 設定ファイル読み込み失敗 : " + ex.Message);
481 FormUtils.ErrorDialog(
482 Resources.ErrorMessageConfigNotFound,
483 Settings.Default.ConfigurationFile);
489 System.Diagnostics.Debug.WriteLine(
490 "MainForm.LoadConfig > 設定ファイル読み込み時エラー : " + ex.StackTrace);
491 FormUtils.ErrorDialog(
492 Resources.ErrorMessageConfigLordFailed,
504 private void LockOperation()
507 this.groupBoxTransfer.Enabled = false;
508 this.groupBoxSaveDirectory.Enabled = false;
509 this.textBoxArticle.Enabled = false;
510 this.buttonRun.Enabled = false;
513 this.buttonStop.Enabled = true;
519 private void Release()
522 this.buttonStop.Enabled = false;
525 this.groupBoxTransfer.Enabled = true;
526 this.groupBoxSaveDirectory.Enabled = true;
527 this.textBoxArticle.Enabled = true;
528 this.buttonRun.Enabled = true;
532 /// 翻訳支援処理のログ・変換後テキストをファイル出力。
534 /// <param name="success">翻訳支援処理が成功した場合<c>true</c>。</param>
535 private void WriteResult(bool success)
537 // 若干時間がかかるのでステータスバーに通知
538 this.toolStripStatusLabelStatus.Text = Resources.StatusFileWriting;
544 this.MakeFileName(out fileName, out logName, this.textBoxArticle.Text.Trim(), this.textBoxSaveDirectory.Text);
548 // 翻訳支援処理成功時は変換後テキストを出力
551 File.WriteAllText(Path.Combine(this.textBoxSaveDirectory.Text, fileName), this.translator.Text);
552 this.textBoxLog.AppendText(String.Format(Resources.LogMessageEnd, fileName, logName));
556 this.textBoxLog.AppendText(String.Format(Resources.LogMessageFileSaveFailed, Path.Combine(this.textBoxSaveDirectory.Text, fileName), ex.Message));
557 this.textBoxLog.AppendText(String.Format(Resources.LogMessageStop, logName));
562 this.textBoxLog.AppendText(String.Format(Resources.LogMessageStop, logName));
568 File.WriteAllText(Path.Combine(this.textBoxSaveDirectory.Text, logName), this.textBoxLog.Text);
572 this.textBoxLog.AppendText(String.Format(Resources.LogMessageFileSaveFailed, Path.Combine(this.textBoxSaveDirectory.Text, logName), ex.Message));
578 this.toolStripStatusLabelStatus.Text = String.Empty;
583 /// 渡された文字列から.txtと.logの重複していないファイル名を作成。
585 /// <param name="fileName">出力結果ファイル名。</param>
586 /// <param name="logName">出力ログファイル名。</param>
587 /// <param name="text">出力する結果テキスト。</param>
588 /// <param name="dir">出力先ディレクトリ。</param>
589 /// <returns><c>true</c> 出力成功</returns>
590 private bool MakeFileName(out string fileName, out string logName, string text, string dir)
592 // 出力先フォルダに存在しないファイル名(の拡張子より前)を作成
593 // ※渡されたWikipedia等の記事名にファイル名に使えない文字が含まれている場合、_ に置き換える
594 // また、ファイル名が重複している場合、xx[0].txtのように連番を付ける
595 string fileNameBase = FormUtils.ReplaceInvalidFileNameChars(text);
596 fileName = fileNameBase + ".txt";
597 logName = fileNameBase + ".log";
598 bool success = false;
599 for (int i = 0; i < 100000; i++)
601 // ※100000まで試して空きが見つからないことは無いはず、もし見つからなかったら最後のを上書き
602 if (!File.Exists(Path.Combine(dir, fileName))
603 && !File.Exists(Path.Combine(dir, logName)))
609 fileName = fileNameBase + "[" + i + "]" + ".txt";
610 logName = fileNameBase + "[" + i + "]" + ".log";
618 /// 翻訳支援処理クラスのログ更新イベント用。
620 /// <param name="sender">イベント発生オブジェクト。</param>
621 /// <param name="e">発生したイベント。</param>
622 private void GetLogUpdate(object sender, EventArgs e)
624 // 前回以降に追加されたログをテキストボックスに出力
625 int length = this.translator.Log.Length;
626 if (length > this.logLength)
628 this.textBoxLog.AppendText(this.translator.Log.Substring(this.logLength, length - this.logLength));
631 this.logLength = length;
635 /// 翻訳支援処理クラスの処理状態更新イベント用。
637 /// <param name="sender">イベント発生オブジェクト。</param>
638 /// <param name="e">発生したイベント。</param>
639 private void GetStatusUpdate(object sender, EventArgs e)
642 this.toolStripStatusLabelStatus.Text = this.translator.Status;