OSDN Git Service

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