OSDN Git Service

投稿画像選択のUIをMediaSelectorクラスとして分離
[opentween/open-tween.git] / OpenTween / Tween.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      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 //コンパイル後コマンド
28 //"c:\Program Files\Microsoft.NET\SDK\v2.0\Bin\sgen.exe" /f /a:"$(TargetPath)"
29 //"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\sgen.exe" /f /a:"$(TargetPath)"
30
31 using System;
32 using System.Collections.Generic;
33 using System.ComponentModel;
34 using System.Diagnostics;
35 using System.Drawing;
36 using System.IO;
37 using System.Linq;
38 using System.Media;
39 using System.Net;
40 using System.Net.Http;
41 using System.Reflection;
42 using System.Text;
43 using System.Text.RegularExpressions;
44 using System.Threading;
45 using System.Threading.Tasks;
46 using System.Windows.Forms;
47 using OpenTween.Api;
48 using OpenTween.Connection;
49 using OpenTween.OpenTweenCustomControl;
50 using OpenTween.Thumbnail;
51
52 namespace OpenTween
53 {
54     public partial class TweenMain : OTBaseForm
55     {
56         private readonly HttpClient http;
57
58         //各種設定
59         private Size _mySize;           //画面サイズ
60         private Point _myLoc;           //画面位置
61         private int _mySpDis;           //区切り位置
62         private int _mySpDis2;          //発言欄区切り位置
63         private int _mySpDis3;          //プレビュー区切り位置
64         private int _iconSz;            //アイコンサイズ(現在は16、24、48の3種類。将来直接数字指定可能とする 注:24x24の場合に26と指定しているのはMSゴシック系フォントのための仕様)
65         private bool _iconCol;          //1列表示の時true(48サイズのとき)
66
67         //雑多なフラグ類
68         private bool _initial;         //true:起動時処理中
69         private bool _initialLayout = true;
70         private bool _ignoreConfigSave;         //true:起動時処理中
71         private bool _tabDrag;           //タブドラッグ中フラグ(DoDragDropを実行するかの判定用)
72         private TabPage _beforeSelectedTab; //タブが削除されたときに前回選択されていたときのタブを選択する為に保持
73         private Point _tabMouseDownPoint;
74         private string _rclickTabName;      //右クリックしたタブの名前(Tabコントロール機能不足対応)
75         private readonly object _syncObject = new object();    //ロック用
76         private const string detailHtmlFormatMono1 = "<html><head><meta http-equiv=\"X-UA-Compatible\" content=\"IE=8\"><style type=\"text/css\"><!-- pre {font-family: \"";
77         private const string detailHtmlFormat2 = "\", sans-serif; font-size: ";
78         private const string detailHtmlFormat3 = "pt; margin: 0; word-wrap: break-word; white-space: pre-wrap; color:rgb(";
79         private const string detailHtmlFormat4 = ");} a:link, a:visited, a:active, a:hover {color:rgb(";
80         private const string detailHtmlFormat5 = "); } --></style></head><body style=\"margin:0px; background-color:rgb(";
81         private const string detailHtmlFormatMono6 = ");\"><pre>";
82         private const string detailHtmlFormatMono7 = "</pre></body></html>";
83         private const string detailHtmlFormat1 = "<html><head><meta http-equiv=\"X-UA-Compatible\" content=\"IE=8\"><style type=\"text/css\"><!-- p {font-family: \"";
84         private const string detailHtmlFormat6 = ");\"><p><span style=\"vertical-align:text-bottom\">";
85         private const string detailHtmlFormat7 = "</span></p></body></html>";
86         private string detailHtmlFormatHeader;
87         private string detailHtmlFormatFooter;
88         private bool _myStatusError = false;
89         private bool _myStatusOnline = false;
90         private bool soundfileListup = false;
91         private FormWindowState _formWindowState = FormWindowState.Normal; // フォームの状態保存用 通知領域からアイコンをクリックして復帰した際に使用する
92
93         //設定ファイル関連
94         //private SettingToConfig _cfg; //旧
95         private SettingLocal _cfgLocal;
96         private SettingCommon _cfgCommon;
97         private bool _modifySettingLocal = false;
98         private bool _modifySettingCommon = false;
99         private bool _modifySettingAtId = false;
100
101         //twitter解析部
102         private Twitter tw = new Twitter();
103
104         //Growl呼び出し部
105         private GrowlHelper gh = new GrowlHelper(Application.ProductName);
106
107         //サブ画面インスタンス
108         private AppendSettingDialog SettingDialog = AppendSettingDialog.Instance;       //設定画面インスタンス
109         private SearchWordDialog SearchDialog = new SearchWordDialog();     //検索画面インスタンス
110         private FilterDialog fltDialog = new FilterDialog(); //フィルター編集画面
111         private OpenURL UrlDialog = new OpenURL();
112         public AtIdSupplement AtIdSupl;     //@id補助
113         public AtIdSupplement HashSupl;    //Hashtag補助
114         public HashtagManage HashMgr;
115         private EventViewerDialog evtDialog;
116
117         //表示フォント、色、アイコン
118         private Font _fntUnread;            //未読用フォント
119         private Color _clUnread;            //未読用文字色
120         private Font _fntReaded;            //既読用フォント
121         private Color _clReaded;            //既読用文字色
122         private Color _clFav;               //Fav用文字色
123         private Color _clOWL;               //片思い用文字色
124         private Color _clRetweet;               //Retweet用文字色
125         private Color _clHighLight = Color.FromKnownColor(KnownColor.HighlightText);         //選択中の行用文字色
126         private Font _fntDetail;            //発言詳細部用フォント
127         private Color _clDetail;              //発言詳細部用色
128         private Color _clDetailLink;          //発言詳細部用リンク文字色
129         private Color _clDetailBackcolor;     //発言詳細部用背景色
130         private Color _clSelf;              //自分の発言用背景色
131         private Color _clAtSelf;            //自分宛返信用背景色
132         private Color _clTarget;            //選択発言者の他の発言用背景色
133         private Color _clAtTarget;          //選択発言中の返信先用背景色
134         private Color _clAtFromTarget;      //選択発言者への返信発言用背景色
135         private Color _clAtTo;              //選択発言の唯一@先
136         private Color _clListBackcolor;       //リスト部通常発言背景色
137         private Color _clInputBackcolor;      //入力欄背景色
138         private Color _clInputFont;           //入力欄文字色
139         private Font _fntInputFont;           //入力欄フォント
140         private ImageCache IconCache;        //アイコン画像リスト
141         private Icon NIconAt;               //At.ico             タスクトレイアイコン:通常時
142         private Icon NIconAtRed;            //AtRed.ico          タスクトレイアイコン:通信エラー時
143         private Icon NIconAtSmoke;          //AtSmoke.ico        タスクトレイアイコン:オフライン時
144         private Icon[] NIconRefresh = new Icon[4];       //Refresh.ico        タスクトレイアイコン:更新中(アニメーション用に4種類を保持するリスト)
145         private Icon TabIcon;               //Tab.ico            未読のあるタブ用アイコン
146         private Icon MainIcon;              //Main.ico           画面左上のアイコン
147         private Icon ReplyIcon;               //5g
148         private Icon ReplyIconBlink;          //6g
149
150         private ImageList _listViewImageList = new ImageList();    //ListViewItemの高さ変更用
151
152         private PostClass _anchorPost;
153         private bool _anchorFlag;        //true:関連発言移動中(関連移動以外のオペレーションをするとfalseへ。trueだとリスト背景色をアンカー発言選択中として描画)
154
155         private List<PostingStatus> _history = new List<PostingStatus>();   //発言履歴
156         private int _hisIdx;                  //発言履歴カレントインデックス
157
158         //発言投稿時のAPI引数(発言編集時に設定。手書きreplyでは設定されない)
159         private long? _reply_to_id;     // リプライ先のステータスID 0の場合はリプライではない 注:複数あてのものはリプライではない
160         private string _reply_to_name;    // リプライ先ステータスの書き込み者の名前
161
162         //時速表示用
163         private List<DateTime> _postTimestamps = new List<DateTime>();
164         private List<DateTime> _favTimestamps = new List<DateTime>();
165         private Dictionary<DateTime, int> _tlTimestamps = new Dictionary<DateTime, int>();
166         private int _tlCount;
167
168         // 以下DrawItem関連
169         private SolidBrush _brsHighLight = new SolidBrush(Color.FromKnownColor(KnownColor.Highlight));
170         private SolidBrush _brsBackColorMine;
171         private SolidBrush _brsBackColorAt;
172         private SolidBrush _brsBackColorYou;
173         private SolidBrush _brsBackColorAtYou;
174         private SolidBrush _brsBackColorAtFromTarget;
175         private SolidBrush _brsBackColorAtTo;
176         private SolidBrush _brsBackColorNone;
177         private SolidBrush _brsDeactiveSelection = new SolidBrush(Color.FromKnownColor(KnownColor.ButtonFace)); //Listにフォーカスないときの選択行の背景色
178         private StringFormat sfTab = new StringFormat();
179
180         //////////////////////////////////////////////////////////////////////////////////////////////////////////
181         private ToolStripAPIGauge _apiGauge;
182         private TabInformations _statuses;
183
184         // ListViewItem のキャッシュ関連
185         private int _itemCacheIndex;
186         private ListViewItem[] _itemCache;
187         private PostClass[] _postCache;
188         private ReaderWriterLockSlim itemCacheLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
189
190         private TabPage _curTab;
191         private int _curItemIndex;
192         private DetailsListView _curList;
193         private PostClass _curPost;
194         private bool _isColumnChanged = false;
195         private bool _waitTimeline = false;
196         private bool _waitReply = false;
197         private bool _waitDm = false;
198         private bool _waitFav = false;
199         private bool _waitPubSearch = false;
200         private bool _waitUserTimeline = false;
201         private bool _waitLists = false;
202         private BackgroundWorker[] _bw = new BackgroundWorker[20];
203         private BackgroundWorker _bwFollower;
204         private InternetSecurityManager SecurityManager;
205
206         private int UnreadCounter = -1;
207         private int UnreadAtCounter = -1;
208
209         private string[] ColumnOrgText = new string[9];
210         private string[] ColumnText = new string[9];
211
212         private bool _DoFavRetweetFlags = false;
213         private bool osResumed = false;
214
215         //////////////////////////////////////////////////////////////////////////////////////////////////////////
216         private string _postBrowserStatusText = "";
217
218         private bool _colorize = false;
219
220         private System.Timers.Timer TimerTimeline = new System.Timers.Timer();
221
222         private ImageListViewItem displayItem;
223
224         /// <summary>
225         /// デザイン時の DPI (96dpi) と実際の表示時の DPI との比を表します
226         /// </summary>
227         protected SizeF currentScaleFactor = new SizeF();
228
229         //URL短縮のUndo用
230         private struct urlUndo
231         {
232             public string Before;
233             public string After;
234         }
235
236         private List<urlUndo> urlUndoBuffer = null;
237
238         private struct ReplyChain
239         {
240             public long OriginalId;
241             public long InReplyToId;
242             public TabPage OriginalTab;
243
244             public ReplyChain(long originalId, long inReplyToId, TabPage originalTab)
245             {
246                 this.OriginalId = originalId;
247                 this.InReplyToId = inReplyToId;
248                 this.OriginalTab = originalTab;
249             }
250         }
251
252         private Stack<ReplyChain> replyChains; //[, ]でのリプライ移動の履歴
253         private Stack<Tuple<TabPage, PostClass>> selectPostChains = new Stack<Tuple<TabPage, PostClass>>(); //ポスト選択履歴
254
255         //Backgroundworkerの処理結果通知用引数構造体
256         private class GetWorkerResult
257         {
258             public string retMsg = "";                     //処理結果詳細メッセージ。エラー時に値がセットされる
259             public int page;                      //取得対象ページ番号
260             public int endPage = 0;                   //取得終了ページ番号(継続可能ならインクリメントされて返る。pageと比較して継続判定)
261             public MyCommon.WORKERTYPE type;                   //処理種別
262             public Dictionary<string, Image> imgs = null;                    //新規取得したアイコンイメージ
263             public string tName = "";                  //Fav追加・削除時のタブ名
264             public List<long> ids = null;               //Fav追加・削除時のID
265             public List<long> sIds = null;                  //Fav追加・削除成功分のID
266             public bool newDM = false;
267             public int addCount;
268             public PostingStatus status;
269         }
270
271         //Backgroundworkerへ処理内容を通知するための引数用構造体
272         private class GetWorkerArg
273         {
274             public int page;                      //処理対象ページ番号
275             public int endPage;                   //処理終了ページ番号(起動時の読み込みページ数。通常時はpageと同じ値をセット)
276             public MyCommon.WORKERTYPE type;                   //処理種別
277             public string url = "";            //URLをブラウザで開くときのアドレス
278             public PostingStatus status = new PostingStatus();          //発言POST時の発言内容
279             public List<long> ids;               //Fav追加・削除時のItemIndex
280             public List<long> sIds;              //Fav追加・削除成功分のItemIndex
281             public string tName = "";            //Fav追加・削除時のタブ名
282         }
283
284         //検索処理タイプ
285         private enum SEARCHTYPE
286         {
287             DialogSearch,
288             NextSearch,
289             PrevSearch,
290         }
291
292         private class PostingStatus
293         {
294             public string status = "";
295             public long? inReplyToId = null;
296             public string inReplyToName = null;
297             public string imageService = "";      //画像投稿サービス名
298             public string[] imagePath = null;
299             public PostingStatus()
300             {
301             }
302             public PostingStatus(string status, long? replyToId, string replyToName)
303             {
304                 this.status = status;
305                 this.inReplyToId = replyToId;
306                 this.inReplyToName = replyToName;
307             }
308         }
309
310         private void TweenMain_Activated(object sender, EventArgs e)
311         {
312             //画面がアクティブになったら、発言欄の背景色戻す
313             if (StatusText.Focused)
314             {
315                 this.StatusText_Enter(this.StatusText, System.EventArgs.Empty);
316             }
317         }
318
319         private void TweenMain_Disposed(object sender, EventArgs e)
320         {
321             //後始末
322             SettingDialog.Dispose();
323             SearchDialog.Dispose();
324             fltDialog.Dispose();
325             UrlDialog.Dispose();
326             if (NIconAt != null) NIconAt.Dispose();
327             if (NIconAtRed != null) NIconAtRed.Dispose();
328             if (NIconAtSmoke != null) NIconAtSmoke.Dispose();
329             if (NIconRefresh[0] != null) NIconRefresh[0].Dispose();
330             if (NIconRefresh[1] != null) NIconRefresh[1].Dispose();
331             if (NIconRefresh[2] != null) NIconRefresh[2].Dispose();
332             if (NIconRefresh[3] != null) NIconRefresh[3].Dispose();
333             if (TabIcon != null) TabIcon.Dispose();
334             if (MainIcon != null) MainIcon.Dispose();
335             if (ReplyIcon != null) ReplyIcon.Dispose();
336             if (ReplyIconBlink != null) ReplyIconBlink.Dispose();
337             _listViewImageList.Dispose();
338             _brsHighLight.Dispose();
339             if (_brsBackColorMine != null) _brsBackColorMine.Dispose();
340             if (_brsBackColorAt != null) _brsBackColorAt.Dispose();
341             if (_brsBackColorYou != null) _brsBackColorYou.Dispose();
342             if (_brsBackColorAtYou != null) _brsBackColorAtYou.Dispose();
343             if (_brsBackColorAtFromTarget != null) _brsBackColorAtFromTarget.Dispose();
344             if (_brsBackColorAtTo != null) _brsBackColorAtTo.Dispose();
345             if (_brsBackColorNone != null) _brsBackColorNone.Dispose();
346             if (_brsDeactiveSelection != null) _brsDeactiveSelection.Dispose();
347             //sf.Dispose();
348             sfTab.Dispose();
349             foreach (BackgroundWorker bw in _bw)
350             {
351                 if (bw != null)
352                     bw.Dispose();
353             }
354             if (_bwFollower != null)
355             {
356                 _bwFollower.Dispose();
357             }
358             this._apiGauge.Dispose();
359             if (IconCache != null)
360             {
361                 this.IconCache.CancelAsync();
362                 this.IconCache.Dispose();
363             }
364
365             this.http.Dispose();
366
367             // 終了時にRemoveHandlerしておかないとメモリリークする
368             // http://msdn.microsoft.com/ja-jp/library/microsoft.win32.systemevents.powermodechanged.aspx
369             Microsoft.Win32.SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
370         }
371
372         private void LoadIcon(ref Icon IconInstance, string FileName)
373         {
374             string dir = Application.StartupPath;
375             if (File.Exists(Path.Combine(dir, FileName)))
376             {
377                 try
378                 {
379                     IconInstance = new Icon(Path.Combine(dir, FileName));
380                 }
381                 catch (Exception)
382                 {
383                 }
384             }
385         }
386
387         private void LoadIcons()
388         {
389             //着せ替えアイコン対応
390             //タスクトレイ通常時アイコン
391             string dir = Application.StartupPath;
392
393             NIconAt = Properties.Resources.At;
394             NIconAtRed = Properties.Resources.AtRed;
395             NIconAtSmoke = Properties.Resources.AtSmoke;
396             NIconRefresh[0] = Properties.Resources.Refresh;
397             NIconRefresh[1] = Properties.Resources.Refresh2;
398             NIconRefresh[2] = Properties.Resources.Refresh3;
399             NIconRefresh[3] = Properties.Resources.Refresh4;
400             TabIcon = Properties.Resources.TabIcon;
401             MainIcon = Properties.Resources.MIcon;
402             ReplyIcon = Properties.Resources.Reply;
403             ReplyIconBlink = Properties.Resources.ReplyBlink;
404
405             if (!Directory.Exists(Path.Combine(dir, "Icons")))
406                 return;
407
408             LoadIcon(ref NIconAt, "Icons\\At.ico");
409
410             //タスクトレイエラー時アイコン
411             LoadIcon(ref NIconAtRed, "Icons\\AtRed.ico");
412
413             //タスクトレイオフライン時アイコン
414             LoadIcon(ref NIconAtSmoke, "Icons\\AtSmoke.ico");
415
416             //タスクトレイ更新中アイコン
417             //アニメーション対応により4種類読み込み
418             LoadIcon(ref NIconRefresh[0], "Icons\\Refresh.ico");
419             LoadIcon(ref NIconRefresh[1], "Icons\\Refresh2.ico");
420             LoadIcon(ref NIconRefresh[2], "Icons\\Refresh3.ico");
421             LoadIcon(ref NIconRefresh[3], "Icons\\Refresh4.ico");
422
423             //タブ見出し未読表示アイコン
424             LoadIcon(ref TabIcon, "Icons\\Tab.ico");
425
426             //画面のアイコン
427             LoadIcon(ref MainIcon, "Icons\\MIcon.ico");
428
429             //Replyのアイコン
430             LoadIcon(ref ReplyIcon, "Icons\\Reply.ico");
431
432             //Reply点滅のアイコン
433             LoadIcon(ref ReplyIconBlink, "Icons\\ReplyBlink.ico");
434         }
435
436         private void InitColumns(ListView list, bool startup)
437         {
438             ColumnHeader _colHd1 = new ColumnHeader();  //アイコン
439             ColumnHeader _colHd2 = new ColumnHeader();  //ニックネーム
440             ColumnHeader _colHd3 = new ColumnHeader();  //本文
441             ColumnHeader _colHd4 = new ColumnHeader();  //日付
442             ColumnHeader _colHd5 = new ColumnHeader();  //ユーザID
443             ColumnHeader _colHd6 = new ColumnHeader();  //未読
444             ColumnHeader _colHd7 = new ColumnHeader();  //マーク&プロテクト
445             ColumnHeader _colHd8 = new ColumnHeader();  //ソース
446
447             if (!_iconCol)
448             {
449                 list.Columns.AddRange(new ColumnHeader[] { _colHd1, _colHd2, _colHd3, _colHd4, _colHd5, _colHd6, _colHd7, _colHd8 });
450             }
451             else
452             {
453                 list.Columns.AddRange(new ColumnHeader[] { _colHd1, _colHd3 });
454             }
455
456             InitColumnText();
457             _colHd1.Text = ColumnText[0];
458             _colHd1.Width = 48;
459             _colHd2.Text = ColumnText[1];
460             _colHd2.Width = 80;
461             _colHd3.Text = ColumnText[2];
462             _colHd3.Width = 300;
463             _colHd4.Text = ColumnText[3];
464             _colHd4.Width = 50;
465             _colHd5.Text = ColumnText[4];
466             _colHd5.Width = 50;
467             _colHd6.Text = ColumnText[5];
468             _colHd6.Width = 16;
469             _colHd7.Text = ColumnText[6];
470             _colHd7.Width = 16;
471             _colHd8.Text = ColumnText[7];
472             _colHd8.Width = 50;
473
474             int[] dispOrder = new int[8];
475             if (!startup)
476             {
477                 for (int i = 0; i < _curList.Columns.Count; i++)
478                 {
479                     for (int j = 0; j < _curList.Columns.Count; j++)
480                     {
481                         if (_curList.Columns[j].DisplayIndex == i)
482                         {
483                             dispOrder[i] = j;
484                             break;
485                         }
486                     }
487                 }
488                 for (int i = 0; i < _curList.Columns.Count; i++)
489                 {
490                     list.Columns[i].Width = _curList.Columns[i].Width;
491                     list.Columns[dispOrder[i]].DisplayIndex = i;
492                 }
493             }
494             else
495             {
496                 if (_iconCol)
497                 {
498                     list.Columns[0].Width = _cfgLocal.Width1;
499                     list.Columns[1].Width = _cfgLocal.Width3;
500                     list.Columns[0].DisplayIndex = 0;
501                     list.Columns[1].DisplayIndex = 1;
502                 }
503                 else
504                 {
505                     for (int i = 0; i <= 7; i++)
506                     {
507                         if (_cfgLocal.DisplayIndex1 == i)
508                             dispOrder[i] = 0;
509                         else if (_cfgLocal.DisplayIndex2 == i)
510                             dispOrder[i] = 1;
511                         else if (_cfgLocal.DisplayIndex3 == i)
512                             dispOrder[i] = 2;
513                         else if (_cfgLocal.DisplayIndex4 == i)
514                             dispOrder[i] = 3;
515                         else if (_cfgLocal.DisplayIndex5 == i)
516                             dispOrder[i] = 4;
517                         else if (_cfgLocal.DisplayIndex6 == i)
518                             dispOrder[i] = 5;
519                         else if (_cfgLocal.DisplayIndex7 == i)
520                             dispOrder[i] = 6;
521                         else if (_cfgLocal.DisplayIndex8 == i)
522                             dispOrder[i] = 7;
523                     }
524                     list.Columns[0].Width = _cfgLocal.Width1;
525                     list.Columns[1].Width = _cfgLocal.Width2;
526                     list.Columns[2].Width = _cfgLocal.Width3;
527                     list.Columns[3].Width = _cfgLocal.Width4;
528                     list.Columns[4].Width = _cfgLocal.Width5;
529                     list.Columns[5].Width = _cfgLocal.Width6;
530                     list.Columns[6].Width = _cfgLocal.Width7;
531                     list.Columns[7].Width = _cfgLocal.Width8;
532                     for (int i = 0; i <= 7; i++)
533                     {
534                         list.Columns[dispOrder[i]].DisplayIndex = i;
535                     }
536                 }
537             }
538         }
539
540         private void InitColumnText()
541         {
542             ColumnText[0] = "";
543             ColumnText[1] = Properties.Resources.AddNewTabText2;
544             ColumnText[2] = Properties.Resources.AddNewTabText3;
545             ColumnText[3] = Properties.Resources.AddNewTabText4_2;
546             ColumnText[4] = Properties.Resources.AddNewTabText5;
547             ColumnText[5] = "";
548             ColumnText[6] = "";
549             ColumnText[7] = "Source";
550
551             ColumnOrgText[0] = "";
552             ColumnOrgText[1] = Properties.Resources.AddNewTabText2;
553             ColumnOrgText[2] = Properties.Resources.AddNewTabText3;
554             ColumnOrgText[3] = Properties.Resources.AddNewTabText4_2;
555             ColumnOrgText[4] = Properties.Resources.AddNewTabText5;
556             ColumnOrgText[5] = "";
557             ColumnOrgText[6] = "";
558             ColumnOrgText[7] = "Source";
559
560             int c = 0;
561             switch (_statuses.SortMode)
562             {
563                 case IdComparerClass.ComparerMode.Nickname:  //ニックネーム
564                     c = 1;
565                     break;
566                 case IdComparerClass.ComparerMode.Data:  //本文
567                     c = 2;
568                     break;
569                 case IdComparerClass.ComparerMode.Id:  //時刻=発言Id
570                     c = 3;
571                     break;
572                 case IdComparerClass.ComparerMode.Name:  //名前
573                     c = 4;
574                     break;
575                 case IdComparerClass.ComparerMode.Source:  //Source
576                     c = 7;
577                     break;
578             }
579
580             if (_iconCol)
581             {
582                 if (_statuses.SortOrder == SortOrder.Descending)
583                 {
584                     // U+25BE BLACK DOWN-POINTING SMALL TRIANGLE
585                     ColumnText[2] = ColumnOrgText[2] + "▾";
586                 }
587                 else
588                 {
589                     // U+25B4 BLACK UP-POINTING SMALL TRIANGLE
590                     ColumnText[2] = ColumnOrgText[2] + "▴";
591                 }
592             }
593             else
594             {
595                 if (_statuses.SortOrder == SortOrder.Descending)
596                 {
597                     // U+25BE BLACK DOWN-POINTING SMALL TRIANGLE
598                     ColumnText[c] = ColumnOrgText[c] + "▾";
599                 }
600                 else
601                 {
602                     // U+25B4 BLACK UP-POINTING SMALL TRIANGLE
603                     ColumnText[c] = ColumnOrgText[c] + "▴";
604                 }
605             }
606         }
607
608         private void InitializeTraceFrag()
609         {
610 #if DEBUG
611             TraceOutToolStripMenuItem.Checked = true;
612             MyCommon.TraceFlag = true;
613 #endif
614             if (!MyCommon.FileVersion.EndsWith("0"))
615             {
616                 TraceOutToolStripMenuItem.Checked = true;
617                 MyCommon.TraceFlag = true;
618             }
619         }
620
621         private void TweenMain_Load(object sender, EventArgs e)
622         {
623             _ignoreConfigSave = true;
624             this.Visible = false;
625
626             //Win32Api.SetProxy(HttpConnection.ProxyType.Specified, "127.0.0.1", 8080, "user", "pass")
627
628             SecurityManager = new InternetSecurityManager(PostBrowser);
629             this.PostBrowser.AllowWebBrowserDrop = false;  // COMException を回避するため、ActiveX の初期化が終わってから設定する
630
631             MyCommon.TwitterApiInfo.AccessLimitUpdated += TwitterApiStatus_AccessLimitUpdated;
632             Microsoft.Win32.SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
633
634             if (MyApplication.StartupOptions.ContainsKey("d"))
635                 MyCommon.TraceFlag = true;
636
637             Regex.CacheSize = 100;
638
639             InitializeTraceFrag();
640             LoadIcons(); // アイコン読み込み
641
642             //発言保持クラス
643             _statuses = TabInformations.GetInstance();
644
645             //アイコン設定
646             this.Icon = MainIcon;              //メインフォーム(TweenMain)
647             NotifyIcon1.Icon = NIconAt;      //タスクトレイ
648             TabImage.Images.Add(TabIcon);    //タブ見出し
649
650             SettingDialog.Owner = this;;
651             SearchDialog.Owner = this;
652             fltDialog.Owner = this;
653             UrlDialog.Owner = this;
654
655             _history.Add(new PostingStatus());
656             _hisIdx = 0;
657             _reply_to_id = null;
658             _reply_to_name = null;
659
660             //<<<<<<<<<設定関連>>>>>>>>>
661             //設定コンバージョン
662             //ConvertConfig();
663
664             ////設定読み出し
665             LoadConfig();
666
667             ThumbnailGenerator.InitializeGenerator(this.http);
668
669             var imgazyobizinet = ThumbnailGenerator.ImgAzyobuziNetInstance;
670             imgazyobizinet.Enabled = this._cfgCommon.EnableImgAzyobuziNet;
671             imgazyobizinet.DisabledInDM = this._cfgCommon.ImgAzyobuziNetDisabledInDM;
672
673             Thumbnail.Services.TonTwitterCom.InitializeOAuthToken = x =>
674                 x.Initialize(ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret,
675                     this.tw.AccessToken, this.tw.AccessTokenSecret, "", "");
676
677             //新着バルーン通知のチェック状態設定
678             NewPostPopMenuItem.Checked = _cfgCommon.NewAllPop;
679             this.NotifyFileMenuItem.Checked = NewPostPopMenuItem.Checked;
680
681             //フォント&文字色&背景色保持
682             _fntUnread = _cfgLocal.FontUnread;
683             _clUnread = _cfgLocal.ColorUnread;
684             _fntReaded = _cfgLocal.FontRead;
685             _clReaded = _cfgLocal.ColorRead;
686             _clFav = _cfgLocal.ColorFav;
687             _clOWL = _cfgLocal.ColorOWL;
688             _clRetweet = _cfgLocal.ColorRetweet;
689             _fntDetail = _cfgLocal.FontDetail;
690             _clDetail = _cfgLocal.ColorDetail;
691             _clDetailLink = _cfgLocal.ColorDetailLink;
692             _clDetailBackcolor = _cfgLocal.ColorDetailBackcolor;
693             _clSelf = _cfgLocal.ColorSelf;
694             _clAtSelf = _cfgLocal.ColorAtSelf;
695             _clTarget = _cfgLocal.ColorTarget;
696             _clAtTarget = _cfgLocal.ColorAtTarget;
697             _clAtFromTarget = _cfgLocal.ColorAtFromTarget;
698             _clAtTo = _cfgLocal.ColorAtTo;
699             _clListBackcolor = _cfgLocal.ColorListBackcolor;
700             _clInputBackcolor = _cfgLocal.ColorInputBackcolor;
701             _clInputFont = _cfgLocal.ColorInputFont;
702             _fntInputFont = _cfgLocal.FontInputFont;
703
704             var fontUIGlobal = this._cfgLocal.FontUIGlobal;
705             if (fontUIGlobal != null)
706             {
707                 OTBaseForm.GlobalFont = fontUIGlobal;
708                 this.Font = fontUIGlobal;
709             }
710
711             // StringFormatオブジェクトへの事前設定
712             //sf.Alignment = StringAlignment.Near;             // Textを近くへ配置(左から右の場合は左寄せ)
713             //sf.LineAlignment = StringAlignment.Near;         // Textを近くへ配置(上寄せ)
714             //sf.FormatFlags = StringFormatFlags.LineLimit;    // 
715             sfTab.Alignment = StringAlignment.Center;
716             sfTab.LineAlignment = StringAlignment.Center;
717
718             //設定画面への反映
719             HttpTwitter.TwitterUrl = _cfgCommon.TwitterUrl;
720             SettingDialog.TwitterApiUrl = _cfgCommon.TwitterUrl;
721
722             //認証関連
723             if (string.IsNullOrEmpty(_cfgCommon.Token)) _cfgCommon.UserName = "";
724             tw.Initialize(_cfgCommon.Token, _cfgCommon.TokenSecret, _cfgCommon.UserName, _cfgCommon.UserId);
725
726             SettingDialog.UserAccounts = _cfgCommon.UserAccounts;
727
728             SettingDialog.TimelinePeriodInt = _cfgCommon.TimelinePeriod;
729             SettingDialog.ReplyPeriodInt = _cfgCommon.ReplyPeriod;
730             SettingDialog.DMPeriodInt = _cfgCommon.DMPeriod;
731             SettingDialog.PubSearchPeriodInt = _cfgCommon.PubSearchPeriod;
732             SettingDialog.UserTimelinePeriodInt = _cfgCommon.UserTimelinePeriod;
733             SettingDialog.ListsPeriodInt = _cfgCommon.ListsPeriod;
734             //不正値チェック
735             if (!MyApplication.StartupOptions.ContainsKey("nolimit"))
736             {
737                 if (SettingDialog.TimelinePeriodInt < 15 && SettingDialog.TimelinePeriodInt > 0) SettingDialog.TimelinePeriodInt = 15;
738                 if (SettingDialog.ReplyPeriodInt < 15 && SettingDialog.ReplyPeriodInt > 0) SettingDialog.ReplyPeriodInt = 15;
739                 if (SettingDialog.DMPeriodInt < 15 && SettingDialog.DMPeriodInt > 0) SettingDialog.DMPeriodInt = 15;
740                 if (SettingDialog.PubSearchPeriodInt < 30 && SettingDialog.PubSearchPeriodInt > 0) SettingDialog.PubSearchPeriodInt = 30;
741                 if (SettingDialog.UserTimelinePeriodInt < 15 && SettingDialog.UserTimelinePeriodInt > 0) SettingDialog.UserTimelinePeriodInt = 15;
742                 if (SettingDialog.ListsPeriodInt < 15 && SettingDialog.ListsPeriodInt > 0) SettingDialog.ListsPeriodInt = 15;
743             }
744
745             //起動時読み込み分を既読にするか。trueなら既読として処理
746             SettingDialog.Readed = _cfgCommon.Read;
747             //新着取得時のリストスクロールをするか。trueならスクロールしない
748             ListLockMenuItem.Checked = _cfgCommon.ListLock;
749             this.LockListFileMenuItem.Checked = _cfgCommon.ListLock;
750             SettingDialog.IconSz = _cfgCommon.IconSize;
751             //文末ステータス
752             SettingDialog.Status = _cfgLocal.StatusText;
753             //未読管理。trueなら未読管理する
754             SettingDialog.UnreadManage = _cfgCommon.UnreadManage;
755             //サウンド再生(タブ別設定より優先)
756             SettingDialog.PlaySound = _cfgCommon.PlaySound;
757             PlaySoundMenuItem.Checked = SettingDialog.PlaySound;
758             this.PlaySoundFileMenuItem.Checked = SettingDialog.PlaySound;
759             //片思い表示。trueなら片思い表示する
760             SettingDialog.OneWayLove = _cfgCommon.OneWayLove;
761             //フォント&文字色&背景色
762             SettingDialog.FontUnread = _fntUnread;
763             SettingDialog.ColorUnread = _clUnread;
764             SettingDialog.FontReaded = _fntReaded;
765             SettingDialog.ColorReaded = _clReaded;
766             SettingDialog.ColorFav = _clFav;
767             SettingDialog.ColorOWL = _clOWL;
768             SettingDialog.ColorRetweet = _clRetweet;
769             SettingDialog.FontDetail = _fntDetail;
770             SettingDialog.ColorDetail = _clDetail;
771             SettingDialog.ColorDetailLink = _clDetailLink;
772             SettingDialog.ColorDetailBackcolor = _clDetailBackcolor;
773             SettingDialog.ColorSelf = _clSelf;
774             SettingDialog.ColorAtSelf = _clAtSelf;
775             SettingDialog.ColorTarget = _clTarget;
776             SettingDialog.ColorAtTarget = _clAtTarget;
777             SettingDialog.ColorAtFromTarget = _clAtFromTarget;
778             SettingDialog.ColorAtTo = _clAtTo;
779             SettingDialog.ColorListBackcolor = _clListBackcolor;
780             SettingDialog.ColorInputBackcolor = _clInputBackcolor;
781             SettingDialog.ColorInputFont = _clInputFont;
782             SettingDialog.FontInputFont = _fntInputFont;
783
784             SettingDialog.NameBalloon = _cfgCommon.NameBalloon;
785             SettingDialog.PostCtrlEnter = _cfgCommon.PostCtrlEnter;
786             SettingDialog.PostShiftEnter = _cfgCommon.PostShiftEnter;
787
788             SettingDialog.CountApi = _cfgCommon.CountApi;
789             SettingDialog.CountApiReply = _cfgCommon.CountApiReply;
790             if (SettingDialog.CountApi < 20 || SettingDialog.CountApi > 200) SettingDialog.CountApi = 60;
791             if (SettingDialog.CountApiReply < 20 || SettingDialog.CountApiReply > 200) SettingDialog.CountApiReply = 40;
792
793             SettingDialog.BrowserPath = _cfgLocal.BrowserPath;
794             SettingDialog.PostAndGet = _cfgCommon.PostAndGet;
795             SettingDialog.UseRecommendStatus = _cfgLocal.UseRecommendStatus;
796             SettingDialog.DispUsername = _cfgCommon.DispUsername;
797             SettingDialog.CloseToExit = _cfgCommon.CloseToExit;
798             SettingDialog.MinimizeToTray = _cfgCommon.MinimizeToTray;
799             SettingDialog.DispLatestPost = _cfgCommon.DispLatestPost;
800             SettingDialog.SortOrderLock = _cfgCommon.SortOrderLock;
801             SettingDialog.ViewTabBottom = _cfgCommon.ViewTabBottom;
802             SettingDialog.TinyUrlResolve = _cfgCommon.TinyUrlResolve;
803
804             SettingDialog.SelectedProxyType = _cfgLocal.ProxyType;
805             SettingDialog.ProxyAddress = _cfgLocal.ProxyAddress;
806             SettingDialog.ProxyPort = _cfgLocal.ProxyPort;
807             SettingDialog.ProxyUser = _cfgLocal.ProxyUser;
808             SettingDialog.ProxyPassword = _cfgLocal.ProxyPassword;
809
810             SettingDialog.StartupVersion = _cfgCommon.StartupVersion;
811             SettingDialog.StartupFollowers = _cfgCommon.StartupFollowers;
812             SettingDialog.RestrictFavCheck = _cfgCommon.RestrictFavCheck;
813             SettingDialog.AlwaysTop = _cfgCommon.AlwaysTop;
814             SettingDialog.UrlConvertAuto = false;
815             //SettingDialog.UrlConvertAuto = _cfgCommon.UrlConvertAuto;
816
817             SettingDialog.UseUnreadStyle = _cfgCommon.UseUnreadStyle;
818             SettingDialog.DefaultTimeOut = _cfgCommon.DefaultTimeOut;
819             SettingDialog.RetweetNoConfirm = _cfgCommon.RetweetNoConfirm;
820             SettingDialog.PlaySound = _cfgCommon.PlaySound;
821             SettingDialog.DateTimeFormat = _cfgCommon.DateTimeFormat;
822             SettingDialog.LimitBalloon = _cfgCommon.LimitBalloon;
823             SettingDialog.EventNotifyEnabled = _cfgCommon.EventNotifyEnabled;
824             SettingDialog.EventNotifyFlag = _cfgCommon.EventNotifyFlag;
825             SettingDialog.IsMyEventNotifyFlag = _cfgCommon.IsMyEventNotifyFlag;
826             SettingDialog.ForceEventNotify = _cfgCommon.ForceEventNotify;
827             SettingDialog.FavEventUnread = _cfgCommon.FavEventUnread;
828             SettingDialog.TranslateLanguage = _cfgCommon.TranslateLanguage;
829             SettingDialog.EventSoundFile = _cfgCommon.EventSoundFile;
830
831             //廃止サービスが選択されていた場合bit.lyへ読み替え
832             if (_cfgCommon.AutoShortUrlFirst < 0)
833                 _cfgCommon.AutoShortUrlFirst = MyCommon.UrlConverter.Uxnu;
834
835             SettingDialog.AutoShortUrlFirst = _cfgCommon.AutoShortUrlFirst;
836             SettingDialog.TabIconDisp = _cfgCommon.TabIconDisp;
837             SettingDialog.ReplyIconState = _cfgCommon.ReplyIconState;
838             SettingDialog.ReadOwnPost = _cfgCommon.ReadOwnPost;
839             SettingDialog.GetFav = _cfgCommon.GetFav;
840             SettingDialog.ReadOldPosts = _cfgCommon.ReadOldPosts;
841             SettingDialog.BitlyUser = _cfgCommon.BilyUser;
842             SettingDialog.BitlyPwd = _cfgCommon.BitlyPwd;
843             SettingDialog.ShowGrid = _cfgCommon.ShowGrid;
844             SettingDialog.Language = _cfgCommon.Language;
845             SettingDialog.UseAtIdSupplement = _cfgCommon.UseAtIdSupplement;
846             SettingDialog.UseHashSupplement = _cfgCommon.UseHashSupplement;
847             SettingDialog.PreviewEnable = _cfgCommon.PreviewEnable;
848             SettingDialog.StatusAreaAtBottom = _cfgCommon.StatusAreaAtBottom;
849             AtIdSupl = new AtIdSupplement(SettingAtIdList.Load().AtIdList, "@");
850
851             SettingDialog.IsMonospace = _cfgCommon.IsMonospace;
852
853             this.IdeographicSpaceToSpaceToolStripMenuItem.Checked = _cfgCommon.WideSpaceConvert;
854             this.ToolStripFocusLockMenuItem.Checked = _cfgCommon.FocusLockToStatusText;
855
856             //Regex statregex = new Regex("^0*");
857             SettingDialog.RecommendStatusText = " [TWNv" + Regex.Replace(MyCommon.FileVersion.Replace(".", ""), "^0*", "") + "]";
858
859             //書式指定文字列エラーチェック
860             try
861             {
862                 if (DateTime.Now.ToString(SettingDialog.DateTimeFormat).Length == 0)
863                 {
864                     // このブロックは絶対に実行されないはず
865                     // 変換が成功した場合にLengthが0にならない
866                     SettingDialog.DateTimeFormat = "yyyy/MM/dd H:mm:ss";
867                 }
868             }
869             catch (FormatException)
870             {
871                 // FormatExceptionが発生したら初期値を設定 (=yyyy/MM/dd H:mm:ssとみなされる)
872                 SettingDialog.DateTimeFormat = "yyyy/MM/dd H:mm:ss";
873             }
874
875             SettingDialog.Nicoms = _cfgCommon.Nicoms;
876             SettingDialog.HotkeyEnabled = _cfgCommon.HotkeyEnabled;
877             SettingDialog.HotkeyMod = _cfgCommon.HotkeyModifier;
878             SettingDialog.HotkeyKey = _cfgCommon.HotkeyKey;
879             SettingDialog.HotkeyValue = _cfgCommon.HotkeyValue;
880
881             SettingDialog.BlinkNewMentions = _cfgCommon.BlinkNewMentions;
882
883             SettingDialog.UseAdditionalCount = _cfgCommon.UseAdditionalCount;
884             SettingDialog.MoreCountApi = _cfgCommon.MoreCountApi;
885             SettingDialog.FirstCountApi = _cfgCommon.FirstCountApi;
886             SettingDialog.SearchCountApi = _cfgCommon.SearchCountApi;
887             SettingDialog.FavoritesCountApi = _cfgCommon.FavoritesCountApi;
888             SettingDialog.UserTimelineCountApi = _cfgCommon.UserTimelineCountApi;
889             SettingDialog.ListCountApi = _cfgCommon.ListCountApi;
890
891             SettingDialog.UserstreamStartup = _cfgCommon.UserstreamStartup;
892             SettingDialog.UserstreamPeriodInt = _cfgCommon.UserstreamPeriod;
893             SettingDialog.OpenUserTimeline = _cfgCommon.OpenUserTimeline;
894             SettingDialog.ListDoubleClickAction = _cfgCommon.ListDoubleClickAction;
895             SettingDialog.UserAppointUrl = _cfgCommon.UserAppointUrl;
896             SettingDialog.HideDuplicatedRetweets = _cfgCommon.HideDuplicatedRetweets;
897
898             SettingDialog.EnableImgAzyobuziNet = _cfgCommon.EnableImgAzyobuziNet;
899             SettingDialog.ImgAzyobuziNetDisabledInDM = _cfgCommon.ImgAzyobuziNetDisabledInDM;
900             SettingDialog.MapThumbnailProvider = _cfgCommon.MapThumbnailProvider;
901             SettingDialog.MapThumbnailHeight = _cfgCommon.MapThumbnailHeight;
902             SettingDialog.MapThumbnailWidth = _cfgCommon.MapThumbnailWidth;
903             SettingDialog.MapThumbnailZoom = _cfgCommon.MapThumbnailZoom;
904             SettingDialog.IsListStatusesIncludeRts = _cfgCommon.IsListsIncludeRts;
905             SettingDialog.TabMouseLock = _cfgCommon.TabMouseLock;
906             SettingDialog.IsRemoveSameEvent = _cfgCommon.IsRemoveSameEvent;
907             SettingDialog.IsNotifyUseGrowl = _cfgCommon.IsUseNotifyGrowl;
908
909             //ハッシュタグ関連
910             HashSupl = new AtIdSupplement(_cfgCommon.HashTags, "#");
911             HashMgr = new HashtagManage(HashSupl,
912                                     _cfgCommon.HashTags.ToArray(),
913                                     _cfgCommon.HashSelected,
914                                     _cfgCommon.HashIsPermanent,
915                                     _cfgCommon.HashIsHead,
916                                     _cfgCommon.HashIsNotAddToAtReply);
917             if (!string.IsNullOrEmpty(HashMgr.UseHash) && HashMgr.IsPermanent) HashStripSplitButton.Text = HashMgr.UseHash;
918
919             _initial = true;
920
921             //アイコンリスト作成
922             this.IconCache = new ImageCache(this.http);
923
924             bool saveRequired = false;
925             bool firstRun = false;
926
927             //ユーザー名、パスワードが未設定なら設定画面を表示(初回起動時など)
928             if (string.IsNullOrEmpty(tw.Username))
929             {
930                 saveRequired = true;
931                 firstRun = true;
932                 SettingDialog.ShowInTaskbar = true;
933
934                 //設定せずにキャンセルされた場合はプログラム終了
935                 if (SettingDialog.ShowDialog(this) == DialogResult.Cancel)
936                 {
937                     Application.Exit();  //強制終了
938                     return;
939                 }
940                 //設定されたが、依然ユーザー名とパスワードが未設定ならプログラム終了
941                 if (string.IsNullOrEmpty(tw.Username))
942                 {
943                     Application.Exit();  //強制終了
944                     return;
945                 }
946                 SettingDialog.ShowInTaskbar = false;
947
948                 //新しい設定を反映
949                 //フォント&文字色&背景色保持
950                 _fntUnread = SettingDialog.FontUnread;
951                 _clUnread = SettingDialog.ColorUnread;
952                 _fntReaded = SettingDialog.FontReaded;
953                 _clReaded = SettingDialog.ColorReaded;
954                 _clFav = SettingDialog.ColorFav;
955                 _clOWL = SettingDialog.ColorOWL;
956                 _clRetweet = SettingDialog.ColorRetweet;
957                 _fntDetail = SettingDialog.FontDetail;
958                 _clDetail = SettingDialog.ColorDetail;
959                 _clDetailLink = SettingDialog.ColorDetailLink;
960                 _clDetailBackcolor = SettingDialog.ColorDetailBackcolor;
961                 _clSelf = SettingDialog.ColorSelf;
962                 _clAtSelf = SettingDialog.ColorAtSelf;
963                 _clTarget = SettingDialog.ColorTarget;
964                 _clAtTarget = SettingDialog.ColorAtTarget;
965                 _clAtFromTarget = SettingDialog.ColorAtFromTarget;
966                 _clAtTo = SettingDialog.ColorAtTo;
967                 _clListBackcolor = SettingDialog.ColorListBackcolor;
968                 _clInputBackcolor = SettingDialog.ColorInputBackcolor;
969                 _clInputFont = SettingDialog.ColorInputFont;
970                 _fntInputFont = SettingDialog.FontInputFont;
971
972                 //他の設定項目は、随時設定画面で保持している値を読み出して使用
973             }
974
975             _brsBackColorMine = new SolidBrush(_clSelf);
976             _brsBackColorAt = new SolidBrush(_clAtSelf);
977             _brsBackColorYou = new SolidBrush(_clTarget);
978             _brsBackColorAtYou = new SolidBrush(_clAtTarget);
979             _brsBackColorAtFromTarget = new SolidBrush(_clAtFromTarget);
980             _brsBackColorAtTo = new SolidBrush(_clAtTo);
981             //_brsBackColorNone = new SolidBrush(Color.FromKnownColor(KnownColor.Window));
982             _brsBackColorNone = new SolidBrush(_clListBackcolor);
983
984             InitDetailHtmlFormat();
985
986             if (SettingDialog.HotkeyEnabled)
987             {
988                 //////グローバルホットキーの登録
989                 HookGlobalHotkey.ModKeys modKey = HookGlobalHotkey.ModKeys.None;
990                 if ((SettingDialog.HotkeyMod & Keys.Alt) == Keys.Alt) modKey = modKey | HookGlobalHotkey.ModKeys.Alt;
991                 if ((SettingDialog.HotkeyMod & Keys.Control) == Keys.Control) modKey = modKey | HookGlobalHotkey.ModKeys.Ctrl;
992                 if ((SettingDialog.HotkeyMod & Keys.Shift) == Keys.Shift) modKey = modKey | HookGlobalHotkey.ModKeys.Shift;
993                 if ((SettingDialog.HotkeyMod & Keys.LWin) == Keys.LWin) modKey = modKey | HookGlobalHotkey.ModKeys.Win;
994
995                 _hookGlobalHotkey.RegisterOriginalHotkey(SettingDialog.HotkeyKey, SettingDialog.HotkeyValue, modKey);
996             }
997
998             //Twitter用通信クラス初期化
999             HttpConnection.InitializeConnection(SettingDialog.DefaultTimeOut,
1000                                                 SettingDialog.SelectedProxyType,
1001                                                 SettingDialog.ProxyAddress,
1002                                                 SettingDialog.ProxyPort,
1003                                                 SettingDialog.ProxyUser,
1004                                                 SettingDialog.ProxyPassword);
1005
1006             tw.RestrictFavCheck = SettingDialog.RestrictFavCheck;
1007             tw.ReadOwnPost = SettingDialog.ReadOwnPost;
1008             ShortUrl.Instance.DisableExpanding = !SettingDialog.TinyUrlResolve;
1009             ShortUrl.Instance.BitlyId = SettingDialog.BitlyUser;
1010             ShortUrl.Instance.BitlyKey = SettingDialog.BitlyPwd;
1011             HttpTwitter.TwitterUrl = _cfgCommon.TwitterUrl;
1012             tw.TrackWord = _cfgCommon.TrackWord;
1013             TrackToolStripMenuItem.Checked = !String.IsNullOrEmpty(tw.TrackWord);
1014             tw.AllAtReply = _cfgCommon.AllAtReply;
1015             AllrepliesToolStripMenuItem.Checked = tw.AllAtReply;
1016
1017             //画像投稿サービス
1018             ImageSelector.Initialize(tw, _cfgCommon.UseImageServiceName, _cfgCommon.UseImageService);
1019
1020             //ウィンドウ設定
1021             this.ClientSize = _cfgLocal.FormSize;
1022             _mySize = _cfgLocal.FormSize;                     //サイズ保持(最小化・最大化されたまま終了した場合の対応用)
1023             _myLoc = _cfgLocal.FormLocation;
1024             //タイトルバー領域
1025             if (this.WindowState != FormWindowState.Minimized)
1026             {
1027                 this.DesktopLocation = _cfgLocal.FormLocation;
1028                 Rectangle tbarRect = new Rectangle(this.Location, new Size(_mySize.Width, SystemInformation.CaptionHeight));
1029                 bool outOfScreen = true;
1030                 if (Screen.AllScreens.Length == 1)    //ハングするとの報告
1031                 {
1032                     foreach (Screen scr in Screen.AllScreens)
1033                     {
1034                         if (!Rectangle.Intersect(tbarRect, scr.Bounds).IsEmpty)
1035                         {
1036                             outOfScreen = false;
1037                             break;
1038                         }
1039                     }
1040                     if (outOfScreen)
1041                     {
1042                         this.DesktopLocation = new Point(0, 0);
1043                         _myLoc = this.DesktopLocation;
1044                     }
1045                 }
1046             }
1047             this.TopMost = SettingDialog.AlwaysTop;
1048             _mySpDis = _cfgLocal.SplitterDistance;
1049             _mySpDis2 = _cfgLocal.StatusTextHeight;
1050             _mySpDis3 = _cfgLocal.PreviewDistance;
1051             if (_mySpDis3 == -1)
1052             {
1053                 _mySpDis3 = _mySize.Width - 150;
1054                 if (_mySpDis3 < 1) _mySpDis3 = 50;
1055                 _cfgLocal.PreviewDistance = _mySpDis3;
1056             }
1057             MultiLineMenuItem.Checked = _cfgLocal.StatusMultiline;
1058             //this.Tween_ClientSizeChanged(this, null);
1059             PlaySoundMenuItem.Checked = SettingDialog.PlaySound;
1060             this.PlaySoundFileMenuItem.Checked = SettingDialog.PlaySound;
1061             //入力欄
1062             StatusText.Font = _fntInputFont;
1063             StatusText.ForeColor = _clInputFont;
1064
1065             // NameLabel のフォントを OTBaseForm.GlobalFont に変更
1066             this.NameLabel.Font = this.ReplaceToGlobalFont(this.NameLabel.Font);
1067
1068             // 必要であれば、発言一覧と発言詳細部・入力欄の上下を入れ替える
1069             SplitContainer1.IsPanelInverted = !SettingDialog.StatusAreaAtBottom;
1070
1071             //全新着通知のチェック状態により、Reply&DMの新着通知有効無効切り替え(タブ別設定にするため削除予定)
1072             if (SettingDialog.UnreadManage == false)
1073             {
1074                 ReadedStripMenuItem.Enabled = false;
1075                 UnreadStripMenuItem.Enabled = false;
1076             }
1077
1078             if (SettingDialog.IsNotifyUseGrowl) gh.RegisterGrowl();
1079
1080             //タイマー設定
1081             TimerTimeline.AutoReset = true;
1082             TimerTimeline.SynchronizingObject = this;
1083             //Recent取得間隔
1084             TimerTimeline.Interval = 1000;
1085             TimerTimeline.Enabled = true;
1086
1087             //更新中アイコンアニメーション間隔
1088             TimerRefreshIcon.Interval = 200;
1089             TimerRefreshIcon.Enabled = true;
1090
1091             //状態表示部の初期化(画面右下)
1092             StatusLabel.Text = "";
1093             StatusLabel.AutoToolTip = false;
1094             StatusLabel.ToolTipText = "";
1095             //文字カウンタ初期化
1096             lblLen.Text = GetRestStatusCount(true, false).ToString();
1097
1098             ////////////////////////////////////////////////////////////////////////////////
1099             _statuses.SortOrder = (SortOrder)_cfgCommon.SortOrder;
1100             IdComparerClass.ComparerMode mode = IdComparerClass.ComparerMode.Id;
1101             switch (_cfgCommon.SortColumn)
1102             {
1103                 case 0:    //0:アイコン,5:未読マーク,6:プロテクト・フィルターマーク
1104                 case 5:
1105                 case 6:
1106                     //ソートしない
1107                     mode = IdComparerClass.ComparerMode.Id;  //Idソートに読み替え
1108                     break;
1109                 case 1:  //ニックネーム
1110                     mode = IdComparerClass.ComparerMode.Nickname;
1111                     break;
1112                 case 2:  //本文
1113                     mode = IdComparerClass.ComparerMode.Data;
1114                     break;
1115                 case 3:  //時刻=発言Id
1116                     mode = IdComparerClass.ComparerMode.Id;
1117                     break;
1118                 case 4:  //名前
1119                     mode = IdComparerClass.ComparerMode.Name;
1120                     break;
1121                 case 7:  //Source
1122                     mode = IdComparerClass.ComparerMode.Source;
1123                     break;
1124             }
1125             _statuses.SortMode = mode;
1126             ////////////////////////////////////////////////////////////////////////////////
1127
1128             ApplyListViewIconSize(SettingDialog.IconSz);
1129
1130             tw.TinyUrlResolve = SettingDialog.TinyUrlResolve;
1131
1132             StatusLabel.Text = Properties.Resources.Form1_LoadText1;       //画面右下の状態表示を変更
1133             StatusLabelUrl.Text = "";            //画面左下のリンク先URL表示部を初期化
1134             NameLabel.Text = "";                 //発言詳細部名前ラベル初期化
1135             DateTimeLabel.Text = "";             //発言詳細部日時ラベル初期化
1136             SourceLinkLabel.Text = "";           //Source部分初期化
1137
1138             //<<<<<<<<タブ関連>>>>>>>
1139             //デフォルトタブの存在チェック、ない場合には追加
1140             if (_statuses.GetTabByType(MyCommon.TabUsageType.Home) == null)
1141             {
1142                 TabClass tab;
1143                 if (!_statuses.Tabs.TryGetValue(MyCommon.DEFAULTTAB.RECENT, out tab))
1144                 {
1145                     _statuses.AddTab(MyCommon.DEFAULTTAB.RECENT, MyCommon.TabUsageType.Home, null);
1146                 }
1147                 else
1148                 {
1149                     tab.TabType = MyCommon.TabUsageType.Home;
1150                 }
1151             }
1152             if (_statuses.GetTabByType(MyCommon.TabUsageType.Mentions) == null)
1153             {
1154                 TabClass tab;
1155                 if (!_statuses.Tabs.TryGetValue(MyCommon.DEFAULTTAB.REPLY, out tab))
1156                 {
1157                     _statuses.AddTab(MyCommon.DEFAULTTAB.REPLY, MyCommon.TabUsageType.Mentions, null);
1158                 }
1159                 else
1160                 {
1161                     tab.TabType = MyCommon.TabUsageType.Mentions;
1162                 }
1163             }
1164             if (_statuses.GetTabByType(MyCommon.TabUsageType.DirectMessage) == null)
1165             {
1166                 TabClass tab;
1167                 if (!_statuses.Tabs.TryGetValue(MyCommon.DEFAULTTAB.DM, out tab))
1168                 {
1169                     _statuses.AddTab(MyCommon.DEFAULTTAB.DM, MyCommon.TabUsageType.DirectMessage, null);
1170                 }
1171                 else
1172                 {
1173                     tab.TabType = MyCommon.TabUsageType.DirectMessage;
1174                 }
1175             }
1176             if (_statuses.GetTabByType(MyCommon.TabUsageType.Favorites) == null)
1177             {
1178                 TabClass tab;
1179                 if (!_statuses.Tabs.TryGetValue(MyCommon.DEFAULTTAB.FAV, out tab))
1180                 {
1181                     _statuses.AddTab(MyCommon.DEFAULTTAB.FAV, MyCommon.TabUsageType.Favorites, null);
1182                 }
1183                 else
1184                 {
1185                     tab.TabType = MyCommon.TabUsageType.Favorites;
1186                 }
1187             }
1188             foreach (var tab in _statuses.Tabs.Values)
1189             {
1190                 if (tab.TabType == MyCommon.TabUsageType.Undefined)
1191                 {
1192                     tab.TabType = MyCommon.TabUsageType.UserDefined;
1193                 }
1194                 if (!AddNewTab(tab.TabName, true, tab.TabType, tab.ListInfo)) throw new Exception(Properties.Resources.TweenMain_LoadText1);
1195             }
1196
1197             this.JumpReadOpMenuItem.ShortcutKeyDisplayString = "Space";
1198             CopySTOTMenuItem.ShortcutKeyDisplayString = "Ctrl+C";
1199             CopyURLMenuItem.ShortcutKeyDisplayString = "Ctrl+Shift+C";
1200             CopyUserIdStripMenuItem.ShortcutKeyDisplayString = "Shift+Alt+C";
1201
1202             if (SettingDialog.MinimizeToTray == false || this.WindowState != FormWindowState.Minimized)
1203             {
1204                 this.Visible = true;
1205             }
1206             _curTab = ListTab.SelectedTab;
1207             _curItemIndex = -1;
1208             _curList = (DetailsListView)_curTab.Tag;
1209             SetMainWindowTitle();
1210             SetNotifyIconText();
1211
1212             if (SettingDialog.TabIconDisp)
1213             {
1214                 ListTab.DrawMode = TabDrawMode.Normal;
1215             }
1216             else
1217             {
1218                 ListTab.DrawMode = TabDrawMode.OwnerDrawFixed;
1219                 ListTab.DrawItem += ListTab_DrawItem;
1220                 ListTab.ImageList = null;
1221             }
1222
1223             _ignoreConfigSave = false;
1224             this.TweenMain_Resize(null, null);
1225             if (saveRequired) SaveConfigsAll(false);
1226
1227             if (tw.UserId == 0)
1228             {
1229                 tw.VerifyCredentials();
1230                 foreach (UserAccount ua in _cfgCommon.UserAccounts)
1231                 {
1232                     if (ua.Username.ToLower() == tw.Username.ToLower())
1233                     {
1234                         ua.UserId = tw.UserId;
1235                         break;
1236                     }
1237                 }
1238             }
1239             foreach (UserAccount ua in SettingDialog.UserAccounts)
1240             {
1241                 if (ua.UserId == 0 && ua.Username.ToLower() == tw.Username.ToLower())
1242                 {
1243                     ua.UserId = tw.UserId;
1244                     break;
1245                 }
1246             }
1247
1248             if (firstRun)
1249             {
1250                 // 初回起動時だけ右下のメニューを目立たせる
1251                 HashStripSplitButton.ShowDropDown();
1252             }
1253
1254             // タブの位置を調整する
1255             SetTabAlignment();
1256         }
1257
1258         private void InitDetailHtmlFormat()
1259         {
1260             if (SettingDialog.IsMonospace)
1261             {
1262                 detailHtmlFormatHeader = detailHtmlFormatMono1;
1263                 detailHtmlFormatFooter = detailHtmlFormatMono7;
1264             }
1265             else
1266             {
1267                 detailHtmlFormatHeader = detailHtmlFormat1;
1268                 detailHtmlFormatFooter = detailHtmlFormat7;
1269             }
1270             detailHtmlFormatHeader += _fntDetail.Name + detailHtmlFormat2 + _fntDetail.Size.ToString() + detailHtmlFormat3 + _clDetail.R.ToString() + "," + _clDetail.G.ToString() + "," + _clDetail.B.ToString() + detailHtmlFormat4 + _clDetailLink.R.ToString() + "," + _clDetailLink.G.ToString() + "," + _clDetailLink.B.ToString() + detailHtmlFormat5 + _clDetailBackcolor.R.ToString() + "," + _clDetailBackcolor.G.ToString() + "," + _clDetailBackcolor.B.ToString();
1271             if (SettingDialog.IsMonospace)
1272             {
1273                 detailHtmlFormatHeader += detailHtmlFormatMono6;
1274             }
1275             else
1276             {
1277                 detailHtmlFormatHeader += detailHtmlFormat6;
1278             }
1279         }
1280
1281         private void ListTab_DrawItem(object sender, DrawItemEventArgs e)
1282         {
1283             string txt;
1284             try
1285             {
1286                 txt = ListTab.TabPages[e.Index].Text;
1287             }
1288             catch (Exception)
1289             {
1290                 return;
1291             }
1292
1293             e.Graphics.FillRectangle(System.Drawing.SystemBrushes.Control, e.Bounds);
1294             if (e.State == DrawItemState.Selected)
1295             {
1296                 e.DrawFocusRectangle();
1297             }
1298             Brush fore;
1299             try
1300             {
1301                 if (_statuses.Tabs[txt].UnreadCount > 0)
1302                     fore = Brushes.Red;
1303                 else
1304                     fore = System.Drawing.SystemBrushes.ControlText;
1305             }
1306             catch (Exception)
1307             {
1308                 fore = System.Drawing.SystemBrushes.ControlText;
1309             }
1310             e.Graphics.DrawString(txt, e.Font, fore, e.Bounds, sfTab);
1311         }
1312
1313         private void LoadConfig()
1314         {
1315             _cfgCommon = SettingCommon.Load();
1316             if (_cfgCommon.UserAccounts == null || _cfgCommon.UserAccounts.Count == 0)
1317             {
1318                 _cfgCommon.UserAccounts = new List<UserAccount>();
1319                 if (!string.IsNullOrEmpty(_cfgCommon.UserName))
1320                 {
1321                     UserAccount account = new UserAccount();
1322                     account.Username = _cfgCommon.UserName;
1323                     account.UserId = _cfgCommon.UserId;
1324                     account.Token = _cfgCommon.Token;
1325                     account.TokenSecret = _cfgCommon.TokenSecret;
1326
1327                     _cfgCommon.UserAccounts.Add(account);
1328                 }
1329             }
1330             _cfgLocal = SettingLocal.Load();
1331             List<TabClass> tabs = SettingTabs.Load().Tabs;
1332             foreach (TabClass tb in tabs)
1333             {
1334                 try
1335                 {
1336                     _statuses.Tabs.Add(tb.TabName, tb);
1337                 }
1338                 catch (Exception)
1339                 {
1340                     tb.TabName = _statuses.GetUniqueTabName();
1341                     _statuses.Tabs.Add(tb.TabName, tb);
1342                 }
1343             }
1344             if (_statuses.Tabs.Count == 0)
1345             {
1346                 _statuses.AddTab(MyCommon.DEFAULTTAB.RECENT, MyCommon.TabUsageType.Home, null);
1347                 _statuses.AddTab(MyCommon.DEFAULTTAB.REPLY, MyCommon.TabUsageType.Mentions, null);
1348                 _statuses.AddTab(MyCommon.DEFAULTTAB.DM, MyCommon.TabUsageType.DirectMessage, null);
1349                 _statuses.AddTab(MyCommon.DEFAULTTAB.FAV, MyCommon.TabUsageType.Favorites, null);
1350             }
1351         }
1352
1353         private void TimerInterval_Changed(object sender, AppendSettingDialog.IntervalChangedEventArgs e) //Handles SettingDialog.IntervalChanged
1354         {
1355             if (!TimerTimeline.Enabled) return;
1356             ResetTimers = e;
1357         }
1358
1359         private AppendSettingDialog.IntervalChangedEventArgs ResetTimers = new AppendSettingDialog.IntervalChangedEventArgs();
1360
1361         private static int homeCounter = 0;
1362         private static int mentionCounter = 0;
1363         private static int dmCounter = 0;
1364         private static int pubSearchCounter = 0;
1365         private static int userTimelineCounter = 0;
1366         private static int listsCounter = 0;
1367         private static int usCounter = 0;
1368         private static int ResumeWait = 0;
1369         private static int refreshFollowers = 0;
1370
1371         private void TimerTimeline_Elapsed(object sender, EventArgs e)
1372         {
1373             if (homeCounter > 0) Interlocked.Decrement(ref homeCounter);
1374             if (mentionCounter > 0) Interlocked.Decrement(ref mentionCounter);
1375             if (dmCounter > 0) Interlocked.Decrement(ref dmCounter);
1376             if (pubSearchCounter > 0) Interlocked.Decrement(ref pubSearchCounter);
1377             if (userTimelineCounter > 0) Interlocked.Decrement(ref userTimelineCounter);
1378             if (listsCounter > 0) Interlocked.Decrement(ref listsCounter);
1379             if (usCounter > 0) Interlocked.Decrement(ref usCounter);
1380             Interlocked.Increment(ref refreshFollowers);
1381
1382             ////タイマー初期化
1383             if (ResetTimers.Timeline || homeCounter <= 0 && SettingDialog.TimelinePeriodInt > 0)
1384             {
1385                 Interlocked.Exchange(ref homeCounter, SettingDialog.TimelinePeriodInt);
1386                 if (!tw.IsUserstreamDataReceived && !ResetTimers.Timeline) GetTimeline(MyCommon.WORKERTYPE.Timeline, 1, 0, "");
1387                 ResetTimers.Timeline = false;
1388             }
1389             if (ResetTimers.Reply || mentionCounter <= 0 && SettingDialog.ReplyPeriodInt > 0)
1390             {
1391                 Interlocked.Exchange(ref mentionCounter, SettingDialog.ReplyPeriodInt);
1392                 if (!tw.IsUserstreamDataReceived && !ResetTimers.Reply) GetTimeline(MyCommon.WORKERTYPE.Reply, 1, 0, "");
1393                 ResetTimers.Reply = false;
1394             }
1395             if (ResetTimers.DirectMessage || dmCounter <= 0 && SettingDialog.DMPeriodInt > 0)
1396             {
1397                 Interlocked.Exchange(ref dmCounter, SettingDialog.DMPeriodInt);
1398                 if (!tw.IsUserstreamDataReceived && !ResetTimers.DirectMessage) GetTimeline(MyCommon.WORKERTYPE.DirectMessegeRcv, 1, 0, "");
1399                 ResetTimers.DirectMessage = false;
1400             }
1401             if (ResetTimers.PublicSearch || pubSearchCounter <= 0 && SettingDialog.PubSearchPeriodInt > 0)
1402             {
1403                 Interlocked.Exchange(ref pubSearchCounter, SettingDialog.PubSearchPeriodInt);
1404                 if (!ResetTimers.PublicSearch) GetTimeline(MyCommon.WORKERTYPE.PublicSearch, 1, 0, "");
1405                 ResetTimers.PublicSearch = false;
1406             }
1407             if (ResetTimers.UserTimeline || userTimelineCounter <= 0 && SettingDialog.UserTimelinePeriodInt > 0)
1408             {
1409                 Interlocked.Exchange(ref userTimelineCounter, SettingDialog.UserTimelinePeriodInt);
1410                 if (!ResetTimers.UserTimeline) GetTimeline(MyCommon.WORKERTYPE.UserTimeline, 1, 0, "");
1411                 ResetTimers.UserTimeline = false;
1412             }
1413             if (ResetTimers.Lists || listsCounter <= 0 && SettingDialog.ListsPeriodInt > 0)
1414             {
1415                 Interlocked.Exchange(ref listsCounter, SettingDialog.ListsPeriodInt);
1416                 if (!ResetTimers.Lists) GetTimeline(MyCommon.WORKERTYPE.List, 1, 0, "");
1417                 ResetTimers.Lists = false;
1418             }
1419             if (ResetTimers.UserStream || usCounter <= 0 && SettingDialog.UserstreamPeriodInt > 0)
1420             {
1421                 Interlocked.Exchange(ref usCounter, SettingDialog.UserstreamPeriodInt);
1422                 if (this._isActiveUserstream) RefreshTimeline(true);
1423                 ResetTimers.UserStream = false;
1424             }
1425             if (refreshFollowers > 6 * 3600)
1426             {
1427                 Interlocked.Exchange(ref refreshFollowers, 0);
1428                 doGetFollowersMenu();
1429                 GetTimeline(MyCommon.WORKERTYPE.NoRetweetIds, 0, 0, "");
1430                 GetTimeline(MyCommon.WORKERTYPE.Configuration, 0, 0, "");
1431             }
1432             if (osResumed)
1433             {
1434                 Interlocked.Increment(ref ResumeWait);
1435                 if (ResumeWait > 30)
1436                 {
1437                     osResumed = false;
1438                     Interlocked.Exchange(ref ResumeWait, 0);
1439                     GetTimeline(MyCommon.WORKERTYPE.Timeline, 1, 0, "");
1440                     GetTimeline(MyCommon.WORKERTYPE.Reply, 1, 0, "");
1441                     GetTimeline(MyCommon.WORKERTYPE.DirectMessegeRcv, 1, 0, "");
1442                     GetTimeline(MyCommon.WORKERTYPE.PublicSearch, 1, 0, "");
1443                     GetTimeline(MyCommon.WORKERTYPE.UserTimeline, 1, 0, "");
1444                     GetTimeline(MyCommon.WORKERTYPE.List, 1, 0, "");
1445                     doGetFollowersMenu();
1446                     GetTimeline(MyCommon.WORKERTYPE.Configuration, 0, 0, "");
1447                 }
1448             }
1449         }
1450
1451         private void RefreshTimeline(bool isUserStream)
1452         {
1453             if (isUserStream) this.RefreshTasktrayIcon(true);
1454             //スクロール制御準備
1455             int smode = -1;    //-1:制御しない,-2:最新へ,その他:topitem使用
1456             long topId = GetScrollPos(ref smode);
1457             int befCnt = _curList.VirtualListSize;
1458
1459             //現在の選択状態を退避
1460             Dictionary<string, long[]> selId = new Dictionary<string, long[]>();
1461             Dictionary<string, long[]> focusedId = new Dictionary<string, long[]>();
1462             SaveSelectedStatus(selId, focusedId);
1463
1464             //mentionsの更新前件数を保持
1465             int dmCount = _statuses.GetTabByType(MyCommon.TabUsageType.DirectMessage).AllCount;
1466
1467             //更新確定
1468             PostClass[] notifyPosts = null;
1469             string soundFile = "";
1470             int addCount = 0;
1471             bool isMention = false;
1472             bool isDelete = false;
1473             addCount = _statuses.SubmitUpdate(ref soundFile, ref notifyPosts, ref isMention, ref isDelete, isUserStream);
1474
1475             if (MyCommon._endingFlag) return;
1476
1477             //リストに反映&選択状態復元
1478             try
1479             {
1480                 foreach (TabPage tab in ListTab.TabPages)
1481                 {
1482                     DetailsListView lst = (DetailsListView)tab.Tag;
1483                     TabClass tabInfo = _statuses.Tabs[tab.Text];
1484                     using (ControlTransaction.Update(lst))
1485                     {
1486                         if (isDelete || lst.VirtualListSize != tabInfo.AllCount)
1487                         {
1488                             if (lst.Equals(_curList))
1489                             {
1490                                 this.PurgeListViewItemCache();
1491                             }
1492                             try
1493                             {
1494                                 lst.VirtualListSize = tabInfo.AllCount; //リスト件数更新
1495                             }
1496                             catch (Exception)
1497                             {
1498                                 //アイコン描画不具合あり?
1499                             }
1500                             this.SelectListItem(lst,
1501                                                 _statuses.IndexOf(tab.Text, selId[tab.Text]),
1502                                                 _statuses.IndexOf(tab.Text, focusedId[tab.Text]));
1503                         }
1504                     }
1505                     if (tabInfo.UnreadCount > 0)
1506                         if (SettingDialog.TabIconDisp)
1507                             if (tab.ImageIndex == -1) tab.ImageIndex = 0; //タブアイコン
1508                 }
1509                 if (!SettingDialog.TabIconDisp) ListTab.Refresh();
1510             }
1511             catch (Exception)
1512             {
1513                 //ex.Data["Msg"] = "Ref1, UseAPI=" + SettingDialog.UseAPI.ToString();
1514                 //throw;
1515             }
1516
1517             //スクロール制御後処理
1518             if (smode != -1)
1519             {
1520                 try
1521                 {
1522                     if (befCnt != _curList.VirtualListSize)
1523                     {
1524                         switch (smode)
1525                         {
1526                             case -3:
1527                                 //最上行
1528                                 if (_curList.VirtualListSize > 0) _curList.EnsureVisible(0);
1529                                 break;
1530                             case -2:
1531                                 //最下行へ
1532                                 if (_curList.VirtualListSize > 0) _curList.EnsureVisible(_curList.VirtualListSize - 1);
1533                                 break;
1534                             case -1:
1535                                 //制御しない
1536                                 break;
1537                             default:
1538                                 //表示位置キープ
1539                                 if (_curList.VirtualListSize > 0 && _statuses.IndexOf(_curTab.Text, topId) > -1)
1540                                 {
1541                                     _curList.EnsureVisible(_curList.VirtualListSize - 1);
1542                                     _curList.EnsureVisible(_statuses.IndexOf(_curTab.Text, topId));
1543                                 }
1544                                 break;
1545                         }
1546                     }
1547                 }
1548                 catch (Exception ex)
1549                 {
1550                     ex.Data["Msg"] = "Ref2";
1551                     throw;
1552                 }
1553             }
1554
1555             //新着通知
1556             NotifyNewPosts(notifyPosts,
1557                            soundFile,
1558                            addCount,
1559                            isMention || dmCount != _statuses.GetTabByType(MyCommon.TabUsageType.DirectMessage).AllCount);
1560
1561             SetMainWindowTitle();
1562             if (!StatusLabelUrl.Text.StartsWith("http")) SetStatusLabelUrl();
1563
1564             HashSupl.AddRangeItem(tw.GetHashList());
1565
1566         }
1567
1568         private long GetScrollPos(ref int smode)
1569         {
1570             long topId = -1;
1571             if (_curList != null && _curTab != null && _curList.VirtualListSize > 0)
1572             {
1573                 if (_statuses.SortMode == IdComparerClass.ComparerMode.Id)
1574                 {
1575                     if (_statuses.SortOrder == SortOrder.Ascending)
1576                     {
1577                         //Id昇順
1578                         if (ListLockMenuItem.Checked)
1579                         {
1580                             //制御しない
1581                             smode = -1;
1582                             ////現在表示位置へ強制スクロール
1583                             //if (_curList.TopItem != null) topId = _statuses.GetId(_curTab.Text, _curList.TopItem.Index);
1584                             //smode = 0;
1585                         }
1586                         else
1587                         {
1588                             //最下行が表示されていたら、最下行へ強制スクロール。最下行が表示されていなかったら制御しない
1589                             ListViewItem _item;
1590                             _item = _curList.GetItemAt(0, _curList.ClientSize.Height - 1);   //一番下
1591                             if (_item == null) _item = _curList.Items[_curList.VirtualListSize - 1];
1592                             if (_item.Index == _curList.VirtualListSize - 1)
1593                             {
1594                                 smode = -2;
1595                             }
1596                             else
1597                             {
1598                                 smode = -1;
1599                                 //if (_curList.TopItem != null) topId = _statuses.GetId(_curTab.Text, _curList.TopItem.Index);
1600                                 //smode = 0;
1601                             }
1602                         }
1603                     }
1604                     else
1605                     {
1606                         //Id降順
1607                         if (ListLockMenuItem.Checked)
1608                         {
1609                             //現在表示位置へ強制スクロール
1610                             if (_curList.TopItem != null) topId = _statuses.GetId(_curTab.Text, _curList.TopItem.Index);
1611                             smode = 0;
1612                         }
1613                         else
1614                         {
1615                             //最上行が表示されていたら、制御しない。最上行が表示されていなかったら、現在表示位置へ強制スクロール
1616                             ListViewItem _item;
1617
1618                             _item = _curList.GetItemAt(0, 10);     //一番上
1619                             if (_item == null) _item = _curList.Items[0];
1620                             if (_item.Index == 0)
1621                             {
1622                                 smode = -3;  //最上行
1623                             }
1624                             else
1625                             {
1626                                 if (_curList.TopItem != null) topId = _statuses.GetId(_curTab.Text, _curList.TopItem.Index);
1627                                 smode = 0;
1628                             }
1629                         }
1630                     }
1631                 }
1632                 else
1633                 {
1634                     //現在表示位置へ強制スクロール
1635                     if (_curList.TopItem != null) topId = _statuses.GetId(_curTab.Text, _curList.TopItem.Index);
1636                     smode = 0;
1637                 }
1638             }
1639             else
1640             {
1641                 smode = -1;
1642             }
1643             return topId;
1644         }
1645
1646         private void SaveSelectedStatus(Dictionary<string, long[]> selId, Dictionary<string, long[]> focusedId)
1647         {
1648             if (MyCommon._endingFlag) return;
1649             foreach (TabPage tab in ListTab.TabPages)
1650             {
1651                 DetailsListView lst = (DetailsListView)tab.Tag;
1652                 if (lst.SelectedIndices.Count > 0 && lst.SelectedIndices.Count < 61)
1653                 {
1654                     selId.Add(tab.Text, _statuses.GetId(tab.Text, lst.SelectedIndices));
1655                 }
1656                 else
1657                 {
1658                     selId.Add(tab.Text, new long[1] {-2});
1659                 }
1660
1661                 var fIds = new long[2];  // 0 = focus, 1 = selection mark
1662                 var item = lst.FocusedItem;
1663                 fIds[0] = (item != null) ? _statuses.GetId(tab.Text, item.Index) : -2;
1664                 var mIdx = lst.SelectionMark;
1665                 fIds[1] = (mIdx > -1) ? _statuses.GetId(tab.Text, mIdx) : -2;
1666                 focusedId.Add(tab.Text, fIds);
1667             }
1668
1669         }
1670
1671         private bool BalloonRequired()
1672         {
1673             Twitter.FormattedEvent ev = new Twitter.FormattedEvent();
1674             ev.Eventtype = MyCommon.EVENTTYPE.None;
1675
1676             return BalloonRequired(ev);
1677         }
1678
1679         private bool IsEventNotifyAsEventType(MyCommon.EVENTTYPE type)
1680         {
1681             return SettingDialog.EventNotifyEnabled && (type & SettingDialog.EventNotifyFlag) != 0 || type == MyCommon.EVENTTYPE.None;
1682         }
1683
1684         private bool IsMyEventNotityAsEventType(Twitter.FormattedEvent ev)
1685         {
1686             return (ev.Eventtype & SettingDialog.IsMyEventNotifyFlag) != 0 ? true : !ev.IsMe;
1687         }
1688
1689         private bool BalloonRequired(Twitter.FormattedEvent ev)
1690         {
1691             if ((
1692                 IsEventNotifyAsEventType(ev.Eventtype) && IsMyEventNotityAsEventType(ev) &&
1693                 (NewPostPopMenuItem.Checked || (SettingDialog.ForceEventNotify && ev.Eventtype != MyCommon.EVENTTYPE.None)) &&
1694                 !_initial &&
1695                 (
1696                     (
1697                         SettingDialog.LimitBalloon &&
1698                         (
1699                             this.WindowState == FormWindowState.Minimized ||
1700                             !this.Visible ||
1701                             Form.ActiveForm == null
1702                             )
1703                         ) ||
1704                     !SettingDialog.LimitBalloon
1705                     )
1706                 ) &&
1707                 !Win32Api.IsScreenSaverRunning())
1708             {
1709                 return true;
1710             }
1711             else
1712             {
1713                 return false;
1714             }
1715         }
1716
1717         private void NotifyNewPosts(PostClass[] notifyPosts, string soundFile, int addCount, bool newMentions)
1718         {
1719             if (notifyPosts != null &&
1720                 notifyPosts.Length > 0 &&
1721                 this.SettingDialog.ReadOwnPost &&
1722                 notifyPosts.All((post) => { return post.UserId == tw.UserId || post.ScreenName == tw.Username; }))
1723             {
1724                 return;
1725             }
1726
1727             //新着通知
1728             if (BalloonRequired())
1729             {
1730                 if (notifyPosts != null && notifyPosts.Length > 0)
1731                 {
1732                     //Growlは一個ずつばらして通知。ただし、3ポスト以上あるときはまとめる
1733                     if (SettingDialog.IsNotifyUseGrowl)
1734                     {
1735                         StringBuilder sb = new StringBuilder();
1736                         bool reply = false;
1737                         bool dm = false;
1738
1739                         foreach (PostClass post in notifyPosts)
1740                         {
1741                             if (!(notifyPosts.Length > 3))
1742                             {
1743                                 sb.Clear();
1744                                 reply = false;
1745                                 dm = false;
1746                             }
1747                             if (post.IsReply && !post.IsExcludeReply) reply = true;
1748                             if (post.IsDm) dm = true;
1749                             if (sb.Length > 0) sb.Append(System.Environment.NewLine);
1750                             switch (SettingDialog.NameBalloon)
1751                             {
1752                                 case MyCommon.NameBalloonEnum.UserID:
1753                                     sb.Append(post.ScreenName).Append(" : ");
1754                                     break;
1755                                 case MyCommon.NameBalloonEnum.NickName:
1756                                     sb.Append(post.Nickname).Append(" : ");
1757                                     break;
1758                             }
1759                             sb.Append(post.TextFromApi);
1760                             if (notifyPosts.Length > 3)
1761                             {
1762                                 if (notifyPosts.Last() != post) continue;
1763                             }
1764
1765                             StringBuilder title = new StringBuilder();
1766                             GrowlHelper.NotifyType nt;
1767                             if (SettingDialog.DispUsername)
1768                             {
1769                                 title.Append(tw.Username);
1770                                 title.Append(" - ");
1771                             }
1772                             else
1773                             {
1774                                 //title.Clear();
1775                             }
1776                             if (dm)
1777                             {
1778                                 //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
1779                                 //NotifyIcon1.BalloonTipTitle += Application.ProductName + " [DM] " + Properties.Resources.RefreshDirectMessageText1 + " " + addCount.ToString() + Properties.Resources.RefreshDirectMessageText2;
1780                                 title.Append(Application.ProductName);
1781                                 title.Append(" [DM] ");
1782                                 title.Append(Properties.Resources.RefreshDirectMessageText1);
1783                                 title.Append(" ");
1784                                 title.Append(addCount);
1785                                 title.Append(Properties.Resources.RefreshDirectMessageText2);
1786                                 nt = GrowlHelper.NotifyType.DirectMessage;
1787                             }
1788                             else if (reply)
1789                             {
1790                                 //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
1791                                 //NotifyIcon1.BalloonTipTitle += Application.ProductName + " [Reply!] " + Properties.Resources.RefreshTimelineText1 + " " + addCount.ToString() + Properties.Resources.RefreshTimelineText2;
1792                                 title.Append(Application.ProductName);
1793                                 title.Append(" [Reply!] ");
1794                                 title.Append(Properties.Resources.RefreshTimelineText1);
1795                                 title.Append(" ");
1796                                 title.Append(addCount);
1797                                 title.Append(Properties.Resources.RefreshTimelineText2);
1798                                 nt = GrowlHelper.NotifyType.Reply;
1799                             }
1800                             else
1801                             {
1802                                 //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
1803                                 //NotifyIcon1.BalloonTipTitle += Application.ProductName + " " + Properties.Resources.RefreshTimelineText1 + " " + addCount.ToString() + Properties.Resources.RefreshTimelineText2;
1804                                 title.Append(Application.ProductName);
1805                                 title.Append(" ");
1806                                 title.Append(Properties.Resources.RefreshTimelineText1);
1807                                 title.Append(" ");
1808                                 title.Append(addCount);
1809                                 title.Append(Properties.Resources.RefreshTimelineText2);
1810                                 nt = GrowlHelper.NotifyType.Notify;
1811                             }
1812                             string bText = sb.ToString();
1813                             if (string.IsNullOrEmpty(bText)) return;
1814
1815                             var image = this.IconCache.TryGetFromCache(post.ImageUrl);
1816                             gh.Notify(nt, post.StatusId.ToString(), title.ToString(), bText, image == null ? null : image.Image, post.ImageUrl);
1817                         }
1818                     }
1819                     else
1820                     {
1821                         StringBuilder sb = new StringBuilder();
1822                         bool reply = false;
1823                         bool dm = false;
1824                         foreach (PostClass post in notifyPosts)
1825                         {
1826                             if (post.IsReply && !post.IsExcludeReply) reply = true;
1827                             if (post.IsDm) dm = true;
1828                             if (sb.Length > 0) sb.Append(System.Environment.NewLine);
1829                             switch (SettingDialog.NameBalloon)
1830                             {
1831                                 case MyCommon.NameBalloonEnum.UserID:
1832                                     sb.Append(post.ScreenName).Append(" : ");
1833                                     break;
1834                                 case MyCommon.NameBalloonEnum.NickName:
1835                                     sb.Append(post.Nickname).Append(" : ");
1836                                     break;
1837                             }
1838                             sb.Append(post.TextFromApi);
1839
1840                         }
1841                         //if (SettingDialog.DispUsername) { NotifyIcon1.BalloonTipTitle = tw.Username + " - "; } else { NotifyIcon1.BalloonTipTitle = ""; }
1842                         StringBuilder title = new StringBuilder();
1843                         ToolTipIcon ntIcon;
1844                         if (SettingDialog.DispUsername)
1845                         {
1846                             title.Append(tw.Username);
1847                             title.Append(" - ");
1848                         }
1849                         else
1850                         {
1851                             //title.Clear();
1852                         }
1853                         if (dm)
1854                         {
1855                             //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
1856                             //NotifyIcon1.BalloonTipTitle += Application.ProductName + " [DM] " + Properties.Resources.RefreshDirectMessageText1 + " " + addCount.ToString() + Properties.Resources.RefreshDirectMessageText2;
1857                             ntIcon = ToolTipIcon.Warning;
1858                             title.Append(Application.ProductName);
1859                             title.Append(" [DM] ");
1860                             title.Append(Properties.Resources.RefreshDirectMessageText1);
1861                             title.Append(" ");
1862                             title.Append(addCount);
1863                             title.Append(Properties.Resources.RefreshDirectMessageText2);
1864                         }
1865                         else if (reply)
1866                         {
1867                             //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
1868                             //NotifyIcon1.BalloonTipTitle += Application.ProductName + " [Reply!] " + Properties.Resources.RefreshTimelineText1 + " " + addCount.ToString() + Properties.Resources.RefreshTimelineText2;
1869                             ntIcon = ToolTipIcon.Warning;
1870                             title.Append(Application.ProductName);
1871                             title.Append(" [Reply!] ");
1872                             title.Append(Properties.Resources.RefreshTimelineText1);
1873                             title.Append(" ");
1874                             title.Append(addCount);
1875                             title.Append(Properties.Resources.RefreshTimelineText2);
1876                         }
1877                         else
1878                         {
1879                             //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
1880                             //NotifyIcon1.BalloonTipTitle += Application.ProductName + " " + Properties.Resources.RefreshTimelineText1 + " " + addCount.ToString() + Properties.Resources.RefreshTimelineText2;
1881                             ntIcon = ToolTipIcon.Info;
1882                             title.Append(Application.ProductName);
1883                             title.Append(" ");
1884                             title.Append(Properties.Resources.RefreshTimelineText1);
1885                             title.Append(" ");
1886                             title.Append(addCount);
1887                             title.Append(Properties.Resources.RefreshTimelineText2);
1888                         }
1889                         string bText = sb.ToString();
1890                         if (string.IsNullOrEmpty(bText)) return;
1891                         //NotifyIcon1.BalloonTipText = sb.ToString();
1892                         //NotifyIcon1.ShowBalloonTip(500);
1893                         NotifyIcon1.BalloonTipTitle = title.ToString();
1894                         NotifyIcon1.BalloonTipText = bText;
1895                         NotifyIcon1.BalloonTipIcon = ntIcon;
1896                         NotifyIcon1.ShowBalloonTip(500);
1897                     }
1898                 }
1899             }
1900
1901             //サウンド再生
1902             if (!_initial && SettingDialog.PlaySound && !string.IsNullOrEmpty(soundFile))
1903             {
1904                 try
1905                 {
1906                     string dir = Application.StartupPath;
1907                     if (Directory.Exists(Path.Combine(dir, "Sounds")))
1908                     {
1909                         dir = Path.Combine(dir, "Sounds");
1910                     }
1911                     using (SoundPlayer player = new SoundPlayer(Path.Combine(dir, soundFile)))
1912                     {
1913                         player.Play();
1914                     }
1915                 }
1916                 catch (Exception)
1917                 {
1918                 }
1919             }
1920
1921             //mentions新着時に画面ブリンク
1922             if (!_initial && SettingDialog.BlinkNewMentions && newMentions && Form.ActiveForm == null)
1923             {
1924                 Win32Api.FlashMyWindow(this.Handle, Win32Api.FlashSpecification.FlashTray, 3);
1925             }
1926         }
1927
1928         private void MyList_SelectedIndexChanged(object sender, EventArgs e)
1929         {
1930             if (_curList == null || !_curList.Equals(sender) || _curList.SelectedIndices.Count != 1) return;
1931
1932             _curItemIndex = _curList.SelectedIndices[0];
1933             if (_curItemIndex > _curList.VirtualListSize - 1) return;
1934
1935             try
1936             {
1937                 _curPost = GetCurTabPost(_curItemIndex);
1938             }
1939             catch (ArgumentException)
1940             {
1941                 return;
1942             }
1943
1944             this.PushSelectPostChain();
1945
1946             if (SettingDialog.UnreadManage) _statuses.SetReadAllTab(true, _curTab.Text, _curItemIndex);
1947             //キャッシュの書き換え
1948             ChangeCacheStyleRead(true, _curItemIndex);   //既読へ(フォント、文字色)
1949
1950             ColorizeList();
1951             _colorize = true;
1952         }
1953
1954         private void ChangeCacheStyleRead(bool Read, int Index)
1955         {
1956             //Read:true=既読 false=未読
1957             //未読管理していなかったら既読として扱う
1958             if (!_statuses.Tabs[_curTab.Text].UnreadManage ||
1959                !SettingDialog.UnreadManage) Read = true;
1960
1961             //対象の特定
1962             ListViewItem itm = null;
1963             PostClass post = null;
1964
1965             this.TryGetListViewItemCache(Index, out itm, out post);
1966
1967             if (itm == null || post == null)
1968             {
1969                 itm = ((DetailsListView)_curTab.Tag).Items[Index];
1970                 post = _statuses[_curTab.Text, Index];
1971             }
1972
1973             ChangeItemStyleRead(Read, itm, post, ((DetailsListView)_curTab.Tag));
1974         }
1975
1976         private void ChangeItemStyleRead(bool Read, ListViewItem Item, PostClass Post, DetailsListView DList)
1977         {
1978             Font fnt;
1979             //フォント
1980             if (Read)
1981             {
1982                 fnt = _fntReaded;
1983                 Item.SubItems[5].Text = "";
1984             }
1985             else
1986             {
1987                 fnt = _fntUnread;
1988                 Item.SubItems[5].Text = "★";
1989             }
1990             //文字色
1991             Color cl;
1992             if (Post.IsFav)
1993                 cl = _clFav;
1994             else if (Post.RetweetedId != null)
1995                 cl = _clRetweet;
1996             else if (Post.IsOwl && (Post.IsDm || SettingDialog.OneWayLove))
1997                 cl = _clOWL;
1998             else if (Read || !SettingDialog.UseUnreadStyle)
1999                 cl = _clReaded;
2000             else
2001                 cl = _clUnread;
2002
2003             if (DList == null || Item.Index == -1)
2004             {
2005                 Item.ForeColor = cl;
2006                 if (SettingDialog.UseUnreadStyle)
2007                     Item.Font = fnt;
2008             }
2009             else
2010             {
2011                 DList.Update();
2012                 if (SettingDialog.UseUnreadStyle)
2013                     DList.ChangeItemFontAndColor(Item.Index, cl, fnt);
2014                 else
2015                     DList.ChangeItemForeColor(Item.Index, cl);
2016                 //if (_itemCache != null) DList.RedrawItems(_itemCacheIndex, _itemCacheIndex + _itemCache.Length - 1, false);
2017             }
2018         }
2019
2020         private void ColorizeList()
2021         {
2022             //Index:更新対象のListviewItem.Index。Colorを返す。
2023             //-1は全キャッシュ。Colorは返さない(ダミーを戻す)
2024             PostClass _post;
2025             if (_anchorFlag)
2026                 _post = _anchorPost;
2027             else
2028                 _post = _curPost;
2029
2030             if (_post == null) return;
2031
2032             var itemColors = new Color[] { };
2033             int itemIndex = -1;
2034
2035             this.itemCacheLock.EnterReadLock();
2036             try
2037             {
2038                 if (this._itemCache == null) return;
2039
2040                 var query = 
2041                     from i in Enumerable.Range(0, this._itemCache.Length)
2042                     select this.JudgeColor(_post, this._postCache[i]);
2043                 
2044                 itemColors = query.ToArray();
2045                 itemIndex = _itemCacheIndex;
2046             }
2047             finally { this.itemCacheLock.ExitReadLock(); }
2048
2049             if (itemIndex < 0) return;
2050
2051             foreach (var backColor in itemColors)
2052             {
2053                 // この処理中に MyList_CacheVirtualItems が呼ばれることがあるため、
2054                 // 同一スレッド内での二重ロックを避けるためにロックの外で実行する必要がある
2055                 _curList.ChangeItemBackColor(itemIndex++, backColor);
2056             }
2057         }
2058
2059         private void ColorizeList(ListViewItem Item, int Index)
2060         {
2061             //Index:更新対象のListviewItem.Index。Colorを返す。
2062             //-1は全キャッシュ。Colorは返さない(ダミーを戻す)
2063             PostClass _post;
2064             if (_anchorFlag)
2065                 _post = _anchorPost;
2066             else
2067                 _post = _curPost;
2068
2069             PostClass tPost = GetCurTabPost(Index);
2070
2071             if (_post == null) return;
2072
2073             if (Item.Index == -1)
2074                 Item.BackColor = JudgeColor(_post, tPost);
2075             else
2076                 _curList.ChangeItemBackColor(Item.Index, JudgeColor(_post, tPost));
2077         }
2078
2079         private Color JudgeColor(PostClass BasePost, PostClass TargetPost)
2080         {
2081             Color cl;
2082             if (TargetPost.StatusId == BasePost.InReplyToStatusId)
2083                 //@先
2084                 cl = _clAtTo;
2085             else if (TargetPost.IsMe)
2086                 //自分=発言者
2087                 cl = _clSelf;
2088             else if (TargetPost.IsReply)
2089                 //自分宛返信
2090                 cl = _clAtSelf;
2091             else if (BasePost.ReplyToList.Contains(TargetPost.ScreenName.ToLower()))
2092                 //返信先
2093                 cl = _clAtFromTarget;
2094             else if (TargetPost.ReplyToList.Contains(BasePost.ScreenName.ToLower()))
2095                 //その人への返信
2096                 cl = _clAtTarget;
2097             else if (TargetPost.ScreenName.Equals(BasePost.ScreenName, StringComparison.OrdinalIgnoreCase))
2098                 //発言者
2099                 cl = _clTarget;
2100             else
2101                 //その他
2102                 cl = _clListBackcolor;
2103
2104             return cl;
2105         }
2106
2107         private async void PostButton_Click(object sender, EventArgs e)
2108         {
2109             if (StatusText.Text.Trim().Length == 0)
2110             {
2111                 if (!ImageSelector.Enabled)
2112                 {
2113                     DoRefresh();
2114                     return;
2115                 }
2116             }
2117
2118             if (this.ExistCurrentPost && StatusText.Text.Trim() == string.Format("RT @{0}: {1}", _curPost.ScreenName, _curPost.TextFromApi))
2119             {
2120                 DialogResult rtResult = MessageBox.Show(string.Format(Properties.Resources.PostButton_Click1, Environment.NewLine),
2121                                                                "Retweet",
2122                                                                MessageBoxButtons.YesNoCancel,
2123                                                                MessageBoxIcon.Question);
2124                 switch (rtResult)
2125                 {
2126                     case DialogResult.Yes:
2127                         doReTweetOfficial(false);
2128                         StatusText.Text = "";
2129                         return;
2130                     case DialogResult.Cancel:
2131                         return;
2132                 }
2133             }
2134
2135             _history[_history.Count - 1] = new PostingStatus(StatusText.Text, _reply_to_id, _reply_to_name);
2136
2137             if (SettingDialog.Nicoms)
2138             {
2139                 StatusText.SelectionStart = StatusText.Text.Length;
2140                 await UrlConvertAsync(MyCommon.UrlConverter.Nicoms);
2141             }
2142             //if (SettingDialog.UrlConvertAuto)
2143             //{
2144             //    StatusText.SelectionStart = StatusText.Text.Length;
2145             //    UrlConvertAutoToolStripMenuItem_Click(null, null);
2146             //}
2147             //else if (SettingDialog.Nicoms)
2148             //{
2149             //    StatusText.SelectionStart = StatusText.Text.Length;
2150             //    UrlConvert(UrlConverter.Nicoms);
2151             //}
2152             StatusText.SelectionStart = StatusText.Text.Length;
2153             GetWorkerArg args = new GetWorkerArg();
2154             args.page = 0;
2155             args.endPage = 0;
2156             args.type = MyCommon.WORKERTYPE.PostMessage;
2157             CheckReplyTo(StatusText.Text);
2158
2159             //整形によって増加する文字数を取得
2160             int adjustCount = 0;
2161             string tmpStatus = StatusText.Text.Trim();
2162             if (ToolStripMenuItemApiCommandEvasion.Checked)
2163             {
2164                 // APIコマンド回避
2165                 if (Regex.IsMatch(tmpStatus,
2166                     @"^[+\-\[\]\s\\.,*/(){}^~|='&%$#""<>?]*(get|g|fav|follow|f|on|off|stop|quit|leave|l|whois|w|nudge|n|stats|invite|track|untrack|tracks|tracking|\*)([+\-\[\]\s\\.,*/(){}^~|='&%$#""<>?]+|$)",
2167                     RegexOptions.IgnoreCase)
2168                    && tmpStatus.EndsWith(" .") == false) adjustCount += 2;
2169             }
2170
2171             if (ToolStripMenuItemUrlMultibyteSplit.Checked)
2172             {
2173                 // URLと全角文字の切り離し
2174                 adjustCount += Regex.Matches(tmpStatus, @"https?:\/\/[-_.!~*'()a-zA-Z0-9;\/?:\@&=+\$,%#^]+").Count;
2175             }
2176
2177             bool isCutOff = false;
2178             bool isRemoveFooter = MyCommon.IsKeyDown(Keys.Shift);
2179             if (StatusText.Multiline && !SettingDialog.PostCtrlEnter)
2180             {
2181                 //複数行でEnter投稿の場合、Ctrlも押されていたらフッタ付加しない
2182                 isRemoveFooter = MyCommon.IsKeyDown(Keys.Control);
2183             }
2184             if (SettingDialog.PostShiftEnter)
2185             {
2186                 isRemoveFooter = MyCommon.IsKeyDown(Keys.Control);
2187             }
2188             if (!isRemoveFooter && (StatusText.Text.Contains("RT @") || StatusText.Text.Contains("QT @")))
2189             {
2190                 isRemoveFooter = true;
2191             }
2192             if (GetRestStatusCount(false, !isRemoveFooter) - adjustCount < 0)
2193             {
2194                 if (MessageBox.Show(Properties.Resources.PostLengthOverMessage1, Properties.Resources.PostLengthOverMessage2, MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.OK)
2195                 {
2196                     isCutOff = true;
2197                     //if (!SettingDialog.UrlConvertAuto) UrlConvertAutoToolStripMenuItem_Click(null, null);
2198                     if (GetRestStatusCount(false, !isRemoveFooter) - adjustCount < 0)
2199                     {
2200                         isRemoveFooter = true;
2201                     }
2202                 }
2203                 else
2204                 {
2205                     return;
2206                 }
2207             }
2208
2209             string footer = "";
2210             string header = "";
2211             if (StatusText.Text.StartsWith("D ") || StatusText.Text.StartsWith("d "))
2212             {
2213                 //DM時は何もつけない
2214                 footer = "";
2215             }
2216             else
2217             {
2218                 //ハッシュタグ
2219                 if (HashMgr.IsNotAddToAtReply)
2220                 {
2221                     if (!string.IsNullOrEmpty(HashMgr.UseHash) && _reply_to_id == null && string.IsNullOrEmpty(_reply_to_name))
2222                     {
2223                         if (HashMgr.IsHead)
2224                             header = HashMgr.UseHash + " ";
2225                         else
2226                             footer = " " + HashMgr.UseHash;
2227                     }
2228                 }
2229                 else
2230                 {
2231                     if (!string.IsNullOrEmpty(HashMgr.UseHash))
2232                     {
2233                         if (HashMgr.IsHead)
2234                             header = HashMgr.UseHash + " ";
2235                         else
2236                             footer = " " + HashMgr.UseHash;
2237                     }
2238                 }
2239                 if (!isRemoveFooter)
2240                 {
2241                     if (SettingDialog.UseRecommendStatus)
2242                         // 推奨ステータスを使用する
2243                         footer += SettingDialog.RecommendStatusText;
2244                     else
2245                         // テキストボックスに入力されている文字列を使用する
2246                         footer += " " + SettingDialog.Status.Trim();
2247                 }
2248             }
2249             args.status.status = header + StatusText.Text + footer;
2250
2251             if (ToolStripMenuItemApiCommandEvasion.Checked)
2252             {
2253                 // APIコマンド回避
2254                 if (Regex.IsMatch(args.status.status,
2255                     @"^[+\-\[\]\s\\.,*/(){}^~|='&%$#""<>?]*(get|g|fav|follow|f|on|off|stop|quit|leave|l|whois|w|nudge|n|stats|invite|track|untrack|tracks|tracking|\*)([+\-\[\]\s\\.,*/(){}^~|='&%$#""<>?]+|$)",
2256                     RegexOptions.IgnoreCase)
2257                    && args.status.status.EndsWith(" .") == false) args.status.status += " .";
2258             }
2259
2260             if (ToolStripMenuItemUrlMultibyteSplit.Checked)
2261             {
2262                 // URLと全角文字の切り離し
2263                 Match mc2 = Regex.Match(args.status.status, @"https?:\/\/[-_.!~*'()a-zA-Z0-9;\/?:\@&=+\$,%#^]+");
2264                 if (mc2.Success) args.status.status = Regex.Replace(args.status.status, @"https?:\/\/[-_.!~*'()a-zA-Z0-9;\/?:\@&=+\$,%#^]+", "$& ");
2265             }
2266
2267             if (IdeographicSpaceToSpaceToolStripMenuItem.Checked)
2268             {
2269                 // 文中の全角スペースを半角スペース1個にする
2270                 args.status.status = args.status.status.Replace(" ", " ");
2271             }
2272
2273             if (isCutOff && args.status.status.Length > 140)
2274             {
2275                 args.status.status = args.status.status.Substring(0, 140);
2276                 string AtId = @"(@|@)[a-z0-9_/]+$";
2277                 string HashTag = @"(^|[^0-9A-Z&\/\?]+)(#|#)([0-9A-Z_]*[A-Z_]+)$";
2278                 string Url = @"https?:\/\/[a-z0-9!\*'\(\);:&=\+\$\/%#\[\]\-_\.,~?]+$"; //簡易判定
2279                 string pattern = string.Format("({0})|({1})|({2})", AtId, HashTag, Url);
2280                 Match mc = Regex.Match(args.status.status, pattern, RegexOptions.IgnoreCase);
2281                 if (mc.Success)
2282                 {
2283                     //さらに@ID、ハッシュタグ、URLと推測される文字列をカットする
2284                     args.status.status = args.status.status.Substring(0, 140 - mc.Value.Length);
2285                 }
2286                 if (MessageBox.Show(args.status.status, "Post or Cancel?", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel) return;
2287             }
2288
2289             args.status.inReplyToId = _reply_to_id;
2290             args.status.inReplyToName = _reply_to_name;
2291             if (ImageSelector.Visible)
2292             {
2293                 //画像投稿
2294                 if (!ImageSelector.TryGetSelectedMedia(out args.status.imageService, out args.status.imagePath))
2295                     return;
2296             }
2297
2298             RunAsync(args);
2299
2300             _reply_to_id = null;
2301             _reply_to_name = null;
2302             StatusText.Text = "";
2303             _history.Add(new PostingStatus());
2304             _hisIdx = _history.Count - 1;
2305             if (!ToolStripFocusLockMenuItem.Checked)
2306                 ((Control)ListTab.SelectedTab.Tag).Focus();
2307             urlUndoBuffer = null;
2308             UrlUndoToolStripMenuItem.Enabled = false;  //Undoをできないように設定
2309
2310             //Google検索(試験実装)
2311             if (StatusText.Text.StartsWith("Google:", StringComparison.OrdinalIgnoreCase) && StatusText.Text.Trim().Length > 7)
2312             {
2313                 string tmp = string.Format(Properties.Resources.SearchItem2Url, Uri.EscapeUriString(StatusText.Text.Substring(7)));
2314                 await this.OpenUriAsync(tmp);
2315             }
2316         }
2317
2318         private void EndToolStripMenuItem_Click(object sender, EventArgs e)
2319         {
2320             MyCommon._endingFlag = true;
2321             this.Close();
2322         }
2323
2324         private void TweenMain_FormClosing(object sender, FormClosingEventArgs e)
2325         {
2326             if (!SettingDialog.CloseToExit && e.CloseReason == CloseReason.UserClosing && MyCommon._endingFlag == false)
2327             {
2328                 //_endingFlag=false:フォームの×ボタン
2329                 e.Cancel = true;
2330                 this.Visible = false;
2331             }
2332             else
2333             {
2334                 _hookGlobalHotkey.UnregisterAllOriginalHotkey();
2335                 _ignoreConfigSave = true;
2336                 MyCommon._endingFlag = true;
2337                 TimerTimeline.Enabled = false;
2338                 TimerRefreshIcon.Enabled = false;
2339             }
2340         }
2341
2342         private void NotifyIcon1_BalloonTipClicked(object sender, EventArgs e)
2343         {
2344             this.Visible = true;
2345             if (this.WindowState == FormWindowState.Minimized)
2346             {
2347                 this.WindowState = FormWindowState.Normal;
2348             }
2349             this.Activate();
2350             this.BringToFront();
2351         }
2352
2353         private static int errorCount = 0;
2354
2355         private static bool CheckAccountValid()
2356         {
2357             if (Twitter.AccountState != MyCommon.ACCOUNT_STATE.Valid)
2358             {
2359                 errorCount += 1;
2360                 if (errorCount > 5)
2361                 {
2362                     errorCount = 0;
2363                     Twitter.AccountState = MyCommon.ACCOUNT_STATE.Valid;
2364                     return true;
2365                 }
2366                 return false;
2367             }
2368             errorCount = 0;
2369             return true;
2370         }
2371
2372         private void GetTimelineWorker_DoWork(object sender, DoWorkEventArgs e)
2373         {
2374             BackgroundWorker bw = (BackgroundWorker)sender;
2375             if (bw.CancellationPending || MyCommon._endingFlag)
2376             {
2377                 e.Cancel = true;
2378                 return;
2379             }
2380
2381             Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
2382
2383             MyApplication.InitCulture();
2384
2385             string ret = "";
2386             GetWorkerResult rslt = new GetWorkerResult();
2387
2388             bool read = !SettingDialog.UnreadManage;
2389             if (_initial && SettingDialog.UnreadManage) read = SettingDialog.Readed;
2390
2391             GetWorkerArg args = (GetWorkerArg)e.Argument;
2392
2393             if (!CheckAccountValid())
2394             {
2395                 rslt.retMsg = "Auth error. Check your account";
2396                 rslt.type = MyCommon.WORKERTYPE.ErrorState;  //エラー表示のみ行ない、後処理キャンセル
2397                 rslt.tName = args.tName;
2398                 e.Result = rslt;
2399                 return;
2400             }
2401
2402             bw.ReportProgress(0, ""); //Notifyアイコンアニメーション開始
2403
2404             switch (args.type)
2405             {
2406                 case MyCommon.WORKERTYPE.Timeline:
2407                 case MyCommon.WORKERTYPE.Reply:
2408                     bw.ReportProgress(50, MakeStatusMessage(args, false));
2409                     ret = tw.GetTimelineApi(read, args.type, args.page == -1, _initial);
2410                     //新着時未読クリア
2411                     if (string.IsNullOrEmpty(ret) && args.type == MyCommon.WORKERTYPE.Timeline && SettingDialog.ReadOldPosts)
2412                         _statuses.SetRead();
2413                     //振り分け
2414                     rslt.addCount = _statuses.DistributePosts();
2415                     break;
2416                 case MyCommon.WORKERTYPE.DirectMessegeRcv:    //送信分もまとめて取得
2417                     bw.ReportProgress(50, MakeStatusMessage(args, false));
2418                     ret = tw.GetDirectMessageApi(read, MyCommon.WORKERTYPE.DirectMessegeRcv, args.page == -1);
2419                     if (string.IsNullOrEmpty(ret)) ret = tw.GetDirectMessageApi(read, MyCommon.WORKERTYPE.DirectMessegeSnt, args.page == -1);
2420                     rslt.addCount = _statuses.DistributePosts();
2421                     break;
2422
2423                 case MyCommon.WORKERTYPE.FavAdd:
2424                 {
2425                     //スレッド処理はしない
2426                     TabClass tab;
2427                     if (_statuses.Tabs.TryGetValue(args.tName, out tab))
2428                     {
2429                         for (int i = 0; i <= args.ids.Count - 1; i++)
2430                         {
2431                             var post = tab.Posts[args.ids[i]];
2432
2433                             args.page = i + 1;
2434                             bw.ReportProgress(50, MakeStatusMessage(args, false));
2435                             if (!post.IsFav)
2436                             {
2437                                 if (post.RetweetedId == null)
2438                                     ret = tw.PostFavAdd(post.StatusId);
2439                                 else
2440                                     ret = tw.PostFavAdd(post.RetweetedId.Value);
2441
2442                                 if (ret.Length == 0)
2443                                 {
2444                                     args.sIds.Add(post.StatusId);
2445                                     post.IsFav = true;    //リスト再描画必要
2446                                     _favTimestamps.Add(DateTime.Now);
2447                                     if (string.IsNullOrEmpty(post.RelTabName))
2448                                     {
2449                                         //検索,リストUserTimeline.Relatedタブからのfavは、favタブへ追加せず。それ以外は追加
2450                                         _statuses.GetTabByType(MyCommon.TabUsageType.Favorites).Add(post.StatusId, post.IsRead, false);
2451                                     }
2452                                     else
2453                                     {
2454                                         //検索,リスト,UserTimeline.Relatedタブからのfavで、TLでも取得済みならfav反映
2455                                         if (_statuses.ContainsKey(post.StatusId))
2456                                         {
2457                                             PostClass postTl = _statuses[post.StatusId];
2458                                             postTl.IsFav = true;
2459                                             _statuses.GetTabByType(MyCommon.TabUsageType.Favorites).Add(postTl.StatusId, postTl.IsRead, false);
2460                                         }
2461                                     }
2462                                     //検索,リスト,UserTimeline,Relatedの各タブに反映
2463                                     foreach (TabClass tb in _statuses.GetTabsByType(MyCommon.TabUsageType.PublicSearch | MyCommon.TabUsageType.Lists | MyCommon.TabUsageType.UserTimeline | MyCommon.TabUsageType.Related))
2464                                     {
2465                                         if (tb.Contains(post.StatusId)) tb.Posts[post.StatusId].IsFav = true;
2466                                     }
2467                                 }
2468                             }
2469                         }
2470                     }
2471                     rslt.sIds = args.sIds;
2472                     break;
2473                 }
2474
2475                 case MyCommon.WORKERTYPE.FavRemove:
2476                 {
2477                     //スレッド処理はしない
2478                     TabClass tab;
2479                     if (_statuses.Tabs.TryGetValue(args.tName, out tab))
2480                     {
2481                         for (int i = 0; i <= args.ids.Count - 1; i++)
2482                         {
2483                             var post = tab.Posts[args.ids[i]];
2484
2485                             args.page = i + 1;
2486                             bw.ReportProgress(50, MakeStatusMessage(args, false));
2487                             if (post.IsFav)
2488                             {
2489                                 if (post.RetweetedId == null)
2490                                     ret = tw.PostFavRemove(post.StatusId);
2491                                 else
2492                                     ret = tw.PostFavRemove(post.RetweetedId.Value);
2493
2494                                 if (ret.Length == 0)
2495                                 {
2496                                     args.sIds.Add(post.StatusId);
2497                                     post.IsFav = false;    //リスト再描画必要
2498                                     if (_statuses.ContainsKey(post.StatusId)) _statuses[post.StatusId].IsFav = false;
2499                                     //検索,リスト,UserTimeline,Relatedの各タブに反映
2500                                     foreach (TabClass tb in _statuses.GetTabsByType(MyCommon.TabUsageType.PublicSearch | MyCommon.TabUsageType.Lists | MyCommon.TabUsageType.UserTimeline | MyCommon.TabUsageType.Related))
2501                                     {
2502                                         if (tb.Contains(post.StatusId)) tb.Posts[post.StatusId].IsFav = false;
2503                                     }
2504                                 }
2505                             }
2506                         }
2507                     }
2508                     rslt.sIds = args.sIds;
2509                     break;
2510                 }
2511
2512                 case MyCommon.WORKERTYPE.PostMessage:
2513                     bw.ReportProgress(200);
2514                     if (args.status.imagePath == null || args.status.imagePath.Length == 0 || string.IsNullOrEmpty(args.status.imagePath[0]))
2515                     {
2516                         ret = tw.PostStatus(args.status.status, args.status.inReplyToId);
2517                     }
2518                     else
2519                     {
2520                         var service = ImageSelector.GetService(args.status.imageService);
2521                         if (args.status.imagePath.Length > 1 &&
2522                             args.status.imageService.Equals("Twitter"))
2523                         {
2524                             //複数画像投稿
2525                             ret = ((TwitterPhoto)service).Upload(ref args.status.imagePath,
2526                                                                  ref args.status.status,
2527                                                                  args.status.inReplyToId);
2528                         }
2529                         else
2530                         {
2531                             ret = service.Upload(ref args.status.imagePath[0],
2532                                                  ref args.status.status,
2533                                                  args.status.inReplyToId);
2534                         }
2535                     }
2536                     bw.ReportProgress(300);
2537                     rslt.status = args.status;
2538                     break;
2539                 case MyCommon.WORKERTYPE.Retweet:
2540                     bw.ReportProgress(200);
2541                     for (int i = 0; i <= args.ids.Count - 1; i++)
2542                     {
2543                         ret = tw.PostRetweet(args.ids[i], read);
2544                     }
2545                     bw.ReportProgress(300);
2546                     break;
2547                 case MyCommon.WORKERTYPE.Follower:
2548                     bw.ReportProgress(50, Properties.Resources.UpdateFollowersMenuItem1_ClickText1);
2549                     try
2550                     {
2551                         tw.RefreshFollowerIds();
2552                     }
2553                     catch (WebApiException ex) { ret = ex.Message; }
2554                     break;
2555                 case MyCommon.WORKERTYPE.NoRetweetIds:
2556                     try
2557                     {
2558                         tw.RefreshNoRetweetIds();
2559                     }
2560                     catch (WebApiException ex) { ret = ex.Message; }
2561                     break;
2562                 case MyCommon.WORKERTYPE.Configuration:
2563                     try
2564                     {
2565                         this.SettingDialog.TwitterConfiguration = tw.ConfigurationApi();
2566                     }
2567                     catch (WebApiException ex) { ret = ex.Message; }
2568                     break;
2569                 case MyCommon.WORKERTYPE.Favorites:
2570                     bw.ReportProgress(50, MakeStatusMessage(args, false));
2571                     ret = tw.GetFavoritesApi(read, args.type, args.page == -1);
2572                     rslt.addCount = _statuses.DistributePosts();
2573                     break;
2574                 case MyCommon.WORKERTYPE.PublicSearch:
2575                     bw.ReportProgress(50, MakeStatusMessage(args, false));
2576                     if (string.IsNullOrEmpty(args.tName))
2577                     {
2578                         foreach (TabClass tb in _statuses.GetTabsByType(MyCommon.TabUsageType.PublicSearch))
2579                         {
2580                             //if (!string.IsNullOrEmpty(tb.SearchWords)) ret = tw.GetPhoenixSearch(read, tb, false);
2581                             if (!string.IsNullOrEmpty(tb.SearchWords)) ret = tw.GetSearch(read, tb, false);
2582                         }
2583                     }
2584                     else
2585                     {
2586                         TabClass tb = _statuses.GetTabByName(args.tName);
2587                         if (tb != null)
2588                         {
2589                             //ret = tw.GetPhoenixSearch(read, tb, false);
2590                             ret = tw.GetSearch(read, tb, false);
2591                             if (string.IsNullOrEmpty(ret) && args.page == -1)
2592                             {
2593                                 //ret = tw.GetPhoenixSearch(read, tb, true)
2594                                 ret = tw.GetSearch(read, tb, true);
2595                             }
2596                         }
2597                     }
2598                     //振り分け
2599                     rslt.addCount = _statuses.DistributePosts();
2600                     break;
2601                 case MyCommon.WORKERTYPE.UserTimeline:
2602                     bw.ReportProgress(50, MakeStatusMessage(args, false));
2603                     int count = 20;
2604                     if (SettingDialog.UseAdditionalCount) count = SettingDialog.UserTimelineCountApi;
2605                     if (string.IsNullOrEmpty(args.tName))
2606                     {
2607                         foreach (TabClass tb in _statuses.GetTabsByType(MyCommon.TabUsageType.UserTimeline))
2608                         {
2609                             if (!string.IsNullOrEmpty(tb.User)) ret = tw.GetUserTimelineApi(read, count, tb.User, tb, false);
2610                         }
2611                     }
2612                     else
2613                     {
2614                         TabClass tb = _statuses.GetTabByName(args.tName);
2615                         if (tb != null)
2616                         {
2617                             ret = tw.GetUserTimelineApi(read, count, tb.User, tb, args.page == -1);
2618                         }
2619                     }
2620                     //振り分け
2621                     rslt.addCount = _statuses.DistributePosts();
2622                     break;
2623                 case MyCommon.WORKERTYPE.List:
2624                     bw.ReportProgress(50, MakeStatusMessage(args, false));
2625                     if (string.IsNullOrEmpty(args.tName))
2626                     {
2627                         //定期更新
2628                         foreach (TabClass tb in _statuses.GetTabsByType(MyCommon.TabUsageType.Lists))
2629                         {
2630                             if (tb.ListInfo != null && tb.ListInfo.Id != 0) ret = tw.GetListStatus(read, tb, false, _initial);
2631                         }
2632                     }
2633                     else
2634                     {
2635                         //手動更新(特定タブのみ更新)
2636                         TabClass tb = _statuses.GetTabByName(args.tName);
2637                         if (tb != null)
2638                         {
2639                             ret = tw.GetListStatus(read, tb, args.page == -1, _initial);
2640                         }
2641                     }
2642                     //振り分け
2643                     rslt.addCount = _statuses.DistributePosts();
2644                     break;
2645
2646                 case MyCommon.WORKERTYPE.Related:
2647                 {
2648                     bw.ReportProgress(50, MakeStatusMessage(args, false));
2649                     TabClass tab = _statuses.GetTabByName(args.tName);
2650                     ret = tw.GetRelatedResult(read, tab);
2651                     rslt.addCount = _statuses.DistributePosts();
2652                     break;
2653                 }
2654
2655                 case MyCommon.WORKERTYPE.BlockIds:
2656                     bw.ReportProgress(50, Properties.Resources.UpdateBlockUserText1);
2657                     try
2658                     {
2659                         tw.RefreshBlockIds();
2660                     }
2661                     catch (WebApiException ex) { ret = ex.Message; }
2662                     break;
2663             }
2664             //キャンセル要求
2665             if (bw.CancellationPending)
2666             {
2667                 e.Cancel = true;
2668                 return;
2669             }
2670
2671             //時速表示用
2672             if (args.type == MyCommon.WORKERTYPE.FavAdd)
2673             {
2674                 DateTime oneHour = DateTime.Now.Subtract(new TimeSpan(1, 0, 0));
2675                 for (int i = _favTimestamps.Count - 1; i >= 0; i--)
2676                 {
2677                     if (_favTimestamps[i].CompareTo(oneHour) < 0)
2678                     {
2679                         _favTimestamps.RemoveAt(i);
2680                     }
2681                 }
2682             }
2683             if (args.type == MyCommon.WORKERTYPE.Timeline && !_initial)
2684             {
2685                 lock (_syncObject)
2686                 {
2687                     DateTime tm = DateTime.Now;
2688                     if (_tlTimestamps.ContainsKey(tm))
2689                         _tlTimestamps[tm] += rslt.addCount;
2690                     else
2691                         _tlTimestamps.Add(tm, rslt.addCount);
2692
2693                     DateTime oneHour = DateTime.Now.Subtract(new TimeSpan(1, 0, 0));
2694                     List<DateTime> keys = new List<DateTime>();
2695                     _tlCount = 0;
2696                     foreach (DateTime key in _tlTimestamps.Keys)
2697                     {
2698                         if (key.CompareTo(oneHour) < 0)
2699                         {
2700                             keys.Add(key);
2701                         }
2702                         else
2703                         {
2704                             _tlCount += _tlTimestamps[key];
2705                         }
2706                     }
2707                     foreach (DateTime key in keys)
2708                     {
2709                         _tlTimestamps.Remove(key);
2710                     }
2711                     keys.Clear();
2712                 }
2713             }
2714
2715             //終了ステータス
2716             bw.ReportProgress(100, MakeStatusMessage(args, true)); //ステータス書き換え、Notifyアイコンアニメーション開始
2717
2718             rslt.retMsg = ret;
2719             rslt.type = args.type;
2720             rslt.tName = args.tName;
2721             if (args.type == MyCommon.WORKERTYPE.DirectMessegeRcv ||
2722                 args.type == MyCommon.WORKERTYPE.DirectMessegeSnt ||
2723                 args.type == MyCommon.WORKERTYPE.Reply ||
2724                 args.type == MyCommon.WORKERTYPE.Timeline ||
2725                 args.type == MyCommon.WORKERTYPE.Favorites)
2726             {
2727                 rslt.page = args.page - 1;   //値が正しいか後でチェック。10ページ毎の継続確認
2728             }
2729
2730             e.Result = rslt;
2731         }
2732
2733         private string MakeStatusMessage(GetWorkerArg AsyncArg, bool Finish)
2734         {
2735             string smsg = "";
2736             if (!Finish)
2737             {
2738                 //継続中メッセージ
2739                 switch (AsyncArg.type)
2740                 {
2741                     case MyCommon.WORKERTYPE.Timeline:
2742                         smsg = Properties.Resources.GetTimelineWorker_RunWorkerCompletedText5 + AsyncArg.page.ToString() + Properties.Resources.GetTimelineWorker_RunWorkerCompletedText6;
2743                         break;
2744                     case MyCommon.WORKERTYPE.Reply:
2745                         smsg = Properties.Resources.GetTimelineWorker_RunWorkerCompletedText4 + AsyncArg.page.ToString() + Properties.Resources.GetTimelineWorker_RunWorkerCompletedText6;
2746                         break;
2747                     case MyCommon.WORKERTYPE.DirectMessegeRcv:
2748                         smsg = Properties.Resources.GetTimelineWorker_RunWorkerCompletedText8 + AsyncArg.page.ToString() + Properties.Resources.GetTimelineWorker_RunWorkerCompletedText6;
2749                         break;
2750                     case MyCommon.WORKERTYPE.FavAdd:
2751                         smsg = Properties.Resources.GetTimelineWorker_RunWorkerCompletedText15 + AsyncArg.page.ToString() + "/" + AsyncArg.ids.Count.ToString() +
2752                                             Properties.Resources.GetTimelineWorker_RunWorkerCompletedText16 + (AsyncArg.page - AsyncArg.sIds.Count - 1).ToString();
2753                         break;
2754                     case MyCommon.WORKERTYPE.FavRemove:
2755                         smsg = Properties.Resources.GetTimelineWorker_RunWorkerCompletedText17 + AsyncArg.page.ToString() + "/" + AsyncArg.ids.Count.ToString() +
2756                                             Properties.Resources.GetTimelineWorker_RunWorkerCompletedText18 + (AsyncArg.page - AsyncArg.sIds.Count - 1).ToString();
2757                         break;
2758                     case MyCommon.WORKERTYPE.Favorites:
2759                         smsg = Properties.Resources.GetTimelineWorker_RunWorkerCompletedText19;
2760                         break;
2761                     case MyCommon.WORKERTYPE.PublicSearch:
2762                         smsg = "Search refreshing...";
2763                         break;
2764                     case MyCommon.WORKERTYPE.List:
2765                         smsg = "List refreshing...";
2766                         break;
2767                     case MyCommon.WORKERTYPE.Related:
2768                         smsg = "Related refreshing...";
2769                         break;
2770                     case MyCommon.WORKERTYPE.UserTimeline:
2771                         smsg = "UserTimeline refreshing...";
2772                         break;
2773                 }
2774             }
2775             else
2776             {
2777                 //完了メッセージ
2778                 switch (AsyncArg.type)
2779                 {
2780                     case MyCommon.WORKERTYPE.Timeline:
2781                         smsg = Properties.Resources.GetTimelineWorker_RunWorkerCompletedText1;
2782                         break;
2783                     case MyCommon.WORKERTYPE.Reply:
2784                         smsg = Properties.Resources.GetTimelineWorker_RunWorkerCompletedText9;
2785                         break;
2786                     case MyCommon.WORKERTYPE.DirectMessegeRcv:
2787                         smsg = Properties.Resources.GetTimelineWorker_RunWorkerCompletedText11;
2788                         break;
2789                     case MyCommon.WORKERTYPE.DirectMessegeSnt:
2790                         smsg = Properties.Resources.GetTimelineWorker_RunWorkerCompletedText13;
2791                         break;
2792                     case MyCommon.WORKERTYPE.FavAdd:
2793                         //進捗メッセージ残す
2794                         break;
2795                     case MyCommon.WORKERTYPE.FavRemove:
2796                         //進捗メッセージ残す
2797                         break;
2798                     case MyCommon.WORKERTYPE.Favorites:
2799                         smsg = Properties.Resources.GetTimelineWorker_RunWorkerCompletedText20;
2800                         break;
2801                     case MyCommon.WORKERTYPE.Follower:
2802                         smsg = Properties.Resources.UpdateFollowersMenuItem1_ClickText3;
2803                         break;
2804                     case MyCommon.WORKERTYPE.NoRetweetIds:
2805                         smsg = "NoRetweetIds refreshed";
2806                         break;
2807                     case MyCommon.WORKERTYPE.Configuration:
2808                         //進捗メッセージ残す
2809                         break;
2810                     case MyCommon.WORKERTYPE.PublicSearch:
2811                         smsg = "Search refreshed";
2812                         break;
2813                     case MyCommon.WORKERTYPE.List:
2814                         smsg = "List refreshed";
2815                         break;
2816                     case MyCommon.WORKERTYPE.Related:
2817                         smsg = "Related refreshed";
2818                         break;
2819                     case MyCommon.WORKERTYPE.UserTimeline:
2820                         smsg = "UserTimeline refreshed";
2821                         break;
2822                     case MyCommon.WORKERTYPE.BlockIds:
2823                         smsg = Properties.Resources.UpdateBlockUserText3;
2824                         break;
2825                 }
2826             }
2827             return smsg;
2828         }
2829
2830         private void GetTimelineWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
2831         {
2832             if (MyCommon._endingFlag) return;
2833             if (e.ProgressPercentage > 100)
2834             {
2835                 //発言投稿
2836                 if (e.ProgressPercentage == 200)    //開始
2837                     StatusLabel.Text = "Posting...";
2838                 if (e.ProgressPercentage == 300)  //終了
2839                     StatusLabel.Text = Properties.Resources.PostWorker_RunWorkerCompletedText4;
2840             }
2841             else
2842             {
2843                 string smsg = (string)e.UserState;
2844                 if (smsg.Length > 0) StatusLabel.Text = smsg;
2845             }
2846         }
2847
2848         private void GetTimelineWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
2849         {
2850             if (MyCommon._endingFlag || e.Cancelled) return; //キャンセル
2851
2852             if (e.Error != null)
2853             {
2854                 _myStatusError = true;
2855                 _waitTimeline = false;
2856                 _waitReply = false;
2857                 _waitDm = false;
2858                 _waitFav = false;
2859                 _waitPubSearch = false;
2860                 _waitUserTimeline = false;
2861                 _waitLists = false;
2862                 throw new Exception("BackgroundWorker Exception", e.Error);
2863             }
2864
2865             GetWorkerResult rslt = (GetWorkerResult)e.Result;
2866
2867             //エラー
2868             if (rslt.retMsg.Length > 0)
2869             {
2870                 _myStatusError = true;
2871                 StatusLabel.Text = rslt.retMsg;
2872             }
2873
2874             if (rslt.type == MyCommon.WORKERTYPE.ErrorState) return;
2875
2876             if (rslt.type == MyCommon.WORKERTYPE.FavRemove)
2877             {
2878                 this.RemovePostFromFavTab(rslt.sIds.ToArray());
2879             }
2880
2881             //リストに反映
2882             //bool busy = false;
2883             //foreach (BackgroundWorker bw in _bw)
2884             //{
2885             //    if (bw != null && bw.IsBusy)
2886             //    {
2887             //        busy = true;
2888             //        break;
2889             //    }
2890             //}
2891             //if (!busy) RefreshTimeline(); //background処理なければ、リスト反映
2892             if (rslt.type == MyCommon.WORKERTYPE.Timeline ||
2893                 rslt.type == MyCommon.WORKERTYPE.Reply ||
2894                 rslt.type == MyCommon.WORKERTYPE.List ||
2895                 rslt.type == MyCommon.WORKERTYPE.PublicSearch ||
2896                 rslt.type == MyCommon.WORKERTYPE.DirectMessegeRcv ||
2897                 rslt.type == MyCommon.WORKERTYPE.DirectMessegeSnt ||
2898                 rslt.type == MyCommon.WORKERTYPE.Favorites ||
2899                 rslt.type == MyCommon.WORKERTYPE.Follower ||
2900                 rslt.type == MyCommon.WORKERTYPE.NoRetweetIds ||
2901                 rslt.type == MyCommon.WORKERTYPE.FavAdd ||
2902                 rslt.type == MyCommon.WORKERTYPE.FavRemove ||
2903                 rslt.type == MyCommon.WORKERTYPE.Related ||
2904                 rslt.type == MyCommon.WORKERTYPE.UserTimeline ||
2905                 rslt.type == MyCommon.WORKERTYPE.BlockIds ||
2906                 rslt.type == MyCommon.WORKERTYPE.Configuration)
2907             {
2908                 RefreshTimeline(false); //リスト反映
2909             }
2910
2911             switch (rslt.type)
2912             {
2913                 case MyCommon.WORKERTYPE.Timeline:
2914                     _waitTimeline = false;
2915                     if (!_initial)
2916                     {
2917                         //    //API使用時の取得調整は別途考える(カウント調整?)
2918                     }
2919                     break;
2920                 case MyCommon.WORKERTYPE.Reply:
2921                     _waitReply = false;
2922                     if (rslt.newDM && !_initial)
2923                     {
2924                         GetTimeline(MyCommon.WORKERTYPE.DirectMessegeRcv, 1, 0, "");
2925                     }
2926                     break;
2927                 case MyCommon.WORKERTYPE.Favorites:
2928                     _waitFav = false;
2929                     break;
2930                 case MyCommon.WORKERTYPE.DirectMessegeRcv:
2931                     _waitDm = false;
2932                     break;
2933                 case MyCommon.WORKERTYPE.FavAdd:
2934                 case MyCommon.WORKERTYPE.FavRemove:
2935                     if (_curList != null && _curTab != null)
2936                     {
2937                         using (ControlTransaction.Update(this._curList))
2938                         {
2939                             if (rslt.type == MyCommon.WORKERTYPE.FavRemove && _statuses.Tabs[_curTab.Text].TabType == MyCommon.TabUsageType.Favorites)
2940                             {
2941                                 //色変えは不要
2942                             }
2943                             else
2944                             {
2945                                 for (int i = 0; i <= rslt.sIds.Count - 1; i++)
2946                                 {
2947                                     if (_curTab.Text.Equals(rslt.tName))
2948                                     {
2949                                         int idx = _statuses.Tabs[rslt.tName].IndexOf(rslt.sIds[i]);
2950                                         if (idx > -1)
2951                                         {
2952                                             PostClass post = null;
2953                                             TabClass tb = _statuses.Tabs[rslt.tName];
2954                                             if (tb != null)
2955                                             {
2956                                                 if (tb.TabType == MyCommon.TabUsageType.Lists || tb.TabType == MyCommon.TabUsageType.PublicSearch)
2957                                                 {
2958                                                     post = tb.Posts[rslt.sIds[i]];
2959                                                 }
2960                                                 else
2961                                                 {
2962                                                     post = _statuses[rslt.sIds[i]];
2963                                                 }
2964                                                 ChangeCacheStyleRead(post.IsRead, idx);
2965                                             }
2966                                             if (idx == _curItemIndex) DispSelectedPost(true); //選択アイテム再表示
2967                                         }
2968                                     }
2969                                 }
2970                             }
2971                         }
2972                     }
2973                     break;
2974                 case MyCommon.WORKERTYPE.PostMessage:
2975                     if (string.IsNullOrEmpty(rslt.retMsg) ||
2976                         rslt.retMsg.StartsWith("OK:") ||
2977                         rslt.retMsg == "Warn:Status is a duplicate.")
2978                     {
2979                         _postTimestamps.Add(DateTime.Now);
2980                         DateTime oneHour = DateTime.Now.Subtract(new TimeSpan(1, 0, 0));
2981                         for (int i = _postTimestamps.Count - 1; i >= 0; i--)
2982                         {
2983                             if (_postTimestamps[i].CompareTo(oneHour) < 0)
2984                             {
2985                                 _postTimestamps.RemoveAt(i);
2986                             }
2987                         }
2988
2989                         if (!HashMgr.IsPermanent && !string.IsNullOrEmpty(HashMgr.UseHash))
2990                         {
2991                             HashMgr.ClearHashtag();
2992                             this.HashStripSplitButton.Text = "#[-]";
2993                             this.HashToggleMenuItem.Checked = false;
2994                             this.HashToggleToolStripMenuItem.Checked = false;
2995                         }
2996                         SetMainWindowTitle();
2997                         rslt.retMsg = "";
2998                     }
2999                     else
3000                     {
3001                         DialogResult retry;
3002                         try
3003                         {
3004                             retry = MessageBox.Show(string.Format("{0}   --->   [ " + rslt.retMsg + " ]" + Environment.NewLine + "\"" + rslt.status.status + "\"" + Environment.NewLine + "{1}",
3005                                                                 Properties.Resources.StatusUpdateFailed1,
3006                                                                 Properties.Resources.StatusUpdateFailed2),
3007                                                             "Failed to update status",
3008                                                             MessageBoxButtons.RetryCancel,
3009                                                             MessageBoxIcon.Question);
3010                         }
3011                         catch (Exception)
3012                         {
3013                             retry = DialogResult.Abort;
3014                         }
3015                         if (retry == DialogResult.Retry)
3016                         {
3017                             GetWorkerArg args = new GetWorkerArg();
3018                             args.page = 0;
3019                             args.endPage = 0;
3020                             args.type = MyCommon.WORKERTYPE.PostMessage;
3021                             args.status = rslt.status;
3022                             RunAsync(args);
3023                         }
3024                         else
3025                         {
3026                             if (ToolStripFocusLockMenuItem.Checked)
3027                             {
3028                                 //連投モードのときだけEnterイベントが起きないので強制的に背景色を戻す
3029                                 StatusText_Enter(StatusText, new EventArgs());
3030                             }
3031                         }
3032                     }
3033                     if (rslt.retMsg.Length == 0 && SettingDialog.PostAndGet)
3034                     {
3035                         if (_isActiveUserstream)
3036                         {
3037                             RefreshTimeline(true);
3038                         }
3039                         else
3040                         {
3041                             GetTimeline(MyCommon.WORKERTYPE.Timeline, 1, 0, "");
3042                         }
3043                     }
3044                     break;
3045                 case MyCommon.WORKERTYPE.Retweet:
3046                     if (rslt.retMsg.Length == 0)
3047                     {
3048                         _postTimestamps.Add(DateTime.Now);
3049                         DateTime oneHour = DateTime.Now.Subtract(new TimeSpan(1, 0, 0));
3050                         for (int i = _postTimestamps.Count - 1; i >= 0; i--)
3051                         {
3052                             if (_postTimestamps[i].CompareTo(oneHour) < 0)
3053                             {
3054                                 _postTimestamps.RemoveAt(i);
3055                             }
3056                         }
3057                         if (!_isActiveUserstream && SettingDialog.PostAndGet) GetTimeline(MyCommon.WORKERTYPE.Timeline, 1, 0, "");
3058                     }
3059                     break;
3060                 case MyCommon.WORKERTYPE.Follower:
3061                     //_waitFollower = false;
3062                     this.PurgeListViewItemCache();
3063                     if (_curList != null) _curList.Refresh();
3064                     break;
3065                 case MyCommon.WORKERTYPE.NoRetweetIds:
3066                     break;
3067                 case MyCommon.WORKERTYPE.Configuration:
3068                     //_waitFollower = false
3069                     if (SettingDialog.TwitterConfiguration.PhotoSizeLimit != 0)
3070                     {
3071                         var service = ImageSelector.GetService("Twitter");
3072                         if (service != null)
3073                             service.Configuration("MaxUploadFilesize", SettingDialog.TwitterConfiguration.PhotoSizeLimit);
3074                     }
3075                     this.PurgeListViewItemCache();
3076                     if (_curList != null) _curList.Refresh();
3077                     break;
3078                 case MyCommon.WORKERTYPE.PublicSearch:
3079                     _waitPubSearch = false;
3080                     break;
3081                 case MyCommon.WORKERTYPE.UserTimeline:
3082                     _waitUserTimeline = false;
3083                     break;
3084                 case MyCommon.WORKERTYPE.List:
3085                     _waitLists = false;
3086                     break;
3087                 case MyCommon.WORKERTYPE.Related:
3088                     TabClass tab = _statuses.GetTabByType(MyCommon.TabUsageType.Related);
3089                     if (tab != null && tab.RelationTargetPost != null && tab.Contains(tab.RelationTargetPost.StatusId))
3090                     {
3091                         foreach (TabPage tp in ListTab.TabPages)
3092                         {
3093                             if (tp.Text == tab.TabName)
3094                             {
3095                                 ((DetailsListView)tp.Tag).SelectedIndices.Add(tab.IndexOf(tab.RelationTargetPost.StatusId));
3096                                 ((DetailsListView)tp.Tag).Items[tab.IndexOf(tab.RelationTargetPost.StatusId)].Focused = true;
3097                                 break;
3098                             }
3099                         }
3100                     }
3101                     break;
3102             }
3103         }
3104
3105         private async Task RefreshMuteUserIdsAsync()
3106         {
3107             this.StatusLabel.Text = Properties.Resources.UpdateMuteUserIds_Start;
3108
3109             try
3110             {
3111                 await tw.RefreshMuteUserIdsAsync();
3112             }
3113             catch (WebApiException ex)
3114             {
3115                 this.StatusLabel.Text = string.Format(Properties.Resources.UpdateMuteUserIds_Error, ex.Message);
3116                 return;
3117             }
3118
3119             this.StatusLabel.Text = Properties.Resources.UpdateMuteUserIds_Finish;
3120         }
3121
3122         private void RemovePostFromFavTab(Int64[] ids)
3123         {
3124             string favTabName = _statuses.GetTabByType(MyCommon.TabUsageType.Favorites).TabName;
3125             int fidx = 0;
3126             if (_curTab.Text.Equals(favTabName))
3127             {
3128                 if (_curList.FocusedItem != null)
3129                     fidx = _curList.FocusedItem.Index;
3130                 else if (_curList.TopItem != null)
3131                     fidx = _curList.TopItem.Index;
3132                 else
3133                     fidx = 0;
3134             }
3135
3136             foreach (long i in ids)
3137             {
3138                 try
3139                 {
3140                     _statuses.RemoveFavPost(i);
3141                 }
3142                 catch (Exception)
3143                 {
3144                     continue;
3145                 }
3146             }
3147             if (_curTab != null && _curTab.Text.Equals(favTabName))
3148             {
3149                 this.PurgeListViewItemCache();
3150                 _curPost = null;
3151                 //_curItemIndex = -1;
3152             }
3153             foreach (TabPage tp in ListTab.TabPages)
3154             {
3155                 if (tp.Text == favTabName)
3156                 {
3157                     ((DetailsListView)tp.Tag).VirtualListSize = _statuses.Tabs[favTabName].AllCount;
3158                     break;
3159                 }
3160             }
3161             if (_curTab.Text.Equals(favTabName))
3162             {
3163                 do
3164                 {
3165                     _curList.SelectedIndices.Clear();
3166                 }
3167                 while (_curList.SelectedIndices.Count > 0);
3168
3169                 if (_statuses.Tabs[favTabName].AllCount > 0)
3170                 {
3171                     if (_statuses.Tabs[favTabName].AllCount - 1 > fidx && fidx > -1)
3172                     {
3173                         _curList.SelectedIndices.Add(fidx);
3174                     }
3175                     else
3176                     {
3177                         _curList.SelectedIndices.Add(_statuses.Tabs[favTabName].AllCount - 1);
3178                     }
3179                     if (_curList.SelectedIndices.Count > 0)
3180                     {
3181                         _curList.EnsureVisible(_curList.SelectedIndices[0]);
3182                         _curList.FocusedItem = _curList.Items[_curList.SelectedIndices[0]];
3183                     }
3184                 }
3185             }
3186         }
3187
3188         private static Dictionary<MyCommon.WORKERTYPE, DateTime> lastTime = new Dictionary<MyCommon.WORKERTYPE, DateTime>();
3189
3190         private void GetTimeline(MyCommon.WORKERTYPE WkType, int fromPage, int toPage, string tabName)
3191         {
3192             if (!this.IsNetworkAvailable()) return;
3193
3194             //非同期実行引数設定
3195             GetWorkerArg args = new GetWorkerArg();
3196             args.page = fromPage;
3197             args.endPage = toPage;
3198             args.type = WkType;
3199             args.tName = tabName;
3200
3201             if (!lastTime.ContainsKey(WkType)) lastTime.Add(WkType, new DateTime());
3202             double period = DateTime.Now.Subtract(lastTime[WkType]).TotalSeconds;
3203             if (period > 1 || period < -1)
3204             {
3205                 lastTime[WkType] = DateTime.Now;
3206                 RunAsync(args);
3207             }
3208
3209             //Timeline取得モードの場合はReplyも同時に取得
3210             //if (!SettingDialog.UseAPI &&
3211             //   !_initial &&
3212             //   WkType == MyCommon.WORKERTYPE.Timeline &&
3213             //   SettingDialog.CheckReply)
3214             //{
3215             //    //TimerReply.Enabled = false;
3216             //    _mentionCounter = SettingDialog.ReplyPeriodInt;
3217             //    GetWorkerArg _args = new GetWorkerArg();
3218             //    _args.page = fromPage;
3219             //    _args.endPage = toPage;
3220             //    _args.type = MyCommon.WORKERTYPE.Reply;
3221             //    RunAsync(_args);
3222             //}
3223         }
3224
3225         private void NotifyIcon1_MouseClick(object sender, MouseEventArgs e)
3226         {
3227             if (e.Button == MouseButtons.Left)
3228             {
3229                 this.Visible = true;
3230                 if (this.WindowState == FormWindowState.Minimized)
3231                 {
3232                     this.WindowState = _formWindowState;
3233                 }
3234                 this.Activate();
3235                 this.BringToFront();
3236             }
3237         }
3238
3239         private void MyList_MouseDoubleClick(object sender, MouseEventArgs e)
3240         {
3241             switch (SettingDialog.ListDoubleClickAction)
3242             {
3243                 case 0:
3244                     MakeReplyOrDirectStatus();
3245                     break;
3246                 case 1:
3247                     FavoriteChange(true);
3248                     break;
3249                 case 2:
3250                     if (_curPost != null)
3251                         ShowUserStatus(_curPost.ScreenName, false);
3252                     break;
3253                 case 3:
3254                     ShowUserTimeline();
3255                     break;
3256                 case 4:
3257                     ShowRelatedStatusesMenuItem_Click(null, null);
3258                     break;
3259                 case 5:
3260                     MoveToHomeToolStripMenuItem_Click(null, null);
3261                     break;
3262                 case 6:
3263                     StatusOpenMenuItem_Click(null, null);
3264                     break;
3265                 case 7:
3266                     //動作なし
3267                     break;
3268             }
3269         }
3270
3271         private void FavAddToolStripMenuItem_Click(object sender, EventArgs e)
3272         {
3273             FavoriteChange(true);
3274         }
3275
3276         private void FavRemoveToolStripMenuItem_Click(object sender, EventArgs e)
3277         {
3278             FavoriteChange(false);
3279         }
3280
3281
3282         private void FavoriteRetweetMenuItem_Click(object sender, EventArgs e)
3283         {
3284             FavoritesRetweetOriginal();
3285         }
3286
3287         private void FavoriteRetweetUnofficialMenuItem_Click(object sender, EventArgs e)
3288         {
3289             FavoritesRetweetUnofficial();
3290         }
3291
3292         private void FavoriteChange(bool FavAdd , bool multiFavoriteChangeDialogEnable = true)
3293         {
3294             //trueでFavAdd,falseでFavRemove
3295             if (_statuses.Tabs[_curTab.Text].TabType == MyCommon.TabUsageType.DirectMessage || _curList.SelectedIndices.Count == 0
3296                 || !this.ExistCurrentPost) return;
3297
3298             //複数fav確認msg
3299             if (_curList.SelectedIndices.Count > 250 && FavAdd)
3300             {
3301                 MessageBox.Show(Properties.Resources.FavoriteLimitCountText);
3302                 _DoFavRetweetFlags = false;
3303                 return;
3304             }
3305             else if (multiFavoriteChangeDialogEnable && _curList.SelectedIndices.Count > 1)
3306             {
3307                 if (FavAdd)
3308                 {
3309                     string QuestionText = Properties.Resources.FavAddToolStripMenuItem_ClickText1;
3310                     if (_DoFavRetweetFlags) QuestionText = Properties.Resources.FavoriteRetweetQuestionText3;
3311                     if (MessageBox.Show(QuestionText, Properties.Resources.FavAddToolStripMenuItem_ClickText2,
3312                                        MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
3313                     {
3314                         _DoFavRetweetFlags = false;
3315                         return;
3316                     }
3317                 }
3318                 else
3319                 {
3320                     if (MessageBox.Show(Properties.Resources.FavRemoveToolStripMenuItem_ClickText1, Properties.Resources.FavRemoveToolStripMenuItem_ClickText2,
3321                                     MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
3322                     {
3323                         return;
3324                     }
3325                 }
3326             }
3327
3328             GetWorkerArg args = new GetWorkerArg();
3329             args.ids = new List<long>();
3330             args.sIds = new List<long>();
3331             args.tName = _curTab.Text;
3332             if (FavAdd)
3333             {
3334                 args.type = MyCommon.WORKERTYPE.FavAdd;
3335             }
3336             else
3337             {
3338                 args.type = MyCommon.WORKERTYPE.FavRemove;
3339             }
3340             foreach (int idx in _curList.SelectedIndices)
3341             {
3342                 PostClass post = GetCurTabPost(idx);
3343                 if (FavAdd)
3344                 {
3345                     if (!post.IsFav) args.ids.Add(post.StatusId);
3346                 }
3347                 else
3348                 {
3349                     if (post.IsFav) args.ids.Add(post.StatusId);
3350                 }
3351             }
3352             if (args.ids.Count == 0)
3353             {
3354                 if (FavAdd)
3355                     StatusLabel.Text = Properties.Resources.FavAddToolStripMenuItem_ClickText4;
3356                 else
3357                     StatusLabel.Text = Properties.Resources.FavRemoveToolStripMenuItem_ClickText4;
3358
3359                 return;
3360             }
3361
3362             RunAsync(args);
3363         }
3364
3365         private PostClass GetCurTabPost(int Index)
3366         {
3367             this.itemCacheLock.EnterReadLock();
3368             try
3369             {
3370                 if (_postCache != null && Index >= _itemCacheIndex && Index < _itemCacheIndex + _postCache.Length)
3371                     return _postCache[Index - _itemCacheIndex];
3372             }
3373             finally { this.itemCacheLock.ExitReadLock(); }
3374
3375             return _statuses[_curTab.Text, Index];
3376         }
3377
3378
3379         private void MoveToHomeToolStripMenuItem_Click(object sender, EventArgs e)
3380         {
3381             if (_curList.SelectedIndices.Count > 0)
3382                 OpenUriAsync(MyCommon.TwitterUrl + GetCurTabPost(_curList.SelectedIndices[0]).ScreenName);
3383             else if (_curList.SelectedIndices.Count == 0)
3384                 OpenUriAsync(MyCommon.TwitterUrl);
3385         }
3386
3387         private void MoveToFavToolStripMenuItem_Click(object sender, EventArgs e)
3388         {
3389             if (_curList.SelectedIndices.Count > 0)
3390                 OpenUriAsync(MyCommon.TwitterUrl + "#!/" + GetCurTabPost(_curList.SelectedIndices[0]).ScreenName + "/favorites");
3391         }
3392
3393         private void TweenMain_ClientSizeChanged(object sender, EventArgs e)
3394         {
3395             if ((!_initialLayout) && this.Visible)
3396             {
3397                 if (this.WindowState == FormWindowState.Normal)
3398                 {
3399                     _mySize = this.ClientSize;
3400                     _mySpDis = this.SplitContainer1.SplitterDistance;
3401                     _mySpDis3 = this.SplitContainer3.SplitterDistance;
3402                     if (StatusText.Multiline) _mySpDis2 = this.StatusText.Height;
3403                     _modifySettingLocal = true;
3404                 }
3405             }
3406         }
3407
3408         private void MyList_ColumnClick(object sender, ColumnClickEventArgs e)
3409         {
3410             if (SettingDialog.SortOrderLock) return;
3411             IdComparerClass.ComparerMode mode = IdComparerClass.ComparerMode.Id;
3412             if (_iconCol)
3413             {
3414                 mode = IdComparerClass.ComparerMode.Id;
3415             }
3416             else
3417             {
3418                 switch (e.Column)
3419                 {
3420                     case 0:
3421                     case 5:
3422                     case 6:    //0:アイコン,5:未読マーク,6:プロテクト・フィルターマーク
3423                         //ソートしない
3424                         return;
3425                     case 1:  //ニックネーム
3426                         mode = IdComparerClass.ComparerMode.Nickname;
3427                         break;
3428                     case 2:  //本文
3429                         mode = IdComparerClass.ComparerMode.Data;
3430                         break;
3431                     case 3:  //時刻=発言Id
3432                         mode = IdComparerClass.ComparerMode.Id;
3433                         break;
3434                     case 4:  //名前
3435                         mode = IdComparerClass.ComparerMode.Name;
3436                         break;
3437                     case 7:  //Source
3438                         mode = IdComparerClass.ComparerMode.Source;
3439                         break;
3440                 }
3441             }
3442             _statuses.ToggleSortOrder(mode);
3443             InitColumnText();
3444
3445             DetailsListView list = (DetailsListView)sender;
3446             if (_iconCol)
3447             {
3448                 list.Columns[0].Text = ColumnOrgText[0];
3449                 list.Columns[1].Text = ColumnText[2];
3450             }
3451             else
3452             {
3453                 for (int i = 0; i <= 7; i++)
3454                 {
3455                     list.Columns[i].Text = ColumnOrgText[i];
3456                 }
3457                 list.Columns[e.Column].Text = ColumnText[e.Column];
3458             }
3459
3460             this.PurgeListViewItemCache();
3461
3462             if (_statuses.Tabs[_curTab.Text].AllCount > 0 && _curPost != null)
3463             {
3464                 int idx = _statuses.Tabs[_curTab.Text].IndexOf(_curPost.StatusId);
3465                 if (idx > -1)
3466                 {
3467                     SelectListItem(_curList, idx);
3468                     _curList.EnsureVisible(idx);
3469                 }
3470             }
3471             _curList.Refresh();
3472             _modifySettingCommon = true;
3473         }
3474
3475         private void TweenMain_LocationChanged(object sender, EventArgs e)
3476         {
3477             if (this.WindowState == FormWindowState.Normal && !_initialLayout)
3478             {
3479                 _myLoc = this.DesktopLocation;
3480                 _modifySettingLocal = true;
3481             }
3482         }
3483
3484         private void ContextMenuOperate_Opening(object sender, CancelEventArgs e)
3485         {
3486             if (ListTab.SelectedTab == null) return;
3487             if (_statuses == null || _statuses.Tabs == null || !_statuses.Tabs.ContainsKey(ListTab.SelectedTab.Text)) return;
3488             if (!this.ExistCurrentPost)
3489             {
3490                 ReplyStripMenuItem.Enabled = false;
3491                 ReplyAllStripMenuItem.Enabled = false;
3492                 DMStripMenuItem.Enabled = false;
3493                 ShowProfileMenuItem.Enabled = false;
3494                 ShowUserTimelineContextMenuItem.Enabled = false;
3495                 ListManageUserContextToolStripMenuItem2.Enabled = false;
3496                 MoveToFavToolStripMenuItem.Enabled = false;
3497                 TabMenuItem.Enabled = false;
3498                 IDRuleMenuItem.Enabled = false;
3499                 ReadedStripMenuItem.Enabled = false;
3500                 UnreadStripMenuItem.Enabled = false;
3501             }
3502             else
3503             {
3504                 ShowProfileMenuItem.Enabled = true;
3505                 ListManageUserContextToolStripMenuItem2.Enabled = true;
3506                 ReplyStripMenuItem.Enabled = true;
3507                 ReplyAllStripMenuItem.Enabled = true;
3508                 DMStripMenuItem.Enabled = true;
3509                 ShowUserTimelineContextMenuItem.Enabled = true;
3510                 MoveToFavToolStripMenuItem.Enabled = true;
3511                 TabMenuItem.Enabled = true;
3512                 IDRuleMenuItem.Enabled = true;
3513                 ReadedStripMenuItem.Enabled = true;
3514                 UnreadStripMenuItem.Enabled = true;
3515             }
3516             DeleteStripMenuItem.Text = Properties.Resources.DeleteMenuText1;
3517             if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.DirectMessage || !this.ExistCurrentPost || _curPost.IsDm)
3518             {
3519                 FavAddToolStripMenuItem.Enabled = false;
3520                 FavRemoveToolStripMenuItem.Enabled = false;
3521                 StatusOpenMenuItem.Enabled = false;
3522                 FavorareMenuItem.Enabled = false;
3523                 ShowRelatedStatusesMenuItem.Enabled = false;
3524
3525                 ReTweetStripMenuItem.Enabled = false;
3526                 ReTweetOriginalStripMenuItem.Enabled = false;
3527                 QuoteStripMenuItem.Enabled = false;
3528                 FavoriteRetweetContextMenu.Enabled = false;
3529                 FavoriteRetweetUnofficialContextMenu.Enabled = false;
3530                 if (this.ExistCurrentPost && _curPost.IsDm)
3531                     DeleteStripMenuItem.Enabled = true;
3532                 else
3533                     DeleteStripMenuItem.Enabled = false;
3534             }
3535             else
3536             {
3537                 FavAddToolStripMenuItem.Enabled = true;
3538                 FavRemoveToolStripMenuItem.Enabled = true;
3539                 StatusOpenMenuItem.Enabled = true;
3540                 FavorareMenuItem.Enabled = true;
3541                 ShowRelatedStatusesMenuItem.Enabled = true;  //PublicSearchの時問題出るかも
3542
3543                 if (_curPost.IsMe)
3544                 {
3545                     ReTweetOriginalStripMenuItem.Enabled = false;
3546                     FavoriteRetweetContextMenu.Enabled = false;
3547                     if (string.IsNullOrEmpty(_curPost.RetweetedBy))
3548                     {
3549                         DeleteStripMenuItem.Text = Properties.Resources.DeleteMenuText1;
3550                     }
3551                     else
3552                     {
3553                         DeleteStripMenuItem.Text = Properties.Resources.DeleteMenuText2;
3554                     }
3555                     DeleteStripMenuItem.Enabled = true;
3556                 }
3557                 else
3558                 {
3559                     if (string.IsNullOrEmpty(_curPost.RetweetedBy))
3560                     {
3561                         DeleteStripMenuItem.Text = Properties.Resources.DeleteMenuText1;
3562                     }
3563                     else
3564                     {
3565                         DeleteStripMenuItem.Text = Properties.Resources.DeleteMenuText2;
3566                     }
3567                     DeleteStripMenuItem.Enabled = false;
3568                     if (_curPost.IsProtect)
3569                     {
3570                         ReTweetOriginalStripMenuItem.Enabled = false;
3571                         ReTweetStripMenuItem.Enabled = false;
3572                         QuoteStripMenuItem.Enabled = false;
3573                         FavoriteRetweetContextMenu.Enabled = false;
3574                         FavoriteRetweetUnofficialContextMenu.Enabled = false;
3575                     }
3576                     else
3577                     {
3578                         ReTweetOriginalStripMenuItem.Enabled = true;
3579                         ReTweetStripMenuItem.Enabled = true;
3580                         QuoteStripMenuItem.Enabled = true;
3581                         FavoriteRetweetContextMenu.Enabled = true;
3582                         FavoriteRetweetUnofficialContextMenu.Enabled = true;
3583                     }
3584                 }
3585             }
3586             //if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType != MyCommon.TabUsageType.Favorites)
3587             //{
3588             //    RefreshMoreStripMenuItem.Enabled = true;
3589             //}
3590             //else
3591             //{
3592             //    RefreshMoreStripMenuItem.Enabled = false;
3593             //}
3594             if (!this.ExistCurrentPost
3595                 || _curPost.InReplyToStatusId == null)
3596             {
3597                 RepliedStatusOpenMenuItem.Enabled = false;
3598             }
3599             else
3600             {
3601                 RepliedStatusOpenMenuItem.Enabled = true;
3602             }
3603             if (!this.ExistCurrentPost || string.IsNullOrEmpty(_curPost.RetweetedBy))
3604             {
3605                 MoveToRTHomeMenuItem.Enabled = false;
3606             }
3607             else
3608             {
3609                 MoveToRTHomeMenuItem.Enabled = true;
3610             }
3611         }
3612
3613         private void ReplyStripMenuItem_Click(object sender, EventArgs e)
3614         {
3615             MakeReplyOrDirectStatus(false, true);
3616         }
3617
3618         private void DMStripMenuItem_Click(object sender, EventArgs e)
3619         {
3620             MakeReplyOrDirectStatus(false, false);
3621         }
3622
3623         private void doStatusDelete()
3624         {
3625             if (_curTab == null || _curList == null) return;
3626             if (_statuses.Tabs[_curTab.Text].TabType != MyCommon.TabUsageType.DirectMessage)
3627             {
3628                 bool myPost = false;
3629                 foreach (int idx in _curList.SelectedIndices)
3630                 {
3631                     if (GetCurTabPost(idx).IsMe ||
3632                        GetCurTabPost(idx).RetweetedBy.ToLower() == tw.Username.ToLower())
3633                     {
3634                         myPost = true;
3635                         break;
3636                     }
3637                 }
3638                 if (!myPost) return;
3639             }
3640             else
3641             {
3642                 if (_curList.SelectedIndices.Count == 0)
3643                     return;
3644             }
3645
3646             string tmp = string.Format(Properties.Resources.DeleteStripMenuItem_ClickText1, Environment.NewLine);
3647
3648             if (MessageBox.Show(tmp, Properties.Resources.DeleteStripMenuItem_ClickText2,
3649                   MessageBoxButtons.OKCancel,
3650                   MessageBoxIcon.Question) == DialogResult.Cancel) return;
3651
3652             int fidx;
3653             if (_curList.FocusedItem != null)
3654                 fidx = _curList.FocusedItem.Index;
3655             else if (_curList.TopItem != null)
3656                 fidx = _curList.TopItem.Index;
3657             else
3658                 fidx = 0;
3659
3660             try
3661             {
3662                 this.Cursor = Cursors.WaitCursor;
3663
3664                 bool rslt = true;
3665                 foreach (long Id in _statuses.GetId(_curTab.Text, _curList.SelectedIndices))
3666                 {
3667                     string rtn = "";
3668                     if (_statuses.Tabs[_curTab.Text].TabType == MyCommon.TabUsageType.DirectMessage)
3669                     {
3670                         rtn = tw.RemoveDirectMessage(Id, _statuses[Id]);
3671                     }
3672                     else
3673                     {
3674                         if (_statuses[Id].IsMe || _statuses[Id].RetweetedBy.ToLower() == tw.Username.ToLower())
3675                             rtn = tw.RemoveStatus(Id);
3676                         else
3677                             continue;
3678                     }
3679                     if (rtn.Length > 0)
3680                     {
3681                         //エラー
3682                         rslt = false;
3683                     }
3684                     else
3685                     {
3686                         _statuses.RemovePost(Id);
3687                     }
3688                 }
3689
3690                 if (!rslt)
3691                     StatusLabel.Text = Properties.Resources.DeleteStripMenuItem_ClickText3;  //失敗
3692                 else
3693                     StatusLabel.Text = Properties.Resources.DeleteStripMenuItem_ClickText4;  //成功
3694
3695                 this.PurgeListViewItemCache();
3696                 _curPost = null;
3697                 _curItemIndex = -1;
3698                 foreach (TabPage tb in ListTab.TabPages)
3699                 {
3700                     ((DetailsListView)tb.Tag).VirtualListSize = _statuses.Tabs[tb.Text].AllCount;
3701                     if (_curTab.Equals(tb))
3702                     {
3703                         do
3704                         {
3705                             _curList.SelectedIndices.Clear();
3706                         }
3707                         while (_curList.SelectedIndices.Count > 0);
3708
3709                         if (_statuses.Tabs[tb.Text].AllCount > 0)
3710                         {
3711                             if (_statuses.Tabs[tb.Text].AllCount - 1 > fidx && fidx > -1)
3712                                 _curList.SelectedIndices.Add(fidx);
3713                             else
3714                                 _curList.SelectedIndices.Add(_statuses.Tabs[tb.Text].AllCount - 1);
3715
3716                             if (_curList.SelectedIndices.Count > 0)
3717                             {
3718                                 _curList.EnsureVisible(_curList.SelectedIndices[0]);
3719                                 _curList.FocusedItem = _curList.Items[_curList.SelectedIndices[0]];
3720                             }
3721                         }
3722                     }
3723                     if (_statuses.Tabs[tb.Text].UnreadCount == 0)
3724                     {
3725                         if (SettingDialog.TabIconDisp)
3726                         {
3727                             if (tb.ImageIndex == 0) tb.ImageIndex = -1; //タブアイコン
3728                         }
3729                     }
3730                 }
3731                 if (!SettingDialog.TabIconDisp) ListTab.Refresh();
3732             }
3733             finally
3734             {
3735                 this.Cursor = Cursors.Default;
3736             }
3737         }
3738
3739         private void DeleteStripMenuItem_Click(object sender, EventArgs e)
3740         {
3741             doStatusDelete();
3742         }
3743
3744         private void ReadedStripMenuItem_Click(object sender, EventArgs e)
3745         {
3746             using (ControlTransaction.Update(this._curList))
3747             {
3748                 if (SettingDialog.UnreadManage)
3749                 {
3750                     foreach (int idx in _curList.SelectedIndices)
3751                     {
3752                         _statuses.SetReadAllTab(true, _curTab.Text, idx);
3753                     }
3754                 }
3755                 foreach (int idx in _curList.SelectedIndices)
3756                 {
3757                     ChangeCacheStyleRead(true, idx);
3758                 }
3759                 ColorizeList();
3760             }
3761             foreach (TabPage tb in ListTab.TabPages)
3762             {
3763                 if (_statuses.Tabs[tb.Text].UnreadCount == 0)
3764                 {
3765                     if (SettingDialog.TabIconDisp)
3766                     {
3767                         if (tb.ImageIndex == 0) tb.ImageIndex = -1; //タブアイコン
3768                     }
3769                 }
3770             }
3771             if (!SettingDialog.TabIconDisp) ListTab.Refresh();
3772         }
3773
3774         private void UnreadStripMenuItem_Click(object sender, EventArgs e)
3775         {
3776             using (ControlTransaction.Update(this._curList))
3777             {
3778                 if (SettingDialog.UnreadManage)
3779                 {
3780                     foreach (int idx in _curList.SelectedIndices)
3781                     {
3782                         _statuses.SetReadAllTab(false, _curTab.Text, idx);
3783                     }
3784                 }
3785                 foreach (int idx in _curList.SelectedIndices)
3786                 {
3787                     ChangeCacheStyleRead(false, idx);
3788                 }
3789                 ColorizeList();
3790             }
3791             foreach (TabPage tb in ListTab.TabPages)
3792             {
3793                 if (_statuses.Tabs[tb.Text].UnreadCount > 0)
3794                 {
3795                     if (SettingDialog.TabIconDisp)
3796                     {
3797                         if (tb.ImageIndex == -1) tb.ImageIndex = 0; //タブアイコン
3798                     }
3799                 }
3800             }
3801             if (!SettingDialog.TabIconDisp) ListTab.Refresh();
3802         }
3803
3804         private void RefreshStripMenuItem_Click(object sender, EventArgs e)
3805         {
3806             DoRefresh();
3807         }
3808
3809         private void DoRefresh()
3810         {
3811             if (_curTab != null)
3812             {
3813                 switch (_statuses.Tabs[_curTab.Text].TabType)
3814                 {
3815                     case MyCommon.TabUsageType.Mentions:
3816                         GetTimeline(MyCommon.WORKERTYPE.Reply, 1, 0, "");
3817                         break;
3818                     case MyCommon.TabUsageType.DirectMessage:
3819                         GetTimeline(MyCommon.WORKERTYPE.DirectMessegeRcv, 1, 0, "");
3820                         break;
3821                     case MyCommon.TabUsageType.Favorites:
3822                         GetTimeline(MyCommon.WORKERTYPE.Favorites, 1, 0, "");
3823                         break;
3824                     //case MyCommon.TabUsageType.Profile:
3825                         //// TODO
3826                     case MyCommon.TabUsageType.PublicSearch:
3827                         //// TODO
3828                         TabClass tb = _statuses.Tabs[_curTab.Text];
3829                         if (string.IsNullOrEmpty(tb.SearchWords)) return;
3830                         GetTimeline(MyCommon.WORKERTYPE.PublicSearch, 1, 0, _curTab.Text);
3831                         break;
3832                     case MyCommon.TabUsageType.UserTimeline:
3833                         GetTimeline(MyCommon.WORKERTYPE.UserTimeline, 1, 0, _curTab.Text);
3834                         break;
3835                     case MyCommon.TabUsageType.Lists:
3836                         //// TODO
3837                         TabClass tab = _statuses.Tabs[_curTab.Text];
3838                         if (tab.ListInfo == null || tab.ListInfo.Id == 0) return;
3839                         GetTimeline(MyCommon.WORKERTYPE.List, 1, 0, _curTab.Text);
3840                         break;
3841                     default:
3842                         GetTimeline(MyCommon.WORKERTYPE.Timeline, 1, 0, "");
3843                         break;
3844                 }
3845             }
3846             else
3847             {
3848                 GetTimeline(MyCommon.WORKERTYPE.Timeline, 1, 0, "");
3849             }
3850         }
3851
3852         private void DoRefreshMore()
3853         {
3854             //ページ指定をマイナス1に
3855             if (_curTab != null)
3856             {
3857                 switch (_statuses.Tabs[_curTab.Text].TabType)
3858                 {
3859                     case MyCommon.TabUsageType.Mentions:
3860                         GetTimeline(MyCommon.WORKERTYPE.Reply, -1, 0, "");
3861                         break;
3862                     case MyCommon.TabUsageType.DirectMessage:
3863                         GetTimeline(MyCommon.WORKERTYPE.DirectMessegeRcv, -1, 0, "");
3864                         break;
3865                     case MyCommon.TabUsageType.Favorites:
3866                         GetTimeline(MyCommon.WORKERTYPE.Favorites, -1, 0, "");
3867                         break;
3868                     case MyCommon.TabUsageType.Profile:
3869                         //// TODO
3870                         break;
3871                     case MyCommon.TabUsageType.PublicSearch:
3872                         // TODO
3873                         TabClass tb = _statuses.Tabs[_curTab.Text];
3874                         if (string.IsNullOrEmpty(tb.SearchWords)) return;
3875                         GetTimeline(MyCommon.WORKERTYPE.PublicSearch, -1, 0, _curTab.Text);
3876                         break;
3877                     case MyCommon.TabUsageType.UserTimeline:
3878                         GetTimeline(MyCommon.WORKERTYPE.UserTimeline, -1, 0, _curTab.Text);
3879                         break;
3880                     case MyCommon.TabUsageType.Lists:
3881                         //// TODO
3882                         TabClass tab = _statuses.Tabs[_curTab.Text];
3883                         if (tab.ListInfo == null || tab.ListInfo.Id == 0) return;
3884                         GetTimeline(MyCommon.WORKERTYPE.List, -1, 0, _curTab.Text);
3885                         break;
3886                     default:
3887                         GetTimeline(MyCommon.WORKERTYPE.Timeline, -1, 0, "");
3888                         break;
3889                 }
3890             }
3891             else
3892             {
3893                 GetTimeline(MyCommon.WORKERTYPE.Timeline, -1, 0, "");
3894             }
3895         }
3896
3897         private void SettingStripMenuItem_Click(object sender, EventArgs e)
3898         {
3899             DialogResult result;
3900             string uid = tw.Username.ToLower();
3901             var oldIconSz = SettingDialog.IconSz;
3902
3903             try
3904             {
3905                 result = SettingDialog.ShowDialog(this);
3906             }
3907             catch (Exception)
3908             {
3909                 return;
3910             }
3911
3912             if (result == DialogResult.OK)
3913             {
3914                 lock (_syncObject)
3915                 {
3916                     tw.TinyUrlResolve = SettingDialog.TinyUrlResolve;
3917                     tw.RestrictFavCheck = SettingDialog.RestrictFavCheck;
3918                     tw.ReadOwnPost = SettingDialog.ReadOwnPost;
3919                     ShortUrl.Instance.DisableExpanding = !SettingDialog.TinyUrlResolve;
3920                     ShortUrl.Instance.BitlyId = SettingDialog.BitlyUser;
3921                     ShortUrl.Instance.BitlyKey = SettingDialog.BitlyPwd;
3922                     HttpTwitter.TwitterUrl = _cfgCommon.TwitterUrl;
3923
3924                     HttpConnection.InitializeConnection(SettingDialog.DefaultTimeOut,
3925                                                         SettingDialog.SelectedProxyType,
3926                                                         SettingDialog.ProxyAddress,
3927                                                         SettingDialog.ProxyPort,
3928                                                         SettingDialog.ProxyUser,
3929                                                         SettingDialog.ProxyPassword);
3930
3931                     ImageSelector.Reset(tw);
3932
3933                     try
3934                     {
3935                         if (SettingDialog.TabIconDisp)
3936                         {
3937                             ListTab.DrawItem -= ListTab_DrawItem;
3938                             ListTab.DrawMode = TabDrawMode.Normal;
3939                             ListTab.ImageList = this.TabImage;
3940                         }
3941                         else
3942                         {
3943                             ListTab.DrawItem -= ListTab_DrawItem;
3944                             ListTab.DrawItem += ListTab_DrawItem;
3945                             ListTab.DrawMode = TabDrawMode.OwnerDrawFixed;
3946                             ListTab.ImageList = null;
3947                         }
3948                     }
3949                     catch (Exception ex)
3950                     {
3951                         ex.Data["Instance"] = "ListTab(TabIconDisp)";
3952                         ex.Data["IsTerminatePermission"] = false;
3953                         throw;
3954                     }
3955
3956                     try
3957                     {
3958                         if (!SettingDialog.UnreadManage)
3959                         {
3960                             ReadedStripMenuItem.Enabled = false;
3961                             UnreadStripMenuItem.Enabled = false;
3962                             if (SettingDialog.TabIconDisp)
3963                             {
3964                                 foreach (TabPage myTab in ListTab.TabPages)
3965                                 {
3966                                     myTab.ImageIndex = -1;
3967                                 }
3968                             }
3969                         }
3970                         else
3971                         {
3972                             ReadedStripMenuItem.Enabled = true;
3973                             UnreadStripMenuItem.Enabled = true;
3974                         }
3975                     }
3976                     catch (Exception ex)
3977                     {
3978                         ex.Data["Instance"] = "ListTab(UnreadManage)";
3979                         ex.Data["IsTerminatePermission"] = false;
3980                         throw;
3981                     }
3982
3983                     // タブの表示位置の決定
3984                     SetTabAlignment();
3985
3986                     SplitContainer1.IsPanelInverted = !SettingDialog.StatusAreaAtBottom;
3987
3988                     var imgazyobizinet = ThumbnailGenerator.ImgAzyobuziNetInstance;
3989                     imgazyobizinet.Enabled = this.SettingDialog.EnableImgAzyobuziNet;
3990                     imgazyobizinet.DisabledInDM = this.SettingDialog.ImgAzyobuziNetDisabledInDM;
3991
3992                     PlaySoundMenuItem.Checked = SettingDialog.PlaySound;
3993                     this.PlaySoundFileMenuItem.Checked = SettingDialog.PlaySound;
3994                     _fntUnread = SettingDialog.FontUnread;
3995                     _clUnread = SettingDialog.ColorUnread;
3996                     _fntReaded = SettingDialog.FontReaded;
3997                     _clReaded = SettingDialog.ColorReaded;
3998                     _clFav = SettingDialog.ColorFav;
3999                     _clOWL = SettingDialog.ColorOWL;
4000                     _clRetweet = SettingDialog.ColorRetweet;
4001                     _fntDetail = SettingDialog.FontDetail;
4002                     _clDetail = SettingDialog.ColorDetail;
4003                     _clDetailLink = SettingDialog.ColorDetailLink;
4004                     _clDetailBackcolor = SettingDialog.ColorDetailBackcolor;
4005                     _clSelf = SettingDialog.ColorSelf;
4006                     _clAtSelf = SettingDialog.ColorAtSelf;
4007                     _clTarget = SettingDialog.ColorTarget;
4008                     _clAtTarget = SettingDialog.ColorAtTarget;
4009                     _clAtFromTarget = SettingDialog.ColorAtFromTarget;
4010                     _clAtTo = SettingDialog.ColorAtTo;
4011                     _clListBackcolor = SettingDialog.ColorListBackcolor;
4012                     _clInputBackcolor = SettingDialog.ColorInputBackcolor;
4013                     _clInputFont = SettingDialog.ColorInputFont;
4014                     _fntInputFont = SettingDialog.FontInputFont;
4015                     _brsBackColorMine.Dispose();
4016                     _brsBackColorAt.Dispose();
4017                     _brsBackColorYou.Dispose();
4018                     _brsBackColorAtYou.Dispose();
4019                     _brsBackColorAtFromTarget.Dispose();
4020                     _brsBackColorAtTo.Dispose();
4021                     _brsBackColorNone.Dispose();
4022                     _brsBackColorMine = new SolidBrush(_clSelf);
4023                     _brsBackColorAt = new SolidBrush(_clAtSelf);
4024                     _brsBackColorYou = new SolidBrush(_clTarget);
4025                     _brsBackColorAtYou = new SolidBrush(_clAtTarget);
4026                     _brsBackColorAtFromTarget = new SolidBrush(_clAtFromTarget);
4027                     _brsBackColorAtTo = new SolidBrush(_clAtTo);
4028                     _brsBackColorNone = new SolidBrush(_clListBackcolor);
4029
4030                     try
4031                     {
4032                         if (StatusText.Focused) StatusText.BackColor = _clInputBackcolor;
4033                         StatusText.Font = _fntInputFont;
4034                         StatusText.ForeColor = _clInputFont;
4035                     }
4036                     catch (Exception ex)
4037                     {
4038                         MessageBox.Show(ex.Message);
4039                     }
4040
4041                     try
4042                     {
4043                         InitDetailHtmlFormat();
4044                     }
4045                     catch (Exception ex)
4046                     {
4047                         ex.Data["Instance"] = "Font";
4048                         ex.Data["IsTerminatePermission"] = false;
4049                         throw;
4050                     }
4051
4052                     try
4053                     {
4054                         _statuses.SetUnreadManage(SettingDialog.UnreadManage);
4055                     }
4056                     catch (Exception ex)
4057                     {
4058                         ex.Data["Instance"] = "_statuses";
4059                         ex.Data["IsTerminatePermission"] = false;
4060                         throw;
4061                     }
4062
4063                     try
4064                     {
4065                         foreach (TabPage tb in ListTab.TabPages)
4066                         {
4067                             if (SettingDialog.TabIconDisp)
4068                             {
4069                                 if (_statuses.Tabs[tb.Text].UnreadCount == 0)
4070                                     tb.ImageIndex = -1;
4071                                 else
4072                                     tb.ImageIndex = 0;
4073                             }
4074                         }
4075                     }
4076                     catch (Exception ex)
4077                     {
4078                         ex.Data["Instance"] = "ListTab(TabIconDisp no2)";
4079                         ex.Data["IsTerminatePermission"] = false;
4080                         throw;
4081                     }
4082
4083                     try
4084                     {
4085                         var oldIconCol = _iconCol;
4086
4087                         if (SettingDialog.IconSz != oldIconSz)
4088                             ApplyListViewIconSize(SettingDialog.IconSz);
4089
4090                         foreach (TabPage tp in ListTab.TabPages)
4091                         {
4092                             DetailsListView lst = (DetailsListView)tp.Tag;
4093
4094                             using (ControlTransaction.Update(lst))
4095                             {
4096                                 lst.GridLines = SettingDialog.ShowGrid;
4097                                 lst.Font = _fntReaded;
4098                                 lst.BackColor = _clListBackcolor;
4099
4100                                 if (_iconCol != oldIconCol)
4101                                     ResetColumns(lst);
4102                             }
4103                         }
4104                     }
4105                     catch (Exception ex)
4106                     {
4107                         ex.Data["Instance"] = "ListView(IconSize)";
4108                         ex.Data["IsTerminatePermission"] = false;
4109                         throw;
4110                     }
4111
4112                     SetMainWindowTitle();
4113                     SetNotifyIconText();
4114
4115                     this.PurgeListViewItemCache();
4116                     if (_curList != null) _curList.Refresh();
4117                     ListTab.Refresh();
4118
4119                     _hookGlobalHotkey.UnregisterAllOriginalHotkey();
4120                     if (SettingDialog.HotkeyEnabled)
4121                     {
4122                         ///グローバルホットキーの登録。設定で変更可能にするかも
4123                         HookGlobalHotkey.ModKeys modKey = HookGlobalHotkey.ModKeys.None;
4124                         if ((SettingDialog.HotkeyMod & Keys.Alt) == Keys.Alt) modKey = modKey | HookGlobalHotkey.ModKeys.Alt;
4125                         if ((SettingDialog.HotkeyMod & Keys.Control) == Keys.Control) modKey = modKey | HookGlobalHotkey.ModKeys.Ctrl;
4126                         if ((SettingDialog.HotkeyMod & Keys.Shift) == Keys.Shift) modKey = modKey | HookGlobalHotkey.ModKeys.Shift;
4127                         if ((SettingDialog.HotkeyMod & Keys.LWin) == Keys.LWin) modKey = modKey | HookGlobalHotkey.ModKeys.Win;
4128
4129                         _hookGlobalHotkey.RegisterOriginalHotkey(SettingDialog.HotkeyKey, SettingDialog.HotkeyValue, modKey);
4130                     }
4131
4132                     if (uid != tw.Username) this.doGetFollowersMenu();
4133
4134                     if (SettingDialog.IsNotifyUseGrowl) gh.RegisterGrowl();
4135                     try
4136                     {
4137                         StatusText_TextChanged(null, null);
4138                     }
4139                     catch (Exception)
4140                     {
4141                     }
4142                 }
4143             }
4144
4145             Twitter.AccountState = MyCommon.ACCOUNT_STATE.Valid;
4146
4147             this.TopMost = SettingDialog.AlwaysTop;
4148             SaveConfigsAll(false);
4149         }
4150
4151         /// <summary>
4152         /// タブの表示位置を設定する
4153         /// </summary>
4154         private void SetTabAlignment()
4155         {
4156             var newAlignment = SettingDialog.ViewTabBottom ? TabAlignment.Bottom : TabAlignment.Top;
4157             if (ListTab.Alignment == newAlignment) return;
4158
4159             //現在の選択状態を退避
4160             Dictionary<string, long[]> selId = new Dictionary<string, long[]>();
4161             Dictionary<string, long[]> focusedId = new Dictionary<string, long[]>();
4162             SaveSelectedStatus(selId, focusedId);
4163
4164             ListTab.Alignment = newAlignment;
4165
4166             //選択状態を復帰
4167             foreach (TabPage tab in ListTab.TabPages)
4168             {
4169                 DetailsListView lst = (DetailsListView)tab.Tag;
4170                 using (ControlTransaction.Update(lst))
4171                 {
4172                     this.SelectListItem(lst,
4173                                         _statuses.IndexOf(tab.Text, selId[tab.Text]),
4174                                         _statuses.IndexOf(tab.Text, focusedId[tab.Text]));
4175                 }
4176             }
4177         }
4178
4179         private void ApplyListViewIconSize(MyCommon.IconSizes iconSz)
4180         {
4181             // アイコンサイズの再設定
4182             _iconCol = false;
4183             switch (iconSz)
4184             {
4185                 case MyCommon.IconSizes.IconNone:
4186                     _iconSz = 0;
4187                     break;
4188                 case MyCommon.IconSizes.Icon16:
4189                     _iconSz = 16;
4190                     break;
4191                 case MyCommon.IconSizes.Icon24:
4192                     _iconSz = 26;
4193                     break;
4194                 case MyCommon.IconSizes.Icon48:
4195                     _iconSz = 48;
4196                     break;
4197                 case MyCommon.IconSizes.Icon48_2:
4198                     _iconSz = 48;
4199                     _iconCol = true;
4200                     break;
4201             }
4202
4203             if (_iconSz > 0)
4204             {
4205                 // ディスプレイの DPI 設定を考慮したサイズを設定する
4206                 _listViewImageList.ImageSize = new Size(
4207                     1,
4208                     (int)Math.Ceiling(this._iconSz * this.currentScaleFactor.Height));
4209             }
4210             else
4211             {
4212                 _listViewImageList.ImageSize = new Size(1, 1);
4213             }
4214         }
4215
4216         private void ResetColumns(DetailsListView list)
4217         {
4218             using (ControlTransaction.Update(list))
4219             using (ControlTransaction.Layout(list, false))
4220             {
4221                 // カラムヘッダの再設定
4222                 list.ColumnClick -= MyList_ColumnClick;
4223                 list.DrawColumnHeader -= MyList_DrawColumnHeader;
4224                 list.ColumnReordered -= MyList_ColumnReordered;
4225                 list.ColumnWidthChanged -= MyList_ColumnWidthChanged;
4226
4227                 var cols = list.Columns.Cast<ColumnHeader>().ToList();
4228                 list.Columns.Clear();
4229                 cols.ForEach(col => col.Dispose());
4230                 cols.Clear();
4231
4232                 InitColumns(list, true);
4233
4234                 list.ColumnClick += MyList_ColumnClick;
4235                 list.DrawColumnHeader += MyList_DrawColumnHeader;
4236                 list.ColumnReordered += MyList_ColumnReordered;
4237                 list.ColumnWidthChanged += MyList_ColumnWidthChanged;
4238             }
4239         }
4240
4241         private void PostBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
4242         {
4243             if (e.Url.AbsoluteUri != "about:blank")
4244             {
4245                 DispSelectedPost();
4246                 OpenUriAsync(e.Url.OriginalString);
4247             }
4248         }
4249
4250         private void PostBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
4251         {
4252             if (e.Url.Scheme == "data")
4253             {
4254                 StatusLabelUrl.Text = PostBrowser.StatusText.Replace("&", "&&");
4255             }
4256             else if (e.Url.AbsoluteUri != "about:blank")
4257             {
4258                 e.Cancel = true;
4259
4260                 if (e.Url.AbsoluteUri.StartsWith("http://twitter.com/search?q=%23") ||
4261                    e.Url.AbsoluteUri.StartsWith("https://twitter.com/search?q=%23"))
4262                 {
4263                     //ハッシュタグの場合は、タブで開く
4264                     string urlStr = Uri.UnescapeDataString(e.Url.AbsoluteUri);
4265                     int i = urlStr.IndexOf('#');
4266                     if (i == -1) return;
4267
4268                     string hash = urlStr.Substring(i);
4269                     HashSupl.AddItem(hash);
4270                     HashMgr.AddHashToHistory(hash.Trim(), false);
4271                     AddNewTabForSearch(hash);
4272                     return;
4273                 }
4274                 else
4275                 {
4276                     Match m = Regex.Match(e.Url.AbsoluteUri, "^https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)$");
4277                     if (m.Success && IsTwitterId(m.Result("${ScreenName}")))
4278                     {
4279                         // Ctrlを押しながらリンクをクリックした場合は設定と逆の動作をする
4280                         if (SettingDialog.OpenUserTimeline)
4281                         {
4282                             if (MyCommon.IsKeyDown(Keys.Control))
4283                                 OpenUriAsync(e.Url.OriginalString);
4284                             else
4285                                 this.AddNewTabForUserTimeline(m.Result("${ScreenName}"));
4286                         }
4287                         else
4288                         {
4289                             if (MyCommon.IsKeyDown(Keys.Control))
4290                                 this.AddNewTabForUserTimeline(m.Result("${ScreenName}"));
4291                             else
4292                                 OpenUriAsync(e.Url.OriginalString);
4293                         }
4294                     }
4295                     else
4296                     {
4297                         OpenUriAsync(e.Url.OriginalString);
4298                     }
4299                 }
4300             }
4301         }
4302
4303         public void AddNewTabForSearch(string searchWord)
4304         {
4305             //同一検索条件のタブが既に存在すれば、そのタブアクティブにして終了
4306             foreach (TabClass tb in _statuses.GetTabsByType(MyCommon.TabUsageType.PublicSearch))
4307             {
4308                 if (tb.SearchWords == searchWord && string.IsNullOrEmpty(tb.SearchLang))
4309                 {
4310                     foreach (TabPage tp in ListTab.TabPages)
4311                     {
4312                         if (tb.TabName == tp.Text)
4313                         {
4314                             ListTab.SelectedTab = tp;
4315                             return;
4316                         }
4317                     }
4318                 }
4319             }
4320             //ユニークなタブ名生成
4321             string tabName = searchWord;
4322             for (int i = 0; i <= 100; i++)
4323             {
4324                 if (_statuses.ContainsTab(tabName))
4325                     tabName += "_";
4326                 else
4327                     break;
4328             }
4329             //タブ追加
4330             _statuses.AddTab(tabName, MyCommon.TabUsageType.PublicSearch, null);
4331             AddNewTab(tabName, false, MyCommon.TabUsageType.PublicSearch);
4332             //追加したタブをアクティブに
4333             ListTab.SelectedIndex = ListTab.TabPages.Count - 1;
4334             //検索条件の設定
4335             ComboBox cmb = (ComboBox)ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"];
4336             cmb.Items.Add(searchWord);
4337             cmb.Text = searchWord;
4338             SaveConfigsTabs();
4339             //検索実行
4340             this.SearchButton_Click(ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"], null);
4341         }
4342
4343         private void ShowUserTimeline()
4344         {
4345             if (!this.ExistCurrentPost) return;
4346             AddNewTabForUserTimeline(_curPost.ScreenName);
4347         }
4348
4349         private void SearchComboBox_KeyDown(object sender, KeyEventArgs e)
4350         {
4351             if (e.KeyCode == Keys.Escape)
4352             {
4353                 TabPage relTp = ListTab.SelectedTab;
4354                 RemoveSpecifiedTab(relTp.Text, false);
4355                 SaveConfigsTabs();
4356                 e.SuppressKeyPress = true;
4357             }
4358         }
4359
4360         public void AddNewTabForUserTimeline(string user)
4361         {
4362             //同一検索条件のタブが既に存在すれば、そのタブアクティブにして終了
4363             foreach (TabClass tb in _statuses.GetTabsByType(MyCommon.TabUsageType.UserTimeline))
4364             {
4365                 if (tb.User == user)
4366                 {
4367                     foreach (TabPage tp in ListTab.TabPages)
4368                     {
4369                         if (tb.TabName == tp.Text)
4370                         {
4371                             ListTab.SelectedTab = tp;
4372                             return;
4373                         }
4374                     }
4375                 }
4376             }
4377             //ユニークなタブ名生成
4378             string tabName = "user:" + user;
4379             while (_statuses.ContainsTab(tabName))
4380             {
4381                 tabName += "_";
4382             }
4383             //タブ追加
4384             _statuses.AddTab(tabName, MyCommon.TabUsageType.UserTimeline, null);
4385             _statuses.Tabs[tabName].User = user;
4386             AddNewTab(tabName, false, MyCommon.TabUsageType.UserTimeline);
4387             //追加したタブをアクティブに
4388             ListTab.SelectedIndex = ListTab.TabPages.Count - 1;
4389             SaveConfigsTabs();
4390             //検索実行
4391
4392             GetTimeline(MyCommon.WORKERTYPE.UserTimeline, 1, 0, tabName);
4393         }
4394
4395         public bool AddNewTab(string tabName, bool startup, MyCommon.TabUsageType tabType, ListElement listInfo = null)
4396         {
4397             //重複チェック
4398             foreach (TabPage tb in ListTab.TabPages)
4399             {
4400                 if (tb.Text == tabName) return false;
4401             }
4402
4403             //新規タブ名チェック
4404             if (tabName == Properties.Resources.AddNewTabText1) return false;
4405
4406             //タブタイプ重複チェック
4407             if (!startup)
4408             {
4409                 if (tabType == MyCommon.TabUsageType.DirectMessage ||
4410                    tabType == MyCommon.TabUsageType.Favorites ||
4411                    tabType == MyCommon.TabUsageType.Home ||
4412                    tabType == MyCommon.TabUsageType.Mentions ||
4413                    tabType == MyCommon.TabUsageType.Related)
4414                 {
4415                     if (_statuses.GetTabByType(tabType) != null) return false;
4416                 }
4417             }
4418
4419             TabPage _tabPage = new TabPage();
4420             DetailsListView _listCustom = new DetailsListView();
4421
4422             int cnt = ListTab.TabPages.Count;
4423
4424             ///ToDo:Create and set controls follow tabtypes
4425
4426             using (ControlTransaction.Update(_listCustom))
4427             using (ControlTransaction.Layout(this.SplitContainer1.Panel1, false))
4428             using (ControlTransaction.Layout(this.SplitContainer1.Panel2, false))
4429             using (ControlTransaction.Layout(this.SplitContainer1, false))
4430             using (ControlTransaction.Layout(this.ListTab, false))
4431             using (ControlTransaction.Layout(this))
4432             using (ControlTransaction.Layout(_tabPage, false))
4433             {
4434                 /// UserTimeline関連
4435                 Label label = null;
4436                 if (tabType == MyCommon.TabUsageType.UserTimeline || tabType == MyCommon.TabUsageType.Lists)
4437                 {
4438                     label = new Label();
4439                     label.Dock = DockStyle.Top;
4440                     label.Name = "labelUser";
4441                     if (tabType == MyCommon.TabUsageType.Lists)
4442                     {
4443                         label.Text = listInfo.ToString();
4444                     }
4445                     else
4446                     {
4447                         label.Text = _statuses.Tabs[tabName].User + "'s Timeline";
4448                     }
4449                     label.TextAlign = ContentAlignment.MiddleLeft;
4450                     using (ComboBox tmpComboBox = new ComboBox())
4451                     {
4452                         label.Height = tmpComboBox.Height;
4453                     }
4454                     _tabPage.Controls.Add(label);
4455                 }
4456
4457                 /// 検索関連の準備
4458                 Panel pnl = null;
4459                 if (tabType == MyCommon.TabUsageType.PublicSearch)
4460                 {
4461                     pnl = new Panel();
4462
4463                     Label lbl = new Label();
4464                     ComboBox cmb = new ComboBox();
4465                     Button btn = new Button();
4466                     ComboBox cmbLang = new ComboBox();
4467
4468                     pnl.SuspendLayout();
4469
4470                     pnl.Controls.Add(cmb);
4471                     pnl.Controls.Add(cmbLang);
4472                     pnl.Controls.Add(btn);
4473                     pnl.Controls.Add(lbl);
4474                     pnl.Name = "panelSearch";
4475                     pnl.Dock = DockStyle.Top;
4476                     pnl.Height = cmb.Height;
4477                     pnl.Enter += SearchControls_Enter;
4478                     pnl.Leave += SearchControls_Leave;
4479
4480                     cmb.Text = "";
4481                     cmb.Anchor = AnchorStyles.Left | AnchorStyles.Right;
4482                     cmb.Dock = DockStyle.Fill;
4483                     cmb.Name = "comboSearch";
4484                     cmb.DropDownStyle = ComboBoxStyle.DropDown;
4485                     cmb.ImeMode = ImeMode.NoControl;
4486                     cmb.TabStop = false;
4487                     cmb.AutoCompleteMode = AutoCompleteMode.None;
4488                     cmb.KeyDown += SearchComboBox_KeyDown;
4489
4490                     if (_statuses.ContainsTab(tabName))
4491                     {
4492                         cmb.Items.Add(_statuses.Tabs[tabName].SearchWords);
4493                         cmb.Text = _statuses.Tabs[tabName].SearchWords;
4494                     }
4495
4496                     cmbLang.Text = "";
4497                     cmbLang.Anchor = AnchorStyles.Left | AnchorStyles.Right;
4498                     cmbLang.Dock = DockStyle.Right;
4499                     cmbLang.Width = 50;
4500                     cmbLang.Name = "comboLang";
4501                     cmbLang.DropDownStyle = ComboBoxStyle.DropDownList;
4502                     cmbLang.TabStop = false;
4503                     cmbLang.Items.Add("");
4504                     cmbLang.Items.Add("ja");
4505                     cmbLang.Items.Add("en");
4506                     cmbLang.Items.Add("ar");
4507                     cmbLang.Items.Add("da");
4508                     cmbLang.Items.Add("nl");
4509                     cmbLang.Items.Add("fa");
4510                     cmbLang.Items.Add("fi");
4511                     cmbLang.Items.Add("fr");
4512                     cmbLang.Items.Add("de");
4513                     cmbLang.Items.Add("hu");
4514                     cmbLang.Items.Add("is");
4515                     cmbLang.Items.Add("it");
4516                     cmbLang.Items.Add("no");
4517                     cmbLang.Items.Add("pl");
4518                     cmbLang.Items.Add("pt");
4519                     cmbLang.Items.Add("ru");
4520                     cmbLang.Items.Add("es");
4521                     cmbLang.Items.Add("sv");
4522                     cmbLang.Items.Add("th");
4523                     if (_statuses.ContainsTab(tabName)) cmbLang.Text = _statuses.Tabs[tabName].SearchLang;
4524
4525                     lbl.Text = "Search(C-S-f)";
4526                     lbl.Name = "label1";
4527                     lbl.Dock = DockStyle.Left;
4528                     lbl.Width = 90;
4529                     lbl.Height = cmb.Height;
4530                     lbl.TextAlign = ContentAlignment.MiddleLeft;
4531
4532                     btn.Text = "Search";
4533                     btn.Name = "buttonSearch";
4534                     btn.UseVisualStyleBackColor = true;
4535                     btn.Dock = DockStyle.Right;
4536                     btn.TabStop = false;
4537                     btn.Click += SearchButton_Click;
4538                 }
4539
4540                 this.ListTab.Controls.Add(_tabPage);
4541                 _tabPage.Controls.Add(_listCustom);
4542
4543                 if (tabType == MyCommon.TabUsageType.PublicSearch) _tabPage.Controls.Add(pnl);
4544                 if (tabType == MyCommon.TabUsageType.UserTimeline || tabType == MyCommon.TabUsageType.Lists) _tabPage.Controls.Add(label);
4545
4546                 _tabPage.Location = new Point(4, 4);
4547                 _tabPage.Name = "CTab" + cnt.ToString();
4548                 _tabPage.Size = new Size(380, 260);
4549                 _tabPage.TabIndex = 2 + cnt;
4550                 _tabPage.Text = tabName;
4551                 _tabPage.UseVisualStyleBackColor = true;
4552
4553                 _listCustom.AllowColumnReorder = true;
4554                 _listCustom.ContextMenuStrip = this.ContextMenuOperate;
4555                 _listCustom.ColumnHeaderContextMenuStrip = this.ContextMenuColumnHeader;
4556                 _listCustom.Dock = DockStyle.Fill;
4557                 _listCustom.FullRowSelect = true;
4558                 _listCustom.HideSelection = false;
4559                 _listCustom.Location = new Point(0, 0);
4560                 _listCustom.Margin = new Padding(0);
4561                 _listCustom.Name = "CList" + Environment.TickCount.ToString();
4562                 _listCustom.ShowItemToolTips = true;
4563                 _listCustom.Size = new Size(380, 260);
4564                 _listCustom.UseCompatibleStateImageBehavior = false;
4565                 _listCustom.View = View.Details;
4566                 _listCustom.OwnerDraw = true;
4567                 _listCustom.VirtualMode = true;
4568                 _listCustom.Font = _fntReaded;
4569                 _listCustom.BackColor = _clListBackcolor;
4570
4571                 _listCustom.GridLines = SettingDialog.ShowGrid;
4572                 _listCustom.AllowDrop = true;
4573
4574                 _listCustom.SmallImageList = _listViewImageList;
4575
4576                 InitColumns(_listCustom, startup);
4577
4578                 _listCustom.SelectedIndexChanged += MyList_SelectedIndexChanged;
4579                 _listCustom.MouseDoubleClick += MyList_MouseDoubleClick;
4580                 _listCustom.ColumnClick += MyList_ColumnClick;
4581                 _listCustom.DrawColumnHeader += MyList_DrawColumnHeader;
4582                 _listCustom.DragDrop += TweenMain_DragDrop;
4583                 _listCustom.DragEnter += TweenMain_DragEnter;
4584                 _listCustom.DragOver += TweenMain_DragOver;
4585                 _listCustom.DrawItem += MyList_DrawItem;
4586                 _listCustom.MouseClick += MyList_MouseClick;
4587                 _listCustom.ColumnReordered += MyList_ColumnReordered;
4588                 _listCustom.ColumnWidthChanged += MyList_ColumnWidthChanged;
4589                 _listCustom.CacheVirtualItems += MyList_CacheVirtualItems;
4590                 _listCustom.RetrieveVirtualItem += MyList_RetrieveVirtualItem;
4591                 _listCustom.DrawSubItem += MyList_DrawSubItem;
4592                 _listCustom.HScrolled += MyList_HScrolled;
4593
4594                 if (tabType == MyCommon.TabUsageType.PublicSearch) pnl.ResumeLayout(false);
4595             }
4596
4597             _tabPage.Tag = _listCustom;
4598             return true;
4599         }
4600
4601         public bool RemoveSpecifiedTab(string TabName, bool confirm)
4602         {
4603             if (_statuses.IsDefaultTab(TabName) || _statuses.Tabs[TabName].Protected) return false;
4604
4605             if (confirm)
4606             {
4607                 string tmp = string.Format(Properties.Resources.RemoveSpecifiedTabText1, Environment.NewLine);
4608                 if (MessageBox.Show(tmp, TabName + " " + Properties.Resources.RemoveSpecifiedTabText2,
4609                                  MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Cancel)
4610                 {
4611                     return false;
4612                 }
4613             }
4614
4615             var _tabPage = ListTab.TabPages.Cast<TabPage>().FirstOrDefault<TabPage>(tp => tp.Text == TabName);
4616             if (_tabPage == null) return false;
4617
4618             SetListProperty();   //他のタブに列幅等を反映
4619
4620             MyCommon.TabUsageType tabType = _statuses.Tabs[TabName].TabType;
4621
4622             //オブジェクトインスタンスの削除
4623             DetailsListView _listCustom = (DetailsListView)_tabPage.Tag;
4624             _tabPage.Tag = null;
4625
4626             using (ControlTransaction.Layout(this.SplitContainer1.Panel1, false))
4627             using (ControlTransaction.Layout(this.SplitContainer1.Panel2, false))
4628             using (ControlTransaction.Layout(this.SplitContainer1, false))
4629             using (ControlTransaction.Layout(this.ListTab, false))
4630             using (ControlTransaction.Layout(this))
4631             using (ControlTransaction.Layout(_tabPage, false))
4632             {
4633                 if (this.ListTab.SelectedTab == _tabPage)
4634                 {
4635                     this.ListTab.SelectTab((this._beforeSelectedTab != null && this.ListTab.TabPages.Contains(this._beforeSelectedTab)) ? this._beforeSelectedTab : this.ListTab.TabPages[0]);
4636                     this._beforeSelectedTab = null;
4637                 }
4638                 this.ListTab.Controls.Remove(_tabPage);
4639
4640                 // 後付けのコントロールを破棄
4641                 if (tabType == MyCommon.TabUsageType.UserTimeline || tabType == MyCommon.TabUsageType.Lists)
4642                 {
4643                     using (Control label = _tabPage.Controls["labelUser"])
4644                     {
4645                         _tabPage.Controls.Remove(label);
4646                     }
4647                 }
4648                 else if (tabType == MyCommon.TabUsageType.PublicSearch)
4649                 {
4650                     using (Control pnl = _tabPage.Controls["panelSearch"])
4651                     {
4652                         pnl.Enter -= SearchControls_Enter;
4653                         pnl.Leave -= SearchControls_Leave;
4654                         _tabPage.Controls.Remove(pnl);
4655
4656                         foreach (Control ctrl in pnl.Controls)
4657                         {
4658                             if (ctrl.Name == "buttonSearch")
4659                             {
4660                                 ctrl.Click -= SearchButton_Click;
4661                             }
4662                             else if (ctrl.Name == "comboSearch")
4663                             {
4664                                 ctrl.KeyDown -= SearchComboBox_KeyDown;
4665                             }
4666                             pnl.Controls.Remove(ctrl);
4667                             ctrl.Dispose();
4668                         }
4669                     }
4670                 }
4671
4672                 _tabPage.Controls.Remove(_listCustom);
4673
4674                 _listCustom.SelectedIndexChanged -= MyList_SelectedIndexChanged;
4675                 _listCustom.MouseDoubleClick -= MyList_MouseDoubleClick;
4676                 _listCustom.ColumnClick -= MyList_ColumnClick;
4677                 _listCustom.DrawColumnHeader -= MyList_DrawColumnHeader;
4678                 _listCustom.DragDrop -= TweenMain_DragDrop;
4679                 _listCustom.DragEnter -= TweenMain_DragEnter;
4680                 _listCustom.DragOver -= TweenMain_DragOver;
4681                 _listCustom.DrawItem -= MyList_DrawItem;
4682                 _listCustom.MouseClick -= MyList_MouseClick;
4683                 _listCustom.ColumnReordered -= MyList_ColumnReordered;
4684                 _listCustom.ColumnWidthChanged -= MyList_ColumnWidthChanged;
4685                 _listCustom.CacheVirtualItems -= MyList_CacheVirtualItems;
4686                 _listCustom.RetrieveVirtualItem -= MyList_RetrieveVirtualItem;
4687                 _listCustom.DrawSubItem -= MyList_DrawSubItem;
4688                 _listCustom.HScrolled -= MyList_HScrolled;
4689
4690                 var cols = _listCustom.Columns.Cast<ColumnHeader>().ToList<ColumnHeader>();
4691                 _listCustom.Columns.Clear();
4692                 cols.ForEach(col => col.Dispose());
4693                 cols.Clear();
4694
4695                 _listCustom.ContextMenuStrip = null;
4696                 _listCustom.ColumnHeaderContextMenuStrip = null;
4697                 _listCustom.Font = null;
4698
4699                 _listCustom.SmallImageList = null;
4700                 _listCustom.ListViewItemSorter = null;
4701
4702                 //キャッシュのクリア
4703                 if (_curTab.Equals(_tabPage))
4704                 {
4705                     _curTab = null;
4706                     _curItemIndex = -1;
4707                     _curList = null;
4708                     _curPost = null;
4709                 }
4710                 this.PurgeListViewItemCache();
4711             }
4712
4713             _tabPage.Dispose();
4714             _listCustom.Dispose();
4715             _statuses.RemoveTab(TabName);
4716
4717             foreach (TabPage tp in ListTab.TabPages)
4718             {
4719                 DetailsListView lst = (DetailsListView)tp.Tag;
4720                 var count = _statuses.Tabs[tp.Text].AllCount;
4721                 if (lst.VirtualListSize != count)
4722                 {
4723                     lst.VirtualListSize = count;
4724                 }
4725             }
4726
4727             return true;
4728         }
4729
4730         private void ListTab_Deselected(object sender, TabControlEventArgs e)
4731         {
4732             this.PurgeListViewItemCache();
4733             _beforeSelectedTab = e.TabPage;
4734         }
4735
4736         private void ListTab_MouseMove(object sender, MouseEventArgs e)
4737         {
4738             //タブのD&D
4739
4740             if (!SettingDialog.TabMouseLock && e.Button == MouseButtons.Left && _tabDrag)
4741             {
4742                 string tn = "";
4743                 Rectangle dragEnableRectangle = new Rectangle((int)(_tabMouseDownPoint.X - (SystemInformation.DragSize.Width / 2)), (int)(_tabMouseDownPoint.Y - (SystemInformation.DragSize.Height / 2)), SystemInformation.DragSize.Width, SystemInformation.DragSize.Height);
4744                 if (!dragEnableRectangle.Contains(e.Location))
4745                 {
4746                     //タブが多段の場合にはMouseDownの前の段階で選択されたタブの段が変わっているので、このタイミングでカーソルの位置からタブを判定出来ない。
4747                     tn = ListTab.SelectedTab.Text;
4748                 }
4749
4750                 if (string.IsNullOrEmpty(tn)) return;
4751
4752                 foreach (TabPage tb in ListTab.TabPages)
4753                 {
4754                     if (tb.Text == tn)
4755                     {
4756                         ListTab.DoDragDrop(tb, DragDropEffects.All);
4757                         break;
4758                     }
4759                 }
4760             }
4761             else
4762             {
4763                 _tabDrag = false;
4764             }
4765
4766             Point cpos = new Point(e.X, e.Y);
4767             for (int i = 0; i < ListTab.TabPages.Count; i++)
4768             {
4769                 Rectangle rect = ListTab.GetTabRect(i);
4770                 if (rect.Left <= cpos.X & cpos.X <= rect.Right &
4771                    rect.Top <= cpos.Y & cpos.Y <= rect.Bottom)
4772                 {
4773                     _rclickTabName = ListTab.TabPages[i].Text;
4774                     break;
4775                 }
4776             }
4777         }
4778
4779         private void ListTab_SelectedIndexChanged(object sender, EventArgs e)
4780         {
4781             //_curList.Refresh();
4782             DispSelectedPost();
4783             SetMainWindowTitle();
4784             SetStatusLabelUrl();
4785             if (ListTab.Focused || ((Control)ListTab.SelectedTab.Tag).Focused) this.Tag = ListTab.Tag;
4786             TabMenuControl(ListTab.SelectedTab.Text);
4787             this.PushSelectPostChain();
4788         }
4789
4790         private void SetListProperty()
4791         {
4792             //削除などで見つからない場合は処理せず
4793             if (_curList == null) return;
4794             if (!_isColumnChanged) return;
4795
4796             int[] dispOrder = new int[_curList.Columns.Count];
4797             for (int i = 0; i < _curList.Columns.Count; i++)
4798             {
4799                 for (int j = 0; j < _curList.Columns.Count; j++)
4800                 {
4801                     if (_curList.Columns[j].DisplayIndex == i)
4802                     {
4803                         dispOrder[i] = j;
4804                         break;
4805                     }
4806                 }
4807             }
4808
4809             //列幅、列並びを他のタブに設定
4810             foreach (TabPage tb in ListTab.TabPages)
4811             {
4812                 if (!tb.Equals(_curTab))
4813                 {
4814                     if (tb.Tag != null && tb.Controls.Count > 0)
4815                     {
4816                         DetailsListView lst = (DetailsListView)tb.Tag;
4817                         for (int i = 0; i < lst.Columns.Count; i++)
4818                         {
4819                             lst.Columns[dispOrder[i]].DisplayIndex = i;
4820                             lst.Columns[i].Width = _curList.Columns[i].Width;
4821                         }
4822                     }
4823                 }
4824             }
4825
4826             _isColumnChanged = false;
4827         }
4828
4829         private void PostBrowser_StatusTextChanged(object sender, EventArgs e)
4830         {
4831             try
4832             {
4833                 if (PostBrowser.StatusText.StartsWith("http") || PostBrowser.StatusText.StartsWith("ftp")
4834                         || PostBrowser.StatusText.StartsWith("data"))
4835                 {
4836                     StatusLabelUrl.Text = PostBrowser.StatusText.Replace("&", "&&");
4837                 }
4838                 if (string.IsNullOrEmpty(PostBrowser.StatusText))
4839                 {
4840                     SetStatusLabelUrl();
4841                 }
4842             }
4843             catch (Exception)
4844             {
4845             }
4846         }
4847
4848         private void StatusText_KeyPress(object sender, KeyPressEventArgs e)
4849         {
4850             if (e.KeyChar == '@')
4851             {
4852                 if (!SettingDialog.UseAtIdSupplement) return;
4853                 //@マーク
4854                 int cnt = AtIdSupl.ItemCount;
4855                 ShowSuplDialog(StatusText, AtIdSupl);
4856                 if (cnt != AtIdSupl.ItemCount) _modifySettingAtId = true;
4857                 e.Handled = true;
4858             }
4859             else if (e.KeyChar == '#')
4860             {
4861                 if (!SettingDialog.UseHashSupplement) return;
4862                 ShowSuplDialog(StatusText, HashSupl);
4863                 e.Handled = true;
4864             }
4865         }
4866
4867         public void ShowSuplDialog(TextBox owner, AtIdSupplement dialog)
4868         {
4869             ShowSuplDialog(owner, dialog, 0, "");
4870         }
4871
4872         public void ShowSuplDialog(TextBox owner, AtIdSupplement dialog, int offset)
4873         {
4874             ShowSuplDialog(owner, dialog, offset, "");
4875         }
4876
4877         public void ShowSuplDialog(TextBox owner, AtIdSupplement dialog, int offset, string startswith)
4878         {
4879             dialog.StartsWith = startswith;
4880             if (dialog.Visible)
4881             {
4882                 dialog.Focus();
4883             }
4884             else
4885             {
4886                 dialog.ShowDialog();
4887             }
4888             this.TopMost = SettingDialog.AlwaysTop;
4889             int selStart = owner.SelectionStart;
4890             string fHalf = "";
4891             string eHalf = "";
4892             if (dialog.DialogResult == DialogResult.OK)
4893             {
4894                 if (!string.IsNullOrEmpty(dialog.inputText))
4895                 {
4896                     if (selStart > 0)
4897                     {
4898                         fHalf = owner.Text.Substring(0, selStart - offset);
4899                     }
4900                     if (selStart < owner.Text.Length)
4901                     {
4902                         eHalf = owner.Text.Substring(selStart);
4903                     }
4904                     owner.Text = fHalf + dialog.inputText + eHalf;
4905                     owner.SelectionStart = selStart + dialog.inputText.Length;
4906                 }
4907             }
4908             else
4909             {
4910                 if (selStart > 0)
4911                 {
4912                     fHalf = owner.Text.Substring(0, selStart);
4913                 }
4914                 if (selStart < owner.Text.Length)
4915                 {
4916                     eHalf = owner.Text.Substring(selStart);
4917                 }
4918                 owner.Text = fHalf + eHalf;
4919                 if (selStart > 0)
4920                 {
4921                     owner.SelectionStart = selStart;
4922                 }
4923             }
4924             owner.Focus();
4925         }
4926
4927         private void StatusText_KeyUp(object sender, KeyEventArgs e)
4928         {
4929             //スペースキーで未読ジャンプ
4930             if (!e.Alt && !e.Control && !e.Shift)
4931             {
4932                 if (e.KeyCode == Keys.Space || e.KeyCode == Keys.ProcessKey)
4933                 {
4934                     bool isSpace = false;
4935                     foreach (char c in StatusText.Text.ToCharArray())
4936                     {
4937                         if (c == ' ' || c == ' ')
4938                         {
4939                             isSpace = true;
4940                         }
4941                         else
4942                         {
4943                             isSpace = false;
4944                             break;
4945                         }
4946                     }
4947                     if (isSpace)
4948                     {
4949                         e.Handled = true;
4950                         StatusText.Text = "";
4951                         JumpUnreadMenuItem_Click(null, null);
4952                     }
4953                 }
4954             }
4955             this.StatusText_TextChanged(null, null);
4956         }
4957
4958         private void StatusText_TextChanged(object sender, EventArgs e)
4959         {
4960             //文字数カウント
4961             int pLen = GetRestStatusCount(true, false);
4962             lblLen.Text = pLen.ToString();
4963             if (pLen < 0)
4964             {
4965                 StatusText.ForeColor = Color.Red;
4966             }
4967             else
4968             {
4969                 StatusText.ForeColor = _clInputFont;
4970             }
4971             if (string.IsNullOrEmpty(StatusText.Text))
4972             {
4973                 _reply_to_id = null;
4974                 _reply_to_name = null;
4975             }
4976         }
4977
4978         private int GetRestStatusCount(bool isAuto, bool isAddFooter)
4979         {
4980             //文字数カウント
4981             var statusText = this.StatusText.Text;
4982             statusText = statusText.Replace("\r\n", "\n");
4983
4984             int pLen = 140 - statusText.Length;
4985             if (this.NotifyIcon1 == null || !this.NotifyIcon1.Visible) return pLen;
4986             if ((isAuto && !MyCommon.IsKeyDown(Keys.Control) && SettingDialog.PostShiftEnter) ||
4987                 (isAuto && !MyCommon.IsKeyDown(Keys.Shift) && !SettingDialog.PostShiftEnter) ||
4988                 (!isAuto && isAddFooter))
4989             {
4990                 if (SettingDialog.UseRecommendStatus)
4991                     pLen -= SettingDialog.RecommendStatusText.Length;
4992                 else if (SettingDialog.Status.Length > 0)
4993                     pLen -= SettingDialog.Status.Length + 1;
4994             }
4995             if (!string.IsNullOrEmpty(HashMgr.UseHash))
4996             {
4997                 pLen -= HashMgr.UseHash.Length + 1;
4998             }
4999             //foreach (Match m in Regex.Matches(statusText, "https?:\/\/[-_.!~*//()a-zA-Z0-9;\/?:\@&=+\$,%#^]+"))
5000             //{
5001             //    pLen += m.Length - SettingDialog.TwitterConfiguration.ShortUrlLength;
5002             //}
5003             foreach (Match m in Regex.Matches(statusText, Twitter.rgUrl, RegexOptions.IgnoreCase))
5004             {
5005                 string before = m.Result("${before}");
5006                 string url = m.Result("${url}");
5007                 string protocol = m.Result("${protocol}");
5008                 string domain = m.Result("${domain}");
5009                 string path = m.Result("${path}");
5010                 if (protocol.Length == 0)
5011                 {
5012                     if (Regex.IsMatch(before, Twitter.url_invalid_without_protocol_preceding_chars))
5013                     {
5014                         continue;
5015                     }
5016
5017                     bool last_url_invalid_match = false;
5018                     string lasturl = null;
5019                     foreach (Match mm in Regex.Matches(domain, Twitter.url_valid_ascii_domain, RegexOptions.IgnoreCase))
5020                     {
5021                         lasturl = mm.ToString();
5022                         last_url_invalid_match = Regex.IsMatch(lasturl, Twitter.url_invalid_short_domain, RegexOptions.IgnoreCase);
5023                         if (!last_url_invalid_match)
5024                         {
5025                             pLen += lasturl.Length - SettingDialog.TwitterConfiguration.ShortUrlLength;
5026                         }
5027                     }
5028
5029                     if (path.Length != 0)
5030                     {
5031                         if (last_url_invalid_match)
5032                         {
5033                             pLen += lasturl.Length - SettingDialog.TwitterConfiguration.ShortUrlLength;
5034                         }
5035                         pLen += path.Length;
5036                     }
5037                 }
5038                 else
5039                 {
5040                     int shortUrlLength = protocol == "https://"
5041                         ? SettingDialog.TwitterConfiguration.ShortUrlLengthHttps
5042                         : SettingDialog.TwitterConfiguration.ShortUrlLength;
5043
5044                     pLen += url.Length - shortUrlLength;
5045                 }
5046                 
5047                 //if (m.Result("${url}").Length > SettingDialog.TwitterConfiguration.ShortUrlLength)
5048                 //{
5049                 //    pLen += m.Result("${url}").Length - SettingDialog.TwitterConfiguration.ShortUrlLength;
5050                 //}
5051             }
5052             if (ImageSelector.Visible && !string.IsNullOrEmpty(ImageSelector.ServiceName))
5053             {
5054                 pLen -= SettingDialog.TwitterConfiguration.CharactersReservedPerMedia;
5055             }
5056             return pLen;
5057         }
5058
5059         private void MyList_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
5060         {
5061             this.itemCacheLock.EnterUpgradeableReadLock();
5062             try
5063             {
5064                 if (_curList.Equals(sender))
5065                 {
5066                     if (_itemCache != null &&
5067                        e.StartIndex >= _itemCacheIndex &&
5068                        e.EndIndex < _itemCacheIndex + _itemCache.Length)
5069                     {
5070                         //If the newly requested cache is a subset of the old cache, 
5071                         //no need to rebuild everything, so do nothing.
5072                         return;
5073                     }
5074
5075                     //Now we need to rebuild the cache.
5076                     CreateCache(e.StartIndex, e.EndIndex);
5077                 }
5078             }
5079             finally { this.itemCacheLock.ExitUpgradeableReadLock(); }
5080         }
5081
5082         private async void MyList_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
5083         {
5084             ListViewItem item = null;
5085             PostClass cacheItemPost = null;
5086
5087             if (_curList.Equals(sender))
5088                 this.TryGetListViewItemCache(e.ItemIndex, out item, out cacheItemPost);
5089
5090             if (item == null)
5091             {
5092                 //A cache miss, so create a new ListViewItem and pass it back.
5093                 TabPage tb = (TabPage)((DetailsListView)sender).Parent;
5094                 try
5095                 {
5096                     item = this.CreateItem(tb, _statuses[tb.Text, e.ItemIndex], e.ItemIndex);
5097                 }
5098                 catch (Exception)
5099                 {
5100                     //不正な要求に対する間に合わせの応答
5101                     string[] sitem = {"", "", "", "", "", "", "", ""};
5102                     item = new ImageListViewItem(sitem);
5103                 }
5104             }
5105
5106             // e.Item に値をセットする前に await しないこと
5107             e.Item = item;
5108
5109             await ((ImageListViewItem)item).GetImageAsync();
5110         }
5111
5112         private void CreateCache(int StartIndex, int EndIndex)
5113         {
5114             this.itemCacheLock.EnterWriteLock();
5115             try
5116             {
5117                 //キャッシュ要求(要求範囲±30を作成)
5118                 StartIndex -= 30;
5119                 if (StartIndex < 0) StartIndex = 0;
5120                 EndIndex += 30;
5121                 if (EndIndex >= _statuses.Tabs[_curTab.Text].AllCount) EndIndex = _statuses.Tabs[_curTab.Text].AllCount - 1;
5122                 _postCache = _statuses[_curTab.Text, StartIndex, EndIndex]; //配列で取得
5123                 _itemCacheIndex = StartIndex;
5124
5125                 _itemCache = new ListViewItem[0] {};
5126                 Array.Resize(ref _itemCache, _postCache.Length);
5127
5128                 for (int i = 0; i < _postCache.Length; i++)
5129                 {
5130                     _itemCache[i] = CreateItem(_curTab, _postCache[i], StartIndex + i);
5131                 }
5132             }
5133             catch (Exception)
5134             {
5135                 //キャッシュ要求が実データとずれるため(イベントの遅延?)
5136                 _postCache = null;
5137                 _itemCacheIndex = -1;
5138                 _itemCache = null;
5139             }
5140             finally { this.itemCacheLock.ExitWriteLock(); }
5141         }
5142
5143         /// <summary>
5144         /// DetailsListView のための ListViewItem のキャッシュを消去する
5145         /// </summary>
5146         private void PurgeListViewItemCache()
5147         {
5148             this.itemCacheLock.EnterWriteLock();
5149             try
5150             {
5151                 this._itemCache = null;
5152                 this._itemCacheIndex = -1;
5153                 this._postCache = null;
5154             }
5155             finally { this.itemCacheLock.ExitWriteLock(); }
5156         }
5157
5158         private bool TryGetListViewItemCache(int index, out ListViewItem item, out PostClass post)
5159         {
5160             this.itemCacheLock.EnterReadLock();
5161             try
5162             {
5163                 if (this._itemCache != null && index >= this._itemCacheIndex && index < this._itemCacheIndex + this._itemCache.Length)
5164                 {
5165                     item = this._itemCache[index - _itemCacheIndex];
5166                     post = this._postCache[index - _itemCacheIndex];
5167                     return true;
5168                 }
5169             }
5170             finally { this.itemCacheLock.ExitReadLock(); }
5171
5172             item = null;
5173             post = null;
5174             return false;
5175         }
5176
5177         private ListViewItem CreateItem(TabPage Tab, PostClass Post, int Index)
5178         {
5179             StringBuilder mk = new StringBuilder();
5180             //if (Post.IsDeleted) mk.Append("×");
5181             //if (Post.IsMark) mk.Append("♪");
5182             //if (Post.IsProtect) mk.Append("Ю");
5183             //if (Post.InReplyToStatusId != null) mk.Append("⇒");
5184             if (Post.FavoritedCount > 0) mk.Append("+" + Post.FavoritedCount.ToString());
5185             ImageListViewItem itm;
5186             if (Post.RetweetedId == null)
5187             {
5188                 string[] sitem= {"",
5189                                  Post.Nickname,
5190                                  Post.IsDeleted ? "(DELETED)" : Post.TextSingleLine,
5191                                  Post.CreatedAt.ToString(SettingDialog.DateTimeFormat),
5192                                  Post.ScreenName,
5193                                  "",
5194                                  mk.ToString(),
5195                                  Post.Source};
5196                 itm = new ImageListViewItem(sitem, this.IconCache, Post.ImageUrl);
5197             }
5198             else
5199             {
5200                 string[] sitem = {"",
5201                                   Post.Nickname,
5202                                   Post.IsDeleted ? "(DELETED)" : Post.TextSingleLine,
5203                                   Post.CreatedAt.ToString(SettingDialog.DateTimeFormat),
5204                                   Post.ScreenName + Environment.NewLine + "(RT:" + Post.RetweetedBy + ")",
5205                                   "",
5206                                   mk.ToString(),
5207                                   Post.Source};
5208                 itm = new ImageListViewItem(sitem, this.IconCache, Post.ImageUrl);
5209             }
5210             itm.StateImageIndex = Post.StateIndex;
5211
5212             bool read = Post.IsRead;
5213             //未読管理していなかったら既読として扱う
5214             if (!_statuses.Tabs[Tab.Text].UnreadManage || !SettingDialog.UnreadManage) read = true;
5215             ChangeItemStyleRead(read, itm, Post, null);
5216             if (Tab.Equals(_curTab)) ColorizeList(itm, Index);
5217             return itm;
5218         }
5219
5220         /// <summary>
5221         /// 全てのタブの振り分けルールを反映し直します
5222         /// </summary>
5223         private void ApplyPostFilters()
5224         {
5225             try
5226             {
5227                 this.Cursor = Cursors.WaitCursor;
5228
5229                 this.PurgeListViewItemCache();
5230                 this._curPost = null;
5231                 this._curItemIndex = -1;
5232                 this._statuses.FilterAll();
5233
5234                 foreach (TabPage tabPage in this.ListTab.TabPages)
5235                 {
5236                     var tab = this._statuses.Tabs[tabPage.Text];
5237
5238                     var listview = (DetailsListView)tabPage.Tag;
5239                     listview.VirtualListSize = tab.AllCount;
5240
5241                     if (this.SettingDialog.TabIconDisp)
5242                     {
5243                         if (tab.UnreadCount > 0)
5244                             tabPage.ImageIndex = 0;
5245                         else
5246                             tabPage.ImageIndex = -1;
5247                     }
5248                 }
5249
5250                 if (!this.SettingDialog.TabIconDisp)
5251                     this.ListTab.Refresh();
5252             }
5253             finally
5254             {
5255                 this.Cursor = Cursors.Default;
5256             }
5257         }
5258
5259         private void MyList_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
5260         {
5261             e.DrawDefault = true;
5262         }
5263
5264         private void MyList_HScrolled(object sender, EventArgs e)
5265         {
5266             DetailsListView listView = (DetailsListView)sender;
5267             listView.Refresh();
5268         }
5269
5270         private void MyList_DrawItem(object sender, DrawListViewItemEventArgs e)
5271         {
5272             if (e.State == 0) return;
5273             e.DrawDefault = false;
5274
5275             SolidBrush brs2 = null;
5276             if (!e.Item.Selected)     //e.ItemStateでうまく判定できない???
5277             {
5278                 if (e.Item.BackColor == _clSelf)
5279                     brs2 = _brsBackColorMine;
5280                 else if (e.Item.BackColor == _clAtSelf)
5281                     brs2 = _brsBackColorAt;
5282                 else if (e.Item.BackColor == _clTarget)
5283                     brs2 = _brsBackColorYou;
5284                 else if (e.Item.BackColor == _clAtTarget)
5285                     brs2 = _brsBackColorAtYou;
5286                 else if (e.Item.BackColor == _clAtFromTarget)
5287                     brs2 = _brsBackColorAtFromTarget;
5288                 else if (e.Item.BackColor == _clAtTo)
5289                     brs2 = _brsBackColorAtTo;
5290                 else
5291                     brs2 = _brsBackColorNone;
5292             }
5293             else
5294             {
5295                 //選択中の行
5296                 if (((Control)sender).Focused)
5297                     brs2 = _brsHighLight;
5298                 else
5299                     brs2 = _brsDeactiveSelection;
5300             }
5301             e.Graphics.FillRectangle(brs2, e.Bounds);
5302             e.DrawFocusRectangle();
5303             this.DrawListViewItemIcon(e);
5304         }
5305
5306         private void MyList_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
5307         {
5308             if (e.ItemState == 0) return;
5309
5310             if (e.ColumnIndex > 0)
5311             {
5312                 //アイコン以外の列
5313                 RectangleF rct = e.Bounds;
5314                 rct.Width = e.Header.Width;
5315                 int fontHeight = e.Item.Font.Height;
5316                 if (_iconCol)
5317                 {
5318                     rct.Y += fontHeight;
5319                     rct.Height -= fontHeight;
5320                 }
5321
5322                 int heightDiff;
5323                 int drawLineCount = Math.Max(1, Math.DivRem((int)rct.Height, fontHeight, out heightDiff));
5324
5325                 //if (heightDiff > fontHeight * 0.7)
5326                 //{
5327                 //    rct.Height += fontHeight;
5328                 //    drawLineCount += 1;
5329                 //}
5330
5331                 //フォントの高さの半分を足してるのは保険。無くてもいいかも。
5332                 if (!_iconCol && drawLineCount <= 1)
5333                 {
5334                     //rct.Inflate(0, heightDiff / -2);
5335                     //rct.Height += fontHeight / 2;
5336                 }
5337                 else if (heightDiff < fontHeight * 0.7)
5338                 {
5339                     //最終行が70%以上欠けていたら、最終行は表示しない
5340                     //rct.Height = (float)((fontHeight * drawLineCount) + (fontHeight / 2));
5341                     rct.Height = (fontHeight * drawLineCount) - 1;
5342                 }
5343                 else
5344                 {
5345                     drawLineCount += 1;
5346                 }
5347
5348                 //if (!_iconCol && drawLineCount > 1)
5349                 //{
5350                 //    rct.Y += fontHeight * 0.2;
5351                 //    if (heightDiff >= fontHeight * 0.8) rct.Height -= fontHeight * 0.2;
5352                 //}
5353
5354                 if (rct.Width > 0)
5355                 {
5356                     Color color = (!e.Item.Selected) ? e.Item.ForeColor :   //選択されていない行
5357                         (((Control)sender).Focused) ? _clHighLight :        //選択中の行
5358                         _clUnread;
5359
5360                     if (_iconCol)
5361                     {
5362                         Rectangle rctB = e.Bounds;
5363                         rctB.Width = e.Header.Width;
5364                         rctB.Height = fontHeight;
5365
5366                         using (Font fnt = new Font(e.Item.Font, FontStyle.Bold))
5367                         {
5368                             TextRenderer.DrawText(e.Graphics,
5369                                                     e.Item.SubItems[2].Text,
5370                                                     e.Item.Font,
5371                                                     Rectangle.Round(rct),
5372                                                     color,
5373                                                     TextFormatFlags.WordBreak |
5374                                                     TextFormatFlags.EndEllipsis |
5375                                                     TextFormatFlags.GlyphOverhangPadding |
5376                                                     TextFormatFlags.NoPrefix);
5377                             TextRenderer.DrawText(e.Graphics,
5378                                                     e.Item.SubItems[4].Text + " / " + e.Item.SubItems[1].Text + " (" + e.Item.SubItems[3].Text + ") " + e.Item.SubItems[5].Text + e.Item.SubItems[6].Text + " [" + e.Item.SubItems[7].Text + "]",
5379                                                     fnt,
5380                                                     rctB,
5381                                                     color,
5382                                                     TextFormatFlags.SingleLine |
5383                                                     TextFormatFlags.EndEllipsis |
5384                                                     TextFormatFlags.GlyphOverhangPadding |
5385                                                     TextFormatFlags.NoPrefix);
5386                         }
5387                     }
5388                     else if (drawLineCount == 1)
5389                     {
5390                         TextRenderer.DrawText(e.Graphics,
5391                                                 e.SubItem.Text,
5392                                                 e.Item.Font,
5393                                                 Rectangle.Round(rct),
5394                                                 color,
5395                                                 TextFormatFlags.SingleLine |
5396                                                 TextFormatFlags.EndEllipsis |
5397                                                 TextFormatFlags.GlyphOverhangPadding |
5398                                                 TextFormatFlags.NoPrefix |
5399                                                 TextFormatFlags.VerticalCenter);
5400                     }
5401                     else
5402                     {
5403                         TextRenderer.DrawText(e.Graphics,
5404                                                 e.SubItem.Text,
5405                                                 e.Item.Font,
5406                                                 Rectangle.Round(rct),
5407                                                 color,
5408                                                 TextFormatFlags.WordBreak |
5409                                                 TextFormatFlags.EndEllipsis |
5410                                                 TextFormatFlags.GlyphOverhangPadding |
5411                                                 TextFormatFlags.NoPrefix);
5412                     }
5413                     //if (e.ColumnIndex == 6) this.DrawListViewItemStateIcon(e, rct);
5414                 }
5415             }
5416         }
5417
5418         private void DrawListViewItemIcon(DrawListViewItemEventArgs e)
5419         {
5420             if (_iconSz == 0) return;
5421
5422             ImageListViewItem item = (ImageListViewItem)e.Item;
5423
5424             //e.Bounds.Leftが常に0を指すから自前で計算
5425             Rectangle itemRect = item.Bounds;
5426             var col0 = e.Item.ListView.Columns[0];
5427             itemRect.Width = col0.Width;
5428
5429             if (col0.DisplayIndex > 0)
5430             {
5431                 foreach (ColumnHeader clm in e.Item.ListView.Columns)
5432                 {
5433                     if (clm.DisplayIndex < col0.DisplayIndex)
5434                         itemRect.X += clm.Width;
5435                 }
5436             }
5437
5438             // ディスプレイの DPI 設定を考慮したアイコンサイズ
5439             var realIconSize = new SizeF(this._iconSz * this.currentScaleFactor.Width, this._iconSz * this.currentScaleFactor.Height).ToSize();
5440             var realStateSize = new SizeF(16 * this.currentScaleFactor.Width, 16 * this.currentScaleFactor.Height).ToSize();
5441
5442             Rectangle iconRect;
5443             var img = item.Image;
5444             if (img != null)
5445             {
5446                 iconRect = Rectangle.Intersect(new Rectangle(e.Item.GetBounds(ItemBoundsPortion.Icon).Location, realIconSize), itemRect);
5447                 iconRect.Offset(0, Math.Max(0, (itemRect.Height - realIconSize.Height) / 2));
5448
5449                 if (iconRect.Width > 0)
5450                 {
5451                     e.Graphics.FillRectangle(Brushes.White, iconRect);
5452                     e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
5453                     try
5454                     {
5455                         e.Graphics.DrawImage(img.Image, iconRect);
5456                     }
5457                     catch (ArgumentException)
5458                     {
5459                         item.RefreshImageAsync();
5460                     }
5461                 }
5462             }
5463             else
5464             {
5465                 iconRect = Rectangle.Intersect(new Rectangle(e.Item.GetBounds(ItemBoundsPortion.Icon).Location, new Size(1, 1)), itemRect);
5466                 //iconRect.Offset(0, Math.Max(0, (itemRect.Height - realIconSize.Height) / 2));
5467             }
5468
5469             if (item.StateImageIndex > -1)
5470             {
5471                 Rectangle stateRect = Rectangle.Intersect(new Rectangle(new Point(iconRect.X + realIconSize.Width + 2, iconRect.Y), realStateSize), itemRect);
5472                 if (stateRect.Width > 0)
5473                 {
5474                     //e.Graphics.FillRectangle(Brushes.White, stateRect);
5475                     //e.Graphics.InterpolationMode = Drawing2D.InterpolationMode.High;
5476                     e.Graphics.DrawImage(this.PostStateImageList.Images[item.StateImageIndex], stateRect);
5477                 }
5478             }
5479         }
5480
5481         protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
5482         {
5483             base.ScaleControl(factor, specified);
5484
5485             const int baseDpi = 96;
5486
5487             // デザイン時の DPI (96dpi) との比を更新する
5488             this.currentScaleFactor = new SizeF(
5489                 this.CurrentAutoScaleDimensions.Width / baseDpi,
5490                 this.CurrentAutoScaleDimensions.Height / baseDpi);
5491         }
5492
5493         //private void DrawListViewItemStateIcon(DrawListViewSubItemEventArgs e, RectangleF rct)
5494         //{
5495         //    ImageListViewItem item = (ImageListViewItem)e.Item;
5496         //    if (item.StateImageIndex > -1)
5497         //    {
5498         //        ////e.Bounds.Leftが常に0を指すから自前で計算
5499         //        //Rectangle itemRect = item.Bounds;
5500         //        //itemRect.Width = e.Item.ListView.Columns[4].Width;
5501
5502         //        //foreach (ColumnHeader clm in e.Item.ListView.Columns)
5503         //        //{
5504         //        //    if (clm.DisplayIndex < e.Item.ListView.Columns[4].DisplayIndex)
5505         //        //    {
5506         //        //        itemRect.X += clm.Width;
5507         //        //    }
5508         //        //}
5509
5510         //        //Rectangle iconRect = Rectangle.Intersect(new Rectangle(e.Item.GetBounds(ItemBoundsPortion.Icon).Location, new Size(_iconSz, _iconSz)), itemRect);
5511         //        //iconRect.Offset(0, Math.Max(0, (itemRect.Height - _iconSz) / 2));
5512
5513         //        if (rct.Width > 0)
5514         //        {
5515         //            RectangleF stateRect = RectangleF.Intersect(rct, new RectangleF(rct.Location, new Size(18, 16)));
5516         //            //e.Graphics.FillRectangle(Brushes.White, rct);
5517         //            //e.Graphics.InterpolationMode = Drawing2D.InterpolationMode.High;
5518         //            e.Graphics.DrawImage(this.PostStateImageList.Images(item.StateImageIndex), stateRect);
5519         //        }
5520         //    }
5521         //}
5522
5523         private void DoTabSearch(string _word,
5524                                  bool CaseSensitive,
5525                                  bool UseRegex,
5526                                  SEARCHTYPE SType)
5527         {
5528             int cidx = 0;
5529             bool fnd = false;
5530             int toIdx;
5531             int stp = 1;
5532
5533             if (_curList.VirtualListSize == 0)
5534             {
5535                 MessageBox.Show(Properties.Resources.DoTabSearchText2, Properties.Resources.DoTabSearchText3, MessageBoxButtons.OK, MessageBoxIcon.Information);
5536             }
5537
5538             if (_curList.SelectedIndices.Count > 0)
5539             {
5540                 cidx = _curList.SelectedIndices[0];
5541             }
5542             toIdx = _curList.VirtualListSize;
5543
5544             switch (SType)
5545             {
5546                 case SEARCHTYPE.DialogSearch:    //ダイアログからの検索
5547                     if (_curList.SelectedIndices.Count > 0)
5548                         cidx = _curList.SelectedIndices[0];
5549                     else
5550                         cidx = 0;
5551                     break;
5552                 case SEARCHTYPE.NextSearch:      //次を検索
5553                     if (_curList.SelectedIndices.Count > 0)
5554                     {
5555                         cidx = _curList.SelectedIndices[0] + 1;
5556                         if (cidx > toIdx) cidx = toIdx;
5557                     }
5558                     else
5559                     {
5560                         cidx = 0;
5561                     }
5562                     break;
5563                 case SEARCHTYPE.PrevSearch:      //前を検索
5564                     if (_curList.SelectedIndices.Count > 0)
5565                     {
5566                         cidx = _curList.SelectedIndices[0] - 1;
5567                         if (cidx < 0) cidx = 0;
5568                     }
5569                     else
5570                     {
5571                         cidx = toIdx;
5572                     }
5573                     toIdx = -1;
5574                     stp = -1;
5575                     break;
5576             }
5577
5578             RegexOptions regOpt = RegexOptions.None;
5579             StringComparison fndOpt = StringComparison.Ordinal;
5580             if (!CaseSensitive)
5581             {
5582                 regOpt = RegexOptions.IgnoreCase;
5583                 fndOpt = StringComparison.OrdinalIgnoreCase;
5584             }
5585             try
5586             {
5587     RETRY:
5588                 if (UseRegex)
5589                 {
5590                     // 正規表現検索
5591                     Regex _search;
5592                     try
5593                     {
5594                         _search = new Regex(_word, regOpt);
5595                         for (int idx = cidx; idx != toIdx; idx += stp)
5596                         {
5597                             PostClass post;
5598                             try
5599                             {
5600                                 post = _statuses[_curTab.Text, idx];
5601                             }
5602                             catch (Exception)
5603                             {
5604                                 continue;
5605                             }
5606                             if (_search.IsMatch(post.Nickname)
5607                                 || _search.IsMatch(post.TextFromApi)
5608                                 || _search.IsMatch(post.ScreenName))
5609                             {
5610                                 SelectListItem(_curList, idx);
5611                                 _curList.EnsureVisible(idx);
5612                                 return;
5613                             }
5614                         }
5615                     }
5616                     catch (ArgumentException)
5617                     {
5618                         MessageBox.Show(Properties.Resources.DoTabSearchText1, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
5619                         return;
5620                     }
5621                 }
5622                 else
5623                 {
5624                     // 通常検索
5625                     for (int idx = cidx; idx != toIdx; idx += stp)
5626                     {
5627                         PostClass post;
5628                         try
5629                         {
5630                             post = _statuses[_curTab.Text, idx];
5631                         }
5632                         catch (Exception)
5633                         {
5634                             continue;
5635                         }
5636                         if (post.Nickname.IndexOf(_word, fndOpt) > -1
5637                             || post.TextFromApi.IndexOf(_word, fndOpt) > -1
5638                             || post.ScreenName.IndexOf(_word, fndOpt) > -1)
5639                         {
5640                             SelectListItem(_curList, idx);
5641                             _curList.EnsureVisible(idx);
5642                             return;
5643                         }
5644                     }
5645                 }
5646
5647                 if (!fnd)
5648                 {
5649                     switch (SType)
5650                     {
5651                         case SEARCHTYPE.DialogSearch:
5652                         case SEARCHTYPE.NextSearch:
5653                             toIdx = cidx;
5654                             cidx = 0;
5655                             break;
5656                         case SEARCHTYPE.PrevSearch:
5657                             toIdx = cidx;
5658                             cidx = _curList.VirtualListSize - 1;
5659                             break;
5660                     }
5661                     fnd = true;
5662                     goto RETRY;
5663                 }
5664             }
5665             catch (ArgumentOutOfRangeException)
5666             {
5667             }
5668             MessageBox.Show(Properties.Resources.DoTabSearchText2, Properties.Resources.DoTabSearchText3, MessageBoxButtons.OK, MessageBoxIcon.Information);
5669         }
5670
5671         private void MenuItemSubSearch_Click(object sender, EventArgs e)
5672         {
5673             // 検索メニュー
5674             this.ShowSearchDialog();
5675         }
5676
5677         private void MenuItemSearchNext_Click(object sender, EventArgs e)
5678         {
5679             var previousSearch = this.SearchDialog.ResultOptions;
5680             if (previousSearch == null || previousSearch.Type != SearchWordDialog.SearchType.Timeline)
5681             {
5682                 this.SearchDialog.Reset();
5683                 this.ShowSearchDialog();
5684                 return;
5685             }
5686
5687             // 次を検索
5688             this.DoTabSearch(
5689                 previousSearch.Query,
5690                 previousSearch.CaseSensitive,
5691                 previousSearch.UseRegex,
5692                 SEARCHTYPE.NextSearch);
5693         }
5694
5695         private void MenuItemSearchPrev_Click(object sender, EventArgs e)
5696         {
5697             var previousSearch = this.SearchDialog.ResultOptions;
5698             if (previousSearch == null || previousSearch.Type != SearchWordDialog.SearchType.Timeline)
5699             {
5700                 this.SearchDialog.Reset();
5701                 this.ShowSearchDialog();
5702                 return;
5703             }
5704
5705             // 前を検索
5706             this.DoTabSearch(
5707                 previousSearch.Query,
5708                 previousSearch.CaseSensitive,
5709                 previousSearch.UseRegex,
5710                 SEARCHTYPE.PrevSearch);
5711         }
5712
5713         /// <summary>
5714         /// 検索ダイアログを表示し、検索を実行します
5715         /// </summary>
5716         private void ShowSearchDialog()
5717         {
5718             // Recentタブの検索時以外では「新規タブに表示」ボタンを無効化する
5719             if (this._statuses.Tabs[this._curTab.Text].TabType == MyCommon.TabUsageType.Home)
5720                 this.SearchDialog.DisableNewTabButton = false;
5721             else
5722                 this.SearchDialog.DisableNewTabButton = true;
5723
5724             if (this.SearchDialog.ShowDialog(this) != DialogResult.OK)
5725             {
5726                 this.TopMost = this.SettingDialog.AlwaysTop;
5727                 return;
5728             }
5729             this.TopMost = this.SettingDialog.AlwaysTop;
5730
5731             var searchOptions = this.SearchDialog.ResultOptions;
5732             if (searchOptions.Type == SearchWordDialog.SearchType.Timeline)
5733             {
5734                 if (searchOptions.NewTab)
5735                 {
5736                     var tabName = searchOptions.Query;
5737
5738                     try
5739                     {
5740                         tabName = this._statuses.MakeTabName(tabName);
5741                     }
5742                     catch (TabException ex)
5743                     {
5744                         MessageBox.Show(this, ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
5745                     }
5746
5747                     this.AddNewTab(tabName, false, MyCommon.TabUsageType.UserDefined);
5748                     this._statuses.AddTab(tabName, MyCommon.TabUsageType.UserDefined, null);
5749
5750                     var filter = new PostFilterRule
5751                     {
5752                         FilterBody = new[] { searchOptions.Query },
5753                         UseRegex = searchOptions.UseRegex,
5754                         CaseSensitive = searchOptions.CaseSensitive,
5755                     };
5756                     this._statuses.Tabs[tabName].AddFilter(filter);
5757
5758                     var tabPage = this.ListTab.TabPages.Cast<TabPage>()
5759                         .First(x => x.Text == tabName);
5760
5761                     this.ListTab.SelectedTab = tabPage;
5762                     this.ListTabSelect(tabPage);
5763
5764                     this.ApplyPostFilters();
5765                     this.SaveConfigsTabs();
5766                 }
5767                 else
5768                 {
5769                     this.DoTabSearch(
5770                         searchOptions.Query,
5771                         searchOptions.CaseSensitive,
5772                         searchOptions.UseRegex,
5773                         SEARCHTYPE.DialogSearch);
5774                 }
5775             }
5776             else if (searchOptions.Type == SearchWordDialog.SearchType.Public)
5777             {
5778                 this.AddNewTabForSearch(searchOptions.Query);
5779             }
5780         }
5781
5782         private void AboutMenuItem_Click(object sender, EventArgs e)
5783         {
5784             using (TweenAboutBox about = new TweenAboutBox())
5785             {
5786                 about.ShowDialog(this);
5787             }
5788             this.TopMost = SettingDialog.AlwaysTop;
5789         }
5790
5791         private void JumpUnreadMenuItem_Click(object sender, EventArgs e)
5792         {
5793             int bgnIdx = ListTab.TabPages.IndexOf(_curTab);
5794             int idx = -1;
5795             DetailsListView lst = null;
5796
5797             if (ImageSelector.Enabled)
5798                 return;
5799
5800             //現在タブから最終タブまで探索
5801             for (int i = bgnIdx; i < ListTab.TabPages.Count; i++)
5802             {
5803                 //未読Index取得
5804                 idx = _statuses.GetOldestUnreadIndex(ListTab.TabPages[i].Text);
5805                 if (idx > -1)
5806                 {
5807                     ListTab.SelectedIndex = i;
5808                     lst = (DetailsListView)ListTab.TabPages[i].Tag;
5809                     //_curTab = ListTab.TabPages[i];
5810                     break;
5811                 }
5812             }
5813
5814             //未読みつからず&現在タブが先頭ではなかったら、先頭タブから現在タブの手前まで探索
5815             if (idx == -1 && bgnIdx > 0)
5816             {
5817                 for (int i = 0; i < bgnIdx; i++)
5818                 {
5819                     idx = _statuses.GetOldestUnreadIndex(ListTab.TabPages[i].Text);
5820                     if (idx > -1)
5821                     {
5822                         ListTab.SelectedIndex = i;
5823                         lst = (DetailsListView)ListTab.TabPages[i].Tag;
5824                         //_curTab = ListTab.TabPages[i];
5825                         break;
5826                     }
5827                 }
5828             }
5829
5830             //全部調べたが未読見つからず→先頭タブの最新発言へ
5831             if (idx == -1)
5832             {
5833                 ListTab.SelectedIndex = 0;
5834                 lst = (DetailsListView)ListTab.TabPages[0].Tag;
5835                 //_curTab = ListTab.TabPages[0];
5836                 if (_statuses.SortOrder == SortOrder.Ascending)
5837                     idx = lst.VirtualListSize - 1;
5838                 else
5839                     idx = 0;
5840             }
5841
5842             if (lst.VirtualListSize > 0 && idx > -1 && lst.VirtualListSize > idx)
5843             {
5844                 SelectListItem(lst, idx);
5845                 if (_statuses.SortMode == IdComparerClass.ComparerMode.Id)
5846                 {
5847                     if (_statuses.SortOrder == SortOrder.Ascending && lst.Items[idx].Position.Y > lst.ClientSize.Height - _iconSz - 10 ||
5848                        _statuses.SortOrder == SortOrder.Descending && lst.Items[idx].Position.Y < _iconSz + 10)
5849                     {
5850                         MoveTop();
5851                     }
5852                     else
5853                     {
5854                         lst.EnsureVisible(idx);
5855                     }
5856                 }
5857                 else
5858                 {
5859                     lst.EnsureVisible(idx);
5860                 }
5861             }
5862             lst.Focus();
5863         }
5864
5865         private void StatusOpenMenuItem_Click(object sender, EventArgs e)
5866         {
5867             if (_curList.SelectedIndices.Count > 0 && _statuses.Tabs[_curTab.Text].TabType != MyCommon.TabUsageType.DirectMessage)
5868             {
5869                 var post = _statuses[_curTab.Text, _curList.SelectedIndices[0]];
5870                 OpenUriAsync(MyCommon.GetStatusUrl(post));
5871             }
5872         }
5873
5874         private void FavorareMenuItem_Click(object sender, EventArgs e)
5875         {
5876             if (_curList.SelectedIndices.Count > 0)
5877             {
5878                 PostClass post = _statuses[_curTab.Text, _curList.SelectedIndices[0]];
5879                 OpenUriAsync(Properties.Resources.FavstarUrl + "users/" + post.ScreenName + "/recent");
5880             }
5881         }
5882
5883         private async void VerUpMenuItem_Click(object sender, EventArgs e)
5884         {
5885             await this.CheckNewVersion(false);
5886         }
5887
5888         private void RunTweenUp()
5889         {
5890             ProcessStartInfo pinfo = new ProcessStartInfo();
5891             pinfo.UseShellExecute = true;
5892             pinfo.WorkingDirectory = MyCommon.settingPath;
5893             pinfo.FileName = Path.Combine(MyCommon.settingPath, "TweenUp3.exe");
5894             pinfo.Arguments = "\"" + Application.StartupPath + "\"";
5895             try
5896             {
5897                 Process.Start(pinfo);
5898             }
5899             catch (Exception)
5900             {
5901                 MessageBox.Show("Failed to execute TweenUp3.exe.");
5902             }
5903         }
5904
5905         public class VersionInfo
5906         {
5907             public Version Version { get; set; }
5908             public Uri DownloadUri { get; set; }
5909             public string ReleaseNote { get; set; }
5910         }
5911
5912         /// <summary>
5913         /// OpenTween の最新バージョンの情報を取得します
5914         /// </summary>
5915         public async Task<VersionInfo> GetVersionInfoAsync()
5916         {
5917             var versionInfoUrl = new Uri(ApplicationSettings.VersionInfoUrl + "?" +
5918                 DateTime.Now.ToString("yyMMddHHmmss") + Environment.TickCount);
5919
5920             var responseText = await this.http.GetStringAsync(versionInfoUrl)
5921                 .ConfigureAwait(false);
5922
5923             // 改行2つで前後パートを分割(前半がバージョン番号など、後半が詳細テキスト)
5924             var msgPart = responseText.Split(new[] { "\n\n", "\r\n\r\n" }, 2, StringSplitOptions.None);
5925
5926             var msgHeader = msgPart[0].Split(new[] { "\n", "\r\n" }, StringSplitOptions.None);
5927             var msgBody = msgPart.Length == 2 ? msgPart[1] : "";
5928
5929             msgBody = Regex.Replace(msgBody, "(?<!\r)\n", "\r\n"); // LF -> CRLF
5930
5931             return new VersionInfo
5932             {
5933                 Version = Version.Parse(msgHeader[0]),
5934                 DownloadUri = new Uri(msgHeader[1]),
5935                 ReleaseNote = msgBody,
5936             };
5937         }
5938
5939         private async Task CheckNewVersion(bool startup = false)
5940         {
5941             if (ApplicationSettings.VersionInfoUrl == null)
5942                 return; // 更新チェック無効化
5943
5944             try
5945             {
5946                 var versionInfo = await this.GetVersionInfoAsync();
5947
5948                 if (versionInfo.Version <= Version.Parse(MyCommon.FileVersion))
5949                 {
5950                     // 更新不要
5951                     if (!startup)
5952                     {
5953                         var msgtext = string.Format(Properties.Resources.CheckNewVersionText7,
5954                             MyCommon.GetReadableVersion(), MyCommon.GetReadableVersion(versionInfo.Version));
5955                         msgtext = MyCommon.ReplaceAppName(msgtext);
5956
5957                         MessageBox.Show(msgtext,
5958                             MyCommon.ReplaceAppName(Properties.Resources.CheckNewVersionText2),
5959                             MessageBoxButtons.OK, MessageBoxIcon.Information);
5960                     }
5961                     return;
5962                 }
5963
5964                 using (var dialog = new UpdateDialog())
5965                 {
5966                     dialog.SummaryText = string.Format(Properties.Resources.CheckNewVersionText3,
5967                         MyCommon.GetReadableVersion(versionInfo.Version));
5968                     dialog.DetailsText = versionInfo.ReleaseNote;
5969
5970                     if (dialog.ShowDialog(this) == DialogResult.Yes)
5971                     {
5972                         await this.OpenUriAsync(versionInfo.DownloadUri.OriginalString);
5973                     }
5974                 }
5975             }
5976             catch (Exception)
5977             {
5978                 this.StatusLabel.Text = Properties.Resources.CheckNewVersionText9;
5979                 if (!startup)
5980                 {
5981                     MessageBox.Show(Properties.Resources.CheckNewVersionText10,
5982                         MyCommon.ReplaceAppName(Properties.Resources.CheckNewVersionText2),
5983                         MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2);
5984                 }
5985             }
5986         }
5987
5988         private void Colorize()
5989         {
5990             _colorize = false;
5991             DispSelectedPost();
5992             //件数関連の場合、タイトル即時書き換え
5993             if (SettingDialog.DispLatestPost != MyCommon.DispTitleEnum.None &&
5994                SettingDialog.DispLatestPost != MyCommon.DispTitleEnum.Post &&
5995                SettingDialog.DispLatestPost != MyCommon.DispTitleEnum.Ver &&
5996                SettingDialog.DispLatestPost != MyCommon.DispTitleEnum.OwnStatus)
5997             {
5998                 SetMainWindowTitle();
5999             }
6000             if (!StatusLabelUrl.Text.StartsWith("http")) SetStatusLabelUrl();
6001             foreach (TabPage tb in ListTab.TabPages)
6002             {
6003                 if (_statuses.Tabs[tb.Text].UnreadCount == 0)
6004                 {
6005                     if (SettingDialog.TabIconDisp)
6006                     {
6007                         if (tb.ImageIndex == 0) tb.ImageIndex = -1;
6008                     }
6009                 }
6010             }
6011             if (!SettingDialog.TabIconDisp) ListTab.Refresh();
6012         }
6013
6014         public string createDetailHtml(string orgdata)
6015         {
6016             return detailHtmlFormatHeader + orgdata + detailHtmlFormatFooter;
6017         }
6018
6019         private async void DisplayItemImage_Downloaded(object sender, EventArgs e)
6020         {
6021             if (sender.Equals(displayItem))
6022             {
6023                 this.ClearUserPicture();
6024
6025                 var img = displayItem.Image;
6026                 try
6027                 {
6028                     if (img != null)
6029                         img = await img.CloneAsync();
6030
6031                     UserPicture.Image = img;
6032                 }
6033                 catch (Exception)
6034                 {
6035                     UserPicture.ShowErrorImage();
6036                 }
6037             }
6038         }
6039
6040         private void DispSelectedPost()
6041         {
6042             DispSelectedPost(false);
6043         }
6044
6045         private static PostClass displaypost = new PostClass();
6046
6047         /// <summary>
6048         /// サムネイルの表示処理を表すタスク
6049         /// </summary>
6050         private Task thumbnailTask = null;
6051
6052         /// <summary>
6053         /// サムネイル表示に使用する CancellationToken の生成元
6054         /// </summary>
6055         private CancellationTokenSource thumbnailTokenSource = null;
6056
6057         private void DispSelectedPost(bool forceupdate)
6058         {
6059             if (_curList.SelectedIndices.Count == 0 || _curPost == null)
6060                 return;
6061
6062             if (!forceupdate && _curPost.Equals(displaypost))
6063                 return;
6064
6065             displaypost = _curPost;
6066             if (displayItem != null)
6067             {
6068                 displayItem.ImageDownloaded -= this.DisplayItemImage_Downloaded;
6069                 displayItem = null;
6070             }
6071             displayItem = (ImageListViewItem)_curList.Items[_curList.SelectedIndices[0]];
6072             displayItem.ImageDownloaded += this.DisplayItemImage_Downloaded;
6073
6074             string dTxt = createDetailHtml(_curPost.IsDeleted ? "(DELETED)" : _curPost.Text);
6075             if (_curPost.IsDm)
6076             {
6077                 SourceLinkLabel.Tag = null;
6078                 SourceLinkLabel.Text = "";
6079             }
6080             else
6081             {
6082                 Match mc = Regex.Match(_curPost.SourceHtml, "<a href=\"(?<sourceurl>.+?)\"");
6083                 if (mc.Success)
6084                 {
6085                     string src = mc.Groups["sourceurl"].Value;
6086                     SourceLinkLabel.Tag = mc.Groups["sourceurl"].Value;
6087                     mc = Regex.Match(src, "^https?://");
6088                     if (!mc.Success)
6089                     {
6090                         src = src.Insert(0, "https://twitter.com");
6091                     }
6092                     SourceLinkLabel.Tag = src;
6093                 }
6094                 else
6095                 {
6096                     SourceLinkLabel.Tag = null;
6097                 }
6098                 if (string.IsNullOrEmpty(_curPost.Source))
6099                 {
6100                     SourceLinkLabel.Text = "";
6101                     //SourceLinkLabel.Visible = false;
6102                 }
6103                 else
6104                 {
6105                     SourceLinkLabel.Text = _curPost.Source;
6106                     //SourceLinkLabel.Visible = true;
6107                 }
6108             }
6109             SourceLinkLabel.TabStop = false;
6110
6111             if (_statuses.Tabs[_curTab.Text].TabType == MyCommon.TabUsageType.DirectMessage && !_curPost.IsOwl)
6112             {
6113                 NameLabel.Text = "DM TO -> ";
6114             }
6115             else if (_statuses.Tabs[_curTab.Text].TabType == MyCommon.TabUsageType.DirectMessage)
6116             {
6117                 NameLabel.Text = "DM FROM <- ";
6118             }
6119             else
6120             {
6121                 NameLabel.Text = "";
6122             }
6123             NameLabel.Text += _curPost.ScreenName + "/" + _curPost.Nickname;
6124             NameLabel.Tag = _curPost.ScreenName;
6125             if (!string.IsNullOrEmpty(_curPost.RetweetedBy))
6126             {
6127                 NameLabel.Text += " (RT:" + _curPost.RetweetedBy + ")";
6128             }
6129
6130             this.ClearUserPicture();
6131
6132             if (!string.IsNullOrEmpty(_curPost.ImageUrl))
6133             {
6134                 var image = IconCache.TryGetFromCache(_curPost.ImageUrl);
6135                 try
6136                 {
6137                     UserPicture.Image = image != null ? image.Clone() : null;
6138                 }
6139                 catch (Exception)
6140                 {
6141                     UserPicture.ShowErrorImage();
6142                 }
6143             }
6144
6145             NameLabel.ForeColor = System.Drawing.SystemColors.ControlText;
6146             DateTimeLabel.Text = _curPost.CreatedAt.ToString();
6147             if (_curPost.IsOwl && (SettingDialog.OneWayLove || _statuses.Tabs[_curTab.Text].TabType == MyCommon.TabUsageType.DirectMessage)) NameLabel.ForeColor = _clOWL;
6148             if (_curPost.RetweetedId != null) NameLabel.ForeColor = _clRetweet;
6149             if (_curPost.IsFav) NameLabel.ForeColor = _clFav;
6150
6151             if (DumpPostClassToolStripMenuItem.Checked)
6152             {
6153                 StringBuilder sb = new StringBuilder(512);
6154
6155                 sb.Append("-----Start PostClass Dump<br>");
6156                 sb.AppendFormat("TextFromApi           : {0}<br>", _curPost.TextFromApi);
6157                 sb.AppendFormat("(PlainText)    : <xmp>{0}</xmp><br>", _curPost.TextFromApi);
6158                 sb.AppendFormat("StatusId             : {0}<br>", _curPost.StatusId.ToString());
6159                 //sb.AppendFormat("ImageIndex     : {0}<br>", _curPost.ImageIndex.ToString());
6160                 sb.AppendFormat("ImageUrl       : {0}<br>", _curPost.ImageUrl);
6161                 sb.AppendFormat("InReplyToStatusId    : {0}<br>", _curPost.InReplyToStatusId.ToString());
6162                 sb.AppendFormat("InReplyToUser  : {0}<br>", _curPost.InReplyToUser);
6163                 sb.AppendFormat("IsDM           : {0}<br>", _curPost.IsDm.ToString());
6164                 sb.AppendFormat("IsFav          : {0}<br>", _curPost.IsFav.ToString());
6165                 sb.AppendFormat("IsMark         : {0}<br>", _curPost.IsMark.ToString());
6166                 sb.AppendFormat("IsMe           : {0}<br>", _curPost.IsMe.ToString());
6167                 sb.AppendFormat("IsOwl          : {0}<br>", _curPost.IsOwl.ToString());
6168                 sb.AppendFormat("IsProtect      : {0}<br>", _curPost.IsProtect.ToString());
6169                 sb.AppendFormat("IsRead         : {0}<br>", _curPost.IsRead.ToString());
6170                 sb.AppendFormat("IsReply        : {0}<br>", _curPost.IsReply.ToString());
6171             
6172                 foreach (string nm in _curPost.ReplyToList)
6173                 {
6174                     sb.AppendFormat("ReplyToList    : {0}<br>", nm);
6175                 }
6176
6177                 sb.AppendFormat("ScreenName           : {0}<br>", _curPost.ScreenName);
6178                 sb.AppendFormat("NickName       : {0}<br>", _curPost.Nickname);
6179                 sb.AppendFormat("Text   : {0}<br>", _curPost.Text);
6180                 sb.AppendFormat("(PlainText)    : <xmp>{0}</xmp><br>", _curPost.Text);
6181                 sb.AppendFormat("CreatedAt          : {0}<br>", _curPost.CreatedAt.ToString());
6182                 sb.AppendFormat("Source         : {0}<br>", _curPost.Source);
6183                 sb.AppendFormat("UserId            : {0}<br>", _curPost.UserId);
6184                 sb.AppendFormat("FilterHit      : {0}<br>", _curPost.FilterHit);
6185                 sb.AppendFormat("RetweetedBy    : {0}<br>", _curPost.RetweetedBy);
6186                 sb.AppendFormat("RetweetedId    : {0}<br>", _curPost.RetweetedId);
6187                 sb.AppendFormat("SearchTabName  : {0}<br>", _curPost.RelTabName);
6188                 sb.Append("-----End PostClass Dump<br>");
6189
6190                 PostBrowser.Visible = false;
6191                 PostBrowser.DocumentText = detailHtmlFormatHeader + sb.ToString() + detailHtmlFormatFooter;
6192                 PostBrowser.Visible = true;
6193             }
6194             else
6195             {
6196                 try
6197                 {
6198                     if (PostBrowser.DocumentText != dTxt)
6199                     {
6200                         PostBrowser.Visible = false;
6201                         PostBrowser.DocumentText = dTxt;
6202
6203                         this.SplitContainer3.Panel2Collapsed = true;
6204
6205                         if (this.IsPreviewEnable)
6206                         {
6207                             if (this.thumbnailTokenSource != null)
6208                             {
6209                                 var oldTokenSource = this.thumbnailTokenSource;
6210
6211                                 // TODO: キャンセルを行うとUIスレッドが阻害される問題を調査
6212                                 //oldTokenSource.Cancel();
6213
6214                                 this.thumbnailTask.ContinueWith(_ => oldTokenSource.Dispose());
6215                             }
6216
6217                             this.thumbnailTokenSource = new CancellationTokenSource();
6218
6219                             var token = this.thumbnailTokenSource.Token;
6220                             this.thumbnailTask = this.tweetThumbnail1.ShowThumbnailAsync(_curPost, token);
6221                         }
6222                     }
6223                 }
6224                 catch (System.Runtime.InteropServices.COMException)
6225                 {
6226                     //原因不明
6227                 }
6228                 catch (UriFormatException)
6229                 {
6230                     PostBrowser.DocumentText = dTxt;
6231                 }
6232                 finally
6233                 {
6234                     PostBrowser.Visible = true;
6235                 }
6236             }
6237         }
6238
6239         private void MatomeMenuItem_Click(object sender, EventArgs e)
6240         {
6241             OpenApplicationWebsite();
6242         }
6243
6244         private void OpenApplicationWebsite()
6245         {
6246             OpenUriAsync(ApplicationSettings.WebsiteUrl);
6247         }
6248
6249         private void ShortcutKeyListMenuItem_Click(object sender, EventArgs e)
6250         {
6251             OpenUriAsync(ApplicationSettings.ShortcutKeyUrl);
6252         }
6253
6254         private void ListTab_KeyDown(object sender, KeyEventArgs e)
6255         {
6256             if (ListTab.SelectedTab != null)
6257             {
6258                 if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.PublicSearch)
6259                 {
6260                     Control pnl = ListTab.SelectedTab.Controls["panelSearch"];
6261                     if (pnl.Controls["comboSearch"].Focused ||
6262                         pnl.Controls["comboLang"].Focused ||
6263                         pnl.Controls["buttonSearch"].Focused) return;
6264                 }
6265                 ModifierState State = GetModifierState(e.Control, e.Shift, e.Alt);
6266                 if (State == ModifierState.NotFlags) return;
6267                 if (State != ModifierState.None) _anchorFlag = false;
6268                 if (CommonKeyDown(e.KeyCode, FocusedControl.ListTab, State))
6269                 {
6270                     e.Handled = true;
6271                     e.SuppressKeyPress = true;
6272                 }
6273             }
6274         }
6275
6276         private ModifierState GetModifierState(bool sControl, bool sShift, bool sAlt)
6277         {
6278             ModifierState state = ModifierState.None;
6279             if (sControl) state = state | ModifierState.Ctrl;
6280             if (sShift) state = state | ModifierState.Shift;
6281             if (sAlt) state = state | ModifierState.Alt;
6282             return state;
6283         }
6284
6285         [FlagsAttribute]
6286         private enum ModifierState
6287         {
6288             None = 0,
6289             Alt = 1,
6290             Shift = 2,
6291             Ctrl = 4,
6292             //CShift = 11,
6293             //CAlt = 12,
6294             //AShift = 13,
6295             NotFlags = 8,
6296
6297             //ListTab = 101,
6298             //PostBrowser = 102,
6299             //StatusText = 103,
6300         }
6301
6302         private enum FocusedControl : int
6303         {
6304             None,
6305             ListTab,
6306             StatusText,
6307             PostBrowser,
6308         }
6309
6310         private bool CommonKeyDown(Keys KeyCode, FocusedControl Focused, ModifierState Modifier)
6311         {
6312             //リストのカーソル移動関係(上下キー、PageUp/Downに該当)
6313             if (Focused == FocusedControl.ListTab)
6314             {
6315                 if (Modifier == (ModifierState.Ctrl | ModifierState.Shift) ||
6316                     Modifier == ModifierState.Ctrl ||
6317                     Modifier == ModifierState.None ||
6318                     Modifier == ModifierState.Shift)
6319                 {
6320                     if (KeyCode == Keys.J)
6321                     {
6322                         SendKeys.Send("{DOWN}");
6323                         return true;
6324                     }
6325                     else if (KeyCode == Keys.K)
6326                     {
6327                         SendKeys.Send("{UP}");
6328                         return true;
6329                     }
6330                 }
6331                 if (Modifier == ModifierState.Shift ||
6332                     Modifier == ModifierState.None)
6333                 {
6334                     if (KeyCode == Keys.F)
6335                     {
6336                         SendKeys.Send("{PGDN}");
6337                         return true;
6338                     }
6339                     else if (KeyCode == Keys.B)
6340                     {
6341                         SendKeys.Send("{PGUP}");
6342                         return true;
6343                     }
6344                 }
6345             }
6346
6347             //修飾キーなし
6348             switch (Modifier)
6349             {
6350                 case ModifierState.None:
6351                     //フォーカス関係なし
6352                     switch (KeyCode)
6353                     {
6354                         case Keys.F1:
6355                             OpenApplicationWebsite();
6356                             return true;
6357                         case Keys.F3:
6358                             MenuItemSearchNext_Click(null, null);
6359                             return true;
6360                         case Keys.F5:
6361                             DoRefresh();
6362                             return true;
6363                         case Keys.F6:
6364                             GetTimeline(MyCommon.WORKERTYPE.Reply, 1, 0, "");
6365                             return true;
6366                         case Keys.F7:
6367                             GetTimeline(MyCommon.WORKERTYPE.DirectMessegeRcv, 1, 0, "");
6368                             return true;
6369                     }
6370                     if (Focused != FocusedControl.StatusText)
6371                     {
6372                         //フォーカスStatusText以外
6373                         switch (KeyCode)
6374                         {
6375                             case Keys.Space:
6376                             case Keys.ProcessKey:
6377                                 if (Focused == FocusedControl.ListTab) _anchorFlag = false;
6378                                 JumpUnreadMenuItem_Click(null, null);
6379                                 return true;
6380                             case Keys.G:
6381                                 if (Focused == FocusedControl.ListTab) _anchorFlag = false;
6382                                 ShowRelatedStatusesMenuItem_Click(null, null);
6383                                 return true;
6384                         }
6385                     }
6386                     if (Focused == FocusedControl.ListTab)
6387                     {
6388                         //フォーカスList
6389                         switch (KeyCode)
6390                         {
6391                             case Keys.N:
6392                             case Keys.Right:
6393                                 GoRelPost(true);
6394                                 return true;
6395                             case Keys.P:
6396                             case Keys.Left:
6397                                 GoRelPost(false);
6398                                 return true;
6399                             case Keys.OemPeriod:
6400                                 GoAnchor();
6401                                 return true;
6402                             case Keys.I:
6403                                 if (this.StatusText.Enabled) this.StatusText.Focus();
6404                                 return true;
6405                             case Keys.Enter:
6406                                 MakeReplyOrDirectStatus();
6407                                 return true;
6408                             case Keys.R:
6409                                 DoRefresh();
6410                                 return true;
6411                         }
6412                         //以下、アンカー初期化
6413                         _anchorFlag = false;
6414                         switch (KeyCode)
6415                         {
6416                             case Keys.L:
6417                                 GoPost(true);
6418                                 return true;
6419                             case Keys.H:
6420                                 GoPost(false);
6421                                 return true;
6422                             case Keys.Z:
6423                             case Keys.Oemcomma:
6424                                 MoveTop();
6425                                 return true;
6426                             case Keys.S:
6427                                 GoNextTab(true);
6428                                 return true;
6429                             case Keys.A:
6430                                 GoNextTab(false);
6431                                 return true;
6432                             case Keys.Oem4:
6433                                 // ] in_reply_to参照元へ戻る
6434                                 GoInReplyToPostTree();
6435                                 return true;
6436                             case Keys.Oem6:
6437                                 // [ in_reply_toへジャンプ
6438                                 GoBackInReplyToPostTree();
6439                                 return true;
6440                             case Keys.Escape:
6441                                 if (ListTab.SelectedTab != null)
6442                                 {
6443                                     MyCommon.TabUsageType tabtype = _statuses.Tabs[ListTab.SelectedTab.Text].TabType;
6444                                     if (tabtype == MyCommon.TabUsageType.Related || tabtype == MyCommon.TabUsageType.UserTimeline || tabtype == MyCommon.TabUsageType.PublicSearch)
6445                                     {
6446                                         TabPage relTp = ListTab.SelectedTab;
6447                                         RemoveSpecifiedTab(relTp.Text, false);
6448                                         SaveConfigsTabs();
6449                                         return true;
6450                                     }
6451                                 }
6452                                 break;
6453                         }
6454                     }
6455                     else if (Focused == FocusedControl.PostBrowser)
6456                     {
6457                         //フォーカスPostBrowser
6458                         switch (KeyCode)
6459                         {
6460                             case Keys.Up:
6461                             case Keys.Down:
6462                                 //スクロールを発生させるため、true を返す
6463                                 return true;
6464                         }
6465                     }
6466                     break;
6467                 case ModifierState.Ctrl:
6468                     //フォーカス関係なし
6469                     switch (KeyCode)
6470                     {
6471                         case Keys.R:
6472                             MakeReplyOrDirectStatus(false, true);
6473                             return true;
6474                         case Keys.D:
6475                             doStatusDelete();
6476                             return true;
6477                         case Keys.M:
6478                             MakeReplyOrDirectStatus(false, false);
6479                             return true;
6480                         case Keys.S:
6481                             FavoriteChange(true);
6482                             return true;
6483                         case Keys.I:
6484                             doRepliedStatusOpen();
6485                             return true;
6486                         case Keys.Q:
6487                             doQuote();
6488                             return true;
6489                         case Keys.B:
6490                             ReadedStripMenuItem_Click(null, null);
6491                             return true;
6492                         case Keys.T:
6493                             HashManageMenuItem_Click(null, null);
6494                             return true;
6495                         case Keys.L:
6496                             UrlConvertAutoToolStripMenuItem_Click(null, null);
6497                             return true;
6498                         case Keys.Y:
6499                             if (Focused != FocusedControl.PostBrowser)
6500                             {
6501                                 MultiLineMenuItem_Click(null, null);
6502                                 return true;
6503                             }
6504                             break;
6505                         case Keys.F:
6506                             MenuItemSubSearch_Click(null, null);
6507                             return true;
6508                         case Keys.U:
6509                             ShowUserTimeline();
6510                             return true;
6511                         case Keys.H:
6512                             // Webページを開く動作
6513                             MoveToHomeToolStripMenuItem_Click(null, null);
6514                             return true;
6515                         case Keys.G:
6516                             // Webページを開く動作
6517                             MoveToFavToolStripMenuItem_Click(null, null);
6518                             return true;
6519                         case Keys.O:
6520                             // Webページを開く動作
6521                             StatusOpenMenuItem_Click(null, null);
6522                             return true;
6523                         case Keys.E:
6524                             // Webページを開く動作
6525                             OpenURLMenuItem_Click(null, null);
6526                             return true;
6527                     }
6528                     //フォーカスList
6529                     if (Focused == FocusedControl.ListTab)
6530                     {
6531                         switch (KeyCode)
6532                         {
6533                             case Keys.Home:
6534                             case Keys.End:
6535                                 _colorize = true;
6536                                 return false;            //スルーする
6537                             case Keys.N:
6538                                 GoNextTab(true);
6539                                 return true;
6540                             case Keys.P:
6541                                 GoNextTab(false);
6542                                 return true;
6543                             case Keys.C:
6544                                 CopyStot();
6545                                 return true;
6546                             case Keys.D1:
6547                             case Keys.D2:
6548                             case Keys.D3:
6549                             case Keys.D4:
6550                             case Keys.D5:
6551                             case Keys.D6:
6552                             case Keys.D7:
6553                             case Keys.D8:
6554                                 // タブダイレクト選択(Ctrl+1~8,Ctrl+9)
6555                                 int tabNo = KeyCode - Keys.D1;
6556                                 if (ListTab.TabPages.Count < tabNo)
6557                                     return false;
6558                                 ListTab.SelectedIndex = tabNo;
6559                                 ListTabSelect(ListTab.TabPages[tabNo]);
6560                                 return true;
6561                             case Keys.D9:
6562                                 ListTab.SelectedIndex = ListTab.TabPages.Count - 1;
6563                                 ListTabSelect(ListTab.TabPages[ListTab.TabPages.Count - 1]);
6564                                 return true;
6565                         }
6566                     }
6567                     else if (Focused == FocusedControl.StatusText)
6568                     {
6569                         //フォーカスStatusText
6570                         switch (KeyCode)
6571                         {
6572                             case Keys.A:
6573                                 StatusText.SelectAll();
6574                                 return true;
6575                             case Keys.Up:
6576                             case Keys.Down:
6577                                 if (!string.IsNullOrWhiteSpace(StatusText.Text))
6578                                 {
6579                                     _history[_hisIdx] = new PostingStatus(StatusText.Text, _reply_to_id, _reply_to_name);
6580                                 }
6581                                 if (KeyCode == Keys.Up)
6582                                 {
6583                                     _hisIdx -= 1;
6584                                     if (_hisIdx < 0) _hisIdx = 0;
6585                                 }
6586                                 else
6587                                 {
6588                                     _hisIdx += 1;
6589                                     if (_hisIdx > _history.Count - 1) _hisIdx = _history.Count - 1;
6590                                 }
6591                                 StatusText.Text = _history[_hisIdx].status;
6592                                 _reply_to_id = _history[_hisIdx].inReplyToId;
6593                                 _reply_to_name = _history[_hisIdx].inReplyToName;
6594                                 StatusText.SelectionStart = StatusText.Text.Length;
6595                                 return true;
6596                             case Keys.PageUp:
6597                             case Keys.P:
6598                                 if (ListTab.SelectedIndex == 0)
6599                                 {
6600                                     ListTab.SelectedIndex = ListTab.TabCount - 1;
6601                                 }
6602                                 else
6603                                 {
6604                                     ListTab.SelectedIndex -= 1;
6605                                 }
6606                                 StatusText.Focus();
6607                                 return true;
6608                             case Keys.PageDown:
6609                             case Keys.N:
6610                                 if (ListTab.SelectedIndex == ListTab.TabCount - 1)
6611                                 {
6612                                     ListTab.SelectedIndex = 0;
6613                                 }
6614                                 else
6615                                 {
6616                                     ListTab.SelectedIndex += 1;
6617                                 }
6618                                 StatusText.Focus();
6619                                 return true;
6620                         }
6621                     }
6622                     else
6623                     {
6624                         //フォーカスPostBrowserもしくは関係なし
6625                         switch (KeyCode)
6626                         {
6627                             case Keys.A:
6628                                 PostBrowser.Document.ExecCommand("SelectAll", false, null);
6629                                 return true;
6630                             case Keys.C:
6631                             case Keys.Insert:
6632                                 string _selText = WebBrowser_GetSelectionText(ref PostBrowser);
6633                                 if (!string.IsNullOrEmpty(_selText))
6634                                 {
6635                                     try
6636                                     {
6637                                         Clipboard.SetDataObject(_selText, false, 5, 100);
6638                                     }
6639                                     catch (Exception ex)
6640                                     {
6641                                         MessageBox.Show(ex.Message);
6642                                     }
6643                                 }
6644                                 return true;
6645                             case Keys.Y:
6646                                 MultiLineMenuItem.Checked = !MultiLineMenuItem.Checked;
6647                                 MultiLineMenuItem_Click(null, null);
6648                                 return true;
6649                         }
6650                     }
6651                     break;
6652                 case ModifierState.Shift:
6653                     //フォーカス関係なし
6654                     switch (KeyCode)
6655                     {
6656                         case Keys.F3:
6657                             MenuItemSearchPrev_Click(null, null);
6658                             return true;
6659                         case Keys.F5:
6660                             DoRefreshMore();
6661                             return true;
6662                         case Keys.F6:
6663                             GetTimeline(MyCommon.WORKERTYPE.Reply, -1, 0, "");
6664                             return true;
6665                         case Keys.F7:
6666                             GetTimeline(MyCommon.WORKERTYPE.DirectMessegeRcv, -1, 0, "");
6667                             return true;
6668                     }
6669                     //フォーカスStatusText以外
6670                     if (Focused != FocusedControl.StatusText)
6671                     {
6672                         if (KeyCode == Keys.R)
6673                         {
6674                             DoRefreshMore();
6675                             return true;
6676                         }
6677                     }
6678                     //フォーカスリスト
6679                     if (Focused == FocusedControl.ListTab)
6680                     {
6681                         switch (KeyCode)
6682                         {
6683                             case Keys.H:
6684                                 GoTopEnd(true);
6685                                 return true;
6686                             case Keys.L:
6687                                 GoTopEnd(false);
6688                                 return true;
6689                             case Keys.M:
6690                                 GoMiddle();
6691                                 return true;
6692                             case Keys.G:
6693                                 GoLast();
6694                                 return true;
6695                             case Keys.Z:
6696                                 MoveMiddle();
6697                                 return true;
6698                             case Keys.Oem4:
6699                                 GoBackInReplyToPostTree(true, false);
6700                                 return true;
6701                             case Keys.Oem6:
6702                                 GoBackInReplyToPostTree(true, true);
6703                                 return true;
6704                             case Keys.N:
6705                             case Keys.Right:
6706                                 // お気に入り前後ジャンプ(SHIFT+N←/P→)
6707                                 GoFav(true);
6708                                 return true;
6709                             case Keys.P:
6710                             case Keys.Left:
6711                                 // お気に入り前後ジャンプ(SHIFT+N←/P→)
6712                                 GoFav(false);
6713                                 return true;
6714                             case Keys.Space:
6715                                 this.GoBackSelectPostChain();
6716                                 return true;
6717                         }
6718                     }
6719                     break;
6720                 case ModifierState.Alt:
6721                     switch (KeyCode)
6722                     {
6723                         case Keys.R:
6724                             doReTweetOfficial(true);
6725                             return true;
6726                         case Keys.P:
6727                             if (_curPost != null)
6728                             {
6729                                 doShowUserStatus(_curPost.ScreenName, false);
6730                                 return true;
6731                             }
6732                             break;
6733                         case Keys.Up:
6734                             ScrollDownPostBrowser(false);
6735                             return true;
6736                         case Keys.Down:
6737                             ScrollDownPostBrowser(true);
6738                             return true;
6739                         case Keys.PageUp:
6740                             PageDownPostBrowser(false);
6741                             return true;
6742                         case Keys.PageDown:
6743                             PageDownPostBrowser(true);
6744                             return true;
6745                     }
6746                     if (Focused == FocusedControl.ListTab)
6747                     {
6748                         // 別タブの同じ書き込みへ(ALT+←/→)
6749                         if (KeyCode == Keys.Right)
6750                         {
6751                             GoSamePostToAnotherTab(false);
6752                             return true;
6753                         }
6754                         else if (KeyCode == Keys.Left)
6755                         {
6756                             GoSamePostToAnotherTab(true);
6757                             return true;
6758                         }
6759                     }
6760                     break;
6761                 case ModifierState.Ctrl | ModifierState.Shift:
6762                     switch (KeyCode)
6763                     {
6764                         case Keys.R:
6765                             MakeReplyOrDirectStatus(false, true, true);
6766                             return true;
6767                         case Keys.C:
6768                             CopyIdUri();
6769                             return true;
6770                         case Keys.F:
6771                             if (ListTab.SelectedTab != null)
6772                             {
6773                                 if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.PublicSearch)
6774                                 {
6775                                     ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"].Focus();
6776                                     return true;
6777                                 }
6778                             }
6779                             break;
6780                         case Keys.S:
6781                             FavoriteChange(false);
6782                             return true;
6783                         case Keys.B:
6784                             UnreadStripMenuItem_Click(null, null);
6785                             return true;
6786                         case Keys.T:
6787                             HashToggleMenuItem_Click(null, null);
6788                             return true;
6789                         case Keys.P:
6790                             ImageSelectMenuItem_Click(null, null);
6791                             return true;
6792                         case Keys.H:
6793                             doMoveToRTHome();
6794                             return true;
6795                         case Keys.O:
6796                             FavorareMenuItem_Click(null, null);
6797                             return true;
6798                     }
6799                     if (Focused == FocusedControl.StatusText)
6800                     {
6801                         int idx = 0;
6802                         switch (KeyCode)
6803                         {
6804                             case Keys.Up:
6805                                 if (_curList != null && _curList.VirtualListSize != 0 &&
6806                                             _curList.SelectedIndices.Count > 0 && _curList.SelectedIndices[0] > 0)
6807                                 {
6808                                     idx = _curList.SelectedIndices[0] - 1;
6809                                     SelectListItem(_curList, idx);
6810                                     _curList.EnsureVisible(idx);
6811                                     return true;
6812                                 }
6813                                 break;
6814                             case Keys.Down:
6815                                 if (_curList != null && _curList.VirtualListSize != 0 && _curList.SelectedIndices.Count > 0
6816                                             && _curList.SelectedIndices[0] < _curList.VirtualListSize - 1)
6817                                 {
6818                                     idx = _curList.SelectedIndices[0] + 1;
6819                                     SelectListItem(_curList, idx);
6820                                     _curList.EnsureVisible(idx);
6821                                     return true;
6822                                 }
6823                                 break;
6824                             case Keys.Space:
6825                                 if (StatusText.SelectionStart > 0)
6826                                 {
6827                                     int endidx = StatusText.SelectionStart - 1;
6828                                     string startstr = "";
6829                                     bool pressed = false;
6830                                     for (int i = StatusText.SelectionStart - 1; i >= 0; i--)
6831                                     {
6832                                         char c = StatusText.Text[i];
6833                                         if (Char.IsLetterOrDigit(c) || c == '_')
6834                                         {
6835                                             continue;
6836                                         }
6837                                         if (c == '@')
6838                                         {
6839                                             pressed = true;
6840                                             startstr = StatusText.Text.Substring(i + 1, endidx - i);
6841                                             int cnt = AtIdSupl.ItemCount;
6842                                             ShowSuplDialog(StatusText, AtIdSupl, startstr.Length + 1, startstr);
6843                                             if (AtIdSupl.ItemCount != cnt) _modifySettingAtId = true;
6844                                         }
6845                                         else if (c == '#')
6846                                         {
6847                                             pressed = true;
6848                                             startstr = StatusText.Text.Substring(i + 1, endidx - i);
6849                                             ShowSuplDialog(StatusText, HashSupl, startstr.Length + 1, startstr);
6850                                         }
6851                                         else
6852                                         {
6853                                             break;
6854                                         }
6855                                     }
6856                                     return pressed;
6857                                 }
6858                                 break;
6859                         }
6860                     }
6861                     else if (Focused == FocusedControl.ListTab)
6862                     {
6863                         DetailsListView lst = (DetailsListView)ListTab.SelectedTab.Tag;
6864                         ColumnHeader col;
6865                         switch (KeyCode)
6866                         {
6867                             case Keys.D1:
6868                             case Keys.D2:
6869                             case Keys.D3:
6870                             case Keys.D4:
6871                             case Keys.D5:
6872                             case Keys.D6:
6873                             case Keys.D7:
6874                             case Keys.D8:
6875                                 // ソートダイレクト選択(Ctrl+Shift+1~8,Ctrl+Shift+9)
6876                                 int colNo = KeyCode - Keys.D1;
6877                                 if (lst.Columns.Count < colNo) return false;
6878                                 col = lst.Columns.Cast<ColumnHeader>().Where((x) => { return x.DisplayIndex == colNo; }).FirstOrDefault();
6879                                 if (col == null) return false;
6880                                 MyList_ColumnClick(lst, new ColumnClickEventArgs(col.Index));
6881                                 return true;
6882                             case Keys.D9:
6883                                 col = lst.Columns.Cast<ColumnHeader>().OrderByDescending((x) => { return x.DisplayIndex; }).First();
6884                                 MyList_ColumnClick(lst, new ColumnClickEventArgs(col.Index));
6885                                 return true;
6886                         }
6887                     }
6888                     break;
6889                 case ModifierState.Ctrl | ModifierState.Alt:
6890                     if (KeyCode == Keys.S)
6891                     {
6892                         FavoritesRetweetOriginal();
6893                         return true;
6894                     }
6895                     else if (KeyCode == Keys.R)
6896                     {
6897                         FavoritesRetweetUnofficial();
6898                         return true;
6899                     }
6900                     else if (KeyCode == Keys.H)
6901                     {
6902                         OpenUserAppointUrl();
6903                         return true;
6904                     }
6905                     break;
6906                 case ModifierState.Alt | ModifierState.Shift:
6907                     if (Focused == FocusedControl.PostBrowser)
6908                     {
6909                         if (KeyCode == Keys.R)
6910                             doReTweetUnofficial();
6911                         else if (KeyCode == Keys.C)
6912                             CopyUserId();
6913                         return true;
6914                     }
6915                     switch (KeyCode)
6916                     {
6917                         case Keys.T:
6918                             if (!this.ExistCurrentPost) return false;
6919                             doTranslation(_curPost.TextFromApi);
6920                             return true;
6921                         case Keys.R:
6922                             doReTweetUnofficial();
6923                             return true;
6924                         case Keys.C:
6925                             CopyUserId();
6926                             return true;
6927                         case Keys.Up:
6928                             this.tweetThumbnail1.ScrollUp();
6929                             return true;
6930                         case Keys.Down:
6931                             this.tweetThumbnail1.ScrollDown();
6932                             return true;
6933                     }
6934                     if (Focused == FocusedControl.ListTab && KeyCode == Keys.Enter)
6935                     {
6936                         if (!this.SplitContainer3.Panel2Collapsed)
6937                         {
6938                             OpenThumbnailPicture(this.tweetThumbnail1.Thumbnail);
6939                         }
6940                         return true;
6941                     }
6942                     break;
6943             }
6944
6945             return false;
6946         }
6947
6948         private void ScrollDownPostBrowser(bool forward)
6949         {
6950             var doc = PostBrowser.Document;
6951             if (doc == null) return;
6952
6953             var tags = doc.GetElementsByTagName("html");
6954             if (tags.Count > 0)
6955             {
6956                 if (forward)
6957                     tags[0].ScrollTop += SettingDialog.FontDetail.Height;
6958                 else
6959                     tags[0].ScrollTop -= SettingDialog.FontDetail.Height;
6960             }
6961         }
6962
6963         private void PageDownPostBrowser(bool forward)
6964         {
6965             var doc = PostBrowser.Document;
6966             if (doc == null) return;
6967
6968             var tags = doc.GetElementsByTagName("html");
6969             if (tags.Count > 0)
6970             {
6971                 if (forward)
6972                     tags[0].ScrollTop += PostBrowser.ClientRectangle.Height - SettingDialog.FontDetail.Height;
6973                 else
6974                     tags[0].ScrollTop -= PostBrowser.ClientRectangle.Height - SettingDialog.FontDetail.Height;
6975             }
6976         }
6977
6978         private void GoNextTab(bool forward)
6979         {
6980             int idx = ListTab.SelectedIndex;
6981             if (forward)
6982             {
6983                 idx += 1;
6984                 if (idx > ListTab.TabPages.Count - 1) idx = 0;
6985             }
6986             else
6987             {
6988                 idx -= 1;
6989                 if (idx < 0) idx = ListTab.TabPages.Count - 1;
6990             }
6991             ListTab.SelectedIndex = idx;
6992             ListTabSelect(ListTab.TabPages[idx]);
6993         }
6994
6995         private void CopyStot()
6996         {
6997             string clstr = "";
6998             StringBuilder sb = new StringBuilder();
6999             bool IsProtected = false;
7000             bool isDm = false;
7001             if (this._curTab != null && this._statuses.GetTabByName(this._curTab.Text) != null) isDm = this._statuses.GetTabByName(this._curTab.Text).TabType == MyCommon.TabUsageType.DirectMessage;
7002             foreach (int idx in _curList.SelectedIndices)
7003             {
7004                 PostClass post = _statuses[_curTab.Text, idx];
7005                 if (post.IsProtect)
7006                 {
7007                     IsProtected = true;
7008                     continue;
7009                 }
7010                 if (post.IsDeleted) continue;
7011                 if (!isDm)
7012                 {
7013                     if (post.RetweetedId != null)
7014                         sb.AppendFormat("{0}:{1} [https://twitter.com/{0}/status/{2}]{3}", post.ScreenName, post.TextSingleLine, post.RetweetedId, Environment.NewLine);
7015                     else
7016                         sb.AppendFormat("{0}:{1} [https://twitter.com/{0}/status/{2}]{3}", post.ScreenName, post.TextSingleLine, post.StatusId, Environment.NewLine);
7017                 }
7018                 else
7019                 {
7020                     sb.AppendFormat("{0}:{1} [{2}]{3}", post.ScreenName, post.TextSingleLine, post.StatusId, Environment.NewLine);
7021                 }
7022             }
7023             if (IsProtected)
7024             {
7025                 MessageBox.Show(Properties.Resources.CopyStotText1);
7026             }
7027             if (sb.Length > 0)
7028             {
7029                 clstr = sb.ToString();
7030                 try
7031                 {
7032                     Clipboard.SetDataObject(clstr, false, 5, 100);
7033                 }
7034                 catch (Exception ex)
7035                 {
7036                     MessageBox.Show(ex.Message);
7037                 }
7038             }
7039         }
7040
7041         private void CopyIdUri()
7042         {
7043             string clstr = "";
7044             StringBuilder sb = new StringBuilder();
7045             if (this._curTab == null) return;
7046             if (this._statuses.GetTabByName(this._curTab.Text) == null) return;
7047             if (this._statuses.GetTabByName(this._curTab.Text).TabType == MyCommon.TabUsageType.DirectMessage) return;
7048             foreach (int idx in _curList.SelectedIndices)
7049             {
7050                 var post = _statuses[_curTab.Text, idx];
7051                 sb.Append(MyCommon.GetStatusUrl(post));
7052                 sb.Append(Environment.NewLine);
7053             }
7054             if (sb.Length > 0)
7055             {
7056                 clstr = sb.ToString();
7057                 try
7058                 {
7059                     Clipboard.SetDataObject(clstr, false, 5, 100);
7060                 }
7061                 catch (Exception ex)
7062                 {
7063                     MessageBox.Show(ex.Message);
7064                 }
7065             }
7066         }
7067
7068         private void GoFav(bool forward)
7069         {
7070             if (_curList.VirtualListSize == 0) return;
7071             int fIdx = 0;
7072             int toIdx = 0;
7073             int stp = 1;
7074
7075             if (forward)
7076             {
7077                 if (_curList.SelectedIndices.Count == 0)
7078                 {
7079                     fIdx = 0;
7080                 }
7081                 else
7082                 {
7083                     fIdx = _curList.SelectedIndices[0] + 1;
7084                     if (fIdx > _curList.VirtualListSize - 1) return;
7085                 }
7086                 toIdx = _curList.VirtualListSize;
7087                 stp = 1;
7088             }
7089             else
7090             {
7091                 if (_curList.SelectedIndices.Count == 0)
7092                 {
7093                     fIdx = _curList.VirtualListSize - 1;
7094                 }
7095                 else
7096                 {
7097                     fIdx = _curList.SelectedIndices[0] - 1;
7098                     if (fIdx < 0) return;
7099                 }
7100                 toIdx = -1;
7101                 stp = -1;
7102             }
7103
7104             for (int idx = fIdx; idx != toIdx; idx += stp)
7105             {
7106                 if (_statuses[_curTab.Text, idx].IsFav)
7107                 {
7108                     SelectListItem(_curList, idx);
7109                     _curList.EnsureVisible(idx);
7110                     break;
7111                 }
7112             }
7113         }
7114
7115         private void GoSamePostToAnotherTab(bool left)
7116         {
7117             if (_curList.VirtualListSize == 0) return;
7118             int fIdx = 0;
7119             int toIdx = 0;
7120             int stp = 1;
7121             long targetId = 0;
7122
7123             if (_statuses.Tabs[_curTab.Text].TabType == MyCommon.TabUsageType.DirectMessage) return; // Directタブは対象外(見つかるはずがない)
7124             if (_curList.SelectedIndices.Count == 0) return; //未選択も処理しない
7125
7126             targetId = GetCurTabPost(_curList.SelectedIndices[0]).StatusId;
7127
7128             if (left)
7129             {
7130                 // 左のタブへ
7131                 if (ListTab.SelectedIndex == 0)
7132                 {
7133                     return;
7134                 }
7135                 else
7136                 {
7137                     fIdx = ListTab.SelectedIndex - 1;
7138                 }
7139                 toIdx = -1;
7140                 stp = -1;
7141             }
7142             else
7143             {
7144                 // 右のタブへ
7145                 if (ListTab.SelectedIndex == ListTab.TabCount - 1)
7146                 {
7147                     return;
7148                 }
7149                 else
7150                 {
7151                     fIdx = ListTab.SelectedIndex + 1;
7152                 }
7153                 toIdx = ListTab.TabCount;
7154                 stp = 1;
7155             }
7156
7157             bool found = false;
7158             for (int tabidx = fIdx; tabidx != toIdx; tabidx += stp)
7159             {
7160                 if (_statuses.Tabs[ListTab.TabPages[tabidx].Text].TabType == MyCommon.TabUsageType.DirectMessage) continue; // Directタブは対象外
7161                 for (int idx = 0; idx < ((DetailsListView)ListTab.TabPages[tabidx].Tag).VirtualListSize; idx++)
7162                 {
7163                     if (_statuses[ListTab.TabPages[tabidx].Text, idx].StatusId == targetId)
7164                     {
7165                         ListTab.SelectedIndex = tabidx;
7166                         ListTabSelect(ListTab.TabPages[tabidx]);
7167                         SelectListItem(_curList, idx);
7168                         _curList.EnsureVisible(idx);
7169                         found = true;
7170                         break;
7171                     }
7172                 }
7173                 if (found) break;
7174             }
7175         }
7176
7177         private void GoPost(bool forward)
7178         {
7179             if (_curList.SelectedIndices.Count == 0 || _curPost == null) return;
7180             int fIdx = 0;
7181             int toIdx = 0;
7182             int stp = 1;
7183
7184             if (forward)
7185             {
7186                 fIdx = _curList.SelectedIndices[0] + 1;
7187                 if (fIdx > _curList.VirtualListSize - 1) return;
7188                 toIdx = _curList.VirtualListSize;
7189                 stp = 1;
7190             }
7191             else
7192             {
7193                 fIdx = _curList.SelectedIndices[0] - 1;
7194                 if (fIdx < 0) return;
7195                 toIdx = -1;
7196                 stp = -1;
7197             }
7198
7199             string name = "";
7200             if (_curPost.RetweetedId == null)
7201             {
7202                 name = _curPost.ScreenName;
7203             }
7204             else
7205             {
7206                 name = _curPost.RetweetedBy;
7207             }
7208             for (int idx = fIdx; idx != toIdx; idx += stp)
7209             {
7210                 if (_statuses[_curTab.Text, idx].RetweetedId == null)
7211                 {
7212                     if (_statuses[_curTab.Text, idx].ScreenName == name)
7213                     {
7214                         SelectListItem(_curList, idx);
7215                         _curList.EnsureVisible(idx);
7216                         break;
7217                     }
7218                 }
7219                 else
7220                 {
7221                     if (_statuses[_curTab.Text, idx].RetweetedBy == name)
7222                     {
7223                         SelectListItem(_curList, idx);
7224                         _curList.EnsureVisible(idx);
7225                         break;
7226                     }
7227                 }
7228             }
7229         }
7230
7231         private void GoRelPost(bool forward)
7232         {
7233             if (_curList.SelectedIndices.Count == 0) return;
7234
7235             int fIdx = 0;
7236             int toIdx = 0;
7237             int stp = 1;
7238             if (forward)
7239             {
7240                 fIdx = _curList.SelectedIndices[0] + 1;
7241                 if (fIdx > _curList.VirtualListSize - 1) return;
7242                 toIdx = _curList.VirtualListSize;
7243                 stp = 1;
7244             }
7245             else
7246             {
7247                 fIdx = _curList.SelectedIndices[0] - 1;
7248                 if (fIdx < 0) return;
7249                 toIdx = -1;
7250                 stp = -1;
7251             }
7252
7253             if (!_anchorFlag)
7254             {
7255                 if (_curPost == null) return;
7256                 _anchorPost = _curPost;
7257                 _anchorFlag = true;
7258             }
7259             else
7260             {
7261                 if (_anchorPost == null) return;
7262             }
7263
7264             for (int idx = fIdx; idx != toIdx; idx += stp)
7265             {
7266                 PostClass post = _statuses[_curTab.Text, idx];
7267                 if (post.ScreenName == _anchorPost.ScreenName ||
7268                     post.RetweetedBy == _anchorPost.ScreenName ||
7269                     post.ScreenName == _anchorPost.RetweetedBy ||
7270                     (!string.IsNullOrEmpty(post.RetweetedBy) && post.RetweetedBy == _anchorPost.RetweetedBy) ||
7271                     _anchorPost.ReplyToList.Contains(post.ScreenName.ToLower()) ||
7272                     _anchorPost.ReplyToList.Contains(post.RetweetedBy.ToLower()) ||
7273                     post.ReplyToList.Contains(_anchorPost.ScreenName.ToLower()) ||
7274                     post.ReplyToList.Contains(_anchorPost.RetweetedBy.ToLower()))
7275                 {
7276                     SelectListItem(_curList, idx);
7277                     _curList.EnsureVisible(idx);
7278                     break;
7279                 }
7280             }
7281         }
7282
7283         private void GoAnchor()
7284         {
7285             if (_anchorPost == null) return;
7286             int idx = _statuses.Tabs[_curTab.Text].IndexOf(_anchorPost.StatusId);
7287             if (idx == -1) return;
7288
7289             SelectListItem(_curList, idx);
7290             _curList.EnsureVisible(idx);
7291         }
7292
7293         private void GoTopEnd(bool GoTop)
7294         {
7295             ListViewItem _item;
7296             int idx;
7297
7298             if (GoTop)
7299             {
7300                 _item = _curList.GetItemAt(0, 25);
7301                 if (_item == null)
7302                     idx = 0;
7303                 else
7304                     idx = _item.Index;
7305             }
7306             else
7307             {
7308                 _item = _curList.GetItemAt(0, _curList.ClientSize.Height - 1);
7309                 if (_item == null)
7310                     idx = _curList.VirtualListSize - 1;
7311                 else
7312                     idx = _item.Index;
7313             }
7314             SelectListItem(_curList, idx);
7315         }
7316
7317         private void GoMiddle()
7318         {
7319             ListViewItem _item;
7320             int idx1;
7321             int idx2;
7322             int idx3;
7323
7324             _item = _curList.GetItemAt(0, 0);
7325             if (_item == null)
7326             {
7327                 idx1 = 0;
7328             }
7329             else
7330             {
7331                 idx1 = _item.Index;
7332             }
7333
7334             _item = _curList.GetItemAt(0, _curList.ClientSize.Height - 1);
7335             if (_item == null)
7336             {
7337                 idx2 = _curList.VirtualListSize - 1;
7338             }
7339             else
7340             {
7341                 idx2 = _item.Index;
7342             }
7343             idx3 = (idx1 + idx2) / 2;
7344
7345             SelectListItem(_curList, idx3);
7346         }
7347
7348         private void GoLast()
7349         {
7350             if (_curList.VirtualListSize == 0) return;
7351
7352             if (_statuses.SortOrder == SortOrder.Ascending)
7353             {
7354                 SelectListItem(_curList, _curList.VirtualListSize - 1);
7355                 _curList.EnsureVisible(_curList.VirtualListSize - 1);
7356             }
7357             else
7358             {
7359                 SelectListItem(_curList, 0);
7360                 _curList.EnsureVisible(0);
7361             }
7362         }
7363
7364         private void MoveTop()
7365         {
7366             if (_curList.SelectedIndices.Count == 0) return;
7367             int idx = _curList.SelectedIndices[0];
7368             if (_statuses.SortOrder == SortOrder.Ascending)
7369             {
7370                 _curList.EnsureVisible(_curList.VirtualListSize - 1);
7371             }
7372             else
7373             {
7374                 _curList.EnsureVisible(0);
7375             }
7376             _curList.EnsureVisible(idx);
7377         }
7378
7379         private void GoInReplyToPostTree()
7380         {
7381             if (_curPost == null) return;
7382
7383             TabClass curTabClass = _statuses.Tabs[_curTab.Text];
7384
7385             if (curTabClass.TabType == MyCommon.TabUsageType.PublicSearch && _curPost.InReplyToStatusId == null && _curPost.TextFromApi.Contains("@"))
7386             {
7387                 PostClass post = null;
7388                 string r = tw.GetStatusApi(false, _curPost.StatusId, ref post);
7389                 if (string.IsNullOrEmpty(r) && post != null)
7390                 {
7391                     _curPost.InReplyToStatusId = post.InReplyToStatusId;
7392                     _curPost.InReplyToUser = post.InReplyToUser;
7393                     _curPost.IsReply = post.IsReply;
7394                     this.PurgeListViewItemCache();
7395                     _curList.RedrawItems(_curItemIndex, _curItemIndex, false);
7396                 }
7397                 else
7398                 {
7399                     this.StatusLabel.Text = r;
7400                 }
7401             }
7402
7403             if (!(this.ExistCurrentPost && _curPost.InReplyToUser != null && _curPost.InReplyToStatusId != null)) return;
7404
7405             if (replyChains == null || (replyChains.Count > 0 && replyChains.Peek().InReplyToId != _curPost.StatusId))
7406             {
7407                 replyChains = new Stack<ReplyChain>();
7408             }
7409             replyChains.Push(new ReplyChain(_curPost.StatusId, _curPost.InReplyToStatusId.Value, _curTab));
7410
7411             int inReplyToIndex;
7412             string inReplyToTabName;
7413             long inReplyToId = _curPost.InReplyToStatusId.Value;
7414             string inReplyToUser = _curPost.InReplyToUser;
7415             //Dictionary<long, PostClass> curTabPosts = curTabClass.Posts;
7416
7417             var inReplyToPosts = from tab in _statuses.Tabs.Values
7418                                  orderby tab != curTabClass
7419                                  from post in tab.Posts.Values
7420                                  where post.StatusId == inReplyToId
7421                                  let index = tab.IndexOf(post.StatusId)
7422                                  where index != -1
7423                                  select new {Tab = tab, Index = index};
7424
7425             try
7426             {
7427                 var inReplyPost = inReplyToPosts.First();
7428                 inReplyToTabName = inReplyPost.Tab.TabName;
7429                 inReplyToIndex = inReplyPost.Index;
7430             }
7431             catch (InvalidOperationException)
7432             {
7433                 PostClass post = null;
7434                 string r = tw.GetStatusApi(false, _curPost.InReplyToStatusId.Value, ref post);
7435                 if (string.IsNullOrEmpty(r) && post != null)
7436                 {
7437                     post.IsRead = true;
7438                     _statuses.AddPost(post);
7439                     _statuses.DistributePosts();
7440                     //_statuses.SubmitUpdate(null, null, null, false);
7441                     this.RefreshTimeline(false);
7442                     try
7443                     {
7444                         var inReplyPost = inReplyToPosts.First();
7445                         inReplyToTabName = inReplyPost.Tab.TabName;
7446                         inReplyToIndex = inReplyPost.Index;
7447                     }
7448                     catch (InvalidOperationException)
7449                     {
7450                         OpenUriAsync("https://twitter.com/" + inReplyToUser + "/statuses/" + inReplyToId.ToString());
7451                         return;
7452                     }
7453                 }
7454                 else
7455                 {
7456                     this.StatusLabel.Text = r;
7457                     OpenUriAsync("https://twitter.com/" + inReplyToUser + "/statuses/" + inReplyToId.ToString());
7458                     return;
7459                 }
7460             }
7461
7462             TabPage tabPage = this.ListTab.TabPages.Cast<TabPage>().First((tp) => { return tp.Text == inReplyToTabName; });
7463             DetailsListView listView = (DetailsListView)tabPage.Tag;
7464
7465             if (_curTab != tabPage)
7466             {
7467                 this.ListTab.SelectTab(tabPage);
7468             }
7469
7470             this.SelectListItem(listView, inReplyToIndex);
7471             listView.EnsureVisible(inReplyToIndex);
7472         }
7473
7474         private void GoBackInReplyToPostTree(bool parallel = false, bool isForward = true)
7475         {
7476             if (_curPost == null) return;
7477
7478             TabClass curTabClass = _statuses.Tabs[_curTab.Text];
7479             //Dictionary<long, PostClass> curTabPosts = curTabClass.Posts;
7480
7481             if (parallel)
7482             {
7483                 if (_curPost.InReplyToStatusId != null)
7484                 {
7485                     var posts = from t in _statuses.Tabs
7486                                 from p in t.Value.Posts
7487                                 where p.Value.StatusId != _curPost.StatusId && p.Value.InReplyToStatusId == _curPost.InReplyToStatusId
7488                                 let indexOf = t.Value.IndexOf(p.Value.StatusId)
7489                                 where indexOf > -1
7490                                 orderby isForward ? indexOf : indexOf * -1
7491                                 orderby t.Value != curTabClass
7492                                 select new {Tab = t.Value, Post = p.Value, Index = indexOf};
7493                     try
7494                     {
7495                         var postList = posts.ToList();
7496                         for (int i = postList.Count - 1; i >= 0; i--)
7497                         {
7498                             int index = i;
7499                             if (postList.FindIndex((pst) => { return pst.Post.StatusId == postList[index].Post.StatusId; }) != index)
7500                             {
7501                                 postList.RemoveAt(index);
7502                             }
7503                         }
7504                         var post = postList.FirstOrDefault((pst) => { return pst.Tab == curTabClass && isForward ? pst.Index > _curItemIndex : pst.Index < _curItemIndex; });
7505                         if (post == null) post = postList.FirstOrDefault((pst) => { return pst.Tab != curTabClass; });
7506                         if (post == null) post = postList.First();
7507                         this.ListTab.SelectTab(this.ListTab.TabPages.Cast<TabPage>().First((tp) => { return tp.Text == post.Tab.TabName; }));
7508                         DetailsListView listView = (DetailsListView)this.ListTab.SelectedTab.Tag;
7509                         SelectListItem(listView, post.Index);
7510                         listView.EnsureVisible(post.Index);
7511                     }
7512                     catch (InvalidOperationException)
7513                     {
7514                         return;
7515                     }
7516                 }
7517             }
7518             else
7519             {
7520                 if (replyChains == null || replyChains.Count < 1)
7521                 {
7522                     var posts = from t in _statuses.Tabs
7523                                 from p in t.Value.Posts
7524                                 where p.Value.InReplyToStatusId == _curPost.StatusId
7525                                 let indexOf = t.Value.IndexOf(p.Value.StatusId)
7526                                 where indexOf > -1
7527                                 orderby indexOf
7528                                 orderby t.Value != curTabClass
7529                                 select new {Tab = t.Value, Index = indexOf};
7530                     try
7531                     {
7532                         var post = posts.First();
7533                         this.ListTab.SelectTab(this.ListTab.TabPages.Cast<TabPage>().First((tp) => { return tp.Text == post.Tab.TabName; }));
7534                         DetailsListView listView = (DetailsListView)this.ListTab.SelectedTab.Tag;
7535                         SelectListItem(listView, post.Index);
7536                         listView.EnsureVisible(post.Index);
7537                     }
7538                     catch (InvalidOperationException)
7539                     {
7540                         return;
7541                     }
7542                 }
7543                 else
7544                 {
7545                     ReplyChain chainHead = replyChains.Pop();
7546                     if (chainHead.InReplyToId == _curPost.StatusId)
7547                     {
7548                         int idx = _statuses.Tabs[chainHead.OriginalTab.Text].IndexOf(chainHead.OriginalId);
7549                         if (idx == -1)
7550                         {
7551                             replyChains = null;
7552                         }
7553                         else
7554                         {
7555                             try
7556                             {
7557                                 ListTab.SelectTab(chainHead.OriginalTab);
7558                             }
7559                             catch (Exception)
7560                             {
7561                                 replyChains = null;
7562                             }
7563                             SelectListItem(_curList, idx);
7564                             _curList.EnsureVisible(idx);
7565                         }
7566                     }
7567                     else
7568                     {
7569                         replyChains = null;
7570                         this.GoBackInReplyToPostTree(parallel);
7571                     }
7572                 }
7573             }
7574         }
7575
7576         private void GoBackSelectPostChain()
7577         {
7578             if (this.selectPostChains.Count > 1)
7579             {
7580                 var idx = -1;
7581                 TabPage tp = null;
7582
7583                 do
7584                 {
7585                     try
7586                     {
7587                         this.selectPostChains.Pop();
7588                         var tabPostPair = this.selectPostChains.Peek();
7589
7590                         if (!this.ListTab.TabPages.Contains(tabPostPair.Item1)) continue;  //該当タブが存在しないので無視
7591
7592                         if (tabPostPair.Item2 != null)
7593                         {
7594                             idx = this._statuses.Tabs[tabPostPair.Item1.Text].IndexOf(tabPostPair.Item2.StatusId);
7595                             if (idx == -1) continue;  //該当ポストが存在しないので無視
7596                         }
7597
7598                         tp = tabPostPair.Item1;
7599
7600                         this.selectPostChains.Pop();
7601                     }
7602                     catch (InvalidOperationException)
7603                     {
7604                     }
7605
7606                     break;
7607                 }
7608                 while (this.selectPostChains.Count > 1);
7609
7610                 if (tp == null)
7611                 {
7612                     //状態がおかしいので処理を中断
7613                     //履歴が残り1つであればクリアしておく
7614                     if (this.selectPostChains.Count == 1)
7615                         this.selectPostChains.Clear();
7616                     return;
7617                 }
7618
7619                 DetailsListView lst = (DetailsListView)tp.Tag;
7620                 this.ListTab.SelectedTab = tp;
7621                 if (idx > -1)
7622                 {
7623                     SelectListItem(lst, idx);
7624                     lst.EnsureVisible(idx);
7625                 }
7626                 lst.Focus();
7627             }
7628         }
7629
7630         private void PushSelectPostChain()
7631         {
7632             int count = this.selectPostChains.Count;
7633             if (count > 0)
7634             {
7635                 var p = this.selectPostChains.Peek();
7636                 if (p.Item1 == this._curTab)
7637                 {
7638                     if (p.Item2 == this._curPost) return;  //最新の履歴と同一
7639                     if (p.Item2 == null) this.selectPostChains.Pop();  //置き換えるため削除
7640                 }
7641             }
7642             if (count >= 2500) TrimPostChain();
7643             this.selectPostChains.Push(Tuple.Create(this._curTab, this._curPost));
7644         }
7645
7646         private void TrimPostChain()
7647         {
7648             if (this.selectPostChains.Count <= 2000) return;
7649             var p = new Stack<Tuple<TabPage, PostClass>>(2000);
7650             for (int i = 0; i < 2000; i++)
7651             {
7652                 p.Push(this.selectPostChains.Pop());
7653             }
7654             this.selectPostChains.Clear();
7655             for (int i = 0; i < 2000; i++)
7656             {
7657                 this.selectPostChains.Push(p.Pop());
7658             }
7659         }
7660
7661         private bool GoStatus(long statusId)
7662         {
7663             if (statusId == 0) return false;
7664             for (int tabidx = 0; tabidx < ListTab.TabCount; tabidx++)
7665             {
7666                 if (_statuses.Tabs[ListTab.TabPages[tabidx].Text].TabType != MyCommon.TabUsageType.DirectMessage && _statuses.Tabs[ListTab.TabPages[tabidx].Text].Contains(statusId))
7667                 {
7668                     int idx = _statuses.Tabs[ListTab.TabPages[tabidx].Text].IndexOf(statusId);
7669                     ListTab.SelectedIndex = tabidx;
7670                     ListTabSelect(ListTab.TabPages[tabidx]);
7671                     SelectListItem(_curList, idx);
7672                     _curList.EnsureVisible(idx);
7673                     return true;
7674                 }
7675             }
7676             return false;
7677         }
7678
7679         private bool GoDirectMessage(long statusId)
7680         {
7681             if (statusId == 0) return false;
7682             for (int tabidx = 0; tabidx < ListTab.TabCount; tabidx++)
7683             {
7684                 if (_statuses.Tabs[ListTab.TabPages[tabidx].Text].TabType == MyCommon.TabUsageType.DirectMessage && _statuses.Tabs[ListTab.TabPages[tabidx].Text].Contains(statusId))
7685                 {
7686                     int idx = _statuses.Tabs[ListTab.TabPages[tabidx].Text].IndexOf(statusId);
7687                     ListTab.SelectedIndex = tabidx;
7688                     ListTabSelect(ListTab.TabPages[tabidx]);
7689                     SelectListItem(_curList, idx);
7690                     _curList.EnsureVisible(idx);
7691                     return true;
7692                 }
7693             }
7694             return false;
7695         }
7696
7697         private void MyList_MouseClick(object sender, MouseEventArgs e)
7698         {
7699             _anchorFlag = false;
7700         }
7701
7702         private void StatusText_Enter(object sender, EventArgs e)
7703         {
7704             // フォーカスの戻り先を StatusText に設定
7705             this.Tag = StatusText;
7706             StatusText.BackColor = _clInputBackcolor;
7707         }
7708
7709         public Color InputBackColor
7710         {
7711             get { return _clInputBackcolor; }
7712             set { _clInputBackcolor = value; }
7713         }
7714
7715         private void StatusText_Leave(object sender, EventArgs e)
7716         {
7717             // フォーカスがメニューに遷移しないならばフォーカスはタブに移ることを期待
7718             if (ListTab.SelectedTab != null && MenuStrip1.Tag == null) this.Tag = ListTab.SelectedTab.Tag;
7719             StatusText.BackColor = Color.FromKnownColor(KnownColor.Window);
7720         }
7721
7722         private void StatusText_KeyDown(object sender, KeyEventArgs e)
7723         {
7724             ModifierState State = GetModifierState(e.Control, e.Shift, e.Alt);
7725             if (State == ModifierState.NotFlags) return;
7726             if (CommonKeyDown(e.KeyCode, FocusedControl.StatusText, State))
7727             {
7728                 e.Handled = true;
7729                 e.SuppressKeyPress = true;
7730             }
7731
7732             this.StatusText_TextChanged(null, null);
7733         }
7734
7735         private void SaveConfigsAll(bool ifModified)
7736         {
7737             if (!ifModified)
7738             {
7739                 SaveConfigsCommon();
7740                 SaveConfigsLocal();
7741                 SaveConfigsTabs();
7742                 SaveConfigsAtId();
7743             }
7744             else
7745             {
7746                 if (_modifySettingCommon) SaveConfigsCommon();
7747                 if (_modifySettingLocal) SaveConfigsLocal();
7748                 if (_modifySettingAtId) SaveConfigsAtId();
7749             }
7750         }
7751
7752         private void SaveConfigsAtId()
7753         {
7754             if (_ignoreConfigSave || !SettingDialog.UseAtIdSupplement && AtIdSupl == null) return;
7755
7756             _modifySettingAtId = false;
7757             SettingAtIdList cfgAtId = new SettingAtIdList(AtIdSupl.GetItemList());
7758             cfgAtId.Save();
7759         }
7760
7761         private void SaveConfigsCommon()
7762         {
7763             if (_ignoreConfigSave) return;
7764
7765             _modifySettingCommon = false;
7766             lock (_syncObject)
7767             {
7768                 _cfgCommon.UserName = tw.Username;
7769                 _cfgCommon.UserId = tw.UserId;
7770                 _cfgCommon.Password = tw.Password;
7771                 _cfgCommon.Token = tw.AccessToken;
7772                 _cfgCommon.TokenSecret = tw.AccessTokenSecret;
7773                 _cfgCommon.UserAccounts = SettingDialog.UserAccounts;
7774                 _cfgCommon.UserstreamStartup = SettingDialog.UserstreamStartup;
7775                 _cfgCommon.UserstreamPeriod = SettingDialog.UserstreamPeriodInt;
7776                 _cfgCommon.TimelinePeriod = SettingDialog.TimelinePeriodInt;
7777                 _cfgCommon.ReplyPeriod = SettingDialog.ReplyPeriodInt;
7778                 _cfgCommon.DMPeriod = SettingDialog.DMPeriodInt;
7779                 _cfgCommon.PubSearchPeriod = SettingDialog.PubSearchPeriodInt;
7780                 _cfgCommon.ListsPeriod = SettingDialog.ListsPeriodInt;
7781                 _cfgCommon.UserTimelinePeriod = SettingDialog.UserTimelinePeriodInt;
7782                 _cfgCommon.Read = SettingDialog.Readed;
7783                 _cfgCommon.IconSize = SettingDialog.IconSz;
7784                 _cfgCommon.UnreadManage = SettingDialog.UnreadManage;
7785                 _cfgCommon.PlaySound = SettingDialog.PlaySound;
7786                 _cfgCommon.OneWayLove = SettingDialog.OneWayLove;
7787
7788                 _cfgCommon.NameBalloon = SettingDialog.NameBalloon;
7789                 _cfgCommon.PostCtrlEnter = SettingDialog.PostCtrlEnter;
7790                 _cfgCommon.PostShiftEnter = SettingDialog.PostShiftEnter;
7791                 _cfgCommon.CountApi = SettingDialog.CountApi;
7792                 _cfgCommon.CountApiReply = SettingDialog.CountApiReply;
7793                 _cfgCommon.PostAndGet = SettingDialog.PostAndGet;
7794                 _cfgCommon.DispUsername = SettingDialog.DispUsername;
7795                 _cfgCommon.MinimizeToTray = SettingDialog.MinimizeToTray;
7796                 _cfgCommon.CloseToExit = SettingDialog.CloseToExit;
7797                 _cfgCommon.DispLatestPost = SettingDialog.DispLatestPost;
7798                 _cfgCommon.SortOrderLock = SettingDialog.SortOrderLock;
7799                 _cfgCommon.ViewTabBottom = SettingDialog.ViewTabBottom;
7800                 _cfgCommon.TinyUrlResolve = SettingDialog.TinyUrlResolve;
7801                 _cfgCommon.StartupVersion = SettingDialog.StartupVersion;
7802                 _cfgCommon.StartupFollowers = SettingDialog.StartupFollowers;
7803                 _cfgCommon.RestrictFavCheck = SettingDialog.RestrictFavCheck;
7804                 _cfgCommon.AlwaysTop = SettingDialog.AlwaysTop;
7805                 _cfgCommon.UrlConvertAuto = SettingDialog.UrlConvertAuto;
7806                 _cfgCommon.UseUnreadStyle = SettingDialog.UseUnreadStyle;
7807                 _cfgCommon.DateTimeFormat = SettingDialog.DateTimeFormat;
7808                 _cfgCommon.DefaultTimeOut = SettingDialog.DefaultTimeOut;
7809                 _cfgCommon.RetweetNoConfirm = SettingDialog.RetweetNoConfirm;
7810                 _cfgCommon.LimitBalloon = SettingDialog.LimitBalloon;
7811                 _cfgCommon.EventNotifyEnabled = SettingDialog.EventNotifyEnabled;
7812                 _cfgCommon.EventNotifyFlag = SettingDialog.EventNotifyFlag;
7813                 _cfgCommon.IsMyEventNotifyFlag = SettingDialog.IsMyEventNotifyFlag;
7814                 _cfgCommon.ForceEventNotify = SettingDialog.ForceEventNotify;
7815                 _cfgCommon.FavEventUnread = SettingDialog.FavEventUnread;
7816                 _cfgCommon.TranslateLanguage = SettingDialog.TranslateLanguage;
7817                 _cfgCommon.EventSoundFile = SettingDialog.EventSoundFile;
7818                 _cfgCommon.AutoShortUrlFirst = SettingDialog.AutoShortUrlFirst;
7819                 _cfgCommon.TabIconDisp = SettingDialog.TabIconDisp;
7820                 _cfgCommon.ReplyIconState = SettingDialog.ReplyIconState;
7821                 _cfgCommon.ReadOwnPost = SettingDialog.ReadOwnPost;
7822                 _cfgCommon.GetFav = SettingDialog.GetFav;
7823                 _cfgCommon.IsMonospace = SettingDialog.IsMonospace;
7824                 if (IdeographicSpaceToSpaceToolStripMenuItem != null &&
7825                    IdeographicSpaceToSpaceToolStripMenuItem.IsDisposed == false)
7826                 {
7827                     _cfgCommon.WideSpaceConvert = this.IdeographicSpaceToSpaceToolStripMenuItem.Checked;
7828                 }
7829                 _cfgCommon.ReadOldPosts = SettingDialog.ReadOldPosts;
7830                 _cfgCommon.BilyUser = SettingDialog.BitlyUser;
7831                 _cfgCommon.BitlyPwd = SettingDialog.BitlyPwd;
7832                 _cfgCommon.ShowGrid = SettingDialog.ShowGrid;
7833                 _cfgCommon.UseAtIdSupplement = SettingDialog.UseAtIdSupplement;
7834                 _cfgCommon.UseHashSupplement = SettingDialog.UseHashSupplement;
7835                 _cfgCommon.PreviewEnable = SettingDialog.PreviewEnable;
7836                 _cfgCommon.StatusAreaAtBottom = SettingDialog.StatusAreaAtBottom;
7837                 _cfgCommon.Language = SettingDialog.Language;
7838
7839                 _cfgCommon.SortOrder = (int)_statuses.SortOrder;
7840                 switch (_statuses.SortMode)
7841                 {
7842                     case IdComparerClass.ComparerMode.Nickname:  //ニックネーム
7843                         _cfgCommon.SortColumn = 1;
7844                         break;
7845                     case IdComparerClass.ComparerMode.Data:  //本文
7846                         _cfgCommon.SortColumn = 2;
7847                         break;
7848                     case IdComparerClass.ComparerMode.Id:  //時刻=発言Id
7849                         _cfgCommon.SortColumn = 3;
7850                         break;
7851                     case IdComparerClass.ComparerMode.Name:  //名前
7852                         _cfgCommon.SortColumn = 4;
7853                         break;
7854                     case IdComparerClass.ComparerMode.Source:  //Source
7855                         _cfgCommon.SortColumn = 7;
7856                         break;
7857                 }
7858
7859                 _cfgCommon.Nicoms = SettingDialog.Nicoms;
7860                 _cfgCommon.HashTags = HashMgr.HashHistories;
7861                 if (HashMgr.IsPermanent)
7862                 {
7863                     _cfgCommon.HashSelected = HashMgr.UseHash;
7864                 }
7865                 else
7866                 {
7867                     _cfgCommon.HashSelected = "";
7868                 }
7869                 _cfgCommon.HashIsHead = HashMgr.IsHead;
7870                 _cfgCommon.HashIsPermanent = HashMgr.IsPermanent;
7871                 _cfgCommon.HashIsNotAddToAtReply = HashMgr.IsNotAddToAtReply;
7872                 _cfgCommon.TwitterUrl = SettingDialog.TwitterApiUrl;
7873                 _cfgCommon.HotkeyEnabled = SettingDialog.HotkeyEnabled;
7874                 _cfgCommon.HotkeyModifier = SettingDialog.HotkeyMod;
7875                 _cfgCommon.HotkeyKey = SettingDialog.HotkeyKey;
7876                 _cfgCommon.HotkeyValue = SettingDialog.HotkeyValue;
7877                 _cfgCommon.BlinkNewMentions = SettingDialog.BlinkNewMentions;
7878                 if (ToolStripFocusLockMenuItem != null &&
7879                         ToolStripFocusLockMenuItem.IsDisposed == false)
7880                 {
7881                     _cfgCommon.FocusLockToStatusText = this.ToolStripFocusLockMenuItem.Checked;
7882                 }
7883                 _cfgCommon.UseAdditionalCount = SettingDialog.UseAdditionalCount;
7884                 _cfgCommon.MoreCountApi = SettingDialog.MoreCountApi;
7885                 _cfgCommon.FirstCountApi = SettingDialog.FirstCountApi;
7886                 _cfgCommon.SearchCountApi = SettingDialog.SearchCountApi;
7887                 _cfgCommon.FavoritesCountApi = SettingDialog.FavoritesCountApi;
7888                 _cfgCommon.UserTimelineCountApi = SettingDialog.UserTimelineCountApi;
7889                 _cfgCommon.TrackWord = tw.TrackWord;
7890                 _cfgCommon.AllAtReply = tw.AllAtReply;
7891                 _cfgCommon.OpenUserTimeline = SettingDialog.OpenUserTimeline;
7892                 _cfgCommon.ListCountApi = SettingDialog.ListCountApi;
7893                 _cfgCommon.UseImageService = ImageSelector.ServiceIndex;
7894                 _cfgCommon.UseImageServiceName = ImageSelector.ServiceName;
7895                 _cfgCommon.ListDoubleClickAction = SettingDialog.ListDoubleClickAction;
7896                 _cfgCommon.UserAppointUrl = SettingDialog.UserAppointUrl;
7897                 _cfgCommon.HideDuplicatedRetweets = SettingDialog.HideDuplicatedRetweets;
7898                 _cfgCommon.EnableImgAzyobuziNet = SettingDialog.EnableImgAzyobuziNet;
7899                 _cfgCommon.ImgAzyobuziNetDisabledInDM = SettingDialog.ImgAzyobuziNetDisabledInDM;
7900                 _cfgCommon.MapThumbnailProvider = SettingDialog.MapThumbnailProvider;
7901                 _cfgCommon.MapThumbnailHeight = SettingDialog.MapThumbnailHeight;
7902                 _cfgCommon.MapThumbnailWidth = SettingDialog.MapThumbnailWidth;
7903                 _cfgCommon.MapThumbnailZoom = SettingDialog.MapThumbnailZoom;
7904                 _cfgCommon.IsListsIncludeRts = SettingDialog.IsListStatusesIncludeRts;
7905                 _cfgCommon.TabMouseLock = SettingDialog.TabMouseLock;
7906                 _cfgCommon.IsRemoveSameEvent = SettingDialog.IsRemoveSameEvent;
7907                 _cfgCommon.IsUseNotifyGrowl = SettingDialog.IsNotifyUseGrowl;
7908
7909                 _cfgCommon.Save();
7910             }
7911         }
7912
7913         private void SaveConfigsLocal()
7914         {
7915             if (_ignoreConfigSave) return;
7916             lock (_syncObject)
7917             {
7918                 _modifySettingLocal = false;
7919                 _cfgLocal.FormSize = _mySize;
7920                 _cfgLocal.FormLocation = _myLoc;
7921                 _cfgLocal.SplitterDistance = _mySpDis;
7922                 _cfgLocal.PreviewDistance = _mySpDis3;
7923                 _cfgLocal.StatusMultiline = StatusText.Multiline;
7924                 _cfgLocal.StatusTextHeight = _mySpDis2;
7925                 _cfgLocal.StatusText = SettingDialog.Status;
7926
7927                 _cfgLocal.FontUnread = _fntUnread;
7928                 _cfgLocal.ColorUnread = _clUnread;
7929                 _cfgLocal.FontRead = _fntReaded;
7930                 _cfgLocal.ColorRead = _clReaded;
7931                 _cfgLocal.FontDetail = _fntDetail;
7932                 _cfgLocal.ColorDetail = _clDetail;
7933                 _cfgLocal.ColorDetailBackcolor = _clDetailBackcolor;
7934                 _cfgLocal.ColorDetailLink = _clDetailLink;
7935                 _cfgLocal.ColorFav = _clFav;
7936                 _cfgLocal.ColorOWL = _clOWL;
7937                 _cfgLocal.ColorRetweet = _clRetweet;
7938                 _cfgLocal.ColorSelf = _clSelf;
7939                 _cfgLocal.ColorAtSelf = _clAtSelf;
7940                 _cfgLocal.ColorTarget = _clTarget;
7941                 _cfgLocal.ColorAtTarget = _clAtTarget;
7942                 _cfgLocal.ColorAtFromTarget = _clAtFromTarget;
7943                 _cfgLocal.ColorAtTo = _clAtTo;
7944                 _cfgLocal.ColorListBackcolor = _clListBackcolor;
7945                 _cfgLocal.ColorInputBackcolor = _clInputBackcolor;
7946                 _cfgLocal.ColorInputFont = _clInputFont;
7947                 _cfgLocal.FontInputFont = _fntInputFont;
7948
7949                 _cfgLocal.BrowserPath = SettingDialog.BrowserPath;
7950                 _cfgLocal.UseRecommendStatus = SettingDialog.UseRecommendStatus;
7951                 _cfgLocal.ProxyType = SettingDialog.SelectedProxyType;
7952                 _cfgLocal.ProxyAddress = SettingDialog.ProxyAddress;
7953                 _cfgLocal.ProxyPort = SettingDialog.ProxyPort;
7954                 _cfgLocal.ProxyUser = SettingDialog.ProxyUser;
7955                 _cfgLocal.ProxyPassword = SettingDialog.ProxyPassword;
7956                 if (_ignoreConfigSave) return;
7957                 _cfgLocal.Save();
7958             }
7959         }
7960
7961         private void SaveConfigsTabs()
7962         {
7963             SettingTabs tabSetting = new SettingTabs();
7964             for (int i = 0; i < ListTab.TabPages.Count; i++)
7965             {
7966                 if (_statuses.Tabs[ListTab.TabPages[i].Text].TabType != MyCommon.TabUsageType.Related) tabSetting.Tabs.Add(_statuses.Tabs[ListTab.TabPages[i].Text]);
7967             }
7968             tabSetting.Save();
7969         }
7970
7971         private async void OpenURLFileMenuItem_Click(object sender, EventArgs e)
7972         {
7973             string inputText;
7974             var ret = InputDialog.Show(this, Properties.Resources.OpenURL_InputText, Properties.Resources.OpenURL_Caption, out inputText);
7975             if (ret != DialogResult.OK)
7976                 return;
7977
7978             var match = Twitter.StatusUrlRegex.Match(inputText);
7979             if (!match.Success)
7980             {
7981                 MessageBox.Show(this, Properties.Resources.OpenURL_InvalidFormat,
7982                     Properties.Resources.OpenURL_Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);
7983                 return;
7984             }
7985
7986             var statusId = long.Parse(match.Groups["StatusId"].Value);
7987
7988             var post = this._statuses[statusId];
7989             if (post == null)
7990             {
7991                 try
7992                 {
7993                     post = await Task.Run(() =>
7994                     {
7995                         PostClass newPost = null;
7996
7997                         var err = this.tw.GetStatusApi(false, statusId, ref newPost);
7998                         if (!string.IsNullOrEmpty(err))
7999                             throw new WebApiException(err);
8000
8001                         return newPost;
8002                     });
8003                 }
8004                 catch (WebApiException ex)
8005                 {
8006                     var message = ex.Message;
8007                     MessageBox.Show(this, string.Format(Properties.Resources.OpenURL_LoadFailed, message),
8008                         Properties.Resources.OpenURL_Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);
8009                     return;
8010                 }
8011             }
8012
8013             try
8014             {
8015                 this.OpenRelatedTab(post);
8016             }
8017             catch (TabException ex)
8018             {
8019                 MessageBox.Show(this, ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
8020             }
8021         }
8022
8023         private void SaveLogMenuItem_Click(object sender, EventArgs e)
8024         {
8025             DialogResult rslt = MessageBox.Show(string.Format(Properties.Resources.SaveLogMenuItem_ClickText1, Environment.NewLine),
8026                     Properties.Resources.SaveLogMenuItem_ClickText2,
8027                     MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
8028             if (rslt == DialogResult.Cancel) return;
8029
8030             SaveFileDialog1.FileName = MyCommon.GetAssemblyName() + "Posts" + DateTime.Now.ToString("yyMMdd-HHmmss") + ".tsv";
8031             SaveFileDialog1.InitialDirectory = Application.ExecutablePath;
8032             SaveFileDialog1.Filter = Properties.Resources.SaveLogMenuItem_ClickText3;
8033             SaveFileDialog1.FilterIndex = 0;
8034             SaveFileDialog1.Title = Properties.Resources.SaveLogMenuItem_ClickText4;
8035             SaveFileDialog1.RestoreDirectory = true;
8036
8037             if (SaveFileDialog1.ShowDialog() == DialogResult.OK)
8038             {
8039                 if (!SaveFileDialog1.ValidateNames) return;
8040                 using (StreamWriter sw = new StreamWriter(SaveFileDialog1.FileName, false, Encoding.UTF8))
8041                 {
8042                     if (rslt == DialogResult.Yes)
8043                     {
8044                         //All
8045                         for (int idx = 0; idx < _curList.VirtualListSize; idx++)
8046                         {
8047                             PostClass post = _statuses[_curTab.Text, idx];
8048                             string protect = "";
8049                             if (post.IsProtect) protect = "Protect";
8050                             sw.WriteLine(post.Nickname + "\t" +
8051                                      "\"" + post.TextFromApi.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
8052                                      post.CreatedAt.ToString() + "\t" +
8053                                      post.ScreenName + "\t" +
8054                                      post.StatusId.ToString() + "\t" +
8055                                      post.ImageUrl + "\t" +
8056                                      "\"" + post.Text.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
8057                                      protect);
8058                         }
8059                     }
8060                     else
8061                     {
8062                         foreach (int idx in _curList.SelectedIndices)
8063                         {
8064                             PostClass post = _statuses[_curTab.Text, idx];
8065                             string protect = "";
8066                             if (post.IsProtect) protect = "Protect";
8067                             sw.WriteLine(post.Nickname + "\t" +
8068                                      "\"" + post.TextFromApi.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
8069                                      post.CreatedAt.ToString() + "\t" +
8070                                      post.ScreenName + "\t" +
8071                                      post.StatusId.ToString() + "\t" +
8072                                      post.ImageUrl + "\t" +
8073                                      "\"" + post.Text.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
8074                                      protect);
8075                         }
8076                     }
8077                 }
8078             }
8079             this.TopMost = SettingDialog.AlwaysTop;
8080         }
8081
8082         private void PostBrowser_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
8083         {
8084             ModifierState State = GetModifierState(e.Control, e.Shift, e.Alt);
8085             if (State == ModifierState.NotFlags) return;
8086             bool KeyRes = CommonKeyDown(e.KeyCode, FocusedControl.PostBrowser, State);
8087             if (KeyRes)
8088             {
8089                 e.IsInputKey = true;
8090             }
8091         }
8092         public bool TabRename(ref string tabName)
8093         {
8094             //タブ名変更
8095             string newTabText = null;
8096             using (InputTabName inputName = new InputTabName())
8097             {
8098                 inputName.TabName = tabName;
8099                 inputName.ShowDialog();
8100                 if (inputName.DialogResult == DialogResult.Cancel) return false;
8101                 newTabText = inputName.TabName;
8102             }
8103             this.TopMost = SettingDialog.AlwaysTop;
8104             if (!string.IsNullOrEmpty(newTabText))
8105             {
8106                 //新タブ名存在チェック
8107                 for (int i = 0; i < ListTab.TabCount; i++)
8108                 {
8109                     if (ListTab.TabPages[i].Text == newTabText)
8110                     {
8111                         string tmp = string.Format(Properties.Resources.Tabs_DoubleClickText1, newTabText);
8112                         MessageBox.Show(tmp, Properties.Resources.Tabs_DoubleClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
8113                         return false;
8114                     }
8115                 }
8116                 //タブ名のリスト作り直し(デフォルトタブ以外は再作成)
8117                 for (int i = 0; i < ListTab.TabCount; i++)
8118                 {
8119                     if (ListTab.TabPages[i].Text == tabName)
8120                     {
8121                         ListTab.TabPages[i].Text = newTabText;
8122                     }
8123                 }
8124                 _statuses.RenameTab(tabName, newTabText);
8125
8126                 for (int i = 0; i < ListTab.TabCount; i++)
8127                 {
8128                     if (_statuses.IsDistributableTab(ListTab.TabPages[i].Text))
8129                     {
8130                         if (ListTab.TabPages[i].Text == tabName)
8131                         {
8132                             ListTab.TabPages[i].Text = newTabText;
8133                         }
8134                     }
8135                 }
8136                 SaveConfigsCommon();
8137                 SaveConfigsTabs();
8138                 _rclickTabName = newTabText;
8139                 tabName = newTabText;
8140                 return true;
8141             }
8142             else
8143             {
8144                 return false;
8145             }
8146         }
8147
8148         private void ListTab_MouseClick(object sender, MouseEventArgs e)
8149         {
8150             if (e.Button == MouseButtons.Middle)
8151             {
8152                 for (int i = 0; i < this.ListTab.TabPages.Count; i++)
8153                 {
8154                     if (this.ListTab.GetTabRect(i).Contains(e.Location))
8155                     {
8156                         this.RemoveSpecifiedTab(this.ListTab.TabPages[i].Text, true);
8157                         this.SaveConfigsTabs();
8158                         break;
8159                     }
8160                 }
8161             }
8162         }
8163
8164         private void ListTab_DoubleClick(object sender, MouseEventArgs e)
8165         {
8166             string tn = ListTab.SelectedTab.Text;
8167             TabRename(ref tn);
8168         }
8169
8170         private void ListTab_MouseDown(object sender, MouseEventArgs e)
8171         {
8172             if (SettingDialog.TabMouseLock) return;
8173             Point cpos = new Point(e.X, e.Y);
8174             if (e.Button == MouseButtons.Left)
8175             {
8176                 for (int i = 0; i < ListTab.TabPages.Count; i++)
8177                 {
8178                     if (this.ListTab.GetTabRect(i).Contains(e.Location))
8179                     {
8180                         _tabDrag = true;
8181                         _tabMouseDownPoint = e.Location;
8182                         break;
8183                     }
8184                 }
8185             }
8186             else
8187             {
8188                 _tabDrag = false;
8189             }
8190         }
8191
8192         private void ListTab_DragEnter(object sender, DragEventArgs e)
8193         {
8194             if (e.Data.GetDataPresent(typeof(TabPage)))
8195                 e.Effect = DragDropEffects.Move;
8196             else
8197                 e.Effect = DragDropEffects.None;
8198         }
8199
8200         private void ListTab_DragDrop(object sender, DragEventArgs e)
8201         {
8202             if (!e.Data.GetDataPresent(typeof(TabPage))) return;
8203
8204             _tabDrag = false;
8205             string tn = "";
8206             bool bef = false;
8207             Point cpos = new Point(e.X, e.Y);
8208             Point spos = ListTab.PointToClient(cpos);
8209             int i;
8210             for (i = 0; i < ListTab.TabPages.Count; i++)
8211             {
8212                 Rectangle rect = ListTab.GetTabRect(i);
8213                 if (rect.Left <= spos.X && spos.X <= rect.Right &&
8214                     rect.Top <= spos.Y && spos.Y <= rect.Bottom)
8215                 {
8216                     tn = ListTab.TabPages[i].Text;
8217                     if (spos.X <= (rect.Left + rect.Right) / 2)
8218                         bef = true;
8219                     else
8220                         bef = false;
8221
8222                     break;
8223                 }
8224             }
8225
8226             //タブのないところにドロップ->最後尾へ移動
8227             if (string.IsNullOrEmpty(tn))
8228             {
8229                 tn = ListTab.TabPages[ListTab.TabPages.Count - 1].Text;
8230                 bef = false;
8231                 i = ListTab.TabPages.Count - 1;
8232             }
8233
8234             TabPage tp = (TabPage)e.Data.GetData(typeof(TabPage));
8235             if (tp.Text == tn) return;
8236
8237             ReOrderTab(tp.Text, tn, bef);
8238         }
8239
8240         public void ReOrderTab(string targetTabText, string baseTabText, bool isBeforeBaseTab)
8241         {
8242             int baseIndex = 0;
8243             for (baseIndex = 0; baseIndex < ListTab.TabPages.Count; baseIndex++)
8244             {
8245                 if (ListTab.TabPages[baseIndex].Text == baseTabText) break;
8246             }
8247
8248             using (ControlTransaction.Layout(this.ListTab))
8249             {
8250                 TabPage mTp = null;
8251                 for (int j = 0; j < ListTab.TabPages.Count; j++)
8252                 {
8253                     if (ListTab.TabPages[j].Text == targetTabText)
8254                     {
8255                         mTp = ListTab.TabPages[j];
8256                         ListTab.TabPages.Remove(mTp);
8257                         if (j < baseIndex) baseIndex -= 1;
8258                         break;
8259                     }
8260                 }
8261                 if (isBeforeBaseTab)
8262                     ListTab.TabPages.Insert(baseIndex, mTp);
8263                 else
8264                     ListTab.TabPages.Insert(baseIndex + 1, mTp);
8265             }
8266
8267             SaveConfigsTabs();
8268         }
8269
8270         private void MakeReplyOrDirectStatus(bool isAuto = true, bool isReply = true, bool isAll = false)
8271         {
8272             //isAuto:true=先頭に挿入、false=カーソル位置に挿入
8273             //isReply:true=@,false=DM
8274             if (!StatusText.Enabled) return;
8275             if (_curList == null) return;
8276             if (_curTab == null) return;
8277             if (!this.ExistCurrentPost) return;
8278
8279             // 複数あてリプライはReplyではなく通常ポスト
8280             //↑仕様変更で全部リプライ扱いでOK(先頭ドット付加しない)
8281             //090403暫定でドットを付加しないようにだけ修正。単独と複数の処理は統合できると思われる。
8282             //090513 all @ replies 廃止の仕様変更によりドット付加に戻し(syo68k)
8283
8284             if (_curList.SelectedIndices.Count > 0)
8285             {
8286                 // アイテムが1件以上選択されている
8287                 if (_curList.SelectedIndices.Count == 1 && !isAll && this.ExistCurrentPost)
8288                 {
8289                     // 単独ユーザー宛リプライまたはDM
8290                     if ((_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.DirectMessage && isAuto) || (!isAuto && !isReply))
8291                     {
8292                         // ダイレクトメッセージ
8293                         StatusText.Text = "D " + _curPost.ScreenName + " " + StatusText.Text;
8294                         StatusText.SelectionStart = StatusText.Text.Length;
8295                         StatusText.Focus();
8296                         _reply_to_id = null;
8297                         _reply_to_name = null;
8298                         return;
8299                     }
8300                     if (string.IsNullOrEmpty(StatusText.Text))
8301                     {
8302                         //空の場合
8303
8304                         // ステータステキストが入力されていない場合先頭に@ユーザー名を追加する
8305                         StatusText.Text = "@" + _curPost.ScreenName + " ";
8306                         if (_curPost.RetweetedId != null)
8307                         {
8308                             _reply_to_id = _curPost.RetweetedId.Value;
8309                         }
8310                         else
8311                         {
8312                             _reply_to_id = _curPost.StatusId;
8313                         }
8314                         _reply_to_name = _curPost.ScreenName;
8315                     }
8316                     else
8317                     {
8318                         //何か入力済の場合
8319
8320                         if (isAuto)
8321                         {
8322                             //1件選んでEnter or DoubleClick
8323                             if (StatusText.Text.Contains("@" + _curPost.ScreenName + " "))
8324                             {
8325                                 if (_reply_to_id != null && _reply_to_name == _curPost.ScreenName)
8326                                 {
8327                                     //返信先書き換え
8328                                     if (_curPost.RetweetedId != null)
8329                                     {
8330                                         _reply_to_id = _curPost.RetweetedId.Value;
8331                                     }
8332                                     else
8333                                     {
8334                                         _reply_to_id = _curPost.StatusId;
8335                                     }
8336                                     _reply_to_name = _curPost.ScreenName;
8337                                 }
8338                                 return;
8339                             }
8340                             if (!StatusText.Text.StartsWith("@"))
8341                             {
8342                                 //文頭@以外
8343                                 if (StatusText.Text.StartsWith(". "))
8344                                 {
8345                                     // 複数リプライ
8346                                     StatusText.Text = StatusText.Text.Insert(2, "@" + _curPost.ScreenName + " ");
8347                                     _reply_to_id = null;
8348                                     _reply_to_name = null;
8349                                 }
8350                                 else
8351                                 {
8352                                     // 単独リプライ
8353                                     StatusText.Text = "@" + _curPost.ScreenName + " " + StatusText.Text;
8354                                     if (_curPost.RetweetedId != null)
8355                                     {
8356                                         _reply_to_id = _curPost.RetweetedId.Value;
8357                                     }
8358                                     else
8359                                     {
8360                                         _reply_to_id = _curPost.StatusId;
8361                                     }
8362                                     _reply_to_name = _curPost.ScreenName;
8363                                 }
8364                             }
8365                             else
8366                             {
8367                                 //文頭@
8368                                 // 複数リプライ
8369                                 StatusText.Text = ". @" + _curPost.ScreenName + " " + StatusText.Text;
8370                                 //StatusText.Text = "@" + _curPost.ScreenName + " " + StatusText.Text;
8371                                 _reply_to_id = null;
8372                                 _reply_to_name = null;
8373                             }
8374                         }
8375                         else
8376                         {
8377                             //1件選んでCtrl-Rの場合(返信先操作せず)
8378                             int sidx = StatusText.SelectionStart;
8379                             string id = "@" + _curPost.ScreenName + " ";
8380                             if (sidx > 0)
8381                             {
8382                                 if (StatusText.Text.Substring(sidx - 1, 1) != " ")
8383                                 {
8384                                     id = " " + id;
8385                                 }
8386                             }
8387                             StatusText.Text = StatusText.Text.Insert(sidx, id);
8388                             sidx += id.Length;
8389                             //if (StatusText.Text.StartsWith("@"))
8390                             //{
8391                             //    //複数リプライ
8392                             //    StatusText.Text = ". " + StatusText.Text.Insert(sidx, " @" + _curPost.ScreenName + " ");
8393                             //    sidx += 5 + _curPost.ScreenName.Length;
8394                             //}
8395                             //else
8396                             //{
8397                             //    // 複数リプライ
8398                             //    StatusText.Text = StatusText.Text.Insert(sidx, " @" + _curPost.ScreenName + " ");
8399                             //    sidx += 3 + _curPost.ScreenName.Length;
8400                             //}
8401                             StatusText.SelectionStart = sidx;
8402                             StatusText.Focus();
8403                             //_reply_to_id = 0;
8404                             //_reply_to_name = null;
8405                             return;
8406                         }
8407                     }
8408                 }
8409                 else
8410                 {
8411                     // 複数リプライ
8412                     if (!isAuto && !isReply) return;
8413
8414                     //C-S-rか、複数の宛先を選択中にEnter/DoubleClick/C-r/C-S-r
8415
8416                     if (isAuto)
8417                     {
8418                         //Enter or DoubleClick
8419
8420                         string sTxt = StatusText.Text;
8421                         if (!sTxt.StartsWith(". "))
8422                         {
8423                             sTxt = ". " + sTxt;
8424                             _reply_to_id = null;
8425                             _reply_to_name = null;
8426                         }
8427                         for (int cnt = 0; cnt < _curList.SelectedIndices.Count; cnt++)
8428                         {
8429                             PostClass post = _statuses[_curTab.Text, _curList.SelectedIndices[cnt]];
8430                             if (!sTxt.Contains("@" + post.ScreenName + " "))
8431                             {
8432                                 sTxt = sTxt.Insert(2, "@" + post.ScreenName + " ");
8433                                 //sTxt = "@" + post.ScreenName + " " + sTxt;
8434                             }
8435                         }
8436                         StatusText.Text = sTxt;
8437                     }
8438                     else
8439                     {
8440                         //C-S-r or C-r
8441                         if (_curList.SelectedIndices.Count > 1)
8442                         {
8443                             //複数ポスト選択
8444
8445                             string ids = "";
8446                             int sidx = StatusText.SelectionStart;
8447                             for (int cnt = 0; cnt < _curList.SelectedIndices.Count; cnt++)
8448                             {
8449                                 PostClass post = _statuses[_curTab.Text, _curList.SelectedIndices[cnt]];
8450                                 if (!ids.Contains("@" + post.ScreenName + " ") &&
8451                                     !post.ScreenName.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
8452                                 {
8453                                     ids += "@" + post.ScreenName + " ";
8454                                 }
8455                                 if (isAll)
8456                                 {
8457                                     foreach (string nm in post.ReplyToList)
8458                                     {
8459                                         if (!ids.Contains("@" + nm + " ") &&
8460                                             !nm.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
8461                                         {
8462                                             Match m = Regex.Match(post.TextFromApi, "[@@](?<id>" + nm + ")([^a-zA-Z0-9]|$)", RegexOptions.IgnoreCase);
8463                                             if (m.Success)
8464                                                 ids += "@" + m.Result("${id}") + " ";
8465                                             else
8466                                                 ids += "@" + nm + " ";
8467                                         }
8468                                     }
8469                                 }
8470                             }
8471                             if (ids.Length == 0) return;
8472                             if (!StatusText.Text.StartsWith(". "))
8473                             {
8474                                 StatusText.Text = ". " + StatusText.Text;
8475                                 sidx += 2;
8476                                 _reply_to_id = null;
8477                                 _reply_to_name = null;
8478                             }
8479                             if (sidx > 0)
8480                             {
8481                                 if (StatusText.Text.Substring(sidx - 1, 1) != " ")
8482                                 {
8483                                     ids = " " + ids;
8484                                 }
8485                             }
8486                             StatusText.Text = StatusText.Text.Insert(sidx, ids);
8487                             sidx += ids.Length;
8488                             //if (StatusText.Text.StartsWith("@"))
8489                             //{
8490                             //    StatusText.Text = ". " + StatusText.Text.Insert(sidx, ids);
8491                             //    sidx += 2 + ids.Length;
8492                             //}
8493                             //else
8494                             //{
8495                             //    StatusText.Text = StatusText.Text.Insert(sidx, ids);
8496                             //    sidx += 1 + ids.Length;
8497                             //}
8498                             StatusText.SelectionStart = sidx;
8499                             StatusText.Focus();
8500                             return;
8501                         }
8502                         else
8503                         {
8504                             //1件のみ選択のC-S-r(返信元付加する可能性あり)
8505
8506                             string ids = "";
8507                             int sidx = StatusText.SelectionStart;
8508                             PostClass post = _curPost;
8509                             if (!ids.Contains("@" + post.ScreenName + " ") &&
8510                                 !post.ScreenName.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
8511                             {
8512                                 ids += "@" + post.ScreenName + " ";
8513                             }
8514                             foreach (string nm in post.ReplyToList)
8515                             {
8516                                 if (!ids.Contains("@" + nm + " ") &&
8517                                     !nm.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
8518                                 {
8519                                     Match m = Regex.Match(post.TextFromApi, "[@@](?<id>" + nm + ")([^a-zA-Z0-9]|$)", RegexOptions.IgnoreCase);
8520                                     if (m.Success)
8521                                         ids += "@" + m.Result("${id}") + " ";
8522                                     else
8523                                         ids += "@" + nm + " ";
8524                                 }
8525                             }
8526                             if (!string.IsNullOrEmpty(post.RetweetedBy))
8527                             {
8528                                 if (!ids.Contains("@" + post.RetweetedBy + " ") &&
8529                                    !post.RetweetedBy.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
8530                                 {
8531                                     ids += "@" + post.RetweetedBy + " ";
8532                                 }
8533                             }
8534                             if (ids.Length == 0) return;
8535                             if (string.IsNullOrEmpty(StatusText.Text))
8536                             {
8537                                 //未入力の場合のみ返信先付加
8538                                 StatusText.Text = ids;
8539                                 StatusText.SelectionStart = ids.Length;
8540                                 StatusText.Focus();
8541                                 if (post.RetweetedId != null)
8542                                 {
8543                                     _reply_to_id = post.RetweetedId.Value;
8544                                 }
8545                                 else
8546                                 {
8547                                     _reply_to_id = post.StatusId;
8548                                 }
8549                                 _reply_to_name = post.ScreenName;
8550                                 return;
8551                             }
8552
8553                             if (sidx > 0)
8554                             {
8555                                 if (StatusText.Text.Substring(sidx - 1, 1) != " ")
8556                                 {
8557                                     ids = " " + ids;
8558                                 }
8559                             }
8560                             StatusText.Text = StatusText.Text.Insert(sidx, ids);
8561                             sidx += ids.Length;
8562                             StatusText.SelectionStart = sidx;
8563                             StatusText.Focus();
8564                             return;
8565                         }
8566                     }
8567                 }
8568                 StatusText.SelectionStart = StatusText.Text.Length;
8569                 StatusText.Focus();
8570             }
8571         }
8572
8573         private void ListTab_MouseUp(object sender, MouseEventArgs e)
8574         {
8575             _tabDrag = false;
8576         }
8577
8578         private static int iconCnt = 0;
8579         private static int blinkCnt = 0;
8580         private static bool blink = false;
8581         private static bool idle = false;
8582
8583         private void RefreshTasktrayIcon(bool forceRefresh)
8584         {
8585             if (_colorize) Colorize();
8586             if (!TimerRefreshIcon.Enabled) return;
8587             //Static usCheckCnt As int = 0
8588
8589             //Static iconDlListTopItem As ListViewItem = null
8590
8591             if (forceRefresh) idle = false;
8592
8593             //if (((ListView)ListTab.SelectedTab.Tag).TopItem == iconDlListTopItem)
8594             //    ((ImageDictionary)this.TIconDic).PauseGetImage = false;
8595             //else
8596             //    ((ImageDictionary)this.TIconDic).PauseGetImage = true;
8597             //
8598             //iconDlListTopItem = ((ListView)ListTab.SelectedTab.Tag).TopItem;
8599
8600             iconCnt += 1;
8601             blinkCnt += 1;
8602             //usCheckCnt += 1;
8603
8604             //if (usCheckCnt > 300)    //1min
8605             //{
8606             //    usCheckCnt = 0;
8607             //    if (!this.IsReceivedUserStream)
8608             //    {
8609             //        TraceOut("ReconnectUserStream");
8610             //        tw.ReconnectUserStream();
8611             //    }
8612             //}
8613
8614             bool busy = false;
8615             foreach (BackgroundWorker bw in this._bw)
8616             {
8617                 if (bw != null && bw.IsBusy)
8618                 {
8619                     busy = true;
8620                     break;
8621                 }
8622             }
8623
8624             if (iconCnt > 3)
8625             {
8626                 iconCnt = 0;
8627             }
8628             if (blinkCnt > 10)
8629             {
8630                 blinkCnt = 0;
8631                 //未保存の変更を保存
8632                 SaveConfigsAll(true);
8633             }
8634
8635             if (busy)
8636             {
8637                 NotifyIcon1.Icon = NIconRefresh[iconCnt];
8638                 idle = false;
8639                 _myStatusError = false;
8640                 return;
8641             }
8642
8643             TabClass tb = _statuses.GetTabByType(MyCommon.TabUsageType.Mentions);
8644             if (SettingDialog.ReplyIconState != MyCommon.REPLY_ICONSTATE.None && tb != null && tb.UnreadCount > 0)
8645             {
8646                 if (blinkCnt > 0) return;
8647                 blink = !blink;
8648                 if (blink || SettingDialog.ReplyIconState == MyCommon.REPLY_ICONSTATE.StaticIcon)
8649                 {
8650                     NotifyIcon1.Icon = ReplyIcon;
8651                 }
8652                 else
8653                 {
8654                     NotifyIcon1.Icon = ReplyIconBlink;
8655                 }
8656                 idle = false;
8657                 return;
8658             }
8659
8660             if (idle) return;
8661             idle = true;
8662             //優先度:エラー→オフライン→アイドル
8663             //エラーは更新アイコンでクリアされる
8664             if (_myStatusError)
8665             {
8666                 NotifyIcon1.Icon = NIconAtRed;
8667                 return;
8668             }
8669             if (_myStatusOnline)
8670             {
8671                 NotifyIcon1.Icon = NIconAt;
8672             }
8673             else
8674             {
8675                 NotifyIcon1.Icon = NIconAtSmoke;
8676             }
8677         }
8678
8679         private void TimerRefreshIcon_Tick(object sender, EventArgs e)
8680         {
8681             //200ms
8682             this.RefreshTasktrayIcon(false);
8683         }
8684
8685         private void ContextMenuTabProperty_Opening(object sender, CancelEventArgs e)
8686         {
8687             //右クリックの場合はタブ名が設定済。アプリケーションキーの場合は現在のタブを対象とする
8688             if (string.IsNullOrEmpty(_rclickTabName) || sender != ContextMenuTabProperty)
8689             {
8690                 if (ListTab != null && ListTab.SelectedTab != null)
8691                     _rclickTabName = ListTab.SelectedTab.Text;
8692                 else
8693                     return;
8694             }
8695
8696             if (_statuses == null) return;
8697             if (_statuses.Tabs == null) return;
8698
8699             TabClass tb = _statuses.Tabs[_rclickTabName];
8700             if (tb == null) return;
8701
8702             NotifyDispMenuItem.Checked = tb.Notify;
8703             this.NotifyTbMenuItem.Checked = tb.Notify;
8704
8705             soundfileListup = true;
8706             SoundFileComboBox.Items.Clear();
8707             this.SoundFileTbComboBox.Items.Clear();
8708             SoundFileComboBox.Items.Add("");
8709             this.SoundFileTbComboBox.Items.Add("");
8710             DirectoryInfo oDir = new DirectoryInfo(Application.StartupPath + Path.DirectorySeparatorChar);
8711             if (Directory.Exists(Path.Combine(Application.StartupPath, "Sounds")))
8712             {
8713                 oDir = oDir.GetDirectories("Sounds")[0];
8714             }
8715             foreach (FileInfo oFile in oDir.GetFiles("*.wav"))
8716             {
8717                 SoundFileComboBox.Items.Add(oFile.Name);
8718                 this.SoundFileTbComboBox.Items.Add(oFile.Name);
8719             }
8720             int idx = SoundFileComboBox.Items.IndexOf(tb.SoundFile);
8721             if (idx == -1) idx = 0;
8722             SoundFileComboBox.SelectedIndex = idx;
8723             this.SoundFileTbComboBox.SelectedIndex = idx;
8724             soundfileListup = false;
8725             UreadManageMenuItem.Checked = tb.UnreadManage;
8726             this.UnreadMngTbMenuItem.Checked = tb.UnreadManage;
8727
8728             TabMenuControl(_rclickTabName);
8729         }
8730
8731         private void TabMenuControl(string tabName)
8732         {
8733             this.FilterEditMenuItem.Enabled = true;
8734             this.EditRuleTbMenuItem.Enabled = true;
8735
8736             if (_statuses.IsDefaultTab(tabName))
8737             {
8738                 this.ProtectTabMenuItem.Enabled = false;
8739                 this.ProtectTbMenuItem.Enabled = false;
8740             }
8741             else
8742             {
8743                 this.ProtectTabMenuItem.Enabled = true;
8744                 this.ProtectTbMenuItem.Enabled = true;
8745             }
8746
8747             if (_statuses.IsDefaultTab(tabName) || _statuses.Tabs[tabName].Protected)
8748             {
8749                 this.ProtectTabMenuItem.Checked = true;
8750                 this.ProtectTbMenuItem.Checked = true;
8751                 this.DeleteTabMenuItem.Enabled = false;
8752                 this.DeleteTbMenuItem.Enabled = false;
8753             }
8754             else
8755             {
8756                 this.ProtectTabMenuItem.Checked = false;
8757                 this.ProtectTbMenuItem.Checked = false;
8758                 this.DeleteTabMenuItem.Enabled = true;
8759                 this.DeleteTbMenuItem.Enabled = true;
8760             }
8761         }
8762
8763         private void ProtectTabMenuItem_Click(object sender, EventArgs e)
8764         {
8765             var checkState = ((ToolStripMenuItem)sender).Checked;
8766
8767             // チェック状態を同期
8768             this.ProtectTbMenuItem.Checked = checkState;
8769             this.ProtectTabMenuItem.Checked = checkState;
8770
8771             // ロック中はタブの削除を無効化
8772             this.DeleteTabMenuItem.Enabled = !checkState;
8773             this.DeleteTbMenuItem.Enabled = !checkState;
8774
8775             if (string.IsNullOrEmpty(_rclickTabName)) return;
8776             _statuses.Tabs[_rclickTabName].Protected = checkState;
8777
8778             SaveConfigsTabs();
8779         }
8780
8781         private void UreadManageMenuItem_Click(object sender, EventArgs e)
8782         {
8783             UreadManageMenuItem.Checked = ((ToolStripMenuItem)sender).Checked;
8784             this.UnreadMngTbMenuItem.Checked = UreadManageMenuItem.Checked;
8785
8786             if (string.IsNullOrEmpty(_rclickTabName)) return;
8787             ChangeTabUnreadManage(_rclickTabName, UreadManageMenuItem.Checked);
8788
8789             SaveConfigsTabs();
8790         }
8791
8792         public void ChangeTabUnreadManage(string tabName, bool isManage)
8793         {
8794             int idx;
8795             for (idx = 0; idx < ListTab.TabCount; idx++)
8796             {
8797                 if (ListTab.TabPages[idx].Text == tabName) break;
8798             }
8799
8800             _statuses.SetTabUnreadManage(tabName, isManage);
8801             if (SettingDialog.TabIconDisp)
8802             {
8803                 if (_statuses.Tabs[tabName].UnreadCount > 0)
8804                     ListTab.TabPages[idx].ImageIndex = 0;
8805                 else
8806                     ListTab.TabPages[idx].ImageIndex = -1;
8807             }
8808
8809             if (_curTab.Text == tabName)
8810             {
8811                 this.PurgeListViewItemCache();
8812                 _curList.Refresh();
8813             }
8814
8815             SetMainWindowTitle();
8816             SetStatusLabelUrl();
8817             if (!SettingDialog.TabIconDisp) ListTab.Refresh();
8818         }
8819
8820         private void NotifyDispMenuItem_Click(object sender, EventArgs e)
8821         {
8822             NotifyDispMenuItem.Checked = ((ToolStripMenuItem)sender).Checked;
8823             this.NotifyTbMenuItem.Checked = NotifyDispMenuItem.Checked;
8824
8825             if (string.IsNullOrEmpty(_rclickTabName)) return;
8826
8827             _statuses.Tabs[_rclickTabName].Notify = NotifyDispMenuItem.Checked;
8828
8829             SaveConfigsTabs();
8830         }
8831
8832         private void SoundFileComboBox_SelectedIndexChanged(object sender, EventArgs e)
8833         {
8834             if (soundfileListup || string.IsNullOrEmpty(_rclickTabName)) return;
8835
8836             _statuses.Tabs[_rclickTabName].SoundFile = (string)((ToolStripComboBox)sender).SelectedItem;
8837
8838             SaveConfigsTabs();
8839         }
8840
8841         private void DeleteTabMenuItem_Click(object sender, EventArgs e)
8842         {
8843             if (string.IsNullOrEmpty(_rclickTabName) || sender == this.DeleteTbMenuItem) _rclickTabName = ListTab.SelectedTab.Text;
8844
8845             RemoveSpecifiedTab(_rclickTabName, true);
8846             SaveConfigsTabs();
8847         }
8848
8849         private void FilterEditMenuItem_Click(object sender, EventArgs e)
8850         {
8851             if (string.IsNullOrEmpty(_rclickTabName)) _rclickTabName = _statuses.GetTabByType(MyCommon.TabUsageType.Home).TabName;
8852             fltDialog.SetCurrent(_rclickTabName);
8853             fltDialog.ShowDialog(this);
8854             this.TopMost = SettingDialog.AlwaysTop;
8855
8856             this.ApplyPostFilters();
8857             SaveConfigsTabs();
8858         }
8859
8860         private void AddTabMenuItem_Click(object sender, EventArgs e)
8861         {
8862             string tabName = null;
8863             MyCommon.TabUsageType tabUsage;
8864             using (InputTabName inputName = new InputTabName())
8865             {
8866                 inputName.TabName = _statuses.GetUniqueTabName();
8867                 inputName.IsShowUsage = true;
8868                 inputName.ShowDialog();
8869                 if (inputName.DialogResult == DialogResult.Cancel) return;
8870                 tabName = inputName.TabName;
8871                 tabUsage = inputName.Usage;
8872             }
8873             this.TopMost = SettingDialog.AlwaysTop;
8874             if (!string.IsNullOrEmpty(tabName))
8875             {
8876                 //List対応
8877                 ListElement list = null;
8878                 if (tabUsage == MyCommon.TabUsageType.Lists)
8879                 {
8880                     using (ListAvailable listAvail = new ListAvailable())
8881                     {
8882                         if (listAvail.ShowDialog(this) == DialogResult.Cancel) return;
8883                         if (listAvail.SelectedList == null) return;
8884                         list = listAvail.SelectedList;
8885                     }
8886                 }
8887                 if (!_statuses.AddTab(tabName, tabUsage, list) || !AddNewTab(tabName, false, tabUsage, list))
8888                 {
8889                     string tmp = string.Format(Properties.Resources.AddTabMenuItem_ClickText1, tabName);
8890                     MessageBox.Show(tmp, Properties.Resources.AddTabMenuItem_ClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
8891                 }
8892                 else
8893                 {
8894                     //成功
8895                     SaveConfigsTabs();
8896                     if (tabUsage == MyCommon.TabUsageType.PublicSearch)
8897                     {
8898                         ListTab.SelectedIndex = ListTab.TabPages.Count - 1;
8899                         ListTabSelect(ListTab.TabPages[ListTab.TabPages.Count - 1]);
8900                         ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"].Focus();
8901                     }
8902                     if (tabUsage == MyCommon.TabUsageType.Lists)
8903                     {
8904                         ListTab.SelectedIndex = ListTab.TabPages.Count - 1;
8905                         ListTabSelect(ListTab.TabPages[ListTab.TabPages.Count - 1]);
8906                         GetTimeline(MyCommon.WORKERTYPE.List, 1, 0, tabName);
8907                     }
8908                 }
8909             }
8910         }
8911
8912         private void TabMenuItem_Click(object sender, EventArgs e)
8913         {
8914             //選択発言を元にフィルタ追加
8915             foreach (int idx in _curList.SelectedIndices)
8916             {
8917                 string tabName;
8918                 //タブ選択(or追加)
8919                 if (!SelectTab(out tabName)) return;
8920
8921                 fltDialog.SetCurrent(tabName);
8922                 if (_statuses[_curTab.Text, idx].RetweetedId == null)
8923                 {
8924                     fltDialog.AddNewFilter(_statuses[_curTab.Text, idx].ScreenName, _statuses[_curTab.Text, idx].TextFromApi);
8925                 }
8926                 else
8927                 {
8928                     fltDialog.AddNewFilter(_statuses[_curTab.Text, idx].RetweetedBy, _statuses[_curTab.Text, idx].TextFromApi);
8929                 }
8930                 fltDialog.ShowDialog(this);
8931                 this.TopMost = SettingDialog.AlwaysTop;
8932             }
8933
8934             this.ApplyPostFilters();
8935             SaveConfigsTabs();
8936             if (this.ListTab.SelectedTab != null &&
8937                 ((DetailsListView)this.ListTab.SelectedTab.Tag).SelectedIndices.Count > 0)
8938             {
8939                 _curPost = _statuses[this.ListTab.SelectedTab.Text, ((DetailsListView)this.ListTab.SelectedTab.Tag).SelectedIndices[0]];
8940             }
8941         }
8942
8943         protected override bool ProcessDialogKey(Keys keyData)
8944         {
8945             //TextBox1でEnterを押してもビープ音が鳴らないようにする
8946             if ((keyData & Keys.KeyCode) == Keys.Enter)
8947             {
8948                 if (StatusText.Focused)
8949                 {
8950                     bool _NewLine = false;
8951                     bool _Post = false;
8952
8953                     if (SettingDialog.PostCtrlEnter) //Ctrl+Enter投稿時
8954                     {
8955                         if (StatusText.Multiline)
8956                         {
8957                             if ((keyData & Keys.Shift) == Keys.Shift && (keyData & Keys.Control) != Keys.Control) _NewLine = true;
8958
8959                             if ((keyData & Keys.Control) == Keys.Control) _Post = true;
8960                         }
8961                         else
8962                         {
8963                             if (((keyData & Keys.Control) == Keys.Control)) _Post = true;
8964                         }
8965
8966                     }
8967                     else if (SettingDialog.PostShiftEnter) //SHift+Enter投稿時
8968                     {
8969                         if (StatusText.Multiline)
8970                         {
8971                             if ((keyData & Keys.Control) == Keys.Control && (keyData & Keys.Shift) != Keys.Shift) _NewLine = true;
8972
8973                             if ((keyData & Keys.Shift) == Keys.Shift) _Post = true;
8974                         }
8975                         else
8976                         {
8977                             if (((keyData & Keys.Shift) == Keys.Shift)) _Post = true;
8978                         }
8979
8980                     }
8981                     else //Enter投稿時
8982                     {
8983                         if (StatusText.Multiline)
8984                         {
8985                             if ((keyData & Keys.Shift) == Keys.Shift && (keyData & Keys.Control) != Keys.Control) _NewLine = true;
8986
8987                             if (((keyData & Keys.Control) != Keys.Control && (keyData & Keys.Shift) != Keys.Shift) ||
8988                                 ((keyData & Keys.Control) == Keys.Control && (keyData & Keys.Shift) == Keys.Shift)) _Post = true;
8989                         }
8990                         else
8991                         {
8992                             if (((keyData & Keys.Shift) == Keys.Shift) ||
8993                                 (((keyData & Keys.Control) != Keys.Control) &&
8994                                 ((keyData & Keys.Shift) != Keys.Shift))) _Post = true;
8995                         }
8996                     }
8997
8998                     if (_NewLine)
8999                     {
9000                         int pos1 = StatusText.SelectionStart;
9001                         if (StatusText.SelectionLength > 0)
9002                         {
9003                             StatusText.Text = StatusText.Text.Remove(pos1, StatusText.SelectionLength);  //選択状態文字列削除
9004                         }
9005                         StatusText.Text = StatusText.Text.Insert(pos1, Environment.NewLine);  //改行挿入
9006                         StatusText.SelectionStart = pos1 + Environment.NewLine.Length;    //カーソルを改行の次の文字へ移動
9007                         return true;
9008                     }
9009                     else if (_Post)
9010                     {
9011                         PostButton_Click(null, null);
9012                         return true;
9013                     }
9014                 }
9015                 else if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.PublicSearch &&
9016                          (ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"].Focused ||
9017                          ListTab.SelectedTab.Controls["panelSearch"].Controls["comboLang"].Focused))
9018                 {
9019                     this.SearchButton_Click(ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"], null);
9020                     return true;
9021                 }
9022             }
9023
9024             return base.ProcessDialogKey(keyData);
9025         }
9026
9027         private void ReplyAllStripMenuItem_Click(object sender, EventArgs e)
9028         {
9029             MakeReplyOrDirectStatus(false, true, true);
9030         }
9031
9032         private void IDRuleMenuItem_Click(object sender, EventArgs e)
9033         {
9034             string tabName;
9035
9036             //未選択なら処理終了
9037             if (_curList.SelectedIndices.Count == 0) return;
9038
9039             //タブ選択(or追加)
9040             if (!SelectTab(out tabName)) return;
9041
9042             bool mv = false;
9043             bool mk = false;
9044             MoveOrCopy(ref mv, ref mk);
9045
9046             List<string> ids = new List<string>();
9047             foreach (int idx in _curList.SelectedIndices)
9048             {
9049                 PostClass post = _statuses[_curTab.Text, idx];
9050                 if (!ids.Contains(post.ScreenName))
9051                 {
9052                     PostFilterRule fc = new PostFilterRule();
9053                     ids.Add(post.ScreenName);
9054                     if (post.RetweetedId == null)
9055                     {
9056                         fc.FilterName = post.ScreenName;
9057                     }
9058                     else
9059                     {
9060                         fc.FilterName = post.RetweetedBy;
9061                     }
9062                     fc.UseNameField = true;
9063                     fc.MoveMatches = mv;
9064                     fc.MarkMatches = mk;
9065                     fc.UseRegex = false;
9066                     fc.FilterByUrl = false;
9067                     _statuses.Tabs[tabName].AddFilter(fc);
9068                 }
9069             }
9070             if (ids.Count != 0)
9071             {
9072                 List<string> atids = new List<string>();
9073                 foreach (string id in ids)
9074                 {
9075                     atids.Add("@" + id);
9076                 }
9077                 int cnt = AtIdSupl.ItemCount;
9078                 AtIdSupl.AddRangeItem(atids.ToArray());
9079                 if (AtIdSupl.ItemCount != cnt) _modifySettingAtId = true;
9080             }
9081
9082             this.ApplyPostFilters();
9083             SaveConfigsTabs();
9084         }
9085
9086         private bool SelectTab(out string tabName)
9087         {
9088             do
9089             {
9090                 tabName = null;
9091
9092                 //振り分け先タブ選択
9093                 using (var dialog = new TabsDialog(_statuses))
9094                 {
9095                     if (dialog.ShowDialog(this) == DialogResult.Cancel) return false;
9096
9097                     var selectedTab = dialog.SelectedTab;
9098                     tabName = selectedTab == null ? null : selectedTab.TabName;
9099                 }
9100
9101                 ListTab.SelectedTab.Focus();
9102                 //新規タブを選択→タブ作成
9103                 if (tabName == null)
9104                 {
9105                     using (InputTabName inputName = new InputTabName())
9106                     {
9107                         inputName.TabName = _statuses.GetUniqueTabName();
9108                         inputName.ShowDialog();
9109                         if (inputName.DialogResult == DialogResult.Cancel) return false;
9110                         tabName = inputName.TabName;
9111                     }
9112                     this.TopMost = SettingDialog.AlwaysTop;
9113                     if (!string.IsNullOrEmpty(tabName))
9114                     {
9115                         if (!_statuses.AddTab(tabName, MyCommon.TabUsageType.UserDefined, null) || !AddNewTab(tabName, false, MyCommon.TabUsageType.UserDefined))
9116                         {
9117                             string tmp = string.Format(Properties.Resources.IDRuleMenuItem_ClickText2, tabName);
9118                             MessageBox.Show(tmp, Properties.Resources.IDRuleMenuItem_ClickText3, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
9119                             //もう一度タブ名入力
9120                         }
9121                         else
9122                         {
9123                             return true;
9124                         }
9125                     }
9126                 }
9127                 else
9128                 {
9129                     //既存タブを選択
9130                     return true;
9131                 }
9132             }
9133             while (true);
9134         }
9135
9136         private void MoveOrCopy(ref bool move, ref bool mark)
9137         {
9138             {
9139                 //移動するか?
9140                 string _tmp = string.Format(Properties.Resources.IDRuleMenuItem_ClickText4, Environment.NewLine);
9141                 if (MessageBox.Show(_tmp, Properties.Resources.IDRuleMenuItem_ClickText5, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
9142                     move = false;
9143                 else
9144                     move = true;
9145             }
9146             if (!move)
9147             {
9148                 //マークするか?
9149                 string _tmp = string.Format(Properties.Resources.IDRuleMenuItem_ClickText6, Environment.NewLine);
9150                 if (MessageBox.Show(_tmp, Properties.Resources.IDRuleMenuItem_ClickText7, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
9151                     mark = true;
9152                 else
9153                     mark = false;
9154             }
9155         }
9156         private void CopySTOTMenuItem_Click(object sender, EventArgs e)
9157         {
9158             this.CopyStot();
9159         }
9160
9161         private void CopyURLMenuItem_Click(object sender, EventArgs e)
9162         {
9163             this.CopyIdUri();
9164         }
9165
9166         private void SelectAllMenuItem_Click(object sender, EventArgs e)
9167         {
9168             if (StatusText.Focused)
9169             {
9170                 // 発言欄でのCtrl+A
9171                 StatusText.SelectAll();
9172             }
9173             else
9174             {
9175                 // ListView上でのCtrl+A
9176                 for (int i = 0; i < _curList.VirtualListSize; i++)
9177                 {
9178                     _curList.SelectedIndices.Add(i);
9179                 }
9180             }
9181         }
9182
9183         private void MoveMiddle()
9184         {
9185             ListViewItem _item;
9186             int idx1;
9187             int idx2;
9188
9189             if (_curList.SelectedIndices.Count == 0) return;
9190
9191             int idx = _curList.SelectedIndices[0];
9192
9193             _item = _curList.GetItemAt(0, 25);
9194             if (_item == null)
9195                 idx1 = 0;
9196             else
9197                 idx1 = _item.Index;
9198
9199             _item = _curList.GetItemAt(0, _curList.ClientSize.Height - 1);
9200             if (_item == null)
9201                 idx2 = _curList.VirtualListSize - 1;
9202             else
9203                 idx2 = _item.Index;
9204
9205             idx -= Math.Abs(idx1 - idx2) / 2;
9206             if (idx < 0) idx = 0;
9207
9208             _curList.EnsureVisible(_curList.VirtualListSize - 1);
9209             _curList.EnsureVisible(idx);
9210         }
9211
9212         private void OpenURLMenuItem_Click(object sender, EventArgs e)
9213         {
9214             if (PostBrowser.Document.Links.Count > 0)
9215             {
9216                 UrlDialog.ClearUrl();
9217
9218                 string openUrlStr = "";
9219
9220                 if (PostBrowser.Document.Links.Count == 1)
9221                 {
9222                     string urlStr = "";
9223                     try
9224                     {
9225                         urlStr = MyCommon.IDNEncode(PostBrowser.Document.Links[0].GetAttribute("href"));
9226                     }
9227                     catch (ArgumentException)
9228                     {
9229                         //変なHTML?
9230                         return;
9231                     }
9232                     catch (Exception)
9233                     {
9234                         return;
9235                     }
9236                     if (string.IsNullOrEmpty(urlStr)) return;
9237                     openUrlStr = MyCommon.urlEncodeMultibyteChar(urlStr);
9238                 }
9239                 else
9240                 {
9241                     foreach (HtmlElement linkElm in PostBrowser.Document.Links)
9242                     {
9243                         string urlStr = "";
9244                         string linkText = "";
9245                         string href = "";
9246                         try
9247                         {
9248                             urlStr = linkElm.GetAttribute("title");
9249                             href = MyCommon.IDNEncode(linkElm.GetAttribute("href"));
9250                             if (string.IsNullOrEmpty(urlStr)) urlStr = href;
9251                             linkText = linkElm.InnerText;
9252                             if (!linkText.StartsWith("http") && !linkText.StartsWith("#") && !linkText.Contains("."))
9253                             {
9254                                 linkText = "@" + linkText;
9255                             }
9256                         }
9257                         catch (ArgumentException)
9258                         {
9259                             //変なHTML?
9260                             return;
9261                         }
9262                         catch (Exception)
9263                         {
9264                             return;
9265                         }
9266                         if (string.IsNullOrEmpty(urlStr)) continue;
9267                         UrlDialog.AddUrl(new OpenUrlItem(linkText, MyCommon.urlEncodeMultibyteChar(urlStr), href));
9268                     }
9269                     try
9270                     {
9271                         if (UrlDialog.ShowDialog() == DialogResult.OK)
9272                         {
9273                             openUrlStr = UrlDialog.SelectedUrl;
9274                         }
9275                     }
9276                     catch (Exception)
9277                     {
9278                         return;
9279                     }
9280                     this.TopMost = SettingDialog.AlwaysTop;
9281                 }
9282                 if (string.IsNullOrEmpty(openUrlStr)) return;
9283
9284                 if (openUrlStr.StartsWith("http://twitter.com/search?q=") ||
9285                     openUrlStr.StartsWith("https://twitter.com/search?q="))
9286                 {
9287                     //ハッシュタグの場合は、タブで開く
9288                     string urlStr = Uri.UnescapeDataString(openUrlStr);
9289                     string hash = urlStr.Substring(urlStr.IndexOf("#"));
9290                     HashSupl.AddItem(hash);
9291                     HashMgr.AddHashToHistory(hash.Trim(), false);
9292                     AddNewTabForSearch(hash);
9293                     return;
9294                 }
9295                 else
9296                 {
9297                     Match m = Regex.Match(openUrlStr, "^https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)$");
9298                     if (SettingDialog.OpenUserTimeline && m.Success && IsTwitterId(m.Result("${ScreenName}")))
9299                         this.AddNewTabForUserTimeline(m.Result("${ScreenName}"));
9300                     else
9301                         OpenUriAsync(openUrlStr);
9302                     return;
9303                 }
9304             }
9305         }
9306
9307         private void ClearTabMenuItem_Click(object sender, EventArgs e)
9308         {
9309             if (string.IsNullOrEmpty(_rclickTabName)) return;
9310             ClearTab(_rclickTabName, true);
9311         }
9312
9313         private void ClearTab(string tabName, bool showWarning)
9314         {
9315             if (showWarning)
9316             {
9317                 string tmp = string.Format(Properties.Resources.ClearTabMenuItem_ClickText1, Environment.NewLine);
9318                 if (MessageBox.Show(tmp, tabName + " " + Properties.Resources.ClearTabMenuItem_ClickText2, MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
9319                 {
9320                     return;
9321                 }
9322             }
9323
9324             _statuses.ClearTabIds(tabName);
9325             if (ListTab.SelectedTab.Text == tabName)
9326             {
9327                 _anchorPost = null;
9328                 _anchorFlag = false;
9329                 this.PurgeListViewItemCache();
9330                 _curItemIndex = -1;
9331                 _curPost = null;
9332             }
9333             foreach (TabPage tb in ListTab.TabPages)
9334             {
9335                 if (tb.Text == tabName)
9336                 {
9337                     tb.ImageIndex = -1;
9338                     ((DetailsListView)tb.Tag).VirtualListSize = 0;
9339                     break;
9340                 }
9341             }
9342             if (!SettingDialog.TabIconDisp) ListTab.Refresh();
9343
9344             SetMainWindowTitle();
9345             SetStatusLabelUrl();
9346         }
9347
9348         private static long followers = 0;
9349
9350         private void SetMainWindowTitle()
9351         {
9352             //メインウインドウタイトルの書き換え
9353             StringBuilder ttl = new StringBuilder(256);
9354             int ur = 0;
9355             int al = 0;
9356             if (SettingDialog.DispLatestPost != MyCommon.DispTitleEnum.None &&
9357                 SettingDialog.DispLatestPost != MyCommon.DispTitleEnum.Post &&
9358                 SettingDialog.DispLatestPost != MyCommon.DispTitleEnum.Ver &&
9359                 SettingDialog.DispLatestPost != MyCommon.DispTitleEnum.OwnStatus)
9360             {
9361                 foreach (var tab in _statuses.Tabs.Values)
9362                 {
9363                     ur += tab.UnreadCount;
9364                     al += tab.AllCount;
9365                 }
9366             }
9367
9368             if (SettingDialog.DispUsername) ttl.Append(tw.Username).Append(" - ");
9369             ttl.Append(Application.ProductName);
9370             ttl.Append("  ");
9371             switch (SettingDialog.DispLatestPost)
9372             {
9373                 case MyCommon.DispTitleEnum.Ver:
9374                     ttl.Append("Ver:").Append(MyCommon.GetReadableVersion());
9375                     break;
9376                 case MyCommon.DispTitleEnum.Post:
9377                     if (_history != null && _history.Count > 1)
9378                         ttl.Append(_history[_history.Count - 2].status.Replace("\r\n", " "));
9379                     break;
9380                 case MyCommon.DispTitleEnum.UnreadRepCount:
9381                     ttl.AppendFormat(Properties.Resources.SetMainWindowTitleText1, _statuses.GetTabByType(MyCommon.TabUsageType.Mentions).UnreadCount + _statuses.GetTabByType(MyCommon.TabUsageType.DirectMessage).UnreadCount);
9382                     break;
9383                 case MyCommon.DispTitleEnum.UnreadAllCount:
9384                     ttl.AppendFormat(Properties.Resources.SetMainWindowTitleText2, ur);
9385                     break;
9386                 case MyCommon.DispTitleEnum.UnreadAllRepCount:
9387                     ttl.AppendFormat(Properties.Resources.SetMainWindowTitleText3, ur, _statuses.GetTabByType(MyCommon.TabUsageType.Mentions).UnreadCount + _statuses.GetTabByType(MyCommon.TabUsageType.DirectMessage).UnreadCount);
9388                     break;
9389                 case MyCommon.DispTitleEnum.UnreadCountAllCount:
9390                     ttl.AppendFormat(Properties.Resources.SetMainWindowTitleText4, ur, al);
9391                     break;
9392                 case MyCommon.DispTitleEnum.OwnStatus:
9393                     if (followers == 0 && tw.FollowersCount > 0) followers = tw.FollowersCount;
9394                     ttl.AppendFormat(Properties.Resources.OwnStatusTitle, tw.StatusesCount, tw.FriendsCount, tw.FollowersCount, tw.FollowersCount - followers);
9395                     break;
9396             }
9397
9398             try
9399             {
9400                 this.Text = ttl.ToString();
9401             }
9402             catch (AccessViolationException)
9403             {
9404                 //原因不明。ポスト内容に依存か?たまーに発生するが再現せず。
9405             }
9406         }
9407
9408         private string GetStatusLabelText()
9409         {
9410             //ステータス欄にカウント表示
9411             //タブ未読数/タブ発言数 全未読数/総発言数 (未読@+未読DM数)
9412             if (_statuses == null) return "";
9413             TabClass tbRep = _statuses.GetTabByType(MyCommon.TabUsageType.Mentions);
9414             TabClass tbDm = _statuses.GetTabByType(MyCommon.TabUsageType.DirectMessage);
9415             if (tbRep == null || tbDm == null) return "";
9416             int urat = tbRep.UnreadCount + tbDm.UnreadCount;
9417             int ur = 0;
9418             int al = 0;
9419             int tur = 0;
9420             int tal = 0;
9421             StringBuilder slbl = new StringBuilder(256);
9422             try
9423             {
9424                 foreach (var tab in _statuses.Tabs.Values)
9425                 {
9426                     ur += tab.UnreadCount;
9427                     al += tab.AllCount;
9428                     if (_curTab != null && tab.TabName.Equals(_curTab.Text))
9429                     {
9430                         tur = tab.UnreadCount;
9431                         tal = tab.AllCount;
9432                     }
9433                 }
9434             }
9435             catch (Exception)
9436             {
9437                 return "";
9438             }
9439
9440             UnreadCounter = ur;
9441             UnreadAtCounter = urat;
9442
9443             slbl.AppendFormat(Properties.Resources.SetStatusLabelText1, tur, tal, ur, al, urat, _postTimestamps.Count, _favTimestamps.Count, _tlCount);
9444             if (SettingDialog.TimelinePeriodInt == 0)
9445             {
9446                 slbl.Append(Properties.Resources.SetStatusLabelText2);
9447             }
9448             else
9449             {
9450                 slbl.Append(SettingDialog.TimelinePeriodInt.ToString() + Properties.Resources.SetStatusLabelText3);
9451             }
9452             return slbl.ToString();
9453         }
9454
9455         private void TwitterApiStatus_AccessLimitUpdated(object sender, EventArgs e)
9456         {
9457             try
9458             {
9459                 if (this.InvokeRequired && !this.IsDisposed)
9460                 {
9461                     this.Invoke((MethodInvoker)(() => this.TwitterApiStatus_AccessLimitUpdated(sender, e)));
9462                 }
9463                 else
9464                 {
9465                     var endpointName = (e as TwitterApiStatus.AccessLimitUpdatedEventArgs).EndpointName;
9466                     if (endpointName == "/statuses/home_timeline" || endpointName == null)
9467                     {
9468                         this._apiGauge.ApiLimit = MyCommon.TwitterApiInfo.AccessLimit["/statuses/home_timeline"];
9469                     }
9470                 }
9471             }
9472             catch (ObjectDisposedException)
9473             {
9474                 return;
9475             }
9476             catch (InvalidOperationException)
9477             {
9478                 return;
9479             }
9480         }
9481
9482         private void SetStatusLabelUrl()
9483         {
9484             StatusLabelUrl.Text = GetStatusLabelText();
9485         }
9486
9487         public void SetStatusLabel(string text)
9488         {
9489             StatusLabel.Text = text;
9490         }
9491
9492         private static StringBuilder ur = new StringBuilder(64);
9493
9494         private void SetNotifyIconText()
9495         {
9496             // タスクトレイアイコンのツールチップテキスト書き換え
9497             // Tween [未読/@]
9498             ur.Remove(0, ur.Length);
9499             if (SettingDialog.DispUsername)
9500             {
9501                 ur.Append(tw.Username);
9502                 ur.Append(" - ");
9503             }
9504             ur.Append(Application.ProductName);
9505 #if DEBUG
9506             ur.Append("(Debug Build)");
9507 #endif
9508             if (UnreadCounter != -1 && UnreadAtCounter != -1)
9509             {
9510                 ur.Append(" [");
9511                 ur.Append(UnreadCounter);
9512                 ur.Append("/@");
9513                 ur.Append(UnreadAtCounter);
9514                 ur.Append("]");
9515             }
9516             NotifyIcon1.Text = ur.ToString();
9517         }
9518
9519         internal void CheckReplyTo(string StatusText)
9520         {
9521             MatchCollection m;
9522             //ハッシュタグの保存
9523             m = Regex.Matches(StatusText, Twitter.HASHTAG, RegexOptions.IgnoreCase);
9524             string hstr = "";
9525             foreach (Match hm in m)
9526             {
9527                 if (!hstr.Contains("#" + hm.Result("$3") + " "))
9528                 {
9529                     hstr += "#" + hm.Result("$3") + " ";
9530                     HashSupl.AddItem("#" + hm.Result("$3"));
9531                 }
9532             }
9533             if (!string.IsNullOrEmpty(HashMgr.UseHash) && !hstr.Contains(HashMgr.UseHash + " "))
9534             {
9535                 hstr += HashMgr.UseHash;
9536             }
9537             if (!string.IsNullOrEmpty(hstr)) HashMgr.AddHashToHistory(hstr.Trim(), false);
9538
9539             // 本当にリプライ先指定すべきかどうかの判定
9540             m = Regex.Matches(StatusText, "(^|[ -/:-@[-^`{-~])(?<id>@[a-zA-Z0-9_]+)");
9541
9542             if (SettingDialog.UseAtIdSupplement)
9543             {
9544                 int bCnt = AtIdSupl.ItemCount;
9545                 foreach (Match mid in m)
9546                 {
9547                     AtIdSupl.AddItem(mid.Result("${id}"));
9548                 }
9549                 if (bCnt != AtIdSupl.ItemCount) _modifySettingAtId = true;
9550             }
9551
9552             // リプライ先ステータスIDの指定がない場合は指定しない
9553             if (_reply_to_id == null) return;
9554
9555             // リプライ先ユーザー名がない場合も指定しない
9556             if (string.IsNullOrEmpty(_reply_to_name))
9557             {
9558                 _reply_to_id = null;
9559                 return;
9560             }
9561
9562             // 通常Reply
9563             // 次の条件を満たす場合に in_reply_to_status_id 指定
9564             // 1. Twitterによりリンクと判定される @idが文中に1つ含まれる (2009/5/28 リンク化される@IDのみカウントするように修正)
9565             // 2. リプライ先ステータスIDが設定されている(リストをダブルクリックで返信している)
9566             // 3. 文中に含まれた@idがリプライ先のポスト者のIDと一致する
9567
9568             if (m != null)
9569             {
9570                 if (StatusText.StartsWith("@"))
9571                 {
9572                     if (StatusText.StartsWith("@" + _reply_to_name)) return;
9573                 }
9574                 else
9575                 {
9576                     foreach (Match mid in m)
9577                     {
9578                         if (StatusText.Contains("QT " + mid.Result("${id}") + ":") && mid.Result("${id}") == "@" + _reply_to_name) return;
9579                     }
9580                 }
9581             }
9582
9583             _reply_to_id = null;
9584             _reply_to_name = null;
9585
9586         }
9587
9588         private void TweenMain_Resize(object sender, EventArgs e)
9589         {
9590             if (!_initialLayout && SettingDialog.MinimizeToTray && WindowState == FormWindowState.Minimized)
9591             {
9592                 this.Visible = false;
9593             }
9594             if (_initialLayout && _cfgLocal != null && this.WindowState == FormWindowState.Normal && this.Visible)
9595             {
9596                 this.ClientSize = _cfgLocal.FormSize;
9597                 //_mySize = this.ClientSize;                     //サイズ保持(最小化・最大化されたまま終了した場合の対応用)
9598                 this.DesktopLocation = _cfgLocal.FormLocation;
9599                 //_myLoc = this.DesktopLocation;                        //位置保持(最小化・最大化されたまま終了した場合の対応用)
9600                 if (_cfgLocal.SplitterDistance > this.SplitContainer1.Panel1MinSize &&
9601                     _cfgLocal.SplitterDistance < this.SplitContainer1.Height - this.SplitContainer1.Panel2MinSize - this.SplitContainer1.SplitterWidth)
9602                 {
9603                     this.SplitContainer1.SplitterDistance = _cfgLocal.SplitterDistance; //Splitterの位置設定
9604                 }
9605                 //発言欄複数行
9606                 StatusText.Multiline = _cfgLocal.StatusMultiline;
9607                 if (StatusText.Multiline)
9608                 {
9609                     int dis = SplitContainer2.Height - _cfgLocal.StatusTextHeight - SplitContainer2.SplitterWidth;
9610                     if (dis > SplitContainer2.Panel1MinSize && dis < SplitContainer2.Height - SplitContainer2.Panel2MinSize - SplitContainer2.SplitterWidth)
9611                     {
9612                         SplitContainer2.SplitterDistance = SplitContainer2.Height - _cfgLocal.StatusTextHeight - SplitContainer2.SplitterWidth;
9613                     }
9614                     StatusText.Height = _cfgLocal.StatusTextHeight;
9615                 }
9616                 else
9617                 {
9618                     if (SplitContainer2.Height - SplitContainer2.Panel2MinSize - SplitContainer2.SplitterWidth > 0)
9619                     {
9620                         SplitContainer2.SplitterDistance = SplitContainer2.Height - SplitContainer2.Panel2MinSize - SplitContainer2.SplitterWidth;
9621                     }
9622                 }
9623                 if (_cfgLocal.PreviewDistance > this.SplitContainer3.Panel1MinSize && _cfgLocal.PreviewDistance < this.SplitContainer3.Width - this.SplitContainer3.Panel2MinSize - this.SplitContainer3.SplitterWidth)
9624                 {
9625                     this.SplitContainer3.SplitterDistance = _cfgLocal.PreviewDistance;
9626                 }
9627                 _initialLayout = false;
9628             }
9629             if (this.WindowState != FormWindowState.Minimized)
9630             {
9631                 _formWindowState = this.WindowState;
9632             }
9633         }
9634
9635         private void PlaySoundMenuItem_CheckedChanged(object sender, EventArgs e)
9636         {
9637             PlaySoundMenuItem.Checked = ((ToolStripMenuItem)sender).Checked;
9638             this.PlaySoundFileMenuItem.Checked = PlaySoundMenuItem.Checked;
9639             if (PlaySoundMenuItem.Checked)
9640             {
9641                 SettingDialog.PlaySound = true;
9642             }
9643             else
9644             {
9645                 SettingDialog.PlaySound = false;
9646             }
9647             _modifySettingCommon = true;
9648         }
9649
9650         private void SplitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
9651         {
9652             if (this.WindowState == FormWindowState.Normal && !_initialLayout)
9653             {
9654                 _mySpDis = SplitContainer1.SplitterDistance;
9655                 if (StatusText.Multiline) _mySpDis2 = StatusText.Height;
9656                 _modifySettingLocal = true;
9657             }
9658         }
9659
9660         private void doRepliedStatusOpen()
9661         {
9662             if (this.ExistCurrentPost && _curPost.InReplyToUser != null && _curPost.InReplyToStatusId != null)
9663             {
9664                 if (MyCommon.IsKeyDown(Keys.Shift))
9665                 {
9666                     OpenUriAsync(MyCommon.GetStatusUrl(_curPost.InReplyToUser, _curPost.InReplyToStatusId.Value));
9667                     return;
9668                 }
9669                 if (_statuses.ContainsKey(_curPost.InReplyToStatusId.Value))
9670                 {
9671                     PostClass repPost = _statuses[_curPost.InReplyToStatusId.Value];
9672                     MessageBox.Show(repPost.ScreenName + " / " + repPost.Nickname + "   (" + repPost.CreatedAt.ToString() + ")" + Environment.NewLine + repPost.TextFromApi);
9673                 }
9674                 else
9675                 {
9676                     foreach (TabClass tb in _statuses.GetTabsByType(MyCommon.TabUsageType.Lists | MyCommon.TabUsageType.PublicSearch))
9677                     {
9678                         if (tb == null || !tb.Contains(_curPost.InReplyToStatusId.Value)) break;
9679                         PostClass repPost = _statuses[_curPost.InReplyToStatusId.Value];
9680                         MessageBox.Show(repPost.ScreenName + " / " + repPost.Nickname + "   (" + repPost.CreatedAt.ToString() + ")" + Environment.NewLine + repPost.TextFromApi);
9681                         return;
9682                     }
9683                     OpenUriAsync(MyCommon.GetStatusUrl(_curPost.InReplyToUser, _curPost.InReplyToStatusId.Value));
9684                 }
9685             }
9686         }
9687
9688         private void RepliedStatusOpenMenuItem_Click(object sender, EventArgs e)
9689         {
9690             doRepliedStatusOpen();
9691         }
9692
9693         /// <summary>
9694         /// UserPicture.Image に設定されている画像を破棄します。
9695         /// </summary>
9696         private void ClearUserPicture()
9697         {
9698             if (this.UserPicture.Image != null)
9699             {
9700                 var oldImage = this.UserPicture.Image;
9701                 this.UserPicture.Image = null;
9702                 oldImage.Dispose();
9703             }
9704         }
9705
9706         private void ContextMenuUserPicture_Opening(object sender, CancelEventArgs e)
9707         {
9708             //発言詳細のアイコン右クリック時のメニュー制御
9709             if (_curList.SelectedIndices.Count > 0 && _curPost != null)
9710             {
9711                 string name = _curPost.ImageUrl;
9712                 if (name != null && name.Length > 0)
9713                 {
9714                     int idx = name.LastIndexOf('/');
9715                     if (idx != -1)
9716                     {
9717                         name = Path.GetFileName(name.Substring(idx));
9718                         if (name.Contains("_normal.") || name.EndsWith("_normal"))
9719                         {
9720                             name = name.Replace("_normal", "");
9721                             this.IconNameToolStripMenuItem.Text = name;
9722                             this.IconNameToolStripMenuItem.Enabled = true;
9723                         }
9724                         else
9725                         {
9726                             this.IconNameToolStripMenuItem.Enabled = false;
9727                             this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText1;
9728                         }
9729                     }
9730                     else
9731                     {
9732                         this.IconNameToolStripMenuItem.Enabled = false;
9733                         this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText1;
9734                     }
9735
9736                     this.ReloadIconToolStripMenuItem.Enabled = true;
9737
9738                     if (this.IconCache.TryGetFromCache(_curPost.ImageUrl) != null)
9739                     {
9740                         this.SaveIconPictureToolStripMenuItem.Enabled = true;
9741                     }
9742                     else
9743                     {
9744                         this.SaveIconPictureToolStripMenuItem.Enabled = false;
9745                     }
9746                 }
9747                 else
9748                 {
9749                     this.IconNameToolStripMenuItem.Enabled = false;
9750                     this.ReloadIconToolStripMenuItem.Enabled = false;
9751                     this.SaveIconPictureToolStripMenuItem.Enabled = false;
9752                     this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText1;
9753                 }
9754             }
9755             else
9756             {
9757                 this.IconNameToolStripMenuItem.Enabled = false;
9758                 this.ReloadIconToolStripMenuItem.Enabled = false;
9759                 this.SaveIconPictureToolStripMenuItem.Enabled = false;
9760                 this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText2;
9761             }
9762             if (NameLabel.Tag != null)
9763             {
9764                 string id = (string)NameLabel.Tag;
9765                 if (id == tw.Username)
9766                 {
9767                     FollowToolStripMenuItem.Enabled = false;
9768                     UnFollowToolStripMenuItem.Enabled = false;
9769                     ShowFriendShipToolStripMenuItem.Enabled = false;
9770                     ShowUserStatusToolStripMenuItem.Enabled = true;
9771                     SearchPostsDetailNameToolStripMenuItem.Enabled = true;
9772                     SearchAtPostsDetailNameToolStripMenuItem.Enabled = false;
9773                     ListManageUserContextToolStripMenuItem3.Enabled = true;
9774                 }
9775                 else
9776                 {
9777                     FollowToolStripMenuItem.Enabled = true;
9778                     UnFollowToolStripMenuItem.Enabled = true;
9779                     ShowFriendShipToolStripMenuItem.Enabled = true;
9780                     ShowUserStatusToolStripMenuItem.Enabled = true;
9781                     SearchPostsDetailNameToolStripMenuItem.Enabled = true;
9782                     SearchAtPostsDetailNameToolStripMenuItem.Enabled = true;
9783                     ListManageUserContextToolStripMenuItem3.Enabled = true;
9784                 }
9785             }
9786             else
9787             {
9788                 FollowToolStripMenuItem.Enabled = false;
9789                 UnFollowToolStripMenuItem.Enabled = false;
9790                 ShowFriendShipToolStripMenuItem.Enabled = false;
9791                 ShowUserStatusToolStripMenuItem.Enabled = false;
9792                 SearchPostsDetailNameToolStripMenuItem.Enabled = false;
9793                 SearchAtPostsDetailNameToolStripMenuItem.Enabled = false;
9794                 ListManageUserContextToolStripMenuItem3.Enabled = false;
9795             }
9796         }
9797
9798         private void IconNameToolStripMenuItem_Click(object sender, EventArgs e)
9799         {
9800             if (_curPost == null) return;
9801             string name = _curPost.ImageUrl;
9802             OpenUriAsync(name.Remove(name.LastIndexOf("_normal"), 7)); // "_normal".Length
9803         }
9804
9805         private async void ReloadIconToolStripMenuItem_Click(object sender, EventArgs e)
9806         {
9807             if (this._curPost == null) return;
9808
9809             var imageUrl = this._curPost.ImageUrl;
9810             try
9811             {
9812                 var image = await this.IconCache.DownloadImageAsync(imageUrl, force: true);
9813
9814                 this.ClearUserPicture();
9815                 this.UserPicture.Image = image.Clone();
9816             }
9817             catch (Exception)
9818             {
9819                 this.UserPicture.ShowErrorImage();
9820                 try
9821                 {
9822                     throw;
9823                 }
9824                 catch (HttpRequestException) { }
9825                 catch (InvalidImageException) { }
9826                 catch (TaskCanceledException) { }
9827             }
9828         }
9829
9830         private void SaveOriginalSizeIconPictureToolStripMenuItem_Click(object sender, EventArgs e)
9831         {
9832             if (_curPost == null) return;
9833             string name = _curPost.ImageUrl;
9834             name = Path.GetFileNameWithoutExtension(name.Substring(name.LastIndexOf('/')));
9835
9836             this.SaveFileDialog1.FileName = name.Substring(0, name.Length - 8); // "_normal".Length + 1
9837
9838             if (this.SaveFileDialog1.ShowDialog() == DialogResult.OK)
9839             {
9840                 // STUB
9841             }
9842         }
9843
9844         private void SaveIconPictureToolStripMenuItem_Click(object sender, EventArgs e)
9845         {
9846             if (_curPost == null) return;
9847             string name = _curPost.ImageUrl;
9848
9849             this.SaveFileDialog1.FileName = name.Substring(name.LastIndexOf('/') + 1);
9850
9851             if (this.SaveFileDialog1.ShowDialog() == DialogResult.OK)
9852             {
9853                 try
9854                 {
9855                     using (Image orgBmp = new Bitmap(IconCache.TryGetFromCache(name).Image))
9856                     {
9857                         using (Bitmap bmp2 = new Bitmap(orgBmp.Size.Width, orgBmp.Size.Height))
9858                         {
9859                             using (Graphics g = Graphics.FromImage(bmp2))
9860                             {
9861                                 g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
9862                                 g.DrawImage(orgBmp, 0, 0, orgBmp.Size.Width, orgBmp.Size.Height);
9863                             }
9864                             bmp2.Save(this.SaveFileDialog1.FileName);
9865                         }
9866                     }
9867                 }
9868                 catch (Exception)
9869                 {
9870                     //処理中にキャッシュアウトする可能性あり
9871                 }
9872             }
9873         }
9874
9875         private void SplitContainer2_Panel2_Resize(object sender, EventArgs e)
9876         {
9877             this.StatusText.Multiline = this.SplitContainer2.Panel2.Height > this.SplitContainer2.Panel2MinSize + 2;
9878             MultiLineMenuItem.Checked = this.StatusText.Multiline;
9879             _modifySettingLocal = true;
9880         }
9881
9882         private void StatusText_MultilineChanged(object sender, EventArgs e)
9883         {
9884             if (this.StatusText.Multiline)
9885                 this.StatusText.ScrollBars = ScrollBars.Vertical;
9886             else
9887                 this.StatusText.ScrollBars = ScrollBars.None;
9888
9889             _modifySettingLocal = true;
9890         }
9891
9892         private void MultiLineMenuItem_Click(object sender, EventArgs e)
9893         {
9894             //発言欄複数行
9895             StatusText.Multiline = MultiLineMenuItem.Checked;
9896             _cfgLocal.StatusMultiline = MultiLineMenuItem.Checked;
9897             if (MultiLineMenuItem.Checked)
9898             {
9899                 if (SplitContainer2.Height - _mySpDis2 - SplitContainer2.SplitterWidth < 0)
9900                     SplitContainer2.SplitterDistance = 0;
9901                 else
9902                     SplitContainer2.SplitterDistance = SplitContainer2.Height - _mySpDis2 - SplitContainer2.SplitterWidth;
9903             }
9904             else
9905             {
9906                 SplitContainer2.SplitterDistance = SplitContainer2.Height - SplitContainer2.Panel2MinSize - SplitContainer2.SplitterWidth;
9907             }
9908             _modifySettingLocal = true;
9909         }
9910
9911         private async Task<bool> UrlConvertAsync(MyCommon.UrlConverter Converter_Type)
9912         {
9913             //t.coで投稿時自動短縮する場合は、外部サービスでの短縮禁止
9914             //if (SettingDialog.UrlConvertAuto && SettingDialog.ShortenTco) return;
9915
9916             //Converter_Type=Nicomsの場合は、nicovideoのみ短縮する
9917             //参考資料 RFC3986 Uniform Resource Identifier (URI): Generic Syntax
9918             //Appendix A.  Collected ABNF for URI
9919             //http://www.ietf.org/rfc/rfc3986.txt
9920
9921             string result = "";
9922
9923             const string nico = @"^https?://[a-z]+\.(nicovideo|niconicommons|nicolive)\.jp/[a-z]+/[a-z0-9]+$";
9924
9925             if (StatusText.SelectionLength > 0)
9926             {
9927                 string tmp = StatusText.SelectedText;
9928                 // httpから始まらない場合、ExcludeStringで指定された文字列で始まる場合は対象としない
9929                 if (tmp.StartsWith("http"))
9930                 {
9931                     // 文字列が選択されている場合はその文字列について処理
9932
9933                     //nico.ms使用、nicovideoにマッチしたら変換
9934                     if (SettingDialog.Nicoms && Regex.IsMatch(tmp, nico))
9935                     {
9936                         result = nicoms.Shorten(tmp);
9937                     }
9938                     else if (Converter_Type != MyCommon.UrlConverter.Nicoms)
9939                     {
9940                         //短縮URL変換 日本語を含むかもしれないのでURLエンコードする
9941                         try
9942                         {
9943                             var srcUri = new Uri(MyCommon.urlEncodeMultibyteChar(tmp));
9944                             var resultUri = await ShortUrl.Instance.ShortenUrlAsync(Converter_Type, srcUri);
9945                             result = resultUri.ToString();
9946                         }
9947                         catch (WebApiException e)
9948                         {
9949                             this.StatusLabel.Text = Converter_Type + ":" + e.Message;
9950                             return false;
9951                         }
9952                         catch (UriFormatException e)
9953                         {
9954                             this.StatusLabel.Text = Converter_Type + ":" + e.Message;
9955                             return false;
9956                         }
9957                     }
9958                     else
9959                     {
9960                         return true;
9961                     }
9962
9963                     if (!string.IsNullOrEmpty(result))
9964                     {
9965                         urlUndo undotmp = new urlUndo();
9966
9967                         StatusText.Select(StatusText.Text.IndexOf(tmp, StringComparison.Ordinal), tmp.Length);
9968                         StatusText.SelectedText = result;
9969
9970                         //undoバッファにセット
9971                         undotmp.Before = tmp;
9972                         undotmp.After = result;
9973
9974                         if (urlUndoBuffer == null)
9975                         {
9976                             urlUndoBuffer = new List<urlUndo>();
9977                             UrlUndoToolStripMenuItem.Enabled = true;
9978                         }
9979
9980                         urlUndoBuffer.Add(undotmp);
9981                     }
9982                 }
9983             }
9984             else
9985             {
9986                 const string url = @"(?<before>(?:[^\""':!=]|^|\:))" +
9987                                    @"(?<url>(?<protocol>https?://)" +
9988                                    @"(?<domain>(?:[\.-]|[^\p{P}\s])+\.[a-z]{2,}(?::[0-9]+)?)" +
9989                                    @"(?<path>/[a-z0-9!*//();:&=+$/%#\-_.,~@]*[a-z0-9)=#/]?)?" +
9990                                    @"(?<query>\?[a-z0-9!*//();:&=+$/%#\-_.,~@?]*[a-z0-9_&=#/])?)";
9991                 // 正規表現にマッチしたURL文字列をtinyurl化
9992                 foreach (Match mt in Regex.Matches(StatusText.Text, url, RegexOptions.IgnoreCase))
9993                 {
9994                     if (StatusText.Text.IndexOf(mt.Result("${url}"), StringComparison.Ordinal) == -1) continue;
9995                     string tmp = mt.Result("${url}");
9996                     if (tmp.StartsWith("w", StringComparison.OrdinalIgnoreCase)) tmp = "http://" + tmp;
9997                     urlUndo undotmp = new urlUndo();
9998
9999                     //選んだURLを選択(?)
10000                     StatusText.Select(StatusText.Text.IndexOf(mt.Result("${url}"), StringComparison.Ordinal), mt.Result("${url}").Length);
10001
10002                     //nico.ms使用、nicovideoにマッチしたら変換
10003                     if (SettingDialog.Nicoms && Regex.IsMatch(tmp, nico))
10004                     {
10005                         result = nicoms.Shorten(tmp);
10006                     }
10007                     else if (Converter_Type != MyCommon.UrlConverter.Nicoms)
10008                     {
10009                         //短縮URL変換 日本語を含むかもしれないのでURLエンコードする
10010                         try
10011                         {
10012                             var srcUri = new Uri(MyCommon.urlEncodeMultibyteChar(tmp));
10013                             var resultUri = await ShortUrl.Instance.ShortenUrlAsync(Converter_Type, srcUri);
10014                             result = resultUri.ToString();
10015                         }
10016                         catch (WebApiException e)
10017                         {
10018                             this.StatusLabel.Text = Converter_Type + ":" + e.Message;
10019                             continue;
10020                         }
10021                         catch (UriFormatException e)
10022                         {
10023                             this.StatusLabel.Text = Converter_Type + ":" + e.Message;
10024                             continue;
10025                         }
10026                     }
10027                     else
10028                     {
10029                         continue;
10030                     }
10031
10032                     if (!string.IsNullOrEmpty(result))
10033                     {
10034                         StatusText.Select(StatusText.Text.IndexOf(mt.Result("${url}"), StringComparison.Ordinal), mt.Result("${url}").Length);
10035                         StatusText.SelectedText = result;
10036                         //undoバッファにセット
10037                         undotmp.Before = mt.Result("${url}");
10038                         undotmp.After = result;
10039
10040                         if (urlUndoBuffer == null)
10041                         {
10042                             urlUndoBuffer = new List<urlUndo>();
10043                             UrlUndoToolStripMenuItem.Enabled = true;
10044                         }
10045
10046                         urlUndoBuffer.Add(undotmp);
10047                     }
10048                 }
10049             }
10050
10051             return true;
10052         }
10053
10054         private void doUrlUndo()
10055         {
10056             if (urlUndoBuffer != null)
10057             {
10058                 string tmp = StatusText.Text;
10059                 foreach (urlUndo data in urlUndoBuffer)
10060                 {
10061                     tmp = tmp.Replace(data.After, data.Before);
10062                 }
10063                 StatusText.Text = tmp;
10064                 urlUndoBuffer = null;
10065                 UrlUndoToolStripMenuItem.Enabled = false;
10066                 StatusText.SelectionStart = 0;
10067                 StatusText.SelectionLength = 0;
10068             }
10069         }
10070
10071         private async void TinyURLToolStripMenuItem_Click(object sender, EventArgs e)
10072         {
10073             await UrlConvertAsync(MyCommon.UrlConverter.TinyUrl);
10074         }
10075
10076         private async void IsgdToolStripMenuItem_Click(object sender, EventArgs e)
10077         {
10078             await UrlConvertAsync(MyCommon.UrlConverter.Isgd);
10079         }
10080
10081         private async void TwurlnlToolStripMenuItem_Click(object sender, EventArgs e)
10082         {
10083             await UrlConvertAsync(MyCommon.UrlConverter.Twurl);
10084         }
10085
10086         private async void UxnuMenuItem_Click(object sender, EventArgs e)
10087         {
10088             await UrlConvertAsync(MyCommon.UrlConverter.Uxnu);
10089         }
10090
10091         private async void UrlConvertAutoToolStripMenuItem_Click(object sender, EventArgs e)
10092         {
10093             if (!await UrlConvertAsync(SettingDialog.AutoShortUrlFirst))
10094             {
10095                 MyCommon.UrlConverter svc = SettingDialog.AutoShortUrlFirst;
10096                 Random rnd = new Random();
10097                 // 前回使用した短縮URLサービス以外を選択する
10098                 do
10099                 {
10100                     svc = (MyCommon.UrlConverter)rnd.Next(System.Enum.GetNames(typeof(MyCommon.UrlConverter)).Length);
10101                 }
10102                 while (svc == SettingDialog.AutoShortUrlFirst || svc == MyCommon.UrlConverter.Nicoms || svc == MyCommon.UrlConverter.Unu);
10103                 await UrlConvertAsync(svc);
10104             }
10105         }
10106
10107         private void UrlUndoToolStripMenuItem_Click(object sender, EventArgs e)
10108         {
10109             doUrlUndo();
10110         }
10111
10112         private void NewPostPopMenuItem_CheckStateChanged(object sender, EventArgs e)
10113         {
10114             this.NotifyFileMenuItem.Checked = ((ToolStripMenuItem)sender).Checked;
10115             this.NewPostPopMenuItem.Checked = this.NotifyFileMenuItem.Checked;
10116             _cfgCommon.NewAllPop = NewPostPopMenuItem.Checked;
10117             _modifySettingCommon = true;
10118         }
10119
10120         private void ListLockMenuItem_CheckStateChanged(object sender, EventArgs e)
10121         {
10122             ListLockMenuItem.Checked = ((ToolStripMenuItem)sender).Checked;
10123             this.LockListFileMenuItem.Checked = ListLockMenuItem.Checked;
10124             _cfgCommon.ListLock = ListLockMenuItem.Checked;
10125             _modifySettingCommon = true;
10126         }
10127
10128         private void MenuStrip1_MenuActivate(object sender, EventArgs e)
10129         {
10130             // フォーカスがメニューに移る (MenuStrip1.Tag フラグを立てる)
10131             MenuStrip1.Tag = new Object();
10132             MenuStrip1.Select(); // StatusText がフォーカスを持っている場合 Leave が発生
10133         }
10134
10135         private void MenuStrip1_MenuDeactivate(object sender, EventArgs e)
10136         {
10137             if (this.Tag != null) // 設定された戻り先へ遷移
10138             {
10139                 if (this.Tag == this.ListTab.SelectedTab)
10140                     ((Control)this.ListTab.SelectedTab.Tag).Select();
10141                 else
10142                     ((Control)this.Tag).Select();
10143             }
10144             else // 戻り先が指定されていない (初期状態) 場合はタブに遷移
10145             {
10146                 if (ListTab.SelectedIndex > -1 && ListTab.SelectedTab.HasChildren)
10147                 {
10148                     this.Tag = ListTab.SelectedTab.Tag;
10149                     ((Control)this.Tag).Select();
10150                 }
10151             }
10152             // フォーカスがメニューに遷移したかどうかを表すフラグを降ろす
10153             MenuStrip1.Tag = null;
10154         }
10155
10156         private void MyList_ColumnReordered(object sender, ColumnReorderedEventArgs e)
10157         {
10158             DetailsListView lst = (DetailsListView)sender;
10159             if (_cfgLocal == null) return;
10160
10161             if (_iconCol)
10162             {
10163                 _cfgLocal.Width1 = lst.Columns[0].Width;
10164                 _cfgLocal.Width3 = lst.Columns[1].Width;
10165             }
10166             else
10167             {
10168                 int[] darr = new int[lst.Columns.Count];
10169                 for (int i = 0; i < lst.Columns.Count; i++)
10170                 {
10171                     darr[lst.Columns[i].DisplayIndex] = i;
10172                 }
10173                 MyCommon.MoveArrayItem(darr, e.OldDisplayIndex, e.NewDisplayIndex);
10174
10175                 for (int i = 0; i < lst.Columns.Count; i++)
10176                 {
10177                     switch (darr[i])
10178                     {
10179                         case 0:
10180                             _cfgLocal.DisplayIndex1 = i;
10181                             break;
10182                         case 1:
10183                             _cfgLocal.DisplayIndex2 = i;
10184                             break;
10185                         case 2:
10186                             _cfgLocal.DisplayIndex3 = i;
10187                             break;
10188                         case 3:
10189                             _cfgLocal.DisplayIndex4 = i;
10190                             break;
10191                         case 4:
10192                             _cfgLocal.DisplayIndex5 = i;
10193                             break;
10194                         case 5:
10195                             _cfgLocal.DisplayIndex6 = i;
10196                             break;
10197                         case 6:
10198                             _cfgLocal.DisplayIndex7 = i;
10199                             break;
10200                         case 7:
10201                             _cfgLocal.DisplayIndex8 = i;
10202                             break;
10203                     }
10204                 }
10205                 _cfgLocal.Width1 = lst.Columns[0].Width;
10206                 _cfgLocal.Width2 = lst.Columns[1].Width;
10207                 _cfgLocal.Width3 = lst.Columns[2].Width;
10208                 _cfgLocal.Width4 = lst.Columns[3].Width;
10209                 _cfgLocal.Width5 = lst.Columns[4].Width;
10210                 _cfgLocal.Width6 = lst.Columns[5].Width;
10211                 _cfgLocal.Width7 = lst.Columns[6].Width;
10212                 _cfgLocal.Width8 = lst.Columns[7].Width;
10213             }
10214             _modifySettingLocal = true;
10215             _isColumnChanged = true;
10216         }
10217
10218         private void MyList_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
10219         {
10220             DetailsListView lst = (DetailsListView)sender;
10221             if (_cfgLocal == null) return;
10222             if (_iconCol)
10223             {
10224                 if (_cfgLocal.Width1 != lst.Columns[0].Width)
10225                 {
10226                     _cfgLocal.Width1 = lst.Columns[0].Width;
10227                     _modifySettingLocal = true;
10228                     _isColumnChanged = true;
10229                 }
10230                 if (_cfgLocal.Width3 != lst.Columns[1].Width)
10231                 {
10232                     _cfgLocal.Width3 = lst.Columns[1].Width;
10233                     _modifySettingLocal = true;
10234                     _isColumnChanged = true;
10235                 }
10236             }
10237             else
10238             {
10239                 if (_cfgLocal.Width1 != lst.Columns[0].Width)
10240                 {
10241                     _cfgLocal.Width1 = lst.Columns[0].Width;
10242                     _modifySettingLocal = true;
10243                     _isColumnChanged = true;
10244                 }
10245                 if (_cfgLocal.Width2 != lst.Columns[1].Width)
10246                 {
10247                     _cfgLocal.Width2 = lst.Columns[1].Width;
10248                     _modifySettingLocal = true;
10249                     _isColumnChanged = true;
10250                 }
10251                 if (_cfgLocal.Width3 != lst.Columns[2].Width)
10252                 {
10253                     _cfgLocal.Width3 = lst.Columns[2].Width;
10254                     _modifySettingLocal = true;
10255                     _isColumnChanged = true;
10256                 }
10257                 if (_cfgLocal.Width4 != lst.Columns[3].Width)
10258                 {
10259                     _cfgLocal.Width4 = lst.Columns[3].Width;
10260                     _modifySettingLocal = true;
10261                     _isColumnChanged = true;
10262                 }
10263                 if (_cfgLocal.Width5 != lst.Columns[4].Width)
10264                 {
10265                     _cfgLocal.Width5 = lst.Columns[4].Width;
10266                     _modifySettingLocal = true;
10267                     _isColumnChanged = true;
10268                 }
10269                 if (_cfgLocal.Width6 != lst.Columns[5].Width)
10270                 {
10271                     _cfgLocal.Width6 = lst.Columns[5].Width;
10272                     _modifySettingLocal = true;
10273                     _isColumnChanged = true;
10274                 }
10275                 if (_cfgLocal.Width7 != lst.Columns[6].Width)
10276                 {
10277                     _cfgLocal.Width7 = lst.Columns[6].Width;
10278                     _modifySettingLocal = true;
10279                     _isColumnChanged = true;
10280                 }
10281                 if (_cfgLocal.Width8 != lst.Columns[7].Width)
10282                 {
10283                     _cfgLocal.Width8 = lst.Columns[7].Width;
10284                     _modifySettingLocal = true;
10285                     _isColumnChanged = true;
10286                 }
10287             }
10288             // 非表示の時にColumnChangedが呼ばれた場合はForm初期化処理中なので保存しない
10289             //if (changed)
10290             //{
10291             //    SaveConfigsLocal();
10292             //}
10293         }
10294
10295         public string WebBrowser_GetSelectionText(ref WebBrowser ComponentInstance)
10296         {
10297             //発言詳細で「選択文字列をコピー」を行う
10298             //WebBrowserコンポーネントのインスタンスを渡す
10299             Type typ = ComponentInstance.ActiveXInstance.GetType();
10300             object _SelObj = typ.InvokeMember("selection", BindingFlags.GetProperty, null, ComponentInstance.Document.DomDocument, null);
10301             object _objRange = _SelObj.GetType().InvokeMember("createRange", BindingFlags.InvokeMethod, null, _SelObj, null);
10302             return (string)_objRange.GetType().InvokeMember("text", BindingFlags.GetProperty, null, _objRange, null);
10303         }
10304
10305         private void SelectionCopyContextMenuItem_Click(object sender, EventArgs e)
10306         {
10307             //発言詳細で「選択文字列をコピー」
10308             string _selText = WebBrowser_GetSelectionText(ref PostBrowser);
10309             try
10310             {
10311                 Clipboard.SetDataObject(_selText, false, 5, 100);
10312             }
10313             catch (Exception ex)
10314             {
10315                 MessageBox.Show(ex.Message);
10316             }
10317         }
10318
10319         private void doSearchToolStrip(string url)
10320         {
10321             //発言詳細で「選択文字列で検索」(選択文字列取得)
10322             string _selText = WebBrowser_GetSelectionText(ref PostBrowser);
10323
10324             if (_selText != null)
10325             {
10326                 if (url == Properties.Resources.SearchItem4Url)
10327                 {
10328                     //公式検索
10329                     AddNewTabForSearch(_selText);
10330                     return;
10331                 }
10332
10333                 string tmp = string.Format(url, Uri.EscapeUriString(_selText));
10334                 OpenUriAsync(tmp);
10335             }
10336         }
10337
10338         private void SelectionAllContextMenuItem_Click(object sender, EventArgs e)
10339         {
10340             //発言詳細ですべて選択
10341             PostBrowser.Document.ExecCommand("SelectAll", false, null);
10342         }
10343
10344         private void SearchWikipediaContextMenuItem_Click(object sender, EventArgs e)
10345         {
10346             doSearchToolStrip(Properties.Resources.SearchItem1Url);
10347         }
10348
10349         private void SearchGoogleContextMenuItem_Click(object sender, EventArgs e)
10350         {
10351             doSearchToolStrip(Properties.Resources.SearchItem2Url);
10352         }
10353
10354         private void SearchPublicSearchContextMenuItem_Click(object sender, EventArgs e)
10355         {
10356             doSearchToolStrip(Properties.Resources.SearchItem4Url);
10357         }
10358
10359         private void UrlCopyContextMenuItem_Click(object sender, EventArgs e)
10360         {
10361             try
10362             {
10363                 MatchCollection mc = Regex.Matches(this.PostBrowser.DocumentText, @"<a[^>]*href=""(?<url>" + this._postBrowserStatusText.Replace(".", @"\.") + @")""[^>]*title=""(?<title>https?://[^""]+)""", RegexOptions.IgnoreCase);
10364                 foreach (Match m in mc)
10365                 {
10366                     if (m.Groups["url"].Value == this._postBrowserStatusText)
10367                     {
10368                         Clipboard.SetDataObject(m.Groups["title"].Value, false, 5, 100);
10369                         break;
10370                     }
10371                 }
10372                 if (mc.Count == 0)
10373                 {
10374                     Clipboard.SetDataObject(this._postBrowserStatusText, false, 5, 100);
10375                 }
10376                 //Clipboard.SetDataObject(this._postBrowserStatusText, false, 5, 100);
10377             }
10378             catch (Exception ex)
10379             {
10380                 MessageBox.Show(ex.Message);
10381             }
10382         }
10383
10384         private void ContextMenuPostBrowser_Opening(object ender, CancelEventArgs e)
10385         {
10386             // URLコピーの項目の表示/非表示
10387             if (PostBrowser.StatusText.StartsWith("http"))
10388             {
10389                 this._postBrowserStatusText = PostBrowser.StatusText;
10390                 string name = GetUserId();
10391                 UrlCopyContextMenuItem.Enabled = true;
10392                 if (name != null)
10393                 {
10394                     FollowContextMenuItem.Enabled = true;
10395                     RemoveContextMenuItem.Enabled = true;
10396                     FriendshipContextMenuItem.Enabled = true;
10397                     ShowUserStatusContextMenuItem.Enabled = true;
10398                     SearchPostsDetailToolStripMenuItem.Enabled = true;
10399                     IdFilterAddMenuItem.Enabled = true;
10400                     ListManageUserContextToolStripMenuItem.Enabled = true;
10401                     SearchAtPostsDetailToolStripMenuItem.Enabled = true;
10402                 }
10403                 else
10404                 {
10405                     FollowContextMenuItem.Enabled = false;
10406                     RemoveContextMenuItem.Enabled = false;
10407                     FriendshipContextMenuItem.Enabled = false;
10408                     ShowUserStatusContextMenuItem.Enabled = false;
10409                     SearchPostsDetailToolStripMenuItem.Enabled = false;
10410                     IdFilterAddMenuItem.Enabled = false;
10411                     ListManageUserContextToolStripMenuItem.Enabled = false;
10412                     SearchAtPostsDetailToolStripMenuItem.Enabled = false;
10413                 }
10414
10415                 if (Regex.IsMatch(this._postBrowserStatusText, @"^https?://twitter.com/search\?q=%23"))
10416                     UseHashtagMenuItem.Enabled = true;
10417                 else
10418                     UseHashtagMenuItem.Enabled = false;
10419             }
10420             else
10421             {
10422                 this._postBrowserStatusText = "";
10423                 UrlCopyContextMenuItem.Enabled = false;
10424                 FollowContextMenuItem.Enabled = false;
10425                 RemoveContextMenuItem.Enabled = false;
10426                 FriendshipContextMenuItem.Enabled = false;
10427                 ShowUserStatusContextMenuItem.Enabled = false;
10428                 SearchPostsDetailToolStripMenuItem.Enabled = false;
10429                 SearchAtPostsDetailToolStripMenuItem.Enabled = false;
10430                 UseHashtagMenuItem.Enabled = false;
10431                 IdFilterAddMenuItem.Enabled = false;
10432                 ListManageUserContextToolStripMenuItem.Enabled = false;
10433             }
10434             // 文字列選択されていないときは選択文字列関係の項目を非表示に
10435             string _selText = WebBrowser_GetSelectionText(ref PostBrowser);
10436             if (_selText == null)
10437             {
10438                 SelectionSearchContextMenuItem.Enabled = false;
10439                 SelectionCopyContextMenuItem.Enabled = false;
10440                 SelectionTranslationToolStripMenuItem.Enabled = false;
10441             }
10442             else
10443             {
10444                 SelectionSearchContextMenuItem.Enabled = true;
10445                 SelectionCopyContextMenuItem.Enabled = true;
10446                 SelectionTranslationToolStripMenuItem.Enabled = true;
10447             }
10448             //発言内に自分以外のユーザーが含まれてればフォロー状態全表示を有効に
10449             MatchCollection ma = Regex.Matches(this.PostBrowser.DocumentText, @"href=""https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)(/status(es)?/[0-9]+)?""");
10450             bool fAllFlag = false;
10451             foreach (Match mu in ma)
10452             {
10453                 if (mu.Result("${ScreenName}").ToLower() != tw.Username.ToLower())
10454                 {
10455                     fAllFlag = true;
10456                     break;
10457                 }
10458             }
10459             this.FriendshipAllMenuItem.Enabled = fAllFlag;
10460
10461             if (_curPost == null)
10462                 TranslationToolStripMenuItem.Enabled = false;
10463             else
10464                 TranslationToolStripMenuItem.Enabled = true;
10465
10466             e.Cancel = false;
10467         }
10468
10469         private void CurrentTabToolStripMenuItem_Click(object sender, EventArgs e)
10470         {
10471             //発言詳細の選択文字列で現在のタブを検索
10472             string _selText = WebBrowser_GetSelectionText(ref PostBrowser);
10473
10474             if (_selText != null)
10475             {
10476                 var searchOptions = new SearchWordDialog.SearchOptions(
10477                     SearchWordDialog.SearchType.Timeline,
10478                     _selText,
10479                     newTab: false,
10480                     caseSensitive: false,
10481                     useRegex: false);
10482
10483                 this.SearchDialog.ResultOptions = searchOptions;
10484
10485                 this.DoTabSearch(
10486                     searchOptions.Query,
10487                     searchOptions.CaseSensitive,
10488                     searchOptions.UseRegex,
10489                     SEARCHTYPE.NextSearch);
10490             }
10491         }
10492
10493         private void SplitContainer2_SplitterMoved(object sender, SplitterEventArgs e)
10494         {
10495             if (StatusText.Multiline) _mySpDis2 = StatusText.Height;
10496             _modifySettingLocal = true;
10497         }
10498
10499         private void TweenMain_DragDrop(object sender, DragEventArgs e)
10500         {
10501             if (e.Data.GetDataPresent(DataFormats.FileDrop))
10502             {
10503                 SelectMedia_DragDrop(e);
10504             }
10505             else if (e.Data.GetDataPresent("UniformResourceLocatorW"))
10506             {
10507                 var url = GetUrlFromDataObject(e.Data);
10508
10509                 string appendText;
10510                 if (url.Item2 == null)
10511                     appendText = url.Item1;
10512                 else
10513                     appendText = url.Item2 + " " + url.Item1;
10514
10515                 if (this.StatusText.TextLength == 0)
10516                     this.StatusText.Text = appendText;
10517                 else
10518                     this.StatusText.Text += " " + appendText;
10519             }
10520             else if (e.Data.GetDataPresent(DataFormats.StringFormat))
10521             {
10522                 string data = (string)e.Data.GetData(DataFormats.StringFormat, true);
10523                 if (data != null) StatusText.Text += data;
10524             }
10525         }
10526
10527         /// <summary>
10528         /// IDataObject から URL とタイトルの対を取得します
10529         /// </summary>
10530         /// <remarks>
10531         /// タイトルのみ取得できなかった場合は Value2 が null のタプルを返すことがあります。
10532         /// </remarks>
10533         /// <exception cref="ArgumentException">不正なフォーマットが入力された場合</exception>
10534         /// <exception cref="NotSupportedException">サポートされていないデータが入力された場合</exception>
10535         internal static Tuple<string, string> GetUrlFromDataObject(IDataObject data)
10536         {
10537             if (data.GetDataPresent("text/x-moz-url"))
10538             {
10539                 // Firefox, Google Chrome で利用可能
10540                 // 参照: https://developer.mozilla.org/ja/docs/DragDrop/Recommended_Drag_Types
10541
10542                 using (var stream = (MemoryStream)data.GetData("text/x-moz-url"))
10543                 {
10544                     var lines = Encoding.Unicode.GetString(stream.ToArray()).TrimEnd('\0').Split('\n');
10545                     if (lines.Length < 2)
10546                         throw new ArgumentException("不正な text/x-moz-url フォーマットです", "data");
10547
10548                     return new Tuple<string, string>(lines[0], lines[1]);
10549                 }
10550             }
10551             else if (data.GetDataPresent("IESiteModeToUrl"))
10552             {
10553                 // Internet Exproler 用
10554                 // 保護モードが有効なデフォルトの IE では DragDrop イベントが発火しないため使えない
10555
10556                 using (var stream = (MemoryStream)data.GetData("IESiteModeToUrl"))
10557                 {
10558                     var lines = Encoding.Unicode.GetString(stream.ToArray()).TrimEnd('\0').Split('\0');
10559                     if (lines.Length < 2)
10560                         throw new ArgumentException("不正な IESiteModeToUrl フォーマットです", "data");
10561
10562                     return new Tuple<string, string>(lines[0], lines[1]);
10563                 }
10564             }
10565             else if (data.GetDataPresent("UniformResourceLocatorW"))
10566             {
10567                 // それ以外のブラウザ向け
10568
10569                 using (var stream = (MemoryStream)data.GetData("UniformResourceLocatorW"))
10570                 {
10571                     var url = Encoding.Unicode.GetString(stream.ToArray()).TrimEnd('\0');
10572                     return new Tuple<string, string>(url, null);
10573                 }
10574             }
10575
10576             throw new NotSupportedException("サポートされていないデータ形式です: " + data.GetFormats()[0]);
10577         }
10578
10579         private void TweenMain_DragEnter(object sender, DragEventArgs e)
10580         {
10581             if (e.Data.GetDataPresent(DataFormats.FileDrop))
10582             {
10583                 SelectMedia_DragEnter(e);
10584             }
10585         }
10586
10587         private void TweenMain_DragOver(object sender, DragEventArgs e)
10588         {
10589             if (e.Data.GetDataPresent(DataFormats.FileDrop))
10590             {
10591                 SelectMedia_DragOver(e);
10592             }
10593             else if (e.Data.GetDataPresent("UniformResourceLocatorW"))
10594             {
10595                 e.Effect = DragDropEffects.Copy;
10596             }
10597             else if (e.Data.GetDataPresent(DataFormats.StringFormat))
10598             {
10599                 e.Effect = DragDropEffects.Copy;
10600             }
10601             else
10602             {
10603                 e.Effect = DragDropEffects.None;
10604             }
10605         }
10606
10607         public bool IsNetworkAvailable()
10608         {
10609             bool nw = true;
10610             nw = MyCommon.IsNetworkAvailable();
10611             _myStatusOnline = nw;
10612             return nw;
10613         }
10614
10615         public Task OpenUriAsync(string UriString)
10616         {
10617             return Task.Run(() =>
10618             {
10619                 string myPath = UriString;
10620
10621                 try
10622                 {
10623                     var configBrowserPath = SettingDialog.BrowserPath;
10624                     if (!string.IsNullOrEmpty(configBrowserPath))
10625                     {
10626                         if (configBrowserPath.StartsWith("\"") && configBrowserPath.Length > 2 && configBrowserPath.IndexOf("\"", 2) > -1)
10627                         {
10628                             int sep = configBrowserPath.IndexOf("\"", 2);
10629                             string browserPath = configBrowserPath.Substring(1, sep - 1);
10630                             string arg = "";
10631                             if (sep < configBrowserPath.Length - 1)
10632                             {
10633                                 arg = configBrowserPath.Substring(sep + 1);
10634                             }
10635                             myPath = arg + " " + myPath;
10636                             System.Diagnostics.Process.Start(browserPath, myPath);
10637                         }
10638                         else
10639                         {
10640                             System.Diagnostics.Process.Start(configBrowserPath, myPath);
10641                         }
10642                     }
10643                     else
10644                     {
10645                         System.Diagnostics.Process.Start(myPath);
10646                     }
10647                 }
10648                 catch (Exception)
10649                 {
10650                     //MessageBox.Show("ブラウザの起動に失敗、またはタイムアウトしました。" + ex.ToString());
10651                 }
10652             });
10653         }
10654
10655         private void ListTabSelect(TabPage _tab)
10656         {
10657             SetListProperty();
10658
10659             this.PurgeListViewItemCache();
10660
10661             _curTab = _tab;
10662             _curList = (DetailsListView)_tab.Tag;
10663             if (_curList.SelectedIndices.Count > 0)
10664             {
10665                 _curItemIndex = _curList.SelectedIndices[0];
10666                 _curPost = GetCurTabPost(_curItemIndex);
10667             }
10668             else
10669             {
10670                 _curItemIndex = -1;
10671                 _curPost = null;
10672             }
10673
10674             _anchorPost = null;
10675             _anchorFlag = false;
10676
10677             if (_iconCol)
10678             {
10679                 ((DetailsListView)_tab.Tag).Columns[1].Text = ColumnText[2];
10680             }
10681             else
10682             {
10683                 for (int i = 0; i < _curList.Columns.Count; i++)
10684                 {
10685                     ((DetailsListView)_tab.Tag).Columns[i].Text = ColumnText[i];
10686                 }
10687             }
10688         }
10689
10690         private void ListTab_Selecting(object sender, TabControlCancelEventArgs e)
10691         {
10692             ListTabSelect(e.TabPage);
10693         }
10694
10695         private void SelectListItem(DetailsListView LView, int Index)
10696         {
10697             //単一
10698             Rectangle bnd = new Rectangle();
10699             bool flg = false;
10700             var item = LView.FocusedItem;
10701             if (item != null)
10702             {
10703                 bnd = item.Bounds;
10704                 flg = true;
10705             }
10706
10707             do
10708             {
10709                 LView.SelectedIndices.Clear();
10710             }
10711             while (LView.SelectedIndices.Count > 0);
10712             item = LView.Items[Index];
10713             item.Selected = true;
10714             item.Focused = true;
10715
10716             if (flg) LView.Invalidate(bnd);
10717         }
10718
10719         private void SelectListItem(DetailsListView LView , int[] Index, int[] FocusedIndex)
10720         {
10721             //複数
10722             Rectangle bnd = new Rectangle();
10723             bool flg = false;
10724             var item = LView.FocusedItem;
10725             if (item != null)
10726             {
10727                 bnd = item.Bounds;
10728                 flg = true;
10729             }
10730
10731             int fIdx = -1;
10732             if (Index != null && !(Index.Length == 1 && Index[0] == -1))
10733             {
10734                 do
10735                 {
10736                     LView.SelectedIndices.Clear();
10737                 }
10738                 while (LView.SelectedIndices.Count > 0);
10739                 foreach (int idx in Index)
10740                 {
10741                     if (idx > -1 && LView.VirtualListSize > idx)
10742                     {
10743                         LView.SelectedIndices.Add(idx);
10744                         if (fIdx == -1) fIdx = idx;
10745                     }
10746                 }
10747             }
10748             if (FocusedIndex[1] > -1 && LView.VirtualListSize > FocusedIndex[1])
10749             {
10750                 LView.SelectionMark = FocusedIndex[1];
10751             }
10752             if (FocusedIndex[0] > -1 && LView.VirtualListSize > FocusedIndex[0])
10753             {
10754                 LView.Items[FocusedIndex[0]].Focused = true;
10755             }
10756             else if (fIdx > -1)
10757             {
10758                 LView.Items[fIdx].Focused = true;
10759             }
10760
10761             if (flg) LView.Invalidate(bnd);
10762         }
10763
10764         private void RunAsync(GetWorkerArg args)
10765         {
10766             BackgroundWorker bw = null;
10767             if (args.type != MyCommon.WORKERTYPE.Follower)
10768             {
10769                 for (int i = 0; i < _bw.Length; i++)
10770                 {
10771                     if (_bw[i] != null && !_bw[i].IsBusy)
10772                     {
10773                         bw = _bw[i];
10774                         break;
10775                     }
10776                 }
10777                 if (bw == null)
10778                 {
10779                     for (int i = 0; i < _bw.Length; i++)
10780                     {
10781                         if (_bw[i] == null)
10782                         {
10783                             _bw[i] = new BackgroundWorker();
10784                             bw = _bw[i];
10785                             bw.WorkerReportsProgress = true;
10786                             bw.WorkerSupportsCancellation = true;
10787                             bw.DoWork += GetTimelineWorker_DoWork;
10788                             bw.ProgressChanged += GetTimelineWorker_ProgressChanged;
10789                             bw.RunWorkerCompleted += GetTimelineWorker_RunWorkerCompleted;
10790                             break;
10791                         }
10792                     }
10793                 }
10794             }
10795             else
10796             {
10797                 if (_bwFollower == null)
10798                 {
10799                     _bwFollower = new BackgroundWorker();
10800                     bw = _bwFollower;
10801                     bw.WorkerReportsProgress = true;
10802                     bw.WorkerSupportsCancellation = true;
10803                     bw.DoWork += GetTimelineWorker_DoWork;
10804                     bw.ProgressChanged += GetTimelineWorker_ProgressChanged;
10805                     bw.RunWorkerCompleted += GetTimelineWorker_RunWorkerCompleted;
10806                 }
10807                 else
10808                 {
10809                     if (_bwFollower.IsBusy == false)
10810                         bw = _bwFollower;
10811                 }
10812             }
10813             if (bw == null) return;
10814
10815             bw.RunWorkerAsync(args);
10816         }
10817
10818         private void StartUserStream()
10819         {
10820             tw.NewPostFromStream += tw_NewPostFromStream;
10821             tw.UserStreamStarted += tw_UserStreamStarted;
10822             tw.UserStreamStopped += tw_UserStreamStopped;
10823             tw.PostDeleted += tw_PostDeleted;
10824             tw.UserStreamEventReceived += tw_UserStreamEventArrived;
10825
10826             MenuItemUserStream.Text = "&UserStream ■";
10827             MenuItemUserStream.Enabled = true;
10828             StopToolStripMenuItem.Text = "&Start";
10829             StopToolStripMenuItem.Enabled = true;
10830             if (SettingDialog.UserstreamStartup) tw.StartUserStream();
10831         }
10832
10833         private async void TweenMain_Shown(object sender, EventArgs e)
10834         {
10835             try
10836             {
10837                 PostBrowser.Url = new Uri("about:blank");
10838                 PostBrowser.DocumentText = "";       //発言詳細部初期化
10839             }
10840             catch (Exception)
10841             {
10842             }
10843
10844             NotifyIcon1.Visible = true;
10845
10846             if (this.IsNetworkAvailable())
10847             {
10848                 this.RefreshMuteUserIdsAsync();
10849                 GetTimeline(MyCommon.WORKERTYPE.BlockIds, 0, 0, "");
10850                 GetTimeline(MyCommon.WORKERTYPE.NoRetweetIds, 0, 0, "");
10851                 if (SettingDialog.StartupFollowers)
10852                 {
10853                     GetTimeline(MyCommon.WORKERTYPE.Follower, 0, 0, "");
10854                 }
10855                 GetTimeline(MyCommon.WORKERTYPE.Configuration, 0, 0, "");
10856                 StartUserStream();
10857                 _waitTimeline = true;
10858                 GetTimeline(MyCommon.WORKERTYPE.Timeline, 1, 1, "");
10859                 _waitReply = true;
10860                 GetTimeline(MyCommon.WORKERTYPE.Reply, 1, 1, "");
10861                 _waitDm = true;
10862                 GetTimeline(MyCommon.WORKERTYPE.DirectMessegeRcv, 1, 1, "");
10863                 if (SettingDialog.GetFav)
10864                 {
10865                     _waitFav = true;
10866                     GetTimeline(MyCommon.WORKERTYPE.Favorites, 1, 1, "");
10867                 }
10868                 _waitPubSearch = true;
10869                 GetTimeline(MyCommon.WORKERTYPE.PublicSearch, 1, 0, "");  //tabname="":全タブ
10870                 _waitUserTimeline = true;
10871                 GetTimeline(MyCommon.WORKERTYPE.UserTimeline, 1, 0, "");  //tabname="":全タブ
10872                 _waitLists = true;
10873                 GetTimeline(MyCommon.WORKERTYPE.List, 1, 0, "");  //tabname="":全タブ
10874
10875                 var i = 0;
10876                 while (this.IsInitialRead())
10877                 {
10878                     await Task.Delay(5000);
10879
10880                     i += 1;
10881                     if (i > 24) break; // 120秒間初期処理が終了しなかったら強制的に打ち切る
10882
10883                     if (MyCommon._endingFlag)
10884                         return;
10885                 }
10886
10887                 if (MyCommon._endingFlag) return;
10888
10889                 if (ApplicationSettings.VersionInfoUrl != null)
10890                 {
10891                     //バージョンチェック(引数:起動時チェックの場合はtrue・・・チェック結果のメッセージを表示しない)
10892                     if (SettingDialog.StartupVersion)
10893                         await this.CheckNewVersion(true);
10894                 }
10895                 else
10896                 {
10897                     // ApplicationSetting.cs の設定により更新チェックが無効化されている場合
10898                     this.VerUpMenuItem.Enabled = false;
10899                     this.VerUpMenuItem.Available = false;
10900                     this.ToolStripSeparator16.Available = false; // VerUpMenuItem の一つ上にあるセパレータ
10901                 }
10902
10903                 // 取得失敗の場合は再試行する
10904                 if (!tw.GetFollowersSuccess && SettingDialog.StartupFollowers)
10905                     GetTimeline(MyCommon.WORKERTYPE.Follower, 0, 0, "");
10906
10907                 // 取得失敗の場合は再試行する
10908                 if (!tw.GetNoRetweetSuccess)
10909                     GetTimeline(MyCommon.WORKERTYPE.NoRetweetIds, 0, 0, "");
10910
10911                 // 取得失敗の場合は再試行する
10912                 if (SettingDialog.TwitterConfiguration.PhotoSizeLimit == 0)
10913                     GetTimeline(MyCommon.WORKERTYPE.Configuration, 0, 0, "");
10914
10915                 // 権限チェック read/write権限(xAuthで取得したトークン)の場合は再認証を促す
10916                 if (MyCommon.TwitterApiInfo.AccessLevel == TwitterApiAccessLevel.ReadWrite)
10917                 {
10918                     MessageBox.Show(Properties.Resources.ReAuthorizeText);
10919                     SettingStripMenuItem_Click(null, null);
10920                 }
10921
10922                 //
10923             }
10924             _initial = false;
10925
10926             TimerTimeline.Enabled = true;
10927         }
10928
10929         private bool IsInitialRead()
10930         {
10931             return _waitTimeline || _waitReply || _waitDm || _waitFav || _waitPubSearch || _waitUserTimeline || _waitLists;
10932         }
10933
10934         private void doGetFollowersMenu()
10935         {
10936             GetTimeline(MyCommon.WORKERTYPE.Follower, 1, 0, "");
10937             DispSelectedPost(true);
10938         }
10939
10940         private void GetFollowersAllToolStripMenuItem_Click(object sender, EventArgs e)
10941         {
10942             doGetFollowersMenu();
10943         }
10944
10945         private void doReTweetUnofficial()
10946         {
10947             //RT @id:内容
10948             if (this.ExistCurrentPost)
10949             {
10950                 if (_curPost.IsDm ||
10951                     !StatusText.Enabled) return;
10952
10953                 if (_curPost.IsProtect)
10954                 {
10955                     MessageBox.Show("Protected.");
10956                     return;
10957                 }
10958                 string rtdata = _curPost.Text;
10959                 rtdata = CreateRetweetUnofficial(rtdata, this.StatusText.Multiline);
10960
10961                 this._reply_to_id = null;
10962                 this._reply_to_name = null;
10963
10964                 StatusText.Text = "RT @" + _curPost.ScreenName + ": " + rtdata;
10965
10966                 StatusText.SelectionStart = 0;
10967                 StatusText.Focus();
10968             }
10969         }
10970
10971         private void ReTweetStripMenuItem_Click(object sender, EventArgs e)
10972         {
10973             doReTweetUnofficial();
10974         }
10975
10976         private void doReTweetOfficial(bool isConfirm)
10977         {
10978             //公式RT
10979             if (this.ExistCurrentPost)
10980             {
10981                 if (_curPost.IsProtect)
10982                 {
10983                     MessageBox.Show("Protected.");
10984                     _DoFavRetweetFlags = false;
10985                     return;
10986                 }
10987                 if (_curList.SelectedIndices.Count > 15)
10988                 {
10989                     MessageBox.Show(Properties.Resources.RetweetLimitText);
10990                     _DoFavRetweetFlags = false;
10991                     return;
10992                 }
10993                 else if (_curList.SelectedIndices.Count > 1)
10994                 {
10995                     string QuestionText = Properties.Resources.RetweetQuestion2;
10996                     if (_DoFavRetweetFlags) QuestionText = Properties.Resources.FavoriteRetweetQuestionText1;
10997                     switch (MessageBox.Show(QuestionText, "Retweet", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
10998                     {
10999                         case DialogResult.Cancel:
11000                         case DialogResult.No:
11001                             _DoFavRetweetFlags = false;
11002                             return;
11003                     }
11004                 }
11005                 else
11006                 {
11007                     if (_curPost.IsDm || _curPost.IsMe)
11008                     {
11009                         _DoFavRetweetFlags = false;
11010                         return;
11011                     }
11012                     if (!SettingDialog.RetweetNoConfirm)
11013                     {
11014                         string Questiontext = Properties.Resources.RetweetQuestion1;
11015                         if (_DoFavRetweetFlags) Questiontext = Properties.Resources.FavoritesRetweetQuestionText2;
11016                         if (isConfirm && MessageBox.Show(Questiontext, "Retweet", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
11017                         {
11018                             _DoFavRetweetFlags = false;
11019                             return;
11020                         }
11021                     }
11022                 }
11023                 GetWorkerArg args = new GetWorkerArg();
11024                 args.ids = new List<long>();
11025                 args.sIds = new List<long>();
11026                 args.tName = _curTab.Text;
11027                 args.type = MyCommon.WORKERTYPE.Retweet;
11028                 foreach (int idx in _curList.SelectedIndices)
11029                 {
11030                     PostClass post = GetCurTabPost(idx);
11031                     if (!post.IsMe && !post.IsProtect && !post.IsDm) args.ids.Add(post.StatusId);
11032                 }
11033                 RunAsync(args);
11034             }
11035         }
11036
11037         private void ReTweetOriginalStripMenuItem_Click(object sender, EventArgs e)
11038         {
11039             doReTweetOfficial(true);
11040         }
11041
11042         private void FavoritesRetweetOriginal()
11043         {
11044             if (!this.ExistCurrentPost) return;
11045             _DoFavRetweetFlags = true;
11046             doReTweetOfficial(true);
11047             if (_DoFavRetweetFlags)
11048             {
11049                 _DoFavRetweetFlags = false;
11050                 FavoriteChange(true, false);
11051             }
11052         }
11053
11054         private void FavoritesRetweetUnofficial()
11055         {
11056             if (this.ExistCurrentPost && !_curPost.IsDm)
11057             {
11058                 _DoFavRetweetFlags = true;
11059                 FavoriteChange(true);
11060                 if (!_curPost.IsProtect && _DoFavRetweetFlags)
11061                 {
11062                     _DoFavRetweetFlags = false;
11063                     doReTweetUnofficial();
11064                 }
11065             }
11066         }
11067
11068         /// <summary>
11069         /// TweetFormatterクラスによって整形された状態のHTMLを、非公式RT用に元のツイートに復元します
11070         /// </summary>
11071         /// <param name="statusHtml">TweetFormatterによって整形された状態のHTML</param>
11072         /// <param name="multiline">trueであればBRタグを改行に、falseであればスペースに変換します</param>
11073         /// <returns>復元されたツイート本文</returns>
11074         internal static string CreateRetweetUnofficial(string statusHtml, bool multiline)
11075         {
11076             // TweetFormatterクラスによって整形された状態のHTMLを元のツイートに復元します
11077
11078             // 通常の URL
11079             statusHtml = Regex.Replace(statusHtml, "<a href=\"(?<href>.+?)\" title=\"(?<title>.+?)\">(?<text>.+?)</a>", "${title}");
11080             // メンション
11081             statusHtml = Regex.Replace(statusHtml, "<a class=\"mention\" href=\"(?<href>.+?)\">(?<text>.+?)</a>", "${text}");
11082             // ハッシュタグ
11083             statusHtml = Regex.Replace(statusHtml, "<a class=\"hashtag\" href=\"(?<href>.+?)\">(?<text>.+?)</a>", "${text}");
11084
11085             // <br> 除去
11086             if (multiline)
11087                 statusHtml = statusHtml.Replace("<br>", Environment.NewLine);
11088             else
11089                 statusHtml = statusHtml.Replace("<br>", " ");
11090
11091             // &nbsp; は本来であれば U+00A0 (NON-BREAK SPACE) に置換すべきですが、
11092             // 現状では半角スペースの代用として &nbsp; を使用しているため U+0020 に置換します
11093             statusHtml = statusHtml.Replace("&nbsp;", " ");
11094
11095             return WebUtility.HtmlDecode(statusHtml);
11096         }
11097
11098         private void DumpPostClassToolStripMenuItem_Click(object sender, EventArgs e)
11099         {
11100             if (_curPost != null)
11101                 DispSelectedPost(true);
11102         }
11103
11104         private void MenuItemHelp_DropDownOpening(object sender, EventArgs e)
11105         {
11106             if (MyCommon.DebugBuild || MyCommon.IsKeyDown(Keys.CapsLock, Keys.Control, Keys.Shift))
11107                 DebugModeToolStripMenuItem.Visible = true;
11108             else
11109                 DebugModeToolStripMenuItem.Visible = false;
11110         }
11111
11112         private void ToolStripMenuItemUrlAutoShorten_CheckedChanged(object sender, EventArgs e)
11113         {
11114             SettingDialog.UrlConvertAuto = ToolStripMenuItemUrlAutoShorten.Checked;
11115         }
11116
11117         private void ContextMenuPostMode_Opening(object sender, CancelEventArgs e)
11118         {
11119             ToolStripMenuItemUrlAutoShorten.Checked = SettingDialog.UrlConvertAuto;
11120         }
11121
11122         private void TraceOutToolStripMenuItem_Click(object sender, EventArgs e)
11123         {
11124             if (TraceOutToolStripMenuItem.Checked)
11125                 MyCommon.TraceFlag = true;
11126             else
11127                 MyCommon.TraceFlag = false;
11128         }
11129
11130         private void TweenMain_Deactivate(object sender, EventArgs e)
11131         {
11132             //画面が非アクティブになったら、発言欄の背景色をデフォルトへ
11133             this.StatusText_Leave(StatusText, System.EventArgs.Empty);
11134         }
11135
11136         private void TabRenameMenuItem_Click(object sender, EventArgs e)
11137         {
11138             if (string.IsNullOrEmpty(_rclickTabName)) return;
11139             TabRename(ref _rclickTabName);
11140         }
11141
11142         private async void BitlyToolStripMenuItem_Click(object sender, EventArgs e)
11143         {
11144             await UrlConvertAsync(MyCommon.UrlConverter.Bitly);
11145         }
11146
11147         private async void JmpToolStripMenuItem_Click(object sender, EventArgs e)
11148         {
11149             await UrlConvertAsync(MyCommon.UrlConverter.Jmp);
11150         }
11151
11152
11153         private void GetApiInfo_Dowork(object sender, DoWorkEventArgs e)
11154         {
11155             e.Result = tw.GetInfoApi();
11156         }
11157
11158         private void ApiUsageInfoMenuItem_Click(object sender, EventArgs e)
11159         {
11160             StringBuilder tmp = new StringBuilder();
11161
11162             using (FormInfo dlg = new FormInfo(this, Properties.Resources.ApiInfo6, GetApiInfo_Dowork))
11163             {
11164                 dlg.ShowDialog();
11165
11166                 var result = (TwitterApiStatus)dlg.Result;
11167
11168                 if (result == null)
11169                 {
11170                     var accessLevel = result.AccessLevel;
11171                     var timelineLimit = result.AccessLimit["/statuses/home_timeline"];
11172                     var mediaLimit = result.MediaUploadLimit;
11173
11174                     tmp.AppendLine(Properties.Resources.ApiInfo1 + timelineLimit.AccessLimitCount);
11175                     tmp.AppendLine(Properties.Resources.ApiInfo2 + timelineLimit.AccessLimitRemain);
11176                     tmp.AppendLine(Properties.Resources.ApiInfo3 + timelineLimit.AccessLimitResetDate);
11177                     tmp.AppendLine(Properties.Resources.ApiInfo7 + (tw.UserStreamEnabled ? Properties.Resources.Enable : Properties.Resources.Disable));
11178
11179                     tmp.AppendLine();
11180                     tmp.AppendLine(Properties.Resources.ApiInfo8 + accessLevel);
11181                     SetStatusLabelUrl();
11182
11183                     tmp.AppendLine();
11184                     tmp.AppendLine(Properties.Resources.ApiInfo9 + (mediaLimit == null ? Properties.Resources.ApiInfo91 : mediaLimit.AccessLimitCount.ToString()));
11185                     tmp.AppendLine(Properties.Resources.ApiInfo10 + (mediaLimit == null ? Properties.Resources.ApiInfo91 : mediaLimit.AccessLimitRemain.ToString()));
11186                     tmp.AppendLine(Properties.Resources.ApiInfo11 + (mediaLimit == null ? Properties.Resources.ApiInfo91 : mediaLimit.AccessLimitResetDate.ToString()));
11187                 }
11188                 else
11189                 {
11190                     tmp.Append(Properties.Resources.ApiInfo5);
11191                 }
11192             }
11193
11194             MessageBox.Show(tmp.ToString(), Properties.Resources.ApiInfo4, MessageBoxButtons.OK, MessageBoxIcon.Information);
11195         }
11196
11197         private void FollowCommandMenuItem_Click(object sender, EventArgs e)
11198         {
11199             string id = "";
11200             if (_curPost != null) id = _curPost.ScreenName;
11201             FollowCommand(id);
11202         }
11203
11204         private void FollowCommand_DoWork(object sender, DoWorkEventArgs e)
11205         {
11206             FollowRemoveCommandArgs arg = (FollowRemoveCommandArgs)e.Argument;
11207             e.Result = arg.tw.PostFollowCommand(arg.id);
11208         }
11209
11210         private void FollowCommand(string id)
11211         {
11212             using (InputTabName inputName = new InputTabName())
11213             {
11214                 inputName.FormTitle = "Follow";
11215                 inputName.FormDescription = Properties.Resources.FRMessage1;
11216                 inputName.TabName = id;
11217                 if (inputName.ShowDialog() == DialogResult.OK &&
11218                     !string.IsNullOrEmpty(inputName.TabName.Trim()))
11219                 {
11220                     FollowRemoveCommandArgs arg = new FollowRemoveCommandArgs();
11221                     arg.tw = tw;
11222                     arg.id = inputName.TabName.Trim();
11223                     using (FormInfo _info = new FormInfo(this, Properties.Resources.FollowCommandText1,
11224                                                          FollowCommand_DoWork,
11225                                                          null,
11226                                                          arg))
11227                     {
11228                         _info.ShowDialog();
11229                         string ret = (string)_info.Result;
11230                         if (!string.IsNullOrEmpty(ret))
11231                             MessageBox.Show(Properties.Resources.FRMessage2 + ret);
11232                         else
11233                             MessageBox.Show(Properties.Resources.FRMessage3);
11234                     }
11235                 }
11236             }
11237         }
11238
11239         private void RemoveCommandMenuItem_Click(object sender, EventArgs e)
11240         {
11241             string id = "";
11242             if (_curPost != null) id = _curPost.ScreenName;
11243             RemoveCommand(id, false);
11244         }
11245
11246         private class FollowRemoveCommandArgs
11247         {
11248             public Twitter tw;
11249             public string id;
11250         }
11251
11252         private void RemoveCommand_DoWork(object sender , DoWorkEventArgs e)
11253         {
11254             FollowRemoveCommandArgs arg = (FollowRemoveCommandArgs)e.Argument;
11255             e.Result = arg.tw.PostRemoveCommand(arg.id);
11256         }
11257
11258         private void RemoveCommand(string id, bool skipInput)
11259         {
11260             FollowRemoveCommandArgs arg = new FollowRemoveCommandArgs();
11261             arg.tw = tw;
11262             arg.id = id;
11263             if (!skipInput)
11264             {
11265                 using (InputTabName inputName = new InputTabName())
11266                 {
11267                     inputName.FormTitle = "Unfollow";
11268                     inputName.FormDescription = Properties.Resources.FRMessage1;
11269                     inputName.TabName = id;
11270                     if (inputName.ShowDialog() == DialogResult.OK &&
11271                         !string.IsNullOrEmpty(inputName.TabName.Trim()))
11272                     {
11273                         arg.tw = tw;
11274                         arg.id = inputName.TabName.Trim();
11275                     }
11276                     else
11277                     {
11278                         return;
11279                     }
11280                 }
11281             }
11282
11283             using (FormInfo _info = new FormInfo(this, Properties.Resources.RemoveCommandText1,
11284                                                  RemoveCommand_DoWork,
11285                                                  null,
11286                                                  arg))
11287             {
11288                 _info.ShowDialog();
11289                 string ret = (string)_info.Result;
11290                 if (!string.IsNullOrEmpty(ret))
11291                     MessageBox.Show(Properties.Resources.FRMessage2 + ret);
11292                 else
11293                     MessageBox.Show(Properties.Resources.FRMessage3);
11294             }
11295         }
11296
11297         private void FriendshipMenuItem_Click(object sender, EventArgs e)
11298         {
11299             string id = "";
11300             if (_curPost != null)
11301                 id = _curPost.ScreenName;
11302
11303             ShowFriendship(id);
11304         }
11305
11306         private class ShowFriendshipArgs
11307         {
11308             public Twitter tw;
11309             public class FriendshipInfo
11310             {
11311                 public string id = "";
11312                 public bool isFollowing = false;
11313                 public bool isFollowed = false;
11314                 public bool isError = false;
11315                 public FriendshipInfo(string id)
11316                 {
11317                     this.id = id;
11318                 }
11319             }
11320             public List<FriendshipInfo> ids = new List<FriendshipInfo>();
11321         }
11322
11323         private void ShowFriendship_DoWork(object sender, DoWorkEventArgs e)
11324         {
11325             ShowFriendshipArgs arg = (ShowFriendshipArgs)e.Argument;
11326             string result = "";
11327             foreach (ShowFriendshipArgs.FriendshipInfo fInfo in arg.ids)
11328             {
11329                 string rt = arg.tw.GetFriendshipInfo(fInfo.id, ref fInfo.isFollowing, ref fInfo.isFollowed);
11330                 if (!string.IsNullOrEmpty(rt))
11331                 {
11332                     if (string.IsNullOrEmpty(result)) result = rt;
11333                     fInfo.isError = true;
11334                 }
11335             }
11336             e.Result = result;
11337         }
11338
11339         private void ShowFriendship(string id)
11340         {
11341             ShowFriendshipArgs args = new ShowFriendshipArgs();
11342             args.tw = tw;
11343             using (InputTabName inputName = new InputTabName())
11344             {
11345                 inputName.FormTitle = "Show Friendships";
11346                 inputName.FormDescription = Properties.Resources.FRMessage1;
11347                 inputName.TabName = id;
11348                 if (inputName.ShowDialog() == DialogResult.OK &&
11349                     !string.IsNullOrEmpty(inputName.TabName.Trim()))
11350                 {
11351                     string ret = "";
11352                     args.ids.Add(new ShowFriendshipArgs.FriendshipInfo(inputName.TabName.Trim()));
11353                     using (FormInfo _info = new FormInfo(this, Properties.Resources.ShowFriendshipText1,
11354                                                          ShowFriendship_DoWork,
11355                                                          null,
11356                                                          args))
11357                     {
11358                         _info.ShowDialog();
11359                         ret = (string)_info.Result;
11360                     }
11361                     string result = "";
11362                     if (string.IsNullOrEmpty(ret))
11363                     {
11364                         if (args.ids[0].isFollowing)
11365                         {
11366                             result = Properties.Resources.GetFriendshipInfo1 + System.Environment.NewLine;
11367                         }
11368                         else
11369                         {
11370                             result = Properties.Resources.GetFriendshipInfo2 + System.Environment.NewLine;
11371                         }
11372                         if (args.ids[0].isFollowed)
11373                         {
11374                             result += Properties.Resources.GetFriendshipInfo3;
11375                         }
11376                         else
11377                         {
11378                             result += Properties.Resources.GetFriendshipInfo4;
11379                         }
11380                         result = args.ids[0].id + Properties.Resources.GetFriendshipInfo5 + System.Environment.NewLine + result;
11381                     }
11382                     else
11383                     {
11384                         result = ret;
11385                     }
11386                     MessageBox.Show(result);
11387                 }
11388             }
11389         }
11390
11391         private void ShowFriendship(string[] ids)
11392         {
11393             foreach (string id in ids)
11394             {
11395                 string ret = "";
11396                 ShowFriendshipArgs args = new ShowFriendshipArgs();
11397                 args.tw = tw;
11398                 args.ids.Add(new ShowFriendshipArgs.FriendshipInfo(id.Trim()));
11399                 using (FormInfo _info = new FormInfo(this, Properties.Resources.ShowFriendshipText1,
11400                                                      ShowFriendship_DoWork,
11401                                                      null,
11402                                                      args))
11403                 {
11404                     _info.ShowDialog();
11405                     ret = (string)_info.Result;
11406                 }
11407                 string result = "";
11408                 ShowFriendshipArgs.FriendshipInfo fInfo = args.ids[0];
11409                 string ff = "";
11410                 if (string.IsNullOrEmpty(ret))
11411                 {
11412                     ff = "  ";
11413                     if (fInfo.isFollowing)
11414                     {
11415                         ff += Properties.Resources.GetFriendshipInfo1;
11416                     }
11417                     else
11418                     {
11419                         ff += Properties.Resources.GetFriendshipInfo2;
11420                     }
11421
11422                     ff += System.Environment.NewLine + "  ";
11423                     if (fInfo.isFollowed)
11424                     {
11425                         ff += Properties.Resources.GetFriendshipInfo3;
11426                     }
11427                     else
11428                     {
11429                         ff += Properties.Resources.GetFriendshipInfo4;
11430                     }
11431                     result += fInfo.id + Properties.Resources.GetFriendshipInfo5 + System.Environment.NewLine + ff;
11432                     if (fInfo.isFollowing)
11433                     {
11434                         if (MessageBox.Show(
11435                             Properties.Resources.GetFriendshipInfo7 + System.Environment.NewLine + result, Properties.Resources.GetFriendshipInfo8,
11436                             MessageBoxButtons.YesNo,
11437                             MessageBoxIcon.Question,
11438                             MessageBoxDefaultButton.Button2) == DialogResult.Yes)
11439                         {
11440                             RemoveCommand(fInfo.id, true);
11441                         }
11442                     }
11443                     else
11444                     {
11445                         MessageBox.Show(result);
11446                     }
11447                 }
11448                 else
11449                 {
11450                     MessageBox.Show(ret);
11451                 }
11452             }
11453         }
11454
11455         private void OwnStatusMenuItem_Click(object sender, EventArgs e)
11456         {
11457             doShowUserStatus(tw.Username, false);
11458             //if (!string.IsNullOrEmpty(tw.UserInfoXml))
11459             //{
11460             //    doShowUserStatus(tw.Username, false);
11461             //}
11462             //else
11463             //{
11464             //    MessageBox.Show(Properties.Resources.ShowYourProfileText1, "Your status", MessageBoxButtons.OK, MessageBoxIcon.Information);
11465             //    return;
11466             //}
11467         }
11468
11469         // TwitterIDでない固定文字列を調べる(文字列検証のみ 実際に取得はしない)
11470         // URLから切り出した文字列を渡す
11471
11472         public bool IsTwitterId(string name)
11473         {
11474             if (SettingDialog.TwitterConfiguration.NonUsernamePaths == null || SettingDialog.TwitterConfiguration.NonUsernamePaths.Length == 0)
11475                 return !Regex.Match(name, @"^(about|jobs|tos|privacy|who_to_follow|download|messages)$", RegexOptions.IgnoreCase).Success;
11476             else
11477                 return !SettingDialog.TwitterConfiguration.NonUsernamePaths.Contains(name.ToLower());
11478         }
11479
11480         private string GetUserId()
11481         {
11482             Match m = Regex.Match(this._postBrowserStatusText, @"^https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)(/status(es)?/[0-9]+)?$");
11483             if (m.Success && IsTwitterId(m.Result("${ScreenName}")))
11484                 return m.Result("${ScreenName}");
11485             else
11486                 return null;
11487         }
11488
11489         private void FollowContextMenuItem_Click(object sender, EventArgs e)
11490         {
11491             string name = GetUserId();
11492             if (name != null) FollowCommand(name);
11493         }
11494
11495         private void RemoveContextMenuItem_Click(object sender, EventArgs e)
11496         {
11497             string name = GetUserId();
11498             if (name != null) RemoveCommand(name, false);
11499         }
11500
11501         private void FriendshipContextMenuItem_Click(object sender, EventArgs e)
11502         {
11503             string name = GetUserId();
11504             if (name != null) ShowFriendship(name);
11505         }
11506
11507         private void FriendshipAllMenuItem_Click(object sender, EventArgs e)
11508         {
11509             MatchCollection ma = Regex.Matches(this.PostBrowser.DocumentText, @"href=""https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)(/status(es)?/[0-9]+)?""");
11510             List<string> ids = new List<string>();
11511             foreach (Match mu in ma)
11512             {
11513                 if (mu.Result("${ScreenName}").ToLower() != tw.Username.ToLower())
11514                 {
11515                     ids.Add(mu.Result("${ScreenName}"));
11516                 }
11517             }
11518             ShowFriendship(ids.ToArray());
11519         }
11520
11521         private void ShowUserStatusContextMenuItem_Click(object sender, EventArgs e)
11522         {
11523             string name = GetUserId();
11524             if (name != null) ShowUserStatus(name);
11525         }
11526
11527         private void SearchPostsDetailToolStripMenuItem_Click(object sender, EventArgs e)
11528         {
11529             string name = GetUserId();
11530             if (name != null) AddNewTabForUserTimeline(name);
11531         }
11532
11533         private void SearchAtPostsDetailToolStripMenuItem_Click(object sender, EventArgs e)
11534         {
11535             string name = GetUserId();
11536             if (name != null) AddNewTabForSearch("@" + name);
11537         }
11538
11539         private void IdeographicSpaceToSpaceToolStripMenuItem_Click(object sender, EventArgs e)
11540         {
11541             _modifySettingCommon = true;
11542         }
11543
11544         private void ToolStripFocusLockMenuItem_CheckedChanged(object sender, EventArgs e)
11545         {
11546             _modifySettingCommon = true;
11547         }
11548
11549         private void doQuote()
11550         {
11551             //QT @id:内容
11552             //返信先情報付加
11553             if (this.ExistCurrentPost)
11554             {
11555                 if (_curPost.IsDm ||
11556                     !StatusText.Enabled) return;
11557
11558                 if (_curPost.IsProtect)
11559                 {
11560                     MessageBox.Show("Protected.");
11561                     return;
11562                 }
11563                 string rtdata = _curPost.Text;
11564                 rtdata = CreateRetweetUnofficial(rtdata, this.StatusText.Multiline);
11565
11566                 StatusText.Text = " QT @" + _curPost.ScreenName + ": " + rtdata;
11567                 if (_curPost.RetweetedId == null)
11568                 {
11569                     _reply_to_id = _curPost.StatusId;
11570                 }
11571                 else
11572                 {
11573                     _reply_to_id = _curPost.RetweetedId.Value;
11574                 }
11575                 _reply_to_name = _curPost.ScreenName;
11576
11577                 StatusText.SelectionStart = 0;
11578                 StatusText.Focus();
11579             }
11580         }
11581
11582         private void QuoteStripMenuItem_Click(object sender, EventArgs e) // Handles QuoteStripMenuItem.Click, QtOpMenuItem.Click
11583         {
11584             doQuote();
11585         }
11586
11587         private void SearchButton_Click(object sender, EventArgs e)
11588         {
11589             //公式検索
11590             Control pnl = ((Control)sender).Parent;
11591             if (pnl == null) return;
11592             string tbName = pnl.Parent.Text;
11593             TabClass tb = _statuses.Tabs[tbName];
11594             ComboBox cmb = (ComboBox)pnl.Controls["comboSearch"];
11595             ComboBox cmbLang = (ComboBox)pnl.Controls["comboLang"];
11596             ComboBox cmbusline = (ComboBox)pnl.Controls["comboUserline"];
11597             cmb.Text = cmb.Text.Trim();
11598             // 検索式演算子 OR についてのみ大文字しか認識しないので強制的に大文字とする
11599             bool Quote = false;
11600             StringBuilder buf = new StringBuilder();
11601             char[] c = cmb.Text.ToCharArray();
11602             for (int cnt = 0; cnt < cmb.Text.Length; cnt++)
11603             {
11604                 if (cnt > cmb.Text.Length - 4)
11605                 {
11606                     buf.Append(cmb.Text.Substring(cnt));
11607                     break;
11608                 }
11609                 if (c[cnt] == '"')
11610                 {
11611                     Quote = !Quote;
11612                 }
11613                 else
11614                 {
11615                     if (!Quote && cmb.Text.Substring(cnt, 4).Equals(" or ", StringComparison.OrdinalIgnoreCase))
11616                     {
11617                         buf.Append(" OR ");
11618                         cnt += 3;
11619                         continue;
11620                     }
11621                 }
11622                 buf.Append(c[cnt]);
11623             }
11624             cmb.Text = buf.ToString();
11625
11626             tb.SearchWords = cmb.Text;
11627             tb.SearchLang = cmbLang.Text;
11628             if (string.IsNullOrEmpty(cmb.Text))
11629             {
11630                 ((DetailsListView)ListTab.SelectedTab.Tag).Focus();
11631                 SaveConfigsTabs();
11632                 return;
11633             }
11634             if (tb.IsQueryChanged())
11635             {
11636                 int idx = ((ComboBox)pnl.Controls["comboSearch"]).Items.IndexOf(tb.SearchWords);
11637                 if (idx > -1) ((ComboBox)pnl.Controls["comboSearch"]).Items.RemoveAt(idx);
11638                 ((ComboBox)pnl.Controls["comboSearch"]).Items.Insert(0, tb.SearchWords);
11639                 cmb.Text = tb.SearchWords;
11640                 cmb.SelectAll();
11641                 DetailsListView lst = (DetailsListView)pnl.Parent.Tag;
11642                 this.PurgeListViewItemCache();
11643                 lst.VirtualListSize = 0;
11644                 _statuses.ClearTabIds(tbName);
11645                 SaveConfigsTabs();   //検索条件の保存
11646             }
11647
11648             GetTimeline(MyCommon.WORKERTYPE.PublicSearch, 1, 0, tbName);
11649             ((DetailsListView)ListTab.SelectedTab.Tag).Focus();
11650         }
11651
11652         private void RefreshMoreStripMenuItem_Click(object sender, EventArgs e)
11653         {
11654             //もっと前を取得
11655             DoRefreshMore();
11656         }
11657
11658         private void UndoRemoveTabMenuItem_Click(object sender, EventArgs e)
11659         {
11660             if (_statuses.RemovedTab.Count == 0)
11661             {
11662                 MessageBox.Show("There isn't removed tab.", "Undo", MessageBoxButtons.OK, MessageBoxIcon.Information);
11663                 return;
11664             }
11665             else
11666             {
11667                 TabClass tb = _statuses.RemovedTab.Pop();
11668                 if (tb.TabType == MyCommon.TabUsageType.Related)
11669                 {
11670                     var relatedTab = _statuses.GetTabByType(MyCommon.TabUsageType.Related);
11671                     if (relatedTab != null)
11672                     {
11673                         // 関連発言なら既存のタブを置き換える
11674                         tb.TabName = relatedTab.TabName;
11675                         this.ClearTab(tb.TabName, false);
11676                         _statuses.Tabs[tb.TabName] = tb;
11677                         for (int i = 0; i < ListTab.TabPages.Count; i++)
11678                         {
11679                             if (tb.TabName == ListTab.TabPages[i].Text)
11680                             {
11681                                 ListTab.SelectedIndex = i;
11682                                 ListTabSelect(ListTab.TabPages[i]);
11683                                 break;
11684                             }
11685                         }
11686                     }
11687                     else
11688                     {
11689                         const string TabName = "Related Tweets";
11690                         string renamed = TabName;
11691                         for (int i = 2; i <= 100; i++)
11692                         {
11693                             if (!_statuses.ContainsTab(renamed)) break;
11694                             renamed = TabName + i.ToString();
11695                         }
11696                         tb.TabName = renamed;
11697                         AddNewTab(renamed, false, tb.TabType, tb.ListInfo);
11698                         _statuses.Tabs.Add(renamed, tb);  // 後に
11699                         ListTab.SelectedIndex = ListTab.TabPages.Count - 1;
11700                         ListTabSelect(ListTab.TabPages[ListTab.TabPages.Count - 1]);
11701                     }
11702                 }
11703                 else
11704                 {
11705                     string renamed = tb.TabName;
11706                     for (int i = 1; i < int.MaxValue; i++)
11707                     {
11708                         if (!_statuses.ContainsTab(renamed)) break;
11709                         renamed = tb.TabName + "(" + i.ToString() + ")";
11710                     }
11711                     tb.TabName = renamed;
11712                     _statuses.Tabs.Add(renamed, tb);  // 先に
11713                     AddNewTab(renamed, false, tb.TabType, tb.ListInfo);
11714                     ListTab.SelectedIndex = ListTab.TabPages.Count - 1;
11715                     ListTabSelect(ListTab.TabPages[ListTab.TabPages.Count - 1]);
11716                 }
11717                 SaveConfigsTabs();
11718             }
11719         }
11720
11721         private void doMoveToRTHome()
11722         {
11723             if (_curList.SelectedIndices.Count > 0)
11724             {
11725                 PostClass post = GetCurTabPost(_curList.SelectedIndices[0]);
11726                 if (post.RetweetedId != null)
11727                 {
11728                     OpenUriAsync("https://twitter.com/" + GetCurTabPost(_curList.SelectedIndices[0]).RetweetedBy);
11729                 }
11730             }
11731         }
11732
11733         private void MoveToRTHomeMenuItem_Click(object sender, EventArgs e)
11734         {
11735             doMoveToRTHome();
11736         }
11737
11738         private void IdFilterAddMenuItem_Click(object sender, EventArgs e)
11739         {
11740             string name = GetUserId();
11741             if (name != null)
11742             {
11743                 string tabName;
11744
11745                 //未選択なら処理終了
11746                 if (_curList.SelectedIndices.Count == 0) return;
11747
11748                 //タブ選択(or追加)
11749                 if (!SelectTab(out tabName)) return;
11750
11751                 bool mv = false;
11752                 bool mk = false;
11753                 MoveOrCopy(ref mv, ref mk);
11754
11755                 PostFilterRule fc = new PostFilterRule();
11756                 fc.FilterName = name;
11757                 fc.UseNameField = true;
11758                 fc.MoveMatches = mv;
11759                 fc.MarkMatches = mk;
11760                 fc.UseRegex = false;
11761                 fc.FilterByUrl = false;
11762                 _statuses.Tabs[tabName].AddFilter(fc);
11763
11764                 this.ApplyPostFilters();
11765                 SaveConfigsTabs();
11766             }
11767         }
11768
11769         private void ListManageUserContextToolStripMenuItem_Click(object sender, EventArgs e)
11770         {
11771             string user;
11772
11773             ToolStripMenuItem menuItem = (ToolStripMenuItem)sender;
11774
11775             if (menuItem.Owner == this.ContextMenuPostBrowser)
11776             {
11777                 user = GetUserId();
11778                 if (user == null) return;
11779             }
11780             else if (this._curPost != null)
11781             {
11782                 user = this._curPost.ScreenName;
11783             }
11784             else
11785             {
11786                 return;
11787             }
11788
11789             if (TabInformations.GetInstance().SubscribableLists.Count == 0)
11790             {
11791                 string res = this.tw.GetListsApi();
11792
11793                 if (!string.IsNullOrEmpty(res))
11794                 {
11795                     MessageBox.Show("Failed to get lists. (" + res + ")");
11796                     return;
11797                 }
11798             }
11799
11800             using (MyLists listSelectForm = new MyLists(user, this.tw))
11801             {
11802                 listSelectForm.ShowDialog(this);
11803             }
11804         }
11805
11806         private void SearchControls_Enter(object sender, EventArgs e)
11807         {
11808             Control pnl = (Control)sender;
11809             foreach (Control ctl in pnl.Controls)
11810             {
11811                 ctl.TabStop = true;
11812             }
11813         }
11814
11815         private void SearchControls_Leave(object sender, EventArgs e)
11816         {
11817             Control pnl = (Control)sender;
11818             foreach (Control ctl in pnl.Controls)
11819             {
11820                 ctl.TabStop = false;
11821             }
11822         }
11823
11824         private void PublicSearchQueryMenuItem_Click(object sender, EventArgs e)
11825         {
11826             if (ListTab.SelectedTab != null)
11827             {
11828                 if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType != MyCommon.TabUsageType.PublicSearch) return;
11829                 ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"].Focus();
11830             }
11831         }
11832
11833         private void UseHashtagMenuItem_Click(object sender, EventArgs e)
11834         {
11835             Match m = Regex.Match(this._postBrowserStatusText, @"^https?://twitter.com/search\?q=%23(?<hash>.+)$");
11836             if (m.Success)
11837             {
11838                 HashMgr.SetPermanentHash("#" + Uri.UnescapeDataString(m.Result("${hash}")));
11839                 HashStripSplitButton.Text = HashMgr.UseHash;
11840                 HashToggleMenuItem.Checked = true;
11841                 HashToggleToolStripMenuItem.Checked = true;
11842                 //使用ハッシュタグとして設定
11843                 _modifySettingCommon = true;
11844             }
11845         }
11846
11847         private void StatusLabel_DoubleClick(object sender, EventArgs e)
11848         {
11849             MessageBox.Show(StatusLabel.TextHistory, "Logs", MessageBoxButtons.OK, MessageBoxIcon.None);
11850         }
11851
11852         private void HashManageMenuItem_Click(object sender, EventArgs e)
11853         {
11854             DialogResult rslt = DialogResult.Cancel;
11855             try
11856             {
11857                 rslt = HashMgr.ShowDialog();
11858             }
11859             catch (Exception)
11860             {
11861                 return;
11862             }
11863             this.TopMost = SettingDialog.AlwaysTop;
11864             if (rslt == DialogResult.Cancel) return;
11865             if (!string.IsNullOrEmpty(HashMgr.UseHash))
11866             {
11867                 HashStripSplitButton.Text = HashMgr.UseHash;
11868                 HashToggleMenuItem.Checked = true;
11869                 HashToggleToolStripMenuItem.Checked = true;
11870             }
11871             else
11872             {
11873                 HashStripSplitButton.Text = "#[-]";
11874                 HashToggleMenuItem.Checked = false;
11875                 HashToggleToolStripMenuItem.Checked = false;
11876             }
11877             //if (HashMgr.IsInsert && HashMgr.UseHash != "")
11878             //{
11879             //    int sidx = StatusText.SelectionStart;
11880             //    string hash = HashMgr.UseHash + " ";
11881             //    if (sidx > 0)
11882             //    {
11883             //        if (StatusText.Text.Substring(sidx - 1, 1) != " ")
11884             //            hash = " " + hash;
11885             //    }
11886             //    StatusText.Text = StatusText.Text.Insert(sidx, hash);
11887             //    sidx += hash.Length;
11888             //    StatusText.SelectionStart = sidx;
11889             //    StatusText.Focus();
11890             //}
11891             _modifySettingCommon = true;
11892             this.StatusText_TextChanged(null, null);
11893         }
11894
11895         private void HashToggleMenuItem_Click(object sender, EventArgs e)
11896         {
11897             HashMgr.ToggleHash();
11898             if (!string.IsNullOrEmpty(HashMgr.UseHash))
11899             {
11900                 HashStripSplitButton.Text = HashMgr.UseHash;
11901                 HashToggleMenuItem.Checked = true;
11902                 HashToggleToolStripMenuItem.Checked = true;
11903             }
11904             else
11905             {
11906                 HashStripSplitButton.Text = "#[-]";
11907                 HashToggleMenuItem.Checked = false;
11908                 HashToggleToolStripMenuItem.Checked = false;
11909             }
11910             _modifySettingCommon = true;
11911             this.StatusText_TextChanged(null, null);
11912         }
11913
11914         private void HashStripSplitButton_ButtonClick(object sender, EventArgs e)
11915         {
11916             HashToggleMenuItem_Click(null, null);
11917         }
11918
11919         private void MenuItemOperate_DropDownOpening(object sender, EventArgs e)
11920         {
11921             if (ListTab.SelectedTab == null) return;
11922             if (_statuses == null || _statuses.Tabs == null || !_statuses.Tabs.ContainsKey(ListTab.SelectedTab.Text)) return;
11923             if (!this.ExistCurrentPost)
11924             {
11925                 this.ReplyOpMenuItem.Enabled = false;
11926                 this.ReplyAllOpMenuItem.Enabled = false;
11927                 this.DmOpMenuItem.Enabled = false;
11928                 this.ShowProfMenuItem.Enabled = false;
11929                 this.ShowUserTimelineToolStripMenuItem.Enabled = false;
11930                 this.ListManageMenuItem.Enabled = false;
11931                 this.OpenFavOpMenuItem.Enabled = false;
11932                 this.CreateTabRuleOpMenuItem.Enabled = false;
11933                 this.CreateIdRuleOpMenuItem.Enabled = false;
11934                 this.ReadOpMenuItem.Enabled = false;
11935                 this.UnreadOpMenuItem.Enabled = false;
11936             }
11937             else
11938             {
11939                 this.ReplyOpMenuItem.Enabled = true;
11940                 this.ReplyAllOpMenuItem.Enabled = true;
11941                 this.DmOpMenuItem.Enabled = true;
11942                 this.ShowProfMenuItem.Enabled = true;
11943                 this.ShowUserTimelineToolStripMenuItem.Enabled = true;
11944                 this.ListManageMenuItem.Enabled = true;
11945                 this.OpenFavOpMenuItem.Enabled = true;
11946                 this.CreateTabRuleOpMenuItem.Enabled = true;
11947                 this.CreateIdRuleOpMenuItem.Enabled = true;
11948                 this.ReadOpMenuItem.Enabled = true;
11949                 this.UnreadOpMenuItem.Enabled = true;
11950             }
11951
11952             if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.DirectMessage || !this.ExistCurrentPost || _curPost.IsDm)
11953             {
11954                 this.FavOpMenuItem.Enabled = false;
11955                 this.UnFavOpMenuItem.Enabled = false;
11956                 this.OpenStatusOpMenuItem.Enabled = false;
11957                 this.OpenFavotterOpMenuItem.Enabled = false;
11958                 this.ShowRelatedStatusesMenuItem2.Enabled = false;
11959                 this.RtOpMenuItem.Enabled = false;
11960                 this.RtUnOpMenuItem.Enabled = false;
11961                 this.QtOpMenuItem.Enabled = false;
11962                 this.FavoriteRetweetMenuItem.Enabled = false;
11963                 this.FavoriteRetweetUnofficialMenuItem.Enabled = false;
11964                 if (this.ExistCurrentPost && _curPost.IsDm) this.DelOpMenuItem.Enabled = true;
11965             }
11966             else
11967             {
11968                 this.FavOpMenuItem.Enabled = true;
11969                 this.UnFavOpMenuItem.Enabled = true;
11970                 this.OpenStatusOpMenuItem.Enabled = true;
11971                 this.OpenFavotterOpMenuItem.Enabled = true;
11972                 this.ShowRelatedStatusesMenuItem2.Enabled = true;  //PublicSearchの時問題出るかも
11973
11974                 if (_curPost.IsMe)
11975                 {
11976                     this.RtOpMenuItem.Enabled = false;
11977                     this.FavoriteRetweetMenuItem.Enabled = false;
11978                     this.DelOpMenuItem.Enabled = true;
11979                 }
11980                 else
11981                 {
11982                     this.DelOpMenuItem.Enabled = false;
11983                     if (_curPost.IsProtect)
11984                     {
11985                         this.RtOpMenuItem.Enabled = false;
11986                         this.RtUnOpMenuItem.Enabled = false;
11987                         this.QtOpMenuItem.Enabled = false;
11988                         this.FavoriteRetweetMenuItem.Enabled = false;
11989                         this.FavoriteRetweetUnofficialMenuItem.Enabled = false;
11990                     }
11991                     else
11992                     {
11993                         this.RtOpMenuItem.Enabled = true;
11994                         this.RtUnOpMenuItem.Enabled = true;
11995                         this.QtOpMenuItem.Enabled = true;
11996                         this.FavoriteRetweetMenuItem.Enabled = true;
11997                         this.FavoriteRetweetUnofficialMenuItem.Enabled = true;
11998                     }
11999                 }
12000             }
12001
12002             if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType != MyCommon.TabUsageType.Favorites)
12003             {
12004                 this.RefreshPrevOpMenuItem.Enabled = true;
12005             }
12006             else
12007             {
12008                 this.RefreshPrevOpMenuItem.Enabled = false;
12009             }
12010             if (!this.ExistCurrentPost
12011                 || _curPost.InReplyToStatusId == null)
12012             {
12013                 OpenRepSourceOpMenuItem.Enabled = false;
12014             }
12015             else
12016             {
12017                 OpenRepSourceOpMenuItem.Enabled = true;
12018             }
12019             if (!this.ExistCurrentPost || string.IsNullOrEmpty(_curPost.RetweetedBy))
12020             {
12021                 OpenRterHomeMenuItem.Enabled = false;
12022             }
12023             else
12024             {
12025                 OpenRterHomeMenuItem.Enabled = true;
12026             }
12027         }
12028
12029         private void MenuItemTab_DropDownOpening(object sender, EventArgs e)
12030         {
12031             ContextMenuTabProperty_Opening(sender, null);
12032         }
12033
12034         public Twitter TwitterInstance
12035         {
12036             get { return tw; }
12037         }
12038
12039         private void SplitContainer3_SplitterMoved(object sender, SplitterEventArgs e)
12040         {
12041             if (this.WindowState == FormWindowState.Normal && !_initialLayout)
12042             {
12043                 _mySpDis3 = SplitContainer3.SplitterDistance;
12044                 _modifySettingLocal = true;
12045             }
12046         }
12047
12048         private void MenuItemEdit_DropDownOpening(object sender, EventArgs e)
12049         {
12050             if (_statuses.RemovedTab.Count == 0)
12051             {
12052                 UndoRemoveTabMenuItem.Enabled = false;
12053             }
12054             else
12055             {
12056                 UndoRemoveTabMenuItem.Enabled = true;
12057             }
12058             if (ListTab.SelectedTab != null)
12059             {
12060                 if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.PublicSearch)
12061                     PublicSearchQueryMenuItem.Enabled = true;
12062                 else
12063                     PublicSearchQueryMenuItem.Enabled = false;
12064             }
12065             else
12066             {
12067                 PublicSearchQueryMenuItem.Enabled = false;
12068             }
12069             if (!this.ExistCurrentPost)
12070             {
12071                 this.CopySTOTMenuItem.Enabled = false;
12072                 this.CopyURLMenuItem.Enabled = false;
12073                 this.CopyUserIdStripMenuItem.Enabled = false;
12074             }
12075             else
12076             {
12077                 this.CopySTOTMenuItem.Enabled = true;
12078                 this.CopyURLMenuItem.Enabled = true;
12079                 this.CopyUserIdStripMenuItem.Enabled = true;
12080                 if (_curPost.IsDm) this.CopyURLMenuItem.Enabled = false;
12081                 if (_curPost.IsProtect) this.CopySTOTMenuItem.Enabled = false;
12082             }
12083         }
12084
12085         private void NotifyIcon1_MouseMove(object sender, MouseEventArgs e)
12086         {
12087             SetNotifyIconText();
12088         }
12089
12090         private void UserStatusToolStripMenuItem_Click(object sender, EventArgs e)
12091         {
12092             string id = "";
12093             if (_curPost != null)
12094             {
12095                 id = _curPost.ScreenName;
12096             }
12097             ShowUserStatus(id);
12098         }
12099
12100         private class GetUserInfoArgs
12101         {
12102             public Twitter tw;
12103             public string id;
12104             public TwitterUser user;
12105         }
12106
12107         private void GetUserInfo_DoWork(object sender, DoWorkEventArgs e)
12108         {
12109             GetUserInfoArgs args = (GetUserInfoArgs)e.Argument;
12110             e.Result = args.tw.GetUserInfo(args.id, ref args.user);
12111         }
12112
12113         private void doShowUserStatus(string id, bool ShowInputDialog)
12114         {
12115             TwitterUser user = null;
12116             GetUserInfoArgs args = new GetUserInfoArgs();
12117             if (ShowInputDialog)
12118             {
12119                 using (InputTabName inputName = new InputTabName())
12120                 {
12121                     inputName.FormTitle = "Show UserStatus";
12122                     inputName.FormDescription = Properties.Resources.FRMessage1;
12123                     inputName.TabName = id;
12124                     if (inputName.ShowDialog() == DialogResult.OK &&
12125                         !string.IsNullOrEmpty(inputName.TabName.Trim()))
12126                     {
12127                         id = inputName.TabName.Trim();
12128                         args.tw = tw;
12129                         args.id = id;
12130                         args.user = user;
12131                         using (FormInfo _info = new FormInfo(this, Properties.Resources.doShowUserStatusText1,
12132                                                              GetUserInfo_DoWork,
12133                                                              null,
12134                                                              args))
12135                         {
12136                             _info.ShowDialog();
12137                             string ret = (string)_info.Result;
12138                             if (string.IsNullOrEmpty(ret))
12139                                 doShowUserStatus(args.user);
12140                             else
12141                                 MessageBox.Show(ret);
12142                         }
12143                     }
12144                 }
12145             }
12146             else
12147             {
12148                 args.tw = tw;
12149                 args.id = id;
12150                 args.user = user;
12151                 using (FormInfo _info = new FormInfo(this, Properties.Resources.doShowUserStatusText1,
12152                                                      GetUserInfo_DoWork,
12153                                                      null,
12154                                                      args))
12155                 {
12156                     _info.ShowDialog();
12157                     string ret = (string)_info.Result;
12158                     if (string.IsNullOrEmpty(ret))
12159                     {
12160                         doShowUserStatus(args.user);
12161                     }
12162                     else
12163                     {
12164                         MessageBox.Show(ret);
12165                     }
12166                 }
12167             }
12168         }
12169
12170         private void doShowUserStatus(TwitterUser user)
12171         {
12172             using (var userinfo = new UserInfoDialog(this, this.tw))
12173             {
12174                 userinfo.DisplayUser = user;
12175                 userinfo.ShowDialog(this);
12176                 this.Activate();
12177                 this.BringToFront();
12178             }
12179         }
12180
12181         private void ShowUserStatus(string id, bool ShowInputDialog)
12182         {
12183             doShowUserStatus(id, ShowInputDialog);
12184         }
12185
12186         private void ShowUserStatus(string id)
12187         {
12188             doShowUserStatus(id, true);
12189         }
12190
12191         private void FollowToolStripMenuItem_Click(object sender, EventArgs e)
12192         {
12193             if (NameLabel.Tag != null)
12194             {
12195                 string id = (string)NameLabel.Tag;
12196                 if (id != tw.Username)
12197                 {
12198                     FollowCommand(id);
12199                 }
12200             }
12201         }
12202
12203         private void UnFollowToolStripMenuItem_Click(object sender, EventArgs e)
12204         {
12205             if (NameLabel.Tag != null)
12206             {
12207                 string id = (string)NameLabel.Tag;
12208                 if (id != tw.Username)
12209                 {
12210                     RemoveCommand(id, false);
12211                 }
12212             }
12213         }
12214
12215         private void ShowFriendShipToolStripMenuItem_Click(object sender, EventArgs e)
12216         {
12217             if (NameLabel.Tag != null)
12218             {
12219                 string id = (string)NameLabel.Tag;
12220                 if (id != tw.Username)
12221                 {
12222                     ShowFriendship(id);
12223                 }
12224             }
12225         }
12226
12227         private void ShowUserStatusToolStripMenuItem_Click(object sender, EventArgs e)
12228         {
12229             if (NameLabel.Tag != null)
12230             {
12231                 string id = (string)NameLabel.Tag;
12232                 ShowUserStatus(id, false);
12233             }
12234         }
12235
12236         private void SearchPostsDetailNameToolStripMenuItem_Click(object sender, EventArgs e)
12237         {
12238             if (NameLabel.Tag != null)
12239             {
12240                 string id = (string)NameLabel.Tag;
12241                 AddNewTabForUserTimeline(id);
12242             }
12243         }
12244
12245         private void SearchAtPostsDetailNameToolStripMenuItem_Click(object sender, EventArgs e)
12246         {
12247             if (NameLabel.Tag != null)
12248             {
12249                 string id = (string)NameLabel.Tag;
12250                 AddNewTabForSearch("@" + id);
12251             }
12252         }
12253
12254         private void ShowProfileMenuItem_Click(object sender, EventArgs e)
12255         {
12256             if (_curPost != null)
12257             {
12258                 ShowUserStatus(_curPost.ScreenName, false);
12259             }
12260         }
12261
12262         private void GetRetweet_DoWork(object sender, DoWorkEventArgs e)
12263         {
12264             int counter = 0;
12265
12266             long statusid;
12267             if (_curPost.RetweetedId != null)
12268             {
12269                 statusid = _curPost.RetweetedId.Value;
12270             }
12271             else
12272             {
12273                 statusid = _curPost.StatusId;
12274             }
12275             tw.GetStatus_Retweeted_Count(statusid, ref counter);
12276
12277             e.Result = counter;
12278         }
12279
12280         private void RtCountMenuItem_Click(object sender, EventArgs e)
12281         {
12282             if (this.ExistCurrentPost)
12283             {
12284                 using (FormInfo _info = new FormInfo(this, Properties.Resources.RtCountMenuItem_ClickText1,
12285                                                      GetRetweet_DoWork))
12286                 {
12287                     int retweet_count = 0;
12288
12289                     // ダイアログ表示
12290                     _info.ShowDialog();
12291                     retweet_count = (int)_info.Result;
12292                     if (retweet_count < 0)
12293                     {
12294                         MessageBox.Show(Properties.Resources.RtCountText2);
12295                     }
12296                     else
12297                     {
12298                         MessageBox.Show(retweet_count.ToString() + Properties.Resources.RtCountText1);
12299                     }
12300                 }
12301             }
12302         }
12303
12304         private HookGlobalHotkey _hookGlobalHotkey;
12305         public TweenMain()
12306         {
12307             this.http = MyCommon.CreateHttpClient();
12308             _hookGlobalHotkey = new HookGlobalHotkey(this);
12309
12310             // この呼び出しは、Windows フォーム デザイナで必要です。
12311             InitializeComponent();
12312
12313             // InitializeComponent() 呼び出しの後で初期化を追加します。
12314
12315             this.SettingDialog.IntervalChanged += this.TimerInterval_Changed;
12316             this.TimerTimeline.Elapsed += this.TimerTimeline_Elapsed;
12317             this._hookGlobalHotkey.HotkeyPressed += _hookGlobalHotkey_HotkeyPressed;
12318             this.gh.NotifyClicked += GrowlHelper_Callback;
12319
12320             // メイリオフォント指定時にタブの最小幅が広くなる問題の対策
12321             this.ListTab.HandleCreated += (s, e) => Win32Api.SetMinTabWidth((TabControl)s, 40);
12322
12323             this._apiGauge = new ToolStripAPIGauge();
12324             this._apiGauge.BorderSides = ToolStripStatusLabelBorderSides.Right;
12325             this.StatusStrip1.Items.Insert(2, this._apiGauge);
12326
12327             this.ImageSelector.Visible = false;
12328             this.ImageSelector.Enabled = false;
12329             this.ImageSelector.FilePickDialog = OpenFileDialog1;
12330
12331             this.ReplaceAppName();
12332         }
12333
12334         private void _hookGlobalHotkey_HotkeyPressed(object sender, KeyEventArgs e)
12335         {
12336             if ((this.WindowState == FormWindowState.Normal || this.WindowState == FormWindowState.Maximized) && this.Visible && Form.ActiveForm == this)
12337             {
12338                 //アイコン化
12339                 this.Visible = false;
12340             }
12341             else if (Form.ActiveForm == null)
12342             {
12343                 this.Visible = true;
12344                 if (this.WindowState == FormWindowState.Minimized) this.WindowState = FormWindowState.Normal;
12345                 this.Activate();
12346                 this.BringToFront();
12347                 this.StatusText.Focus();
12348             }
12349         }
12350
12351         private void UserPicture_MouseEnter(object sender, EventArgs e)
12352         {
12353             this.UserPicture.Cursor = Cursors.Hand;
12354         }
12355
12356         private void UserPicture_MouseLeave(object sender, EventArgs e)
12357         {
12358             this.UserPicture.Cursor = Cursors.Default;
12359         }
12360
12361         private void UserPicture_DoubleClick(object sender, EventArgs e)
12362         {
12363             if (NameLabel.Tag != null)
12364             {
12365                 OpenUriAsync(MyCommon.TwitterUrl + NameLabel.Tag.ToString());
12366             }
12367         }
12368
12369         private void SplitContainer2_MouseDoubleClick(object sender, MouseEventArgs e)
12370         {
12371             this.MultiLineMenuItem.PerformClick();
12372         }
12373
12374         public PostClass CurPost
12375         {
12376             get { return _curPost; }
12377         }
12378
12379         public bool IsPreviewEnable
12380         {
12381             get { return SettingDialog.PreviewEnable; }
12382         }
12383
12384 #region "画像投稿"
12385         private void ImageSelectMenuItem_Click(object sender, EventArgs e)
12386         {
12387             if (ImageSelector.Visible)
12388                 ImageSelector.EndSelection();
12389             else
12390                 ImageSelector.BeginSelection();
12391         }
12392
12393         private void SelectMedia_DragEnter(DragEventArgs e)
12394         {
12395             if (ImageSelector.HasUploadableService(((string[])e.Data.GetData(DataFormats.FileDrop, false))[0]))
12396             {
12397                 e.Effect = DragDropEffects.Copy;
12398                 return;
12399             }
12400             e.Effect = DragDropEffects.None;
12401         }
12402
12403         private void SelectMedia_DragOver(DragEventArgs e)
12404         {
12405             //何も触らない
12406         }
12407
12408         private void SelectMedia_DragDrop(DragEventArgs e)
12409         {
12410             this.Activate();
12411             this.BringToFront();
12412             ImageSelector.BeginSelection(((string[])e.Data.GetData(DataFormats.FileDrop, false))[0]);
12413             StatusText.Focus();
12414         }
12415
12416         private void ImageSelector_BeginSelecting(object sender, EventArgs e)
12417         {
12418             TimelinePanel.Visible = false;
12419             TimelinePanel.Enabled = false;
12420         }
12421
12422         private void ImageSelector_EndSelecting(object sender, EventArgs e)
12423         {
12424             TimelinePanel.Visible = true;
12425             TimelinePanel.Enabled = true;
12426             ((DetailsListView)ListTab.SelectedTab.Tag).Focus();
12427         }
12428
12429         private void ImageSelector_FilePickDialogOpening(object sender, EventArgs e)
12430         {
12431             this.AllowDrop = false;
12432         }
12433
12434         private void ImageSelector_FilePickDialogClosed(object sender, EventArgs e)
12435         {
12436             this.AllowDrop = true;
12437         }
12438
12439         private void ImageSelector_SelectedServiceChanged(object sender, EventArgs e)
12440         {
12441             if (ImageSelector.Visible)
12442             {
12443                 _modifySettingCommon = true;
12444                 SaveConfigsAll(true);
12445
12446                 if (ImageSelector.ServiceName.Equals("Twitter"))
12447                     this.StatusText_TextChanged(null, null);
12448             }
12449         }
12450
12451         private void ImageSelector_VisibleChanged(object sender, EventArgs e)
12452         {
12453             this.StatusText_TextChanged(null, null);
12454         }
12455 #endregion
12456
12457         private void ListManageToolStripMenuItem_Click(object sender, EventArgs e)
12458         {
12459             using (ListManage form = new ListManage(tw))
12460             {
12461                 form.ShowDialog(this);
12462             }
12463         }
12464
12465         public bool ModifySettingCommon
12466         {
12467             set { _modifySettingCommon = value; }
12468         }
12469
12470         public bool ModifySettingLocal
12471         {
12472             set { _modifySettingLocal = value; }
12473         }
12474
12475         public bool ModifySettingAtId
12476         {
12477             set { _modifySettingAtId = value; }
12478         }
12479
12480         private void SourceLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
12481         {
12482             string link = (string)SourceLinkLabel.Tag;
12483             if (!string.IsNullOrEmpty(link) && e.Button == MouseButtons.Left)
12484             {
12485                 OpenUriAsync(link);
12486             }
12487         }
12488
12489         private void SourceLinkLabel_MouseEnter(object sender, EventArgs e)
12490         {
12491             string link = (string)SourceLinkLabel.Tag;
12492             if (!string.IsNullOrEmpty(link))
12493             {
12494                 StatusLabelUrl.Text = MyCommon.ConvertToReadableUrl(link);
12495             }
12496         }
12497
12498         private void SourceLinkLabel_MouseLeave(object sender, EventArgs e)
12499         {
12500             SetStatusLabelUrl();
12501         }
12502
12503         private void MenuItemCommand_DropDownOpening(object sender, EventArgs e)
12504         {
12505             if (this.ExistCurrentPost && !_curPost.IsDm)
12506                 RtCountMenuItem.Enabled = true;
12507             else
12508                 RtCountMenuItem.Enabled = false;
12509
12510             //if (SettingDialog.UrlConvertAuto && SettingDialog.ShortenTco)
12511             //    TinyUrlConvertToolStripMenuItem.Enabled = false;
12512             //else
12513             //    TinyUrlConvertToolStripMenuItem.Enabled = true;
12514         }
12515
12516         private void CopyUserIdStripMenuItem_Click(object sender, EventArgs e)
12517         {
12518             CopyUserId();
12519         }
12520
12521         private void CopyUserId()
12522         {
12523             if (_curPost == null) return;
12524             string clstr = _curPost.ScreenName;
12525             try
12526             {
12527                 Clipboard.SetDataObject(clstr, false, 5, 100);
12528             }
12529             catch (Exception ex)
12530             {
12531                 MessageBox.Show(ex.Message);
12532             }
12533         }
12534
12535         private void ShowRelatedStatusesMenuItem_Click(object sender, EventArgs e) // Handles ShowRelatedStatusesMenuItem.Click, ShowRelatedStatusesMenuItem2.Click
12536         {
12537             if (this.ExistCurrentPost && !_curPost.IsDm)
12538             {
12539                 try
12540                 {
12541                     this.OpenRelatedTab(this._curPost);
12542                 }
12543                 catch (TabException ex)
12544                 {
12545                     MessageBox.Show(this, ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
12546                 }
12547             }
12548         }
12549
12550         /// <summary>
12551         /// 指定されたツイートに対する関連発言タブを開きます
12552         /// </summary>
12553         /// <param name="post">表示する対象となるツイート</param>
12554         /// <exception cref="TabException">名前の重複が多すぎてタブを作成できない場合</exception>
12555         private void OpenRelatedTab(PostClass post)
12556         {
12557             var tabRelated = this._statuses.GetTabByType(MyCommon.TabUsageType.Related);
12558             string tabName;
12559
12560             if (tabRelated == null)
12561             {
12562                 tabName = this._statuses.MakeTabName("Related Tweets");
12563
12564                 this.AddNewTab(tabName, false, MyCommon.TabUsageType.Related);
12565                 this._statuses.AddTab(tabName, MyCommon.TabUsageType.Related, null);
12566
12567                 tabRelated = this._statuses.GetTabByType(MyCommon.TabUsageType.Related);
12568                 tabRelated.UnreadManage = false;
12569                 tabRelated.Notify = false;
12570             }
12571             else
12572             {
12573                 tabName = tabRelated.TabName;
12574             }
12575
12576             tabRelated.RelationTargetPost = post;
12577             this.ClearTab(tabName, false);
12578
12579             for (int i = 0; i < this.ListTab.TabPages.Count; i++)
12580             {
12581                 var tabPage = this.ListTab.TabPages[i];
12582                 if (tabName == tabPage.Text)
12583                 {
12584                     this.ListTab.SelectedIndex = i;
12585                     this.ListTabSelect(tabPage);
12586                     break;
12587                 }
12588             }
12589
12590             this.GetTimeline(MyCommon.WORKERTYPE.Related, 1, 1, tabName);
12591         }
12592
12593         private void CacheInfoMenuItem_Click(object sender, EventArgs e)
12594         {
12595             StringBuilder buf = new StringBuilder();
12596             //buf.AppendFormat("キャッシュメモリ容量         : {0}bytes({1}MB)" + Environment.NewLine, IconCache.CacheMemoryLimit, ((ImageDictionary)IconCache).CacheMemoryLimit / 1048576);
12597             //buf.AppendFormat("物理メモリ使用割合           : {0}%" + Environment.NewLine, IconCache.PhysicalMemoryLimit);
12598             buf.AppendFormat("キャッシュエントリ保持数     : {0}" + Environment.NewLine, IconCache.CacheCount);
12599             buf.AppendFormat("キャッシュエントリ破棄数     : {0}" + Environment.NewLine, IconCache.CacheRemoveCount);
12600             MessageBox.Show(buf.ToString(), "アイコンキャッシュ使用状況");
12601         }
12602
12603         private void tw_UserIdChanged()
12604         {
12605             this._modifySettingCommon = true;
12606         }
12607
12608 #region "Userstream"
12609         private bool _isActiveUserstream = false;
12610
12611         private void tw_PostDeleted(long id)
12612         {
12613             try
12614             {
12615                 if (InvokeRequired && !IsDisposed)
12616                 {
12617                     Invoke((Action) (() =>
12618                            {
12619                                _statuses.RemovePostReserve(id);
12620                                if (_curTab != null && _statuses.Tabs[_curTab.Text].Contains(id))
12621                                {
12622                                    this.PurgeListViewItemCache();
12623                                    ((DetailsListView)_curTab.Tag).Update();
12624                                    if (_curPost != null && _curPost.StatusId == id) DispSelectedPost(true);
12625                                }
12626                            }));
12627                     return;
12628                 }
12629             }
12630             catch (ObjectDisposedException)
12631             {
12632                 return;
12633             }
12634             catch (InvalidOperationException)
12635             {
12636                 return;
12637             }
12638         }
12639
12640         private void tw_NewPostFromStream()
12641         {
12642             if (SettingDialog.ReadOldPosts)
12643             {
12644                 _statuses.SetRead(); //新着時未読クリア
12645             }
12646
12647             int rsltAddCount = _statuses.DistributePosts();
12648             lock (_syncObject)
12649             {
12650                 DateTime tm = DateTime.Now;
12651                 if (_tlTimestamps.ContainsKey(tm))
12652                 {
12653                     _tlTimestamps[tm] += rsltAddCount;
12654                 }
12655                 else
12656                 {
12657                     _tlTimestamps.Add(tm, rsltAddCount);
12658                 }
12659                 DateTime oneHour = DateTime.Now.Subtract(new TimeSpan(1, 0, 0));
12660                 List<DateTime> keys = new List<DateTime>();
12661                 _tlCount = 0;
12662                 foreach (DateTime key in _tlTimestamps.Keys)
12663                 {
12664                     if (key.CompareTo(oneHour) < 0)
12665                         keys.Add(key);
12666                     else
12667                         _tlCount += _tlTimestamps[key];
12668                 }
12669                 foreach (DateTime key in keys)
12670                 {
12671                     _tlTimestamps.Remove(key);
12672                 }
12673                 keys.Clear();
12674
12675                 //Static DateTime before = Now;
12676                 //if (before.Subtract(Now).Seconds > -5) return;
12677                 //before = Now;
12678             }
12679
12680             if (SettingDialog.UserstreamPeriodInt > 0) return;
12681
12682             try
12683             {
12684                 if (InvokeRequired && !IsDisposed)
12685                 {
12686                     Invoke(new Action<bool>(RefreshTimeline), true);
12687                     return;
12688                 }
12689             }
12690             catch (ObjectDisposedException)
12691             {
12692                 return;
12693             }
12694             catch (InvalidOperationException)
12695             {
12696                 return;
12697             }
12698         }
12699
12700         private void tw_UserStreamStarted()
12701         {
12702             this._isActiveUserstream = true;
12703             try
12704             {
12705                 if (InvokeRequired && !IsDisposed)
12706                 {
12707                     Invoke(new MethodInvoker(tw_UserStreamStarted));
12708                     return;
12709                 }
12710             }
12711             catch (ObjectDisposedException)
12712             {
12713                 return;
12714             }
12715             catch (InvalidOperationException)
12716             {
12717                 return;
12718             }
12719
12720             MenuItemUserStream.Text = "&UserStream ▶";
12721             MenuItemUserStream.Enabled = true;
12722             StopToolStripMenuItem.Text = "&Stop";
12723             StopToolStripMenuItem.Enabled = true;
12724
12725             StatusLabel.Text = "UserStream Started.";
12726         }
12727
12728         private void tw_UserStreamStopped()
12729         {
12730             this._isActiveUserstream = false;
12731             try
12732             {
12733                 if (InvokeRequired && !IsDisposed)
12734                 {
12735                     Invoke(new MethodInvoker(tw_UserStreamStopped));
12736                     return;
12737                 }
12738             }
12739             catch (ObjectDisposedException)
12740             {
12741                 return;
12742             }
12743             catch (InvalidOperationException)
12744             {
12745                 return;
12746             }
12747
12748             MenuItemUserStream.Text = "&UserStream ■";
12749             MenuItemUserStream.Enabled = true;
12750             StopToolStripMenuItem.Text = "&Start";
12751             StopToolStripMenuItem.Enabled = true;
12752
12753             StatusLabel.Text = "UserStream Stopped.";
12754         }
12755
12756         private void tw_UserStreamEventArrived(Twitter.FormattedEvent ev)
12757         {
12758             try
12759             {
12760                 if (InvokeRequired && !IsDisposed)
12761                 {
12762                     Invoke(new Action<Twitter.FormattedEvent>(tw_UserStreamEventArrived), ev);
12763                     return;
12764                 }
12765             }
12766             catch (ObjectDisposedException)
12767             {
12768                 return;
12769             }
12770             catch (InvalidOperationException)
12771             {
12772                 return;
12773             }
12774             StatusLabel.Text = "Event: " + ev.Event;
12775             //if (ev.Event == "favorite")
12776             //{
12777             //    NotifyFavorite(ev);
12778             //}
12779             NotifyEvent(ev);
12780             if (ev.Event == "favorite" || ev.Event == "unfavorite")
12781             {
12782                 if (_curTab != null && _statuses.Tabs[_curTab.Text].Contains(ev.Id))
12783                 {
12784                     this.PurgeListViewItemCache();
12785                     ((DetailsListView)_curTab.Tag).Update();
12786                 }
12787                 if (ev.Event == "unfavorite" && ev.Username.ToLower().Equals(tw.Username.ToLower()))
12788                 {
12789                     RemovePostFromFavTab(new long[] {ev.Id});
12790                 }
12791             }
12792         }
12793
12794         private void NotifyEvent(Twitter.FormattedEvent ev)
12795         {
12796             //新着通知 
12797             if (BalloonRequired(ev))
12798             {
12799                 NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
12800                 //if (SettingDialog.DispUsername) NotifyIcon1.BalloonTipTitle = tw.Username + " - "; else NotifyIcon1.BalloonTipTitle = "";
12801                 //NotifyIcon1.BalloonTipTitle += Application.ProductName + " [" + ev.Event.ToUpper() + "] by " + ((string)(!string.IsNullOrEmpty(ev.Username) ? ev.Username : ""), string);
12802                 StringBuilder title = new StringBuilder();
12803                 if (SettingDialog.DispUsername)
12804                 {
12805                     title.Append(tw.Username);
12806                     title.Append(" - ");
12807                 }
12808                 else
12809                 {
12810                     //title.Clear();
12811                 }
12812                 title.Append(Application.ProductName);
12813                 title.Append(" [");
12814                 title.Append(ev.Event.ToUpper());
12815                 title.Append("] by ");
12816                 if (!string.IsNullOrEmpty(ev.Username))
12817                 {
12818                     title.Append(ev.Username.ToString());
12819                 }
12820                 else
12821                 {
12822                     //title.Append("");
12823                 }
12824                 string text;
12825                 if (!string.IsNullOrEmpty(ev.Target))
12826                 {
12827                     //NotifyIcon1.BalloonTipText = ev.Target;
12828                     text = ev.Target;
12829                 }
12830                 else
12831                 {
12832                     //NotifyIcon1.BalloonTipText = " ";
12833                     text = " ";
12834                 }
12835                 //NotifyIcon1.ShowBalloonTip(500);
12836                 if (SettingDialog.IsNotifyUseGrowl)
12837                 {
12838                     gh.Notify(GrowlHelper.NotifyType.UserStreamEvent,
12839                               ev.Id.ToString(), title.ToString(), text);
12840                 }
12841                 else
12842                 {
12843                     NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
12844                     NotifyIcon1.BalloonTipTitle = title.ToString();
12845                     NotifyIcon1.BalloonTipText = text;
12846                     NotifyIcon1.ShowBalloonTip(500);
12847                 }
12848             }
12849
12850             //サウンド再生
12851             string snd = SettingDialog.EventSoundFile;
12852             if (!_initial && SettingDialog.PlaySound && !string.IsNullOrEmpty(snd))
12853             {
12854                 if ((ev.Eventtype & SettingDialog.EventNotifyFlag) != 0 && IsMyEventNotityAsEventType(ev))
12855                 {
12856                     try
12857                     {
12858                         string dir = Application.StartupPath;
12859                         if (Directory.Exists(Path.Combine(dir, "Sounds")))
12860                         {
12861                             dir = Path.Combine(dir, "Sounds");
12862                         }
12863                         using (SoundPlayer player = new SoundPlayer(Path.Combine(dir, snd)))
12864                         {
12865                             player.Play();
12866                         }
12867                     }
12868                     catch (Exception)
12869                     {
12870                     }
12871                 }
12872             }
12873         }
12874
12875         private void StopToolStripMenuItem_Click(object sender, EventArgs e)
12876         {
12877             MenuItemUserStream.Enabled = false;
12878             if (StopRefreshAllMenuItem.Checked)
12879             {
12880                 StopRefreshAllMenuItem.Checked = false;
12881                 return;
12882             }
12883             if (this._isActiveUserstream)
12884             {
12885                 tw.StopUserStream();
12886             }
12887             else
12888             {
12889                 tw.StartUserStream();
12890             }
12891         }
12892
12893         private static string inputTrack = "";
12894
12895         private void TrackToolStripMenuItem_Click(object sender, EventArgs e)
12896         {
12897             if (TrackToolStripMenuItem.Checked)
12898             {
12899                 using (InputTabName inputForm = new InputTabName())
12900                 {
12901                     inputForm.TabName = inputTrack;
12902                     inputForm.FormTitle = "Input track word";
12903                     inputForm.FormDescription = "Track word";
12904                     if (inputForm.ShowDialog() != DialogResult.OK)
12905                     {
12906                         TrackToolStripMenuItem.Checked = false;
12907                         return;
12908                     }
12909                     inputTrack = inputForm.TabName.Trim();
12910                 }
12911                 if (!inputTrack.Equals(tw.TrackWord))
12912                 {
12913                     tw.TrackWord = inputTrack;
12914                     this._modifySettingCommon = true;
12915                     TrackToolStripMenuItem.Checked = !string.IsNullOrEmpty(inputTrack);
12916                     tw.ReconnectUserStream();
12917                 }
12918             }
12919             else
12920             {
12921                 tw.TrackWord = "";
12922                 tw.ReconnectUserStream();
12923             }
12924             this._modifySettingCommon = true;
12925         }
12926
12927         private void AllrepliesToolStripMenuItem_Click(object sender, EventArgs e)
12928         {
12929             tw.AllAtReply = AllrepliesToolStripMenuItem.Checked;
12930             this._modifySettingCommon = true;
12931             tw.ReconnectUserStream();
12932         }
12933
12934         private void EventViewerMenuItem_Click(object sender, EventArgs e)
12935         {
12936             if (evtDialog == null || evtDialog.IsDisposed)
12937             {
12938                 evtDialog = null;
12939                 evtDialog = new EventViewerDialog();
12940                 evtDialog.Owner = this;
12941                 //親の中央に表示
12942                 Point pos = evtDialog.Location;
12943                 pos.X = Convert.ToInt32(this.Location.X + this.Size.Width / 2 - evtDialog.Size.Width / 2);
12944                 pos.Y = Convert.ToInt32(this.Location.Y + this.Size.Height / 2 - evtDialog.Size.Height / 2);
12945                 evtDialog.Location = pos;
12946             }
12947             evtDialog.EventSource = tw.StoredEvent;
12948             if (!evtDialog.Visible)
12949             {
12950                 evtDialog.Show(this);
12951             }
12952             else
12953             {
12954                 evtDialog.Activate();
12955             }
12956             this.TopMost = this.SettingDialog.AlwaysTop;
12957         }
12958 #endregion
12959
12960         private void TweenRestartMenuItem_Click(object sender, EventArgs e)
12961         {
12962             MyCommon._endingFlag = true;
12963             try
12964             {
12965                 this.Close();
12966                 Application.Restart();
12967             }
12968             catch (Exception)
12969             {
12970                 MessageBox.Show("Failed to restart. Please run " + Application.ProductName + " manually.");
12971             }
12972         }
12973
12974         private void OpenOwnFavedMenuItem_Click(object sender, EventArgs e)
12975         {
12976             if (!string.IsNullOrEmpty(tw.Username)) OpenUriAsync(Properties.Resources.FavstarUrl + "users/" + tw.Username + "/recent");
12977         }
12978
12979         private void OpenOwnHomeMenuItem_Click(object sender, EventArgs e)
12980         {
12981             OpenUriAsync(MyCommon.TwitterUrl + tw.Username);
12982         }
12983
12984         private async Task doTranslation(string str)
12985         {
12986             if (string.IsNullOrEmpty(str))
12987                 return;
12988
12989             var bing = new Bing(this.http);
12990             try
12991             {
12992                 var translatedText = await bing.TranslateAsync(str,
12993                     langFrom: null,
12994                     langTo: this.SettingDialog.TranslateLanguage);
12995
12996                 this.PostBrowser.DocumentText = translatedText;
12997             }
12998             catch (HttpRequestException e)
12999             {
13000                 this.StatusLabel.Text = "Err:" + e.Message;
13001             }
13002         }
13003
13004         private async void TranslationToolStripMenuItem_Click(object sender, EventArgs e)
13005         {
13006             if (!this.ExistCurrentPost)
13007                 return;
13008
13009             await this.doTranslation(this._curPost.TextFromApi);
13010         }
13011
13012         private async void SelectionTranslationToolStripMenuItem_Click(object sender, EventArgs e)
13013         {
13014             var text = this.WebBrowser_GetSelectionText(ref this.PostBrowser);
13015             await this.doTranslation(text);
13016         }
13017
13018         private bool ExistCurrentPost
13019         {
13020             get
13021             {
13022                 if (_curPost == null) return false;
13023                 if (_curPost.IsDeleted) return false;
13024                 return true;
13025             }
13026         }
13027
13028         private void ShowUserTimelineToolStripMenuItem_Click(object sender, EventArgs e)
13029         {
13030             ShowUserTimeline();
13031         }
13032
13033         public bool FavEventChangeUnread
13034         {
13035             get { return SettingDialog.FavEventUnread; }
13036         }
13037
13038         private string GetUserIdFromCurPostOrInput(string caption)
13039         {
13040             string id = "";
13041             if (_curPost != null)
13042             {
13043                 id = _curPost.ScreenName;
13044             }
13045             using (InputTabName inputName = new InputTabName())
13046             {
13047                 inputName.FormTitle = caption;
13048                 inputName.FormDescription = Properties.Resources.FRMessage1;
13049                 inputName.TabName = id;
13050                 if (inputName.ShowDialog() == DialogResult.OK &&
13051                     !string.IsNullOrEmpty(inputName.TabName.Trim()))
13052                 {
13053                     id = inputName.TabName.Trim();
13054                 }
13055                 else
13056                 {
13057                     id = "";
13058                 }
13059             }
13060             return id;
13061         }
13062
13063         private void UserTimelineToolStripMenuItem_Click(object sender, EventArgs e)
13064         {
13065             string id = GetUserIdFromCurPostOrInput("Show UserTimeline");
13066             if (!string.IsNullOrEmpty(id))
13067             {
13068                 AddNewTabForUserTimeline(id);
13069             }
13070         }
13071
13072         private void UserFavorareToolStripMenuItem_Click(object sender, EventArgs e)
13073         {
13074             string id = GetUserIdFromCurPostOrInput("Show Favstar");
13075             if (!string.IsNullOrEmpty(id))
13076             {
13077                 OpenUriAsync(Properties.Resources.FavstarUrl + "users/" + id + "/recent");
13078             }
13079         }
13080
13081         private void SystemEvents_PowerModeChanged(object sender, Microsoft.Win32.PowerModeChangedEventArgs e)
13082         {
13083             if (e.Mode == Microsoft.Win32.PowerModes.Resume) osResumed = true;
13084         }
13085
13086         private void TimelineRefreshEnableChange(bool isEnable)
13087         {
13088             if (isEnable)
13089             {
13090                 tw.StartUserStream();
13091             }
13092             else
13093             {
13094                 tw.StopUserStream();
13095             }
13096             TimerTimeline.Enabled = isEnable;
13097         }
13098
13099         private void StopRefreshAllMenuItem_CheckedChanged(object sender, EventArgs e)
13100         {
13101             TimelineRefreshEnableChange(!StopRefreshAllMenuItem.Checked);
13102         }
13103
13104         private void OpenUserAppointUrl()
13105         {
13106             if (SettingDialog.UserAppointUrl != null)
13107             {
13108                 if (SettingDialog.UserAppointUrl.Contains("{ID}") || SettingDialog.UserAppointUrl.Contains("{STATUS}"))
13109                 {
13110                     if (_curPost != null)
13111                     {
13112                         string xUrl = SettingDialog.UserAppointUrl;
13113                         xUrl = xUrl.Replace("{ID}", _curPost.ScreenName);
13114                         if (_curPost.RetweetedId != null)
13115                         {
13116                             xUrl = xUrl.Replace("{STATUS}", _curPost.RetweetedId.ToString());
13117                         }
13118                         else
13119                         {
13120                             xUrl = xUrl.Replace("{STATUS}", _curPost.StatusId.ToString());
13121                         }
13122                         OpenUriAsync(xUrl);
13123                     }
13124                 }
13125                 else
13126                 {
13127                     OpenUriAsync(SettingDialog.UserAppointUrl);
13128                 }
13129             }
13130         }
13131
13132         private void OpenUserSpecifiedUrlMenuItem_Click(object sender, EventArgs e)
13133         {
13134             OpenUserAppointUrl();
13135         }
13136
13137         private void SourceCopyMenuItem_Click(object sender, EventArgs e)
13138         {
13139             string selText = SourceLinkLabel.Text;
13140             try
13141             {
13142                 Clipboard.SetDataObject(selText, false, 5, 100);
13143             }
13144             catch (Exception ex)
13145             {
13146                 MessageBox.Show(ex.Message);
13147             }
13148         }
13149
13150         private void SourceUrlCopyMenuItem_Click(object sender, EventArgs e)
13151         {
13152             string selText = (string)SourceLinkLabel.Tag;
13153             try
13154             {
13155                 Clipboard.SetDataObject(selText, false, 5, 100);
13156             }
13157             catch (Exception ex)
13158             {
13159                 MessageBox.Show(ex.Message);
13160             }
13161         }
13162
13163         private void ContextMenuSource_Opening(object sender, CancelEventArgs e)
13164         {
13165             if (_curPost == null || !ExistCurrentPost || _curPost.IsDm)
13166             {
13167                 SourceCopyMenuItem.Enabled = false;
13168                 SourceUrlCopyMenuItem.Enabled = false;
13169             }
13170             else
13171             {
13172                 SourceCopyMenuItem.Enabled = true;
13173                 SourceUrlCopyMenuItem.Enabled = true;
13174             }
13175         }
13176
13177         private void GrowlHelper_Callback(object sender, GrowlHelper.NotifyCallbackEventArgs e)
13178         {
13179             if (Form.ActiveForm == null)
13180             {
13181                 this.BeginInvoke((Action) (() =>
13182                 {
13183                     this.Visible = true;
13184                     if (this.WindowState == FormWindowState.Minimized) this.WindowState = FormWindowState.Normal;
13185                     this.Activate();
13186                     this.BringToFront();
13187                     if (e.NotifyType == GrowlHelper.NotifyType.DirectMessage)
13188                     {
13189                         if (!this.GoDirectMessage(e.StatusId)) this.StatusText.Focus();
13190                     }
13191                     else
13192                     {
13193                         if (!this.GoStatus(e.StatusId)) this.StatusText.Focus();
13194                     }
13195                 }));
13196             }
13197         }
13198
13199         private void ReplaceAppName()
13200         {
13201             MatomeMenuItem.Text = MyCommon.ReplaceAppName(MatomeMenuItem.Text);
13202             AboutMenuItem.Text = MyCommon.ReplaceAppName(AboutMenuItem.Text);
13203         }
13204
13205         private void tweetThumbnail1_ThumbnailLoading(object sender, EventArgs e)
13206         {
13207             this.SplitContainer3.Panel2Collapsed = false;
13208
13209             // PreviewDistance が起動のたびに広がっていく問題の回避策
13210             // FixedPanel が Panel2 に設定された状態で Panel2 を開くと、初回だけ SplitterDistance が再計算されておかしくなるため、
13211             // None で開いた後に設定するようにする
13212             if (this.SplitContainer3.FixedPanel == FixedPanel.None)
13213                 this.SplitContainer3.FixedPanel = FixedPanel.Panel2;
13214         }
13215
13216         private void tweetThumbnail1_ThumbnailDoubleClick(object sender, ThumbnailDoubleClickEventArgs e)
13217         {
13218             this.OpenThumbnailPicture(e.Thumbnail);
13219         }
13220
13221         private void tweetThumbnail1_ThumbnailImageSearchClick(object sender, ThumbnailImageSearchEventArgs e)
13222         {
13223             this.OpenUriAsync(e.ImageUrl);
13224         }
13225
13226         private void OpenThumbnailPicture(ThumbnailInfo thumbnail)
13227         {
13228             this.OpenUriAsync(Uri.EscapeUriString(thumbnail.ImageUrl));
13229         }
13230
13231         private void TwitterApiStatusToolStripMenuItem_Click(object sender, EventArgs e)
13232         {
13233             this.OpenUriAsync(Twitter.ServiceAvailabilityStatusUrl);
13234         }
13235
13236         private void PostButton_KeyDown(object sender, KeyEventArgs e)
13237         {
13238             if (e.KeyCode == Keys.Space)
13239             {
13240                 this.JumpUnreadMenuItem_Click(null, null);
13241
13242                 e.SuppressKeyPress = true;
13243             }
13244         }
13245
13246         private void ContextMenuColumnHeader_Opening(object sender, CancelEventArgs e)
13247         {
13248             this.IconSizeNoneToolStripMenuItem.Checked = SettingDialog.IconSz == MyCommon.IconSizes.IconNone;
13249             this.IconSize16ToolStripMenuItem.Checked = SettingDialog.IconSz == MyCommon.IconSizes.Icon16;
13250             this.IconSize24ToolStripMenuItem.Checked = SettingDialog.IconSz == MyCommon.IconSizes.Icon24;
13251             this.IconSize48ToolStripMenuItem.Checked = SettingDialog.IconSz == MyCommon.IconSizes.Icon48;
13252             this.IconSize48_2ToolStripMenuItem.Checked = SettingDialog.IconSz == MyCommon.IconSizes.Icon48_2;
13253
13254             this.LockListSortOrderToolStripMenuItem.Checked = SettingDialog.SortOrderLock;
13255         }
13256
13257         private void IconSizeNoneToolStripMenuItem_Click(object sender, EventArgs e)
13258         {
13259             ChangeListViewIconSize(MyCommon.IconSizes.IconNone);
13260         }
13261
13262         private void IconSize16ToolStripMenuItem_Click(object sender, EventArgs e)
13263         {
13264             ChangeListViewIconSize(MyCommon.IconSizes.Icon16);
13265         }
13266
13267         private void IconSize24ToolStripMenuItem_Click(object sender, EventArgs e)
13268         {
13269             ChangeListViewIconSize(MyCommon.IconSizes.Icon24);
13270         }
13271
13272         private void IconSize48ToolStripMenuItem_Click(object sender, EventArgs e)
13273         {
13274             ChangeListViewIconSize(MyCommon.IconSizes.Icon48);
13275         }
13276
13277         private void IconSize48_2ToolStripMenuItem_Click(object sender, EventArgs e)
13278         {
13279             ChangeListViewIconSize(MyCommon.IconSizes.Icon48_2);
13280         }
13281
13282         private void ChangeListViewIconSize(MyCommon.IconSizes iconSize)
13283         {
13284             if (SettingDialog.IconSz == iconSize) return;
13285
13286             var oldIconCol = _iconCol;
13287
13288             SettingDialog.IconSz = iconSize;
13289             ApplyListViewIconSize(iconSize);
13290
13291             if (_iconCol != oldIconCol)
13292             {
13293                 foreach (TabPage tp in ListTab.TabPages)
13294                 {
13295                     ResetColumns((DetailsListView)tp.Tag);
13296                 }
13297             }
13298
13299             if (_curList != null) _curList.Refresh();
13300
13301             _modifySettingCommon = true;
13302         }
13303
13304         private void LockListSortToolStripMenuItem_Click(object sender, EventArgs e)
13305         {
13306             var state = this.LockListSortOrderToolStripMenuItem.Checked;
13307             if (SettingDialog.SortOrderLock == state) return;
13308
13309             SettingDialog.SortOrderLock = state;
13310
13311             _modifySettingCommon = true;
13312         }
13313     }
13314 }