OSDN Git Service

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