OSDN Git Service

varを使用する (IDE0007)
[opentween/open-tween.git] / OpenTween / FilterDialog.cs
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.
9 // 
10 // This file is part of OpenTween.
11 // 
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)
15 // any later version.
16 // 
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
20 // for more details. 
21 // 
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.
26
27 using System;
28 using System.Collections.Generic;
29 using System.ComponentModel;
30 using System.Data;
31 using System.Drawing;
32 using System.Linq;
33 using System.Text;
34 using System.Windows.Forms;
35 using System.Linq.Expressions;
36 using System.Text.RegularExpressions;
37 using System.IO;
38 using System.Collections.Specialized;
39 using OpenTween.Models;
40
41 namespace OpenTween
42 {
43     public partial class FilterDialog : OTBaseForm
44     {
45         private EDITMODE _mode;
46         private bool _directAdd;
47         private MultiSelectionState _multiSelState = MultiSelectionState.None;
48         private readonly TabInformations _sts;
49
50         private List<TabModel> tabs = new List<TabModel>();
51         private int selectedTabIndex = -1;
52
53         private readonly List<string> idlist = new List<string>();
54
55         private enum EDITMODE
56         {
57             AddNew,
58             Edit,
59             None,
60         }
61
62         private enum EnableButtonMode
63         {
64             NotSelected,
65             Enable,
66             Disable,
67         }
68
69         [Flags]
70         private enum MultiSelectionState
71         {
72             None = 0,
73             MoveSelected = 1,
74             SelectAll = 2,
75         }
76
77         private EnableButtonMode RuleEnableButtonMode
78         {
79             get => this._ruleEnableButtonMode;
80             set
81             {
82                 this._ruleEnableButtonMode = value;
83
84                 this.buttonRuleToggleEnabled.Text = value == FilterDialog.EnableButtonMode.Enable
85                     ? Properties.Resources.EnableButtonCaption
86                     : Properties.Resources.DisableButtonCaption;
87                 this.buttonRuleToggleEnabled.Enabled = value != EnableButtonMode.NotSelected;
88             }
89         }
90         private EnableButtonMode _ruleEnableButtonMode = FilterDialog.EnableButtonMode.NotSelected;
91
92         public TabModel SelectedTab
93             => this.selectedTabIndex != -1 ? this.tabs[this.selectedTabIndex] : null;
94
95         public FilterDialog()
96         {
97             this.InitializeComponent();
98
99             this._sts = TabInformations.GetInstance();
100             this.RefreshListTabs();
101         }
102
103         private void RefreshListTabs()
104         {
105             this.tabs = this._sts.Tabs.Append(this._sts.MuteTab).ToList();
106
107             using (ControlTransaction.Update(this.ListTabs))
108             {
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);
113             }
114         }
115
116         private void SetFilters(TabModel tab)
117         {
118             if (ListTabs.Items.Count == 0) return;
119
120             ListFilters.Items.Clear();
121
122             if (tab is FilterTabModel filterTab)
123                 ListFilters.Items.AddRange(filterTab.GetFilters());
124
125             if (ListFilters.Items.Count > 0)
126                 ListFilters.SelectedIndex = 0;
127             else
128                 ShowDetail();
129
130             if (tab.IsDefaultTabType)
131             {
132                 CheckProtected.Checked = true;
133                 CheckProtected.Enabled = false;
134             }
135             else
136             {
137                 CheckProtected.Checked = tab.Protected;
138                 CheckProtected.Enabled = true;
139             }
140
141             CheckManageRead.Checked = tab.UnreadManage;
142             CheckNotifyNew.Checked = tab.Notify;
143
144             var idx = ComboSound.Items.IndexOf(tab.SoundFile);
145             if (idx == -1) idx = 0;
146             ComboSound.SelectedIndex = idx;
147
148             if (_directAdd) return;
149
150             if (tab.TabType == MyCommon.TabUsageType.Mute)
151             {
152                 this.CheckManageRead.Enabled = false;
153                 this.CheckNotifyNew.Enabled = false;
154                 this.ComboSound.Enabled = false;
155
156                 this.GroupBox1.Visible = false;
157                 this.labelMuteTab.Visible = true;
158             }
159             else
160             {
161                 this.CheckManageRead.Enabled = true;
162                 this.CheckNotifyNew.Enabled = true;
163                 this.ComboSound.Enabled = true;
164
165                 this.GroupBox1.Visible = true;
166                 this.labelMuteTab.Visible = false;
167             }
168
169             ListTabs.Enabled = true;
170             GroupTab.Enabled = true;
171             ListFilters.Enabled = true;
172             EditFilterGroup.Enabled = false;
173
174             if (tab.IsDistributableTabType)
175             {
176                 ButtonNew.Enabled = true;
177                 if (ListFilters.SelectedIndex > -1)
178                 {
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;
186                 }
187                 else
188                 {
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;
196                 }
197             }
198             else
199             {
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;
208             }
209
210             switch (tab.TabType)
211             {
212                 case MyCommon.TabUsageType.Home:
213                     LabelTabType.Text = Properties.Resources.TabUsageTypeName_Home;
214                     break;
215                 case MyCommon.TabUsageType.Mentions:
216                     LabelTabType.Text = Properties.Resources.TabUsageTypeName_Mentions;
217                     break;
218                 case MyCommon.TabUsageType.DirectMessage:
219                     LabelTabType.Text = Properties.Resources.TabUsageTypeName_DirectMessage;
220                     break;
221                 case MyCommon.TabUsageType.Favorites:
222                     LabelTabType.Text = Properties.Resources.TabUsageTypeName_Favorites;
223                     break;
224                 case MyCommon.TabUsageType.UserDefined:
225                     LabelTabType.Text = Properties.Resources.TabUsageTypeName_UserDefined;
226                     break;
227                 case MyCommon.TabUsageType.PublicSearch:
228                     LabelTabType.Text = Properties.Resources.TabUsageTypeName_PublicSearch;
229                     break;
230                 case MyCommon.TabUsageType.Lists:
231                     LabelTabType.Text = Properties.Resources.TabUsageTypeName_Lists;
232                     break;
233                 case MyCommon.TabUsageType.Related:
234                     LabelTabType.Text = Properties.Resources.TabUsageTypeName_Related;
235                     break;
236                 case MyCommon.TabUsageType.UserTimeline:
237                     LabelTabType.Text = Properties.Resources.TabUsageTypeName_UserTimeline;
238                     break;
239                 case MyCommon.TabUsageType.Mute:
240                     LabelTabType.Text = "Mute";
241                     break;
242                 case MyCommon.TabUsageType.SearchResults:
243                     LabelTabType.Text = "SearchResults";
244                     break;
245                 default:
246                     LabelTabType.Text = "UNKNOWN";
247                     break;
248             }
249             ButtonRenameTab.Enabled = true;
250             if (tab.IsDefaultTabType || tab.Protected)
251             {
252                 ButtonDeleteTab.Enabled = false;
253             }
254             else
255             {
256                 ButtonDeleteTab.Enabled = true;
257             }
258             ButtonClose.Enabled = true;
259         }
260
261         public void SetCurrent(string tabName)
262         {
263             var index = this.tabs.FindIndex(x => x.TabName == tabName);
264             if (index == -1)
265                 throw new ArgumentException($"Unknown tab: {tabName}", nameof(tabName));
266
267             this.selectedTabIndex = index;
268         }
269
270         public void AddNewFilter(string id, string msg)
271         {
272             //元フォームから直接呼ばれる
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;
286
287             RadioAND.Checked = true;
288             RadioPLUS.Checked = false;
289             UID.Text = id;
290             UID.SelectAll();
291             MSG1.Text = msg;
292             MSG1.SelectAll();
293             MSG2.Text = id + msg;
294             MSG2.SelectAll();
295             TextSource.Text = "";
296             UID.Enabled = true;
297             MSG1.Enabled = true;
298             MSG2.Enabled = false;
299             CheckRegex.Checked = false;
300             CheckURL.Checked = false;
301             CheckCaseSensitive.Checked = false;
302             CheckRetweet.Checked = false;
303             CheckLambda.Checked = false;
304
305             RadioExAnd.Checked = true;
306             RadioExPLUS.Checked = false;
307             ExUID.Text = "";
308             ExUID.SelectAll();
309             ExMSG1.Text = "";
310             ExMSG1.SelectAll();
311             ExMSG2.Text = "";
312             ExMSG2.SelectAll();
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;
322
323             OptCopy.Checked = true;
324             CheckMark.Checked = true;
325             UID.Focus();
326             _mode = EDITMODE.AddNew;
327             _directAdd = true;
328         }
329
330         private void ButtonNew_Click(object sender, EventArgs e)
331         {
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;
346
347             RadioAND.Checked = true;
348             RadioPLUS.Checked = false;
349             UID.Text = "";
350             MSG1.Text = "";
351             MSG2.Text = "";
352             TextSource.Text = "";
353             UID.Enabled = true;
354             MSG1.Enabled = true;
355             MSG2.Enabled = false;
356             CheckRegex.Checked = false;
357             CheckURL.Checked = false;
358             CheckCaseSensitive.Checked = false;
359             CheckRetweet.Checked = false;
360             CheckLambda.Checked = false;
361
362             RadioExAnd.Checked = true;
363             RadioExPLUS.Checked = false;
364             ExUID.Text = "";
365             ExMSG1.Text = "";
366             ExMSG2.Text = "";
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;
376
377             OptCopy.Checked = true;
378             CheckMark.Checked = true;
379             UID.Focus();
380             _mode = EDITMODE.AddNew;
381         }
382
383         private void ButtonEdit_Click(object sender, EventArgs e)
384         {
385             if (ListFilters.SelectedIndex == -1) return;
386
387             ShowDetail();
388
389             var idx = ListFilters.SelectedIndex;
390             ListFilters.SelectedIndex = -1;
391             ListFilters.SelectedIndex = idx;
392             ListFilters.Enabled = false;
393
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;
406
407             _mode = EDITMODE.Edit;
408         }
409
410         private void ButtonDelete_Click(object sender, EventArgs e)
411         {
412             var selectedCount = ListFilters.SelectedIndices.Count;
413             if (selectedCount == 0) return;
414
415             string tmp;
416
417             if (selectedCount == 1)
418             {
419                 tmp = string.Format(Properties.Resources.ButtonDelete_ClickText1, Environment.NewLine, ListFilters.SelectedItem);
420             }
421             else
422             {
423                 tmp = string.Format(Properties.Resources.ButtonDelete_ClickText3, selectedCount);
424             }
425
426             var rslt = MessageBox.Show(tmp, Properties.Resources.ButtonDelete_ClickText2, MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
427             if (rslt == DialogResult.Cancel) return;
428
429             var indices = ListFilters.SelectedIndices.Cast<int>().Reverse().ToArray();  // 後ろの要素から削除
430             var tab = (FilterTabModel)this.SelectedTab;
431
432             using (ControlTransaction.Update(ListFilters))
433             {
434                 foreach (var idx in indices)
435                 {
436                     tab.RemoveFilter((PostFilterRule)ListFilters.Items[idx]);
437                     ListFilters.Items.RemoveAt(idx);
438                 }
439             }
440         }
441
442         private void ButtonCancel_Click(object sender, EventArgs e)
443         {
444             ListTabs.Enabled = true;
445             GroupTab.Enabled = true;
446             ListFilters.Enabled = true;
447             ListFilters.Focus();
448             if (ListFilters.SelectedIndex != -1)
449             {
450                 ShowDetail();
451             }
452             EditFilterGroup.Enabled = false;
453             ButtonNew.Enabled = true;
454             if (ListFilters.SelectedIndex > -1)
455             {
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;
463             }
464             else
465             {
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;
473             }
474             ButtonClose.Enabled = true;
475             if (_directAdd)
476             {
477                 this.Close();
478             }
479         }
480
481         private void ShowDetail()
482         {
483             if (_directAdd) return;
484
485             if (ListFilters.SelectedIndex > -1)
486             {
487                 var fc = (PostFilterRule)ListFilters.SelectedItem;
488                 if (fc.UseNameField)
489                 {
490                     RadioAND.Checked = true;
491                     RadioPLUS.Checked = false;
492                     UID.Enabled = true;
493                     MSG1.Enabled = true;
494                     MSG2.Enabled = false;
495                     UID.Text = fc.FilterName;
496                     UID.SelectAll();
497                     MSG1.Text = string.Join(" ", fc.FilterBody);
498                     MSG1.SelectAll();
499                     MSG2.Text = "";
500                 }
501                 else
502                 {
503                     RadioPLUS.Checked = true;
504                     RadioAND.Checked = false;
505                     UID.Enabled = false;
506                     MSG1.Enabled = false;
507                     MSG2.Enabled = true;
508                     UID.Text = "";
509                     MSG1.Text = "";
510                     MSG2.Text = string.Join(" ", fc.FilterBody);
511                     MSG2.SelectAll();
512                 }
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;
519
520                 if (fc.ExUseNameField)
521                 {
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;
528                     ExUID.SelectAll();
529                     ExMSG1.Text = string.Join(" ", fc.ExFilterBody);
530                     ExMSG1.SelectAll();
531                     ExMSG2.Text = "";
532                 }
533                 else
534                 {
535                     RadioExPLUS.Checked = true;
536                     RadioExAnd.Checked = false;
537                     ExUID.Enabled = false;
538                     ExMSG1.Enabled = false;
539                     ExMSG2.Enabled = true;
540                     ExUID.Text = "";
541                     ExMSG1.Text = "";
542                     ExMSG2.Text = string.Join(" ", fc.ExFilterBody);
543                     ExMSG2.SelectAll();
544                 }
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;
551
552                 if (fc.MoveMatches)
553                 {
554                     OptMove.Checked = true;
555                 }
556                 else
557                 {
558                     OptCopy.Checked = true;
559                 }
560                 CheckMark.Checked = fc.MarkMatches;
561
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;
569             }
570             else
571             {
572                 RadioAND.Checked = true;
573                 RadioPLUS.Checked = false;
574                 UID.Enabled = true;
575                 MSG1.Enabled = true;
576                 MSG2.Enabled = false;
577                 UID.Text = "";
578                 MSG1.Text = "";
579                 MSG2.Text = "";
580                 TextSource.Text = "";
581                 CheckRegex.Checked = false;
582                 CheckURL.Checked = false;
583                 CheckCaseSensitive.Checked = false;
584                 CheckRetweet.Checked = false;
585                 CheckLambda.Checked = false;
586
587                 RadioExAnd.Checked = true;
588                 RadioExPLUS.Checked = false;
589                 ExUID.Enabled = true;
590                 ExMSG1.Enabled = true;
591                 ExMSG2.Enabled = false;
592                 ExUID.Text = "";
593                 ExMSG1.Text = "";
594                 ExMSG2.Text = "";
595                 TextExSource.Text = "";
596                 CheckExRegex.Checked = false;
597                 CheckExURL.Checked = false;
598                 CheckExCaseSensitive.Checked = false;
599                 CheckExRetweet.Checked = false;
600                 CheckExLambDa.Checked = false;
601
602                 OptCopy.Checked = true;
603                 CheckMark.Checked = true;
604
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;
612             }
613         }
614
615         private void RadioAND_CheckedChanged(object sender, EventArgs e)
616         {
617             var flg = RadioAND.Checked;
618             UID.Enabled = flg;
619             MSG1.Enabled = flg;
620             MSG2.Enabled = !flg;
621         }
622
623         private void ButtonOK_Click(object sender, EventArgs e)
624         {
625             //入力チェック
626             if (!CheckMatchRule(out var isBlankMatch) || !CheckExcludeRule(out var isBlankExclude))
627             {
628                 return;
629             }
630             if (isBlankMatch && isBlankExclude)
631             {
632                 MessageBox.Show(Properties.Resources.ButtonOK_ClickText1, Properties.Resources.ButtonOK_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
633                 return;
634             }
635
636             var tab = (FilterTabModel)this.SelectedTab;
637             var i = ListFilters.SelectedIndex;
638
639             PostFilterRule ft;
640             if (_mode == EDITMODE.AddNew)
641                 ft = new PostFilterRule();
642             else
643                 ft = (PostFilterRule)this.ListFilters.SelectedItem;
644
645             if (tab.TabType != MyCommon.TabUsageType.Mute)
646             {
647                 ft.MoveMatches = OptMove.Checked;
648                 ft.MarkMatches = CheckMark.Checked;
649             }
650             else
651             {
652                 ft.MoveMatches = true;
653                 ft.MarkMatches = false;
654             }
655
656             var bdy = "";
657             if (RadioAND.Checked)
658             {
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)
664                 {
665                     owner.MarkSettingAtIdModified();
666                 }
667                 ft.UseNameField = true;
668                 bdy = MSG1.Text;
669             }
670             else
671             {
672                 ft.FilterName = "";
673                 ft.UseNameField = false;
674                 bdy = MSG2.Text;
675             }
676             ft.FilterSource = TextSource.Text;
677
678             if (CheckRegex.Checked || CheckLambda.Checked)
679             {
680                 ft.FilterBody = new[] { bdy };
681             }
682             else
683             {
684                 ft.FilterBody = bdy.Split(' ', ' ')
685                     .Where(x => !string.IsNullOrEmpty(x))
686                     .ToArray();
687             }
688
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;
694
695             bdy = "";
696             if (RadioExAnd.Checked)
697             {
698                 ft.ExFilterName = ExUID.Text;
699                 ft.ExUseNameField = true;
700                 bdy = ExMSG1.Text;
701             }
702             else
703             {
704                 ft.ExFilterName = "";
705                 ft.ExUseNameField = false;
706                 bdy = ExMSG2.Text;
707             }
708             ft.ExFilterSource = TextExSource.Text;
709
710             if (CheckExRegex.Checked || CheckExLambDa.Checked)
711             {
712                 ft.ExFilterBody = new[] { bdy };
713             }
714             else
715             {
716                 ft.ExFilterBody = bdy.Split(' ', ' ')
717                     .Where(x => !string.IsNullOrEmpty(x))
718                     .ToArray();
719             }
720
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;
726
727             if (_mode == EDITMODE.AddNew)
728             {
729                 if (!tab.AddFilter(ft))
730                     MessageBox.Show(Properties.Resources.ButtonOK_ClickText4, Properties.Resources.ButtonOK_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Error);
731             }
732
733             SetFilters(tab);
734             ListFilters.SelectedIndex = -1;
735             if (_mode == EDITMODE.AddNew)
736             {
737                 ListFilters.SelectedIndex = ListFilters.Items.Count - 1;
738             }
739             else
740             {
741                 ListFilters.SelectedIndex = i;
742             }
743             _mode = EDITMODE.None;
744
745             if (_directAdd)
746             {
747                 this.Close();
748             }
749         }
750
751         private bool IsValidLambdaExp(string text)
752             => false; // TODO DynamicQuery相当のGPLv3互換なライブラリで置換する
753
754         private bool IsValidRegexp(string text)
755         {
756             try
757             {
758                 new Regex(text);
759             }
760             catch (Exception ex)
761             {
762                 MessageBox.Show(Properties.Resources.ButtonOK_ClickText3 + ex.Message, Properties.Resources.ButtonOK_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
763                 return false;
764             }
765             return true;
766         }
767
768         private bool CheckMatchRule(out bool isBlank)
769         {
770             isBlank = false;
771             if (RadioAND.Checked)
772             {
773                 if (string.IsNullOrEmpty(UID.Text) && string.IsNullOrEmpty(MSG1.Text) && string.IsNullOrEmpty(TextSource.Text) && CheckRetweet.Checked == false)
774                 {
775                     isBlank = true;
776                     return true;
777                 }
778                 if (CheckLambda.Checked)
779                 {
780                     if (!IsValidLambdaExp(UID.Text))
781                     {
782                         return false;
783                     }
784                     if (!IsValidLambdaExp(MSG1.Text))
785                     {
786                         return false;
787                     }
788                 }
789                 else if (CheckRegex.Checked)
790                 {
791                     if (!IsValidRegexp(UID.Text))
792                     {
793                         return false;
794                     }
795                     if (!IsValidRegexp(MSG1.Text))
796                     {
797                         return false;
798                     }
799                 }
800             }
801             else
802             {
803                 if (string.IsNullOrEmpty(MSG2.Text) && string.IsNullOrEmpty(TextSource.Text) && CheckRetweet.Checked == false)
804                 {
805                     isBlank = true;
806                     return true;
807                 }
808                 if (CheckLambda.Checked && !IsValidLambdaExp(MSG2.Text))
809                 {
810                     return false;
811                 }
812                 else if (CheckRegex.Checked && !IsValidRegexp(MSG2.Text))
813                 {
814                     return false;
815                 }
816             }
817
818             if (CheckRegex.Checked && !IsValidRegexp(TextSource.Text))
819             {
820                 return false;
821             }
822             return true;
823         }
824
825         private bool CheckExcludeRule(out bool isBlank)
826         {
827             isBlank = false;
828             if (RadioExAnd.Checked)
829             {
830                 if (string.IsNullOrEmpty(ExUID.Text) && string.IsNullOrEmpty(ExMSG1.Text) && string.IsNullOrEmpty(TextExSource.Text) && CheckExRetweet.Checked == false)
831                 {
832                     isBlank = true;
833                     return true;
834                 }
835                 if (CheckExLambDa.Checked)
836                 {
837                     if (!IsValidLambdaExp(ExUID.Text))
838                     {
839                         return false;
840                     }
841                     if (!IsValidLambdaExp(ExMSG1.Text))
842                     {
843                         return false;
844                     }
845                 }
846                 else if (CheckExRegex.Checked)
847                 {
848                     if (!IsValidRegexp(ExUID.Text))
849                     {
850                         return false;
851                     }
852                     if (!IsValidRegexp(ExMSG1.Text))
853                     {
854                         return false;
855                     }
856                 }
857             }
858             else
859             {
860                 if (string.IsNullOrEmpty(ExMSG2.Text) && string.IsNullOrEmpty(TextExSource.Text) && CheckExRetweet.Checked == false)
861                 {
862                     isBlank = true;
863                     return true;
864                 }
865                 if (CheckExLambDa.Checked && !IsValidLambdaExp(ExMSG2.Text))
866                 {
867                     return false;
868                 }
869                 else if (CheckExRegex.Checked && !IsValidRegexp(ExMSG2.Text))
870                 {
871                     return false;
872                 }
873             }
874
875             if (CheckExRegex.Checked && !IsValidRegexp(TextExSource.Text))
876             {
877                 return false;
878             }
879
880             return true;
881         }
882
883         private void ListFilters_SelectedIndexChanged(object sender, EventArgs e)
884         {
885             if (_multiSelState != MultiSelectionState.None)  //複数選択処理中は無視する
886                 return;
887
888             ShowDetail();
889
890             var selectedCount = this.ListFilters.SelectedIndices.Count;
891             if (selectedCount == 0)
892             {
893                 this.RuleEnableButtonMode = EnableButtonMode.NotSelected;
894             }
895             else
896             {
897                 if (selectedCount == 1 ||
898                     this.RuleEnableButtonMode == EnableButtonMode.NotSelected)
899                 {
900                     var topItem = (PostFilterRule)this.ListFilters.SelectedItem;
901                     this.RuleEnableButtonMode = topItem.Enabled ? EnableButtonMode.Disable : EnableButtonMode.Enable;
902                 }
903             }
904         }
905
906         private void ButtonClose_Click(object sender, EventArgs e)
907             => this.Close();
908
909         private void FilterDialog_FormClosed(object sender, FormClosedEventArgs e)
910             => this._directAdd = false;
911
912         private void FilterDialog_KeyDown(object sender, KeyEventArgs e)
913         {
914             if (e.KeyCode == Keys.Escape)
915             {
916                 if (EditFilterGroup.Enabled)
917                     ButtonCancel_Click(null, null);
918                 else
919                     ButtonClose_Click(null, null);
920             }
921         }
922
923         private void ListFilters_DoubleClick(object sender, EventArgs e)
924         {
925             var idx = ListFilters.SelectedIndex;
926             if (idx == -1) return;
927
928             var midx = ListFilters.IndexFromPoint(ListFilters.PointToClient(Control.MousePosition));
929             if (midx == ListBox.NoMatches || idx != midx) return;
930
931             ButtonEdit_Click(sender, e);
932         }
933
934         private void FilterDialog_Shown(object sender, EventArgs e)
935         {
936             ListTabs.DisplayMember = nameof(TabModel.TabName);
937
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")))
942             {
943                 oDir = oDir.GetDirectories("Sounds")[0];
944             }
945             foreach (var oFile in oDir.GetFiles("*.wav"))
946             {
947                 ComboSound.Items.Add(oFile.Name);
948             }
949
950             idlist.Clear();
951             foreach (var tmp in ((TweenMain)this.Owner).AtIdSupl.GetItemList())
952             {
953                 idlist.Add(tmp.Remove(0, 1));  // @文字削除
954             }
955             UID.AutoCompleteCustomSource.Clear();
956             UID.AutoCompleteCustomSource.AddRange(idlist.ToArray());
957
958             ExUID.AutoCompleteCustomSource.Clear();
959             ExUID.AutoCompleteCustomSource.AddRange(idlist.ToArray());
960
961             //選択タブ変更
962             this.ListTabs.SelectedIndex = this.selectedTabIndex;
963         }
964
965         private void ListTabs_SelectedIndexChanged(object sender, EventArgs e)
966         {
967             this.selectedTabIndex = this.ListTabs.SelectedIndex;
968
969             if (ListTabs.SelectedIndex > -1)
970                 SetFilters(this.SelectedTab);
971             else
972                 ListFilters.Items.Clear();
973         }
974
975         private async void ButtonAddTab_Click(object sender, EventArgs e)
976         {
977             string tabName = null;
978             MyCommon.TabUsageType tabType;
979             using (var inputName = new InputTabName())
980             {
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;
987             }
988             if (!string.IsNullOrEmpty(tabName))
989             {
990                 //List対応
991                 ListElement list = null;
992                 if (tabType == MyCommon.TabUsageType.Lists)
993                 {
994                     try
995                     {
996                         using (var dialog = new WaitingDialog(Properties.Resources.ListsGetting))
997                         {
998                             var cancellationToken = dialog.EnableCancellation();
999
1000                             var task = ((TweenMain)this.Owner).TwitterInstance.GetListsApi();
1001                             await dialog.WaitForAsync(this, task);
1002
1003                             cancellationToken.ThrowIfCancellationRequested();
1004                         }
1005                     }
1006                     catch (OperationCanceledException) { return; }
1007                     catch (WebApiException ex)
1008                     {
1009                         MessageBox.Show("Failed to get lists. (" + ex.Message + ")");
1010                     }
1011                     using (var listAvail = new ListAvailable())
1012                     {
1013                         if (listAvail.ShowDialog(this) == DialogResult.Cancel) return;
1014                         if (listAvail.SelectedList == null) return;
1015                         list = listAvail.SelectedList;
1016                     }
1017                 }
1018
1019                 TabModel tab;
1020                 switch (tabType)
1021                 {
1022                     case MyCommon.TabUsageType.UserDefined:
1023                         tab = new FilterTabModel(tabName);
1024                         break;
1025                     case MyCommon.TabUsageType.PublicSearch:
1026                         tab = new PublicSearchTabModel(tabName);
1027                         break;
1028                     case MyCommon.TabUsageType.Lists:
1029                         tab = new ListTimelineTabModel(tabName, list);
1030                         break;
1031                     default:
1032                         return;
1033                 }
1034
1035                 if (!_sts.AddTab(tab) || !((TweenMain)this.Owner).AddNewTab(tab, startup: false))
1036                 {
1037                     var tmp = string.Format(Properties.Resources.AddTabMenuItem_ClickText1, tabName);
1038                     MessageBox.Show(tmp, Properties.Resources.AddTabMenuItem_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
1039                     return;
1040                 }
1041                 else
1042                 {
1043                     // タブ作成成功
1044                     this.RefreshListTabs();
1045                 }
1046             }
1047         }
1048
1049         private void ButtonDeleteTab_Click(object sender, EventArgs e)
1050         {
1051             if (ListTabs.SelectedIndex > -1)
1052             {
1053                 var tb = this.SelectedTab.TabName;
1054                 var idx = ListTabs.SelectedIndex;
1055                 if (((TweenMain)this.Owner).RemoveSpecifiedTab(tb, true))
1056                 {
1057                     this.RefreshListTabs();
1058                     idx -= 1;
1059                     if (idx < 0) idx = 0;
1060                     ListTabs.SelectedIndex = idx;
1061                 }
1062             }
1063         }
1064
1065         private void ButtonRenameTab_Click(object sender, EventArgs e)
1066         {
1067             if (ListTabs.SelectedIndex > -1)
1068             {
1069                 var origTabName = this.SelectedTab.TabName;
1070                 if (((TweenMain)this.Owner).TabRename(origTabName, out var _))
1071                     this.RefreshListTabs();
1072             }
1073         }
1074
1075         private void CheckManageRead_CheckedChanged(object sender, EventArgs e)
1076         {
1077             if (ListTabs.SelectedIndex > -1)
1078             {
1079                 ((TweenMain)this.Owner).ChangeTabUnreadManage(
1080                     this.SelectedTab.TabName,
1081                     CheckManageRead.Checked);
1082             }
1083         }
1084
1085         private void ButtonUp_Click(object sender, EventArgs e)
1086         {
1087             var selectedIndex = this.ListTabs.SelectedIndex;
1088
1089             if (selectedIndex == -1 || selectedIndex == 0)
1090                 return;
1091
1092             var selectedTab = this.tabs[selectedIndex];
1093             var selectedTabName = selectedTab.TabName;
1094
1095             var targetTab = this.tabs[selectedIndex - 1];
1096             var targetTabName = targetTab.TabName;
1097
1098             // ミュートタブは移動禁止
1099             if (selectedTab.TabType == MyCommon.TabUsageType.Mute || targetTab.TabType == MyCommon.TabUsageType.Mute)
1100                 return;
1101
1102             var tweenMain = (TweenMain)this.Owner;
1103             tweenMain.ReOrderTab(selectedTabName, targetTabName, true);
1104
1105             this.RefreshListTabs();
1106         }
1107
1108         private void ButtonDown_Click(object sender, EventArgs e)
1109         {
1110             var selectedIndex = this.ListTabs.SelectedIndex;
1111
1112             if (selectedIndex == -1 || selectedIndex == this.ListTabs.Items.Count - 1)
1113                 return;
1114
1115             var selectedTab = this.tabs[selectedIndex];
1116             var selectedTabName = selectedTab.TabName;
1117
1118             var targetTab = this.tabs[selectedIndex + 1];
1119             var targetTabName = targetTab.TabName;
1120
1121             // ミュートタブは移動禁止
1122             if (selectedTab.TabType == MyCommon.TabUsageType.Mute || targetTab.TabType == MyCommon.TabUsageType.Mute)
1123                 return;
1124
1125             var tweenMain = (TweenMain)this.Owner;
1126             tweenMain.ReOrderTab(selectedTabName, targetTabName, false);
1127
1128             this.RefreshListTabs();
1129         }
1130
1131         private void CheckLocked_CheckedChanged(object sender, EventArgs e)
1132         {
1133             if (ListTabs.SelectedIndex > -1)
1134             {
1135                 this.SelectedTab.Protected = CheckProtected.Checked;
1136                 ButtonDeleteTab.Enabled = !CheckProtected.Checked;
1137             }
1138         }
1139
1140         private void CheckNotifyNew_CheckedChanged(object sender, EventArgs e)
1141         {
1142             if (ListTabs.SelectedIndex > -1)
1143             {
1144                 this.SelectedTab.Notify = CheckNotifyNew.Checked;
1145             }
1146         }
1147
1148         private void ComboSound_SelectedIndexChanged(object sender, EventArgs e)
1149         {
1150             if (ListTabs.SelectedIndex > -1)
1151             {
1152                 var filename = "";
1153                 if (ComboSound.SelectedIndex > -1) filename = ComboSound.SelectedItem.ToString();
1154                 this.SelectedTab.SoundFile = filename;
1155             }
1156         }
1157
1158         private void RadioExAnd_CheckedChanged(object sender, EventArgs e)
1159         {
1160             var flg = RadioExAnd.Checked;
1161             ExUID.Enabled = flg;
1162             ExMSG1.Enabled = flg;
1163             ExMSG2.Enabled = !flg;
1164         }
1165
1166         private void OptMove_CheckedChanged(object sender, EventArgs e)
1167             => this.CheckMark.Enabled = !OptMove.Checked;
1168
1169         private void ButtonRuleUp_Click(object sender, EventArgs e)
1170             => this.MoveSelectedRules(up: true);
1171
1172         private void ButtonRuleDown_Click(object sender, EventArgs e)
1173             => this.MoveSelectedRules(up: false);
1174
1175         private void MoveSelectedRules(bool up)
1176         {
1177             var tabIdx = ListTabs.SelectedIndex;
1178             if (tabIdx == -1 ||
1179                 ListFilters.SelectedIndices.Count == 0) return;
1180
1181             var indices = ListFilters.SelectedIndices.Cast<int>().ToArray();
1182
1183             int diff;
1184             if (up)
1185             {
1186                 if (indices[0] <= 0) return;
1187                 diff = -1;
1188             }
1189             else
1190             {
1191                 if (indices[indices.Length - 1] >= ListFilters.Items.Count - 1) return;
1192                 diff = +1;
1193                 Array.Reverse(indices);  // 逆順にして、下にある要素から処理する
1194             }
1195
1196             var lastSelIdx = indices[0] + diff;
1197             var tab = (FilterTabModel)this.SelectedTab;
1198
1199             try
1200             {
1201                 _multiSelState |= MultiSelectionState.MoveSelected;
1202
1203                 using (ControlTransaction.Update(ListFilters))
1204                 {
1205                     ListFilters.SelectedIndices.Clear();
1206
1207                     foreach (var idx in indices)
1208                     {
1209                         var tidx = idx + diff;
1210                         var target = (PostFilterRule)ListFilters.Items[tidx];
1211
1212                         // 移動先にある要素と位置を入れ替える
1213                         ListFilters.Items.RemoveAt(tidx);
1214                         ListFilters.Items.Insert(idx, target);
1215
1216                         // 移動方向の先頭要素以外なら選択する
1217                         if (tidx != lastSelIdx)
1218                             ListFilters.SelectedIndex = tidx;
1219                     }
1220
1221                     tab.FilterArray = ListFilters.Items.Cast<PostFilterRule>().ToArray();
1222
1223                     // 移動方向の先頭要素は最後に選択する
1224                     // ※移動方向への自動スクロール目的
1225                     ListFilters.SelectedIndex = lastSelIdx;
1226                 }
1227             }
1228             finally
1229             {
1230                 _multiSelState &= ~MultiSelectionState.MoveSelected;
1231             }
1232         }
1233
1234         private void buttonRuleToggleEnabled_Click(object sender, EventArgs e)
1235         {
1236             if (this.RuleEnableButtonMode == EnableButtonMode.NotSelected)
1237                 return;
1238
1239             var enabled = this.RuleEnableButtonMode == EnableButtonMode.Enable;
1240
1241             foreach (var idx in this.ListFilters.SelectedIndices.Cast<int>())
1242             {
1243                 var filter = (PostFilterRule)this.ListFilters.Items[idx];
1244                 if (filter.Enabled != enabled)
1245                 {
1246                     filter.Enabled = enabled;
1247
1248                     var itemRect = this.ListFilters.GetItemRectangle(idx);
1249                     this.ListFilters.Invalidate(itemRect);
1250                 }
1251             }
1252
1253             this.RuleEnableButtonMode = enabled ? EnableButtonMode.Disable : EnableButtonMode.Enable;
1254         }
1255
1256         private void ButtonRuleCopy_Click(object sender, EventArgs e)
1257         {
1258             if (ListTabs.SelectedIndex > -1 && ListFilters.SelectedItem != null)
1259             {
1260                 TabModel[] selectedTabs;
1261                 using (var dialog = new TabsDialog(_sts))
1262                 {
1263                     dialog.MultiSelect = true;
1264                     dialog.Text = Properties.Resources.ButtonRuleCopy_ClickText1;
1265
1266                     if (dialog.ShowDialog(this) == DialogResult.Cancel) return;
1267
1268                     selectedTabs = dialog.SelectedTabs;
1269                 }
1270
1271                 var currentTab = (FilterTabModel)this.SelectedTab;
1272                 var filters = new List<PostFilterRule>();
1273
1274                 foreach (int idx in ListFilters.SelectedIndices)
1275                 {
1276                     filters.Add(currentTab.FilterArray[idx].Clone());
1277                 }
1278                 foreach (var tb in selectedTabs.Cast<FilterTabModel>())
1279                 {
1280                     if (tb.TabName == currentTab.TabName) continue;
1281
1282                     foreach (var flt in filters)
1283                     {
1284                         if (!tb.FilterArray.Contains(flt))
1285                             tb.AddFilter(flt.Clone());
1286                     }
1287                 }
1288                 SetFilters(this.SelectedTab);
1289             }
1290         }
1291
1292         private void ButtonRuleMove_Click(object sender, EventArgs e)
1293         {
1294             if (ListTabs.SelectedIndex > -1 && ListFilters.SelectedItem != null)
1295             {
1296                 TabModel[] selectedTabs;
1297                 using (var dialog = new TabsDialog(_sts))
1298                 {
1299                     dialog.MultiSelect = true;
1300                     dialog.Text = Properties.Resources.ButtonRuleMove_ClickText1;
1301
1302                     if (dialog.ShowDialog(this) == DialogResult.Cancel) return;
1303
1304                     selectedTabs = dialog.SelectedTabs;
1305                 }
1306                 var currentTab = (FilterTabModel)this.SelectedTab;
1307                 var filters = new List<PostFilterRule>();
1308
1309                 foreach (int idx in ListFilters.SelectedIndices)
1310                 {
1311                     filters.Add(currentTab.FilterArray[idx].Clone());
1312                 }
1313                 if (selectedTabs.Length == 1 && selectedTabs[0].TabName == currentTab.TabName) return;
1314                 foreach (var tb in selectedTabs.Cast<FilterTabModel>())
1315                 {
1316                     if (tb.TabName == currentTab.TabName) continue;
1317
1318                     foreach (var flt in filters)
1319                     {
1320                         if (!tb.FilterArray.Contains(flt))
1321                             tb.AddFilter(flt.Clone());
1322                     }
1323                 }
1324                 for (var idx = ListFilters.Items.Count - 1; idx >= 0; idx--)
1325                 {
1326                     if (ListFilters.GetSelected(idx))
1327                     {
1328                         currentTab.RemoveFilter((PostFilterRule)ListFilters.Items[idx]);
1329                         ListFilters.Items.RemoveAt(idx);
1330                     }
1331                 }
1332                 SetFilters(this.SelectedTab);
1333             }
1334         }
1335
1336         private void FilterTextBox_KeyDown(object sender, KeyEventArgs e)
1337         {
1338             if (e.KeyCode == Keys.Space && e.Modifiers == (Keys.Shift | Keys.Control))
1339             {
1340                 var main = (TweenMain)this.Owner;
1341                 var tbox = (TextBox)sender;
1342                 if (tbox.SelectionStart > 0)
1343                 {
1344                     var endidx = tbox.SelectionStart - 1;
1345                     var startstr = "";
1346                     for (var i = tbox.SelectionStart - 1; i >= 0; i--)
1347                     {
1348                         var c = tbox.Text[i];
1349                         if (Char.IsLetterOrDigit(c) || c == '_')
1350                         {
1351                             continue;
1352                         }
1353                         if (c == '@')
1354                         {
1355                             startstr = tbox.Text.Substring(i + 1, endidx - i);
1356                             main.ShowSuplDialog(tbox, main.AtIdSupl, startstr.Length + 1, startstr);
1357                         }
1358                         else if (c == '#')
1359                         {
1360                             startstr = tbox.Text.Substring(i + 1, endidx - i);
1361                             main.ShowSuplDialog(tbox, main.HashSupl, startstr.Length + 1, startstr);
1362                         }
1363                         else
1364                         {
1365                             break;
1366                         }
1367                     }
1368                     e.Handled = true;
1369                 }
1370             }
1371         }
1372
1373         private void FilterTextBox_KeyPress(object sender, KeyPressEventArgs e)
1374         {
1375             var main = (TweenMain)this.Owner;
1376             var tbox = (TextBox)sender;
1377             if (e.KeyChar == '@')
1378             {
1379                 //if (!SettingDialog.UseAtIdSupplement) return;
1380                 //@マーク
1381                 main.ShowSuplDialog(tbox, main.AtIdSupl);
1382                 e.Handled = true;
1383             }
1384             else if (e.KeyChar == '#')
1385             {
1386                 //if (!SettingDialog.UseHashSupplement) return;
1387                 main.ShowSuplDialog(tbox, main.HashSupl);
1388                 e.Handled = true;
1389             }
1390         }
1391
1392         private void ListFilters_DrawItem(object sender, DrawItemEventArgs e)
1393         {
1394             e.DrawBackground();
1395
1396             if (e.Index != -1)
1397             {
1398                 var filter = (PostFilterRule)this.ListFilters.Items[e.Index];
1399                 var isSelected = e.State.HasFlag(DrawItemState.Selected);
1400
1401                 Brush textBrush;
1402                 if (isSelected)
1403                     textBrush = SystemBrushes.HighlightText;
1404                 else if (filter.Enabled)
1405                     textBrush = SystemBrushes.WindowText;
1406                 else
1407                     textBrush = SystemBrushes.GrayText;
1408
1409                 e.Graphics.DrawString(filter.ToString(), e.Font, textBrush, e.Bounds);
1410             }
1411
1412             e.DrawFocusRectangle();
1413         }
1414
1415         private void ListFilters_KeyDown(object sender, KeyEventArgs e)
1416         {
1417             if (e.Control && e.KeyCode == Keys.A)
1418             {
1419                 var itemCount = this.ListFilters.Items.Count;
1420                 if (itemCount == 0) return;
1421
1422                 using (ControlTransaction.Update(this.ListFilters))
1423                 {
1424                     if (itemCount > 1)
1425                     {
1426                         try
1427                         {
1428                             _multiSelState |= MultiSelectionState.SelectAll;
1429
1430                             for (var i = 1; i < itemCount; i++)
1431                             {
1432                                 this.ListFilters.SetSelected(i, true);
1433                             }
1434                         }
1435                         finally
1436                         {
1437                             _multiSelState &= ~MultiSelectionState.SelectAll;
1438                         }
1439                     }
1440
1441                     this.ListFilters.SetSelected(0, true);
1442                 }
1443             }
1444         }
1445
1446         protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
1447         {
1448             base.ScaleControl(factor, specified);
1449             this.ListFilters.ItemHeight = this.ListFilters.Font.Height;
1450         }
1451     }
1452 }