OSDN Git Service

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