OSDN Git Service

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