OSDN Git Service

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