OSDN Git Service

814968eab271a5a4034d4f60fbb9454afb21d8a7
[opentween/open-tween.git] / OpenTween / HashtagManage.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) 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.Globalization;
33 using System.Linq;
34 using System.Text;
35 using System.Windows.Forms;
36
37 namespace OpenTween
38 {
39     public partial class HashtagManage : OTBaseForm
40     {
41         public string UseHash { get; private set; } = "";
42         public bool IsPermanent { get; private set; } = false;
43         public bool IsHead { get; private set; } = false;
44         public bool IsNotAddToAtReply { get; private set; } = true;
45
46         /// <summary>
47         /// エラー時にダイアログを表示させない (ユニットテストなどで使用)
48         /// </summary>
49         public bool RunSilent { get; set; }
50
51         //入力補助画面
52         private readonly AtIdSupplement _hashSupl;
53
54         //編集モード
55         private bool _isAdd = false;
56
57         private void ChangeMode(bool isEdit)
58         {
59             this.GroupHashtag.Enabled = !isEdit;
60             this.GroupDetail.Enabled = isEdit;
61             this.TableLayoutButtons.Enabled = !isEdit;
62             if (isEdit)
63                 this.UseHashText.Focus();
64             else
65                 this.HistoryHashList.Focus();
66         }
67
68         private void Cancel_Button_Click(object sender, EventArgs e)
69         {
70             this.DialogResult = DialogResult.Cancel;
71             this.Close();
72         }
73
74         private void AddButton_Click(object sender, EventArgs e)
75         {
76             this.UseHashText.Text = "";
77             ChangeMode(true);
78             _isAdd = true;
79         }
80
81         private void EditButton_Click(object sender, EventArgs e)
82         {
83             if (this.HistoryHashList.SelectedIndices.Count == 0) return;
84             this.UseHashText.Text = this.HistoryHashList.SelectedItems[0].ToString();
85             ChangeMode(true);
86             _isAdd = false;
87         }
88
89         private void DeleteButton_Click(object sender, EventArgs e)
90         {
91             if (this.HistoryHashList.SelectedIndices.Count == 0) return;
92             if (!this.RunSilent &&
93                 MessageBox.Show(Properties.Resources.DeleteHashtagsMessage1,
94                                 "Delete Hashtags",
95                                 MessageBoxButtons.OKCancel,
96                                 MessageBoxIcon.Question) == DialogResult.Cancel)
97             {
98                 return;
99             }
100
101             // 削除によってインデックス番号が変わらないように逆順に処理する
102             var selectedIndices = this.HistoryHashList.SelectedIndices.Cast<int>()
103                 .OrderByDescending(x => x).ToArray();
104
105             foreach (var idx in selectedIndices)
106             {
107                 if (UseHashText.Text == HistoryHashList.Items[idx].ToString()) UseHashText.Text = "";
108                 HistoryHashList.Items.RemoveAt(idx);
109             }
110             if (HistoryHashList.Items.Count > 0)
111             {
112                 HistoryHashList.SelectedIndex = 0;
113             }
114         }
115
116         private void UnSelectButton_Click(object sender, EventArgs e)
117         {
118             do
119             {
120                 HistoryHashList.SelectedIndices.Clear();
121             } while (HistoryHashList.SelectedIndices.Count > 0);
122         }
123
124         private int GetIndexOf(ListBox.ObjectCollection list, string value)
125         {
126             if (string.IsNullOrEmpty(value)) return -1;
127
128             var idx = 0;
129
130             foreach (var l in list)
131             {
132                 var src = l as string;
133                 if (string.IsNullOrEmpty(src))
134                 {
135                     idx += 1;
136                     continue;
137                 }
138                 if (string.Compare(src, value, StringComparison.OrdinalIgnoreCase) == 0)
139                 {
140                     return idx;
141                 }
142                 idx += 1;
143             }
144
145             // Not Found
146             return -1;
147         }
148
149         public void AddHashToHistory(string hash, bool isIgnorePermanent)
150         {
151             hash = hash.Trim();
152             if (!string.IsNullOrEmpty(hash))
153             {
154                 if (isIgnorePermanent || !this.IsPermanent)
155                 {
156                     //無条件に先頭に挿入
157                     var idx = GetIndexOf(HistoryHashList.Items, hash);
158
159                     if (idx != -1) HistoryHashList.Items.RemoveAt(idx);
160                     HistoryHashList.Items.Insert(0, hash);
161                 }
162                 else
163                 {
164                     //固定されていたら2行目に挿入
165                     var idx = GetIndexOf(HistoryHashList.Items, hash);
166                     if (this.IsPermanent)
167                     {
168                         if (idx > 0)
169                         {
170                             //重複アイテムが2行目以降にあれば2行目へ
171                             HistoryHashList.Items.RemoveAt(idx);
172                             HistoryHashList.Items.Insert(1, hash);
173                         }
174                         else if (idx == -1)
175                         {
176                             //重複アイテムなし
177                             if (HistoryHashList.Items.Count == 0)
178                             {
179                                 //リストが空なら追加
180                                 HistoryHashList.Items.Add(hash);
181                             }
182                             else
183                             {
184                                 //リストにアイテムがあれば2行目へ
185                                 HistoryHashList.Items.Insert(1, hash);
186                             }
187                         }
188                     }
189                 }
190             }
191         }
192
193         private void HashtagManage_Shown(object sender, EventArgs e)
194         {
195             //オプション
196             this.CheckPermanent.Checked = this.IsPermanent;
197             this.RadioHead.Checked = this.IsHead;
198             this.RadioLast.Checked = !this.IsHead;
199             //リスト選択
200             if (this.HistoryHashList.Items.Contains(this.UseHash))
201             {
202                 this.HistoryHashList.SelectedItem = this.UseHash;
203             }
204             else
205             {
206                 if (this.HistoryHashList.Items.Count > 0)
207                     this.HistoryHashList.SelectedIndex = 0;
208             }
209             this.ChangeMode(false);
210         }
211
212         public HashtagManage(AtIdSupplement hashSuplForm, string[] history, string permanentHash, bool IsPermanent, bool IsHead, bool IsNotAddToAtReply)
213         {
214             // この呼び出しは、Windows フォーム デザイナで必要です。
215             InitializeComponent();
216
217             // InitializeComponent() 呼び出しの後で初期化を追加します。
218
219             _hashSupl = hashSuplForm;
220             HistoryHashList.Items.AddRange(history);
221             this.UseHash = permanentHash;
222             this.IsPermanent = IsPermanent;
223             this.IsHead = IsHead;
224             this.IsNotAddToAtReply = IsNotAddToAtReply;
225         }
226
227         private void UseHashText_KeyPress(object sender, KeyPressEventArgs e)
228         {
229             if (e.KeyChar == '#')
230             {
231                 _hashSupl.ShowDialog();
232                 if (!string.IsNullOrEmpty(_hashSupl.inputText))
233                 {
234                     var fHalf = "";
235                     var eHalf = "";
236                     var selStart = UseHashText.SelectionStart;
237                     if (selStart > 0)
238                     {
239                         fHalf = UseHashText.Text.Substring(0, selStart);
240                     }
241                     if (selStart < UseHashText.Text.Length)
242                     {
243                         eHalf = UseHashText.Text.Substring(selStart);
244                     }
245                     UseHashText.Text = fHalf + _hashSupl.inputText + eHalf;
246                     UseHashText.SelectionStart = selStart + _hashSupl.inputText.Length;
247                 }
248                 e.Handled = true;
249             }
250         }
251
252         private void HistoryHashList_DoubleClick(object sender, EventArgs e)
253             => this.OK_Button_Click(null, null);
254
255         public void ToggleHash()
256         {
257             if (string.IsNullOrEmpty(this.UseHash))
258             {
259                 if (this.HistoryHashList.Items.Count > 0)
260                     this.UseHash = this.HistoryHashList.Items[0].ToString();
261             }
262             else
263             {
264                 this.UseHash = "";
265             }
266         }
267
268         public List<string> HashHistories
269         {
270             get
271             {
272                 var hash = new List<string>();
273                 foreach (string item in HistoryHashList.Items)
274                 {
275                     hash.Add(item);
276                 }
277                 return hash;
278             }
279         }
280
281         public void ClearHashtag()
282             => this.UseHash = "";
283
284         public void SetPermanentHash(string hash)
285         {
286             //固定ハッシュタグの変更
287             this.UseHash = hash.Trim();
288             this.AddHashToHistory(UseHash, false);
289             this.IsPermanent = true;
290         }
291
292         private void PermOK_Button_Click(object sender, EventArgs e)
293         {
294             //ハッシュタグの整形
295             var hashStr = UseHashText.Text;
296             if (!this.AdjustHashtags(ref hashStr, !this.RunSilent)) return;
297
298             UseHashText.Text = hashStr;
299             if (!this._isAdd && this.HistoryHashList.SelectedIndices.Count > 0)
300             {
301                 var idx = this.HistoryHashList.SelectedIndices[0];
302                 this.HistoryHashList.Items.RemoveAt(idx);
303                 do
304                 {
305                     this.HistoryHashList.SelectedIndices.Clear();
306                 } while (this.HistoryHashList.SelectedIndices.Count > 0);
307                 this.HistoryHashList.Items.Insert(idx, hashStr);
308                 this.HistoryHashList.SelectedIndex = idx;
309             }
310             else
311             {
312                 this.AddHashToHistory(hashStr, false);
313                 do
314                 {
315                     this.HistoryHashList.SelectedIndices.Clear();
316                 } while (this.HistoryHashList.SelectedIndices.Count > 0);
317                 this.HistoryHashList.SelectedIndex = this.HistoryHashList.Items.IndexOf(hashStr);
318             }
319
320             ChangeMode(false);
321         }
322
323         private void PermCancel_Button_Click(object sender, EventArgs e)
324         {
325             if (this.HistoryHashList.Items.Count > 0 && this.HistoryHashList.SelectedIndices.Count > 0)
326                 this.UseHashText.Text = this.HistoryHashList.Items[this.HistoryHashList.SelectedIndices[0]].ToString();
327             else
328                 this.UseHashText.Text = "";
329
330             ChangeMode(false);
331         }
332
333         private void HistoryHashList_KeyDown(object sender, KeyEventArgs e)
334         {
335             if (e.KeyCode == Keys.Delete)
336                 this.DeleteButton_Click(null, null);
337             else if (e.KeyCode == Keys.Insert)
338                 this.AddButton_Click(null, null);
339         }
340
341         private bool AdjustHashtags(ref string hashtag, bool isShowWarn)
342         {
343             //ハッシュタグの整形
344             hashtag = hashtag.Trim();
345             if (string.IsNullOrEmpty(hashtag))
346             {
347                 if (isShowWarn) MessageBox.Show("emply hashtag.", "Hashtag warning", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
348                 return false;
349             }
350             hashtag = hashtag.Replace("#", "#");
351             hashtag = hashtag.Replace(" ", " ");
352             var adjust = "";
353             foreach (var hash in hashtag.Split(' '))
354             {
355                 if (hash.Length > 0)
356                 {
357                     if (!hash.StartsWith("#", StringComparison.Ordinal))
358                     {
359                         if (isShowWarn) MessageBox.Show("Invalid hashtag. -> " + hash, "Hashtag warning", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
360                         return false;
361                     }
362                     if (hash.Length == 1)
363                     {
364                         if (isShowWarn) MessageBox.Show("empty hashtag.", "Hashtag warning", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
365                         return false;
366                     }
367                     //使用不可の文字チェックはしない
368                     adjust += hash + " ";
369                 }
370             }
371             hashtag = adjust.Trim();
372             return true;
373         }
374
375         private void OK_Button_Click(object sender, EventArgs e)
376         {
377             var hash = "";
378             foreach (string hs in this.HistoryHashList.SelectedItems)
379             {
380                 hash += hs + " ";
381             }
382             hash = hash.Trim();
383             if (!string.IsNullOrEmpty(hash))
384             {
385                 this.AddHashToHistory(hash, true);
386                 this.IsPermanent = this.CheckPermanent.Checked;
387             }
388             else
389             {
390                 //使用ハッシュが未選択ならば、固定オプション外す
391                 this.IsPermanent = false;
392             }
393             this.IsHead = this.RadioHead.Checked;
394             this.UseHash = hash;
395
396             this.DialogResult = DialogResult.OK;
397             this.Close();
398         }
399
400         private void HashtagManage_KeyDown(object sender, KeyEventArgs e)
401         {
402             if (e.KeyCode == Keys.Enter)
403             {
404                 e.Handled = true;
405                 if (this.GroupDetail.Enabled)
406                     this.PermOK_Button_Click(null, null);
407                 else
408                     this.OK_Button_Click(null, null);
409             }
410             else if (e.KeyCode == Keys.Escape)
411             {
412                 e.Handled = true;
413                 if (this.GroupDetail.Enabled)
414                     this.PermCancel_Button_Click(null, null);
415                 else
416                     this.Cancel_Button_Click(null, null);
417             }
418         }
419
420         private void CheckNotAddToAtReply_CheckedChanged(object sender, EventArgs e)
421             => this.IsNotAddToAtReply = CheckNotAddToAtReply.Checked;
422     }
423 }