1 // OpenTween - Client of Twitter
2 // Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 // (c) 2008-2011 Moz (@syo68k)
4 // (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
5 // (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 // (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
7 // (c) 2011-2012 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
8 // All rights reserved.
10 // This file is part of OpenTween.
12 // This program is free software; you can redistribute it and/or modify it
13 // under the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 3 of the License, or (at your option)
17 // This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
24 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
25 // Boston, MA 02110-1301, USA.
28 using System.Collections.Generic;
29 using System.ComponentModel;
34 using System.Windows.Forms;
35 using System.Linq.Expressions;
36 using System.Text.RegularExpressions;
38 using System.Collections.Specialized;
39 using OpenTween.Models;
43 public partial class FilterDialog : OTBaseForm
45 private EDITMODE _mode;
46 private bool _directAdd;
47 private MultiSelectionState _multiSelState = MultiSelectionState.None;
48 private readonly TabInformations _sts;
50 private List<TabModel> tabs = new List<TabModel>();
51 private int selectedTabIndex = -1;
53 private readonly List<string> idlist = new List<string>();
62 private enum EnableButtonMode
70 private enum MultiSelectionState
77 private EnableButtonMode RuleEnableButtonMode
79 get => this._ruleEnableButtonMode;
82 this._ruleEnableButtonMode = value;
84 this.buttonRuleToggleEnabled.Text = value == FilterDialog.EnableButtonMode.Enable
85 ? Properties.Resources.EnableButtonCaption
86 : Properties.Resources.DisableButtonCaption;
87 this.buttonRuleToggleEnabled.Enabled = value != EnableButtonMode.NotSelected;
90 private EnableButtonMode _ruleEnableButtonMode = FilterDialog.EnableButtonMode.NotSelected;
92 public TabModel SelectedTab
93 => this.selectedTabIndex != -1 ? this.tabs[this.selectedTabIndex] : null;
97 this.InitializeComponent();
99 this._sts = TabInformations.GetInstance();
100 this.RefreshListTabs();
103 private void RefreshListTabs()
105 this.tabs = this._sts.Tabs.Append(this._sts.MuteTab).ToList();
107 using (ControlTransaction.Update(this.ListTabs))
109 var selectedTab = this.ListTabs.SelectedItem;
110 this.ListTabs.Items.Clear();
111 this.ListTabs.Items.AddRange(this.tabs.ToArray());
112 this.ListTabs.SelectedIndex = this.tabs.FindIndex(x => x == selectedTab);
116 private void SetFilters(TabModel tab)
118 if (ListTabs.Items.Count == 0) return;
120 ListFilters.Items.Clear();
122 if (tab is FilterTabModel filterTab)
123 ListFilters.Items.AddRange(filterTab.GetFilters());
125 if (ListFilters.Items.Count > 0)
126 ListFilters.SelectedIndex = 0;
130 if (tab.IsDefaultTabType)
132 CheckProtected.Checked = true;
133 CheckProtected.Enabled = false;
137 CheckProtected.Checked = tab.Protected;
138 CheckProtected.Enabled = true;
141 CheckManageRead.Checked = tab.UnreadManage;
142 CheckNotifyNew.Checked = tab.Notify;
144 var idx = ComboSound.Items.IndexOf(tab.SoundFile);
145 if (idx == -1) idx = 0;
146 ComboSound.SelectedIndex = idx;
148 if (_directAdd) return;
150 if (tab.TabType == MyCommon.TabUsageType.Mute)
152 this.CheckManageRead.Enabled = false;
153 this.CheckNotifyNew.Enabled = false;
154 this.ComboSound.Enabled = false;
156 this.GroupBox1.Visible = false;
157 this.labelMuteTab.Visible = true;
161 this.CheckManageRead.Enabled = true;
162 this.CheckNotifyNew.Enabled = true;
163 this.ComboSound.Enabled = true;
165 this.GroupBox1.Visible = true;
166 this.labelMuteTab.Visible = false;
169 ListTabs.Enabled = true;
170 GroupTab.Enabled = true;
171 ListFilters.Enabled = true;
172 EditFilterGroup.Enabled = false;
174 if (tab.IsDistributableTabType)
176 ButtonNew.Enabled = true;
177 if (ListFilters.SelectedIndex > -1)
179 ButtonEdit.Enabled = true;
180 ButtonDelete.Enabled = true;
181 ButtonRuleUp.Enabled = true;
182 ButtonRuleDown.Enabled = true;
183 ButtonRuleCopy.Enabled = true;
184 ButtonRuleMove.Enabled = true;
185 buttonRuleToggleEnabled.Enabled = true;
189 ButtonEdit.Enabled = false;
190 ButtonDelete.Enabled = false;
191 ButtonRuleUp.Enabled = false;
192 ButtonRuleDown.Enabled = false;
193 ButtonRuleCopy.Enabled = false;
194 ButtonRuleMove.Enabled = false;
195 buttonRuleToggleEnabled.Enabled = false;
200 ButtonNew.Enabled = false;
201 ButtonEdit.Enabled = false;
202 ButtonDelete.Enabled = false;
203 ButtonRuleUp.Enabled = false;
204 ButtonRuleDown.Enabled = false;
205 ButtonRuleCopy.Enabled = false;
206 ButtonRuleMove.Enabled = false;
207 buttonRuleToggleEnabled.Enabled = false;
212 case MyCommon.TabUsageType.Home:
213 LabelTabType.Text = Properties.Resources.TabUsageTypeName_Home;
215 case MyCommon.TabUsageType.Mentions:
216 LabelTabType.Text = Properties.Resources.TabUsageTypeName_Mentions;
218 case MyCommon.TabUsageType.DirectMessage:
219 LabelTabType.Text = Properties.Resources.TabUsageTypeName_DirectMessage;
221 case MyCommon.TabUsageType.Favorites:
222 LabelTabType.Text = Properties.Resources.TabUsageTypeName_Favorites;
224 case MyCommon.TabUsageType.UserDefined:
225 LabelTabType.Text = Properties.Resources.TabUsageTypeName_UserDefined;
227 case MyCommon.TabUsageType.PublicSearch:
228 LabelTabType.Text = Properties.Resources.TabUsageTypeName_PublicSearch;
230 case MyCommon.TabUsageType.Lists:
231 LabelTabType.Text = Properties.Resources.TabUsageTypeName_Lists;
233 case MyCommon.TabUsageType.Related:
234 LabelTabType.Text = Properties.Resources.TabUsageTypeName_Related;
236 case MyCommon.TabUsageType.UserTimeline:
237 LabelTabType.Text = Properties.Resources.TabUsageTypeName_UserTimeline;
239 case MyCommon.TabUsageType.Mute:
240 LabelTabType.Text = "Mute";
242 case MyCommon.TabUsageType.SearchResults:
243 LabelTabType.Text = "SearchResults";
246 LabelTabType.Text = "UNKNOWN";
249 ButtonRenameTab.Enabled = true;
250 if (tab.IsDefaultTabType || tab.Protected)
252 ButtonDeleteTab.Enabled = false;
256 ButtonDeleteTab.Enabled = true;
258 ButtonClose.Enabled = true;
261 public void SetCurrent(string tabName)
263 var index = this.tabs.FindIndex(x => x.TabName == tabName);
265 throw new ArgumentException($"Unknown tab: {tabName}", nameof(tabName));
267 this.selectedTabIndex = index;
270 public void AddNewFilter(string id, string msg)
273 ButtonNew.Enabled = false;
274 ButtonEdit.Enabled = false;
275 ButtonRuleUp.Enabled = false;
276 ButtonRuleDown.Enabled = false;
277 ButtonRuleCopy.Enabled = false;
278 ButtonRuleMove.Enabled = false;
279 buttonRuleToggleEnabled.Enabled = false;
280 ButtonDelete.Enabled = false;
281 ButtonClose.Enabled = false;
282 EditFilterGroup.Enabled = true;
283 ListTabs.Enabled = false;
284 GroupTab.Enabled = false;
285 ListFilters.Enabled = false;
287 RadioAND.Checked = true;
288 RadioPLUS.Checked = false;
293 MSG2.Text = id + msg;
295 TextSource.Text = "";
298 MSG2.Enabled = false;
299 CheckRegex.Checked = false;
300 CheckURL.Checked = false;
301 CheckCaseSensitive.Checked = false;
302 CheckRetweet.Checked = false;
303 CheckLambda.Checked = false;
305 RadioExAnd.Checked = true;
306 RadioExPLUS.Checked = false;
313 TextExSource.Text = "";
314 ExUID.Enabled = true;
315 ExMSG1.Enabled = true;
316 ExMSG2.Enabled = false;
317 CheckExRegex.Checked = false;
318 CheckExURL.Checked = false;
319 CheckExCaseSensitive.Checked = false;
320 CheckExRetweet.Checked = false;
321 CheckExLambDa.Checked = false;
323 OptCopy.Checked = true;
324 CheckMark.Checked = true;
326 _mode = EDITMODE.AddNew;
330 private void ButtonNew_Click(object sender, EventArgs e)
332 ButtonNew.Enabled = false;
333 ButtonEdit.Enabled = false;
334 ButtonClose.Enabled = false;
335 ButtonRuleUp.Enabled = false;
336 ButtonRuleDown.Enabled = false;
337 ButtonRuleCopy.Enabled = false;
338 ButtonRuleMove.Enabled = false;
339 buttonRuleToggleEnabled.Enabled = false;
340 ButtonDelete.Enabled = false;
341 ButtonClose.Enabled = false;
342 EditFilterGroup.Enabled = true;
343 ListTabs.Enabled = false;
344 GroupTab.Enabled = false;
345 ListFilters.Enabled = false;
347 RadioAND.Checked = true;
348 RadioPLUS.Checked = false;
352 TextSource.Text = "";
355 MSG2.Enabled = false;
356 CheckRegex.Checked = false;
357 CheckURL.Checked = false;
358 CheckCaseSensitive.Checked = false;
359 CheckRetweet.Checked = false;
360 CheckLambda.Checked = false;
362 RadioExAnd.Checked = true;
363 RadioExPLUS.Checked = false;
367 TextExSource.Text = "";
368 ExUID.Enabled = true;
369 ExMSG1.Enabled = true;
370 ExMSG2.Enabled = false;
371 CheckExRegex.Checked = false;
372 CheckExURL.Checked = false;
373 CheckExCaseSensitive.Checked = false;
374 CheckExRetweet.Checked = false;
375 CheckExLambDa.Checked = false;
377 OptCopy.Checked = true;
378 CheckMark.Checked = true;
380 _mode = EDITMODE.AddNew;
383 private void ButtonEdit_Click(object sender, EventArgs e)
385 if (ListFilters.SelectedIndex == -1) return;
389 var idx = ListFilters.SelectedIndex;
390 ListFilters.SelectedIndex = -1;
391 ListFilters.SelectedIndex = idx;
392 ListFilters.Enabled = false;
394 ButtonNew.Enabled = false;
395 ButtonEdit.Enabled = false;
396 ButtonDelete.Enabled = false;
397 ButtonClose.Enabled = false;
398 ButtonRuleUp.Enabled = false;
399 ButtonRuleDown.Enabled = false;
400 ButtonRuleCopy.Enabled = false;
401 ButtonRuleMove.Enabled = false;
402 buttonRuleToggleEnabled.Enabled = false;
403 EditFilterGroup.Enabled = true;
404 ListTabs.Enabled = false;
405 GroupTab.Enabled = false;
407 _mode = EDITMODE.Edit;
410 private void ButtonDelete_Click(object sender, EventArgs e)
412 var selectedCount = ListFilters.SelectedIndices.Count;
413 if (selectedCount == 0) return;
417 if (selectedCount == 1)
419 tmp = string.Format(Properties.Resources.ButtonDelete_ClickText1, Environment.NewLine, ListFilters.SelectedItem);
423 tmp = string.Format(Properties.Resources.ButtonDelete_ClickText3, selectedCount);
426 var rslt = MessageBox.Show(tmp, Properties.Resources.ButtonDelete_ClickText2, MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
427 if (rslt == DialogResult.Cancel) return;
429 var indices = ListFilters.SelectedIndices.Cast<int>().Reverse().ToArray(); // 後ろの要素から削除
430 var tab = (FilterTabModel)this.SelectedTab;
432 using (ControlTransaction.Update(ListFilters))
434 foreach (var idx in indices)
436 tab.RemoveFilter((PostFilterRule)ListFilters.Items[idx]);
437 ListFilters.Items.RemoveAt(idx);
442 private void ButtonCancel_Click(object sender, EventArgs e)
444 ListTabs.Enabled = true;
445 GroupTab.Enabled = true;
446 ListFilters.Enabled = true;
448 if (ListFilters.SelectedIndex != -1)
452 EditFilterGroup.Enabled = false;
453 ButtonNew.Enabled = true;
454 if (ListFilters.SelectedIndex > -1)
456 ButtonEdit.Enabled = true;
457 ButtonDelete.Enabled = true;
458 ButtonRuleUp.Enabled = true;
459 ButtonRuleDown.Enabled = true;
460 ButtonRuleCopy.Enabled = true;
461 ButtonRuleMove.Enabled = true;
462 buttonRuleToggleEnabled.Enabled = true;
466 ButtonEdit.Enabled = false;
467 ButtonDelete.Enabled = false;
468 ButtonRuleUp.Enabled = false;
469 ButtonRuleDown.Enabled = false;
470 ButtonRuleCopy.Enabled = false;
471 ButtonRuleMove.Enabled = false;
472 buttonRuleToggleEnabled.Enabled = false;
474 ButtonClose.Enabled = true;
481 private void ShowDetail()
483 if (_directAdd) return;
485 if (ListFilters.SelectedIndex > -1)
487 var fc = (PostFilterRule)ListFilters.SelectedItem;
490 RadioAND.Checked = true;
491 RadioPLUS.Checked = false;
494 MSG2.Enabled = false;
495 UID.Text = fc.FilterName;
497 MSG1.Text = string.Join(" ", fc.FilterBody);
503 RadioPLUS.Checked = true;
504 RadioAND.Checked = false;
506 MSG1.Enabled = false;
510 MSG2.Text = string.Join(" ", fc.FilterBody);
513 TextSource.Text = fc.FilterSource;
514 CheckRegex.Checked = fc.UseRegex;
515 CheckURL.Checked = fc.FilterByUrl;
516 CheckCaseSensitive.Checked = fc.CaseSensitive;
517 CheckRetweet.Checked = fc.FilterRt;
518 CheckLambda.Checked = fc.UseLambda;
520 if (fc.ExUseNameField)
522 RadioExAnd.Checked = true;
523 RadioExPLUS.Checked = false;
524 ExUID.Enabled = true;
525 ExMSG1.Enabled = true;
526 ExMSG2.Enabled = false;
527 ExUID.Text = fc.ExFilterName;
529 ExMSG1.Text = string.Join(" ", fc.ExFilterBody);
535 RadioExPLUS.Checked = true;
536 RadioExAnd.Checked = false;
537 ExUID.Enabled = false;
538 ExMSG1.Enabled = false;
539 ExMSG2.Enabled = true;
542 ExMSG2.Text = string.Join(" ", fc.ExFilterBody);
545 TextExSource.Text = fc.ExFilterSource;
546 CheckExRegex.Checked = fc.ExUseRegex;
547 CheckExURL.Checked = fc.ExFilterByUrl;
548 CheckExCaseSensitive.Checked = fc.ExCaseSensitive;
549 CheckExRetweet.Checked = fc.ExFilterRt;
550 CheckExLambDa.Checked = fc.ExUseLambda;
554 OptMove.Checked = true;
558 OptCopy.Checked = true;
560 CheckMark.Checked = fc.MarkMatches;
562 ButtonEdit.Enabled = true;
563 ButtonDelete.Enabled = true;
564 ButtonRuleUp.Enabled = true;
565 ButtonRuleDown.Enabled = true;
566 ButtonRuleCopy.Enabled = true;
567 ButtonRuleMove.Enabled = true;
568 buttonRuleToggleEnabled.Enabled = true;
572 RadioAND.Checked = true;
573 RadioPLUS.Checked = false;
576 MSG2.Enabled = false;
580 TextSource.Text = "";
581 CheckRegex.Checked = false;
582 CheckURL.Checked = false;
583 CheckCaseSensitive.Checked = false;
584 CheckRetweet.Checked = false;
585 CheckLambda.Checked = false;
587 RadioExAnd.Checked = true;
588 RadioExPLUS.Checked = false;
589 ExUID.Enabled = true;
590 ExMSG1.Enabled = true;
591 ExMSG2.Enabled = false;
595 TextExSource.Text = "";
596 CheckExRegex.Checked = false;
597 CheckExURL.Checked = false;
598 CheckExCaseSensitive.Checked = false;
599 CheckExRetweet.Checked = false;
600 CheckExLambDa.Checked = false;
602 OptCopy.Checked = true;
603 CheckMark.Checked = true;
605 ButtonEdit.Enabled = false;
606 ButtonDelete.Enabled = false;
607 ButtonRuleUp.Enabled = false;
608 ButtonRuleDown.Enabled = false;
609 ButtonRuleCopy.Enabled = false;
610 ButtonRuleMove.Enabled = false;
611 buttonRuleToggleEnabled.Enabled = false;
615 private void RadioAND_CheckedChanged(object sender, EventArgs e)
617 var flg = RadioAND.Checked;
623 private void ButtonOK_Click(object sender, EventArgs e)
626 if (!CheckMatchRule(out var isBlankMatch) || !CheckExcludeRule(out var isBlankExclude))
630 if (isBlankMatch && isBlankExclude)
632 MessageBox.Show(Properties.Resources.ButtonOK_ClickText1, Properties.Resources.ButtonOK_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
636 var tab = (FilterTabModel)this.SelectedTab;
637 var i = ListFilters.SelectedIndex;
640 if (_mode == EDITMODE.AddNew)
641 ft = new PostFilterRule();
643 ft = (PostFilterRule)this.ListFilters.SelectedItem;
645 if (tab.TabType != MyCommon.TabUsageType.Mute)
647 ft.MoveMatches = OptMove.Checked;
648 ft.MarkMatches = CheckMark.Checked;
652 ft.MoveMatches = true;
653 ft.MarkMatches = false;
657 if (RadioAND.Checked)
659 ft.FilterName = UID.Text;
660 var owner = (TweenMain)this.Owner;
661 var cnt = owner.AtIdSupl.ItemCount;
662 owner.AtIdSupl.AddItem("@" + ft.FilterName);
663 if (cnt != owner.AtIdSupl.ItemCount)
665 owner.MarkSettingAtIdModified();
667 ft.UseNameField = true;
673 ft.UseNameField = false;
676 ft.FilterSource = TextSource.Text;
678 if (CheckRegex.Checked || CheckLambda.Checked)
680 ft.FilterBody = new[] { bdy };
684 ft.FilterBody = bdy.Split(' ', ' ')
685 .Where(x => !string.IsNullOrEmpty(x))
689 ft.UseRegex = CheckRegex.Checked;
690 ft.FilterByUrl = CheckURL.Checked;
691 ft.CaseSensitive = CheckCaseSensitive.Checked;
692 ft.FilterRt = CheckRetweet.Checked;
693 ft.UseLambda = CheckLambda.Checked;
696 if (RadioExAnd.Checked)
698 ft.ExFilterName = ExUID.Text;
699 ft.ExUseNameField = true;
704 ft.ExFilterName = "";
705 ft.ExUseNameField = false;
708 ft.ExFilterSource = TextExSource.Text;
710 if (CheckExRegex.Checked || CheckExLambDa.Checked)
712 ft.ExFilterBody = new[] { bdy };
716 ft.ExFilterBody = bdy.Split(' ', ' ')
717 .Where(x => !string.IsNullOrEmpty(x))
721 ft.ExUseRegex = CheckExRegex.Checked;
722 ft.ExFilterByUrl = CheckExURL.Checked;
723 ft.ExCaseSensitive = CheckExCaseSensitive.Checked;
724 ft.ExFilterRt = CheckExRetweet.Checked;
725 ft.ExUseLambda = CheckExLambDa.Checked;
727 if (_mode == EDITMODE.AddNew)
729 if (!tab.AddFilter(ft))
730 MessageBox.Show(Properties.Resources.ButtonOK_ClickText4, Properties.Resources.ButtonOK_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Error);
734 ListFilters.SelectedIndex = -1;
735 if (_mode == EDITMODE.AddNew)
737 ListFilters.SelectedIndex = ListFilters.Items.Count - 1;
741 ListFilters.SelectedIndex = i;
743 _mode = EDITMODE.None;
751 private bool IsValidLambdaExp(string text)
752 => false; // TODO DynamicQuery相当のGPLv3互換なライブラリで置換する
754 private bool IsValidRegexp(string text)
762 MessageBox.Show(Properties.Resources.ButtonOK_ClickText3 + ex.Message, Properties.Resources.ButtonOK_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
768 private bool CheckMatchRule(out bool isBlank)
771 if (RadioAND.Checked)
773 if (string.IsNullOrEmpty(UID.Text) && string.IsNullOrEmpty(MSG1.Text) && string.IsNullOrEmpty(TextSource.Text) && CheckRetweet.Checked == false)
778 if (CheckLambda.Checked)
780 if (!IsValidLambdaExp(UID.Text))
784 if (!IsValidLambdaExp(MSG1.Text))
789 else if (CheckRegex.Checked)
791 if (!IsValidRegexp(UID.Text))
795 if (!IsValidRegexp(MSG1.Text))
803 if (string.IsNullOrEmpty(MSG2.Text) && string.IsNullOrEmpty(TextSource.Text) && CheckRetweet.Checked == false)
808 if (CheckLambda.Checked && !IsValidLambdaExp(MSG2.Text))
812 else if (CheckRegex.Checked && !IsValidRegexp(MSG2.Text))
818 if (CheckRegex.Checked && !IsValidRegexp(TextSource.Text))
825 private bool CheckExcludeRule(out bool isBlank)
828 if (RadioExAnd.Checked)
830 if (string.IsNullOrEmpty(ExUID.Text) && string.IsNullOrEmpty(ExMSG1.Text) && string.IsNullOrEmpty(TextExSource.Text) && CheckExRetweet.Checked == false)
835 if (CheckExLambDa.Checked)
837 if (!IsValidLambdaExp(ExUID.Text))
841 if (!IsValidLambdaExp(ExMSG1.Text))
846 else if (CheckExRegex.Checked)
848 if (!IsValidRegexp(ExUID.Text))
852 if (!IsValidRegexp(ExMSG1.Text))
860 if (string.IsNullOrEmpty(ExMSG2.Text) && string.IsNullOrEmpty(TextExSource.Text) && CheckExRetweet.Checked == false)
865 if (CheckExLambDa.Checked && !IsValidLambdaExp(ExMSG2.Text))
869 else if (CheckExRegex.Checked && !IsValidRegexp(ExMSG2.Text))
875 if (CheckExRegex.Checked && !IsValidRegexp(TextExSource.Text))
883 private void ListFilters_SelectedIndexChanged(object sender, EventArgs e)
885 if (_multiSelState != MultiSelectionState.None) //複数選択処理中は無視する
890 var selectedCount = this.ListFilters.SelectedIndices.Count;
891 if (selectedCount == 0)
893 this.RuleEnableButtonMode = EnableButtonMode.NotSelected;
897 if (selectedCount == 1 ||
898 this.RuleEnableButtonMode == EnableButtonMode.NotSelected)
900 var topItem = (PostFilterRule)this.ListFilters.SelectedItem;
901 this.RuleEnableButtonMode = topItem.Enabled ? EnableButtonMode.Disable : EnableButtonMode.Enable;
906 private void ButtonClose_Click(object sender, EventArgs e)
909 private void FilterDialog_FormClosed(object sender, FormClosedEventArgs e)
910 => this._directAdd = false;
912 private void FilterDialog_KeyDown(object sender, KeyEventArgs e)
914 if (e.KeyCode == Keys.Escape)
916 if (EditFilterGroup.Enabled)
917 ButtonCancel_Click(null, null);
919 ButtonClose_Click(null, null);
923 private void ListFilters_DoubleClick(object sender, EventArgs e)
925 var idx = ListFilters.SelectedIndex;
926 if (idx == -1) return;
928 var midx = ListFilters.IndexFromPoint(ListFilters.PointToClient(Control.MousePosition));
929 if (midx == ListBox.NoMatches || idx != midx) return;
931 ButtonEdit_Click(sender, e);
934 private void FilterDialog_Shown(object sender, EventArgs e)
936 ListTabs.DisplayMember = nameof(TabModel.TabName);
938 ComboSound.Items.Clear();
939 ComboSound.Items.Add("");
940 var oDir = new DirectoryInfo(Application.StartupPath + Path.DirectorySeparatorChar);
941 if (Directory.Exists(Path.Combine(Application.StartupPath, "Sounds")))
943 oDir = oDir.GetDirectories("Sounds")[0];
945 foreach (var oFile in oDir.GetFiles("*.wav"))
947 ComboSound.Items.Add(oFile.Name);
951 foreach (var tmp in ((TweenMain)this.Owner).AtIdSupl.GetItemList())
953 idlist.Add(tmp.Remove(0, 1)); // @文字削除
955 UID.AutoCompleteCustomSource.Clear();
956 UID.AutoCompleteCustomSource.AddRange(idlist.ToArray());
958 ExUID.AutoCompleteCustomSource.Clear();
959 ExUID.AutoCompleteCustomSource.AddRange(idlist.ToArray());
962 this.ListTabs.SelectedIndex = this.selectedTabIndex;
965 private void ListTabs_SelectedIndexChanged(object sender, EventArgs e)
967 this.selectedTabIndex = this.ListTabs.SelectedIndex;
969 if (ListTabs.SelectedIndex > -1)
970 SetFilters(this.SelectedTab);
972 ListFilters.Items.Clear();
975 private async void ButtonAddTab_Click(object sender, EventArgs e)
977 string tabName = null;
978 MyCommon.TabUsageType tabType;
979 using (var inputName = new InputTabName())
981 inputName.TabName = _sts.MakeTabName("MyTab");
982 inputName.IsShowUsage = true;
983 inputName.ShowDialog();
984 if (inputName.DialogResult == DialogResult.Cancel) return;
985 tabName = inputName.TabName;
986 tabType = inputName.Usage;
988 if (!string.IsNullOrEmpty(tabName))
991 ListElement list = null;
992 if (tabType == MyCommon.TabUsageType.Lists)
996 using (var dialog = new WaitingDialog(Properties.Resources.ListsGetting))
998 var cancellationToken = dialog.EnableCancellation();
1000 var task = ((TweenMain)this.Owner).TwitterInstance.GetListsApi();
1001 await dialog.WaitForAsync(this, task);
1003 cancellationToken.ThrowIfCancellationRequested();
1006 catch (OperationCanceledException) { return; }
1007 catch (WebApiException ex)
1009 MessageBox.Show("Failed to get lists. (" + ex.Message + ")");
1011 using (var listAvail = new ListAvailable())
1013 if (listAvail.ShowDialog(this) == DialogResult.Cancel) return;
1014 if (listAvail.SelectedList == null) return;
1015 list = listAvail.SelectedList;
1022 case MyCommon.TabUsageType.UserDefined:
1023 tab = new FilterTabModel(tabName);
1025 case MyCommon.TabUsageType.PublicSearch:
1026 tab = new PublicSearchTabModel(tabName);
1028 case MyCommon.TabUsageType.Lists:
1029 tab = new ListTimelineTabModel(tabName, list);
1035 if (!_sts.AddTab(tab) || !((TweenMain)this.Owner).AddNewTab(tab, startup: false))
1037 var tmp = string.Format(Properties.Resources.AddTabMenuItem_ClickText1, tabName);
1038 MessageBox.Show(tmp, Properties.Resources.AddTabMenuItem_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
1044 this.RefreshListTabs();
1049 private void ButtonDeleteTab_Click(object sender, EventArgs e)
1051 if (ListTabs.SelectedIndex > -1)
1053 var tb = this.SelectedTab.TabName;
1054 var idx = ListTabs.SelectedIndex;
1055 if (((TweenMain)this.Owner).RemoveSpecifiedTab(tb, true))
1057 this.RefreshListTabs();
1059 if (idx < 0) idx = 0;
1060 ListTabs.SelectedIndex = idx;
1065 private void ButtonRenameTab_Click(object sender, EventArgs e)
1067 if (ListTabs.SelectedIndex > -1)
1069 var origTabName = this.SelectedTab.TabName;
1070 if (((TweenMain)this.Owner).TabRename(origTabName, out var _))
1071 this.RefreshListTabs();
1075 private void CheckManageRead_CheckedChanged(object sender, EventArgs e)
1077 if (ListTabs.SelectedIndex > -1)
1079 ((TweenMain)this.Owner).ChangeTabUnreadManage(
1080 this.SelectedTab.TabName,
1081 CheckManageRead.Checked);
1085 private void ButtonUp_Click(object sender, EventArgs e)
1087 var selectedIndex = this.ListTabs.SelectedIndex;
1089 if (selectedIndex == -1 || selectedIndex == 0)
1092 var selectedTab = this.tabs[selectedIndex];
1093 var selectedTabName = selectedTab.TabName;
1095 var targetTab = this.tabs[selectedIndex - 1];
1096 var targetTabName = targetTab.TabName;
1099 if (selectedTab.TabType == MyCommon.TabUsageType.Mute || targetTab.TabType == MyCommon.TabUsageType.Mute)
1102 var tweenMain = (TweenMain)this.Owner;
1103 tweenMain.ReOrderTab(selectedTabName, targetTabName, true);
1105 this.RefreshListTabs();
1108 private void ButtonDown_Click(object sender, EventArgs e)
1110 var selectedIndex = this.ListTabs.SelectedIndex;
1112 if (selectedIndex == -1 || selectedIndex == this.ListTabs.Items.Count - 1)
1115 var selectedTab = this.tabs[selectedIndex];
1116 var selectedTabName = selectedTab.TabName;
1118 var targetTab = this.tabs[selectedIndex + 1];
1119 var targetTabName = targetTab.TabName;
1122 if (selectedTab.TabType == MyCommon.TabUsageType.Mute || targetTab.TabType == MyCommon.TabUsageType.Mute)
1125 var tweenMain = (TweenMain)this.Owner;
1126 tweenMain.ReOrderTab(selectedTabName, targetTabName, false);
1128 this.RefreshListTabs();
1131 private void CheckLocked_CheckedChanged(object sender, EventArgs e)
1133 if (ListTabs.SelectedIndex > -1)
1135 this.SelectedTab.Protected = CheckProtected.Checked;
1136 ButtonDeleteTab.Enabled = !CheckProtected.Checked;
1140 private void CheckNotifyNew_CheckedChanged(object sender, EventArgs e)
1142 if (ListTabs.SelectedIndex > -1)
1144 this.SelectedTab.Notify = CheckNotifyNew.Checked;
1148 private void ComboSound_SelectedIndexChanged(object sender, EventArgs e)
1150 if (ListTabs.SelectedIndex > -1)
1153 if (ComboSound.SelectedIndex > -1) filename = ComboSound.SelectedItem.ToString();
1154 this.SelectedTab.SoundFile = filename;
1158 private void RadioExAnd_CheckedChanged(object sender, EventArgs e)
1160 var flg = RadioExAnd.Checked;
1161 ExUID.Enabled = flg;
1162 ExMSG1.Enabled = flg;
1163 ExMSG2.Enabled = !flg;
1166 private void OptMove_CheckedChanged(object sender, EventArgs e)
1167 => this.CheckMark.Enabled = !OptMove.Checked;
1169 private void ButtonRuleUp_Click(object sender, EventArgs e)
1170 => this.MoveSelectedRules(up: true);
1172 private void ButtonRuleDown_Click(object sender, EventArgs e)
1173 => this.MoveSelectedRules(up: false);
1175 private void MoveSelectedRules(bool up)
1177 var tabIdx = ListTabs.SelectedIndex;
1179 ListFilters.SelectedIndices.Count == 0) return;
1181 var indices = ListFilters.SelectedIndices.Cast<int>().ToArray();
1186 if (indices[0] <= 0) return;
1191 if (indices[indices.Length - 1] >= ListFilters.Items.Count - 1) return;
1193 Array.Reverse(indices); // 逆順にして、下にある要素から処理する
1196 var lastSelIdx = indices[0] + diff;
1197 var tab = (FilterTabModel)this.SelectedTab;
1201 _multiSelState |= MultiSelectionState.MoveSelected;
1203 using (ControlTransaction.Update(ListFilters))
1205 ListFilters.SelectedIndices.Clear();
1207 foreach (var idx in indices)
1209 var tidx = idx + diff;
1210 var target = (PostFilterRule)ListFilters.Items[tidx];
1212 // 移動先にある要素と位置を入れ替える
1213 ListFilters.Items.RemoveAt(tidx);
1214 ListFilters.Items.Insert(idx, target);
1216 // 移動方向の先頭要素以外なら選択する
1217 if (tidx != lastSelIdx)
1218 ListFilters.SelectedIndex = tidx;
1221 tab.FilterArray = ListFilters.Items.Cast<PostFilterRule>().ToArray();
1223 // 移動方向の先頭要素は最後に選択する
1225 ListFilters.SelectedIndex = lastSelIdx;
1230 _multiSelState &= ~MultiSelectionState.MoveSelected;
1234 private void buttonRuleToggleEnabled_Click(object sender, EventArgs e)
1236 if (this.RuleEnableButtonMode == EnableButtonMode.NotSelected)
1239 var enabled = this.RuleEnableButtonMode == EnableButtonMode.Enable;
1241 foreach (var idx in this.ListFilters.SelectedIndices.Cast<int>())
1243 var filter = (PostFilterRule)this.ListFilters.Items[idx];
1244 if (filter.Enabled != enabled)
1246 filter.Enabled = enabled;
1248 var itemRect = this.ListFilters.GetItemRectangle(idx);
1249 this.ListFilters.Invalidate(itemRect);
1253 this.RuleEnableButtonMode = enabled ? EnableButtonMode.Disable : EnableButtonMode.Enable;
1256 private void ButtonRuleCopy_Click(object sender, EventArgs e)
1258 if (ListTabs.SelectedIndex > -1 && ListFilters.SelectedItem != null)
1260 TabModel[] selectedTabs;
1261 using (var dialog = new TabsDialog(_sts))
1263 dialog.MultiSelect = true;
1264 dialog.Text = Properties.Resources.ButtonRuleCopy_ClickText1;
1266 if (dialog.ShowDialog(this) == DialogResult.Cancel) return;
1268 selectedTabs = dialog.SelectedTabs;
1271 var currentTab = (FilterTabModel)this.SelectedTab;
1272 var filters = new List<PostFilterRule>();
1274 foreach (int idx in ListFilters.SelectedIndices)
1276 filters.Add(currentTab.FilterArray[idx].Clone());
1278 foreach (var tb in selectedTabs.Cast<FilterTabModel>())
1280 if (tb.TabName == currentTab.TabName) continue;
1282 foreach (var flt in filters)
1284 if (!tb.FilterArray.Contains(flt))
1285 tb.AddFilter(flt.Clone());
1288 SetFilters(this.SelectedTab);
1292 private void ButtonRuleMove_Click(object sender, EventArgs e)
1294 if (ListTabs.SelectedIndex > -1 && ListFilters.SelectedItem != null)
1296 TabModel[] selectedTabs;
1297 using (var dialog = new TabsDialog(_sts))
1299 dialog.MultiSelect = true;
1300 dialog.Text = Properties.Resources.ButtonRuleMove_ClickText1;
1302 if (dialog.ShowDialog(this) == DialogResult.Cancel) return;
1304 selectedTabs = dialog.SelectedTabs;
1306 var currentTab = (FilterTabModel)this.SelectedTab;
1307 var filters = new List<PostFilterRule>();
1309 foreach (int idx in ListFilters.SelectedIndices)
1311 filters.Add(currentTab.FilterArray[idx].Clone());
1313 if (selectedTabs.Length == 1 && selectedTabs[0].TabName == currentTab.TabName) return;
1314 foreach (var tb in selectedTabs.Cast<FilterTabModel>())
1316 if (tb.TabName == currentTab.TabName) continue;
1318 foreach (var flt in filters)
1320 if (!tb.FilterArray.Contains(flt))
1321 tb.AddFilter(flt.Clone());
1324 for (var idx = ListFilters.Items.Count - 1; idx >= 0; idx--)
1326 if (ListFilters.GetSelected(idx))
1328 currentTab.RemoveFilter((PostFilterRule)ListFilters.Items[idx]);
1329 ListFilters.Items.RemoveAt(idx);
1332 SetFilters(this.SelectedTab);
1336 private void FilterTextBox_KeyDown(object sender, KeyEventArgs e)
1338 if (e.KeyCode == Keys.Space && e.Modifiers == (Keys.Shift | Keys.Control))
1340 var main = (TweenMain)this.Owner;
1341 var tbox = (TextBox)sender;
1342 if (tbox.SelectionStart > 0)
1344 var endidx = tbox.SelectionStart - 1;
1346 for (var i = tbox.SelectionStart - 1; i >= 0; i--)
1348 var c = tbox.Text[i];
1349 if (Char.IsLetterOrDigit(c) || c == '_')
1355 startstr = tbox.Text.Substring(i + 1, endidx - i);
1356 main.ShowSuplDialog(tbox, main.AtIdSupl, startstr.Length + 1, startstr);
1360 startstr = tbox.Text.Substring(i + 1, endidx - i);
1361 main.ShowSuplDialog(tbox, main.HashSupl, startstr.Length + 1, startstr);
1373 private void FilterTextBox_KeyPress(object sender, KeyPressEventArgs e)
1375 var main = (TweenMain)this.Owner;
1376 var tbox = (TextBox)sender;
1377 if (e.KeyChar == '@')
1379 //if (!SettingDialog.UseAtIdSupplement) return;
1381 main.ShowSuplDialog(tbox, main.AtIdSupl);
1384 else if (e.KeyChar == '#')
1386 //if (!SettingDialog.UseHashSupplement) return;
1387 main.ShowSuplDialog(tbox, main.HashSupl);
1392 private void ListFilters_DrawItem(object sender, DrawItemEventArgs e)
1398 var filter = (PostFilterRule)this.ListFilters.Items[e.Index];
1399 var isSelected = e.State.HasFlag(DrawItemState.Selected);
1403 textBrush = SystemBrushes.HighlightText;
1404 else if (filter.Enabled)
1405 textBrush = SystemBrushes.WindowText;
1407 textBrush = SystemBrushes.GrayText;
1409 e.Graphics.DrawString(filter.ToString(), e.Font, textBrush, e.Bounds);
1412 e.DrawFocusRectangle();
1415 private void ListFilters_KeyDown(object sender, KeyEventArgs e)
1417 if (e.Control && e.KeyCode == Keys.A)
1419 var itemCount = this.ListFilters.Items.Count;
1420 if (itemCount == 0) return;
1422 using (ControlTransaction.Update(this.ListFilters))
1428 _multiSelState |= MultiSelectionState.SelectAll;
1430 for (var i = 1; i < itemCount; i++)
1432 this.ListFilters.SetSelected(i, true);
1437 _multiSelState &= ~MultiSelectionState.SelectAll;
1441 this.ListFilters.SetSelected(0, true);
1446 protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
1448 base.ScaleControl(factor, specified);
1449 this.ListFilters.ItemHeight = this.ListFilters.Font.Height;