OSDN Git Service

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