// ================================================================================================ // // Wikipedia翻訳支援ツール設定画面クラスソース // // // Copyright (C) 2013 Honeplus. All rights reserved. // // Honeplus // ================================================================================================ namespace Honememo.Wptscs { using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Windows.Forms; using Honememo.Utilities; using Honememo.Wptscs.Models; using Honememo.Wptscs.Properties; using Honememo.Wptscs.Utilities; using Honememo.Wptscs.Websites; /// /// Wikipedia翻訳支援ツール設定画面のクラスです。 /// public partial class ConfigForm : Form { #region private変数 /// /// 現在設定中のアプリケーションの設定。 /// /// 設定画面を閉じた後は再読み込みされるので、必要に応じて随時更新してよい。 private Config config; /// /// で選択していたアイテムのバックアップ。 /// private string comboBoxLanguageSelectedText; #endregion #region コンストラクタ /// /// コンストラクタ。 /// /// 設定対象のConfig。 /// configは設定画面の操作により随時更新される。呼び出し元では再読み込みすること。 public ConfigForm(Config config) { this.InitializeComponent(); // 設定対象のConfigを受け取る this.config = Honememo.Utilities.Validate.NotNull(config, "config"); } #endregion #region フォームの各イベントのメソッド /// /// フォームロード時の処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void ConfigForm_Load(object sender, EventArgs e) { try { // 各タブの内容を初期化する // 記事の置き換えタブの初期化 this.ImportTranslationDictionaryView(this.dataGridViewItems, this.config.ItemTables); // 見出しの置き換えタブの初期化 this.ImportTranslationTableView(this.dataGridViewHeading, this.config.HeadingTable); // サーバー/言語タブの初期化 foreach (Website site in this.config.Websites) { this.comboBoxLanguage.Items.Add(site.Language.Code); } // その他タブの初期化 this.textBoxCacheExpire.Text = Settings.Default.CacheExpire.Days.ToString(); this.textBoxUserAgent.Text = Settings.Default.UserAgent; this.textBoxReferer.Text = Settings.Default.Referer; this.textBoxMaxConnectRetries.Text = Settings.Default.MaxConnectRetries.ToString(); this.textBoxConnectRetryTime.Text = Settings.Default.ConnectRetryTime.ToString(); this.checkBoxIgnoreError.Checked = Settings.Default.IgnoreError; this.labelApplicationName.Text = FormUtils.ApplicationName(); AssemblyCopyrightAttribute copyright = Attribute.GetCustomAttribute( Assembly.GetExecutingAssembly(), typeof(AssemblyCopyrightAttribute)) as AssemblyCopyrightAttribute; if (copyright != null) { this.labelCopyright.Text = copyright.Copyright; } } catch (Exception ex) { // 通常この処理では例外は発生しないはず(Configに読めているので)。想定外のエラー用 FormUtils.ErrorDialog(Resources.ErrorMessageDevelopmentError, ex.Message, ex.StackTrace); } } /// /// OKボタン押下時の処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void ButtonOk_Click(object sender, EventArgs e) { try { // 各タブの内容を設定ファイルに保存する // 記事の置き換えタブの保存 this.config.ItemTables = this.ExportTranslationDictionaryView(this.dataGridViewItems); // 見出しの置き換えタブの保存 this.config.HeadingTable = this.ExportTranslationTableView(this.dataGridViewHeading); // サーバー/言語タブの保存 // ※ このタブはコンボボックス変更のタイミングで保存されるので、そのメソッドを呼ぶ this.ComboBoxLanguuage_SelectedIndexChanged(sender, e); // その他タブの保存 Settings.Default.CacheExpire = new TimeSpan(int.Parse(this.textBoxCacheExpire.Text), 0, 0, 0); Settings.Default.UserAgent = this.textBoxUserAgent.Text; Settings.Default.Referer = this.textBoxReferer.Text; Settings.Default.MaxConnectRetries = int.Parse(this.textBoxMaxConnectRetries.Text); Settings.Default.ConnectRetryTime = int.Parse(this.textBoxConnectRetryTime.Text); Settings.Default.IgnoreError = this.checkBoxIgnoreError.Checked; // 設定をファイルに保存 Settings.Default.Save(); try { this.config.Save(); // 全部成功なら画面を閉じる // ※ エラーの場合、どうしても駄目ならキャンセルボタンで閉じてもらう this.DialogResult = DialogResult.OK; } catch (Exception ex) { // 異常時はエラーメッセージを表示 System.Diagnostics.Debug.WriteLine(ex.ToString()); FormUtils.ErrorDialog(Resources.ErrorMessageConfigSaveFailed, ex.Message); } } catch (Exception ex) { // 通常ファイル保存以外では例外は発生しないはず。想定外のエラー用 FormUtils.ErrorDialog(Resources.ErrorMessageDevelopmentError, ex.Message, ex.StackTrace); } } #endregion #region 記事の置き換えタブのイベントのメソッド /// /// 記事の置き換え対訳表への行追加時の処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void DataGridViewItems_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) { for (int i = e.RowIndex - 1; i < this.dataGridViewItems.Rows.Count; i++) { // プログラムから追加された場合は現在のインデックス、画面から追加した場合は+1したインデックスが来る if (i >= 0) { this.dataGridViewItems.Rows[i].Cells["ColumnArrow"].Value = Resources.RightArrow; } } } /// /// 記事の置き換え対訳表のセル編集時のバリデート処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void DataGridViewItems_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) { // 取得日時列のみチェック if (this.dataGridViewItems.Columns[e.ColumnIndex].Name != "ColumnTimestamp") { return; } // 空または日付として認識可能な値の場合OK string value = e.FormattedValue.ToString(); DateTime dummy; if (string.IsNullOrWhiteSpace(value) || DateTime.TryParse(value, out dummy)) { return; } // 不許可値の場合、NGメッセージを表示 this.dataGridViewItems.Rows[e.RowIndex].ErrorText = Resources.WarningMessageUnformatedTimestamp; e.Cancel = true; } /// /// 記事の置き換え対訳表のセル編集時のバリデート成功時の処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void DataGridViewItems_CellValidated(object sender, DataGridViewCellEventArgs e) { // 取得日時列の場合、バリデートNGメッセージを消す // ※ 他の列で消さないのは、エラーを出しているのがRowValidatingの場合もあるから if (this.dataGridViewItems.Columns[e.ColumnIndex].Name == "ColumnTimestamp") { this.dataGridViewItems.Rows[e.RowIndex].ErrorText = string.Empty; } } /// /// 記事の置き換え対訳表のセル変更時の処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void DataGridViewItems_CellValueChanged(object sender, DataGridViewCellEventArgs e) { // 取得日時列が空の場合、有効期限が無期限として背景色を変更 // ※ ただし全列が空(新規行など)の場合は無視 if (e.RowIndex >= 0) { DataGridViewRow row = this.dataGridViewItems.Rows[e.RowIndex]; if (string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnTimestamp"])) && !this.IsEmptyDataGridViewItemsRow(row)) { // 背景色を変更 row.DefaultCellStyle.BackColor = Color.Bisque; } else if (row.InheritedStyle.BackColor != this.dataGridViewItems.DefaultCellStyle.BackColor) { // 背景色を戻す // ※ DefaultCellStyleプロパティにアクセスしたタイミングでインスタンスが // 作成されてしまうため、InheritedStyleを調べて変更が必要な場合だけアクセス row.DefaultCellStyle.BackColor = this.dataGridViewItems.DefaultCellStyle.BackColor; } } } /// /// 記事の置き換え対訳表の行編集時のバリデート処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void DataGridViewItems_RowValidating(object sender, DataGridViewCellCancelEventArgs e) { // 翻訳元、記事名、翻訳先が未入力の場合、バリデートNGメッセージを表示 // ※ ただし全列が空(新規行など)の場合は無視 DataGridViewRow row = this.dataGridViewItems.Rows[e.RowIndex]; if ((string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnFromCode"])) || string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnToCode"])) || string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnFromTitle"]))) && !this.IsEmptyDataGridViewItemsRow(row)) { row.ErrorText = Resources.WarningMessageEmptyTranslationDictionary; e.Cancel = true; } } /// /// 記事の置き換え対訳表を使用するの値設定を行う。 /// /// 対訳表を表示するビュー。 /// 対訳表データ。 private void ImportTranslationDictionaryView(DataGridView view, IList dictionaries) { // 初期設定以外の場合も想定して最初にクリア view.Rows.Clear(); foreach (TranslationDictionary dic in dictionaries) { foreach (KeyValuePair item in dic) { // 行を追加しその行を取得 DataGridViewRow row = view.Rows[view.Rows.Add()]; // 1行分の初期値を設定。右矢印は別途イベントで追加すること row.Cells["ColumnFromCode"].Value = dic.From; row.Cells["ColumnFromTitle"].Value = item.Key; row.Cells["ColumnAlias"].Value = item.Value.Alias; row.Cells["ColumnToCode"].Value = dic.To; row.Cells["ColumnToTitle"].Value = item.Value.Word; if (item.Value.Timestamp.HasValue) { row.Cells["ColumnTimestamp"].Value = item.Value.Timestamp.Value.ToLocalTime().ToString("G"); } } } // 取得日時の降順でソート、空の列は先頭にする this.dataGridViewItems.Sort(new TranslationDictionaryViewComparer()); // 列幅をデータ長に応じて自動調整 // ※ 常に行ってしまうと、読み込みに非常に時間がかかるため view.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); } /// /// 記事の置き換え対訳表を使用するからデータを抽出する。 /// /// 対訳表を表示するビュー。 /// 対訳表データ。 private IList ExportTranslationDictionaryView(DataGridView view) { IList dictionaries = new List(); foreach (DataGridViewRow row in view.Rows) { // 画面での追加用の最終行が空で渡されてくるので無視 if (this.IsEmptyDataGridViewItemsRow(row)) { continue; } // その行で対象とする言語を探索、無ければ新規作成 string from = FormUtils.ToString(row.Cells["ColumnFromCode"]); string to = FormUtils.ToString(row.Cells["ColumnToCode"]); TranslationDictionary dic = TranslationDictionary.GetDictionaryNeedCreate(dictionaries, from, to); // 値を格納 TranslationDictionary.Item item = new TranslationDictionary.Item { Word = FormUtils.ToString(row.Cells["ColumnToTitle"]), Alias = FormUtils.ToString(row.Cells["ColumnAlias"]) }; string timestamp = FormUtils.ToString(row.Cells["ColumnTimestamp"]); if (!string.IsNullOrWhiteSpace(timestamp)) { item.Timestamp = DateTime.Parse(timestamp); // UTCでもなくタイムゾーンでも無い場合、ローカル時刻として設定する if (item.Timestamp.Value.Kind == DateTimeKind.Unspecified) { item.Timestamp = DateTime.SpecifyKind(item.Timestamp.Value, DateTimeKind.Local); } } dic[FormUtils.ToString(row.Cells["ColumnFromTitle"])] = item; } return dictionaries; } /// /// 記事の置き換え対訳表の行が空かを判定する。 /// /// 対訳表の1行。 /// 空の場合true private bool IsEmptyDataGridViewItemsRow(DataGridViewRow row) { return string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnFromCode"])) && string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnFromTitle"])) && string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnAlias"])) && string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnToCode"])) && string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnToTitle"])) && string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnTimestamp"])); } #endregion #region 見出しの置き換えタブのイベントのメソッド /// /// 見出しの置き換え対訳表を使用するの値設定を行う。 /// /// 対訳表を表示するビュー。 /// 対訳表データ。 private void ImportTranslationTableView(DataGridView view, TranslationTable table) { // 初期設定以外の場合も想定して最初にクリア view.Columns.Clear(); // 言語コードを列、語句を行とする。登録されている全言語分の列を作成する foreach (Website site in this.config.Websites) { this.AddTranslationTableColumn(view.Columns, site.Language.Code, this.GetHeaderLanguage(site.Language)); } // 各行にデータを取り込み foreach (IDictionary record in table) { // 行を追加しその行を取得 DataGridViewRow row = view.Rows[view.Rows.Add()]; foreach (KeyValuePair cell in record) { // 上で登録した列では足りなかった場合、その都度生成する if (!view.Columns.Contains(cell.Key)) { this.AddTranslationTableColumn(view.Columns, cell.Key, cell.Key); } // 改行区切りで表示 row.Cells[cell.Key].Value = string.Join("\n", cell.Value); } } // 可能であれば現在表示中の言語の列の昇順でソートする // ※ 無ければenで試みる string code = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; if (view.Columns.Contains(code)) { view.Sort(view.Columns[code], ListSortDirection.Ascending); } else if (view.Columns.Contains("en")) { view.Sort(view.Columns["en"], ListSortDirection.Ascending); } } /// /// 見出しの置き換え対訳表を使用するからデータを抽出する。 /// /// 対訳表を表示するビュー。 /// 対訳表データ。 private TranslationTable ExportTranslationTableView(DataGridView view) { TranslationTable table = new TranslationTable(); foreach (DataGridViewRow row in view.Rows) { IDictionary record = new SortedDictionary(); foreach (DataGridViewCell cell in row.Cells) { // 空のセルは格納しない、該当の組み合わせは消える string value = FormUtils.ToString(cell); if (!string.IsNullOrWhiteSpace(value)) { // 改行区切りの配列で格納 record[cell.OwningColumn.Name] = CollectionUtils.Trim(value.Split('\n')); } } // 1件もデータが無い行は丸々カットする if (record.Count > 0) { table.Add(record); } } return table; } /// /// 指定された情報を元に見出しの置き換え対訳表の列を追加する。 /// /// 列コレクション。 /// 列名。 /// 列見出し。 private void AddTranslationTableColumn(DataGridViewColumnCollection columns, string columnName, string headerText) { columns.Add(columnName, headerText); } /// /// 指定された言語用の表示名を返す。 /// /// 表示言語コード。 /// 表示名、無ければ言語コード。 private string GetHeaderLanguage(Language lang) { Language.LanguageName name; if (lang.Names.TryGetValue( Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName, out name)) { if (!string.IsNullOrEmpty(name.Name)) { return string.Format(Resources.HeadingViewHeaderText, name.Name, lang.Code); } } return lang.Code; } #endregion #region 言語/サーバータブのイベントのメソッド /// /// 言語コンボボックス変更時の処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void ComboBoxLanguuage_SelectedIndexChanged(object sender, EventArgs e) { try { // 変更前の設定を保存 if (!string.IsNullOrEmpty(this.comboBoxLanguageSelectedText)) { // 設定が存在しなければ自動生成される this.SaveChangedValue(this.GetMediaWikiNeedCreate(this.config.Websites, this.comboBoxLanguageSelectedText)); } // 変更後の値に応じて、画面表示を更新 if (!string.IsNullOrEmpty(this.comboBoxLanguage.Text)) { // 設定が存在しなければ基本的に自動生成されるのでそのまま使用 this.LoadCurrentValue(this.GetMediaWikiNeedCreate(this.config.Websites, this.comboBoxLanguage.Text)); // 各入力欄を有効に this.buttonLanguageRemove.Enabled = true; this.groupBoxServer.Enabled = true; this.groupBoxLanguage.Enabled = true; // 現在の選択値を更新 this.comboBoxLanguageSelectedText = this.comboBoxLanguage.Text; } else { // 各入力欄を無効に this.buttonLanguageRemove.Enabled = false; this.groupBoxServer.Enabled = false; this.groupBoxLanguage.Enabled = false; // 現在の選択値を更新 this.comboBoxLanguageSelectedText = string.Empty; } } catch (Exception ex) { // 通常この処理では例外は発生しないはず。想定外のエラー用 FormUtils.ErrorDialog(Resources.ErrorMessageDevelopmentError, ex.Message, ex.StackTrace); } } /// /// 言語の追加ボタン押下時の処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void ButtonLunguageAdd_Click(object sender, EventArgs e) { // 言語追加用ダイアログで言語コードを入力 using (AddLanguageDialog form = new AddLanguageDialog(this.config)) { if (form.ShowDialog() == DialogResult.OK) { // 値をコンボボックスと見出しの対訳表に追加、登録した値を選択状態に変更 this.comboBoxLanguage.Items.Add(form.LanguageCode); this.dataGridViewHeading.Columns.Add(form.LanguageCode, form.LanguageCode); this.comboBoxLanguage.SelectedItem = form.LanguageCode; } } } /// /// 言語の削除ボタン押下時の処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void ButtonLanguageRemove_Click(object sender, EventArgs e) { // 表示されている言語を設定から削除する for (int i = this.config.Websites.Count - 1; i >= 0; i--) { if (this.config.Websites[i].Language.Code == this.comboBoxLanguage.Text) { // 万が一複数あれば全て削除 this.config.Websites.RemoveAt(i); } } // 値を見出しの対訳表とコンボボックスからも削除し、表示を更新する this.comboBoxLanguageSelectedText = null; this.dataGridViewHeading.Columns.Remove(this.comboBoxLanguage.Text); this.comboBoxLanguage.Items.Remove(this.comboBoxLanguage.Text); this.ComboBoxLanguuage_SelectedIndexChanged(sender, e); } /// /// 各名前空間のIDボックスバリデート処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void TextBoxNamespace_Validating(object sender, CancelEventArgs e) { // 空か数値のみ許可 TextBox box = (TextBox)sender; box.Text = StringUtils.DefaultString(box.Text).Trim(); int value; if (!string.IsNullOrEmpty(box.Text) && !int.TryParse(box.Text, out value)) { this.errorProvider.SetError(box, Resources.WarningMessageIgnoreNumericNamespace); e.Cancel = true; } } /// /// 括弧のスタイルボックスバリデート処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void TextBoxBracket_Validating(object sender, CancelEventArgs e) { // 空か$1が含まれる文字列のみ許可 TextBox box = (TextBox)sender; if (!string.IsNullOrEmpty(box.Text) && !box.Text.Contains("$1")) { this.errorProvider.SetError(box, Resources.WarningMessageUnformatedBracket); e.Cancel = true; } } /// /// 言語の設定表の行編集時のバリデート処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void DataGridViewLanguageName_RowValidating(object sender, DataGridViewCellCancelEventArgs e) { DataGridViewRow row = this.dataGridViewLanguageName.Rows[e.RowIndex]; // 空行(新規行など)の場合無視 if (FormUtils.IsEmptyRow(row)) { return; } // 言語コードは必須、またトリムして小文字に変換 string code = FormUtils.ToString(row.Cells["ColumnCode"]).Trim().ToLower(); row.Cells["ColumnCode"].Value = code; if (string.IsNullOrEmpty(code)) { row.ErrorText = Resources.WarningMessageEmptyCodeColumn; e.Cancel = true; return; } // 略称を設定する場合、呼称を必須とする if (!string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnShortName"])) && string.IsNullOrWhiteSpace(FormUtils.ToString(row.Cells["ColumnName"]))) { row.ErrorText = Resources.WarningMessageShortNameColumnOnly; e.Cancel = true; } } /// /// 言語の設定表バリデート処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void DataGridViewLanguageName_Validating(object sender, CancelEventArgs e) { // 言語コードの重複チェック IDictionary codeMap = new Dictionary(); for (int i = 0; i < this.dataGridViewLanguageName.RowCount - 1; i++) { string code = FormUtils.ToString(this.dataGridViewLanguageName["ColumnCode", i]); int y; if (codeMap.TryGetValue(code, out y)) { // 重複の場合、両方の行にエラーを設定 this.dataGridViewLanguageName.Rows[i].ErrorText = Resources.WarningMessageDuplicateCodeColumn; this.dataGridViewLanguageName.Rows[y].ErrorText = Resources.WarningMessageDuplicateCodeColumn; e.Cancel = true; } else { // それ以外はマップに出現行とともに追加 codeMap[code] = i; } } } #region イベント実装支援用メソッド /// /// コレクションから指定された言語のMediaWikiを取得する。 /// 存在しない場合は空のインスタンスを生成、コレクションに追加して返す。 /// /// 翻訳元言語。 /// 言語コード。 /// 翻訳パターン。存在しない場合は新たに作成した翻訳パターンを返す。 private MediaWiki GetMediaWikiNeedCreate(ICollection collection, string lang) { // 設定が存在すれば取得した値を返す foreach (Website s in collection) { if (s.Language.Code == lang) { if (s is MediaWiki) { return s as MediaWiki; } // 万が一同じ言語コードで違う型の値があったら上書き collection.Remove(s); break; } } // 存在しないか上書きの場合、作成した翻訳パターンをコレクションに追加し、返す MediaWiki site = new MediaWiki(new Language(lang)); collection.Add(site); return site; } /// /// 指定されたLanguage設定を画面表示/編集用に読み込む。 /// /// 読込元Language設定。 /// 一部パラメータには初期値が存在するが、格納時に対処するため全て読み込む。 private void LoadCurrentValue(Language lang) { // 言語情報を読み込み // ※ Bracketは初期値があるパラメータのため、必ず値が返る this.textBoxBracket.Text = lang.Bracket; // 呼称の情報を表に設定 this.dataGridViewLanguageName.Rows.Clear(); foreach (KeyValuePair name in lang.Names) { int index = this.dataGridViewLanguageName.Rows.Add(); this.dataGridViewLanguageName["ColumnCode", index].Value = name.Key; this.dataGridViewLanguageName["ColumnName", index].Value = name.Value.Name; this.dataGridViewLanguageName["ColumnShortName", index].Value = name.Value.ShortName; } // 言語コードの昇順でソート this.dataGridViewLanguageName.Sort(this.dataGridViewLanguageName.Columns["ColumnCode"], ListSortDirection.Ascending); } /// /// 指定されたWebsite設定を画面表示/編集用に読み込む。 /// /// 読込元Website設定。 private void LoadCurrentValue(Website site) { // Languageクラス分の読み込みを行う this.LoadCurrentValue(site.Language); // サイト情報を読み込み this.textBoxLocation.Text = site.Location; } /// /// 指定されたMediaWiki設定を画面表示/編集用に読み込む。 /// /// 読込元MediaWiki設定。 /// 一部パラメータには初期値が存在するが、格納時に対処するため全て読み込む。 private void LoadCurrentValue(MediaWiki site) { // Websiteクラス分の読み込みを行う this.LoadCurrentValue((Website)site); // MediaWikiクラス分の読み込み this.textBoxContentApi.Text = StringUtils.DefaultString(site.ContentApi); this.textBoxMetaApi.Text = StringUtils.DefaultString(site.MetaApi); this.textBoxInterlanguageApi.Text = StringUtils.DefaultString(site.InterlanguageApi); this.textBoxTemplateNamespace.Text = site.TemplateNamespace.ToString(); this.textBoxCategoryNamespace.Text = site.CategoryNamespace.ToString(); this.textBoxFileNamespace.Text = site.FileNamespace.ToString(); this.textBoxLinkInterwikiFormat.Text = StringUtils.DefaultString(site.LinkInterwikiFormat); this.textBoxLangFormat.Text = StringUtils.DefaultString(site.LangFormat); this.checkBoxHasLanguagePage.Checked = site.HasLanguagePage; } /// /// 指定されたLanguage設定に画面上で変更された値の格納を行う。 /// /// 格納先Language設定。 /// 一部パラメータには初期値が存在するため、変更がある場合のみ格納する。 private void SaveChangedValue(Language lang) { // Bracketは初期値を持つパラメータのため、変更された場合のみ格納する。 // ※ この値は前後の空白に意味があるため、Trimしてはいけない string str = StringUtils.DefaultString(this.textBoxBracket.Text); if (str != lang.Bracket) { lang.Bracket = str; } // 表から呼称の情報も保存 lang.Names.Clear(); for (int y = 0; y < this.dataGridViewLanguageName.RowCount - 1; y++) { // 値が入ってないとかはガードしているはずだが、一応チェック string code = FormUtils.ToString(this.dataGridViewLanguageName["ColumnCode", y]).Trim(); if (!string.IsNullOrEmpty(code)) { Language.LanguageName name = new Language.LanguageName(); name.Name = FormUtils.ToString(this.dataGridViewLanguageName["ColumnName", y]).Trim(); name.ShortName = FormUtils.ToString(this.dataGridViewLanguageName["ColumnShortName", y]).Trim(); lang.Names[code] = name; } } } /// /// 指定されたWebsite設定に画面上で変更された値の格納を行う。 /// /// 格納先Website設定。 /// Websiteについては特に特殊な処理は無いため全て上書きする。 private void SaveChangedValue(Website site) { // Languageクラス分の設定を行う this.SaveChangedValue(site.Language); // サイト情報を格納 site.Location = StringUtils.DefaultString(this.textBoxLocation.Text).Trim(); } /// /// 指定されたMediaWiki設定に画面上で変更された値の格納を行う。 /// /// 格納先MediaWiki設定。 /// 一部パラメータには初期値が存在するため、変更がある場合のみ格納する。 private void SaveChangedValue(MediaWiki site) { // Websiteクラス分の設定を行う this.SaveChangedValue((Website)site); // 初期値を持つパラメータがあるため、全て変更された場合のみ格納する。 // ※ もうちょっと綺麗に書きたかったが、うまい手が思いつかなかったので力技 // MediaWikiクラス側で行わないのは、場合によっては意図的に初期値と同じ値を設定すること // もありえるから(初期値が変わる可能性がある場合など)。 string str = StringUtils.DefaultString(this.textBoxContentApi.Text).Trim(); if (str != site.ContentApi) { site.ContentApi = str; } str = StringUtils.DefaultString(this.textBoxMetaApi.Text).Trim(); if (str != site.MetaApi) { site.MetaApi = str; } str = StringUtils.DefaultString(this.textBoxInterlanguageApi.Text).Trim(); if (str != site.InterlanguageApi) { site.InterlanguageApi = str; } str = StringUtils.DefaultString(this.textBoxLinkInterwikiFormat.Text).Trim(); if (str != site.LinkInterwikiFormat) { site.LinkInterwikiFormat = str; } str = StringUtils.DefaultString(this.textBoxLangFormat.Text).Trim(); if (str != site.LangFormat) { site.LangFormat = str; } site.HasLanguagePage = this.checkBoxHasLanguagePage.Checked; // 以下、数値へのparseは事前にチェックしてあるので、ここではチェックしない if (!string.IsNullOrWhiteSpace(this.textBoxTemplateNamespace.Text)) { int num = int.Parse(this.textBoxTemplateNamespace.Text); if (site.TemplateNamespace != num) { site.TemplateNamespace = num; } } if (!string.IsNullOrWhiteSpace(this.textBoxCategoryNamespace.Text)) { int num = int.Parse(this.textBoxCategoryNamespace.Text); if (site.CategoryNamespace != num) { site.CategoryNamespace = num; } } if (!string.IsNullOrWhiteSpace(this.textBoxFileNamespace.Text)) { int num = int.Parse(this.textBoxFileNamespace.Text); if (site.FileNamespace != num) { site.FileNamespace = num; } } } #endregion #endregion #region その他タブのイベントのメソッド /// /// キャッシュ有効期限ボックスバリデート処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void TextBoxCacheExpire_Validating(object sender, CancelEventArgs e) { // 値が0以上の数値かをチェック this.TextBoxGreaterThanValidating((TextBox)sender, e, 0, Resources.WarningMessageIgnoreCacheExpire); } /// /// リトライ回数ボックスバリデート処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void TextBoxMaxConnectRetries_Validating(object sender, CancelEventArgs e) { // 値が0以上の数値かをチェック this.TextBoxGreaterThanValidating((TextBox)sender, e, 0, Resources.WarningMessageIgnoreMaxConnectRetries); } /// /// ウェイト時間ボックスバリデート処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void TextBoxConnectRetryTime_Validating(object sender, CancelEventArgs e) { // 値が0以上の数値かをチェック this.TextBoxGreaterThanValidating((TextBox)sender, e, 0, Resources.WarningMessageIgnoreConnectRetryTime); } /// /// ウェブサイトURLクリック時の処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void LinkLabelWebsite_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { // リンクを開く System.Diagnostics.Process.Start(((LinkLabel)sender).Text); } #region イベント実装支援用メソッド /// /// メッセージのみ差し替え可能なテキストボックス用の値がxx以上の数値か、のバリデート処理。 /// /// イベント発生テキストボックス。 /// 発生したイベント。 /// 比較対象の数値。 /// バリデートメッセージ。 private void TextBoxGreaterThanValidating(TextBox box, CancelEventArgs e, int num, string message) { box.Text = StringUtils.DefaultString(box.Text).Trim(); int value; if (!int.TryParse(box.Text, out value) || value < num) { this.errorProvider.SetError(box, message); e.Cancel = true; } } #endregion #endregion #region 共通のイベントメソッド /// /// 汎用のエラープロバイダ初期化処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void ResetErrorProvider_Validated(object sender, EventArgs e) { this.errorProvider.SetError((Control)sender, null); } /// /// 汎用の行編集時のエラーテキスト初期化処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void ResetErrorText_RowValidated(object sender, DataGridViewCellEventArgs e) { ((DataGridView)sender).Rows[e.RowIndex].ErrorText = string.Empty; } /// /// 汎用のテーブルエラーテキスト初期化処理。 /// /// イベント発生オブジェクト。 /// 発生したイベント。 private void ResetErrorText_Validated(object sender, EventArgs e) { // 全行のエラーメッセージを解除 foreach (DataGridViewRow row in ((DataGridView)sender).Rows) { row.ErrorText = string.Empty; } } #endregion #region 内部クラス /// /// 記事の置き換え対訳表の日付並び替え用クラスです。 /// /// /// 取得日時の降順でソート、空の列は先頭にします。 /// 取得日時が同じ場合、先頭の列から順に昇順でソート。 /// public class TranslationDictionaryViewComparer : System.Collections.IComparer { /// /// 取得日時が同じ場合にソートに用いる列名。 /// private static readonly string[] SortOrder = new string[] { "ColumnFromCode", "ColumnToCode", "ColumnFromTitle" }; /// /// 2行を比較し、一方が他方より小さいか、等しいか、大きいかを示す値を返します。 /// /// 比較する最初の行です。 /// 比較する2番目の行。 /// 0未満:xはyより小さい, 0:xとyは等しい, 0より大きい:xはyより大きい。 public int Compare(object x, object y) { DataGridViewRow xrow = (DataGridViewRow)x; DataGridViewRow yrow = (DataGridViewRow)y; // 取得日時列の降順でソート、ただし空の列は先頭にする int compare = StringUtils.CompareNullsLast( FormUtils.ToString(xrow.Cells["ColumnTimestamp"]), FormUtils.ToString(yrow.Cells["ColumnTimestamp"])); if (compare != 0) { return compare * -1; } // 取得日時列が同じ場合、残りの列の昇順でソート foreach (string column in SortOrder) { compare = string.Compare( FormUtils.ToString(xrow.Cells[column]), FormUtils.ToString(yrow.Cells[column])); if (compare != 0) { return compare; } } return 0; } } #endregion } }