OSDN Git Service

自動プロパティを使用する (IDE0032)
[opentween/open-tween.git] / OpenTween / ShortcutCommand.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2015 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
4 //
5 // This file is part of OpenTween.
6 //
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
10 // any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License
15 // for more details.
16 //
17 // You should have received a copy of the GNU General public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
21
22 using System;
23 using System.Collections.Generic;
24 using System.Linq;
25 using System.Text;
26 using System.Threading.Tasks;
27 using System.Windows.Forms;
28
29 namespace OpenTween
30 {
31     public enum FocusedControl
32     {
33         None,
34         ListTab,
35         StatusText,
36         PostBrowser,
37     }
38
39     /// <summary>
40     /// ショートカットキーの条件と動作を定義するクラス
41     /// </summary>
42     public class ShortcutCommand
43     {
44         private Func<bool> onlyWhen;
45         private Func<Task> command;
46
47         /// <summary>
48         /// ショートカットキーが動作する条件となるキー入力
49         /// </summary>
50         public Keys[] Shortcuts { get; private set; }
51
52         /// <summary>
53         /// ショートカットキーが動作する条件となるフォーカス状態
54         /// </summary>
55         public FocusedControl FocusedOn { get; private set; }
56
57         /// <summary>
58         /// ショートカットキーが動作する否定条件となるフォーカス状態
59         /// </summary>
60         public FocusedControl NotFocusedOn { get; private set; }
61
62         /// <summary>
63         /// コマンドを実行した後、コントロール既定の動作を無効化するか否か (デフォルトは true)
64         /// </summary>
65         public bool PreventDefault { get; private set; }
66
67         private ShortcutCommand()
68         {
69             this.Shortcuts = new Keys[0];
70             this.command = () => Task.FromResult(0);
71             this.onlyWhen = () => true;
72             this.FocusedOn = FocusedControl.None;
73             this.NotFocusedOn = FocusedControl.None;
74             this.PreventDefault = true;
75         }
76
77         /// <summary>
78         /// コマンドを実行する条件を満たしているか判定します
79         /// </summary>
80         public bool IsMatch(Keys pressedKey, FocusedControl focusedOn)
81         {
82             if (!this.Shortcuts.Contains(pressedKey))
83                 return false;
84
85             if (this.FocusedOn != FocusedControl.None && this.FocusedOn != focusedOn)
86                 return false;
87
88             if (this.NotFocusedOn != FocusedControl.None && this.NotFocusedOn == focusedOn)
89                 return false;
90
91             if (!this.onlyWhen())
92                 return false;
93
94             return true;
95         }
96
97         /// <summary>
98         /// コマンドを実行します
99         /// </summary>
100         public async Task RunCommand()
101         {
102             await this.command();
103         }
104
105         /// <summary>
106         /// 新規に ShortcutCommand インスタンスを作成するビルダーを返します
107         /// </summary>
108         public static ShortcutCommand.Builder Create(params Keys[] shortcuts)
109         {
110             return new Builder().Keys(shortcuts);
111         }
112
113         public class Builder
114         {
115             private readonly ShortcutCommand instance;
116
117             internal Builder()
118             {
119                 this.instance = new ShortcutCommand();
120             }
121
122             /// <summary>
123             /// 指定されたキーが入力された時にショートカットを発動します
124             /// </summary>
125             public Builder Keys(params Keys[] shortcuts)
126             {
127                 this.instance.Shortcuts = shortcuts;
128                 return this;
129             }
130
131             /// <summary>
132             /// 指定されたコントロールにフォーカスが当たっている時のみショートカットを有効にします
133             /// </summary>
134             public Builder FocusedOn(FocusedControl focusedOn)
135             {
136                 this.instance.FocusedOn = focusedOn;
137                 return this;
138             }
139
140             /// <summary>
141             /// 指定されたコントロールにフォーカスが当たっている時はショートカットを有効にしません
142             /// </summary>
143             public Builder NotFocusedOn(FocusedControl notFocusedOn)
144             {
145                 this.instance.NotFocusedOn = notFocusedOn;
146                 return this;
147             }
148
149             /// <summary>
150             /// 指定された条件が true になる間のみショートカットを有効にします
151             /// </summary>
152             public Builder OnlyWhen(Func<bool> condition)
153             {
154                 this.instance.onlyWhen = condition;
155                 return this;
156             }
157
158             /// <summary>
159             /// ショートカットが入力された時に行う動作の内容
160             /// </summary>
161             public ShortcutCommand Do(Action action, bool preventDefault = true)
162             {
163                 return this.Do(SynchronousTask(action), preventDefault);
164             }
165
166             /// <summary>
167             /// ショートカットが入力された時に行う動作の内容
168             /// </summary>
169             public ShortcutCommand Do(Func<Task> action, bool preventDefault = true)
170             {
171                 this.instance.command = action;
172                 this.instance.PreventDefault = preventDefault;
173
174                 return this.instance;
175             }
176
177             /// <summary>何もしないタスク</summary>
178             private static Task noOpTask = Task.FromResult(0);
179
180             /// <summary>
181             /// Action を Func&lt;Task&gt; に変換します
182             /// </summary>
183             private static Func<Task> SynchronousTask(Action action)
184             {
185                 return () => { action(); return noOpTask; };
186             }
187         }
188     }
189 }