OSDN Git Service

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