1 // ================================================================================================
3 // Wikipedia翻訳支援ツール設定画面クラスソース</summary>
5 // <copyright file="ConfigForm.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;
19 using System.Reflection;
21 using System.Windows.Forms;
22 using Honememo.Utilities;
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 ConfigForm : Form
36 /// 現在設定中のアプリケーションの設定。
38 /// <remarks>設定画面を閉じた後は再読み込みされるので、必要に応じて随時更新してよい。</remarks>
39 private Config config;
42 /// <seealso cref="comboBoxLanguage"/>で選択していたアイテムのバックアップ。
44 private string comboBoxLanguageSelectedText;
53 /// <param name="config">設定対象のConfig。</param>
54 /// <remarks>configは設定画面の操作により随時更新される。呼び出し元では再読み込みすること。</remarks>
55 public ConfigForm(Config config)
57 this.InitializeComponent();
60 this.config = Honememo.Utilities.Validate.NotNull(config, "config");
65 #region フォームの各イベントのメソッド
70 /// <param name="sender">イベント発生オブジェクト。</param>
71 /// <param name="e">発生したイベント。</param>
72 private void ConfigForm_Load(object sender, EventArgs e)
79 this.ImportTranslationDictionaryView(this.dataGridViewItems, this.config.ItemTables);
82 this.ImportTranslationTableView(this.dataGridViewHeading, this.config.HeadingTable);
85 foreach (Website site in this.config.Websites)
87 this.comboBoxLanguage.Items.Add(site.Language.Code);
91 this.textBoxCacheExpire.Text = Settings.Default.CacheExpire.Days.ToString();
92 this.textBoxUserAgent.Text = Settings.Default.UserAgent;
93 this.textBoxReferer.Text = Settings.Default.Referer;
94 this.textBoxMaxConnectRetries.Text = Settings.Default.MaxConnectRetries.ToString();
95 this.textBoxConnectRetryTime.Text = Settings.Default.ConnectRetryTime.ToString();
96 this.checkBoxIgnoreError.Checked = Settings.Default.IgnoreError;
97 this.labelApplicationName.Text = FormUtils.ApplicationName();
98 AssemblyCopyrightAttribute copyright = Attribute.GetCustomAttribute(
99 Assembly.GetExecutingAssembly(),
100 typeof(AssemblyCopyrightAttribute)) as AssemblyCopyrightAttribute;
101 if (copyright != null)
103 this.labelCopyright.Text = copyright.Copyright;
108 // 通常この処理では例外は発生しないはず(Configに読めているので)。想定外のエラー用
109 FormUtils.ErrorDialog(Resources.ErrorMessageDevelopmentError, ex.Message, ex.StackTrace);
116 /// <param name="sender">イベント発生オブジェクト。</param>
117 /// <param name="e">発生したイベント。</param>
118 private void ButtonOk_Click(object sender, EventArgs e)
122 // 各タブの内容を設定ファイルに保存する
125 this.config.ItemTables = this.ExportTranslationDictionaryView(this.dataGridViewItems);
128 this.config.HeadingTable = this.ExportTranslationTableView(this.dataGridViewHeading);
131 // ※ このタブはコンボボックス変更のタイミングで保存されるので、そのメソッドを呼ぶ
132 this.ComboBoxLanguuage_SelectedIndexChanged(sender, e);
135 Settings.Default.CacheExpire = new TimeSpan(int.Parse(this.textBoxCacheExpire.Text), 0, 0, 0);
136 Settings.Default.UserAgent = this.textBoxUserAgent.Text;
137 Settings.Default.Referer = this.textBoxReferer.Text;
138 Settings.Default.MaxConnectRetries = int.Parse(this.textBoxMaxConnectRetries.Text);
139 Settings.Default.ConnectRetryTime = int.Parse(this.textBoxConnectRetryTime.Text);
140 Settings.Default.IgnoreError = this.checkBoxIgnoreError.Checked;
143 Settings.Default.Save();
149 // ※ エラーの場合、どうしても駄目ならキャンセルボタンで閉じてもらう
155 System.Diagnostics.Debug.WriteLine(ex.StackTrace);
156 FormUtils.ErrorDialog(Resources.ErrorMessageConfigSaveFailed, ex.Message);
161 // 通常ファイル保存以外では例外は発生しないはず。想定外のエラー用
162 FormUtils.ErrorDialog(Resources.ErrorMessageDevelopmentError, ex.Message, ex.StackTrace);
168 #region 記事の置き換えタブのイベントのメソッド
171 /// 記事の置き換え対訳表への行追加時の処理。
173 /// <param name="sender">イベント発生オブジェクト。</param>
174 /// <param name="e">発生したイベント。</param>
175 private void DataGridViewItems_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
177 for (int i = e.RowIndex - 1; i < this.dataGridViewItems.Rows.Count; i++)
179 // プログラムから追加された場合は現在のインデックス、画面から追加した場合は+1したインデックスが来る
182 this.dataGridViewItems.Rows[i].Cells["ColumnArrow"].Value = Resources.RightArrow;
188 /// 記事の置き換え対訳表のセル編集時のバリデート処理。
190 /// <param name="sender">イベント発生オブジェクト。</param>
191 /// <param name="e">発生したイベント。</param>
192 private void DataGridViewItems_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
195 if (this.dataGridViewItems.Columns[e.ColumnIndex].Name != "ColumnTimestamp")
200 // 空または日付として認識可能な値の場合OK
201 string value = e.FormattedValue.ToString();
203 if (String.IsNullOrWhiteSpace(value) || DateTime.TryParse(value, out dummy))
208 // 不許可値の場合、NGメッセージを表示
209 this.dataGridViewItems.Rows[e.RowIndex].ErrorText = Resources.WarningMessageUnformatedTimestamp;
214 /// 記事の置き換え対訳表のセル編集時のバリデート成功時の処理。
216 /// <param name="sender">イベント発生オブジェクト。</param>
217 /// <param name="e">発生したイベント。</param>
218 private void DataGridViewItems_CellValidated(object sender, DataGridViewCellEventArgs e)
220 // 取得日時列の場合、バリデートNGメッセージを消す
221 // ※ 他の列で消さないのは、エラーを出しているのがRowValidatingの場合もあるから
222 if (this.dataGridViewItems.Columns[e.ColumnIndex].Name == "ColumnTimestamp")
224 this.dataGridViewItems.Rows[e.RowIndex].ErrorText = String.Empty;
229 /// 記事の置き換え対訳表のセル変更時の処理。
231 /// <param name="sender">イベント発生オブジェクト。</param>
232 /// <param name="e">発生したイベント。</param>
233 private void DataGridViewItems_CellValueChanged(object sender, DataGridViewCellEventArgs e)
235 // 取得日時列が空の場合、有効期限が無期限として背景色を変更
236 // ※ ただし全列が空(新規行など)の場合は無視
239 DataGridViewRow row = this.dataGridViewItems.Rows[e.RowIndex];
240 if (String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnTimestamp"]))
241 && !this.IsEmptyDataGridViewItemsRow(row))
244 row.DefaultCellStyle.BackColor = Color.Bisque;
246 else if (row.InheritedStyle.BackColor != this.dataGridViewItems.DefaultCellStyle.BackColor)
249 // ※ DefaultCellStyleプロパティにアクセスしたタイミングでインスタンスが
250 // 作成されてしまうため、InheritedStyleを調べて変更が必要な場合だけアクセス
251 row.DefaultCellStyle.BackColor = this.dataGridViewItems.DefaultCellStyle.BackColor;
257 /// 記事の置き換え対訳表の行編集時のバリデート処理。
259 /// <param name="sender">イベント発生オブジェクト。</param>
260 /// <param name="e">発生したイベント。</param>
261 private void DataGridViewItems_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
263 // 翻訳元、記事名、翻訳先が未入力の場合、バリデートNGメッセージを表示
264 // ※ ただし全列が空(新規行など)の場合は無視
265 DataGridViewRow row = this.dataGridViewItems.Rows[e.RowIndex];
266 if ((String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnFromCode"]))
267 || String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnToCode"]))
268 || String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnFromTitle"])))
269 && !this.IsEmptyDataGridViewItemsRow(row))
271 row.ErrorText = Resources.WarningMessageEmptyTranslationDictionary;
277 /// 記事の置き換え対訳表を使用する<see cref="DataGridView"/>の値設定を行う。
279 /// <param name="view">対訳表を表示するビュー。</param>
280 /// <param name="dictionaries">対訳表データ。</param>
281 private void ImportTranslationDictionaryView(DataGridView view, IList<TranslationDictionary> dictionaries)
283 // 初期設定以外の場合も想定して最初にクリア
285 foreach (TranslationDictionary dic in dictionaries)
287 foreach (KeyValuePair<string, TranslationDictionary.Item> item in dic)
290 DataGridViewRow row = view.Rows[view.Rows.Add()];
292 // 1行分の初期値を設定。右矢印は別途イベントで追加すること
293 row.Cells["ColumnFromCode"].Value = dic.From;
294 row.Cells["ColumnFromTitle"].Value = item.Key;
295 row.Cells["ColumnAlias"].Value = item.Value.Alias;
296 row.Cells["ColumnToCode"].Value = dic.To;
297 row.Cells["ColumnToTitle"].Value = item.Value.Word;
298 if (item.Value.Timestamp.HasValue)
300 row.Cells["ColumnTimestamp"].Value = item.Value.Timestamp.Value.ToLocalTime().ToString("G");
305 // 取得日時の降順でソート、空の列は先頭にする
306 this.dataGridViewItems.Sort(new TranslationDictionaryViewComparer());
309 // ※ 常に行ってしまうと、読み込みに非常に時間がかかるため
310 view.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
314 /// 記事の置き換え対訳表を使用する<see cref="DataGridView"/>からデータを抽出する。
316 /// <param name="view">対訳表を表示するビュー。</param>
317 /// <returns>対訳表データ。</returns>
318 private IList<TranslationDictionary> ExportTranslationDictionaryView(DataGridView view)
320 IList<TranslationDictionary> dictionaries = new List<TranslationDictionary>();
321 foreach (DataGridViewRow row in view.Rows)
323 // 画面での追加用の最終行が空で渡されてくるので無視
324 if (this.IsEmptyDataGridViewItemsRow(row))
329 // その行で対象とする言語を探索、無ければ新規作成
330 string from = FormUtils.ToString(row.Cells["ColumnFromCode"]);
331 string to = FormUtils.ToString(row.Cells["ColumnToCode"]);
332 TranslationDictionary dic
333 = TranslationDictionary.GetDictionaryNeedCreate(dictionaries, from, to);
336 TranslationDictionary.Item item = new TranslationDictionary.Item
338 Word = FormUtils.ToString(row.Cells["ColumnToTitle"]),
339 Alias = FormUtils.ToString(row.Cells["ColumnAlias"])
342 string timestamp = FormUtils.ToString(row.Cells["ColumnTimestamp"]);
343 if (!String.IsNullOrWhiteSpace(timestamp))
345 item.Timestamp = DateTime.Parse(timestamp);
347 // UTCでもなくタイムゾーンでも無い場合、ローカル時刻として設定する
348 if (item.Timestamp.Value.Kind == DateTimeKind.Unspecified)
350 item.Timestamp = DateTime.SpecifyKind(item.Timestamp.Value, DateTimeKind.Local);
354 dic[FormUtils.ToString(row.Cells["ColumnFromTitle"])] = item;
361 /// 記事の置き換え対訳表の行が空かを判定する。
363 /// <param name="row">対訳表の1行。</param>
364 /// <returns>空の場合<c>true</c>。</returns>
365 private bool IsEmptyDataGridViewItemsRow(DataGridViewRow row)
367 return String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnFromCode"]))
368 && String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnFromTitle"]))
369 && String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnAlias"]))
370 && String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnToCode"]))
371 && String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnToTitle"]))
372 && String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnTimestamp"]));
377 #region 見出しの置き換えタブのイベントのメソッド
380 /// 見出しの置き換え対訳表を使用する<see cref="DataGridView"/>の値設定を行う。
382 /// <param name="view">対訳表を表示するビュー。</param>
383 /// <param name="table">対訳表データ。</param>
384 private void ImportTranslationTableView(DataGridView view, TranslationTable table)
386 // 初期設定以外の場合も想定して最初にクリア
387 view.Columns.Clear();
389 // 言語コードを列、語句を行とする。登録されている全言語分の列を作成する
390 foreach (Website site in this.config.Websites)
392 this.AddTranslationTableColumn(view.Columns, site.Language.Code, this.GetHeaderLanguage(site.Language));
396 foreach (IDictionary<string, string> record in table)
399 DataGridViewRow row = view.Rows[view.Rows.Add()];
401 foreach (KeyValuePair<string, string> cell in record)
403 // 上で登録した列では足りなかった場合、その都度生成する
404 if (!view.Columns.Contains(cell.Key))
406 this.AddTranslationTableColumn(view.Columns, cell.Key, cell.Key);
409 row.Cells[cell.Key].Value = cell.Value;
414 // ※ 常に行ってしまうと、読み込みに時間がかかるため
415 view.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
419 /// 見出しの置き換え対訳表を使用する<see cref="DataGridView"/>からデータを抽出する。
421 /// <param name="view">対訳表を表示するビュー。</param>
422 /// <returns>対訳表データ。</returns>
423 private TranslationTable ExportTranslationTableView(DataGridView view)
425 TranslationTable table = new TranslationTable();
426 foreach (DataGridViewRow row in view.Rows)
428 IDictionary<string, string> record = new SortedDictionary<string, string>();
429 foreach (DataGridViewCell cell in row.Cells)
431 // 空のセルは格納しない、該当の組み合わせは消える
432 string value = FormUtils.ToString(cell);
433 if (!String.IsNullOrWhiteSpace(value))
435 record[cell.OwningColumn.Name] = value;
439 // 1件もデータが無い行は丸々カットする
440 if (record.Count > 0)
450 /// 指定された情報を元に見出しの置き換え対訳表の列を追加する。
452 /// <param name="columns">列コレクション。</param>
453 /// <param name="columnName">列名。</param>
454 /// <param name="headerText">列見出し。</param>
455 private void AddTranslationTableColumn(DataGridViewColumnCollection columns, string columnName, string headerText)
457 columns.Add(columnName, headerText);
463 /// <param name="lang">表示言語コード。</param>
464 /// <returns>表示名、無ければ言語コード。</returns>
465 private string GetHeaderLanguage(Language lang)
467 Language.LanguageName name;
468 if (lang.Names.TryGetValue(
469 System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName, out name))
471 if (!String.IsNullOrEmpty(name.Name))
473 return String.Format(Resources.HeadingViewHeaderText, name.Name, lang.Code);
482 #region 言語/サーバータブのイベントのメソッド
487 /// <param name="sender">イベント発生オブジェクト。</param>
488 /// <param name="e">発生したイベント。</param>
489 private void ComboBoxLanguuage_SelectedIndexChanged(object sender, EventArgs e)
494 if (!String.IsNullOrEmpty(this.comboBoxLanguageSelectedText))
497 this.SaveChangedValue(this.GetMediaWikiNeedCreate(this.config.Websites, this.comboBoxLanguageSelectedText));
501 if (!String.IsNullOrEmpty(this.comboBoxLanguage.Text))
503 // 設定が存在しなければ基本的に自動生成されるのでそのまま使用
504 this.LoadCurrentValue(this.GetMediaWikiNeedCreate(this.config.Websites, this.comboBoxLanguage.Text));
507 this.buttonLanguageRemove.Enabled = true;
508 this.groupBoxServer.Enabled = true;
509 this.groupBoxLanguage.Enabled = true;
512 this.comboBoxLanguageSelectedText = this.comboBoxLanguage.Text;
517 this.buttonLanguageRemove.Enabled = false;
518 this.groupBoxServer.Enabled = false;
519 this.groupBoxLanguage.Enabled = false;
522 this.comboBoxLanguageSelectedText = String.Empty;
527 // 通常この処理では例外は発生しないはず。想定外のエラー用
528 FormUtils.ErrorDialog(Resources.ErrorMessageDevelopmentError, ex.Message, ex.StackTrace);
535 /// <param name="sender">イベント発生オブジェクト。</param>
536 /// <param name="e">発生したイベント。</param>
537 private void ButtonLunguageAdd_Click(object sender, EventArgs e)
540 InputLanguageCodeDialog form = new InputLanguageCodeDialog(this.config);
544 if (!String.IsNullOrWhiteSpace(form.LanguageCode))
546 // 値を一覧・見出しの対訳表に追加、登録した値を選択状態に変更
547 this.comboBoxLanguage.Items.Add(form.LanguageCode);
548 this.dataGridViewHeading.Columns.Add(form.LanguageCode, form.LanguageCode);
549 this.comboBoxLanguage.SelectedItem = form.LanguageCode;
556 /// <param name="sender">イベント発生オブジェクト。</param>
557 /// <param name="e">発生したイベント。</param>
558 private void ButtonLanguageRemove_Click(object sender, EventArgs e)
560 // 表示されている言語を設定から削除する
561 for (int i = this.config.Websites.Count - 1; i >= 0; i--)
563 if (this.config.Websites[i].Language.Code == this.comboBoxLanguage.Text)
566 this.config.Websites.RemoveAt(i);
570 // コンボボックスからも削除し、表示を更新する
571 this.comboBoxLanguageSelectedText = null;
572 this.comboBoxLanguage.Items.Remove(this.comboBoxLanguage.Text);
573 this.ComboBoxLanguuage_SelectedIndexChanged(sender, e);
577 /// 各名前空間のIDボックスバリデート処理。
579 /// <param name="sender">イベント発生オブジェクト。</param>
580 /// <param name="e">発生したイベント。</param>
581 private void TextBoxNamespace_Validating(object sender, CancelEventArgs e)
584 TextBox box = (TextBox)sender;
585 box.Text = StringUtils.DefaultString(box.Text).Trim();
587 if (!String.IsNullOrEmpty(box.Text) && !int.TryParse(box.Text, out value))
589 this.errorProvider.SetError(box, Resources.WarningMessageIgnoreNumericNamespace);
595 /// 言語の設定表の行編集時のバリデート処理。
597 /// <param name="sender">イベント発生オブジェクト。</param>
598 /// <param name="e">発生したイベント。</param>
599 private void DataGridViewLanguageName_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
601 DataGridViewRow row = this.dataGridViewLanguageName.Rows[e.RowIndex];
604 if (FormUtils.IsEmptyRow(row))
609 // 言語コードは必須、またトリムして小文字に変換
610 string code = FormUtils.ToString(row.Cells["ColumnCode"]).Trim().ToLower();
611 row.Cells["ColumnCode"].Value = code;
612 if (String.IsNullOrEmpty(code))
614 row.ErrorText = Resources.WarningMessageEmptyCodeColumn;
619 // 略称を設定する場合、呼称を必須とする
620 if (!String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnShortName"]))
621 && String.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnName"])))
623 row.ErrorText = Resources.WarningMessageShortNameColumnOnly;
631 /// <param name="sender">イベント発生オブジェクト。</param>
632 /// <param name="e">発生したイベント。</param>
633 private void DataGridViewLanguageName_Validating(object sender, CancelEventArgs e)
636 IDictionary<string, int> codeMap = new Dictionary<string, int>();
637 for (int i = 0; i < this.dataGridViewLanguageName.RowCount - 1; i++)
639 string code = FormUtils.ToString(this.dataGridViewLanguageName["ColumnCode", i]);
641 if (codeMap.TryGetValue(code, out y))
644 this.dataGridViewLanguageName.Rows[i].ErrorText = Resources.WarningMessageDuplicateCodeColumn;
645 this.dataGridViewLanguageName.Rows[y].ErrorText = Resources.WarningMessageDuplicateCodeColumn;
650 // それ以外はマップに出現行とともに追加
656 #region イベント実装支援用メソッド
659 /// コレクションから指定された言語のMediaWikiを取得する。
660 /// 存在しない場合は空のインスタンスを生成、コレクションに追加して返す。
662 /// <param name="collection">翻訳元言語。</param>
663 /// <param name="lang">言語コード。</param>
664 /// <returns>翻訳パターン。存在しない場合は新たに作成した翻訳パターンを返す。</returns>
665 private MediaWiki GetMediaWikiNeedCreate(ICollection<Website> collection, string lang)
668 foreach (Website s in collection)
670 if (s.Language.Code == lang)
674 return s as MediaWiki;
677 // 万が一同じ言語コードで違う型の値があったら上書き
678 collection.Remove(s);
683 // 存在しないか上書きの場合、作成した翻訳パターンをコレクションに追加し、返す
684 MediaWiki site = new MediaWiki(new Language(lang));
685 collection.Add(site);
690 /// 指定されたLanguage設定を画面表示/編集用に読み込む。
692 /// <param name="lang">読込元Language設定。</param>
693 /// <remarks>一部パラメータには初期値が存在するが、格納時に対処するため全て読み込む。</remarks>
694 private void LoadCurrentValue(Language lang)
697 // ※ Bracketは初期値があるパラメータのため、必ず値が返る
698 this.textBoxBracket.Text = lang.Bracket;
701 this.dataGridViewLanguageName.Rows.Clear();
702 foreach (KeyValuePair<string, Language.LanguageName> name in lang.Names)
704 int index = this.dataGridViewLanguageName.Rows.Add();
705 this.dataGridViewLanguageName["ColumnCode", index].Value = name.Key;
706 this.dataGridViewLanguageName["ColumnName", index].Value = name.Value.Name;
707 this.dataGridViewLanguageName["ColumnShortName", index].Value = name.Value.ShortName;
712 /// 指定されたWebsite設定を画面表示/編集用に読み込む。
714 /// <param name="site">読込元Website設定。</param>
715 private void LoadCurrentValue(Website site)
717 // Languageクラス分の読み込みを行う
718 this.LoadCurrentValue(site.Language);
721 this.textBoxLocation.Text = site.Location;
725 /// 指定されたMediaWiki設定を画面表示/編集用に読み込む。
727 /// <param name="site">読込元MediaWiki設定。</param>
728 /// <remarks>一部パラメータには初期値が存在するが、格納時に対処するため全て読み込む。</remarks>
729 private void LoadCurrentValue(MediaWiki site)
731 // Websiteクラス分の読み込みを行う
732 this.LoadCurrentValue((Website)site);
734 // MediaWikiクラス分の読み込み
735 this.textBoxExportPath.Text = StringUtils.DefaultString(site.ExportPath);
736 this.textBoxMetaApi.Text = StringUtils.DefaultString(site.MetaApi);
737 this.textBoxTemplateNamespace.Text = site.TemplateNamespace.ToString();
738 this.textBoxCategoryNamespace.Text = site.CategoryNamespace.ToString();
739 this.textBoxFileNamespace.Text = site.FileNamespace.ToString();
740 this.textBoxRedirect.Text = StringUtils.DefaultString(site.Redirect);
742 // Template:Documentionは改行区切りのマルチテキストとして扱う
743 StringBuilder b = new StringBuilder();
744 foreach (string s in site.DocumentationTemplates)
746 b.Append(s).Append(Environment.NewLine);
749 this.textBoxDocumentationTemplate.Text = b.ToString();
750 this.textBoxDocumentationTemplateDefaultPage.Text = StringUtils.DefaultString(site.DocumentationTemplateDefaultPage);
751 this.textBoxLinkInterwikiFormat.Text = StringUtils.DefaultString(site.LinkInterwikiFormat);
752 this.textBoxLangFormat.Text = StringUtils.DefaultString(site.LangFormat);
756 /// 指定されたLanguage設定に画面上で変更された値の格納を行う。
758 /// <param name="lang">格納先Language設定。</param>
759 /// <remarks>一部パラメータには初期値が存在するため、変更がある場合のみ格納する。</remarks>
760 private void SaveChangedValue(Language lang)
762 // Bracketは初期値を持つパラメータのため、変更された場合のみ格納する。
763 // ※ この値は前後の空白に意味があるため、Trimしてはいけない
764 string str = StringUtils.DefaultString(this.textBoxBracket.Text);
765 if (str != lang.Bracket)
771 this.dataGridViewLanguageName.Sort(this.dataGridViewLanguageName.Columns["ColumnCode"], ListSortDirection.Ascending);
773 for (int y = 0; y < this.dataGridViewLanguageName.RowCount - 1; y++)
775 // 値が入ってないとかはガードしているはずだが、一応チェック
776 string code = FormUtils.ToString(this.dataGridViewLanguageName["ColumnCode", y]).Trim();
777 if (!String.IsNullOrEmpty(code))
779 Language.LanguageName name = new Language.LanguageName();
780 name.Name = FormUtils.ToString(this.dataGridViewLanguageName["ColumnName", y]).Trim();
781 name.ShortName = FormUtils.ToString(this.dataGridViewLanguageName["ColumnShortName", y]).Trim();
782 lang.Names[code] = name;
788 /// 指定されたWebsite設定に画面上で変更された値の格納を行う。
790 /// <param name="site">格納先Website設定。</param>
791 /// <remarks>Websiteについては特に特殊な処理は無いため全て上書きする。</remarks>
792 private void SaveChangedValue(Website site)
794 // Languageクラス分の設定を行う
795 this.SaveChangedValue(site.Language);
798 site.Location = StringUtils.DefaultString(this.textBoxLocation.Text).Trim();
802 /// 指定されたMediaWiki設定に画面上で変更された値の格納を行う。
804 /// <param name="site">格納先MediaWiki設定。</param>
805 /// <remarks>一部パラメータには初期値が存在するため、変更がある場合のみ格納する。</remarks>
806 private void SaveChangedValue(MediaWiki site)
809 this.SaveChangedValue((Website)site);
811 // 初期値を持つパラメータがあるため、全て変更された場合のみ格納する。
812 // ※ もうちょっと綺麗に書きたかったが、うまい手が思いつかなかったので力技
813 // MediaWikiクラス側で行わないのは、場合によっては意図的に初期値と同じ値を設定すること
814 // もありえるから(初期値が変わる可能性がある場合など)。
815 string str = StringUtils.DefaultString(this.textBoxExportPath.Text).Trim();
816 if (str != site.ExportPath)
818 site.ExportPath = str;
821 str = StringUtils.DefaultString(this.textBoxMetaApi.Text).Trim();
822 if (str != site.MetaApi)
827 str = StringUtils.DefaultString(this.textBoxRedirect.Text).Trim();
828 if (str != site.Redirect)
833 // Template:Documentionの設定は行ごとに格納
834 // ※ この値は初期値を持たないパラメータ
835 site.DocumentationTemplates.Clear();
836 foreach (string s in StringUtils.DefaultString(this.textBoxDocumentationTemplate.Text).Split('\n'))
838 if (!String.IsNullOrWhiteSpace(s))
840 site.DocumentationTemplates.Add(s.Trim());
844 str = StringUtils.DefaultString(this.textBoxDocumentationTemplateDefaultPage.Text).Trim();
845 if (str != site.DocumentationTemplateDefaultPage)
847 site.DocumentationTemplateDefaultPage = str;
850 str = StringUtils.DefaultString(this.textBoxLinkInterwikiFormat.Text).Trim();
851 if (str != site.LinkInterwikiFormat)
853 site.LinkInterwikiFormat = str;
856 str = StringUtils.DefaultString(this.textBoxLangFormat.Text).Trim();
857 if (str != site.LangFormat)
859 site.LangFormat = str;
862 // 以下、数値へのparseは事前にチェックしてあるので、ここではチェックしない
863 if (!String.IsNullOrWhiteSpace(this.textBoxTemplateNamespace.Text))
865 int num = int.Parse(this.textBoxTemplateNamespace.Text);
866 if (site.TemplateNamespace != num)
868 site.TemplateNamespace = num;
872 if (!String.IsNullOrWhiteSpace(this.textBoxCategoryNamespace.Text))
874 int num = int.Parse(this.textBoxCategoryNamespace.Text);
875 if (site.CategoryNamespace != num)
877 site.CategoryNamespace = num;
881 if (!String.IsNullOrWhiteSpace(this.textBoxFileNamespace.Text))
883 int num = int.Parse(this.textBoxFileNamespace.Text);
884 if (site.FileNamespace != num)
886 site.FileNamespace = num;
895 #region その他タブのイベントのメソッド
898 /// キャッシュ有効期限ボックスバリデート処理。
900 /// <param name="sender">イベント発生オブジェクト。</param>
901 /// <param name="e">発生したイベント。</param>
902 private void TextBoxCacheExpire_Validating(object sender, CancelEventArgs e)
905 this.TextBoxGreaterThanValidating((TextBox)sender, e, 0, Resources.WarningMessageIgnoreCacheExpire);
909 /// リトライ回数ボックスバリデート処理。
911 /// <param name="sender">イベント発生オブジェクト。</param>
912 /// <param name="e">発生したイベント。</param>
913 private void TextBoxMaxConnectRetries_Validating(object sender, CancelEventArgs e)
916 this.TextBoxGreaterThanValidating((TextBox)sender, e, 0, Resources.WarningMessageIgnoreMaxConnectRetries);
920 /// ウェイト時間ボックスバリデート処理。
922 /// <param name="sender">イベント発生オブジェクト。</param>
923 /// <param name="e">発生したイベント。</param>
924 private void TextBoxConnectRetryTime_Validating(object sender, CancelEventArgs e)
927 this.TextBoxGreaterThanValidating((TextBox)sender, e, 0, Resources.WarningMessageIgnoreConnectRetryTime);
931 /// ウェブサイトURLクリック時の処理。
933 /// <param name="sender">イベント発生オブジェクト。</param>
934 /// <param name="e">発生したイベント。</param>
935 private void LinkLabelWebsite_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
938 System.Diagnostics.Process.Start(((LinkLabel)sender).Text);
941 #region イベント実装支援用メソッド
944 /// メッセージのみ差し替え可能なテキストボックス用の値がxx以上の数値か、のバリデート処理。
946 /// <param name="box">イベント発生テキストボックス。</param>
947 /// <param name="e">発生したイベント。</param>
948 /// <param name="num">比較対象の数値。</param>
949 /// <param name="message">バリデートメッセージ。</param>
950 private void TextBoxGreaterThanValidating(TextBox box, CancelEventArgs e, int num, string message)
952 box.Text = StringUtils.DefaultString(box.Text).Trim();
954 if (!int.TryParse(box.Text, out value) || value < num)
956 this.errorProvider.SetError(box, message);
968 /// 汎用のエラープロバイダ初期化処理。
970 /// <param name="sender">イベント発生オブジェクト。</param>
971 /// <param name="e">発生したイベント。</param>
972 private void ResetErrorProvider_Validated(object sender, EventArgs e)
974 this.errorProvider.SetError((Control)sender, null);
978 /// 汎用の行編集時のエラーテキスト初期化処理。
980 /// <param name="sender">イベント発生オブジェクト。</param>
981 /// <param name="e">発生したイベント。</param>
982 private void ResetErrorText_RowValidated(object sender, DataGridViewCellEventArgs e)
984 ((DataGridView)sender).Rows[e.RowIndex].ErrorText = String.Empty;
988 /// 汎用のテーブルエラーテキスト初期化処理。
990 /// <param name="sender">イベント発生オブジェクト。</param>
991 /// <param name="e">発生したイベント。</param>
992 private void ResetErrorText_Validated(object sender, EventArgs e)
995 foreach (DataGridViewRow row in ((DataGridView)sender).Rows)
997 row.ErrorText = String.Empty;
1006 /// 記事の置き換え対訳表の日付並び替え用クラスです。
1008 /// <remarks>取得日時の降順でソート、空の列は先頭にします。</remarks>
1009 public class TranslationDictionaryViewComparer : System.Collections.IComparer
1012 /// 2行を比較し、一方が他方より小さいか、等しいか、大きいかを示す値を返します。
1014 /// <param name="y">比較する最初の行です。</param>
1015 /// <param name="x">比較する 2 番目の行。</param>
1016 /// <returns>1以下:xはyより小さい, 0:等しい, 1以上:xはyより大きい</returns>
1017 public int Compare(object y, object x)
1019 string xstr = ObjectUtils.ToString(((DataGridViewRow)x).Cells["ColumnTimestamp"].Value);
1020 string ystr = ObjectUtils.ToString(((DataGridViewRow)y).Cells["ColumnTimestamp"].Value);
1021 if (String.IsNullOrWhiteSpace(xstr) && String.IsNullOrWhiteSpace(ystr))
1025 else if (String.IsNullOrWhiteSpace(xstr))
1029 else if (String.IsNullOrWhiteSpace(ystr))
1034 return xstr.CompareTo(ystr);