OSDN Git Service

35bc568dd0622173eb13689d7dd9e70b9399f1f1
[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             var idx = 0;
300             if (!this._isAdd && this.HistoryHashList.SelectedIndices.Count > 0)
301             {
302                 idx = this.HistoryHashList.SelectedIndices[0];
303                 this.HistoryHashList.Items.RemoveAt(idx);
304                 do
305                 {
306                     this.HistoryHashList.SelectedIndices.Clear();
307                 } while (this.HistoryHashList.SelectedIndices.Count > 0);
308                 this.HistoryHashList.Items.Insert(idx, hashStr);
309                 this.HistoryHashList.SelectedIndex = idx;
310             }
311             else
312             {
313                 this.AddHashToHistory(hashStr, false);
314                 do
315                 {
316                     this.HistoryHashList.SelectedIndices.Clear();
317                 } while (this.HistoryHashList.SelectedIndices.Count > 0);
318                 this.HistoryHashList.SelectedIndex = this.HistoryHashList.Items.IndexOf(hashStr);
319             }
320
321             ChangeMode(false);
322         }
323
324         private void PermCancel_Button_Click(object sender, EventArgs e)
325         {
326             if (this.HistoryHashList.Items.Count > 0 && this.HistoryHashList.SelectedIndices.Count > 0)
327                 this.UseHashText.Text = this.HistoryHashList.Items[this.HistoryHashList.SelectedIndices[0]].ToString();
328             else
329                 this.UseHashText.Text = "";
330
331             ChangeMode(false);
332         }
333
334         private void HistoryHashList_KeyDown(object sender, KeyEventArgs e)
335         {
336             if (e.KeyCode == Keys.Delete)
337                 this.DeleteButton_Click(null, null);
338             else if (e.KeyCode == Keys.Insert)
339                 this.AddButton_Click(null, null);
340         }
341
342         private bool AdjustHashtags(ref string hashtag, bool isShowWarn)
343         {
344             //ハッシュタグの整形
345             hashtag = hashtag.Trim();
346             if (string.IsNullOrEmpty(hashtag))
347             {
348                 if (isShowWarn) MessageBox.Show("emply hashtag.", "Hashtag warning", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
349                 return false;
350             }
351             hashtag = hashtag.Replace("#", "#");
352             hashtag = hashtag.Replace(" ", " ");
353             var adjust = "";
354             foreach (var hash in hashtag.Split(' '))
355             {
356                 if (hash.Length > 0)
357                 {
358                     if (!hash.StartsWith("#", StringComparison.Ordinal))
359                     {
360                         if (isShowWarn) MessageBox.Show("Invalid hashtag. -> " + hash, "Hashtag warning", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
361                         return false;
362                     }
363                     if (hash.Length == 1)
364                     {
365                         if (isShowWarn) MessageBox.Show("empty hashtag.", "Hashtag warning", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
366                         return false;
367                     }
368                     //使用不可の文字チェックはしない
369                     adjust += hash + " ";
370                 }
371             }
372             hashtag = adjust.Trim();
373             return true;
374         }
375
376         private void OK_Button_Click(object sender, EventArgs e)
377         {
378             var hash = "";
379             foreach (string hs in this.HistoryHashList.SelectedItems)
380             {
381                 hash += hs + " ";
382             }
383             hash = hash.Trim();
384             if (!string.IsNullOrEmpty(hash))
385             {
386                 this.AddHashToHistory(hash, true);
387                 this.IsPermanent = this.CheckPermanent.Checked;
388             }
389             else
390             {
391                 //使用ハッシュが未選択ならば、固定オプション外す
392                 this.IsPermanent = false;
393             }
394             this.IsHead = this.RadioHead.Checked;
395             this.UseHash = hash;
396
397             this.DialogResult = DialogResult.OK;
398             this.Close();
399         }
400
401         private void HashtagManage_KeyDown(object sender, KeyEventArgs e)
402         {
403             if (e.KeyCode == Keys.Enter)
404             {
405                 e.Handled = true;
406                 if (this.GroupDetail.Enabled)
407                     this.PermOK_Button_Click(null, null);
408                 else
409                     this.OK_Button_Click(null, null);
410             }
411             else if (e.KeyCode == Keys.Escape)
412             {
413                 e.Handled = true;
414                 if (this.GroupDetail.Enabled)
415                     this.PermCancel_Button_Click(null, null);
416                 else
417                     this.Cancel_Button_Click(null, null);
418             }
419         }
420
421         private void CheckNotAddToAtReply_CheckedChanged(object sender, EventArgs e)
422             => this.IsNotAddToAtReply = CheckNotAddToAtReply.Checked;
423     }
424 }