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.
10 // This file is part of OpenTween.
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)
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
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.
30 using System.Collections.Generic;
31 using System.Collections.Specialized;
32 using System.ComponentModel;
37 using System.Linq.Expressions;
39 using System.Text.RegularExpressions;
40 using System.Windows.Forms;
41 using OpenTween.Models;
45 public partial class FilterDialog : OTBaseForm
47 private EDITMODE mode;
48 private bool directAdd;
49 private MultiSelectionState multiSelState = MultiSelectionState.None;
50 private readonly TabInformations sts;
52 private List<TabModel> tabs = new();
53 private int selectedTabIndex = -1;
55 private readonly List<string> idlist = new();
64 private enum EnableButtonMode
72 private enum MultiSelectionState
79 private EnableButtonMode RuleEnableButtonMode
81 get => this.ruleEnableButtonMode;
84 this.ruleEnableButtonMode = value;
86 this.buttonRuleToggleEnabled.Text = value == FilterDialog.EnableButtonMode.Enable
87 ? Properties.Resources.EnableButtonCaption
88 : Properties.Resources.DisableButtonCaption;
89 this.buttonRuleToggleEnabled.Enabled = value != EnableButtonMode.NotSelected;
93 private EnableButtonMode ruleEnableButtonMode = FilterDialog.EnableButtonMode.NotSelected;
95 public TabModel? SelectedTab
96 => this.selectedTabIndex != -1 ? this.tabs[this.selectedTabIndex] : null;
100 this.InitializeComponent();
102 this.sts = TabInformations.GetInstance();
103 this.RefreshListTabs();
106 private void RefreshListTabs()
108 this.tabs = this.sts.Tabs.Append(this.sts.MuteTab).ToList();
110 using (ControlTransaction.Update(this.ListTabs))
112 var selectedTab = this.ListTabs.SelectedItem;
113 this.ListTabs.Items.Clear();
114 this.ListTabs.Items.AddRange(this.tabs.ToArray());
115 this.ListTabs.SelectedIndex = this.tabs.FindIndex(x => x == selectedTab);
119 private void SetFilters(TabModel tab)
121 if (this.ListTabs.Items.Count == 0) return;
123 this.ListFilters.Items.Clear();
125 if (tab is FilterTabModel filterTab)
126 this.ListFilters.Items.AddRange(filterTab.GetFilters());
128 if (this.ListFilters.Items.Count > 0)
129 this.ListFilters.SelectedIndex = 0;
133 if (tab.IsDefaultTabType)
135 this.CheckProtected.Checked = true;
136 this.CheckProtected.Enabled = false;
140 this.CheckProtected.Checked = tab.Protected;
141 this.CheckProtected.Enabled = true;
144 this.CheckManageRead.CheckedChanged -= this.CheckManageRead_CheckedChanged;
145 this.CheckManageRead.Checked = tab.UnreadManage;
146 this.CheckManageRead.CheckedChanged += this.CheckManageRead_CheckedChanged;
148 this.CheckNotifyNew.CheckedChanged -= this.CheckNotifyNew_CheckedChanged;
149 this.CheckNotifyNew.Checked = tab.Notify;
150 this.CheckNotifyNew.CheckedChanged += this.CheckNotifyNew_CheckedChanged;
152 var idx = this.ComboSound.Items.IndexOf(tab.SoundFile);
153 if (idx == -1) idx = 0;
154 this.ComboSound.SelectedIndex = idx;
156 if (this.directAdd) return;
158 if (tab.TabType == MyCommon.TabUsageType.Mute)
160 this.ButtonRenameTab.Enabled = false;
161 this.CheckManageRead.Enabled = false;
162 this.CheckNotifyNew.Enabled = false;
163 this.ComboSound.Enabled = false;
165 this.GroupBox1.Visible = false;
166 this.labelMuteTab.Visible = true;
170 this.ButtonRenameTab.Enabled = true;
171 this.CheckManageRead.Enabled = true;
172 this.CheckNotifyNew.Enabled = true;
173 this.ComboSound.Enabled = true;
175 this.GroupBox1.Visible = true;
176 this.labelMuteTab.Visible = false;
179 this.ListTabs.Enabled = true;
180 this.GroupTab.Enabled = true;
181 this.ListFilters.Enabled = true;
182 this.EditFilterGroup.Enabled = false;
184 if (tab.IsDistributableTabType)
186 this.ButtonNew.Enabled = true;
187 if (this.ListFilters.SelectedIndex > -1)
189 this.ButtonEdit.Enabled = true;
190 this.ButtonDelete.Enabled = true;
191 this.ButtonRuleUp.Enabled = true;
192 this.ButtonRuleDown.Enabled = true;
193 this.ButtonRuleCopy.Enabled = true;
194 this.ButtonRuleMove.Enabled = true;
195 this.buttonRuleToggleEnabled.Enabled = true;
199 this.ButtonEdit.Enabled = false;
200 this.ButtonDelete.Enabled = false;
201 this.ButtonRuleUp.Enabled = false;
202 this.ButtonRuleDown.Enabled = false;
203 this.ButtonRuleCopy.Enabled = false;
204 this.ButtonRuleMove.Enabled = false;
205 this.buttonRuleToggleEnabled.Enabled = false;
210 this.ButtonNew.Enabled = false;
211 this.ButtonEdit.Enabled = false;
212 this.ButtonDelete.Enabled = false;
213 this.ButtonRuleUp.Enabled = false;
214 this.ButtonRuleDown.Enabled = false;
215 this.ButtonRuleCopy.Enabled = false;
216 this.ButtonRuleMove.Enabled = false;
217 this.buttonRuleToggleEnabled.Enabled = false;
220 this.LabelTabType.Text = tab.TabType switch
222 MyCommon.TabUsageType.Home => Properties.Resources.TabUsageTypeName_Home,
223 MyCommon.TabUsageType.Mentions => Properties.Resources.TabUsageTypeName_Mentions,
224 MyCommon.TabUsageType.DirectMessage => Properties.Resources.TabUsageTypeName_DirectMessage,
225 MyCommon.TabUsageType.Favorites => Properties.Resources.TabUsageTypeName_Favorites,
226 MyCommon.TabUsageType.UserDefined => Properties.Resources.TabUsageTypeName_UserDefined,
227 MyCommon.TabUsageType.PublicSearch => Properties.Resources.TabUsageTypeName_PublicSearch,
228 MyCommon.TabUsageType.Lists => Properties.Resources.TabUsageTypeName_Lists,
229 MyCommon.TabUsageType.Related => Properties.Resources.TabUsageTypeName_Related,
230 MyCommon.TabUsageType.UserTimeline => Properties.Resources.TabUsageTypeName_UserTimeline,
231 MyCommon.TabUsageType.Mute => "Mute",
232 MyCommon.TabUsageType.SearchResults => "SearchResults",
236 if (tab.IsDefaultTabType || tab.Protected)
238 this.ButtonDeleteTab.Enabled = false;
242 this.ButtonDeleteTab.Enabled = true;
244 this.ButtonClose.Enabled = true;
247 public void SetCurrent(string tabName)
249 var index = this.tabs.FindIndex(x => x.TabName == tabName);
251 throw new ArgumentException($"Unknown tab: {tabName}", nameof(tabName));
253 this.selectedTabIndex = index;
256 public void AddNewFilter(string id, string msg)
259 this.ButtonNew.Enabled = false;
260 this.ButtonEdit.Enabled = false;
261 this.ButtonRuleUp.Enabled = false;
262 this.ButtonRuleDown.Enabled = false;
263 this.ButtonRuleCopy.Enabled = false;
264 this.ButtonRuleMove.Enabled = false;
265 this.buttonRuleToggleEnabled.Enabled = false;
266 this.ButtonDelete.Enabled = false;
267 this.ButtonClose.Enabled = false;
268 this.EditFilterGroup.Enabled = true;
269 this.ListTabs.Enabled = false;
270 this.GroupTab.Enabled = false;
271 this.ListFilters.Enabled = false;
273 this.RadioAND.Checked = true;
274 this.RadioPLUS.Checked = false;
276 this.UID.SelectAll();
277 this.MSG1.Text = msg;
278 this.MSG1.SelectAll();
279 this.MSG2.Text = id + msg;
280 this.MSG2.SelectAll();
281 this.TextSource.Text = "";
282 this.UID.Enabled = true;
283 this.MSG1.Enabled = true;
284 this.MSG2.Enabled = false;
285 this.CheckRegex.Checked = false;
286 this.CheckURL.Checked = false;
287 this.CheckCaseSensitive.Checked = false;
288 this.CheckRetweet.Checked = false;
289 this.CheckLambda.Checked = false;
291 this.RadioExAnd.Checked = true;
292 this.RadioExPLUS.Checked = false;
293 this.ExUID.Text = "";
294 this.ExUID.SelectAll();
295 this.ExMSG1.Text = "";
296 this.ExMSG1.SelectAll();
297 this.ExMSG2.Text = "";
298 this.ExMSG2.SelectAll();
299 this.TextExSource.Text = "";
300 this.ExUID.Enabled = true;
301 this.ExMSG1.Enabled = true;
302 this.ExMSG2.Enabled = false;
303 this.CheckExRegex.Checked = false;
304 this.CheckExURL.Checked = false;
305 this.CheckExCaseSensitive.Checked = false;
306 this.CheckExRetweet.Checked = false;
307 this.CheckExLambDa.Checked = false;
309 this.OptCopy.Checked = true;
310 this.CheckMark.Checked = true;
312 this.mode = EDITMODE.AddNew;
313 this.directAdd = true;
316 private void ButtonNew_Click(object sender, EventArgs e)
318 this.ButtonNew.Enabled = false;
319 this.ButtonEdit.Enabled = false;
320 this.ButtonClose.Enabled = false;
321 this.ButtonRuleUp.Enabled = false;
322 this.ButtonRuleDown.Enabled = false;
323 this.ButtonRuleCopy.Enabled = false;
324 this.ButtonRuleMove.Enabled = false;
325 this.buttonRuleToggleEnabled.Enabled = false;
326 this.ButtonDelete.Enabled = false;
327 this.ButtonClose.Enabled = false;
328 this.EditFilterGroup.Enabled = true;
329 this.ListTabs.Enabled = false;
330 this.GroupTab.Enabled = false;
331 this.ListFilters.Enabled = false;
333 this.RadioAND.Checked = true;
334 this.RadioPLUS.Checked = false;
338 this.TextSource.Text = "";
339 this.UID.Enabled = true;
340 this.MSG1.Enabled = true;
341 this.MSG2.Enabled = false;
342 this.CheckRegex.Checked = false;
343 this.CheckURL.Checked = false;
344 this.CheckCaseSensitive.Checked = false;
345 this.CheckRetweet.Checked = false;
346 this.CheckLambda.Checked = false;
348 this.RadioExAnd.Checked = true;
349 this.RadioExPLUS.Checked = false;
350 this.ExUID.Text = "";
351 this.ExMSG1.Text = "";
352 this.ExMSG2.Text = "";
353 this.TextExSource.Text = "";
354 this.ExUID.Enabled = true;
355 this.ExMSG1.Enabled = true;
356 this.ExMSG2.Enabled = false;
357 this.CheckExRegex.Checked = false;
358 this.CheckExURL.Checked = false;
359 this.CheckExCaseSensitive.Checked = false;
360 this.CheckExRetweet.Checked = false;
361 this.CheckExLambDa.Checked = false;
363 this.OptCopy.Checked = true;
364 this.CheckMark.Checked = true;
366 this.mode = EDITMODE.AddNew;
369 private void ButtonEdit_Click(object sender, EventArgs e)
371 if (this.ListFilters.SelectedIndex == -1) return;
375 var idx = this.ListFilters.SelectedIndex;
376 this.ListFilters.SelectedIndex = -1;
377 this.ListFilters.SelectedIndex = idx;
378 this.ListFilters.Enabled = false;
380 this.ButtonNew.Enabled = false;
381 this.ButtonEdit.Enabled = false;
382 this.ButtonDelete.Enabled = false;
383 this.ButtonClose.Enabled = false;
384 this.ButtonRuleUp.Enabled = false;
385 this.ButtonRuleDown.Enabled = false;
386 this.ButtonRuleCopy.Enabled = false;
387 this.ButtonRuleMove.Enabled = false;
388 this.buttonRuleToggleEnabled.Enabled = false;
389 this.EditFilterGroup.Enabled = true;
390 this.ListTabs.Enabled = false;
391 this.GroupTab.Enabled = false;
393 this.mode = EDITMODE.Edit;
396 private void ButtonDelete_Click(object sender, EventArgs e)
398 var selectedCount = this.ListFilters.SelectedIndices.Count;
399 if (selectedCount == 0) return;
403 if (selectedCount == 1)
405 tmp = string.Format(Properties.Resources.ButtonDelete_ClickText1, Environment.NewLine, this.ListFilters.SelectedItem);
409 tmp = string.Format(Properties.Resources.ButtonDelete_ClickText3, selectedCount);
412 var rslt = MessageBox.Show(tmp, Properties.Resources.ButtonDelete_ClickText2, MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
413 if (rslt == DialogResult.Cancel) return;
415 var indices = this.ListFilters.SelectedIndices.Cast<int>().Reverse().ToArray(); // 後ろの要素から削除
416 var tab = (FilterTabModel)this.SelectedTab!;
418 using (ControlTransaction.Update(this.ListFilters))
420 foreach (var idx in indices)
422 tab.RemoveFilter((PostFilterRule)this.ListFilters.Items[idx]);
423 this.ListFilters.Items.RemoveAt(idx);
428 private void ButtonCancel_Click(object sender, EventArgs e)
430 this.ListTabs.Enabled = true;
431 this.GroupTab.Enabled = true;
432 this.ListFilters.Enabled = true;
433 this.ListFilters.Focus();
434 if (this.ListFilters.SelectedIndex != -1)
438 this.EditFilterGroup.Enabled = false;
439 this.ButtonNew.Enabled = true;
440 if (this.ListFilters.SelectedIndex > -1)
442 this.ButtonEdit.Enabled = true;
443 this.ButtonDelete.Enabled = true;
444 this.ButtonRuleUp.Enabled = true;
445 this.ButtonRuleDown.Enabled = true;
446 this.ButtonRuleCopy.Enabled = true;
447 this.ButtonRuleMove.Enabled = true;
448 this.buttonRuleToggleEnabled.Enabled = true;
452 this.ButtonEdit.Enabled = false;
453 this.ButtonDelete.Enabled = false;
454 this.ButtonRuleUp.Enabled = false;
455 this.ButtonRuleDown.Enabled = false;
456 this.ButtonRuleCopy.Enabled = false;
457 this.ButtonRuleMove.Enabled = false;
458 this.buttonRuleToggleEnabled.Enabled = false;
460 this.ButtonClose.Enabled = true;
467 private void ShowDetail()
469 if (this.directAdd) return;
471 if (this.ListFilters.SelectedIndex > -1)
473 var fc = (PostFilterRule)this.ListFilters.SelectedItem;
476 this.RadioAND.Checked = true;
477 this.RadioPLUS.Checked = false;
478 this.UID.Enabled = true;
479 this.MSG1.Enabled = true;
480 this.MSG2.Enabled = false;
481 this.UID.Text = fc.FilterName;
482 this.UID.SelectAll();
483 this.MSG1.Text = string.Join(" ", fc.FilterBody);
484 this.MSG1.SelectAll();
489 this.RadioPLUS.Checked = true;
490 this.RadioAND.Checked = false;
491 this.UID.Enabled = false;
492 this.MSG1.Enabled = false;
493 this.MSG2.Enabled = true;
496 this.MSG2.Text = string.Join(" ", fc.FilterBody);
497 this.MSG2.SelectAll();
499 this.TextSource.Text = fc.FilterSource;
500 this.CheckRegex.Checked = fc.UseRegex;
501 this.CheckURL.Checked = fc.FilterByUrl;
502 this.CheckCaseSensitive.Checked = fc.CaseSensitive;
503 this.CheckRetweet.Checked = fc.FilterRt;
504 this.CheckLambda.Checked = fc.UseLambda;
506 if (fc.ExUseNameField)
508 this.RadioExAnd.Checked = true;
509 this.RadioExPLUS.Checked = false;
510 this.ExUID.Enabled = true;
511 this.ExMSG1.Enabled = true;
512 this.ExMSG2.Enabled = false;
513 this.ExUID.Text = fc.ExFilterName;
514 this.ExUID.SelectAll();
515 this.ExMSG1.Text = string.Join(" ", fc.ExFilterBody);
516 this.ExMSG1.SelectAll();
517 this.ExMSG2.Text = "";
521 this.RadioExPLUS.Checked = true;
522 this.RadioExAnd.Checked = false;
523 this.ExUID.Enabled = false;
524 this.ExMSG1.Enabled = false;
525 this.ExMSG2.Enabled = true;
526 this.ExUID.Text = "";
527 this.ExMSG1.Text = "";
528 this.ExMSG2.Text = string.Join(" ", fc.ExFilterBody);
529 this.ExMSG2.SelectAll();
531 this.TextExSource.Text = fc.ExFilterSource;
532 this.CheckExRegex.Checked = fc.ExUseRegex;
533 this.CheckExURL.Checked = fc.ExFilterByUrl;
534 this.CheckExCaseSensitive.Checked = fc.ExCaseSensitive;
535 this.CheckExRetweet.Checked = fc.ExFilterRt;
536 this.CheckExLambDa.Checked = fc.ExUseLambda;
540 this.OptMove.Checked = true;
544 this.OptCopy.Checked = true;
546 this.CheckMark.Checked = fc.MarkMatches;
548 this.ButtonEdit.Enabled = true;
549 this.ButtonDelete.Enabled = true;
550 this.ButtonRuleUp.Enabled = true;
551 this.ButtonRuleDown.Enabled = true;
552 this.ButtonRuleCopy.Enabled = true;
553 this.ButtonRuleMove.Enabled = true;
554 this.buttonRuleToggleEnabled.Enabled = true;
558 this.RadioAND.Checked = true;
559 this.RadioPLUS.Checked = false;
560 this.UID.Enabled = true;
561 this.MSG1.Enabled = true;
562 this.MSG2.Enabled = false;
566 this.TextSource.Text = "";
567 this.CheckRegex.Checked = false;
568 this.CheckURL.Checked = false;
569 this.CheckCaseSensitive.Checked = false;
570 this.CheckRetweet.Checked = false;
571 this.CheckLambda.Checked = false;
573 this.RadioExAnd.Checked = true;
574 this.RadioExPLUS.Checked = false;
575 this.ExUID.Enabled = true;
576 this.ExMSG1.Enabled = true;
577 this.ExMSG2.Enabled = false;
578 this.ExUID.Text = "";
579 this.ExMSG1.Text = "";
580 this.ExMSG2.Text = "";
581 this.TextExSource.Text = "";
582 this.CheckExRegex.Checked = false;
583 this.CheckExURL.Checked = false;
584 this.CheckExCaseSensitive.Checked = false;
585 this.CheckExRetweet.Checked = false;
586 this.CheckExLambDa.Checked = false;
588 this.OptCopy.Checked = true;
589 this.CheckMark.Checked = true;
591 this.ButtonEdit.Enabled = false;
592 this.ButtonDelete.Enabled = false;
593 this.ButtonRuleUp.Enabled = false;
594 this.ButtonRuleDown.Enabled = false;
595 this.ButtonRuleCopy.Enabled = false;
596 this.ButtonRuleMove.Enabled = false;
597 this.buttonRuleToggleEnabled.Enabled = false;
601 private void RadioAND_CheckedChanged(object sender, EventArgs e)
603 var flg = this.RadioAND.Checked;
604 this.UID.Enabled = flg;
605 this.MSG1.Enabled = flg;
606 this.MSG2.Enabled = !flg;
609 private void ButtonOK_Click(object sender, EventArgs e)
612 if (!this.CheckMatchRule(out var isBlankMatch) || !this.CheckExcludeRule(out var isBlankExclude))
616 if (isBlankMatch && isBlankExclude)
618 MessageBox.Show(Properties.Resources.ButtonOK_ClickText1, Properties.Resources.ButtonOK_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
622 var tab = (FilterTabModel)this.SelectedTab!;
623 var i = this.ListFilters.SelectedIndex;
626 if (this.mode == EDITMODE.AddNew)
627 ft = new PostFilterRule();
629 ft = (PostFilterRule)this.ListFilters.SelectedItem;
631 if (tab.TabType != MyCommon.TabUsageType.Mute)
633 ft.MoveMatches = this.OptMove.Checked;
634 ft.MarkMatches = this.CheckMark.Checked;
638 ft.MoveMatches = true;
639 ft.MarkMatches = false;
643 if (this.RadioAND.Checked)
645 ft.FilterName = this.UID.Text;
646 var owner = (TweenMain)this.Owner;
647 var cnt = owner.AtIdSupl.ItemCount;
648 owner.AtIdSupl.AddItem("@" + ft.FilterName);
649 if (cnt != owner.AtIdSupl.ItemCount)
651 owner.MarkSettingAtIdModified();
653 ft.UseNameField = true;
654 bdy = this.MSG1.Text;
659 ft.UseNameField = false;
660 bdy = this.MSG2.Text;
662 ft.FilterSource = this.TextSource.Text;
664 if (this.CheckRegex.Checked || this.CheckLambda.Checked)
666 ft.FilterBody = new[] { bdy };
670 ft.FilterBody = bdy.Split(' ', ' ')
671 .Where(x => !MyCommon.IsNullOrEmpty(x))
675 ft.UseRegex = this.CheckRegex.Checked;
676 ft.FilterByUrl = this.CheckURL.Checked;
677 ft.CaseSensitive = this.CheckCaseSensitive.Checked;
678 ft.FilterRt = this.CheckRetweet.Checked;
679 ft.UseLambda = this.CheckLambda.Checked;
682 if (this.RadioExAnd.Checked)
684 ft.ExFilterName = this.ExUID.Text;
685 ft.ExUseNameField = true;
686 bdy = this.ExMSG1.Text;
690 ft.ExFilterName = "";
691 ft.ExUseNameField = false;
692 bdy = this.ExMSG2.Text;
694 ft.ExFilterSource = this.TextExSource.Text;
696 if (this.CheckExRegex.Checked || this.CheckExLambDa.Checked)
698 ft.ExFilterBody = new[] { bdy };
702 ft.ExFilterBody = bdy.Split(' ', ' ')
703 .Where(x => !MyCommon.IsNullOrEmpty(x))
707 ft.ExUseRegex = this.CheckExRegex.Checked;
708 ft.ExFilterByUrl = this.CheckExURL.Checked;
709 ft.ExCaseSensitive = this.CheckExCaseSensitive.Checked;
710 ft.ExFilterRt = this.CheckExRetweet.Checked;
711 ft.ExUseLambda = this.CheckExLambDa.Checked;
713 if (this.mode == EDITMODE.AddNew)
715 if (!tab.AddFilter(ft))
716 MessageBox.Show(Properties.Resources.ButtonOK_ClickText4, Properties.Resources.ButtonOK_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Error);
719 this.SetFilters(tab);
720 this.ListFilters.SelectedIndex = -1;
721 if (this.mode == EDITMODE.AddNew)
723 this.ListFilters.SelectedIndex = this.ListFilters.Items.Count - 1;
727 this.ListFilters.SelectedIndex = i;
729 this.mode = EDITMODE.None;
737 private bool IsValidLambdaExp(string text)
738 => false; // TODO DynamicQuery相当のGPLv3互換なライブラリで置換する
740 private bool IsValidRegexp(string text)
748 MessageBox.Show(Properties.Resources.ButtonOK_ClickText3 + ex.Message, Properties.Resources.ButtonOK_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
754 private bool CheckMatchRule(out bool isBlank)
757 if (this.RadioAND.Checked)
759 if (MyCommon.IsNullOrEmpty(this.UID.Text) && MyCommon.IsNullOrEmpty(this.MSG1.Text) && MyCommon.IsNullOrEmpty(this.TextSource.Text) && this.CheckRetweet.Checked == false)
764 if (this.CheckLambda.Checked)
766 if (!this.IsValidLambdaExp(this.UID.Text))
770 if (!this.IsValidLambdaExp(this.MSG1.Text))
775 else if (this.CheckRegex.Checked)
777 if (!this.IsValidRegexp(this.UID.Text))
781 if (!this.IsValidRegexp(this.MSG1.Text))
789 if (MyCommon.IsNullOrEmpty(this.MSG2.Text) && MyCommon.IsNullOrEmpty(this.TextSource.Text) && this.CheckRetweet.Checked == false)
794 if (this.CheckLambda.Checked && !this.IsValidLambdaExp(this.MSG2.Text))
798 else if (this.CheckRegex.Checked && !this.IsValidRegexp(this.MSG2.Text))
804 if (this.CheckRegex.Checked && !this.IsValidRegexp(this.TextSource.Text))
811 private bool CheckExcludeRule(out bool isBlank)
814 if (this.RadioExAnd.Checked)
816 if (MyCommon.IsNullOrEmpty(this.ExUID.Text) && MyCommon.IsNullOrEmpty(this.ExMSG1.Text) && MyCommon.IsNullOrEmpty(this.TextExSource.Text) && this.CheckExRetweet.Checked == false)
821 if (this.CheckExLambDa.Checked)
823 if (!this.IsValidLambdaExp(this.ExUID.Text))
827 if (!this.IsValidLambdaExp(this.ExMSG1.Text))
832 else if (this.CheckExRegex.Checked)
834 if (!this.IsValidRegexp(this.ExUID.Text))
838 if (!this.IsValidRegexp(this.ExMSG1.Text))
846 if (MyCommon.IsNullOrEmpty(this.ExMSG2.Text) && MyCommon.IsNullOrEmpty(this.TextExSource.Text) && this.CheckExRetweet.Checked == false)
851 if (this.CheckExLambDa.Checked && !this.IsValidLambdaExp(this.ExMSG2.Text))
855 else if (this.CheckExRegex.Checked && !this.IsValidRegexp(this.ExMSG2.Text))
861 if (this.CheckExRegex.Checked && !this.IsValidRegexp(this.TextExSource.Text))
869 private void ListFilters_SelectedIndexChanged(object sender, EventArgs e)
871 if (this.multiSelState != MultiSelectionState.None) // 複数選択処理中は無視する
876 var selectedCount = this.ListFilters.SelectedIndices.Count;
877 if (selectedCount == 0)
879 this.RuleEnableButtonMode = EnableButtonMode.NotSelected;
883 if (selectedCount == 1 ||
884 this.RuleEnableButtonMode == EnableButtonMode.NotSelected)
886 var topItem = (PostFilterRule)this.ListFilters.SelectedItem;
887 this.RuleEnableButtonMode = topItem.Enabled ? EnableButtonMode.Disable : EnableButtonMode.Enable;
892 private void ButtonClose_Click(object sender, EventArgs e)
895 private void FilterDialog_FormClosed(object sender, FormClosedEventArgs e)
896 => this.directAdd = false;
898 private void FilterDialog_KeyDown(object sender, KeyEventArgs e)
900 if (e.KeyCode == Keys.Escape)
902 if (this.EditFilterGroup.Enabled)
903 this.ButtonCancel_Click(this.ButtonCancel, EventArgs.Empty);
905 this.ButtonClose_Click(this.ButtonClose, EventArgs.Empty);
909 private void ListFilters_DoubleClick(object sender, EventArgs e)
911 var idx = this.ListFilters.SelectedIndex;
912 if (idx == -1) return;
914 var midx = this.ListFilters.IndexFromPoint(this.ListFilters.PointToClient(Control.MousePosition));
915 if (midx == ListBox.NoMatches || idx != midx) return;
917 this.ButtonEdit_Click(sender, e);
920 private void FilterDialog_Shown(object sender, EventArgs e)
922 this.ListTabs.DisplayMember = nameof(TabModel.TabName);
924 this.ComboSound.Items.Clear();
925 this.ComboSound.Items.Add("");
926 var oDir = new DirectoryInfo(Application.StartupPath + Path.DirectorySeparatorChar);
927 if (Directory.Exists(Path.Combine(Application.StartupPath, "Sounds")))
929 oDir = oDir.GetDirectories("Sounds")[0];
931 foreach (var oFile in oDir.GetFiles("*.wav"))
933 this.ComboSound.Items.Add(oFile.Name);
937 foreach (var tmp in ((TweenMain)this.Owner).AtIdSupl.GetItemList())
939 this.idlist.Add(tmp.Remove(0, 1)); // @文字削除
941 this.UID.AutoCompleteCustomSource.Clear();
942 this.UID.AutoCompleteCustomSource.AddRange(this.idlist.ToArray());
944 this.ExUID.AutoCompleteCustomSource.Clear();
945 this.ExUID.AutoCompleteCustomSource.AddRange(this.idlist.ToArray());
948 this.ListTabs.SelectedIndex = this.selectedTabIndex;
951 private void ListTabs_SelectedIndexChanged(object sender, EventArgs e)
953 this.selectedTabIndex = this.ListTabs.SelectedIndex;
955 var selectedTab = this.SelectedTab;
956 if (selectedTab != null)
957 this.SetFilters(selectedTab);
959 this.ListFilters.Items.Clear();
962 private async void ButtonAddTab_Click(object sender, EventArgs e)
964 string? tabName = null;
965 MyCommon.TabUsageType tabType;
966 using (var inputName = new InputTabName())
968 inputName.TabName = this.sts.MakeTabName("MyTab");
969 inputName.IsShowUsage = true;
970 inputName.ShowDialog();
971 if (inputName.DialogResult == DialogResult.Cancel) return;
972 tabName = inputName.TabName;
973 tabType = inputName.Usage;
975 if (!MyCommon.IsNullOrEmpty(tabName))
978 ListElement? list = null;
979 if (tabType == MyCommon.TabUsageType.Lists)
983 using var dialog = new WaitingDialog(Properties.Resources.ListsGetting);
984 var cancellationToken = dialog.EnableCancellation();
986 var task = ((TweenMain)this.Owner).TwitterInstance.GetListsApi();
987 await dialog.WaitForAsync(this, task);
989 cancellationToken.ThrowIfCancellationRequested();
991 catch (OperationCanceledException)
995 catch (WebApiException ex)
997 MessageBox.Show("Failed to get lists. (" + ex.Message + ")");
1000 using var listAvail = new ListAvailable();
1002 if (listAvail.ShowDialog(this) == DialogResult.Cancel)
1004 if (listAvail.SelectedList == null)
1006 list = listAvail.SelectedList;
1012 case MyCommon.TabUsageType.UserDefined:
1013 tab = new FilterTabModel(tabName);
1015 case MyCommon.TabUsageType.PublicSearch:
1016 tab = new PublicSearchTabModel(tabName);
1018 case MyCommon.TabUsageType.Lists:
1019 tab = new ListTimelineTabModel(tabName, list!);
1025 if (!this.sts.AddTab(tab) || !((TweenMain)this.Owner).AddNewTab(tab, startup: false))
1027 var tmp = string.Format(Properties.Resources.AddTabMenuItem_ClickText1, tabName);
1028 MessageBox.Show(tmp, Properties.Resources.AddTabMenuItem_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
1034 this.RefreshListTabs();
1039 private void ButtonDeleteTab_Click(object sender, EventArgs e)
1041 var selectedTab = this.SelectedTab;
1042 if (selectedTab != null)
1044 var tb = selectedTab.TabName;
1045 var idx = this.ListTabs.SelectedIndex;
1046 if (((TweenMain)this.Owner).RemoveSpecifiedTab(tb, true))
1048 this.RefreshListTabs();
1050 if (idx < 0) idx = 0;
1051 this.ListTabs.SelectedIndex = idx;
1056 private void ButtonRenameTab_Click(object sender, EventArgs e)
1058 var selectedTab = this.SelectedTab;
1059 if (selectedTab != null)
1061 var origTabName = selectedTab.TabName;
1062 if (((TweenMain)this.Owner).TabRename(origTabName, out _))
1063 this.RefreshListTabs();
1067 private void CheckManageRead_CheckedChanged(object sender, EventArgs e)
1069 var selectedTab = this.SelectedTab;
1070 if (selectedTab != null)
1072 ((TweenMain)this.Owner).ChangeTabUnreadManage(
1073 selectedTab.TabName,
1074 this.CheckManageRead.Checked);
1078 private void ButtonUp_Click(object sender, EventArgs e)
1080 var selectedIndex = this.ListTabs.SelectedIndex;
1082 if (selectedIndex == -1 || selectedIndex == 0)
1085 var selectedTab = this.tabs[selectedIndex];
1086 var selectedTabName = selectedTab.TabName;
1088 var targetTab = this.tabs[selectedIndex - 1];
1089 var targetTabName = targetTab.TabName;
1092 if (selectedTab.TabType == MyCommon.TabUsageType.Mute || targetTab.TabType == MyCommon.TabUsageType.Mute)
1095 var tweenMain = (TweenMain)this.Owner;
1096 tweenMain.ReOrderTab(selectedTabName, targetTabName, true);
1098 this.RefreshListTabs();
1101 private void ButtonDown_Click(object sender, EventArgs e)
1103 var selectedIndex = this.ListTabs.SelectedIndex;
1105 if (selectedIndex == -1 || selectedIndex == this.ListTabs.Items.Count - 1)
1108 var selectedTab = this.tabs[selectedIndex];
1109 var selectedTabName = selectedTab.TabName;
1111 var targetTab = this.tabs[selectedIndex + 1];
1112 var targetTabName = targetTab.TabName;
1115 if (selectedTab.TabType == MyCommon.TabUsageType.Mute || targetTab.TabType == MyCommon.TabUsageType.Mute)
1118 var tweenMain = (TweenMain)this.Owner;
1119 tweenMain.ReOrderTab(selectedTabName, targetTabName, false);
1121 this.RefreshListTabs();
1124 private void CheckLocked_CheckedChanged(object sender, EventArgs e)
1126 var selectedTab = this.SelectedTab;
1127 if (selectedTab != null)
1129 selectedTab.Protected = this.CheckProtected.Checked;
1130 this.ButtonDeleteTab.Enabled = !this.CheckProtected.Checked;
1134 private void CheckNotifyNew_CheckedChanged(object sender, EventArgs e)
1136 var selectedTab = this.SelectedTab;
1137 if (selectedTab != null)
1139 selectedTab.Notify = this.CheckNotifyNew.Checked;
1143 private void ComboSound_SelectedIndexChanged(object sender, EventArgs e)
1145 var selectedTab = this.SelectedTab;
1146 if (selectedTab != null)
1149 if (this.ComboSound.SelectedIndex > -1) filename = this.ComboSound.SelectedItem.ToString();
1150 selectedTab.SoundFile = filename;
1154 private void RadioExAnd_CheckedChanged(object sender, EventArgs e)
1156 var flg = this.RadioExAnd.Checked;
1157 this.ExUID.Enabled = flg;
1158 this.ExMSG1.Enabled = flg;
1159 this.ExMSG2.Enabled = !flg;
1162 private void OptMove_CheckedChanged(object sender, EventArgs e)
1163 => this.CheckMark.Enabled = !this.OptMove.Checked;
1165 private void ButtonRuleUp_Click(object sender, EventArgs e)
1166 => this.MoveSelectedRules(up: true);
1168 private void ButtonRuleDown_Click(object sender, EventArgs e)
1169 => this.MoveSelectedRules(up: false);
1171 private void MoveSelectedRules(bool up)
1173 var selectedTab = this.SelectedTab;
1174 if (selectedTab == null || this.ListFilters.SelectedIndices.Count == 0)
1177 var indices = this.ListFilters.SelectedIndices.Cast<int>().ToArray();
1182 if (indices[0] <= 0) return;
1187 if (indices[indices.Length - 1] >= this.ListFilters.Items.Count - 1) return;
1189 Array.Reverse(indices); // 逆順にして、下にある要素から処理する
1192 var lastSelIdx = indices[0] + diff;
1193 var tab = (FilterTabModel)selectedTab;
1197 this.multiSelState |= MultiSelectionState.MoveSelected;
1199 using (ControlTransaction.Update(this.ListFilters))
1201 this.ListFilters.SelectedIndices.Clear();
1203 foreach (var idx in indices)
1205 var tidx = idx + diff;
1206 var target = (PostFilterRule)this.ListFilters.Items[tidx];
1208 // 移動先にある要素と位置を入れ替える
1209 this.ListFilters.Items.RemoveAt(tidx);
1210 this.ListFilters.Items.Insert(idx, target);
1212 // 移動方向の先頭要素以外なら選択する
1213 if (tidx != lastSelIdx)
1214 this.ListFilters.SelectedIndex = tidx;
1217 tab.FilterArray = this.ListFilters.Items.Cast<PostFilterRule>().ToArray();
1219 // 移動方向の先頭要素は最後に選択する
1221 this.ListFilters.SelectedIndex = lastSelIdx;
1226 this.multiSelState &= ~MultiSelectionState.MoveSelected;
1230 private void ButtonRuleToggleEnabled_Click(object sender, EventArgs e)
1232 if (this.RuleEnableButtonMode == EnableButtonMode.NotSelected)
1235 var enabled = this.RuleEnableButtonMode == EnableButtonMode.Enable;
1237 foreach (var idx in this.ListFilters.SelectedIndices.Cast<int>())
1239 var filter = (PostFilterRule)this.ListFilters.Items[idx];
1240 if (filter.Enabled != enabled)
1242 filter.Enabled = enabled;
1244 var itemRect = this.ListFilters.GetItemRectangle(idx);
1245 this.ListFilters.Invalidate(itemRect);
1249 this.RuleEnableButtonMode = enabled ? EnableButtonMode.Disable : EnableButtonMode.Enable;
1252 private void ButtonRuleCopy_Click(object sender, EventArgs e)
1254 var selectedTab = this.SelectedTab;
1255 if (selectedTab != null && this.ListFilters.SelectedItem != null)
1257 TabModel[] destinationTabs;
1258 using (var dialog = new TabsDialog(this.sts))
1260 dialog.MultiSelect = true;
1261 dialog.Text = Properties.Resources.ButtonRuleCopy_ClickText1;
1263 if (dialog.ShowDialog(this) == DialogResult.Cancel) return;
1265 destinationTabs = dialog.SelectedTabs;
1268 var currentTab = (FilterTabModel)selectedTab;
1269 var filters = new List<PostFilterRule>();
1271 foreach (int idx in this.ListFilters.SelectedIndices)
1273 filters.Add(currentTab.FilterArray[idx].Clone());
1275 foreach (var tb in destinationTabs.Cast<FilterTabModel>())
1277 if (tb.TabName == currentTab.TabName) continue;
1279 foreach (var flt in filters)
1281 if (!tb.FilterArray.Contains(flt))
1282 tb.AddFilter(flt.Clone());
1285 this.SetFilters(selectedTab);
1289 private void ButtonRuleMove_Click(object sender, EventArgs e)
1291 var selectedTab = this.SelectedTab;
1292 if (selectedTab != null && this.ListFilters.SelectedItem != null)
1294 TabModel[] destinationTabs;
1295 using (var dialog = new TabsDialog(this.sts))
1297 dialog.MultiSelect = true;
1298 dialog.Text = Properties.Resources.ButtonRuleMove_ClickText1;
1300 if (dialog.ShowDialog(this) == DialogResult.Cancel) return;
1302 destinationTabs = dialog.SelectedTabs;
1304 var currentTab = (FilterTabModel)selectedTab;
1305 var filters = new List<PostFilterRule>();
1307 foreach (int idx in this.ListFilters.SelectedIndices)
1309 filters.Add(currentTab.FilterArray[idx].Clone());
1311 if (destinationTabs.Length == 1 && destinationTabs[0].TabName == currentTab.TabName) return;
1312 foreach (var tb in destinationTabs.Cast<FilterTabModel>())
1314 if (tb.TabName == currentTab.TabName) continue;
1316 foreach (var flt in filters)
1318 if (!tb.FilterArray.Contains(flt))
1319 tb.AddFilter(flt.Clone());
1322 for (var idx = this.ListFilters.Items.Count - 1; idx >= 0; idx--)
1324 if (this.ListFilters.GetSelected(idx))
1326 currentTab.RemoveFilter((PostFilterRule)this.ListFilters.Items[idx]);
1327 this.ListFilters.Items.RemoveAt(idx);
1330 this.SetFilters(selectedTab);
1334 private void FilterTextBox_KeyDown(object sender, KeyEventArgs e)
1336 if (e.KeyCode == Keys.Space && e.Modifiers == (Keys.Shift | Keys.Control))
1338 var main = (TweenMain)this.Owner;
1339 var tbox = (TextBox)sender;
1340 if (tbox.SelectionStart > 0)
1342 var endidx = tbox.SelectionStart - 1;
1343 for (var i = tbox.SelectionStart - 1; i >= 0; i--)
1345 var c = tbox.Text[i];
1346 if (char.IsLetterOrDigit(c) || c == '_')
1353 startstr = tbox.Text.Substring(i + 1, endidx - i);
1354 main.ShowSuplDialog(tbox, main.AtIdSupl, startstr.Length + 1, startstr);
1358 startstr = tbox.Text.Substring(i + 1, endidx - i);
1359 main.ShowSuplDialog(tbox, main.HashSupl, startstr.Length + 1, startstr);
1371 private void FilterTextBox_KeyPress(object sender, KeyPressEventArgs e)
1373 var main = (TweenMain)this.Owner;
1374 var tbox = (TextBox)sender;
1375 if (e.KeyChar == '@')
1378 main.ShowSuplDialog(tbox, main.AtIdSupl);
1381 else if (e.KeyChar == '#')
1383 main.ShowSuplDialog(tbox, main.HashSupl);
1388 private void ListFilters_DrawItem(object sender, DrawItemEventArgs e)
1394 var filter = (PostFilterRule)this.ListFilters.Items[e.Index];
1395 var isSelected = e.State.HasFlag(DrawItemState.Selected);
1399 textBrush = SystemBrushes.HighlightText;
1400 else if (filter.Enabled)
1401 textBrush = SystemBrushes.WindowText;
1403 textBrush = SystemBrushes.GrayText;
1405 e.Graphics.DrawString(filter.ToString(), e.Font, textBrush, e.Bounds);
1408 e.DrawFocusRectangle();
1411 private void ListFilters_KeyDown(object sender, KeyEventArgs e)
1413 if (e.Control && e.KeyCode == Keys.A)
1415 var itemCount = this.ListFilters.Items.Count;
1416 if (itemCount == 0) return;
1418 using (ControlTransaction.Update(this.ListFilters))
1424 this.multiSelState |= MultiSelectionState.SelectAll;
1426 for (var i = 1; i < itemCount; i++)
1428 this.ListFilters.SetSelected(i, true);
1433 this.multiSelState &= ~MultiSelectionState.SelectAll;
1437 this.ListFilters.SetSelected(0, true);
1442 protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
1444 base.ScaleControl(factor, specified);
1445 this.ListFilters.ItemHeight = this.ListFilters.Font.Height;