OSDN Git Service

C#7.0で追加されたTupleの構文を使用する
[opentween/open-tween.git] / OpenTween / Tween.cs
index b4a70dc..6bf4f12 100644 (file)
@@ -41,6 +41,7 @@ using System.Media;
 using System.Net;
 using System.Net.Http;
 using System.Reflection;
+using System.Runtime.InteropServices;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading;
@@ -51,6 +52,7 @@ using OpenTween.Api.DataModel;
 using OpenTween.Connection;
 using OpenTween.Models;
 using OpenTween.OpenTweenCustomControl;
+using OpenTween.Setting;
 using OpenTween.Thumbnail;
 
 namespace OpenTween
@@ -110,11 +112,6 @@ namespace OpenTween
         private bool soundfileListup = false;
         private FormWindowState _formWindowState = FormWindowState.Normal; // フォームの状態保存用 通知領域からアイコンをクリックして復帰した際に使用する
 
-        //設定ファイル関連
-        //private SettingToConfig _cfg; //旧
-        private SettingLocal _cfgLocal;
-        private SettingCommon _cfgCommon;
-
         //twitter解析部
         private TwitterApi twitterApi = new TwitterApi();
         private Twitter tw;
@@ -123,7 +120,7 @@ namespace OpenTween
         private GrowlHelper gh = new GrowlHelper(Application.ProductName);
 
         //サブ画面インスタンス
-        private SearchWordDialog SearchDialog = new SearchWordDialog();     //検索画面インスタンス
+        internal SearchWordDialog SearchDialog = new SearchWordDialog();     //検索画面インスタンス
         private OpenURL UrlDialog = new OpenURL();
         public AtIdSupplement AtIdSupl;     //@id補助
         public AtIdSupplement HashSupl;    //Hashtag補助
@@ -262,6 +259,7 @@ namespace OpenTween
         private const int MAX_WORKER_THREADS = 20;
         private SemaphoreSlim workerSemaphore = new SemaphoreSlim(MAX_WORKER_THREADS);
         private CancellationTokenSource workerCts = new CancellationTokenSource();
+        private IProgress<string> workerProgress;
 
         private int UnreadCounter = -1;
         private int UnreadAtCounter = -1;
@@ -273,14 +271,10 @@ namespace OpenTween
         private bool osResumed = false;
 
         //////////////////////////////////////////////////////////////////////////////////////////////////////////
-        private string _postBrowserStatusText = "";
-
         private bool _colorize = false;
 
         private System.Timers.Timer TimerTimeline = new System.Timers.Timer();
 
-        private ImageListViewItem displayItem;
-
         private string recommendedStatusFooter;
 
         //URL短縮のUndo用
@@ -307,10 +301,10 @@ namespace OpenTween
         }
 
         private Stack<ReplyChain> replyChains; //[, ]でのリプライ移動の履歴
-        private Stack<Tuple<TabPage, PostClass>> selectPostChains = new Stack<Tuple<TabPage, PostClass>>(); //ポスト選択履歴
+        private Stack<ValueTuple<TabPage, PostClass>> selectPostChains = new Stack<ValueTuple<TabPage, PostClass>>(); //ポスト選択履歴
 
         //検索処理タイプ
-        private enum SEARCHTYPE
+        internal enum SEARCHTYPE
         {
             DialogSearch,
             NextSearch,
@@ -519,10 +513,10 @@ namespace OpenTween
 
                     if (startup)
                     {
-                        var widthScaleFactor = this.CurrentAutoScaleDimensions.Width / this._cfgLocal.ScaleDimension.Width;
+                        var widthScaleFactor = this.CurrentAutoScaleDimensions.Width / SettingManager.Local.ScaleDimension.Width;
 
-                        columns[0].Width = ScaleBy(widthScaleFactor, _cfgLocal.Width1);
-                        columns[1].Width = ScaleBy(widthScaleFactor, _cfgLocal.Width3);
+                        columns[0].Width = ScaleBy(widthScaleFactor, SettingManager.Local.Width1);
+                        columns[1].Width = ScaleBy(widthScaleFactor, SettingManager.Local.Width3);
                         columns[0].DisplayIndex = 0;
                         columns[1].DisplayIndex = 1;
                     }
@@ -556,22 +550,22 @@ namespace OpenTween
 
                     if (startup)
                     {
-                        var widthScaleFactor = this.CurrentAutoScaleDimensions.Width / this._cfgLocal.ScaleDimension.Width;
+                        var widthScaleFactor = this.CurrentAutoScaleDimensions.Width / SettingManager.Local.ScaleDimension.Width;
 
-                        columns[0].Width = ScaleBy(widthScaleFactor, _cfgLocal.Width1);
-                        columns[1].Width = ScaleBy(widthScaleFactor, _cfgLocal.Width2);
-                        columns[2].Width = ScaleBy(widthScaleFactor, _cfgLocal.Width3);
-                        columns[3].Width = ScaleBy(widthScaleFactor, _cfgLocal.Width4);
-                        columns[4].Width = ScaleBy(widthScaleFactor, _cfgLocal.Width5);
-                        columns[5].Width = ScaleBy(widthScaleFactor, _cfgLocal.Width6);
-                        columns[6].Width = ScaleBy(widthScaleFactor, _cfgLocal.Width7);
-                        columns[7].Width = ScaleBy(widthScaleFactor, _cfgLocal.Width8);
+                        columns[0].Width = ScaleBy(widthScaleFactor, SettingManager.Local.Width1);
+                        columns[1].Width = ScaleBy(widthScaleFactor, SettingManager.Local.Width2);
+                        columns[2].Width = ScaleBy(widthScaleFactor, SettingManager.Local.Width3);
+                        columns[3].Width = ScaleBy(widthScaleFactor, SettingManager.Local.Width4);
+                        columns[4].Width = ScaleBy(widthScaleFactor, SettingManager.Local.Width5);
+                        columns[5].Width = ScaleBy(widthScaleFactor, SettingManager.Local.Width6);
+                        columns[6].Width = ScaleBy(widthScaleFactor, SettingManager.Local.Width7);
+                        columns[7].Width = ScaleBy(widthScaleFactor, SettingManager.Local.Width8);
 
                         var displayIndex = new[] {
-                            this._cfgLocal.DisplayIndex1, this._cfgLocal.DisplayIndex2,
-                            this._cfgLocal.DisplayIndex3, this._cfgLocal.DisplayIndex4,
-                            this._cfgLocal.DisplayIndex5, this._cfgLocal.DisplayIndex6,
-                            this._cfgLocal.DisplayIndex7, this._cfgLocal.DisplayIndex8
+                            SettingManager.Local.DisplayIndex1, SettingManager.Local.DisplayIndex2,
+                            SettingManager.Local.DisplayIndex3, SettingManager.Local.DisplayIndex4,
+                            SettingManager.Local.DisplayIndex5, SettingManager.Local.DisplayIndex6,
+                            SettingManager.Local.DisplayIndex7, SettingManager.Local.DisplayIndex8
                         };
 
                         foreach (var i in Enumerable.Range(0, displayIndex.Length))
@@ -698,9 +692,6 @@ namespace OpenTween
 
             //Win32Api.SetProxy(HttpConnection.ProxyType.Specified, "127.0.0.1", 8080, "user", "pass")
 
-            new InternetSecurityManager(PostBrowser);
-            this.PostBrowser.AllowWebBrowserDrop = false;  // COMException を回避するため、ActiveX の初期化が終わってから設定する
-
             MyCommon.TwitterApiInfo.AccessLimitUpdated += TwitterApiStatus_AccessLimitUpdated;
             Microsoft.Win32.SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
 
@@ -720,10 +711,10 @@ namespace OpenTween
             LoadConfig();
 
             // 現在の DPI と設定保存時の DPI との比を取得する
-            var configScaleFactor = this._cfgLocal.GetConfigScaleFactor(this.CurrentAutoScaleDimensions);
+            var configScaleFactor = SettingManager.Local.GetConfigScaleFactor(this.CurrentAutoScaleDimensions);
 
             // UIフォント設定
-            var fontUIGlobal = this._cfgLocal.FontUIGlobal;
+            var fontUIGlobal = SettingManager.Local.FontUIGlobal;
             if (fontUIGlobal != null)
             {
                 OTBaseForm.GlobalFont = fontUIGlobal;
@@ -733,54 +724,54 @@ namespace OpenTween
             //不正値チェック
             if (!MyApplication.StartupOptions.ContainsKey("nolimit"))
             {
-                if (this._cfgCommon.TimelinePeriod < 15 && this._cfgCommon.TimelinePeriod > 0)
-                    this._cfgCommon.TimelinePeriod = 15;
+                if (SettingManager.Common.TimelinePeriod < 15 && SettingManager.Common.TimelinePeriod > 0)
+                    SettingManager.Common.TimelinePeriod = 15;
 
-                if (this._cfgCommon.ReplyPeriod < 15 && this._cfgCommon.ReplyPeriod > 0)
-                    this._cfgCommon.ReplyPeriod = 15;
+                if (SettingManager.Common.ReplyPeriod < 15 && SettingManager.Common.ReplyPeriod > 0)
+                    SettingManager.Common.ReplyPeriod = 15;
 
-                if (this._cfgCommon.DMPeriod < 15 && this._cfgCommon.DMPeriod > 0)
-                    this._cfgCommon.DMPeriod = 15;
+                if (SettingManager.Common.DMPeriod < 15 && SettingManager.Common.DMPeriod > 0)
+                    SettingManager.Common.DMPeriod = 15;
 
-                if (this._cfgCommon.PubSearchPeriod < 30 && this._cfgCommon.PubSearchPeriod > 0)
-                    this._cfgCommon.PubSearchPeriod = 30;
+                if (SettingManager.Common.PubSearchPeriod < 30 && SettingManager.Common.PubSearchPeriod > 0)
+                    SettingManager.Common.PubSearchPeriod = 30;
 
-                if (this._cfgCommon.UserTimelinePeriod < 15 && this._cfgCommon.UserTimelinePeriod > 0)
-                    this._cfgCommon.UserTimelinePeriod = 15;
+                if (SettingManager.Common.UserTimelinePeriod < 15 && SettingManager.Common.UserTimelinePeriod > 0)
+                    SettingManager.Common.UserTimelinePeriod = 15;
 
-                if (this._cfgCommon.ListsPeriod < 15 && this._cfgCommon.ListsPeriod > 0)
-                    this._cfgCommon.ListsPeriod = 15;
+                if (SettingManager.Common.ListsPeriod < 15 && SettingManager.Common.ListsPeriod > 0)
+                    SettingManager.Common.ListsPeriod = 15;
             }
 
-            if (!Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.Timeline, this._cfgCommon.CountApi))
-                this._cfgCommon.CountApi = 60;
-            if (!Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.Reply, this._cfgCommon.CountApiReply))
-                this._cfgCommon.CountApiReply = 40;
+            if (!Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.Timeline, SettingManager.Common.CountApi))
+                SettingManager.Common.CountApi = 60;
+            if (!Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.Reply, SettingManager.Common.CountApiReply))
+                SettingManager.Common.CountApiReply = 40;
 
-            if (this._cfgCommon.MoreCountApi != 0 && !Twitter.VerifyMoreApiResultCount(this._cfgCommon.MoreCountApi))
-                this._cfgCommon.MoreCountApi = 200;
-            if (this._cfgCommon.FirstCountApi != 0 && !Twitter.VerifyFirstApiResultCount(this._cfgCommon.FirstCountApi))
-                this._cfgCommon.FirstCountApi = 100;
+            if (SettingManager.Common.MoreCountApi != 0 && !Twitter.VerifyMoreApiResultCount(SettingManager.Common.MoreCountApi))
+                SettingManager.Common.MoreCountApi = 200;
+            if (SettingManager.Common.FirstCountApi != 0 && !Twitter.VerifyFirstApiResultCount(SettingManager.Common.FirstCountApi))
+                SettingManager.Common.FirstCountApi = 100;
 
-            if (this._cfgCommon.FavoritesCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.Favorites, this._cfgCommon.FavoritesCountApi))
-                this._cfgCommon.FavoritesCountApi = 40;
-            if (this._cfgCommon.ListCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.List, this._cfgCommon.ListCountApi))
-                this._cfgCommon.ListCountApi = 100;
-            if (this._cfgCommon.SearchCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.PublicSearch, this._cfgCommon.SearchCountApi))
-                this._cfgCommon.SearchCountApi = 100;
-            if (this._cfgCommon.UserTimelineCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.UserTimeline, this._cfgCommon.UserTimelineCountApi))
-                this._cfgCommon.UserTimelineCountApi = 20;
+            if (SettingManager.Common.FavoritesCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.Favorites, SettingManager.Common.FavoritesCountApi))
+                SettingManager.Common.FavoritesCountApi = 40;
+            if (SettingManager.Common.ListCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.List, SettingManager.Common.ListCountApi))
+                SettingManager.Common.ListCountApi = 100;
+            if (SettingManager.Common.SearchCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.PublicSearch, SettingManager.Common.SearchCountApi))
+                SettingManager.Common.SearchCountApi = 100;
+            if (SettingManager.Common.UserTimelineCountApi != 0 && !Twitter.VerifyApiResultCount(MyCommon.WORKERTYPE.UserTimeline, SettingManager.Common.UserTimelineCountApi))
+                SettingManager.Common.UserTimelineCountApi = 20;
 
             //廃止サービスが選択されていた場合ux.nuへ読み替え
-            if (this._cfgCommon.AutoShortUrlFirst < 0)
-                this._cfgCommon.AutoShortUrlFirst = MyCommon.UrlConverter.Uxnu;
+            if (SettingManager.Common.AutoShortUrlFirst < 0)
+                SettingManager.Common.AutoShortUrlFirst = MyCommon.UrlConverter.Uxnu;
 
-            TwitterApiConnection.RestApiBase = this._cfgCommon.TwitterApiBaseUri;
+            TwitterApiConnection.RestApiHost = SettingManager.Common.TwitterApiHost;
             this.tw = new Twitter(this.twitterApi);
 
             //認証関連
-            if (string.IsNullOrEmpty(this._cfgCommon.Token)) this._cfgCommon.UserName = "";
-            tw.Initialize(this._cfgCommon.Token, this._cfgCommon.TokenSecret, this._cfgCommon.UserName, this._cfgCommon.UserId);
+            if (string.IsNullOrEmpty(SettingManager.Common.Token)) SettingManager.Common.UserName = "";
+            tw.Initialize(SettingManager.Common.Token, SettingManager.Common.TokenSecret, SettingManager.Common.UserName, SettingManager.Common.UserId);
 
             _initial = true;
 
@@ -805,22 +796,23 @@ namespace OpenTween
             }
 
             //Twitter用通信クラス初期化
-            Networking.DefaultTimeout = TimeSpan.FromSeconds(this._cfgCommon.DefaultTimeOut);
-            Networking.SetWebProxy(this._cfgLocal.ProxyType,
-                this._cfgLocal.ProxyAddress, this._cfgLocal.ProxyPort,
-                this._cfgLocal.ProxyUser, this._cfgLocal.ProxyPassword);
-            Networking.ForceIPv4 = this._cfgCommon.ForceIPv4;
-
-            TwitterApiConnection.RestApiBase = this._cfgCommon.TwitterApiBaseUri;
-            tw.RestrictFavCheck = this._cfgCommon.RestrictFavCheck;
-            tw.ReadOwnPost = this._cfgCommon.ReadOwnPost;
-            tw.TrackWord = this._cfgCommon.TrackWord;
+            Networking.DefaultTimeout = TimeSpan.FromSeconds(SettingManager.Common.DefaultTimeOut);
+            Networking.UploadImageTimeout = TimeSpan.FromSeconds(SettingManager.Common.UploadImageTimeout);
+            Networking.SetWebProxy(SettingManager.Local.ProxyType,
+                SettingManager.Local.ProxyAddress, SettingManager.Local.ProxyPort,
+                SettingManager.Local.ProxyUser, SettingManager.Local.ProxyPassword);
+            Networking.ForceIPv4 = SettingManager.Common.ForceIPv4;
+
+            TwitterApiConnection.RestApiHost = SettingManager.Common.TwitterApiHost;
+            tw.RestrictFavCheck = SettingManager.Common.RestrictFavCheck;
+            tw.ReadOwnPost = SettingManager.Common.ReadOwnPost;
+            tw.TrackWord = SettingManager.Common.TrackWord;
             TrackToolStripMenuItem.Checked = !String.IsNullOrEmpty(tw.TrackWord);
-            tw.AllAtReply = this._cfgCommon.AllAtReply;
+            tw.AllAtReply = SettingManager.Common.AllAtReply;
             AllrepliesToolStripMenuItem.Checked = tw.AllAtReply;
-            ShortUrl.Instance.DisableExpanding = !this._cfgCommon.TinyUrlResolve;
-            ShortUrl.Instance.BitlyId = this._cfgCommon.BilyUser;
-            ShortUrl.Instance.BitlyKey = this._cfgCommon.BitlyPwd;
+            ShortUrl.Instance.DisableExpanding = !SettingManager.Common.TinyUrlResolve;
+            ShortUrl.Instance.BitlyId = SettingManager.Common.BilyUser;
+            ShortUrl.Instance.BitlyKey = SettingManager.Common.BitlyPwd;
 
             // アクセストークンが有効であるか確認する
             // ここが Twitter API への最初のアクセスになるようにすること
@@ -839,50 +831,51 @@ namespace OpenTween
             ThumbnailGenerator.InitializeGenerator();
 
             var imgazyobizinet = ThumbnailGenerator.ImgAzyobuziNetInstance;
-            imgazyobizinet.Enabled = this._cfgCommon.EnableImgAzyobuziNet;
-            imgazyobizinet.DisabledInDM = this._cfgCommon.ImgAzyobuziNetDisabledInDM;
+            imgazyobizinet.Enabled = SettingManager.Common.EnableImgAzyobuziNet;
+            imgazyobizinet.DisabledInDM = SettingManager.Common.ImgAzyobuziNetDisabledInDM;
 
             Thumbnail.Services.TonTwitterCom.GetApiConnection = () => this.twitterApi.Connection;
 
             //画像投稿サービス
-            ImageSelector.Initialize(tw, this.tw.Configuration, _cfgCommon.UseImageServiceName, _cfgCommon.UseImageService);
+            ImageSelector.Initialize(tw, this.tw.Configuration, SettingManager.Common.UseImageServiceName, SettingManager.Common.UseImageService);
 
             //ハッシュタグ/@id関連
-            AtIdSupl = new AtIdSupplement(SettingAtIdList.Load().AtIdList, "@");
-            HashSupl = new AtIdSupplement(_cfgCommon.HashTags, "#");
+            AtIdSupl = new AtIdSupplement(SettingManager.AtIdList.AtIdList, "@");
+            HashSupl = new AtIdSupplement(SettingManager.Common.HashTags, "#");
             HashMgr = new HashtagManage(HashSupl,
-                                    _cfgCommon.HashTags.ToArray(),
-                                    _cfgCommon.HashSelected,
-                                    _cfgCommon.HashIsPermanent,
-                                    _cfgCommon.HashIsHead,
-                                    _cfgCommon.HashIsNotAddToAtReply);
+                                    SettingManager.Common.HashTags.ToArray(),
+                                    SettingManager.Common.HashSelected,
+                                    SettingManager.Common.HashIsPermanent,
+                                    SettingManager.Common.HashIsHead,
+                                    SettingManager.Common.HashIsNotAddToAtReply);
             if (!string.IsNullOrEmpty(HashMgr.UseHash) && HashMgr.IsPermanent) HashStripSplitButton.Text = HashMgr.UseHash;
 
             //アイコンリスト作成
             this.IconCache = new ImageCache();
+            this.tweetDetailsView.IconCache = this.IconCache;
 
             //フォント&文字色&背景色保持
-            _fntUnread = this._cfgLocal.FontUnread;
-            _clUnread = this._cfgLocal.ColorUnread;
-            _fntReaded = this._cfgLocal.FontRead;
-            _clReaded = this._cfgLocal.ColorRead;
-            _clFav = this._cfgLocal.ColorFav;
-            _clOWL = this._cfgLocal.ColorOWL;
-            _clRetweet = this._cfgLocal.ColorRetweet;
-            _fntDetail = this._cfgLocal.FontDetail;
-            _clDetail = this._cfgLocal.ColorDetail;
-            _clDetailLink = this._cfgLocal.ColorDetailLink;
-            _clDetailBackcolor = this._cfgLocal.ColorDetailBackcolor;
-            _clSelf = this._cfgLocal.ColorSelf;
-            _clAtSelf = this._cfgLocal.ColorAtSelf;
-            _clTarget = this._cfgLocal.ColorTarget;
-            _clAtTarget = this._cfgLocal.ColorAtTarget;
-            _clAtFromTarget = this._cfgLocal.ColorAtFromTarget;
-            _clAtTo = this._cfgLocal.ColorAtTo;
-            _clListBackcolor = this._cfgLocal.ColorListBackcolor;
-            _clInputBackcolor = this._cfgLocal.ColorInputBackcolor;
-            _clInputFont = this._cfgLocal.ColorInputFont;
-            _fntInputFont = this._cfgLocal.FontInputFont;
+            _fntUnread = SettingManager.Local.FontUnread;
+            _clUnread = SettingManager.Local.ColorUnread;
+            _fntReaded = SettingManager.Local.FontRead;
+            _clReaded = SettingManager.Local.ColorRead;
+            _clFav = SettingManager.Local.ColorFav;
+            _clOWL = SettingManager.Local.ColorOWL;
+            _clRetweet = SettingManager.Local.ColorRetweet;
+            _fntDetail = SettingManager.Local.FontDetail;
+            _clDetail = SettingManager.Local.ColorDetail;
+            _clDetailLink = SettingManager.Local.ColorDetailLink;
+            _clDetailBackcolor = SettingManager.Local.ColorDetailBackcolor;
+            _clSelf = SettingManager.Local.ColorSelf;
+            _clAtSelf = SettingManager.Local.ColorAtSelf;
+            _clTarget = SettingManager.Local.ColorTarget;
+            _clAtTarget = SettingManager.Local.ColorAtTarget;
+            _clAtFromTarget = SettingManager.Local.ColorAtFromTarget;
+            _clAtTo = SettingManager.Local.ColorAtTo;
+            _clListBackcolor = SettingManager.Local.ColorListBackcolor;
+            _clInputBackcolor = SettingManager.Local.ColorInputBackcolor;
+            _clInputFont = SettingManager.Local.ColorInputFont;
+            _fntInputFont = SettingManager.Local.FontInputFont;
 
             _brsBackColorMine = new SolidBrush(_clSelf);
             _brsBackColorAt = new SolidBrush(_clAtSelf);
@@ -914,27 +907,27 @@ namespace OpenTween
             UrlDialog.Owner = this;
 
             //新着バルーン通知のチェック状態設定
-            NewPostPopMenuItem.Checked = _cfgCommon.NewAllPop;
+            NewPostPopMenuItem.Checked = SettingManager.Common.NewAllPop;
             this.NotifyFileMenuItem.Checked = NewPostPopMenuItem.Checked;
 
             //新着取得時のリストスクロールをするか。trueならスクロールしない
-            ListLockMenuItem.Checked = _cfgCommon.ListLock;
-            this.LockListFileMenuItem.Checked = _cfgCommon.ListLock;
+            ListLockMenuItem.Checked = SettingManager.Common.ListLock;
+            this.LockListFileMenuItem.Checked = SettingManager.Common.ListLock;
             //サウンド再生(タブ別設定より優先)
-            this.PlaySoundMenuItem.Checked = this._cfgCommon.PlaySound;
-            this.PlaySoundFileMenuItem.Checked = this._cfgCommon.PlaySound;
+            this.PlaySoundMenuItem.Checked = SettingManager.Common.PlaySound;
+            this.PlaySoundFileMenuItem.Checked = SettingManager.Common.PlaySound;
 
-            this.IdeographicSpaceToSpaceToolStripMenuItem.Checked = _cfgCommon.WideSpaceConvert;
-            this.ToolStripFocusLockMenuItem.Checked = _cfgCommon.FocusLockToStatusText;
+            this.IdeographicSpaceToSpaceToolStripMenuItem.Checked = SettingManager.Common.WideSpaceConvert;
+            this.ToolStripFocusLockMenuItem.Checked = SettingManager.Common.FocusLockToStatusText;
 
             //ウィンドウ設定
-            this.ClientSize = ScaleBy(configScaleFactor, _cfgLocal.FormSize);
+            this.ClientSize = ScaleBy(configScaleFactor, SettingManager.Local.FormSize);
             _mySize = this.ClientSize; // サイズ保持(最小化・最大化されたまま終了した場合の対応用)
-            _myLoc = _cfgLocal.FormLocation;
+            _myLoc = SettingManager.Local.FormLocation;
             //タイトルバー領域
             if (this.WindowState != FormWindowState.Minimized)
             {
-                this.DesktopLocation = _cfgLocal.FormLocation;
+                this.DesktopLocation = SettingManager.Local.FormLocation;
                 Rectangle tbarRect = new Rectangle(this.Location, new Size(_mySize.Width, SystemInformation.CaptionHeight));
                 bool outOfScreen = true;
                 if (Screen.AllScreens.Length == 1)    //ハングするとの報告
@@ -954,49 +947,41 @@ namespace OpenTween
                     }
                 }
             }
-            this.TopMost = this._cfgCommon.AlwaysTop;
-            _mySpDis = ScaleBy(configScaleFactor.Height, _cfgLocal.SplitterDistance);
-            _mySpDis2 = ScaleBy(configScaleFactor.Height, _cfgLocal.StatusTextHeight);
-            if (_cfgLocal.PreviewDistance == -1)
+            this.TopMost = SettingManager.Common.AlwaysTop;
+            _mySpDis = ScaleBy(configScaleFactor.Height, SettingManager.Local.SplitterDistance);
+            _mySpDis2 = ScaleBy(configScaleFactor.Height, SettingManager.Local.StatusTextHeight);
+            if (SettingManager.Local.PreviewDistance == -1)
             {
                 _mySpDis3 = _mySize.Width - ScaleBy(this.CurrentScaleFactor.Width, 150);
                 if (_mySpDis3 < 1) _mySpDis3 = ScaleBy(this.CurrentScaleFactor.Width, 50);
-                _cfgLocal.PreviewDistance = _mySpDis3;
+                SettingManager.Local.PreviewDistance = _mySpDis3;
             }
             else
             {
-                _mySpDis3 = ScaleBy(configScaleFactor.Width, _cfgLocal.PreviewDistance);
+                _mySpDis3 = ScaleBy(configScaleFactor.Width, SettingManager.Local.PreviewDistance);
             }
-            MultiLineMenuItem.Checked = _cfgLocal.StatusMultiline;
+            MultiLineMenuItem.Checked = SettingManager.Local.StatusMultiline;
             //this.Tween_ClientSizeChanged(this, null);
-            this.PlaySoundMenuItem.Checked = this._cfgCommon.PlaySound;
-            this.PlaySoundFileMenuItem.Checked = this._cfgCommon.PlaySound;
+            this.PlaySoundMenuItem.Checked = SettingManager.Common.PlaySound;
+            this.PlaySoundFileMenuItem.Checked = SettingManager.Common.PlaySound;
             //入力欄
             StatusText.Font = _fntInputFont;
             StatusText.ForeColor = _clInputFont;
 
             // SplitContainer2.Panel2MinSize を一行表示の入力欄の高さに合わせる (MS UI Gothic 12pt (96dpi) の場合は 19px)
-            this.StatusText.Multiline = false; // _cfgLocal.StatusMultiline の設定は後で反映される
+            this.StatusText.Multiline = false; // SettingManager.Local.StatusMultiline の設定は後で反映される
             this.SplitContainer2.Panel2MinSize = this.StatusText.Height;
 
-            // NameLabel のフォントを OTBaseForm.GlobalFont に変更
-            this.NameLabel.Font = this.ReplaceToGlobalFont(this.NameLabel.Font);
-
             // 必要であれば、発言一覧と発言詳細部・入力欄の上下を入れ替える
-            SplitContainer1.IsPanelInverted = !this._cfgCommon.StatusAreaAtBottom;
+            SplitContainer1.IsPanelInverted = !SettingManager.Common.StatusAreaAtBottom;
 
             //全新着通知のチェック状態により、Reply&DMの新着通知有効無効切り替え(タブ別設定にするため削除予定)
-            if (this._cfgCommon.UnreadManage == false)
+            if (SettingManager.Common.UnreadManage == false)
             {
                 ReadedStripMenuItem.Enabled = false;
                 UnreadStripMenuItem.Enabled = false;
             }
 
-            //発言詳細部の初期化
-            NameLabel.Text = "";
-            DateTimeLabel.Text = "";
-            SourceLinkLabel.Text = "";
-
             //リンク先URL表示部の初期化(画面左下)
             StatusLabelUrl.Text = "";
             //状態表示部の初期化(画面右下)
@@ -1017,9 +1002,9 @@ namespace OpenTween
             this.SplitContainer2.Panel2.AccessibleName = "";
 
             ////////////////////////////////////////////////////////////////////////////////
-            var sortOrder = (SortOrder)_cfgCommon.SortOrder;
+            var sortOrder = (SortOrder)SettingManager.Common.SortOrder;
             var mode = ComparerMode.Id;
-            switch (_cfgCommon.SortColumn)
+            switch (SettingManager.Common.SortColumn)
             {
                 case 0:    //0:アイコン,5:未読マーク,6:プロテクト・フィルターマーク
                 case 5:
@@ -1046,7 +1031,7 @@ namespace OpenTween
             _statuses.SetSortMode(mode, sortOrder);
             ////////////////////////////////////////////////////////////////////////////////
 
-            ApplyListViewIconSize(this._cfgCommon.IconSize);
+            ApplyListViewIconSize(SettingManager.Common.IconSize);
 
             //<<<<<<<<タブ関連>>>>>>>
             // タブの位置を調整する
@@ -1082,7 +1067,7 @@ namespace OpenTween
             _curItemIndex = -1;
             _curList = (DetailsListView)_curTab.Tag;
 
-            if (this._cfgCommon.TabIconDisp)
+            if (SettingManager.Common.TabIconDisp)
             {
                 ListTab.DrawMode = TabDrawMode.Normal;
             }
@@ -1093,23 +1078,23 @@ namespace OpenTween
                 ListTab.ImageList = null;
             }
 
-            if (this._cfgCommon.HotkeyEnabled)
+            if (SettingManager.Common.HotkeyEnabled)
             {
                 //////グローバルホットキーの登録
                 HookGlobalHotkey.ModKeys modKey = HookGlobalHotkey.ModKeys.None;
-                if ((this._cfgCommon.HotkeyModifier & Keys.Alt) == Keys.Alt)
+                if ((SettingManager.Common.HotkeyModifier & Keys.Alt) == Keys.Alt)
                     modKey |= HookGlobalHotkey.ModKeys.Alt;
-                if ((this._cfgCommon.HotkeyModifier & Keys.Control) == Keys.Control)
+                if ((SettingManager.Common.HotkeyModifier & Keys.Control) == Keys.Control)
                     modKey |= HookGlobalHotkey.ModKeys.Ctrl;
-                if ((this._cfgCommon.HotkeyModifier & Keys.Shift) == Keys.Shift)
+                if ((SettingManager.Common.HotkeyModifier & Keys.Shift) == Keys.Shift)
                     modKey |= HookGlobalHotkey.ModKeys.Shift;
-                if ((this._cfgCommon.HotkeyModifier & Keys.LWin) == Keys.LWin)
+                if ((SettingManager.Common.HotkeyModifier & Keys.LWin) == Keys.LWin)
                     modKey |= HookGlobalHotkey.ModKeys.Win;
 
-                _hookGlobalHotkey.RegisterOriginalHotkey(this._cfgCommon.HotkeyKey, this._cfgCommon.HotkeyValue, modKey);
+                _hookGlobalHotkey.RegisterOriginalHotkey(SettingManager.Common.HotkeyKey, SettingManager.Common.HotkeyValue, modKey);
             }
 
-            if (this._cfgCommon.IsUseNotifyGrowl)
+            if (SettingManager.Common.IsUseNotifyGrowl)
                 gh.RegisterGrowl();
 
             StatusLabel.Text = Properties.Resources.Form1_LoadText1;       //画面右下の状態表示を変更
@@ -1117,7 +1102,7 @@ namespace OpenTween
             SetMainWindowTitle();
             SetNotifyIconText();
 
-            if (!this._cfgCommon.MinimizeToTray || this.WindowState != FormWindowState.Minimized)
+            if (!SettingManager.Common.MinimizeToTray || this.WindowState != FormWindowState.Minimized)
             {
                 this.Visible = true;
             }
@@ -1136,7 +1121,7 @@ namespace OpenTween
             this.TweenMain_Resize(null, null);
             if (saveRequired) SaveConfigsAll(false);
 
-            foreach (var ua in this._cfgCommon.UserAccounts)
+            foreach (var ua in SettingManager.Common.UserAccounts)
             {
                 if (ua.UserId == 0 && ua.Username.ToLowerInvariant() == tw.Username.ToLowerInvariant())
                 {
@@ -1154,7 +1139,7 @@ namespace OpenTween
 
         private void InitDetailHtmlFormat()
         {
-            if (this._cfgCommon.IsMonospace)
+            if (SettingManager.Common.IsMonospace)
             {
                 detailHtmlFormatHeader = detailHtmlFormatHeaderMono;
                 detailHtmlFormatFooter = detailHtmlFormatFooterMono;
@@ -1168,9 +1153,9 @@ namespace OpenTween
             detailHtmlFormatHeader = detailHtmlFormatHeader
                     .Replace("%FONT_FAMILY%", _fntDetail.Name)
                     .Replace("%FONT_SIZE%", _fntDetail.Size.ToString())
-                    .Replace("%FONT_COLOR%", _clDetail.R.ToString() + "," + _clDetail.G.ToString() + "," + _clDetail.B.ToString())
-                    .Replace("%LINK_COLOR%", _clDetailLink.R.ToString() + "," + _clDetailLink.G.ToString() + "," + _clDetailLink.B.ToString())
-                    .Replace("%BG_COLOR%", _clDetailBackcolor.R.ToString() + "," + _clDetailBackcolor.G.ToString() + "," + _clDetailBackcolor.B.ToString())
+                    .Replace("%FONT_COLOR%", $"{_clDetail.R},{_clDetail.G},{_clDetail.B}")
+                    .Replace("%LINK_COLOR%", $"{_clDetailLink.R},{_clDetailLink.G},{_clDetailLink.B}")
+                    .Replace("%BG_COLOR%", $"{_clDetailBackcolor.R},{_clDetailBackcolor.G},{_clDetailBackcolor.B}")
                     .Replace("%BG_REPLY_COLOR%", $"{_clAtTo.R}, {_clAtTo.G}, {_clAtTo.B}");
         }
 
@@ -1208,31 +1193,14 @@ namespace OpenTween
 
         private void LoadConfig()
         {
-            _cfgCommon = SettingCommon.Load();
-            SettingCommon.Instance = this._cfgCommon;
-            if (_cfgCommon.UserAccounts == null || _cfgCommon.UserAccounts.Count == 0)
-            {
-                _cfgCommon.UserAccounts = new List<UserAccount>();
-                if (!string.IsNullOrEmpty(_cfgCommon.UserName))
-                {
-                    UserAccount account = new UserAccount();
-                    account.Username = _cfgCommon.UserName;
-                    account.UserId = _cfgCommon.UserId;
-                    account.Token = _cfgCommon.Token;
-                    account.TokenSecret = _cfgCommon.TokenSecret;
-
-                    _cfgCommon.UserAccounts.Add(account);
-                }
-            }
-
-            _cfgLocal = SettingLocal.Load();
+            SettingManager.Local = SettingManager.Local;
 
             // v1.2.4 以前の設定には ScaleDimension の項目がないため、現在の DPI と同じとして扱う
-            if (_cfgLocal.ScaleDimension.IsEmpty)
-                _cfgLocal.ScaleDimension = this.CurrentAutoScaleDimensions;
+            if (SettingManager.Local.ScaleDimension.IsEmpty)
+                SettingManager.Local.ScaleDimension = this.CurrentAutoScaleDimensions;
 
-            var tabsSetting = SettingTabs.Load().Tabs;
-            foreach (var tabSetting in tabsSetting)
+            var tabSettings = SettingManager.Tabs;
+            foreach (var tabSetting in tabSettings.Tabs)
             {
                 TabModel tab;
                 switch (tabSetting.TabType)
@@ -1330,51 +1298,51 @@ namespace OpenTween
             var refreshTasks = new List<Task>();
 
             ////タイマー初期化
-            if (ResetTimers.Timeline || homeCounter <= 0 && this._cfgCommon.TimelinePeriod > 0)
+            if (ResetTimers.Timeline || homeCounter <= 0 && SettingManager.Common.TimelinePeriod > 0)
             {
-                Interlocked.Exchange(ref homeCounter, this._cfgCommon.TimelinePeriod);
+                Interlocked.Exchange(ref homeCounter, SettingManager.Common.TimelinePeriod);
                 if (!tw.IsUserstreamDataReceived && !ResetTimers.Timeline)
                     refreshTasks.Add(this.GetHomeTimelineAsync());
                 ResetTimers.Timeline = false;
             }
-            if (ResetTimers.Reply || mentionCounter <= 0 && this._cfgCommon.ReplyPeriod > 0)
+            if (ResetTimers.Reply || mentionCounter <= 0 && SettingManager.Common.ReplyPeriod > 0)
             {
-                Interlocked.Exchange(ref mentionCounter, this._cfgCommon.ReplyPeriod);
+                Interlocked.Exchange(ref mentionCounter, SettingManager.Common.ReplyPeriod);
                 if (!tw.IsUserstreamDataReceived && !ResetTimers.Reply)
                     refreshTasks.Add(this.GetReplyAsync());
                 ResetTimers.Reply = false;
             }
-            if (ResetTimers.DirectMessage || dmCounter <= 0 && this._cfgCommon.DMPeriod > 0)
+            if (ResetTimers.DirectMessage || dmCounter <= 0 && SettingManager.Common.DMPeriod > 0)
             {
-                Interlocked.Exchange(ref dmCounter, this._cfgCommon.DMPeriod);
+                Interlocked.Exchange(ref dmCounter, SettingManager.Common.DMPeriod);
                 if (!tw.IsUserstreamDataReceived && !ResetTimers.DirectMessage)
                     refreshTasks.Add(this.GetDirectMessagesAsync());
                 ResetTimers.DirectMessage = false;
             }
-            if (ResetTimers.PublicSearch || pubSearchCounter <= 0 && this._cfgCommon.PubSearchPeriod > 0)
+            if (ResetTimers.PublicSearch || pubSearchCounter <= 0 && SettingManager.Common.PubSearchPeriod > 0)
             {
-                Interlocked.Exchange(ref pubSearchCounter, this._cfgCommon.PubSearchPeriod);
+                Interlocked.Exchange(ref pubSearchCounter, SettingManager.Common.PubSearchPeriod);
                 if (!ResetTimers.PublicSearch)
                     refreshTasks.Add(this.GetPublicSearchAllAsync());
                 ResetTimers.PublicSearch = false;
             }
-            if (ResetTimers.UserTimeline || userTimelineCounter <= 0 && this._cfgCommon.UserTimelinePeriod > 0)
+            if (ResetTimers.UserTimeline || userTimelineCounter <= 0 && SettingManager.Common.UserTimelinePeriod > 0)
             {
-                Interlocked.Exchange(ref userTimelineCounter, this._cfgCommon.UserTimelinePeriod);
+                Interlocked.Exchange(ref userTimelineCounter, SettingManager.Common.UserTimelinePeriod);
                 if (!ResetTimers.UserTimeline)
                     refreshTasks.Add(this.GetUserTimelineAllAsync());
                 ResetTimers.UserTimeline = false;
             }
-            if (ResetTimers.Lists || listsCounter <= 0 && this._cfgCommon.ListsPeriod > 0)
+            if (ResetTimers.Lists || listsCounter <= 0 && SettingManager.Common.ListsPeriod > 0)
             {
-                Interlocked.Exchange(ref listsCounter, this._cfgCommon.ListsPeriod);
+                Interlocked.Exchange(ref listsCounter, SettingManager.Common.ListsPeriod);
                 if (!ResetTimers.Lists)
                     refreshTasks.Add(this.GetListTimelineAllAsync());
                 ResetTimers.Lists = false;
             }
-            if (ResetTimers.UserStream || usCounter <= 0 && this._cfgCommon.UserstreamPeriod > 0)
+            if (ResetTimers.UserStream || usCounter <= 0 && SettingManager.Common.UserstreamPeriod > 0)
             {
-                Interlocked.Exchange(ref usCounter, this._cfgCommon.UserstreamPeriod);
+                Interlocked.Exchange(ref usCounter, SettingManager.Common.UserstreamPeriod);
                 if (this.tw.UserStreamActive)
                     this.RefreshTimeline();
                 ResetTimers.UserStream = false;
@@ -1415,64 +1383,71 @@ namespace OpenTween
 
         private void RefreshTimeline()
         {
+            var curTabModel = this._statuses.Tabs[this._curTab.Text];
+
             // 現在表示中のタブのスクロール位置を退避
-            var curListScroll = this.SaveListViewScroll(this._curList, this._statuses.Tabs[this._curTab.Text]);
+            var curListScroll = this.SaveListViewScroll(this._curList, curTabModel);
 
             // 各タブのリスト上の選択位置などを退避
             var listSelections = this.SaveListViewSelection();
 
             //更新確定
-            PostClass[] notifyPosts;
-            string soundFile;
             int addCount;
-            bool newMentionOrDm;
-            bool isDelete;
-            addCount = _statuses.SubmitUpdate(out soundFile, out notifyPosts, out newMentionOrDm, out isDelete);
+            addCount = _statuses.SubmitUpdate(out var soundFile, out var notifyPosts,
+                out var newMentionOrDm, out var isDelete);
 
             if (MyCommon._endingFlag) return;
 
-            //リストに反映&選択状態復元
-            try
+            // リストに反映&選択状態復元
+            foreach (var tabPage in this.ListTab.TabPages.Cast<TabPage>())
             {
-                foreach (TabPage tab in ListTab.TabPages)
+                var listView = (DetailsListView)tabPage.Tag;
+                var tabModel = this._statuses.Tabs[tabPage.Text];
+
+                if (listView.VirtualListSize != tabModel.AllCount || isDelete)
                 {
-                    DetailsListView lst = (DetailsListView)tab.Tag;
-                    TabModel tabInfo = _statuses.Tabs[tab.Text];
-                    if (isDelete || lst.VirtualListSize != tabInfo.AllCount)
+                    using (ControlTransaction.Update(listView))
                     {
-                        using (ControlTransaction.Update(lst))
-                        {
-                            if (lst.Equals(_curList))
-                            {
-                                this.PurgeListViewItemCache();
-                            }
-                            try
-                            {
-                                lst.VirtualListSize = tabInfo.AllCount; //リスト件数更新
-                            }
-                            catch (Exception)
-                            {
-                                //アイコン描画不具合あり?
-                            }
+                        if (listView == this._curList)
+                            this.PurgeListViewItemCache();
 
-                            // 選択位置などを復元
-                            this.RestoreListViewSelection(lst, tabInfo, listSelections[tabInfo.TabName]);
+                        try
+                        {
+                            // リスト件数更新
+                            listView.VirtualListSize = tabModel.AllCount;
+                        }
+                        catch (NullReferenceException ex)
+                        {
+                            // WinForms 内部で ListView.set_TopItem が発生させている例外
+                            // https://ja.osdn.net/ticket/browse.php?group_id=6526&tid=36588
+                            MyCommon.TraceOut(ex, $"TabType: {tabModel.TabType}, Count: {tabModel.AllCount}, ListSize: {listView.VirtualListSize}");
                         }
+
+                        // 選択位置などを復元
+                        this.RestoreListViewSelection(listView, tabModel, listSelections[tabModel.TabName]);
                     }
-                    if (tabInfo.UnreadCount > 0)
-                        if (this._cfgCommon.TabIconDisp)
-                            if (tab.ImageIndex == -1) tab.ImageIndex = 0; //タブアイコン
                 }
-                if (!this._cfgCommon.TabIconDisp) ListTab.Refresh();
             }
-            catch (Exception)
+
+            if (addCount > 0)
             {
-                //ex.Data["Msg"] = "Ref1, UseAPI=" + SettingDialog.UseAPI.ToString();
-                //throw;
+                if (SettingManager.Common.TabIconDisp)
+                {
+                    foreach (var tabPage in this.ListTab.TabPages.Cast<TabPage>())
+                    {
+                        var tabModel = this._statuses.Tabs[tabPage.Text];
+                        if (tabModel.UnreadCount > 0 && tabPage.ImageIndex != 0)
+                            tabPage.ImageIndex = 0; // 未読アイコン
+                    }
+                }
+                else
+                {
+                    this.ListTab.Refresh();
+                }
             }
 
             // スクロール位置を復元
-            this.RestoreListViewScroll(this._curList, this._statuses.Tabs[this._curTab.Text], curListScroll);
+            this.RestoreListViewScroll(this._curList, curTabModel, curListScroll);
 
             //新着通知
             NotifyNewPosts(notifyPosts, soundFile, addCount, newMentionOrDm);
@@ -1517,9 +1492,9 @@ namespace OpenTween
 
             if (listScroll.ScrollLockMode == ScrollLockMode.FixedToItem)
             {
-                var topItem = listView.TopItem;
-                if (topItem != null)
-                    listScroll.TopItemStatusId = tab.GetStatusIdAt(topItem.Index);
+                var topItemIndex = listView.TopItem?.Index ?? -1;
+                if (topItemIndex != -1 && topItemIndex < tab.AllCount)
+                    listScroll.TopItemStatusId = tab.GetStatusIdAt(topItemIndex);
             }
 
             return listScroll;
@@ -1583,32 +1558,35 @@ namespace OpenTween
                 var listView = (DetailsListView)tabPage.Tag;
                 var tab = _statuses.Tabs[tabPage.Text];
 
-                ListViewSelection listStatus;
-                if (listView.VirtualListSize != 0)
-                {
-                    listStatus = new ListViewSelection
-                    {
-                        SelectedStatusIds = this.GetSelectedStatusIds(listView, tab),
-                        FocusedStatusId = this.GetFocusedStatusId(listView, tab),
-                        SelectionMarkStatusId = this.GetSelectionMarkStatusId(listView, tab),
-                    };
-                }
-                else
-                {
-                    listStatus = new ListViewSelection
-                    {
-                        SelectedStatusIds = new long[0],
-                        SelectionMarkStatusId = null,
-                        FocusedStatusId = null,
-                    };
-                }
-
-                listsDict[tab.TabName] = listStatus;
+                listsDict[tab.TabName] = this.SaveListViewSelection(listView, tab);
             }
 
             return listsDict;
         }
 
+        /// <summary>
+        /// <see cref="ListView"/> の選択状態を <see cref="ListViewSelection"/> として返します
+        /// </summary>
+        private ListViewSelection SaveListViewSelection(DetailsListView listView, TabModel tab)
+        {
+            if (listView.VirtualListSize == 0)
+            {
+                return new ListViewSelection
+                {
+                    SelectedStatusIds = new long[0],
+                    SelectionMarkStatusId = null,
+                    FocusedStatusId = null,
+                };
+            }
+
+            return new ListViewSelection
+            {
+                SelectedStatusIds = this.GetSelectedStatusIds(listView, tab),
+                FocusedStatusId = this.GetFocusedStatusId(listView, tab),
+                SelectionMarkStatusId = this.GetSelectionMarkStatusId(listView, tab),
+            };
+        }
+
         private long[] GetSelectedStatusIds(DetailsListView listView, TabModel tab)
         {
             var selectedIndices = listView.SelectedIndices;
@@ -1620,16 +1598,16 @@ namespace OpenTween
 
         private long? GetFocusedStatusId(DetailsListView listView, TabModel tab)
         {
-            var focusedItem = listView.FocusedItem;
+            var index = listView.FocusedItem?.Index ?? -1;
 
-            return focusedItem != null ? tab.GetStatusIdAt(focusedItem.Index) : (long?)null;
+            return index != -1 && index < tab.AllCount ? tab.GetStatusIdAt(index) : (long?)null;
         }
 
         private long? GetSelectionMarkStatusId(DetailsListView listView, TabModel tab)
         {
-            var selectionMarkIndex = listView.SelectionMark;
+            var index = listView.SelectionMark;
 
-            return selectionMarkIndex != -1 ? tab.GetStatusIdAt(selectionMarkIndex) : (long?)null;
+            return index != -1 && index < tab.AllCount ? tab.GetStatusIdAt(index) : (long?)null;
         }
 
         /// <summary>
@@ -1660,7 +1638,7 @@ namespace OpenTween
         }
 
         /// <summary>
-        /// <see cref="SaveListViewStatus"/> によって保存された選択状態を復元します
+        /// <see cref="SaveListViewSelection"/> によって保存された選択状態を復元します
         /// </summary>
         private void RestoreListViewSelection(DetailsListView listView, TabModel tab, ListViewSelection listSelection)
         {
@@ -1693,10 +1671,10 @@ namespace OpenTween
             if (type == MyCommon.EVENTTYPE.None)
                 return true;
 
-            if (!this._cfgCommon.EventNotifyEnabled)
+            if (!SettingManager.Common.EventNotifyEnabled)
                 return false;
 
-            return this._cfgCommon.EventNotifyFlag.HasFlag(type);
+            return SettingManager.Common.EventNotifyFlag.HasFlag(type);
         }
 
         private bool IsMyEventNotityAsEventType(Twitter.FormattedEvent ev)
@@ -1704,7 +1682,7 @@ namespace OpenTween
             if (!ev.IsMe)
                 return true;
 
-            return this._cfgCommon.IsMyEventNotifyFlag.HasFlag(ev.Eventtype);
+            return SettingManager.Common.IsMyEventNotifyFlag.HasFlag(ev.Eventtype);
         }
 
         private bool BalloonRequired(Twitter.FormattedEvent ev)
@@ -1719,12 +1697,12 @@ namespace OpenTween
             if (!this.NewPostPopMenuItem.Checked)
             {
                 // 「新着通知が無効でもイベントを通知する」にも該当しない
-                if (!this._cfgCommon.ForceEventNotify || ev.Eventtype == MyCommon.EVENTTYPE.None)
+                if (!SettingManager.Common.ForceEventNotify || ev.Eventtype == MyCommon.EVENTTYPE.None)
                     return false;
             }
 
             // 「画面最小化・アイコン時のみバルーンを表示する」が有効
-            if (this._cfgCommon.LimitBalloon)
+            if (SettingManager.Common.LimitBalloon)
             {
                 if (this.WindowState != FormWindowState.Minimized && this.Visible && Form.ActiveForm != null)
                     return false;
@@ -1735,7 +1713,7 @@ namespace OpenTween
 
         private void NotifyNewPosts(PostClass[] notifyPosts, string soundFile, int addCount, bool newMentions)
         {
-            if (this._cfgCommon.ReadOwnPost)
+            if (SettingManager.Common.ReadOwnPost)
             {
                 if (notifyPosts != null && notifyPosts.Length > 0 && notifyPosts.All(x => x.UserId == tw.UserId))
                     return;
@@ -1747,7 +1725,7 @@ namespace OpenTween
                 if (notifyPosts != null && notifyPosts.Length > 0)
                 {
                     //Growlは一個ずつばらして通知。ただし、3ポスト以上あるときはまとめる
-                    if (this._cfgCommon.IsUseNotifyGrowl)
+                    if (SettingManager.Common.IsUseNotifyGrowl)
                     {
                         StringBuilder sb = new StringBuilder();
                         bool reply = false;
@@ -1764,7 +1742,7 @@ namespace OpenTween
                             if (post.IsReply && !post.IsExcludeReply) reply = true;
                             if (post.IsDm) dm = true;
                             if (sb.Length > 0) sb.Append(System.Environment.NewLine);
-                            switch (this._cfgCommon.NameBalloon)
+                            switch (SettingManager.Common.NameBalloon)
                             {
                                 case MyCommon.NameBalloonEnum.UserID:
                                     sb.Append(post.ScreenName).Append(" : ");
@@ -1781,7 +1759,7 @@ namespace OpenTween
 
                             StringBuilder title = new StringBuilder();
                             GrowlHelper.NotifyType nt;
-                            if (this._cfgCommon.DispUsername)
+                            if (SettingManager.Common.DispUsername)
                             {
                                 title.Append(tw.Username);
                                 title.Append(" - ");
@@ -1834,7 +1812,7 @@ namespace OpenTween
                             if (post.IsReply && !post.IsExcludeReply) reply = true;
                             if (post.IsDm) dm = true;
                             if (sb.Length > 0) sb.Append(System.Environment.NewLine);
-                            switch (this._cfgCommon.NameBalloon)
+                            switch (SettingManager.Common.NameBalloon)
                             {
                                 case MyCommon.NameBalloonEnum.UserID:
                                     sb.Append(post.ScreenName).Append(" : ");
@@ -1849,7 +1827,7 @@ namespace OpenTween
                         //if (SettingDialog.DispUsername) { NotifyIcon1.BalloonTipTitle = tw.Username + " - "; } else { NotifyIcon1.BalloonTipTitle = ""; }
                         StringBuilder title = new StringBuilder();
                         ToolTipIcon ntIcon;
-                        if (this._cfgCommon.DispUsername)
+                        if (SettingManager.Common.DispUsername)
                         {
                             title.Append(tw.Username);
                             title.Append(" - ");
@@ -1898,7 +1876,7 @@ namespace OpenTween
             }
 
             //サウンド再生
-            if (!_initial && this._cfgCommon.PlaySound && !string.IsNullOrEmpty(soundFile))
+            if (!_initial && SettingManager.Common.PlaySound && !string.IsNullOrEmpty(soundFile))
             {
                 try
                 {
@@ -1918,7 +1896,7 @@ namespace OpenTween
             }
 
             //mentions新着時に画面ブリンク
-            if (!_initial && this._cfgCommon.BlinkNewMentions && newMentions && Form.ActiveForm == null)
+            if (!_initial && SettingManager.Common.BlinkNewMentions && newMentions && Form.ActiveForm == null)
             {
                 NativeMethods.FlashMyWindow(this.Handle, NativeMethods.FlashSpecification.FlashTray, 3);
             }
@@ -1956,16 +1934,14 @@ namespace OpenTween
             //Read:true=既読 false=未読
             //未読管理していなかったら既読として扱う
             if (!tabInfo.UnreadManage ||
-               !this._cfgCommon.UnreadManage) Read = true;
+               !SettingManager.Common.UnreadManage) Read = true;
 
             var listCache = this._listItemCache;
             if (listCache == null)
                 return;
 
             // キャッシュに含まれていないアイテムは対象外
-            ListViewItem itm;
-            PostClass post;
-            if (!listCache.TryGetValue(Index, out itm, out post))
+            if (!listCache.TryGetValue(Index, out var itm, out var post))
                 return;
 
             ChangeItemStyleRead(Read, itm, post, ((DetailsListView)_curTab.Tag));
@@ -1991,9 +1967,9 @@ namespace OpenTween
                 cl = _clFav;
             else if (Post.RetweetedId != null)
                 cl = _clRetweet;
-            else if (Post.IsOwl && (Post.IsDm || this._cfgCommon.OneWayLove))
+            else if (Post.IsOwl && (Post.IsDm || SettingManager.Common.OneWayLove))
                 cl = _clOWL;
-            else if (Read || !this._cfgCommon.UseUnreadStyle)
+            else if (Read || !SettingManager.Common.UseUnreadStyle)
                 cl = _clReaded;
             else
                 cl = _clUnread;
@@ -2001,13 +1977,13 @@ namespace OpenTween
             if (DList == null || Item.Index == -1)
             {
                 Item.ForeColor = cl;
-                if (this._cfgCommon.UseUnreadStyle)
+                if (SettingManager.Common.UseUnreadStyle)
                     Item.Font = fnt;
             }
             else
             {
                 DList.Update();
-                if (this._cfgCommon.UseUnreadStyle)
+                if (SettingManager.Common.UseUnreadStyle)
                     DList.ChangeItemFontAndColor(Item.Index, cl, fnt);
                 else
                     DList.ChangeItemForeColor(Item.Index, cl);
@@ -2119,7 +2095,7 @@ namespace OpenTween
             var inReplyToScreenName = this.inReplyTo?.Item2;
             _history[_history.Count - 1] = new PostingStatus(StatusText.Text, inReplyToStatusId, inReplyToScreenName);
 
-            if (this._cfgCommon.Nicoms)
+            if (SettingManager.Common.Nicoms)
             {
                 StatusText.SelectionStart = StatusText.Text.Length;
                 await UrlConvertAsync(MyCommon.UrlConverter.Nicoms);
@@ -2186,7 +2162,7 @@ namespace OpenTween
 
         private void TweenMain_FormClosing(object sender, FormClosingEventArgs e)
         {
-            if (!this._cfgCommon.CloseToExit && e.CloseReason == CloseReason.UserClosing && MyCommon._endingFlag == false)
+            if (!SettingManager.Common.CloseToExit && e.CloseReason == CloseReason.UserClosing && MyCommon._endingFlag == false)
             {
                 //_endingFlag=false:フォームの×ボタン
                 e.Cancel = true;
@@ -2243,9 +2219,10 @@ namespace OpenTween
 
             try
             {
-                var progress = new Progress<string>(x => this.StatusLabel.Text = x);
+                var homeTab = this._statuses.GetTabByType<HomeTabModel>();
+                await homeTab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
 
-                await this.GetHomeTimelineAsyncInternal(progress, this.workerCts.Token, loadMore);
+                this.RefreshTimeline();
             }
             catch (WebApiException ex)
             {
@@ -2258,42 +2235,6 @@ namespace OpenTween
             }
         }
 
-        private async Task GetHomeTimelineAsyncInternal(IProgress<string> p, CancellationToken ct, bool loadMore)
-        {
-            if (ct.IsCancellationRequested)
-                return;
-
-            if (!CheckAccountValid())
-                throw new WebApiException("Auth error. Check your account");
-
-            bool read;
-            if (!this._cfgCommon.UnreadManage)
-                read = true;
-            else
-                read = this._initial && this._cfgCommon.Read;
-
-            p.Report(string.Format(Properties.Resources.GetTimelineWorker_RunWorkerCompletedText5, loadMore ? -1 : 1));
-
-            await Task.Run(async () =>
-            {
-                await this.tw.GetTimelineApi(read, MyCommon.WORKERTYPE.Timeline, loadMore, this._initial)
-                    .ConfigureAwait(false);
-
-                // 新着時未読クリア
-                if (this._cfgCommon.ReadOldPosts)
-                    this._statuses.SetReadHomeTab();
-
-                var addCount = this._statuses.DistributePosts();
-            });
-
-            if (ct.IsCancellationRequested)
-                return;
-
-            p.Report(Properties.Resources.GetTimelineWorker_RunWorkerCompletedText1);
-
-            this.RefreshTimeline();
-        }
-
         private Task GetReplyAsync()
         {
             return this.GetReplyAsync(loadMore: false);
@@ -2305,9 +2246,10 @@ namespace OpenTween
 
             try
             {
-                var progress = new Progress<string>(x => this.StatusLabel.Text = x);
+                var replyTab = this._statuses.GetTabByType<MentionsTabModel>();
+                await replyTab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
 
-                await this.GetReplyAsyncInternal(progress, this.workerCts.Token, loadMore);
+                this.RefreshTimeline();
             }
             catch (WebApiException ex)
             {
@@ -2320,38 +2262,6 @@ namespace OpenTween
             }
         }
 
-        private async Task GetReplyAsyncInternal(IProgress<string> p, CancellationToken ct, bool loadMore)
-        {
-            if (ct.IsCancellationRequested)
-                return;
-
-            if (!CheckAccountValid())
-                throw new WebApiException("Auth error. Check your account");
-
-            bool read;
-            if (!this._cfgCommon.UnreadManage)
-                read = true;
-            else
-                read = this._initial && this._cfgCommon.Read;
-
-            p.Report(string.Format(Properties.Resources.GetTimelineWorker_RunWorkerCompletedText4, loadMore ? -1 : 1));
-
-            await Task.Run(async () =>
-            {
-                await this.tw.GetTimelineApi(read, MyCommon.WORKERTYPE.Reply, loadMore, this._initial)
-                    .ConfigureAwait(false);
-
-                this._statuses.DistributePosts();
-            });
-
-            if (ct.IsCancellationRequested)
-                return;
-
-            p.Report(Properties.Resources.GetTimelineWorker_RunWorkerCompletedText9);
-
-            this.RefreshTimeline();
-        }
-
         private Task GetDirectMessagesAsync()
         {
             return this.GetDirectMessagesAsync(loadMore: false);
@@ -2363,9 +2273,10 @@ namespace OpenTween
 
             try
             {
-                var progress = new Progress<string>(x => this.StatusLabel.Text = x);
+                var dmTab = this._statuses.GetTabByType<DirectMessagesTabModel>();
+                await dmTab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
 
-                await this.GetDirectMessagesAsyncInternal(progress, this.workerCts.Token, loadMore);
+                this.RefreshTimeline();
             }
             catch (WebApiException ex)
             {
@@ -2378,40 +2289,6 @@ namespace OpenTween
             }
         }
 
-        private async Task GetDirectMessagesAsyncInternal(IProgress<string> p, CancellationToken ct, bool loadMore)
-        {
-            if (ct.IsCancellationRequested)
-                return;
-
-            if (!CheckAccountValid())
-                throw new WebApiException("Auth error. Check your account");
-
-            bool read;
-            if (!this._cfgCommon.UnreadManage)
-                read = true;
-            else
-                read = this._initial && this._cfgCommon.Read;
-
-            p.Report(string.Format(Properties.Resources.GetTimelineWorker_RunWorkerCompletedText8, loadMore ? -1 : 1));
-
-            await Task.Run(async () =>
-            {
-                await this.tw.GetDirectMessageApi(read, MyCommon.WORKERTYPE.DirectMessegeRcv, loadMore)
-                    .ConfigureAwait(false);
-                await this.tw.GetDirectMessageApi(read, MyCommon.WORKERTYPE.DirectMessegeSnt, loadMore)
-                    .ConfigureAwait(false);
-
-                this._statuses.DistributePosts();
-            });
-
-            if (ct.IsCancellationRequested)
-                return;
-
-            p.Report(Properties.Resources.GetTimelineWorker_RunWorkerCompletedText11);
-
-            this.RefreshTimeline();
-        }
-
         private Task GetFavoritesAsync()
         {
             return this.GetFavoritesAsync(loadMore: false);
@@ -2423,9 +2300,10 @@ namespace OpenTween
 
             try
             {
-                var progress = new Progress<string>(x => this.StatusLabel.Text = x);
+                var favTab = this._statuses.GetTabByType<FavoritesTabModel>();
+                await favTab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
 
-                await this.GetFavoritesAsyncInternal(progress, this.workerCts.Token, loadMore);
+                this.RefreshTimeline();
             }
             catch (WebApiException ex)
             {
@@ -2438,38 +2316,6 @@ namespace OpenTween
             }
         }
 
-        private async Task GetFavoritesAsyncInternal(IProgress<string> p, CancellationToken ct, bool loadMore)
-        {
-            if (ct.IsCancellationRequested)
-                return;
-
-            if (!CheckAccountValid())
-                throw new WebApiException("Auth error. Check your account");
-
-            bool read;
-            if (!this._cfgCommon.UnreadManage)
-                read = true;
-            else
-                read = this._initial && this._cfgCommon.Read;
-
-            p.Report(Properties.Resources.GetTimelineWorker_RunWorkerCompletedText19);
-
-            await Task.Run(async () =>
-            {
-                await this.tw.GetFavoritesApi(read, loadMore)
-                    .ConfigureAwait(false);
-
-                this._statuses.DistributePosts();
-            });
-
-            if (ct.IsCancellationRequested)
-                return;
-
-            p.Report(Properties.Resources.GetTimelineWorker_RunWorkerCompletedText20);
-
-            this.RefreshTimeline();
-        }
-
         private Task GetPublicSearchAllAsync()
         {
             var tabs = this._statuses.GetTabsByType<PublicSearchTabModel>();
@@ -2493,73 +2339,25 @@ namespace OpenTween
 
             try
             {
-                var progress = new Progress<string>(x => this.StatusLabel.Text = x);
-
-                await this.GetPublicSearchAsyncInternal(progress, this.workerCts.Token, tabs, loadMore);
-            }
-            catch (WebApiException ex)
-            {
-                this._myStatusError = true;
-                this.StatusLabel.Text = ex.Message;
-            }
-            finally
-            {
-                this.workerSemaphore.Release();
-            }
-        }
-
-        private async Task GetPublicSearchAsyncInternal(IProgress<string> p, CancellationToken ct, IEnumerable<PublicSearchTabModel> tabs, bool loadMore)
-        {
-            if (ct.IsCancellationRequested)
-                return;
-
-            if (!CheckAccountValid())
-                throw new WebApiException("Auth error. Check your account");
-
-            bool read;
-            if (!this._cfgCommon.UnreadManage)
-                read = true;
-            else
-                read = this._initial && this._cfgCommon.Read;
-
-            p.Report("Search refreshing...");
-
-            await Task.Run(async () =>
-            {
-                WebApiException lastException = null;
-
                 foreach (var tab in tabs)
                 {
                     try
                     {
-                        if (string.IsNullOrEmpty(tab.SearchWords))
-                            continue;
-
-                        await this.tw.GetSearch(read, tab, false)
-                            .ConfigureAwait(false);
-
-                        if (loadMore)
-                            await this.tw.GetSearch(read, tab, true)
-                                .ConfigureAwait(false);
+                        await tab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
                     }
                     catch (WebApiException ex)
                     {
-                        lastException = ex;
+                        this._myStatusError = true;
+                        this.StatusLabel.Text = $"Err:{ex.Message}(GetSearch)";
                     }
                 }
 
-                this._statuses.DistributePosts();
-
-                if (lastException != null)
-                    throw new WebApiException(lastException.Message, lastException);
-            });
-
-            if (ct.IsCancellationRequested)
-                return;
-
-            p.Report("Search refreshed");
-
-            this.RefreshTimeline();
+                this.RefreshTimeline();
+            }
+            finally
+            {
+                this.workerSemaphore.Release();
+            }
         }
 
         private Task GetUserTimelineAllAsync()
@@ -2585,69 +2383,25 @@ namespace OpenTween
 
             try
             {
-                var progress = new Progress<string>(x => this.StatusLabel.Text = x);
-
-                await this.GetUserTimelineAsyncInternal(progress, this.workerCts.Token, tabs, loadMore);
-            }
-            catch (WebApiException ex)
-            {
-                this._myStatusError = true;
-                this.StatusLabel.Text = $"Err:{ex.Message}(GetUserTimeline)";
-            }
-            finally
-            {
-                this.workerSemaphore.Release();
-            }
-        }
-
-        private async Task GetUserTimelineAsyncInternal(IProgress<string> p, CancellationToken ct, IEnumerable<UserTimelineTabModel> tabs, bool loadMore)
-        {
-            if (ct.IsCancellationRequested)
-                return;
-
-            if (!CheckAccountValid())
-                throw new WebApiException("Auth error. Check your account");
-
-            bool read;
-            if (!this._cfgCommon.UnreadManage)
-                read = true;
-            else
-                read = this._initial && this._cfgCommon.Read;
-
-            p.Report("UserTimeline refreshing...");
-
-            await Task.Run(async () =>
-            {
-                WebApiException lastException = null;
-
                 foreach (var tab in tabs)
                 {
                     try
                     {
-                        if (string.IsNullOrEmpty(tab.ScreenName))
-                            continue;
-
-                        await this.tw.GetUserTimelineApi(read, tab.ScreenName, tab, loadMore)
-                            .ConfigureAwait(false);
+                        await tab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
                     }
                     catch (WebApiException ex)
                     {
-                        lastException = ex;
+                        this._myStatusError = true;
+                        this.StatusLabel.Text = $"Err:{ex.Message}(GetUserTimeline)";
                     }
                 }
 
-                this._statuses.DistributePosts();
-
-                if (lastException != null)
-                    throw new WebApiException(lastException.Message, lastException);
-            });
-
-            if (ct.IsCancellationRequested)
-                return;
-
-            p.Report("UserTimeline refreshed");
-
-            this.RefreshTimeline();
+                this.RefreshTimeline();
+            }
+            finally
+            {
+                this.workerSemaphore.Release();
+            }
         }
 
         private Task GetListTimelineAllAsync()
@@ -2673,69 +2427,25 @@ namespace OpenTween
 
             try
             {
-                var progress = new Progress<string>(x => this.StatusLabel.Text = x);
-
-                await this.GetListTimelineAsyncInternal(progress, this.workerCts.Token, tabs, loadMore);
-            }
-            catch (WebApiException ex)
-            {
-                this._myStatusError = true;
-                this.StatusLabel.Text = $"Err:{ex.Message}(GetListStatus)";
-            }
-            finally
-            {
-                this.workerSemaphore.Release();
-            }
-        }
-
-        private async Task GetListTimelineAsyncInternal(IProgress<string> p, CancellationToken ct, IEnumerable<ListTimelineTabModel> tabs, bool loadMore)
-        {
-            if (ct.IsCancellationRequested)
-                return;
-
-            if (!CheckAccountValid())
-                throw new WebApiException("Auth error. Check your account");
-
-            bool read;
-            if (!this._cfgCommon.UnreadManage)
-                read = true;
-            else
-                read = this._initial && this._cfgCommon.Read;
-
-            p.Report("List refreshing...");
-
-            await Task.Run(async () =>
-            {
-                WebApiException lastException = null;
-
                 foreach (var tab in tabs)
                 {
                     try
                     {
-                        if (tab.ListInfo == null || tab.ListInfo.Id == 0)
-                            continue;
-
-                        await this.tw.GetListStatus(read, tab, loadMore, this._initial)
-                            .ConfigureAwait(false);
+                        await tab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
                     }
                     catch (WebApiException ex)
                     {
-                        lastException = ex;
+                        this._myStatusError = true;
+                        this.StatusLabel.Text = $"Err:{ex.Message}(GetListStatus)";
                     }
                 }
 
-                this._statuses.DistributePosts();
-
-                if (lastException != null)
-                    throw new WebApiException(lastException.Message, lastException);
-            });
-
-            if (ct.IsCancellationRequested)
-                return;
-
-            p.Report("List refreshed");
-
-            this.RefreshTimeline();
+                this.RefreshTimeline();
+            }
+            finally
+            {
+                this.workerSemaphore.Release();
+            }
         }
 
         private async Task GetRelatedTweetsAsync(RelatedPostsTabModel tab)
@@ -2744,9 +2454,9 @@ namespace OpenTween
 
             try
             {
-                var progress = new Progress<string>(x => this.StatusLabel.Text = x);
+                await tab.RefreshAsync(this.tw, this._initial, this.workerProgress);
 
-                await this.GetRelatedTweetsAsyncInternal(progress, this.workerCts.Token, tab);
+                this.RefreshTimeline();
             }
             catch (WebApiException ex)
             {
@@ -2759,55 +2469,6 @@ namespace OpenTween
             }
         }
 
-        private async Task GetRelatedTweetsAsyncInternal(IProgress<string> p, CancellationToken ct, RelatedPostsTabModel tab)
-        {
-            if (ct.IsCancellationRequested)
-                return;
-
-            if (!CheckAccountValid())
-                throw new WebApiException("Auth error. Check your account");
-
-            bool read;
-            if (!this._cfgCommon.UnreadManage)
-                read = true;
-            else
-                read = this._initial && this._cfgCommon.Read;
-
-            p.Report("Related refreshing...");
-
-            await Task.Run(async () =>
-            {
-                await this.tw.GetRelatedResult(read, tab)
-                    .ConfigureAwait(false);
-
-                this._statuses.DistributePosts();
-            });
-
-            if (ct.IsCancellationRequested)
-                return;
-
-            p.Report("Related refreshed");
-
-            this.RefreshTimeline();
-
-            var tabPage = this.ListTab.TabPages.Cast<TabPage>()
-                .FirstOrDefault(x => x.Text == tab.TabName);
-
-            if (tabPage != null)
-            {
-                // TODO: 非同期更新中にタブが閉じられている場合を厳密に考慮したい
-
-                var listView = (DetailsListView)tabPage.Tag;
-                var index = tab.IndexOf(tab.TargetPost.RetweetedId ?? tab.TargetPost.StatusId);
-
-                if (index != -1 && index < listView.Items.Count)
-                {
-                    listView.SelectedIndices.Add(index);
-                    listView.Items[index].Focused = true;
-                }
-            }
-        }
-
         private async Task FavAddAsync(long statusId, TabModel tab)
         {
             await this.workerSemaphore.WaitAsync();
@@ -2837,8 +2498,7 @@ namespace OpenTween
             if (!CheckAccountValid())
                 throw new WebApiException("Auth error. Check your account");
 
-            PostClass post;
-            if (!tab.Posts.TryGetValue(statusId, out post))
+            if (!tab.Posts.TryGetValue(statusId, out var post))
                 return;
 
             if (post.IsFav)
@@ -2854,7 +2514,7 @@ namespace OpenTween
                         .IgnoreResponse()
                         .ConfigureAwait(false);
 
-                    if (this._cfgCommon.RestrictFavCheck)
+                    if (SettingManager.Common.RestrictFavCheck)
                     {
                         var status = await this.twitterApi.StatusesShow(post.RetweetedId ?? post.StatusId)
                             .ConfigureAwait(false);
@@ -3094,6 +2754,13 @@ namespace OpenTween
                 p.Report(errMsg);
                 this._myStatusError = true;
             }
+            catch (UnauthorizedAccessException ex)
+            {
+                // アップロード対象のファイルが開けなかった場合など
+                errMsg = $"Err:{ex.Message}(PostMessage)";
+                p.Report(errMsg);
+                this._myStatusError = true;
+            }
             finally
             {
                 // 使い終わった MediaItem は破棄する
@@ -3113,13 +2780,10 @@ namespace OpenTween
                 !errMsg.StartsWith("OK:", StringComparison.Ordinal) &&
                 !errMsg.StartsWith("Warn:", StringComparison.Ordinal))
             {
+                var message = string.Format(Properties.Resources.StatusUpdateFailed, errMsg, status.status);
+
                 var ret = MessageBox.Show(
-                    string.Format(
-                        "{0}   --->   [ " + errMsg + " ]" + Environment.NewLine +
-                        "\"" + status.status + "\"" + Environment.NewLine +
-                        "{1}",
-                        Properties.Resources.StatusUpdateFailed1,
-                        Properties.Resources.StatusUpdateFailed2),
+                    message,
                     "Failed to update status",
                     MessageBoxButtons.RetryCancel,
                     MessageBoxIcon.Question);
@@ -3156,7 +2820,7 @@ namespace OpenTween
 
             this.SetMainWindowTitle();
 
-            if (this._cfgCommon.PostAndGet)
+            if (SettingManager.Common.PostAndGet)
             {
                 if (this.tw.UserStreamActive)
                     this.RefreshTimeline();
@@ -3174,6 +2838,9 @@ namespace OpenTween
                 var progress = new Progress<string>(x => this.StatusLabel.Text = x);
 
                 await this.RetweetAsyncInternal(progress, this.workerCts.Token, statusIds);
+
+                if (SettingManager.Common.PostAndGet && !this.tw.UserStreamActive)
+                    await this.GetHomeTimelineAsync();
             }
             catch (WebApiException ex)
             {
@@ -3195,18 +2862,17 @@ namespace OpenTween
                 throw new WebApiException("Auth error. Check your account");
 
             bool read;
-            if (!this._cfgCommon.UnreadManage)
+            if (!SettingManager.Common.UnreadManage)
                 read = true;
             else
-                read = this._initial && this._cfgCommon.Read;
+                read = this._initial && SettingManager.Common.Read;
 
             p.Report("Posting...");
 
-            var retweetTasks = from statusId in statusIds
-                               select this.tw.PostRetweet(statusId, read);
-
-            await Task.WhenAll(retweetTasks)
-                .ConfigureAwait(false);
+            foreach (var statusId in statusIds)
+            {
+                await this.tw.PostRetweet(statusId, read).ConfigureAwait(false);
+            }
 
             if (ct.IsCancellationRequested)
                 return;
@@ -3221,9 +2887,6 @@ namespace OpenTween
                 if (this._postTimestamps[i] < oneHour)
                     this._postTimestamps.RemoveAt(i);
             }
-
-            if (this._cfgCommon.PostAndGet && !this.tw.UserStreamActive)
-                await this.GetHomeTimelineAsync();
         }
 
         private async Task RefreshFollowerIdsAsync()
@@ -3353,7 +3016,7 @@ namespace OpenTween
 
         private async void MyList_MouseDoubleClick(object sender, MouseEventArgs e)
         {
-            switch (this._cfgCommon.ListDoubleClickAction)
+            switch (SettingManager.Common.ListDoubleClickAction)
             {
                 case 0:
                     MakeReplyOrDirectStatus();
@@ -3406,8 +3069,7 @@ namespace OpenTween
 
         private async Task FavoriteChange(bool FavAdd, bool multiFavoriteChangeDialogEnable = true)
         {
-            TabModel tab;
-            if (!this._statuses.Tabs.TryGetValue(this._curTab.Text, out tab))
+            if (!this._statuses.Tabs.TryGetValue(this._curTab.Text, out var tab))
                 return;
 
             //trueでFavAdd,falseでFavRemove
@@ -3471,9 +3133,7 @@ namespace OpenTween
             var listCache = this._listItemCache;
             if (listCache != null)
             {
-                ListViewItem item;
-                PostClass post;
-                if (listCache.TryGetValue(Index, out item, out post))
+                if (listCache.TryGetValue(Index, out var item, out var post))
                     return post;
             }
 
@@ -3554,8 +3214,7 @@ namespace OpenTween
         {
             // 表示上の列の位置から ColumnHeader を求める
             var col = this._curList.Columns.Cast<ColumnHeader>()
-                .Where(x => x.DisplayIndex == columnIndex)
-                .FirstOrDefault();
+                .FirstOrDefault(x => x.DisplayIndex == columnIndex);
 
             if (col == null)
                 return;
@@ -3589,7 +3248,7 @@ namespace OpenTween
         /// </summary>
         private void SetSortColumn(ComparerMode sortColumn)
         {
-            if (this._cfgCommon.SortOrderLock)
+            if (SettingManager.Common.SortOrderLock)
                 return;
 
             this._statuses.ToggleSortOrder(sortColumn);
@@ -3691,32 +3350,21 @@ namespace OpenTween
                 FavorareMenuItem.Enabled = true;
                 ShowRelatedStatusesMenuItem.Enabled = true;  //PublicSearchの時問題出るかも
 
-                if (_curPost.IsMe)
+                if (!_curPost.CanRetweetBy(this.twitterApi.CurrentUserId))
                 {
-                    ReTweetStripMenuItem.Enabled = false;  //公式RTは無効に
-                    ReTweetUnofficialStripMenuItem.Enabled = true;
-                    QuoteStripMenuItem.Enabled = true;
-                    FavoriteRetweetContextMenu.Enabled = false;  //公式RTは無効に
-                    FavoriteRetweetUnofficialContextMenu.Enabled = true;
+                    ReTweetStripMenuItem.Enabled = false;
+                    ReTweetUnofficialStripMenuItem.Enabled = false;
+                    QuoteStripMenuItem.Enabled = false;
+                    FavoriteRetweetContextMenu.Enabled = false;
+                    FavoriteRetweetUnofficialContextMenu.Enabled = false;
                 }
                 else
                 {
-                    if (_curPost.IsProtect)
-                    {
-                        ReTweetStripMenuItem.Enabled = false;
-                        ReTweetUnofficialStripMenuItem.Enabled = false;
-                        QuoteStripMenuItem.Enabled = false;
-                        FavoriteRetweetContextMenu.Enabled = false;
-                        FavoriteRetweetUnofficialContextMenu.Enabled = false;
-                    }
-                    else
-                    {
-                        ReTweetStripMenuItem.Enabled = true;
-                        ReTweetUnofficialStripMenuItem.Enabled = true;
-                        QuoteStripMenuItem.Enabled = true;
-                        FavoriteRetweetContextMenu.Enabled = true;
-                        FavoriteRetweetUnofficialContextMenu.Enabled = true;
-                    }
+                    ReTweetStripMenuItem.Enabled = true;
+                    ReTweetUnofficialStripMenuItem.Enabled = true;
+                    QuoteStripMenuItem.Enabled = true;
+                    FavoriteRetweetContextMenu.Enabled = true;
+                    FavoriteRetweetUnofficialContextMenu.Enabled = true;
                 }
             }
             //if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType != MyCommon.TabUsageType.Favorites)
@@ -3808,14 +3456,29 @@ namespace OpenTween
                         }
                         else
                         {
-                            if (post.RetweetedId != null && post.UserId == this.tw.UserId)
-                                // 他人に RT された自分のツイート
-                                await this.twitterApi.StatusesDestroy(post.RetweetedId.Value)
-                                    .IgnoreResponse();
-                            else
-                                // 自分のツイート or 自分が RT したツイート
+                            if (post.RetweetedByUserId == this.tw.UserId)
+                            {
+                                // 自分が RT したツイート (自分が RT した自分のツイートも含む)
+                                //   => RT を取り消し
                                 await this.twitterApi.StatusesDestroy(post.StatusId)
                                     .IgnoreResponse();
+                            }
+                            else
+                            {
+                                if (post.UserId == this.tw.UserId)
+                                {
+                                    if (post.RetweetedId != null)
+                                        // 他人に RT された自分のツイート
+                                        //   => RT 元の自分のツイートを削除
+                                        await this.twitterApi.StatusesDestroy(post.RetweetedId.Value)
+                                            .IgnoreResponse();
+                                    else
+                                        // 自分のツイート
+                                        //   => ツイートを削除
+                                        await this.twitterApi.StatusesDestroy(post.StatusId)
+                                            .IgnoreResponse();
+                                }
+                            }
                         }
                     }
                     catch (WebApiException ex)
@@ -3864,14 +3527,14 @@ namespace OpenTween
                         }
                     }
 
-                    if (this._cfgCommon.TabIconDisp && tab.UnreadCount == 0)
+                    if (SettingManager.Common.TabIconDisp && tab.UnreadCount == 0)
                     {
                         if (tabPage.ImageIndex == 0)
                             tabPage.ImageIndex = -1; // タブアイコン
                     }
                 }
 
-                if (!this._cfgCommon.TabIconDisp)
+                if (!SettingManager.Common.TabIconDisp)
                     this.ListTab.Refresh();
             }
         }
@@ -3897,13 +3560,13 @@ namespace OpenTween
             {
                 if (_statuses.Tabs[tb.Text].UnreadCount == 0)
                 {
-                    if (this._cfgCommon.TabIconDisp)
+                    if (SettingManager.Common.TabIconDisp)
                     {
                         if (tb.ImageIndex == 0) tb.ImageIndex = -1; //タブアイコン
                     }
                 }
             }
-            if (!this._cfgCommon.TabIconDisp) ListTab.Refresh();
+            if (!SettingManager.Common.TabIconDisp) ListTab.Refresh();
         }
 
         private void UnreadStripMenuItem_Click(object sender, EventArgs e)
@@ -3922,13 +3585,13 @@ namespace OpenTween
             {
                 if (_statuses.Tabs[tb.Text].UnreadCount > 0)
                 {
-                    if (this._cfgCommon.TabIconDisp)
+                    if (SettingManager.Common.TabIconDisp)
                     {
                         if (tb.ImageIndex == -1) tb.ImageIndex = 0; //タブアイコン
                     }
                 }
             }
-            if (!this._cfgCommon.TabIconDisp) ListTab.Refresh();
+            if (!SettingManager.Common.TabIconDisp) ListTab.Refresh();
         }
 
         private async void RefreshStripMenuItem_Click(object sender, EventArgs e)
@@ -3940,33 +3603,28 @@ namespace OpenTween
         {
             if (_curTab != null)
             {
-                TabModel tab;
-                if (!this._statuses.Tabs.TryGetValue(this._curTab.Text, out tab))
+                if (!this._statuses.Tabs.TryGetValue(this._curTab.Text, out var tab))
                     return;
 
-                switch (_statuses.Tabs[_curTab.Text].TabType)
+                switch (tab)
                 {
-                    case MyCommon.TabUsageType.Mentions:
+                    case MentionsTabModel replyTab:
                         await this.GetReplyAsync();
                         break;
-                    case MyCommon.TabUsageType.DirectMessage:
+                    case DirectMessagesTabModel dmTab:
                         await this.GetDirectMessagesAsync();
                         break;
-                    case MyCommon.TabUsageType.Favorites:
+                    case FavoritesTabModel favTab:
                         await this.GetFavoritesAsync();
                         break;
-                    //case MyCommon.TabUsageType.Profile:
-                        //// TODO
-                    case MyCommon.TabUsageType.PublicSearch:
-                        var searchTab = (PublicSearchTabModel)tab;
+                    case PublicSearchTabModel searchTab:
                         if (string.IsNullOrEmpty(searchTab.SearchWords)) return;
                         await this.GetPublicSearchAsync(searchTab);
                         break;
-                    case MyCommon.TabUsageType.UserTimeline:
-                        await this.GetUserTimelineAsync((UserTimelineTabModel)tab);
+                    case UserTimelineTabModel userTab:
+                        await this.GetUserTimelineAsync(userTab);
                         break;
-                    case MyCommon.TabUsageType.Lists:
-                        var listTab = (ListTimelineTabModel)tab;
+                    case ListTimelineTabModel listTab:
                         if (listTab.ListInfo == null || listTab.ListInfo.Id == 0) return;
                         await this.GetListTimelineAsync(listTab);
                         break;
@@ -3986,34 +3644,28 @@ namespace OpenTween
             //ページ指定をマイナス1に
             if (_curTab != null)
             {
-                TabModel tab;
-                if (!this._statuses.Tabs.TryGetValue(this._curTab.Text, out tab))
+                if (!this._statuses.Tabs.TryGetValue(this._curTab.Text, out var tab))
                     return;
 
-                switch (_statuses.Tabs[_curTab.Text].TabType)
+                switch (tab)
                 {
-                    case MyCommon.TabUsageType.Mentions:
+                    case MentionsTabModel replyTab:
                         await this.GetReplyAsync(loadMore: true);
                         break;
-                    case MyCommon.TabUsageType.DirectMessage:
+                    case DirectMessagesTabModel dmTab:
                         await this.GetDirectMessagesAsync(loadMore: true);
                         break;
-                    case MyCommon.TabUsageType.Favorites:
+                    case FavoritesTabModel favTab:
                         await this.GetFavoritesAsync(loadMore: true);
                         break;
-                    case MyCommon.TabUsageType.Profile:
-                        //// TODO
-                        break;
-                    case MyCommon.TabUsageType.PublicSearch:
-                        var searchTab = (PublicSearchTabModel)tab;
+                    case PublicSearchTabModel searchTab:
                         if (string.IsNullOrEmpty(searchTab.SearchWords)) return;
                         await this.GetPublicSearchAsync(searchTab, loadMore: true);
                         break;
-                    case MyCommon.TabUsageType.UserTimeline:
-                        await this.GetUserTimelineAsync((UserTimelineTabModel)tab, loadMore: true);
+                    case UserTimelineTabModel userTab:
+                        await this.GetUserTimelineAsync(userTab, loadMore: true);
                         break;
-                    case MyCommon.TabUsageType.Lists:
-                        var listTab = (ListTimelineTabModel)tab;
+                    case ListTimelineTabModel listTab:
                         if (listTab.ListInfo == null || listTab.ListInfo.Id == 0) return;
                         await this.GetListTimelineAsync(listTab, loadMore: true);
                         break;
@@ -4042,7 +3694,7 @@ namespace OpenTween
                 settingDialog.tw = this.tw;
                 settingDialog.twitterApi = this.twitterApi;
 
-                settingDialog.LoadConfig(this._cfgCommon, this._cfgLocal);
+                settingDialog.LoadConfig(SettingManager.Common, SettingManager.Local);
 
                 try
                 {
@@ -4057,7 +3709,7 @@ namespace OpenTween
                 {
                     lock (_syncObject)
                     {
-                        settingDialog.SaveConfig(this._cfgCommon, this._cfgLocal);
+                        settingDialog.SaveConfig(SettingManager.Common, SettingManager.Local);
                     }
                 }
             }
@@ -4070,30 +3722,31 @@ namespace OpenTween
             // 設定画面表示前のユーザー情報
             var oldUser = new { tw.AccessToken, tw.AccessTokenSecret, tw.Username, tw.UserId };
 
-            var oldIconSz = this._cfgCommon.IconSize;
+            var oldIconSz = SettingManager.Common.IconSize;
 
             if (ShowSettingDialog() == DialogResult.OK)
             {
                 lock (_syncObject)
                 {
-                    tw.RestrictFavCheck = this._cfgCommon.RestrictFavCheck;
-                    tw.ReadOwnPost = this._cfgCommon.ReadOwnPost;
-                    ShortUrl.Instance.DisableExpanding = !this._cfgCommon.TinyUrlResolve;
-                    ShortUrl.Instance.BitlyId = this._cfgCommon.BilyUser;
-                    ShortUrl.Instance.BitlyKey = this._cfgCommon.BitlyPwd;
-                    TwitterApiConnection.RestApiBase = this._cfgCommon.TwitterApiBaseUri;
+                    tw.RestrictFavCheck = SettingManager.Common.RestrictFavCheck;
+                    tw.ReadOwnPost = SettingManager.Common.ReadOwnPost;
+                    ShortUrl.Instance.DisableExpanding = !SettingManager.Common.TinyUrlResolve;
+                    ShortUrl.Instance.BitlyId = SettingManager.Common.BilyUser;
+                    ShortUrl.Instance.BitlyKey = SettingManager.Common.BitlyPwd;
+                    TwitterApiConnection.RestApiHost = SettingManager.Common.TwitterApiHost;
 
-                    Networking.DefaultTimeout = TimeSpan.FromSeconds(this._cfgCommon.DefaultTimeOut);
-                    Networking.SetWebProxy(this._cfgLocal.ProxyType,
-                        this._cfgLocal.ProxyAddress, this._cfgLocal.ProxyPort,
-                        this._cfgLocal.ProxyUser, this._cfgLocal.ProxyPassword);
-                    Networking.ForceIPv4 = this._cfgCommon.ForceIPv4;
+                    Networking.DefaultTimeout = TimeSpan.FromSeconds(SettingManager.Common.DefaultTimeOut);
+                    Networking.UploadImageTimeout = TimeSpan.FromSeconds(SettingManager.Common.UploadImageTimeout);
+                    Networking.SetWebProxy(SettingManager.Local.ProxyType,
+                        SettingManager.Local.ProxyAddress, SettingManager.Local.ProxyPort,
+                        SettingManager.Local.ProxyUser, SettingManager.Local.ProxyPassword);
+                    Networking.ForceIPv4 = SettingManager.Common.ForceIPv4;
 
                     ImageSelector.Reset(tw, this.tw.Configuration);
 
                     try
                     {
-                        if (this._cfgCommon.TabIconDisp)
+                        if (SettingManager.Common.TabIconDisp)
                         {
                             ListTab.DrawItem -= ListTab_DrawItem;
                             ListTab.DrawMode = TabDrawMode.Normal;
@@ -4116,11 +3769,11 @@ namespace OpenTween
 
                     try
                     {
-                        if (!this._cfgCommon.UnreadManage)
+                        if (!SettingManager.Common.UnreadManage)
                         {
                             ReadedStripMenuItem.Enabled = false;
                             UnreadStripMenuItem.Enabled = false;
-                            if (this._cfgCommon.TabIconDisp)
+                            if (SettingManager.Common.TabIconDisp)
                             {
                                 foreach (TabPage myTab in ListTab.TabPages)
                                 {
@@ -4144,35 +3797,35 @@ namespace OpenTween
                     // タブの表示位置の決定
                     SetTabAlignment();
 
-                    SplitContainer1.IsPanelInverted = !this._cfgCommon.StatusAreaAtBottom;
+                    SplitContainer1.IsPanelInverted = !SettingManager.Common.StatusAreaAtBottom;
 
                     var imgazyobizinet = ThumbnailGenerator.ImgAzyobuziNetInstance;
-                    imgazyobizinet.Enabled = this._cfgCommon.EnableImgAzyobuziNet;
-                    imgazyobizinet.DisabledInDM = this._cfgCommon.ImgAzyobuziNetDisabledInDM;
-
-                    this.PlaySoundMenuItem.Checked = this._cfgCommon.PlaySound;
-                    this.PlaySoundFileMenuItem.Checked = this._cfgCommon.PlaySound;
-                    _fntUnread = this._cfgLocal.FontUnread;
-                    _clUnread = this._cfgLocal.ColorUnread;
-                    _fntReaded = this._cfgLocal.FontRead;
-                    _clReaded = this._cfgLocal.ColorRead;
-                    _clFav = this._cfgLocal.ColorFav;
-                    _clOWL = this._cfgLocal.ColorOWL;
-                    _clRetweet = this._cfgLocal.ColorRetweet;
-                    _fntDetail = this._cfgLocal.FontDetail;
-                    _clDetail = this._cfgLocal.ColorDetail;
-                    _clDetailLink = this._cfgLocal.ColorDetailLink;
-                    _clDetailBackcolor = this._cfgLocal.ColorDetailBackcolor;
-                    _clSelf = this._cfgLocal.ColorSelf;
-                    _clAtSelf = this._cfgLocal.ColorAtSelf;
-                    _clTarget = this._cfgLocal.ColorTarget;
-                    _clAtTarget = this._cfgLocal.ColorAtTarget;
-                    _clAtFromTarget = this._cfgLocal.ColorAtFromTarget;
-                    _clAtTo = this._cfgLocal.ColorAtTo;
-                    _clListBackcolor = this._cfgLocal.ColorListBackcolor;
-                    _clInputBackcolor = this._cfgLocal.ColorInputBackcolor;
-                    _clInputFont = this._cfgLocal.ColorInputFont;
-                    _fntInputFont = this._cfgLocal.FontInputFont;
+                    imgazyobizinet.Enabled = SettingManager.Common.EnableImgAzyobuziNet;
+                    imgazyobizinet.DisabledInDM = SettingManager.Common.ImgAzyobuziNetDisabledInDM;
+
+                    this.PlaySoundMenuItem.Checked = SettingManager.Common.PlaySound;
+                    this.PlaySoundFileMenuItem.Checked = SettingManager.Common.PlaySound;
+                    _fntUnread = SettingManager.Local.FontUnread;
+                    _clUnread = SettingManager.Local.ColorUnread;
+                    _fntReaded = SettingManager.Local.FontRead;
+                    _clReaded = SettingManager.Local.ColorRead;
+                    _clFav = SettingManager.Local.ColorFav;
+                    _clOWL = SettingManager.Local.ColorOWL;
+                    _clRetweet = SettingManager.Local.ColorRetweet;
+                    _fntDetail = SettingManager.Local.FontDetail;
+                    _clDetail = SettingManager.Local.ColorDetail;
+                    _clDetailLink = SettingManager.Local.ColorDetailLink;
+                    _clDetailBackcolor = SettingManager.Local.ColorDetailBackcolor;
+                    _clSelf = SettingManager.Local.ColorSelf;
+                    _clAtSelf = SettingManager.Local.ColorAtSelf;
+                    _clTarget = SettingManager.Local.ColorTarget;
+                    _clAtTarget = SettingManager.Local.ColorAtTarget;
+                    _clAtFromTarget = SettingManager.Local.ColorAtFromTarget;
+                    _clAtTo = SettingManager.Local.ColorAtTo;
+                    _clListBackcolor = SettingManager.Local.ColorListBackcolor;
+                    _clInputBackcolor = SettingManager.Local.ColorInputBackcolor;
+                    _clInputFont = SettingManager.Local.ColorInputFont;
+                    _fntInputFont = SettingManager.Local.FontInputFont;
                     _brsBackColorMine.Dispose();
                     _brsBackColorAt.Dispose();
                     _brsBackColorYou.Dispose();
@@ -4214,7 +3867,7 @@ namespace OpenTween
                     {
                         foreach (TabPage tb in ListTab.TabPages)
                         {
-                            if (this._cfgCommon.TabIconDisp)
+                            if (SettingManager.Common.TabIconDisp)
                             {
                                 if (_statuses.Tabs[tb.Text].UnreadCount == 0)
                                     tb.ImageIndex = -1;
@@ -4234,8 +3887,8 @@ namespace OpenTween
                     {
                         var oldIconCol = _iconCol;
 
-                        if (this._cfgCommon.IconSize != oldIconSz)
-                            ApplyListViewIconSize(this._cfgCommon.IconSize);
+                        if (SettingManager.Common.IconSize != oldIconSz)
+                            ApplyListViewIconSize(SettingManager.Common.IconSize);
 
                         foreach (TabPage tp in ListTab.TabPages)
                         {
@@ -4243,7 +3896,7 @@ namespace OpenTween
 
                             using (ControlTransaction.Update(lst))
                             {
-                                lst.GridLines = this._cfgCommon.ShowGrid;
+                                lst.GridLines = SettingManager.Common.ShowGrid;
                                 lst.Font = _fntReaded;
                                 lst.BackColor = _clListBackcolor;
 
@@ -4267,23 +3920,23 @@ namespace OpenTween
                     ListTab.Refresh();
 
                     _hookGlobalHotkey.UnregisterAllOriginalHotkey();
-                    if (this._cfgCommon.HotkeyEnabled)
+                    if (SettingManager.Common.HotkeyEnabled)
                     {
                         ///グローバルホットキーの登録。設定で変更可能にするかも
                         HookGlobalHotkey.ModKeys modKey = HookGlobalHotkey.ModKeys.None;
-                        if ((this._cfgCommon.HotkeyModifier & Keys.Alt) == Keys.Alt)
+                        if ((SettingManager.Common.HotkeyModifier & Keys.Alt) == Keys.Alt)
                             modKey |= HookGlobalHotkey.ModKeys.Alt;
-                        if ((this._cfgCommon.HotkeyModifier & Keys.Control) == Keys.Control)
+                        if ((SettingManager.Common.HotkeyModifier & Keys.Control) == Keys.Control)
                             modKey |= HookGlobalHotkey.ModKeys.Ctrl;
-                        if ((this._cfgCommon.HotkeyModifier & Keys.Shift) == Keys.Shift)
+                        if ((SettingManager.Common.HotkeyModifier & Keys.Shift) == Keys.Shift)
                             modKey |=  HookGlobalHotkey.ModKeys.Shift;
-                        if ((this._cfgCommon.HotkeyModifier & Keys.LWin) == Keys.LWin)
+                        if ((SettingManager.Common.HotkeyModifier & Keys.LWin) == Keys.LWin)
                             modKey |= HookGlobalHotkey.ModKeys.Win;
 
-                        _hookGlobalHotkey.RegisterOriginalHotkey(this._cfgCommon.HotkeyKey, this._cfgCommon.HotkeyValue, modKey);
+                        _hookGlobalHotkey.RegisterOriginalHotkey(SettingManager.Common.HotkeyKey, SettingManager.Common.HotkeyValue, modKey);
                     }
 
-                    if (this._cfgCommon.IsUseNotifyGrowl) gh.RegisterGrowl();
+                    if (SettingManager.Common.IsUseNotifyGrowl) gh.RegisterGrowl();
                     try
                     {
                         StatusText_TextChanged(null, null);
@@ -4301,7 +3954,7 @@ namespace OpenTween
 
             Twitter.AccountState = MyCommon.ACCOUNT_STATE.Valid;
 
-            this.TopMost = this._cfgCommon.AlwaysTop;
+            this.TopMost = SettingManager.Common.AlwaysTop;
             SaveConfigsAll(false);
 
             if (tw.Username != oldUser.Username)
@@ -4313,7 +3966,7 @@ namespace OpenTween
         /// </summary>
         private void SetTabAlignment()
         {
-            var newAlignment = this._cfgCommon.ViewTabBottom ? TabAlignment.Bottom : TabAlignment.Top;
+            var newAlignment = SettingManager.Common.ViewTabBottom ? TabAlignment.Bottom : TabAlignment.Top;
             if (ListTab.Alignment == newAlignment) return;
 
             // 各タブのリスト上の選択位置などを退避
@@ -4395,29 +4048,6 @@ namespace OpenTween
             }
         }
 
-        private async void PostBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
-        {
-            if (e.Url.AbsoluteUri != "about:blank")
-            {
-                await this.DispSelectedPost();
-                await this.OpenUriInBrowserAsync(e.Url.OriginalString);
-            }
-        }
-
-        private async void PostBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
-        {
-            if (e.Url.Scheme == "data")
-            {
-                StatusLabelUrl.Text = PostBrowser.StatusText.Replace("&", "&&");
-            }
-            else if (e.Url.AbsoluteUri != "about:blank")
-            {
-                e.Cancel = true;
-                // Ctrlを押しながらリンクを開いた場合は、設定と逆の動作をするフラグを true としておく
-                await this.OpenUriAsync( e.Url, MyCommon.IsKeyDown( Keys.Control ) );
-            }
-        }
-
         public void AddNewTabForSearch(string searchWord)
         {
             //同一検索条件のタブが既に存在すれば、そのタブアクティブにして終了
@@ -4660,7 +4290,7 @@ namespace OpenTween
                 this.ListTab.Controls.Add(_tabPage);
 
                 _tabPage.Location = new Point(4, 4);
-                _tabPage.Name = "CTab" + cnt.ToString();
+                _tabPage.Name = "CTab" + cnt;
                 _tabPage.Size = new Size(380, 260);
                 _tabPage.TabIndex = 2 + cnt;
                 _tabPage.Text = tab.TabName;
@@ -4677,7 +4307,7 @@ namespace OpenTween
                 _listCustom.HideSelection = false;
                 _listCustom.Location = new Point(0, 0);
                 _listCustom.Margin = new Padding(0);
-                _listCustom.Name = "CList" + Environment.TickCount.ToString();
+                _listCustom.Name = "CList" + Environment.TickCount;
                 _listCustom.ShowItemToolTips = true;
                 _listCustom.Size = new Size(380, 260);
                 _listCustom.UseCompatibleStateImageBehavior = false;
@@ -4687,7 +4317,7 @@ namespace OpenTween
                 _listCustom.Font = _fntReaded;
                 _listCustom.BackColor = _clListBackcolor;
 
-                _listCustom.GridLines = this._cfgCommon.ShowGrid;
+                _listCustom.GridLines = SettingManager.Common.ShowGrid;
                 _listCustom.AllowDrop = true;
 
                 _listCustom.SmallImageList = _listViewImageList;
@@ -4833,10 +4463,7 @@ namespace OpenTween
             {
                 DetailsListView lst = (DetailsListView)tp.Tag;
                 var count = _statuses.Tabs[tp.Text].AllCount;
-                if (lst.VirtualListSize != count)
-                {
-                    lst.VirtualListSize = count;
-                }
+                lst.VirtualListSize = count;
             }
 
             return true;
@@ -4852,10 +4479,10 @@ namespace OpenTween
         {
             //タブのD&D
 
-            if (!this._cfgCommon.TabMouseLock && e.Button == MouseButtons.Left && _tabDrag)
+            if (!SettingManager.Common.TabMouseLock && e.Button == MouseButtons.Left && _tabDrag)
             {
                 string tn = "";
-                Rectangle dragEnableRectangle = new Rectangle((int)(_tabMouseDownPoint.X - (SystemInformation.DragSize.Width / 2)), (int)(_tabMouseDownPoint.Y - (SystemInformation.DragSize.Height / 2)), SystemInformation.DragSize.Width, SystemInformation.DragSize.Height);
+                Rectangle dragEnableRectangle = new Rectangle(_tabMouseDownPoint.X - (SystemInformation.DragSize.Width / 2), _tabMouseDownPoint.Y - (SystemInformation.DragSize.Height / 2), SystemInformation.DragSize.Width, SystemInformation.DragSize.Height);
                 if (!dragEnableRectangle.Contains(e.Location))
                 {
                     //タブが多段の場合にはMouseDownの前の段階で選択されたタブの段が変わっているので、このタイミングでカーソルの位置からタブを判定出来ない。
@@ -4942,31 +4569,11 @@ namespace OpenTween
             _isColumnChanged = false;
         }
 
-        private void PostBrowser_StatusTextChanged(object sender, EventArgs e)
-        {
-            try
-            {
-                if (PostBrowser.StatusText.StartsWith("http", StringComparison.Ordinal)
-                    || PostBrowser.StatusText.StartsWith("ftp", StringComparison.Ordinal)
-                    || PostBrowser.StatusText.StartsWith("data", StringComparison.Ordinal))
-                {
-                    StatusLabelUrl.Text = PostBrowser.StatusText.Replace("&", "&&");
-                }
-                if (string.IsNullOrEmpty(PostBrowser.StatusText))
-                {
-                    SetStatusLabelUrl();
-                }
-            }
-            catch (Exception)
-            {
-            }
-        }
-
         private void StatusText_KeyPress(object sender, KeyPressEventArgs e)
         {
             if (e.KeyChar == '@')
             {
-                if (!this._cfgCommon.UseAtIdSupplement) return;
+                if (!SettingManager.Common.UseAtIdSupplement) return;
                 //@マーク
                 int cnt = AtIdSupl.ItemCount;
                 ShowSuplDialog(StatusText, AtIdSupl);
@@ -4975,7 +4582,7 @@ namespace OpenTween
             }
             else if (e.KeyChar == '#')
             {
-                if (!this._cfgCommon.UseHashSupplement) return;
+                if (!SettingManager.Common.UseHashSupplement) return;
                 ShowSuplDialog(StatusText, HashSupl);
                 e.Handled = true;
             }
@@ -5002,7 +4609,7 @@ namespace OpenTween
             {
                 dialog.ShowDialog();
             }
-            this.TopMost = this._cfgCommon.AlwaysTop;
+            this.TopMost = SettingManager.Common.AlwaysTop;
             int selStart = owner.SelectionStart;
             string fHalf = "";
             string eHalf = "";
@@ -5049,7 +4656,7 @@ namespace OpenTween
                 if (e.KeyCode == Keys.Space || e.KeyCode == Keys.ProcessKey)
                 {
                     bool isSpace = false;
-                    foreach (char c in StatusText.Text.ToCharArray())
+                    foreach (char c in StatusText.Text)
                     {
                         if (c == ' ' || c == ' ')
                         {
@@ -5085,6 +4692,9 @@ namespace OpenTween
             {
                 StatusText.ForeColor = _clInputFont;
             }
+
+            this.StatusText.AccessibleDescription = string.Format(Properties.Resources.StatusText_AccessibleDescription, pLen);
+
             if (string.IsNullOrEmpty(StatusText.Text))
             {
                 this.inReplyTo = null;
@@ -5115,13 +4725,13 @@ namespace OpenTween
                 return statusText;
 
             bool disableFooter;
-            if (this._cfgCommon.PostShiftEnter)
+            if (SettingManager.Common.PostShiftEnter)
             {
                 disableFooter = MyCommon.IsKeyDown(Keys.Control);
             }
             else
             {
-                if (this.StatusText.Multiline && !this._cfgCommon.PostCtrlEnter)
+                if (this.StatusText.Multiline && !SettingManager.Common.PostCtrlEnter)
                     disableFooter = MyCommon.IsKeyDown(Keys.Control);
                 else
                     disableFooter = MyCommon.IsKeyDown(Keys.Shift);
@@ -5144,15 +4754,15 @@ namespace OpenTween
 
             if (!disableFooter)
             {
-                if (this._cfgLocal.UseRecommendStatus)
+                if (SettingManager.Local.UseRecommendStatus)
                 {
                     // 推奨ステータスを使用する
                     footer += this.recommendedStatusFooter;
                 }
-                else if (!string.IsNullOrEmpty(this._cfgLocal.StatusText))
+                else if (!string.IsNullOrEmpty(SettingManager.Local.StatusText))
                 {
                     // テキストボックスに入力されている文字列を使用する
-                    footer += " " + this._cfgLocal.StatusText.Trim();
+                    footer += " " + SettingManager.Local.StatusText.Trim();
                 }
             }
 
@@ -5182,9 +4792,11 @@ namespace OpenTween
             //文字数カウント
             var remainCount = this.tw.GetTextLengthRemain(statusText);
 
-            if (this.ImageSelector.Visible && !string.IsNullOrEmpty(this.ImageSelector.ServiceName))
+            var uploadService = this.ImageSelector.SelectedService;
+            if (this.ImageSelector.Visible && uploadService != null)
             {
-                remainCount -= this.tw.Configuration.CharactersReservedPerMedia;
+                // TODO: ImageSelector で選択中の画像の枚数が mediaCount 引数に渡るようにする
+                remainCount -= uploadService.GetReservedTextLength(1);
             }
 
             return remainCount;
@@ -5196,7 +4808,7 @@ namespace OpenTween
                 return;
 
             var listCache = this._listItemCache;
-            if (listCache != null && listCache.IsSupersetOf(e.StartIndex, e.EndIndex))
+            if (listCache?.TargetList == sender && listCache.IsSupersetOf(e.StartIndex, e.EndIndex))
             {
                 // If the newly requested cache is a subset of the old cache,
                 // no need to rebuild everything, so do nothing.
@@ -5210,11 +4822,9 @@ namespace OpenTween
         private void MyList_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
         {
             var listCache = this._listItemCache;
-            if (listCache != null && listCache.TargetList == sender)
+            if (listCache?.TargetList == sender)
             {
-                ListViewItem item;
-                PostClass cacheItemPost;
-                if (listCache.TryGetValue(e.ItemIndex, out item, out cacheItemPost))
+                if (listCache.TryGetValue(e.ItemIndex, out var item, out var cacheItemPost))
                 {
                     e.Item = item;
                     return;
@@ -5280,14 +4890,14 @@ namespace OpenTween
             //if (Post.IsMark) mk.Append("♪");
             //if (Post.IsProtect) mk.Append("Ю");
             //if (Post.InReplyToStatusId != null) mk.Append("⇒");
-            if (Post.FavoritedCount > 0) mk.Append("+" + Post.FavoritedCount.ToString());
+            if (Post.FavoritedCount > 0) mk.Append("+" + Post.FavoritedCount);
             ImageListViewItem itm;
             if (Post.RetweetedId == null)
             {
                 string[] sitem= {"",
                                  Post.Nickname,
-                                 Post.IsDeleted ? "(DELETED)" : Post.TextSingleLine,
-                                 Post.CreatedAt.ToString(this._cfgCommon.DateTimeFormat),
+                                 Post.IsDeleted ? "(DELETED)" : Post.AccessibleText,
+                                 Post.CreatedAt.ToString(SettingManager.Common.DateTimeFormat),
                                  Post.ScreenName,
                                  "",
                                  mk.ToString(),
@@ -5298,8 +4908,8 @@ namespace OpenTween
             {
                 string[] sitem = {"",
                                   Post.Nickname,
-                                  Post.IsDeleted ? "(DELETED)" : Post.TextSingleLine,
-                                  Post.CreatedAt.ToString(this._cfgCommon.DateTimeFormat),
+                                  Post.IsDeleted ? "(DELETED)" : Post.AccessibleText,
+                                  Post.CreatedAt.ToString(SettingManager.Common.DateTimeFormat),
                                   Post.ScreenName + Environment.NewLine + "(RT:" + Post.RetweetedBy + ")",
                                   "",
                                   mk.ToString(),
@@ -5307,10 +4917,11 @@ namespace OpenTween
                 itm = new ImageListViewItem(sitem, this.IconCache, Post.ImageUrl);
             }
             itm.StateIndex = Post.StateIndex;
+            itm.Tag = Post;
 
             bool read = Post.IsRead;
             //未読管理していなかったら既読として扱う
-            if (!_statuses.Tabs[Tab.Text].UnreadManage || !this._cfgCommon.UnreadManage) read = true;
+            if (!_statuses.Tabs[Tab.Text].UnreadManage || !SettingManager.Common.UnreadManage) read = true;
             ChangeItemStyleRead(read, itm, Post, null);
             if (Tab.Equals(_curTab)) ColorizeList(itm, Index);
             return itm;
@@ -5338,7 +4949,7 @@ namespace OpenTween
                         listview.VirtualListSize = tab.AllCount;
                     }
 
-                    if (this._cfgCommon.TabIconDisp)
+                    if (SettingManager.Common.TabIconDisp)
                     {
                         if (tab.UnreadCount > 0)
                             tabPage.ImageIndex = 0;
@@ -5347,7 +4958,7 @@ namespace OpenTween
                     }
                 }
 
-                if (!this._cfgCommon.TabIconDisp)
+                if (!SettingManager.Common.TabIconDisp)
                     this.ListTab.Refresh();
 
                 SetMainWindowTitle();
@@ -5409,6 +5020,8 @@ namespace OpenTween
             if (e.ColumnIndex > 0)
             {
                 //アイコン以外の列
+                var post = (PostClass)e.Item.Tag;
+
                 RectangleF rct = e.Bounds;
                 rct.Width = e.Header.Width;
                 int fontHeight = e.Item.Font.Height;
@@ -5418,8 +5031,7 @@ namespace OpenTween
                     rct.Height -= fontHeight;
                 }
 
-                int heightDiff;
-                int drawLineCount = Math.Max(1, Math.DivRem((int)rct.Height, fontHeight, out heightDiff));
+                int drawLineCount = Math.Max(1, Math.DivRem((int)rct.Height, fontHeight, out var heightDiff));
 
                 //if (heightDiff > fontHeight * 0.7)
                 //{
@@ -5465,7 +5077,50 @@ namespace OpenTween
                         using (Font fnt = new Font(e.Item.Font, FontStyle.Bold))
                         {
                             TextRenderer.DrawText(e.Graphics,
-                                                    e.Item.SubItems[2].Text,
+                                                    post.IsDeleted ? "(DELETED)" : post.TextSingleLine,
+                                                    e.Item.Font,
+                                                    Rectangle.Round(rct),
+                                                    color,
+                                                    TextFormatFlags.WordBreak |
+                                                    TextFormatFlags.EndEllipsis |
+                                                    TextFormatFlags.GlyphOverhangPadding |
+                                                    TextFormatFlags.NoPrefix);
+                            TextRenderer.DrawText(e.Graphics,
+                                                    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 + "]",
+                                                    fnt,
+                                                    rctB,
+                                                    color,
+                                                    TextFormatFlags.SingleLine |
+                                                    TextFormatFlags.EndEllipsis |
+                                                    TextFormatFlags.GlyphOverhangPadding |
+                                                    TextFormatFlags.NoPrefix);
+                        }
+                    }
+                    else
+                    {
+                        string text;
+                        if (e.ColumnIndex != 2)
+                            text = e.SubItem.Text;
+                        else
+                            text = post.IsDeleted ? "(DELETED)" : post.TextSingleLine;
+
+                        if (drawLineCount == 1)
+                        {
+                            TextRenderer.DrawText(e.Graphics,
+                                                    text,
+                                                    e.Item.Font,
+                                                    Rectangle.Round(rct),
+                                                    color,
+                                                    TextFormatFlags.SingleLine |
+                                                    TextFormatFlags.EndEllipsis |
+                                                    TextFormatFlags.GlyphOverhangPadding |
+                                                    TextFormatFlags.NoPrefix |
+                                                    TextFormatFlags.VerticalCenter);
+                        }
+                        else
+                        {
+                            TextRenderer.DrawText(e.Graphics,
+                                                    text,
                                                     e.Item.Font,
                                                     Rectangle.Round(rct),
                                                     color,
@@ -5473,42 +5128,8 @@ namespace OpenTween
                                                     TextFormatFlags.EndEllipsis |
                                                     TextFormatFlags.GlyphOverhangPadding |
                                                     TextFormatFlags.NoPrefix);
-                            TextRenderer.DrawText(e.Graphics,
-                                                    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 + "]",
-                                                    fnt,
-                                                    rctB,
-                                                    color,
-                                                    TextFormatFlags.SingleLine |
-                                                    TextFormatFlags.EndEllipsis |
-                                                    TextFormatFlags.GlyphOverhangPadding |
-                                                    TextFormatFlags.NoPrefix);
                         }
                     }
-                    else if (drawLineCount == 1)
-                    {
-                        TextRenderer.DrawText(e.Graphics,
-                                                e.SubItem.Text,
-                                                e.Item.Font,
-                                                Rectangle.Round(rct),
-                                                color,
-                                                TextFormatFlags.SingleLine |
-                                                TextFormatFlags.EndEllipsis |
-                                                TextFormatFlags.GlyphOverhangPadding |
-                                                TextFormatFlags.NoPrefix |
-                                                TextFormatFlags.VerticalCenter);
-                    }
-                    else
-                    {
-                        TextRenderer.DrawText(e.Graphics,
-                                                e.SubItem.Text,
-                                                e.Item.Font,
-                                                Rectangle.Round(rct),
-                                                color,
-                                                TextFormatFlags.WordBreak |
-                                                TextFormatFlags.EndEllipsis |
-                                                TextFormatFlags.GlyphOverhangPadding |
-                                                TextFormatFlags.NoPrefix);
-                    }
                     //if (e.ColumnIndex == 6) this.DrawListViewItemStateIcon(e, rct);
                 }
             }
@@ -5624,7 +5245,7 @@ namespace OpenTween
         //    }
         //}
 
-        private void DoTabSearch(string searchWord, bool caseSensitive, bool useRegex, SEARCHTYPE searchType)
+        internal void DoTabSearch(string searchWord, bool caseSensitive, bool useRegex, SEARCHTYPE searchType)
         {
             var tab = this._statuses.Tabs[this._curTab.Text];
 
@@ -5734,10 +5355,10 @@ namespace OpenTween
         {
             if (this.SearchDialog.ShowDialog(this) != DialogResult.OK)
             {
-                this.TopMost = this._cfgCommon.AlwaysTop;
+                this.TopMost = SettingManager.Common.AlwaysTop;
                 return;
             }
-            this.TopMost = this._cfgCommon.AlwaysTop;
+            this.TopMost = SettingManager.Common.AlwaysTop;
 
             var searchOptions = this.SearchDialog.ResultOptions;
             if (searchOptions.Type == SearchWordDialog.SearchType.Timeline)
@@ -5810,7 +5431,7 @@ namespace OpenTween
 
         /// <summary>発言検索に使用するメソッドを生成します</summary>
         /// <exception cref="ArgumentException">
-        /// <paramref name="useRegex"/> が true かつ、<paramref name="query"> が不正な正規表現な場合
+        /// <paramref name="useRegex"/> が true かつ、<paramref name="query"/> が不正な正規表現な場合
         /// </exception>
         private Func<string, bool> CreateSearchComparer(string query, bool useRegex, bool caseSensitive)
         {
@@ -5835,80 +5456,95 @@ namespace OpenTween
             {
                 about.ShowDialog(this);
             }
-            this.TopMost = this._cfgCommon.AlwaysTop;
+            this.TopMost = SettingManager.Common.AlwaysTop;
         }
 
         private void JumpUnreadMenuItem_Click(object sender, EventArgs e)
         {
             int bgnIdx = ListTab.TabPages.IndexOf(_curTab);
-            int idx = -1;
-            DetailsListView lst = null;
 
             if (ImageSelector.Enabled)
                 return;
 
+            TabModel foundTab = null;
+            int foundIndex = 0;
+
+            DetailsListView lst = null;
+
             //現在タブから最終タブまで探索
             for (int i = bgnIdx; i < ListTab.TabPages.Count; i++)
             {
-                //未読Index取得
-                idx = _statuses.Tabs[ListTab.TabPages[i].Text].NextUnreadIndex;
-                if (idx > -1)
+                var tabPage = this.ListTab.TabPages[i];
+                var tab = this._statuses.Tabs[tabPage.Text];
+                var unreadIndex = tab.NextUnreadIndex;
+
+                if (unreadIndex != -1)
                 {
                     ListTab.SelectedIndex = i;
-                    lst = (DetailsListView)ListTab.TabPages[i].Tag;
-                    //_curTab = ListTab.TabPages[i];
+                    foundTab = tab;
+                    foundIndex = unreadIndex;
+                    lst = (DetailsListView)tabPage.Tag;
                     break;
                 }
             }
 
             //未読みつからず&現在タブが先頭ではなかったら、先頭タブから現在タブの手前まで探索
-            if (idx == -1 && bgnIdx > 0)
+            if (foundTab == null && bgnIdx > 0)
             {
                 for (int i = 0; i < bgnIdx; i++)
                 {
-                    idx = _statuses.Tabs[ListTab.TabPages[i].Text].NextUnreadIndex;
-                    if (idx > -1)
+                    var tabPage = this.ListTab.TabPages[i];
+                    var tab = this._statuses.Tabs[tabPage.Text];
+                    var unreadIndex = tab.NextUnreadIndex;
+
+                    if (unreadIndex != -1)
                     {
                         ListTab.SelectedIndex = i;
-                        lst = (DetailsListView)ListTab.TabPages[i].Tag;
-                        //_curTab = ListTab.TabPages[i];
+                        foundTab = tab;
+                        foundIndex = unreadIndex;
+                        lst = (DetailsListView)tabPage.Tag;
                         break;
                     }
                 }
             }
 
-            //全部調べたが未読見つからず→先頭タブの最新発言へ
-            if (idx == -1)
+            if (foundTab == null)
             {
+                //全部調べたが未読見つからず→先頭タブの最新発言へ
                 ListTab.SelectedIndex = 0;
-                lst = (DetailsListView)ListTab.TabPages[0].Tag;
-                //_curTab = ListTab.TabPages[0];
+                var tabPage = this.ListTab.TabPages[0];
+                var tab = this._statuses.Tabs[tabPage.Text];
+
+                if (tab.AllCount == 0)
+                    return;
+
                 if (_statuses.SortOrder == SortOrder.Ascending)
-                    idx = lst.VirtualListSize - 1;
+                    foundIndex = tab.AllCount - 1;
                 else
-                    idx = 0;
+                    foundIndex = 0;
+
+                lst = (DetailsListView)tabPage.Tag;
             }
 
-            if (lst.VirtualListSize > 0 && idx > -1 && lst.VirtualListSize > idx)
+            SelectListItem(lst, foundIndex);
+
+            if (_statuses.SortMode == ComparerMode.Id)
             {
-                SelectListItem(lst, idx);
-                if (_statuses.SortMode == ComparerMode.Id)
+                if (_statuses.SortOrder == SortOrder.Ascending && lst.Items[foundIndex].Position.Y > lst.ClientSize.Height - _iconSz - 10 ||
+                    _statuses.SortOrder == SortOrder.Descending && lst.Items[foundIndex].Position.Y < _iconSz + 10)
                 {
-                    if (_statuses.SortOrder == SortOrder.Ascending && lst.Items[idx].Position.Y > lst.ClientSize.Height - _iconSz - 10 ||
-                       _statuses.SortOrder == SortOrder.Descending && lst.Items[idx].Position.Y < _iconSz + 10)
-                    {
-                        MoveTop();
-                    }
-                    else
-                    {
-                        lst.EnsureVisible(idx);
-                    }
+                    MoveTop();
                 }
                 else
                 {
-                    lst.EnsureVisible(idx);
+                    lst.EnsureVisible(foundIndex);
                 }
             }
+            else
+            {
+                lst.EnsureVisible(foundIndex);
+            }
+
             lst.Focus();
         }
 
@@ -6040,56 +5676,36 @@ namespace OpenTween
             _colorize = false;
             await this.DispSelectedPost();
             //件数関連の場合、タイトル即時書き換え
-            if (this._cfgCommon.DispLatestPost != MyCommon.DispTitleEnum.None &&
-               this._cfgCommon.DispLatestPost != MyCommon.DispTitleEnum.Post &&
-               this._cfgCommon.DispLatestPost != MyCommon.DispTitleEnum.Ver &&
-               this._cfgCommon.DispLatestPost != MyCommon.DispTitleEnum.OwnStatus)
+            if (SettingManager.Common.DispLatestPost != MyCommon.DispTitleEnum.None &&
+               SettingManager.Common.DispLatestPost != MyCommon.DispTitleEnum.Post &&
+               SettingManager.Common.DispLatestPost != MyCommon.DispTitleEnum.Ver &&
+               SettingManager.Common.DispLatestPost != MyCommon.DispTitleEnum.OwnStatus)
             {
                 SetMainWindowTitle();
             }
-            if (!StatusLabelUrl.Text.StartsWith("http")) SetStatusLabelUrl();
+            if (!StatusLabelUrl.Text.StartsWith("http", StringComparison.OrdinalIgnoreCase))
+                SetStatusLabelUrl();
             foreach (TabPage tb in ListTab.TabPages)
             {
                 if (_statuses.Tabs[tb.Text].UnreadCount == 0)
                 {
-                    if (this._cfgCommon.TabIconDisp)
+                    if (SettingManager.Common.TabIconDisp)
                     {
                         if (tb.ImageIndex == 0) tb.ImageIndex = -1;
                     }
                 }
             }
-            if (!this._cfgCommon.TabIconDisp) ListTab.Refresh();
+            if (!SettingManager.Common.TabIconDisp) ListTab.Refresh();
         }
 
         public string createDetailHtml(string orgdata)
         {
-            if (this._cfgLocal.UseTwemoji)
+            if (SettingManager.Local.UseTwemoji)
                 orgdata = EmojiFormatter.ReplaceEmojiToImg(orgdata);
 
             return detailHtmlFormatHeader + orgdata + detailHtmlFormatFooter;
         }
 
-        private async void DisplayItemImage_Downloaded(object sender, EventArgs e)
-        {
-            if (sender.Equals(displayItem))
-            {
-                this.ClearUserPicture();
-
-                var img = displayItem.Image;
-                try
-                {
-                    if (img != null)
-                        img = await img.CloneAsync();
-
-                    UserPicture.Image = img;
-                }
-                catch (Exception)
-                {
-                    UserPicture.ShowErrorImage();
-                }
-            }
-        }
-
         private Task DispSelectedPost()
         {
             return this.DispSelectedPost(false);
@@ -6113,145 +5729,20 @@ namespace OpenTween
             if (!forceupdate && this._curPost.Equals(oldDisplayPost))
                 return;
 
-            if (displayItem != null)
-            {
-                displayItem.ImageDownloaded -= this.DisplayItemImage_Downloaded;
-                displayItem = null;
-            }
-            displayItem = (ImageListViewItem)_curList.Items[_curList.SelectedIndices[0]];
-            displayItem.ImageDownloaded += this.DisplayItemImage_Downloaded;
-
-            using (ControlTransaction.Update(this.TableLayoutPanel1))
-            {
-                SourceLinkLabel.Text = this._curPost.Source;
-                SourceLinkLabel.Tag = this._curPost.SourceUri;
-                SourceLinkLabel.TabStop = false; // Text を更新すると勝手に true にされる
-
-                string nameText;
-                if (_curPost.IsDm)
-                {
-                    if (_curPost.IsOwl)
-                        nameText = "DM FROM <- ";
-                    else
-                        nameText = "DM TO -> ";
-                }
-                else
-                {
-                    nameText = "";
-                }
-                nameText += _curPost.ScreenName + "/" + _curPost.Nickname;
-                if (_curPost.RetweetedId != null)
-                    nameText += " (RT:" + _curPost.RetweetedBy + ")";
-
-                NameLabel.Text = nameText;
-                NameLabel.Tag = _curPost.ScreenName;
-
-                var nameForeColor = SystemColors.ControlText;
-                if (_curPost.IsOwl && (this._cfgCommon.OneWayLove || _curPost.IsDm))
-                    nameForeColor = this._clOWL;
-                if (_curPost.RetweetedId != null)
-                    nameForeColor = this._clRetweet;
-                if (_curPost.IsFav)
-                    nameForeColor = this._clFav;
-                NameLabel.ForeColor = nameForeColor;
-
-                this.ClearUserPicture();
-
-                if (!string.IsNullOrEmpty(_curPost.ImageUrl))
-                {
-                    var image = IconCache.TryGetFromCache(_curPost.ImageUrl);
-                    try
-                    {
-                        UserPicture.Image = image?.Clone();
-                    }
-                    catch (Exception)
-                    {
-                        UserPicture.ShowErrorImage();
-                    }
-                }
-
-                DateTimeLabel.Text = _curPost.CreatedAt.ToString();
-            }
-
-            if (DumpPostClassToolStripMenuItem.Checked)
+            var loadTasks = new List<Task>
             {
-                StringBuilder sb = new StringBuilder(512);
-
-                sb.Append("-----Start PostClass Dump<br>");
-                sb.AppendFormat("TextFromApi           : {0}<br>", _curPost.TextFromApi);
-                sb.AppendFormat("(PlainText)    : <xmp>{0}</xmp><br>", _curPost.TextFromApi);
-                sb.AppendFormat("StatusId             : {0}<br>", _curPost.StatusId.ToString());
-                //sb.AppendFormat("ImageIndex     : {0}<br>", _curPost.ImageIndex.ToString());
-                sb.AppendFormat("ImageUrl       : {0}<br>", _curPost.ImageUrl);
-                sb.AppendFormat("InReplyToStatusId    : {0}<br>", _curPost.InReplyToStatusId.ToString());
-                sb.AppendFormat("InReplyToUser  : {0}<br>", _curPost.InReplyToUser);
-                sb.AppendFormat("IsDM           : {0}<br>", _curPost.IsDm.ToString());
-                sb.AppendFormat("IsFav          : {0}<br>", _curPost.IsFav.ToString());
-                sb.AppendFormat("IsMark         : {0}<br>", _curPost.IsMark.ToString());
-                sb.AppendFormat("IsMe           : {0}<br>", _curPost.IsMe.ToString());
-                sb.AppendFormat("IsOwl          : {0}<br>", _curPost.IsOwl.ToString());
-                sb.AppendFormat("IsProtect      : {0}<br>", _curPost.IsProtect.ToString());
-                sb.AppendFormat("IsRead         : {0}<br>", _curPost.IsRead.ToString());
-                sb.AppendFormat("IsReply        : {0}<br>", _curPost.IsReply.ToString());
-
-                foreach (string nm in _curPost.ReplyToList)
-                {
-                    sb.AppendFormat("ReplyToList    : {0}<br>", nm);
-                }
-
-                sb.AppendFormat("ScreenName           : {0}<br>", _curPost.ScreenName);
-                sb.AppendFormat("NickName       : {0}<br>", _curPost.Nickname);
-                sb.AppendFormat("Text   : {0}<br>", _curPost.Text);
-                sb.AppendFormat("(PlainText)    : <xmp>{0}</xmp><br>", _curPost.Text);
-                sb.AppendFormat("CreatedAt          : {0}<br>", _curPost.CreatedAt.ToString());
-                sb.AppendFormat("Source         : {0}<br>", _curPost.Source);
-                sb.AppendFormat("UserId            : {0}<br>", _curPost.UserId);
-                sb.AppendFormat("FilterHit      : {0}<br>", _curPost.FilterHit);
-                sb.AppendFormat("RetweetedBy    : {0}<br>", _curPost.RetweetedBy);
-                sb.AppendFormat("RetweetedId    : {0}<br>", _curPost.RetweetedId);
-
-                sb.AppendFormat("Media.Count    : {0}<br>", _curPost.Media.Count);
-                if (_curPost.Media.Count > 0)
-                {
-                    for (int i = 0; i < _curPost.Media.Count; i++)
-                    {
-                        var info = _curPost.Media[i];
-                        sb.AppendFormat("Media[{0}].Url         : {1}<br>", i, info.Url);
-                        sb.AppendFormat("Media[{0}].VideoUrl    : {1}<br>", i, info.VideoUrl ?? "---");
-                    }
-                }
-                sb.Append("-----End PostClass Dump<br>");
-
-                PostBrowser.DocumentText = detailHtmlFormatHeader + sb.ToString() + detailHtmlFormatFooter;
-                return;
-            }
+                this.tweetDetailsView.ShowPostDetails(this._curPost),
+            };
 
-            var loadTasks = new List<Task>();
+            this.SplitContainer3.Panel2Collapsed = true;
 
-            // 同じIDのツイートであれば WebBrowser とサムネイルの更新を行わない
-            // (同一ツイートの RT は文面が同じであるため同様に更新しない)
-            if (_curPost.StatusId != oldDisplayPost.StatusId)
+            if (SettingManager.Common.PreviewEnable)
             {
-                using (ControlTransaction.Update(this.PostBrowser))
-                {
-                    this.PostBrowser.DocumentText =
-                        this.createDetailHtml(_curPost.IsDeleted ? "(DELETED)" : _curPost.Text);
-
-                    this.PostBrowser.Document.Window.ScrollTo(0, 0);
-                }
-
-                this.SplitContainer3.Panel2Collapsed = true;
-
-                if (this._cfgCommon.PreviewEnable)
-                {
-                    var oldTokenSource = Interlocked.Exchange(ref this.thumbnailTokenSource, new CancellationTokenSource());
-                    oldTokenSource?.Cancel();
-
-                    var token = this.thumbnailTokenSource.Token;
-                    loadTasks.Add(this.tweetThumbnail1.ShowThumbnailAsync(_curPost, token));
-                }
+                var oldTokenSource = Interlocked.Exchange(ref this.thumbnailTokenSource, new CancellationTokenSource());
+                oldTokenSource?.Cancel();
 
-                loadTasks.Add(this.AppendQuoteTweetAsync(this._curPost));
+                var token = this.thumbnailTokenSource.Token;
+                loadTasks.Add(this.tweetThumbnail1.ShowThumbnailAsync(_curPost, token));
             }
 
             try
@@ -6261,99 +5752,6 @@ namespace OpenTween
             catch (OperationCanceledException) { }
         }
 
-        /// <summary>
-        /// 発言詳細欄のツイートURLを展開する
-        /// </summary>
-        private async Task AppendQuoteTweetAsync(PostClass post)
-        {
-            var quoteStatusIds = post.QuoteStatusIds;
-            if (quoteStatusIds.Length == 0 && post.InReplyToStatusId == null)
-                return;
-
-            // 「読み込み中」テキストを表示
-            var loadingQuoteHtml = quoteStatusIds.Select(x => FormatQuoteTweetHtml(x, Properties.Resources.LoadingText, isReply: false));
-
-            var loadingReplyHtml = string.Empty;
-            if (post.InReplyToStatusId != null)
-                loadingReplyHtml = FormatQuoteTweetHtml(post.InReplyToStatusId.Value, Properties.Resources.LoadingText, isReply: true);
-
-            var body = post.Text + string.Concat(loadingQuoteHtml) + loadingReplyHtml;
-
-            using (ControlTransaction.Update(this.PostBrowser))
-                this.PostBrowser.DocumentText = this.createDetailHtml(body);
-
-            // 引用ツイートを読み込み
-            var loadTweetTasks = quoteStatusIds.Select(x => this.CreateQuoteTweetHtml(x, isReply: false)).ToList();
-
-            if (post.InReplyToStatusId != null)
-                loadTweetTasks.Add(this.CreateQuoteTweetHtml(post.InReplyToStatusId.Value, isReply: true));
-
-            var quoteHtmls = await Task.WhenAll(loadTweetTasks);
-
-            // 非同期処理中に表示中のツイートが変わっていたらキャンセルされたものと扱う
-            if (this._curPost != post || this._curPost.IsDeleted)
-                return;
-
-            body = post.Text + string.Concat(quoteHtmls);
-
-            using (ControlTransaction.Update(this.PostBrowser))
-                this.PostBrowser.DocumentText = this.createDetailHtml(body);
-        }
-
-        private async Task<string> CreateQuoteTweetHtml(long statusId, bool isReply)
-        {
-            PostClass post = this._statuses[statusId];
-            if (post == null)
-            {
-                try
-                {
-                    post = await this.tw.GetStatusApi(false, statusId)
-                        .ConfigureAwait(false);
-                }
-                catch (WebApiException ex)
-                {
-                    return FormatQuoteTweetHtml(statusId, WebUtility.HtmlEncode($"Err:{ex.Message}(GetStatus)"), isReply);
-                }
-
-                post.IsRead = true;
-                if (!this._statuses.AddQuoteTweet(post))
-                    return FormatQuoteTweetHtml(statusId, "This Tweet is unavailable.", isReply);
-            }
-
-            return FormatQuoteTweetHtml(post, isReply);
-        }
-
-        internal static string FormatQuoteTweetHtml(PostClass post, bool isReply)
-        {
-            var innerHtml = "<p>" + StripLinkTagHtml(post.Text) + "</p>" +
-                " &mdash; " + WebUtility.HtmlEncode(post.Nickname) +
-                " (@" + WebUtility.HtmlEncode(post.ScreenName) + ") " +
-                WebUtility.HtmlEncode(post.CreatedAt.ToString());
-
-            return FormatQuoteTweetHtml(post.StatusId, innerHtml, isReply);
-        }
-
-        internal static string FormatQuoteTweetHtml(long statusId, string innerHtml, bool isReply)
-        {
-            var blockClassName = "quote-tweet";
-
-            if (isReply)
-                blockClassName += " reply";
-
-            return "<a class=\"quote-tweet-link\" href=\"//opentween/status/" + statusId + "\">" +
-                $"<blockquote class=\"{blockClassName}\">{innerHtml}</blockquote>" +
-                "</a>";
-        }
-
-        /// <summary>
-        /// 指定されたHTMLからリンクを除去します
-        /// </summary>
-        internal static string StripLinkTagHtml(string html)
-        {
-            // a 要素はネストされていない前提の正規表現パターン
-            return Regex.Replace(html, @"<a[^>]*>(.*?)</a>", "$1");
-        }
-
         private async void MatomeMenuItem_Click(object sender, EventArgs e)
         {
             await this.OpenApplicationWebsite();
@@ -6384,8 +5782,7 @@ namespace OpenTween
                 if (e.Control || e.Shift || e.Alt)
                     this._anchorFlag = false;
 
-                Task asyncTask;
-                if (CommonKeyDown(e.KeyData, FocusedControl.ListTab, out asyncTask))
+                if (CommonKeyDown(e.KeyData, FocusedControl.ListTab, out var asyncTask))
                 {
                     e.Handled = true;
                     e.SuppressKeyPress = true;
@@ -6784,16 +6181,16 @@ namespace OpenTween
                     .Do(() => this.doShowUserStatus(_curPost.ScreenName, ShowInputDialog: false)),
 
                 ShortcutCommand.Create(Keys.Alt | Keys.Up)
-                    .Do(() => this.ScrollDownPostBrowser(forward: false)),
+                    .Do(() => this.tweetDetailsView.ScrollDownPostBrowser(forward: false)),
 
                 ShortcutCommand.Create(Keys.Alt | Keys.Down)
-                    .Do(() => this.ScrollDownPostBrowser(forward: true)),
+                    .Do(() => this.tweetDetailsView.ScrollDownPostBrowser(forward: true)),
 
                 ShortcutCommand.Create(Keys.Alt | Keys.PageUp)
-                    .Do(() => this.PageDownPostBrowser(forward: false)),
+                    .Do(() => this.tweetDetailsView.PageDownPostBrowser(forward: false)),
 
                 ShortcutCommand.Create(Keys.Alt | Keys.PageDown)
-                    .Do(() => this.PageDownPostBrowser(forward: true)),
+                    .Do(() => this.tweetDetailsView.PageDownPostBrowser(forward: true)),
 
                 // 別タブの同じ書き込みへ(ALT+←/→)
                 ShortcutCommand.Create(Keys.Alt | Keys.Right)
@@ -6943,7 +6340,7 @@ namespace OpenTween
 
                 ShortcutCommand.Create(Keys.Alt | Keys.Shift | Keys.T)
                     .OnlyWhen(() => this.ExistCurrentPost)
-                    .Do(() => this.doTranslation(_curPost.TextFromApi)),
+                    .Do(() => this.tweetDetailsView.DoTranslation()),
 
                 ShortcutCommand.Create(Keys.Alt | Keys.Shift | Keys.R)
                     .Do(() => this.doReTweetUnofficial()),
@@ -6964,7 +6361,7 @@ namespace OpenTween
             };
         }
 
-        private bool CommonKeyDown(Keys keyData, FocusedControl focusedOn, out Task asyncTask)
+        internal bool CommonKeyDown(Keys keyData, FocusedControl focusedOn, out Task asyncTask)
         {
             // Task を返す非同期処理があれば asyncTask に代入する
             asyncTask = null;
@@ -6982,36 +6379,6 @@ namespace OpenTween
             return false;
         }
 
-        private void ScrollDownPostBrowser(bool forward)
-        {
-            var doc = PostBrowser.Document;
-            if (doc == null) return;
-
-            var tags = doc.GetElementsByTagName("html");
-            if (tags.Count > 0)
-            {
-                if (forward)
-                    tags[0].ScrollTop += this._fntDetail.Height;
-                else
-                    tags[0].ScrollTop -= this._fntDetail.Height;
-            }
-        }
-
-        private void PageDownPostBrowser(bool forward)
-        {
-            var doc = PostBrowser.Document;
-            if (doc == null) return;
-
-            var tags = doc.GetElementsByTagName("html");
-            if (tags.Count > 0)
-            {
-                if (forward)
-                    tags[0].ScrollTop += PostBrowser.ClientRectangle.Height - this._fntDetail.Height;
-                else
-                    tags[0].ScrollTop -= PostBrowser.ClientRectangle.Height - this._fntDetail.Height;
-            }
-        }
-
         private void GoNextTab(bool forward)
         {
             int idx = ListTab.SelectedIndex;
@@ -7038,11 +6405,6 @@ namespace OpenTween
             foreach (int idx in _curList.SelectedIndices)
             {
                 PostClass post = _statuses.Tabs[_curTab.Text][idx];
-                if (post.IsProtect)
-                {
-                    IsProtected = true;
-                    continue;
-                }
                 if (post.IsDeleted) continue;
                 if (!isDm)
                 {
@@ -7076,28 +6438,30 @@ namespace OpenTween
 
         private void CopyIdUri()
         {
-            string clstr = "";
-            StringBuilder sb = new StringBuilder();
-            if (this._curTab == null) return;
-            if (this._statuses.GetTabByName(this._curTab.Text) == null) return;
-            if (this._statuses.GetTabByName(this._curTab.Text).TabType == MyCommon.TabUsageType.DirectMessage) return;
+            if (this._curTab == null)
+                return;
+
+            var tab = this._statuses.GetTabByName(this._curTab.Text);
+            if (tab == null || tab is DirectMessagesTabModel)
+                return;
+
+            var copyUrls = new List<string>();
             foreach (int idx in _curList.SelectedIndices)
             {
-                var post = _statuses.Tabs[_curTab.Text][idx];
-                sb.Append(MyCommon.GetStatusUrl(post));
-                sb.Append(Environment.NewLine);
+                var post = tab[idx];
+                copyUrls.Add(MyCommon.GetStatusUrl(post));
             }
-            if (sb.Length > 0)
+
+            if (copyUrls.Count == 0)
+                return;
+
+            try
             {
-                clstr = sb.ToString();
-                try
-                {
-                    Clipboard.SetDataObject(clstr, false, 5, 100);
-                }
-                catch (Exception ex)
-                {
-                    MessageBox.Show(ex.Message);
-                }
+                Clipboard.SetDataObject(string.Join(Environment.NewLine, copyUrls), false, 5, 100);
+            }
+            catch (ExternalException ex)
+            {
+                MessageBox.Show(ex.Message);
             }
         }
 
@@ -7150,16 +6514,19 @@ namespace OpenTween
 
         private void GoSamePostToAnotherTab(bool left)
         {
-            if (_curList.VirtualListSize == 0) return;
-            int fIdx = 0;
-            int toIdx = 0;
-            int stp = 1;
-            long targetId = 0;
+            if (this._curList.SelectedIndices.Count == 0)
+                return;
+
+            var tab = this._statuses.Tabs[this._curTab.Text];
+
+            // Directタブは対象外(見つかるはずがない)
+            if (tab.TabType == MyCommon.TabUsageType.DirectMessage)
+                return;
 
-            if (_statuses.Tabs[_curTab.Text].TabType == MyCommon.TabUsageType.DirectMessage) return; // Directタブは対象外(見つかるはずがない)
-            if (_curList.SelectedIndices.Count == 0) return; //未選択も処理しない
+            var selectedIndex = this._curList.SelectedIndices[0];
+            var selectedStatusId = tab.GetStatusIdAt(selectedIndex);
 
-            targetId = GetCurTabPost(_curList.SelectedIndices[0]).StatusId;
+            int fIdx, toIdx, stp;
 
             if (left)
             {
@@ -7190,42 +6557,45 @@ namespace OpenTween
                 stp = 1;
             }
 
-            bool found = false;
             for (int tabidx = fIdx; tabidx != toIdx; tabidx += stp)
             {
-                if (_statuses.Tabs[ListTab.TabPages[tabidx].Text].TabType == MyCommon.TabUsageType.DirectMessage) continue; // Directタブは対象外
-                for (int idx = 0; idx < ((DetailsListView)ListTab.TabPages[tabidx].Tag).VirtualListSize; idx++)
+                var targetTab = this._statuses.Tabs[this.ListTab.TabPages[tabidx].Text];
+
+                // Directタブは対象外
+                if (targetTab.TabType == MyCommon.TabUsageType.DirectMessage)
+                    continue;
+
+                var foundIndex = targetTab.IndexOf(selectedStatusId);
+                if (foundIndex != -1)
                 {
-                    if (_statuses.Tabs[ListTab.TabPages[tabidx].Text][idx].StatusId == targetId)
-                    {
-                        ListTab.SelectedIndex = tabidx;
-                        SelectListItem(_curList, idx);
-                        _curList.EnsureVisible(idx);
-                        found = true;
-                        break;
-                    }
+                    ListTab.SelectedIndex = tabidx;
+                    SelectListItem(_curList, foundIndex);
+                    _curList.EnsureVisible(foundIndex);
+                    return;
                 }
-                if (found) break;
             }
         }
 
         private void GoPost(bool forward)
         {
-            if (_curList.SelectedIndices.Count == 0 || _curPost == null) return;
-            int fIdx = 0;
-            int toIdx = 0;
-            int stp = 1;
+            if (_curList.SelectedIndices.Count == 0 || _curPost == null)
+                return;
+
+            var tab = this._statuses.Tabs[this._curTab.Text];
+            var selectedIndex = this._curList.SelectedIndices[0];
+
+            int fIdx, toIdx, stp;
 
             if (forward)
             {
-                fIdx = _curList.SelectedIndices[0] + 1;
-                if (fIdx > _curList.VirtualListSize - 1) return;
-                toIdx = _curList.VirtualListSize;
+                fIdx = selectedIndex + 1;
+                if (fIdx > tab.AllCount - 1) return;
+                toIdx = tab.AllCount;
                 stp = 1;
             }
             else
             {
-                fIdx = _curList.SelectedIndices[0] - 1;
+                fIdx = selectedIndex - 1;
                 if (fIdx < 0) return;
                 toIdx = -1;
                 stp = -1;
@@ -7242,9 +6612,10 @@ namespace OpenTween
             }
             for (int idx = fIdx; idx != toIdx; idx += stp)
             {
-                if (_statuses.Tabs[_curTab.Text][idx].RetweetedId == null)
+                var post = tab[idx];
+                if (post.RetweetedId == null)
                 {
-                    if (_statuses.Tabs[_curTab.Text][idx].ScreenName == name)
+                    if (post.ScreenName == name)
                     {
                         SelectListItem(_curList, idx);
                         _curList.EnsureVisible(idx);
@@ -7253,7 +6624,7 @@ namespace OpenTween
                 }
                 else
                 {
-                    if (_statuses.Tabs[_curTab.Text][idx].RetweetedBy == name)
+                    if (post.RetweetedBy == name)
                     {
                         SelectListItem(_curList, idx);
                         _curList.EnsureVisible(idx);
@@ -7265,21 +6636,24 @@ namespace OpenTween
 
         private void GoRelPost(bool forward)
         {
-            if (_curList.SelectedIndices.Count == 0) return;
+            if (this._curList.SelectedIndices.Count == 0)
+                return;
+
+            var tab = this._statuses.Tabs[this._curTab.Text];
+            var selectedIndex = this._curList.SelectedIndices[0];
+
+            int fIdx, toIdx, stp;
 
-            int fIdx = 0;
-            int toIdx = 0;
-            int stp = 1;
             if (forward)
             {
-                fIdx = _curList.SelectedIndices[0] + 1;
-                if (fIdx > _curList.VirtualListSize - 1) return;
-                toIdx = _curList.VirtualListSize;
+                fIdx = selectedIndex + 1;
+                if (fIdx > tab.AllCount - 1) return;
+                toIdx = tab.AllCount;
                 stp = 1;
             }
             else
             {
-                fIdx = _curList.SelectedIndices[0] - 1;
+                fIdx = selectedIndex - 1;
                 if (fIdx < 0) return;
                 toIdx = -1;
                 stp = -1;
@@ -7298,7 +6672,7 @@ namespace OpenTween
 
             for (int idx = fIdx; idx != toIdx; idx += stp)
             {
-                PostClass post = _statuses.Tabs[_curTab.Text][idx];
+                var post = tab[idx];
                 if (post.ScreenName == _anchorPost.ScreenName ||
                     post.RetweetedBy == _anchorPost.ScreenName ||
                     post.ScreenName == _anchorPost.RetweetedBy ||
@@ -7481,7 +6855,7 @@ namespace OpenTween
                 catch (WebApiException ex)
                 {
                     this.StatusLabel.Text = $"Err:{ex.Message}(GetStatus)";
-                    await this.OpenUriInBrowserAsync("https://twitter.com/" + inReplyToUser + "/statuses/" + inReplyToId.ToString());
+                    await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(inReplyToUser, inReplyToId));
                     return;
                 }
 
@@ -7490,7 +6864,7 @@ namespace OpenTween
                 inReplyPost = inReplyToPosts.FirstOrDefault();
                 if (inReplyPost == null)
                 {
-                    await this.OpenUriInBrowserAsync("https://twitter.com/" + inReplyToUser + "/statuses/" + inReplyToId.ToString());
+                    await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(inReplyToUser, inReplyToId));
                     return;
                 }
             }
@@ -7623,17 +6997,17 @@ namespace OpenTween
                     try
                     {
                         this.selectPostChains.Pop();
-                        var tabPostPair = this.selectPostChains.Peek();
+                        var (tabPage, post) = this.selectPostChains.Peek();
 
-                        if (!this.ListTab.TabPages.Contains(tabPostPair.Item1)) continue;  //該当タブが存在しないので無視
+                        if (!this.ListTab.TabPages.Contains(tabPage)) continue;  //該当タブが存在しないので無視
 
-                        if (tabPostPair.Item2 != null)
+                        if (post != null)
                         {
-                            idx = this._statuses.Tabs[tabPostPair.Item1.Text].IndexOf(tabPostPair.Item2.StatusId);
+                            idx = this._statuses.Tabs[tabPage.Text].IndexOf(post.StatusId);
                             if (idx == -1) continue;  //該当ポストが存在しないので無視
                         }
 
-                        tp = tabPostPair.Item1;
+                        tp = tabPage;
 
                         this.selectPostChains.Pop();
                     }
@@ -7670,21 +7044,21 @@ namespace OpenTween
             int count = this.selectPostChains.Count;
             if (count > 0)
             {
-                var p = this.selectPostChains.Peek();
-                if (p.Item1 == this._curTab)
+                var (tabPage, post) = this.selectPostChains.Peek();
+                if (tabPage == this._curTab)
                 {
-                    if (p.Item2 == this._curPost) return;  //最新の履歴と同一
-                    if (p.Item2 == null) this.selectPostChains.Pop();  //置き換えるため削除
+                    if (post == this._curPost) return;  //最新の履歴と同一
+                    if (post == null) this.selectPostChains.Pop();  //置き換えるため削除
                 }
             }
             if (count >= 2500) TrimPostChain();
-            this.selectPostChains.Push(Tuple.Create(this._curTab, this._curPost));
+            this.selectPostChains.Push((this._curTab, this._curPost));
         }
 
         private void TrimPostChain()
         {
             if (this.selectPostChains.Count <= 2000) return;
-            var p = new Stack<Tuple<TabPage, PostClass>>(2000);
+            var p = new Stack<ValueTuple<TabPage, PostClass>>(2000);
             for (int i = 0; i < 2000; i++)
             {
                 p.Push(this.selectPostChains.Pop());
@@ -7744,8 +7118,8 @@ namespace OpenTween
 
         public Color InputBackColor
         {
-            get { return _clInputBackcolor; }
-            set { _clInputBackcolor = value; }
+            get => _clInputBackcolor;
+            set => _clInputBackcolor = value;
         }
 
         private void StatusText_Leave(object sender, EventArgs e)
@@ -7757,8 +7131,7 @@ namespace OpenTween
 
         private async void StatusText_KeyDown(object sender, KeyEventArgs e)
         {
-            Task asyncTask;
-            if (CommonKeyDown(e.KeyData, FocusedControl.StatusText, out asyncTask))
+            if (CommonKeyDown(e.KeyData, FocusedControl.StatusText, out var asyncTask))
             {
                 e.Handled = true;
                 e.SuppressKeyPress = true;
@@ -7789,11 +7162,11 @@ namespace OpenTween
 
         private void SaveConfigsAtId()
         {
-            if (_ignoreConfigSave || !this._cfgCommon.UseAtIdSupplement && AtIdSupl == null) return;
+            if (_ignoreConfigSave || !SettingManager.Common.UseAtIdSupplement && AtIdSupl == null) return;
 
             ModifySettingAtId = false;
-            SettingAtIdList cfgAtId = new SettingAtIdList(AtIdSupl.GetItemList());
-            cfgAtId.Save();
+            SettingManager.AtIdList.AtIdList = this.AtIdSupl.GetItemList();
+            SettingManager.SaveAtIdList();
         }
 
         private void SaveConfigsCommon()
@@ -7803,60 +7176,60 @@ namespace OpenTween
             ModifySettingCommon = false;
             lock (_syncObject)
             {
-                _cfgCommon.UserName = tw.Username;
-                _cfgCommon.UserId = tw.UserId;
-                _cfgCommon.Token = tw.AccessToken;
-                _cfgCommon.TokenSecret = tw.AccessTokenSecret;
+                SettingManager.Common.UserName = tw.Username;
+                SettingManager.Common.UserId = tw.UserId;
+                SettingManager.Common.Token = tw.AccessToken;
+                SettingManager.Common.TokenSecret = tw.AccessTokenSecret;
 
                 if (IdeographicSpaceToSpaceToolStripMenuItem != null &&
                    IdeographicSpaceToSpaceToolStripMenuItem.IsDisposed == false)
                 {
-                    _cfgCommon.WideSpaceConvert = this.IdeographicSpaceToSpaceToolStripMenuItem.Checked;
+                    SettingManager.Common.WideSpaceConvert = this.IdeographicSpaceToSpaceToolStripMenuItem.Checked;
                 }
 
-                _cfgCommon.SortOrder = (int)_statuses.SortOrder;
+                SettingManager.Common.SortOrder = (int)_statuses.SortOrder;
                 switch (_statuses.SortMode)
                 {
                     case ComparerMode.Nickname:  //ニックネーム
-                        _cfgCommon.SortColumn = 1;
+                        SettingManager.Common.SortColumn = 1;
                         break;
                     case ComparerMode.Data:  //本文
-                        _cfgCommon.SortColumn = 2;
+                        SettingManager.Common.SortColumn = 2;
                         break;
                     case ComparerMode.Id:  //時刻=発言Id
-                        _cfgCommon.SortColumn = 3;
+                        SettingManager.Common.SortColumn = 3;
                         break;
                     case ComparerMode.Name:  //名前
-                        _cfgCommon.SortColumn = 4;
+                        SettingManager.Common.SortColumn = 4;
                         break;
                     case ComparerMode.Source:  //Source
-                        _cfgCommon.SortColumn = 7;
+                        SettingManager.Common.SortColumn = 7;
                         break;
                 }
 
-                _cfgCommon.HashTags = HashMgr.HashHistories;
+                SettingManager.Common.HashTags = HashMgr.HashHistories;
                 if (HashMgr.IsPermanent)
                 {
-                    _cfgCommon.HashSelected = HashMgr.UseHash;
+                    SettingManager.Common.HashSelected = HashMgr.UseHash;
                 }
                 else
                 {
-                    _cfgCommon.HashSelected = "";
+                    SettingManager.Common.HashSelected = "";
                 }
-                _cfgCommon.HashIsHead = HashMgr.IsHead;
-                _cfgCommon.HashIsPermanent = HashMgr.IsPermanent;
-                _cfgCommon.HashIsNotAddToAtReply = HashMgr.IsNotAddToAtReply;
+                SettingManager.Common.HashIsHead = HashMgr.IsHead;
+                SettingManager.Common.HashIsPermanent = HashMgr.IsPermanent;
+                SettingManager.Common.HashIsNotAddToAtReply = HashMgr.IsNotAddToAtReply;
                 if (ToolStripFocusLockMenuItem != null &&
                         ToolStripFocusLockMenuItem.IsDisposed == false)
                 {
-                    _cfgCommon.FocusLockToStatusText = this.ToolStripFocusLockMenuItem.Checked;
+                    SettingManager.Common.FocusLockToStatusText = this.ToolStripFocusLockMenuItem.Checked;
                 }
-                _cfgCommon.TrackWord = tw.TrackWord;
-                _cfgCommon.AllAtReply = tw.AllAtReply;
-                _cfgCommon.UseImageService = ImageSelector.ServiceIndex;
-                _cfgCommon.UseImageServiceName = ImageSelector.ServiceName;
+                SettingManager.Common.TrackWord = tw.TrackWord;
+                SettingManager.Common.AllAtReply = tw.AllAtReply;
+                SettingManager.Common.UseImageService = ImageSelector.ServiceIndex;
+                SettingManager.Common.UseImageServiceName = ImageSelector.ServiceName;
 
-                _cfgCommon.Save();
+                SettingManager.SaveCommon();
             }
         }
 
@@ -7866,44 +7239,44 @@ namespace OpenTween
             lock (_syncObject)
             {
                 ModifySettingLocal = false;
-                _cfgLocal.ScaleDimension = this.CurrentAutoScaleDimensions;
-                _cfgLocal.FormSize = _mySize;
-                _cfgLocal.FormLocation = _myLoc;
-                _cfgLocal.SplitterDistance = _mySpDis;
-                _cfgLocal.PreviewDistance = _mySpDis3;
-                _cfgLocal.StatusMultiline = StatusText.Multiline;
-                _cfgLocal.StatusTextHeight = _mySpDis2;
-
-                _cfgLocal.FontUnread = _fntUnread;
-                _cfgLocal.ColorUnread = _clUnread;
-                _cfgLocal.FontRead = _fntReaded;
-                _cfgLocal.ColorRead = _clReaded;
-                _cfgLocal.FontDetail = _fntDetail;
-                _cfgLocal.ColorDetail = _clDetail;
-                _cfgLocal.ColorDetailBackcolor = _clDetailBackcolor;
-                _cfgLocal.ColorDetailLink = _clDetailLink;
-                _cfgLocal.ColorFav = _clFav;
-                _cfgLocal.ColorOWL = _clOWL;
-                _cfgLocal.ColorRetweet = _clRetweet;
-                _cfgLocal.ColorSelf = _clSelf;
-                _cfgLocal.ColorAtSelf = _clAtSelf;
-                _cfgLocal.ColorTarget = _clTarget;
-                _cfgLocal.ColorAtTarget = _clAtTarget;
-                _cfgLocal.ColorAtFromTarget = _clAtFromTarget;
-                _cfgLocal.ColorAtTo = _clAtTo;
-                _cfgLocal.ColorListBackcolor = _clListBackcolor;
-                _cfgLocal.ColorInputBackcolor = _clInputBackcolor;
-                _cfgLocal.ColorInputFont = _clInputFont;
-                _cfgLocal.FontInputFont = _fntInputFont;
+                SettingManager.Local.ScaleDimension = this.CurrentAutoScaleDimensions;
+                SettingManager.Local.FormSize = _mySize;
+                SettingManager.Local.FormLocation = _myLoc;
+                SettingManager.Local.SplitterDistance = _mySpDis;
+                SettingManager.Local.PreviewDistance = _mySpDis3;
+                SettingManager.Local.StatusMultiline = StatusText.Multiline;
+                SettingManager.Local.StatusTextHeight = _mySpDis2;
+
+                SettingManager.Local.FontUnread = _fntUnread;
+                SettingManager.Local.ColorUnread = _clUnread;
+                SettingManager.Local.FontRead = _fntReaded;
+                SettingManager.Local.ColorRead = _clReaded;
+                SettingManager.Local.FontDetail = _fntDetail;
+                SettingManager.Local.ColorDetail = _clDetail;
+                SettingManager.Local.ColorDetailBackcolor = _clDetailBackcolor;
+                SettingManager.Local.ColorDetailLink = _clDetailLink;
+                SettingManager.Local.ColorFav = _clFav;
+                SettingManager.Local.ColorOWL = _clOWL;
+                SettingManager.Local.ColorRetweet = _clRetweet;
+                SettingManager.Local.ColorSelf = _clSelf;
+                SettingManager.Local.ColorAtSelf = _clAtSelf;
+                SettingManager.Local.ColorTarget = _clTarget;
+                SettingManager.Local.ColorAtTarget = _clAtTarget;
+                SettingManager.Local.ColorAtFromTarget = _clAtFromTarget;
+                SettingManager.Local.ColorAtTo = _clAtTo;
+                SettingManager.Local.ColorListBackcolor = _clListBackcolor;
+                SettingManager.Local.ColorInputBackcolor = _clInputBackcolor;
+                SettingManager.Local.ColorInputFont = _clInputFont;
+                SettingManager.Local.FontInputFont = _fntInputFont;
 
                 if (_ignoreConfigSave) return;
-                _cfgLocal.Save();
+                SettingManager.SaveLocal();
             }
         }
 
         private void SaveConfigsTabs()
         {
-            var tabsSetting = new SettingTabs();
+            var tabSettingList = new List<SettingTabs.SettingTabItem>();
 
             var tabs = this.ListTab.TabPages.Cast<TabPage>()
                 .Select(x => this._statuses.Tabs[x.Text])
@@ -7924,35 +7297,33 @@ namespace OpenTween
                     SoundFile = tab.SoundFile,
                 };
 
-                var filterTab = tab as FilterTabModel;
-                if (filterTab != null)
-                    tabSetting.FilterArray = filterTab.FilterArray;
-
-                var userTab = tab as UserTimelineTabModel;
-                if (userTab != null)
-                    tabSetting.User = userTab.ScreenName;
-
-                var searchTab = tab as PublicSearchTabModel;
-                if (searchTab != null)
+                switch (tab)
                 {
-                    tabSetting.SearchWords = searchTab.SearchWords;
-                    tabSetting.SearchLang = searchTab.SearchLang;
+                    case FilterTabModel filterTab:
+                        tabSetting.FilterArray = filterTab.FilterArray;
+                        break;
+                    case UserTimelineTabModel userTab:
+                        tabSetting.User = userTab.ScreenName;
+                        break;
+                    case PublicSearchTabModel searchTab:
+                        tabSetting.SearchWords = searchTab.SearchWords;
+                        tabSetting.SearchLang = searchTab.SearchLang;
+                        break;
+                    case ListTimelineTabModel listTab:
+                        tabSetting.ListInfo = listTab.ListInfo;
+                        break;
                 }
 
-                var listTab = tab as ListTimelineTabModel;
-                if (listTab != null)
-                    tabSetting.ListInfo = listTab.ListInfo;
-
-                tabsSetting.Tabs.Add(tabSetting);
+                tabSettingList.Add(tabSetting);
             }
 
-            tabsSetting.Save();
+            SettingManager.Tabs.Tabs = tabSettingList;
+            SettingManager.SaveTabs();
         }
 
         private async void OpenURLFileMenuItem_Click(object sender, EventArgs e)
         {
-            string inputText;
-            var ret = InputDialog.Show(this, Properties.Resources.OpenURL_InputText, Properties.Resources.OpenURL_Caption, out inputText);
+            var ret = InputDialog.Show(this, Properties.Resources.OpenURL_InputText, Properties.Resources.OpenURL_Caption, out var inputText);
             if (ret != DialogResult.OK)
                 return;
 
@@ -8004,9 +7375,9 @@ namespace OpenTween
                             if (post.IsProtect) protect = "Protect";
                             sw.WriteLine(post.Nickname + "\t" +
                                      "\"" + post.TextFromApi.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
-                                     post.CreatedAt.ToString() + "\t" +
+                                     post.CreatedAt + "\t" +
                                      post.ScreenName + "\t" +
-                                     post.StatusId.ToString() + "\t" +
+                                     post.StatusId + "\t" +
                                      post.ImageUrl + "\t" +
                                      "\"" + post.Text.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
                                      protect);
@@ -8021,9 +7392,9 @@ namespace OpenTween
                             if (post.IsProtect) protect = "Protect";
                             sw.WriteLine(post.Nickname + "\t" +
                                      "\"" + post.TextFromApi.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
-                                     post.CreatedAt.ToString() + "\t" +
+                                     post.CreatedAt + "\t" +
                                      post.ScreenName + "\t" +
-                                     post.StatusId.ToString() + "\t" +
+                                     post.StatusId + "\t" +
                                      post.ImageUrl + "\t" +
                                      "\"" + post.Text.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
                                      protect);
@@ -8031,79 +7402,46 @@ namespace OpenTween
                     }
                 }
             }
-            this.TopMost = this._cfgCommon.AlwaysTop;
+            this.TopMost = SettingManager.Common.AlwaysTop;
         }
 
-        private async void PostBrowser_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
-        {
-            Task asyncTask;
-            bool KeyRes = CommonKeyDown(e.KeyData, FocusedControl.PostBrowser, out asyncTask);
-            if (KeyRes)
-            {
-                e.IsInputKey = true;
-            }
-            else
-            {
-                if (Enum.IsDefined(typeof(Shortcut), (Shortcut)e.KeyData))
-                {
-                    var shortcut = (Shortcut)e.KeyData;
-                    switch (shortcut)
-                    {
-                        case Shortcut.CtrlA:
-                        case Shortcut.CtrlC:
-                        case Shortcut.CtrlIns:
-                            // 既定の動作を有効にする
-                            break;
-                        default:
-                            // その他のショートカットキーは無効にする
-                            e.IsInputKey = true;
-                            break;
-                    }
-                }
-            }
-
-            if (asyncTask != null)
-                await asyncTask;
-        }
-        public bool TabRename(ref string tabName)
+        public bool TabRename(string origTabName, out string newTabName)
         {
             //タブ名変更
-            string newTabText = null;
+            newTabName = null;
             using (InputTabName inputName = new InputTabName())
             {
-                inputName.TabName = tabName;
+                inputName.TabName = origTabName;
                 inputName.ShowDialog();
                 if (inputName.DialogResult == DialogResult.Cancel) return false;
-                newTabText = inputName.TabName;
+                newTabName = inputName.TabName;
             }
-            this.TopMost = this._cfgCommon.AlwaysTop;
-            if (!string.IsNullOrEmpty(newTabText))
+            this.TopMost = SettingManager.Common.AlwaysTop;
+            if (!string.IsNullOrEmpty(newTabName))
             {
                 //新タブ名存在チェック
                 for (int i = 0; i < ListTab.TabCount; i++)
                 {
-                    if (ListTab.TabPages[i].Text == newTabText)
+                    if (ListTab.TabPages[i].Text == newTabName)
                     {
-                        string tmp = string.Format(Properties.Resources.Tabs_DoubleClickText1, newTabText);
+                        string tmp = string.Format(Properties.Resources.Tabs_DoubleClickText1, newTabName);
                         MessageBox.Show(tmp, Properties.Resources.Tabs_DoubleClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                         return false;
                     }
                 }
-                //タブ名を変更
-                for (int i = 0; i < ListTab.TabCount; i++)
-                {
-                    if (ListTab.TabPages[i].Text == tabName)
-                    {
-                        ListTab.TabPages[i].Text = newTabText;
-                        break;
-                    }
-                }
-                _statuses.RenameTab(tabName, newTabText);
+
+                var tabPage = this.ListTab.TabPages.Cast<TabPage>()
+                    .FirstOrDefault(x => x.Text == origTabName);
+
+                // タブ名を変更
+                if (tabPage != null)
+                    tabPage.Text = newTabName;
+
+                _statuses.RenameTab(origTabName, newTabName);
 
                 SaveConfigsCommon();
                 SaveConfigsTabs();
-                _rclickTabName = newTabText;
-                tabName = newTabText;
+                _rclickTabName = newTabName;
                 return true;
             }
             else
@@ -8130,14 +7468,12 @@ namespace OpenTween
 
         private void ListTab_DoubleClick(object sender, MouseEventArgs e)
         {
-            string tn = ListTab.SelectedTab.Text;
-            TabRename(ref tn);
+            TabRename(this.ListTab.SelectedTab.Text, out var _);
         }
 
         private void ListTab_MouseDown(object sender, MouseEventArgs e)
         {
-            if (this._cfgCommon.TabMouseLock) return;
-            Point cpos = new Point(e.X, e.Y);
+            if (SettingManager.Common.TabMouseLock) return;
             if (e.Button == MouseButtons.Left)
             {
                 for (int i = 0; i < ListTab.TabPages.Count; i++)
@@ -8570,11 +7906,11 @@ namespace OpenTween
             }
 
             TabModel tb = _statuses.GetTabByType(MyCommon.TabUsageType.Mentions);
-            if (this._cfgCommon.ReplyIconState != MyCommon.REPLY_ICONSTATE.None && tb != null && tb.UnreadCount > 0)
+            if (SettingManager.Common.ReplyIconState != MyCommon.REPLY_ICONSTATE.None && tb != null && tb.UnreadCount > 0)
             {
                 if (blinkCnt > 0) return;
                 blink = !blink;
-                if (blink || this._cfgCommon.ReplyIconState == MyCommon.REPLY_ICONSTATE.StaticIcon)
+                if (blink || SettingManager.Common.ReplyIconState == MyCommon.REPLY_ICONSTATE.StaticIcon)
                 {
                     NotifyIcon1.Icon = ReplyIcon;
                 }
@@ -8625,8 +7961,8 @@ namespace OpenTween
             if (_statuses == null) return;
             if (_statuses.Tabs == null) return;
 
-            TabModel tb = _statuses.Tabs[_rclickTabName];
-            if (tb == null) return;
+            if (!this._statuses.Tabs.TryGetValue(this._rclickTabName, out var tb))
+                return;
 
             NotifyDispMenuItem.Checked = tb.Notify;
             this.NotifyTbMenuItem.Checked = tb.Notify;
@@ -8727,7 +8063,7 @@ namespace OpenTween
                 return;
 
             _statuses.Tabs[tabName].UnreadManage = isManage;
-            if (this._cfgCommon.TabIconDisp)
+            if (SettingManager.Common.TabIconDisp)
             {
                 if (_statuses.Tabs[tabName].UnreadCount > 0)
                     ListTab.TabPages[idx].ImageIndex = 0;
@@ -8743,7 +8079,7 @@ namespace OpenTween
 
             SetMainWindowTitle();
             SetStatusLabelUrl();
-            if (!this._cfgCommon.TabIconDisp) ListTab.Refresh();
+            if (!SettingManager.Common.TabIconDisp) ListTab.Refresh();
         }
 
         private void NotifyDispMenuItem_Click(object sender, EventArgs e)
@@ -8785,7 +8121,7 @@ namespace OpenTween
                 fltDialog.SetCurrent(_rclickTabName);
                 fltDialog.ShowDialog(this);
             }
-            this.TopMost = this._cfgCommon.AlwaysTop;
+            this.TopMost = SettingManager.Common.AlwaysTop;
 
             this.ApplyPostFilters();
             SaveConfigsTabs();
@@ -8804,7 +8140,7 @@ namespace OpenTween
                 tabName = inputName.TabName;
                 tabUsage = inputName.Usage;
             }
-            this.TopMost = this._cfgCommon.AlwaysTop;
+            this.TopMost = SettingManager.Common.AlwaysTop;
             if (!string.IsNullOrEmpty(tabName))
             {
                 //List対応
@@ -8868,9 +8204,8 @@ namespace OpenTween
                 //選択発言を元にフィルタ追加
                 foreach (int idx in _curList.SelectedIndices)
                 {
-                    string tabName;
                     //タブ選択(or追加)
-                    if (!SelectTab(out tabName)) return;
+                    if (!SelectTab(out var tabName)) return;
 
                     fltDialog.SetCurrent(tabName);
                     if (_statuses.Tabs[_curTab.Text][idx].RetweetedId == null)
@@ -8882,7 +8217,7 @@ namespace OpenTween
                         fltDialog.AddNewFilter(_statuses.Tabs[_curTab.Text][idx].RetweetedBy, _statuses.Tabs[_curTab.Text][idx].TextFromApi);
                     }
                     fltDialog.ShowDialog(this);
-                    this.TopMost = this._cfgCommon.AlwaysTop;
+                    this.TopMost = SettingManager.Common.AlwaysTop;
                 }
             }
 
@@ -8905,7 +8240,7 @@ namespace OpenTween
                     bool _NewLine = false;
                     bool _Post = false;
 
-                    if (this._cfgCommon.PostCtrlEnter) //Ctrl+Enter投稿時
+                    if (SettingManager.Common.PostCtrlEnter) //Ctrl+Enter投稿時
                     {
                         if (StatusText.Multiline)
                         {
@@ -8919,7 +8254,7 @@ namespace OpenTween
                         }
 
                     }
-                    else if (this._cfgCommon.PostShiftEnter) //SHift+Enter投稿時
+                    else if (SettingManager.Common.PostShiftEnter) //SHift+Enter投稿時
                     {
                         if (StatusText.Multiline)
                         {
@@ -8986,13 +8321,46 @@ namespace OpenTween
 
         private void IDRuleMenuItem_Click(object sender, EventArgs e)
         {
-            string tabName;
-
             //未選択なら処理終了
             if (_curList.SelectedIndices.Count == 0) return;
 
+            var tab = this._statuses.Tabs[this._curTab.Text];
+            var screenNameArray = this._curList.SelectedIndices.Cast<int>()
+                .Select(x => tab[x])
+                .Select(x => x.RetweetedId != null ? x.RetweetedBy : x.ScreenName)
+                .ToArray();
+
+            this.AddFilterRuleByScreenName(screenNameArray);
+
+            if (screenNameArray.Length != 0)
+            {
+                List<string> atids = new List<string>();
+                foreach (var screenName in screenNameArray)
+                {
+                    atids.Add("@" + screenName);
+                }
+                int cnt = AtIdSupl.ItemCount;
+                AtIdSupl.AddRangeItem(atids.ToArray());
+                if (AtIdSupl.ItemCount != cnt) ModifySettingAtId = true;
+            }
+        }
+
+        private void SourceRuleMenuItem_Click(object sender, EventArgs e)
+        {
+            if (this._curList.SelectedIndices.Count == 0)
+                return;
+
+            var tab = this._statuses.Tabs[this._curTab.Text];
+            var sourceArray = this._curList.SelectedIndices.Cast<int>()
+                .Select(x => tab[x].Source).ToArray();
+
+            this.AddFilterRuleBySource(sourceArray);
+        }
+
+        public void AddFilterRuleByScreenName(params string[] screenNameArray)
+        {
             //タブ選択(or追加)
-            if (!SelectTab(out tabName)) return;
+            if (!SelectTab(out var tabName)) return;
 
             var tab = (FilterTabModel)this._statuses.Tabs[tabName];
 
@@ -9009,57 +8377,29 @@ namespace OpenTween
                 mk = false;
             }
 
-            List<string> ids = new List<string>();
-            foreach (int idx in _curList.SelectedIndices)
-            {
-                PostClass post = _statuses.Tabs[_curTab.Text][idx];
-                if (!ids.Contains(post.ScreenName))
-                {
-                    PostFilterRule fc = new PostFilterRule();
-                    ids.Add(post.ScreenName);
-                    if (post.RetweetedId == null)
-                    {
-                        fc.FilterName = post.ScreenName;
-                    }
-                    else
-                    {
-                        fc.FilterName = post.RetweetedBy;
-                    }
-                    fc.UseNameField = true;
-                    fc.MoveMatches = mv;
-                    fc.MarkMatches = mk;
-                    fc.UseRegex = false;
-                    fc.FilterByUrl = false;
-                    tab.AddFilter(fc);
-                }
-            }
-            if (ids.Count != 0)
+            foreach (var screenName in screenNameArray)
             {
-                List<string> atids = new List<string>();
-                foreach (string id in ids)
+                tab.AddFilter(new PostFilterRule
                 {
-                    atids.Add("@" + id);
-                }
-                int cnt = AtIdSupl.ItemCount;
-                AtIdSupl.AddRangeItem(atids.ToArray());
-                if (AtIdSupl.ItemCount != cnt) ModifySettingAtId = true;
+                    FilterName = screenName,
+                    UseNameField = true,
+                    MoveMatches = mv,
+                    MarkMatches = mk,
+                    UseRegex = false,
+                    FilterByUrl = false,
+                });
             }
 
             this.ApplyPostFilters();
             SaveConfigsTabs();
         }
 
-        private void SourceRuleMenuItem_Click(object sender, EventArgs e)
+        public void AddFilterRuleBySource(params string[] sourceArray)
         {
-            if (this._curList.SelectedIndices.Count == 0)
-                return;
-
             // タブ選択ダイアログを表示(or追加)
-            string tabName;
-            if (!this.SelectTab(out tabName))
+            if (!this.SelectTab(out var tabName))
                 return;
 
-            var currentTab = this._statuses.Tabs[this._curTab.Text];
             var filterTab = (FilterTabModel)this._statuses.Tabs[tabName];
 
             bool mv;
@@ -9077,25 +8417,16 @@ namespace OpenTween
             }
 
             // 振り分けルールに追加するSource
-            var sources = new HashSet<string>();
-
-            foreach (var idx in this._curList.SelectedIndices.Cast<int>())
+            foreach (var source in sourceArray)
             {
-                var post = currentTab[idx];
-                var filterSource = post.Source;
-
-                if (sources.Add(filterSource))
+                filterTab.AddFilter(new PostFilterRule
                 {
-                    var filter = new PostFilterRule
-                    {
-                        FilterSource = filterSource,
-                        MoveMatches = mv,
-                        MarkMatches = mk,
-                        UseRegex = false,
-                        FilterByUrl = false,
-                    };
-                    filterTab.AddFilter(filter);
-                }
+                    FilterSource = source,
+                    MoveMatches = mv,
+                    MarkMatches = mk,
+                    UseRegex = false,
+                    FilterByUrl = false,
+                });
             }
 
             this.ApplyPostFilters();
@@ -9128,7 +8459,7 @@ namespace OpenTween
                         if (inputName.DialogResult == DialogResult.Cancel) return false;
                         tabName = inputName.TabName;
                     }
-                    this.TopMost = this._cfgCommon.AlwaysTop;
+                    this.TopMost = SettingManager.Common.AlwaysTop;
                     if (!string.IsNullOrEmpty(tabName))
                     {
                         var tab = new FilterTabModel(tabName);
@@ -9232,9 +8563,7 @@ namespace OpenTween
 
         private async void OpenURLMenuItem_Click(object sender, EventArgs e)
         {
-            var linkElements = this.PostBrowser.Document.Links.Cast<HtmlElement>()
-                .Where(x => x.GetAttribute("className") != "tweet-quote-link") // 引用ツイートで追加されたリンクを除く
-                .ToArray();
+            var linkElements = this.tweetDetailsView.GetLinkElements();
 
             if (linkElements.Length > 0)
             {
@@ -9310,7 +8639,7 @@ namespace OpenTween
                     {
                         return;
                     }
-                    this.TopMost = this._cfgCommon.AlwaysTop;
+                    this.TopMost = SettingManager.Common.AlwaysTop;
                 }
             }
         }
@@ -9345,12 +8674,12 @@ namespace OpenTween
             {
                 if (tb.Text == tabName)
                 {
-                    tb.ImageIndex = -1;
                     ((DetailsListView)tb.Tag).VirtualListSize = 0;
+                    tb.ImageIndex = -1;
                     break;
                 }
             }
-            if (!this._cfgCommon.TabIconDisp) ListTab.Refresh();
+            if (!SettingManager.Common.TabIconDisp) ListTab.Refresh();
 
             SetMainWindowTitle();
             SetStatusLabelUrl();
@@ -9364,10 +8693,10 @@ namespace OpenTween
             StringBuilder ttl = new StringBuilder(256);
             int ur = 0;
             int al = 0;
-            if (this._cfgCommon.DispLatestPost != MyCommon.DispTitleEnum.None &&
-                this._cfgCommon.DispLatestPost != MyCommon.DispTitleEnum.Post &&
-                this._cfgCommon.DispLatestPost != MyCommon.DispTitleEnum.Ver &&
-                this._cfgCommon.DispLatestPost != MyCommon.DispTitleEnum.OwnStatus)
+            if (SettingManager.Common.DispLatestPost != MyCommon.DispTitleEnum.None &&
+                SettingManager.Common.DispLatestPost != MyCommon.DispTitleEnum.Post &&
+                SettingManager.Common.DispLatestPost != MyCommon.DispTitleEnum.Ver &&
+                SettingManager.Common.DispLatestPost != MyCommon.DispTitleEnum.OwnStatus)
             {
                 foreach (var tab in _statuses.Tabs.Values)
                 {
@@ -9376,10 +8705,10 @@ namespace OpenTween
                 }
             }
 
-            if (this._cfgCommon.DispUsername) ttl.Append(tw.Username).Append(" - ");
+            if (SettingManager.Common.DispUsername) ttl.Append(tw.Username).Append(" - ");
             ttl.Append(Application.ProductName);
             ttl.Append("  ");
-            switch (this._cfgCommon.DispLatestPost)
+            switch (SettingManager.Common.DispLatestPost)
             {
                 case MyCommon.DispTitleEnum.Ver:
                     ttl.Append("Ver:").Append(MyCommon.GetReadableVersion());
@@ -9454,13 +8783,13 @@ namespace OpenTween
             var homeTab = this._statuses.GetTabByType<HomeTabModel>();
 
             slbl.AppendFormat(Properties.Resources.SetStatusLabelText1, tur, tal, ur, al, urat, _postTimestamps.Count, _favTimestamps.Count, homeTab.TweetsPerHour);
-            if (this._cfgCommon.TimelinePeriod == 0)
+            if (SettingManager.Common.TimelinePeriod == 0)
             {
                 slbl.Append(Properties.Resources.SetStatusLabelText2);
             }
             else
             {
-                slbl.Append(this._cfgCommon.TimelinePeriod + Properties.Resources.SetStatusLabelText3);
+                slbl.Append(SettingManager.Common.TimelinePeriod + Properties.Resources.SetStatusLabelText3);
             }
             return slbl.ToString();
         }
@@ -9605,14 +8934,14 @@ namespace OpenTween
             StatusLabel.Text = text;
         }
 
-        private static StringBuilder ur = new StringBuilder(64);
-
         private void SetNotifyIconText()
         {
+            var ur = new StringBuilder(64);
+
             // タスクトレイアイコンのツールチップテキスト書き換え
             // Tween [未読/@]
             ur.Remove(0, ur.Length);
-            if (this._cfgCommon.DispUsername)
+            if (SettingManager.Common.DispUsername)
             {
                 ur.Append(tw.Username);
                 ur.Append(" - ");
@@ -9655,7 +8984,7 @@ namespace OpenTween
             // 本当にリプライ先指定すべきかどうかの判定
             m = Regex.Matches(StatusText, "(^|[ -/:-@[-^`{-~])(?<id>@[a-zA-Z0-9_]+)");
 
-            if (this._cfgCommon.UseAtIdSupplement)
+            if (SettingManager.Common.UseAtIdSupplement)
             {
                 int bCnt = AtIdSupl.ItemCount;
                 foreach (Match mid in m)
@@ -9696,22 +9025,22 @@ namespace OpenTween
 
         private void TweenMain_Resize(object sender, EventArgs e)
         {
-            if (!_initialLayout && this._cfgCommon.MinimizeToTray && WindowState == FormWindowState.Minimized)
+            if (!_initialLayout && SettingManager.Common.MinimizeToTray && WindowState == FormWindowState.Minimized)
             {
                 this.Visible = false;
             }
-            if (_initialLayout && _cfgLocal != null && this.WindowState == FormWindowState.Normal && this.Visible)
+            if (_initialLayout && SettingManager.Local != null && this.WindowState == FormWindowState.Normal && this.Visible)
             {
                 // 現在の DPI と設定保存時の DPI との比を取得する
-                var configScaleFactor = this._cfgLocal.GetConfigScaleFactor(this.CurrentAutoScaleDimensions);
+                var configScaleFactor = SettingManager.Local.GetConfigScaleFactor(this.CurrentAutoScaleDimensions);
 
-                this.ClientSize = ScaleBy(configScaleFactor, _cfgLocal.FormSize);
+                this.ClientSize = ScaleBy(configScaleFactor, SettingManager.Local.FormSize);
                 //_mySize = this.ClientSize;                     //サイズ保持(最小化・最大化されたまま終了した場合の対応用)
-                this.DesktopLocation = _cfgLocal.FormLocation;
+                this.DesktopLocation = SettingManager.Local.FormLocation;
                 //_myLoc = this.DesktopLocation;                        //位置保持(最小化・最大化されたまま終了した場合の対応用)
 
                 // Splitterの位置設定
-                var splitterDistance = ScaleBy(configScaleFactor.Height, _cfgLocal.SplitterDistance);
+                var splitterDistance = ScaleBy(configScaleFactor.Height, SettingManager.Local.SplitterDistance);
                 if (splitterDistance > this.SplitContainer1.Panel1MinSize &&
                     splitterDistance < this.SplitContainer1.Height - this.SplitContainer1.Panel2MinSize - this.SplitContainer1.SplitterWidth)
                 {
@@ -9719,10 +9048,10 @@ namespace OpenTween
                 }
 
                 //発言欄複数行
-                StatusText.Multiline = _cfgLocal.StatusMultiline;
+                StatusText.Multiline = SettingManager.Local.StatusMultiline;
                 if (StatusText.Multiline)
                 {
-                    var statusTextHeight = ScaleBy(configScaleFactor.Height, _cfgLocal.StatusTextHeight);
+                    var statusTextHeight = ScaleBy(configScaleFactor.Height, SettingManager.Local.StatusTextHeight);
                     int dis = SplitContainer2.Height - statusTextHeight - SplitContainer2.SplitterWidth;
                     if (dis > SplitContainer2.Panel1MinSize && dis < SplitContainer2.Height - SplitContainer2.Panel2MinSize - SplitContainer2.SplitterWidth)
                     {
@@ -9738,7 +9067,7 @@ namespace OpenTween
                     }
                 }
 
-                var previewDistance = ScaleBy(configScaleFactor.Width, _cfgLocal.PreviewDistance);
+                var previewDistance = ScaleBy(configScaleFactor.Width, SettingManager.Local.PreviewDistance);
                 if (previewDistance > this.SplitContainer3.Panel1MinSize && previewDistance < this.SplitContainer3.Width - this.SplitContainer3.Panel2MinSize - this.SplitContainer3.SplitterWidth)
                 {
                     this.SplitContainer3.SplitterDistance = previewDistance;
@@ -9761,11 +9090,11 @@ namespace OpenTween
             this.PlaySoundFileMenuItem.Checked = PlaySoundMenuItem.Checked;
             if (PlaySoundMenuItem.Checked)
             {
-                this._cfgCommon.PlaySound = true;
+                SettingManager.Common.PlaySound = true;
             }
             else
             {
-                this._cfgCommon.PlaySound = false;
+                SettingManager.Common.PlaySound = false;
             }
             ModifySettingCommon = true;
         }
@@ -9807,7 +9136,7 @@ namespace OpenTween
                 if (_statuses.ContainsKey(_curPost.InReplyToStatusId.Value))
                 {
                     PostClass repPost = _statuses[_curPost.InReplyToStatusId.Value];
-                    MessageBox.Show(repPost.ScreenName + " / " + repPost.Nickname + "   (" + repPost.CreatedAt.ToString() + ")" + Environment.NewLine + repPost.TextFromApi);
+                    MessageBox.Show($"{repPost.ScreenName} / {repPost.Nickname}   ({repPost.CreatedAt})" + Environment.NewLine + repPost.TextFromApi);
                 }
                 else
                 {
@@ -9815,7 +9144,7 @@ namespace OpenTween
                     {
                         if (tb == null || !tb.Contains(_curPost.InReplyToStatusId.Value)) break;
                         PostClass repPost = _statuses[_curPost.InReplyToStatusId.Value];
-                        MessageBox.Show(repPost.ScreenName + " / " + repPost.Nickname + "   (" + repPost.CreatedAt.ToString() + ")" + Environment.NewLine + repPost.TextFromApi);
+                        MessageBox.Show($"{repPost.ScreenName} / {repPost.Nickname}   ({repPost.CreatedAt})" + Environment.NewLine + repPost.TextFromApi);
                         return;
                     }
                     await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(_curPost.InReplyToUser, _curPost.InReplyToStatusId.Value));
@@ -9828,179 +9157,6 @@ namespace OpenTween
             await this.doRepliedStatusOpen();
         }
 
-        /// <summary>
-        /// UserPicture.Image に設定されている画像を破棄します。
-        /// </summary>
-        private void ClearUserPicture()
-        {
-            if (this.UserPicture.Image != null)
-            {
-                var oldImage = this.UserPicture.Image;
-                this.UserPicture.Image = null;
-                oldImage.Dispose();
-            }
-        }
-
-        private void ContextMenuUserPicture_Opening(object sender, CancelEventArgs e)
-        {
-            //発言詳細のアイコン右クリック時のメニュー制御
-            if (_curList.SelectedIndices.Count > 0 && _curPost != null)
-            {
-                string name = _curPost.ImageUrl;
-                if (name != null && name.Length > 0)
-                {
-                    int idx = name.LastIndexOf('/');
-                    if (idx != -1)
-                    {
-                        name = Path.GetFileName(name.Substring(idx));
-                        if (name.Contains("_normal.") || name.EndsWith("_normal", StringComparison.Ordinal))
-                        {
-                            name = name.Replace("_normal", "");
-                            this.IconNameToolStripMenuItem.Text = name;
-                            this.IconNameToolStripMenuItem.Enabled = true;
-                        }
-                        else
-                        {
-                            this.IconNameToolStripMenuItem.Enabled = false;
-                            this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText1;
-                        }
-                    }
-                    else
-                    {
-                        this.IconNameToolStripMenuItem.Enabled = false;
-                        this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText1;
-                    }
-
-                    this.ReloadIconToolStripMenuItem.Enabled = true;
-
-                    if (this.IconCache.TryGetFromCache(_curPost.ImageUrl) != null)
-                    {
-                        this.SaveIconPictureToolStripMenuItem.Enabled = true;
-                    }
-                    else
-                    {
-                        this.SaveIconPictureToolStripMenuItem.Enabled = false;
-                    }
-                }
-                else
-                {
-                    this.IconNameToolStripMenuItem.Enabled = false;
-                    this.ReloadIconToolStripMenuItem.Enabled = false;
-                    this.SaveIconPictureToolStripMenuItem.Enabled = false;
-                    this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText1;
-                }
-            }
-            else
-            {
-                this.IconNameToolStripMenuItem.Enabled = false;
-                this.ReloadIconToolStripMenuItem.Enabled = false;
-                this.SaveIconPictureToolStripMenuItem.Enabled = false;
-                this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText2;
-            }
-            if (NameLabel.Tag != null)
-            {
-                string id = (string)NameLabel.Tag;
-                if (id == tw.Username)
-                {
-                    FollowToolStripMenuItem.Enabled = false;
-                    UnFollowToolStripMenuItem.Enabled = false;
-                    ShowFriendShipToolStripMenuItem.Enabled = false;
-                    ShowUserStatusToolStripMenuItem.Enabled = true;
-                    SearchPostsDetailNameToolStripMenuItem.Enabled = true;
-                    SearchAtPostsDetailNameToolStripMenuItem.Enabled = false;
-                    ListManageUserContextToolStripMenuItem3.Enabled = true;
-                }
-                else
-                {
-                    FollowToolStripMenuItem.Enabled = true;
-                    UnFollowToolStripMenuItem.Enabled = true;
-                    ShowFriendShipToolStripMenuItem.Enabled = true;
-                    ShowUserStatusToolStripMenuItem.Enabled = true;
-                    SearchPostsDetailNameToolStripMenuItem.Enabled = true;
-                    SearchAtPostsDetailNameToolStripMenuItem.Enabled = true;
-                    ListManageUserContextToolStripMenuItem3.Enabled = true;
-                }
-            }
-            else
-            {
-                FollowToolStripMenuItem.Enabled = false;
-                UnFollowToolStripMenuItem.Enabled = false;
-                ShowFriendShipToolStripMenuItem.Enabled = false;
-                ShowUserStatusToolStripMenuItem.Enabled = false;
-                SearchPostsDetailNameToolStripMenuItem.Enabled = false;
-                SearchAtPostsDetailNameToolStripMenuItem.Enabled = false;
-                ListManageUserContextToolStripMenuItem3.Enabled = false;
-            }
-        }
-
-        private async void IconNameToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            if (_curPost == null) return;
-            string name = _curPost.ImageUrl;
-            await this.OpenUriInBrowserAsync(name.Remove(name.LastIndexOf("_normal"), 7)); // "_normal".Length
-        }
-
-        private async void ReloadIconToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            if (this._curPost == null) return;
-
-            await this.UserPicture.SetImageFromTask(async () =>
-            {
-                var imageUrl = this._curPost.ImageUrl;
-
-                var image = await this.IconCache.DownloadImageAsync(imageUrl, force: true)
-                    .ConfigureAwait(false);
-
-                return await image.CloneAsync()
-                    .ConfigureAwait(false);
-            });
-        }
-
-        private void SaveOriginalSizeIconPictureToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            if (_curPost == null) return;
-            string name = _curPost.ImageUrl;
-            name = Path.GetFileNameWithoutExtension(name.Substring(name.LastIndexOf('/')));
-
-            this.SaveFileDialog1.FileName = name.Substring(0, name.Length - 8); // "_normal".Length + 1
-
-            if (this.SaveFileDialog1.ShowDialog() == DialogResult.OK)
-            {
-                // STUB
-            }
-        }
-
-        private void SaveIconPictureToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            if (_curPost == null) return;
-            string name = _curPost.ImageUrl;
-
-            this.SaveFileDialog1.FileName = name.Substring(name.LastIndexOf('/') + 1);
-
-            if (this.SaveFileDialog1.ShowDialog() == DialogResult.OK)
-            {
-                try
-                {
-                    using (Image orgBmp = new Bitmap(IconCache.TryGetFromCache(name).Image))
-                    {
-                        using (Bitmap bmp2 = new Bitmap(orgBmp.Size.Width, orgBmp.Size.Height))
-                        {
-                            using (Graphics g = Graphics.FromImage(bmp2))
-                            {
-                                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
-                                g.DrawImage(orgBmp, 0, 0, orgBmp.Size.Width, orgBmp.Size.Height);
-                            }
-                            bmp2.Save(this.SaveFileDialog1.FileName);
-                        }
-                    }
-                }
-                catch (Exception)
-                {
-                    //処理中にキャッシュアウトする可能性あり
-                }
-            }
-        }
-
         private void SplitContainer2_Panel2_Resize(object sender, EventArgs e)
         {
             var multiline = this.SplitContainer2.Panel2.Height > this.SplitContainer2.Panel2MinSize + 2;
@@ -10026,7 +9182,7 @@ namespace OpenTween
         {
             //発言欄複数行
             StatusText.Multiline = MultiLineMenuItem.Checked;
-            _cfgLocal.StatusMultiline = MultiLineMenuItem.Checked;
+            SettingManager.Local.StatusMultiline = MultiLineMenuItem.Checked;
             if (MultiLineMenuItem.Checked)
             {
                 if (SplitContainer2.Height - _mySpDis2 - SplitContainer2.SplitterWidth < 0)
@@ -10059,12 +9215,12 @@ namespace OpenTween
             {
                 string tmp = StatusText.SelectedText;
                 // httpから始まらない場合、ExcludeStringで指定された文字列で始まる場合は対象としない
-                if (tmp.StartsWith("http"))
+                if (tmp.StartsWith("http", StringComparison.OrdinalIgnoreCase))
                 {
                     // 文字列が選択されている場合はその文字列について処理
 
                     //nico.ms使用、nicovideoにマッチしたら変換
-                    if (this._cfgCommon.Nicoms && Regex.IsMatch(tmp, nico))
+                    if (SettingManager.Common.Nicoms && Regex.IsMatch(tmp, nico))
                     {
                         result = nicoms.Shorten(tmp);
                     }
@@ -10097,7 +9253,12 @@ namespace OpenTween
                     {
                         urlUndo undotmp = new urlUndo();
 
-                        StatusText.Select(StatusText.Text.IndexOf(tmp, StringComparison.Ordinal), tmp.Length);
+                        // 短縮 URL が生成されるまでの間に投稿欄から元の URL が削除されていたら中断する
+                        var origUrlIndex = this.StatusText.Text.IndexOf(tmp, StringComparison.Ordinal);
+                        if (origUrlIndex == -1)
+                            return false;
+
+                        StatusText.Select(origUrlIndex, tmp.Length);
                         StatusText.SelectedText = result;
 
                         //undoバッファにセット
@@ -10133,7 +9294,7 @@ namespace OpenTween
                     StatusText.Select(StatusText.Text.IndexOf(mt.Result("${url}"), StringComparison.Ordinal), mt.Result("${url}").Length);
 
                     //nico.ms使用、nicovideoにマッチしたら変換
-                    if (this._cfgCommon.Nicoms && Regex.IsMatch(tmp, nico))
+                    if (SettingManager.Common.Nicoms && Regex.IsMatch(tmp, nico))
                     {
                         result = nicoms.Shorten(tmp);
                     }
@@ -10173,7 +9334,12 @@ namespace OpenTween
 
                     if (!string.IsNullOrEmpty(result))
                     {
-                        StatusText.Select(StatusText.Text.IndexOf(mt.Result("${url}"), StringComparison.Ordinal), mt.Result("${url}").Length);
+                        // 短縮 URL が生成されるまでの間に投稿欄から元の URL が削除されていたら中断する
+                        var origUrlIndex = this.StatusText.Text.IndexOf(mt.Result("${url}"), StringComparison.Ordinal);
+                        if (origUrlIndex == -1)
+                            return false;
+
+                        StatusText.Select(origUrlIndex, mt.Result("${url}").Length);
                         StatusText.SelectedText = result;
                         //undoバッファにセット
                         undotmp.Before = mt.Result("${url}");
@@ -10232,16 +9398,16 @@ namespace OpenTween
 
         private async void UrlConvertAutoToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            if (!await UrlConvertAsync(this._cfgCommon.AutoShortUrlFirst))
+            if (!await UrlConvertAsync(SettingManager.Common.AutoShortUrlFirst))
             {
-                MyCommon.UrlConverter svc = this._cfgCommon.AutoShortUrlFirst;
+                MyCommon.UrlConverter svc = SettingManager.Common.AutoShortUrlFirst;
                 Random rnd = new Random();
                 // 前回使用した短縮URLサービス以外を選択する
                 do
                 {
                     svc = (MyCommon.UrlConverter)rnd.Next(System.Enum.GetNames(typeof(MyCommon.UrlConverter)).Length);
                 }
-                while (svc == this._cfgCommon.AutoShortUrlFirst || svc == MyCommon.UrlConverter.Nicoms || svc == MyCommon.UrlConverter.Unu);
+                while (svc == SettingManager.Common.AutoShortUrlFirst || svc == MyCommon.UrlConverter.Nicoms || svc == MyCommon.UrlConverter.Unu);
                 await UrlConvertAsync(svc);
             }
         }
@@ -10255,7 +9421,7 @@ namespace OpenTween
         {
             this.NotifyFileMenuItem.Checked = ((ToolStripMenuItem)sender).Checked;
             this.NewPostPopMenuItem.Checked = this.NotifyFileMenuItem.Checked;
-            _cfgCommon.NewAllPop = NewPostPopMenuItem.Checked;
+            SettingManager.Common.NewAllPop = NewPostPopMenuItem.Checked;
             ModifySettingCommon = true;
         }
 
@@ -10263,7 +9429,7 @@ namespace OpenTween
         {
             ListLockMenuItem.Checked = ((ToolStripMenuItem)sender).Checked;
             this.LockListFileMenuItem.Checked = ListLockMenuItem.Checked;
-            _cfgCommon.ListLock = ListLockMenuItem.Checked;
+            SettingManager.Common.ListLock = ListLockMenuItem.Checked;
             ModifySettingCommon = true;
         }
 
@@ -10298,12 +9464,12 @@ namespace OpenTween
         private void MyList_ColumnReordered(object sender, ColumnReorderedEventArgs e)
         {
             DetailsListView lst = (DetailsListView)sender;
-            if (_cfgLocal == null) return;
+            if (SettingManager.Local == null) return;
 
             if (_iconCol)
             {
-                _cfgLocal.Width1 = lst.Columns[0].Width;
-                _cfgLocal.Width3 = lst.Columns[1].Width;
+                SettingManager.Local.Width1 = lst.Columns[0].Width;
+                SettingManager.Local.Width3 = lst.Columns[1].Width;
             }
             else
             {
@@ -10319,39 +9485,39 @@ namespace OpenTween
                     switch (darr[i])
                     {
                         case 0:
-                            _cfgLocal.DisplayIndex1 = i;
+                            SettingManager.Local.DisplayIndex1 = i;
                             break;
                         case 1:
-                            _cfgLocal.DisplayIndex2 = i;
+                            SettingManager.Local.DisplayIndex2 = i;
                             break;
                         case 2:
-                            _cfgLocal.DisplayIndex3 = i;
+                            SettingManager.Local.DisplayIndex3 = i;
                             break;
                         case 3:
-                            _cfgLocal.DisplayIndex4 = i;
+                            SettingManager.Local.DisplayIndex4 = i;
                             break;
                         case 4:
-                            _cfgLocal.DisplayIndex5 = i;
+                            SettingManager.Local.DisplayIndex5 = i;
                             break;
                         case 5:
-                            _cfgLocal.DisplayIndex6 = i;
+                            SettingManager.Local.DisplayIndex6 = i;
                             break;
                         case 6:
-                            _cfgLocal.DisplayIndex7 = i;
+                            SettingManager.Local.DisplayIndex7 = i;
                             break;
                         case 7:
-                            _cfgLocal.DisplayIndex8 = i;
+                            SettingManager.Local.DisplayIndex8 = i;
                             break;
                     }
                 }
-                _cfgLocal.Width1 = lst.Columns[0].Width;
-                _cfgLocal.Width2 = lst.Columns[1].Width;
-                _cfgLocal.Width3 = lst.Columns[2].Width;
-                _cfgLocal.Width4 = lst.Columns[3].Width;
-                _cfgLocal.Width5 = lst.Columns[4].Width;
-                _cfgLocal.Width6 = lst.Columns[5].Width;
-                _cfgLocal.Width7 = lst.Columns[6].Width;
-                _cfgLocal.Width8 = lst.Columns[7].Width;
+                SettingManager.Local.Width1 = lst.Columns[0].Width;
+                SettingManager.Local.Width2 = lst.Columns[1].Width;
+                SettingManager.Local.Width3 = lst.Columns[2].Width;
+                SettingManager.Local.Width4 = lst.Columns[3].Width;
+                SettingManager.Local.Width5 = lst.Columns[4].Width;
+                SettingManager.Local.Width6 = lst.Columns[5].Width;
+                SettingManager.Local.Width7 = lst.Columns[6].Width;
+                SettingManager.Local.Width8 = lst.Columns[7].Width;
             }
             ModifySettingLocal = true;
             _isColumnChanged = true;
@@ -10360,69 +9526,69 @@ namespace OpenTween
         private void MyList_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
         {
             DetailsListView lst = (DetailsListView)sender;
-            if (_cfgLocal == null) return;
+            if (SettingManager.Local == null) return;
             if (_iconCol)
             {
-                if (_cfgLocal.Width1 != lst.Columns[0].Width)
+                if (SettingManager.Local.Width1 != lst.Columns[0].Width)
                 {
-                    _cfgLocal.Width1 = lst.Columns[0].Width;
+                    SettingManager.Local.Width1 = lst.Columns[0].Width;
                     ModifySettingLocal = true;
                     _isColumnChanged = true;
                 }
-                if (_cfgLocal.Width3 != lst.Columns[1].Width)
+                if (SettingManager.Local.Width3 != lst.Columns[1].Width)
                 {
-                    _cfgLocal.Width3 = lst.Columns[1].Width;
+                    SettingManager.Local.Width3 = lst.Columns[1].Width;
                     ModifySettingLocal = true;
                     _isColumnChanged = true;
                 }
             }
             else
             {
-                if (_cfgLocal.Width1 != lst.Columns[0].Width)
+                if (SettingManager.Local.Width1 != lst.Columns[0].Width)
                 {
-                    _cfgLocal.Width1 = lst.Columns[0].Width;
+                    SettingManager.Local.Width1 = lst.Columns[0].Width;
                     ModifySettingLocal = true;
                     _isColumnChanged = true;
                 }
-                if (_cfgLocal.Width2 != lst.Columns[1].Width)
+                if (SettingManager.Local.Width2 != lst.Columns[1].Width)
                 {
-                    _cfgLocal.Width2 = lst.Columns[1].Width;
+                    SettingManager.Local.Width2 = lst.Columns[1].Width;
                     ModifySettingLocal = true;
                     _isColumnChanged = true;
                 }
-                if (_cfgLocal.Width3 != lst.Columns[2].Width)
+                if (SettingManager.Local.Width3 != lst.Columns[2].Width)
                 {
-                    _cfgLocal.Width3 = lst.Columns[2].Width;
+                    SettingManager.Local.Width3 = lst.Columns[2].Width;
                     ModifySettingLocal = true;
                     _isColumnChanged = true;
                 }
-                if (_cfgLocal.Width4 != lst.Columns[3].Width)
+                if (SettingManager.Local.Width4 != lst.Columns[3].Width)
                 {
-                    _cfgLocal.Width4 = lst.Columns[3].Width;
+                    SettingManager.Local.Width4 = lst.Columns[3].Width;
                     ModifySettingLocal = true;
                     _isColumnChanged = true;
                 }
-                if (_cfgLocal.Width5 != lst.Columns[4].Width)
+                if (SettingManager.Local.Width5 != lst.Columns[4].Width)
                 {
-                    _cfgLocal.Width5 = lst.Columns[4].Width;
+                    SettingManager.Local.Width5 = lst.Columns[4].Width;
                     ModifySettingLocal = true;
                     _isColumnChanged = true;
                 }
-                if (_cfgLocal.Width6 != lst.Columns[5].Width)
+                if (SettingManager.Local.Width6 != lst.Columns[5].Width)
                 {
-                    _cfgLocal.Width6 = lst.Columns[5].Width;
+                    SettingManager.Local.Width6 = lst.Columns[5].Width;
                     ModifySettingLocal = true;
                     _isColumnChanged = true;
                 }
-                if (_cfgLocal.Width7 != lst.Columns[6].Width)
+                if (SettingManager.Local.Width7 != lst.Columns[6].Width)
                 {
-                    _cfgLocal.Width7 = lst.Columns[6].Width;
+                    SettingManager.Local.Width7 = lst.Columns[6].Width;
                     ModifySettingLocal = true;
                     _isColumnChanged = true;
                 }
-                if (_cfgLocal.Width8 != lst.Columns[7].Width)
+                if (SettingManager.Local.Width8 != lst.Columns[7].Width)
                 {
-                    _cfgLocal.Width8 = lst.Columns[7].Width;
+                    SettingManager.Local.Width8 = lst.Columns[7].Width;
                     ModifySettingLocal = true;
                     _isColumnChanged = true;
                 }
@@ -10434,194 +9600,6 @@ namespace OpenTween
             //}
         }
 
-        private void SelectionCopyContextMenuItem_Click(object sender, EventArgs e)
-        {
-            //発言詳細で「選択文字列をコピー」
-            string _selText = this.PostBrowser.GetSelectedText();
-            try
-            {
-                Clipboard.SetDataObject(_selText, false, 5, 100);
-            }
-            catch (Exception ex)
-            {
-                MessageBox.Show(ex.Message);
-            }
-        }
-
-        private async Task doSearchToolStrip(string url)
-        {
-            //発言詳細で「選択文字列で検索」(選択文字列取得)
-            string _selText = this.PostBrowser.GetSelectedText();
-
-            if (_selText != null)
-            {
-                if (url == Properties.Resources.SearchItem4Url)
-                {
-                    //公式検索
-                    AddNewTabForSearch(_selText);
-                    return;
-                }
-
-                string tmp = string.Format(url, Uri.EscapeDataString(_selText));
-                await this.OpenUriInBrowserAsync(tmp);
-            }
-        }
-
-        private void SelectionAllContextMenuItem_Click(object sender, EventArgs e)
-        {
-            //発言詳細ですべて選択
-            PostBrowser.Document.ExecCommand("SelectAll", false, null);
-        }
-
-        private async void SearchWikipediaContextMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.doSearchToolStrip(Properties.Resources.SearchItem1Url);
-        }
-
-        private async void SearchGoogleContextMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.doSearchToolStrip(Properties.Resources.SearchItem2Url);
-        }
-
-        private async void SearchPublicSearchContextMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.doSearchToolStrip(Properties.Resources.SearchItem4Url);
-        }
-
-        private void UrlCopyContextMenuItem_Click(object sender, EventArgs e)
-        {
-            try
-            {
-                foreach (var link in this.PostBrowser.Document.Links.Cast<HtmlElement>())
-                {
-                    if (link.GetAttribute("href") == this._postBrowserStatusText)
-                    {
-                        var linkStr = link.GetAttribute("title");
-                        if (string.IsNullOrEmpty(linkStr))
-                            linkStr = link.GetAttribute("href");
-
-                        Clipboard.SetDataObject(linkStr, false, 5, 100);
-                        return;
-                    }
-                }
-
-                Clipboard.SetDataObject(this._postBrowserStatusText, false, 5, 100);
-            }
-            catch (Exception ex)
-            {
-                MessageBox.Show(ex.Message);
-            }
-        }
-
-        private void ContextMenuPostBrowser_Opening(object ender, CancelEventArgs e)
-        {
-            // URLコピーの項目の表示/非表示
-            if (PostBrowser.StatusText.StartsWith("http", StringComparison.Ordinal))
-            {
-                this._postBrowserStatusText = PostBrowser.StatusText;
-                string name = GetUserId();
-                UrlCopyContextMenuItem.Enabled = true;
-                if (name != null)
-                {
-                    FollowContextMenuItem.Enabled = true;
-                    RemoveContextMenuItem.Enabled = true;
-                    FriendshipContextMenuItem.Enabled = true;
-                    ShowUserStatusContextMenuItem.Enabled = true;
-                    SearchPostsDetailToolStripMenuItem.Enabled = true;
-                    IdFilterAddMenuItem.Enabled = true;
-                    ListManageUserContextToolStripMenuItem.Enabled = true;
-                    SearchAtPostsDetailToolStripMenuItem.Enabled = true;
-                }
-                else
-                {
-                    FollowContextMenuItem.Enabled = false;
-                    RemoveContextMenuItem.Enabled = false;
-                    FriendshipContextMenuItem.Enabled = false;
-                    ShowUserStatusContextMenuItem.Enabled = false;
-                    SearchPostsDetailToolStripMenuItem.Enabled = false;
-                    IdFilterAddMenuItem.Enabled = false;
-                    ListManageUserContextToolStripMenuItem.Enabled = false;
-                    SearchAtPostsDetailToolStripMenuItem.Enabled = false;
-                }
-
-                if (Regex.IsMatch(this._postBrowserStatusText, @"^https?://twitter.com/search\?q=%23"))
-                    UseHashtagMenuItem.Enabled = true;
-                else
-                    UseHashtagMenuItem.Enabled = false;
-            }
-            else
-            {
-                this._postBrowserStatusText = "";
-                UrlCopyContextMenuItem.Enabled = false;
-                FollowContextMenuItem.Enabled = false;
-                RemoveContextMenuItem.Enabled = false;
-                FriendshipContextMenuItem.Enabled = false;
-                ShowUserStatusContextMenuItem.Enabled = false;
-                SearchPostsDetailToolStripMenuItem.Enabled = false;
-                SearchAtPostsDetailToolStripMenuItem.Enabled = false;
-                UseHashtagMenuItem.Enabled = false;
-                IdFilterAddMenuItem.Enabled = false;
-                ListManageUserContextToolStripMenuItem.Enabled = false;
-            }
-            // 文字列選択されていないときは選択文字列関係の項目を非表示に
-            string _selText = this.PostBrowser.GetSelectedText();
-            if (_selText == null)
-            {
-                SelectionSearchContextMenuItem.Enabled = false;
-                SelectionCopyContextMenuItem.Enabled = false;
-                SelectionTranslationToolStripMenuItem.Enabled = false;
-            }
-            else
-            {
-                SelectionSearchContextMenuItem.Enabled = true;
-                SelectionCopyContextMenuItem.Enabled = true;
-                SelectionTranslationToolStripMenuItem.Enabled = true;
-            }
-            //発言内に自分以外のユーザーが含まれてればフォロー状態全表示を有効に
-            MatchCollection ma = Regex.Matches(this.PostBrowser.DocumentText, @"href=""https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)(/status(es)?/[0-9]+)?""");
-            bool fAllFlag = false;
-            foreach (Match mu in ma)
-            {
-                if (mu.Result("${ScreenName}").ToLowerInvariant() != tw.Username.ToLowerInvariant())
-                {
-                    fAllFlag = true;
-                    break;
-                }
-            }
-            this.FriendshipAllMenuItem.Enabled = fAllFlag;
-
-            if (_curPost == null)
-                TranslationToolStripMenuItem.Enabled = false;
-            else
-                TranslationToolStripMenuItem.Enabled = true;
-
-            e.Cancel = false;
-        }
-
-        private void CurrentTabToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            //発言詳細の選択文字列で現在のタブを検索
-            string _selText = this.PostBrowser.GetSelectedText();
-
-            if (_selText != null)
-            {
-                var searchOptions = new SearchWordDialog.SearchOptions(
-                    SearchWordDialog.SearchType.Timeline,
-                    _selText,
-                    newTab: false,
-                    caseSensitive: false,
-                    useRegex: false);
-
-                this.SearchDialog.ResultOptions = searchOptions;
-
-                this.DoTabSearch(
-                    searchOptions.Query,
-                    searchOptions.CaseSensitive,
-                    searchOptions.UseRegex,
-                    SEARCHTYPE.NextSearch);
-            }
-        }
-
         private void SplitContainer2_SplitterMoved(object sender, SplitterEventArgs e)
         {
             if (StatusText.Multiline) _mySpDis2 = StatusText.Height;
@@ -10639,13 +9617,13 @@ namespace OpenTween
             }
             else if (e.Data.GetDataPresent("UniformResourceLocatorW"))
             {
-                var url = GetUrlFromDataObject(e.Data);
+                var (url, title) = GetUrlFromDataObject(e.Data);
 
                 string appendText;
-                if (url.Item2 == null)
-                    appendText = url.Item1;
+                if (title == null)
+                    appendText = url;
                 else
-                    appendText = url.Item2 + " " + url.Item1;
+                    appendText = title + " " + url;
 
                 if (this.StatusText.TextLength == 0)
                     this.StatusText.Text = appendText;
@@ -10673,7 +9651,7 @@ namespace OpenTween
         /// </remarks>
         /// <exception cref="ArgumentException">不正なフォーマットが入力された場合</exception>
         /// <exception cref="NotSupportedException">サポートされていないデータが入力された場合</exception>
-        internal static Tuple<string, string> GetUrlFromDataObject(IDataObject data)
+        internal static (string Url, string Title) GetUrlFromDataObject(IDataObject data)
         {
             if (data.GetDataPresent("text/x-moz-url"))
             {
@@ -10686,7 +9664,7 @@ namespace OpenTween
                     if (lines.Length < 2)
                         throw new ArgumentException("不正な text/x-moz-url フォーマットです", nameof(data));
 
-                    return new Tuple<string, string>(lines[0], lines[1]);
+                    return (lines[0], lines[1]);
                 }
             }
             else if (data.GetDataPresent("IESiteModeToUrl"))
@@ -10700,7 +9678,7 @@ namespace OpenTween
                     if (lines.Length < 2)
                         throw new ArgumentException("不正な IESiteModeToUrl フォーマットです", nameof(data));
 
-                    return new Tuple<string, string>(lines[0], lines[1]);
+                    return (lines[0], lines[1]);
                 }
             }
             else if (data.GetDataPresent("UniformResourceLocatorW"))
@@ -10710,7 +9688,7 @@ namespace OpenTween
                 using (var stream = (MemoryStream)data.GetData("UniformResourceLocatorW"))
                 {
                     var url = Encoding.Unicode.GetString(stream.ToArray()).TrimEnd('\0');
-                    return new Tuple<string, string>(url, null);
+                    return (url, null);
                 }
             }
 
@@ -10786,8 +9764,8 @@ namespace OpenTween
 
             // ユーザープロフィールURL
             // フラグが立っている場合は設定と逆の動作をする
-            if( this._cfgCommon.OpenUserTimeline && !isReverseSettings ||
-                !this._cfgCommon.OpenUserTimeline && isReverseSettings )
+            if( SettingManager.Common.OpenUserTimeline && !isReverseSettings ||
+                !SettingManager.Common.OpenUserTimeline && isReverseSettings )
             {
                 var userUriMatch = Regex.Match(uriStr, "^https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)$");
                 if (userUriMatch.Success)
@@ -10828,7 +9806,7 @@ namespace OpenTween
 
                 try
                 {
-                    var configBrowserPath = this._cfgLocal.BrowserPath;
+                    var configBrowserPath = SettingManager.Local.BrowserPath;
                     if (!string.IsNullOrEmpty(configBrowserPath))
                     {
                         if (configBrowserPath.StartsWith("\"", StringComparison.Ordinal) && configBrowserPath.Length > 2 && configBrowserPath.IndexOf("\"", 2, StringComparison.Ordinal) > -1)
@@ -10868,6 +9846,7 @@ namespace OpenTween
 
             _curTab = _tab;
             _curList = (DetailsListView)_tab.Tag;
+
             if (_curList.SelectedIndices.Count > 0)
             {
                 _curItemIndex = _curList.SelectedIndices[0];
@@ -10971,24 +9950,12 @@ namespace OpenTween
 
             this.RefreshUserStreamsMenu();
 
-            if (this._cfgCommon.UserstreamStartup)
+            if (SettingManager.Common.UserstreamStartup)
                 tw.StartUserStream();
         }
 
-        private async void TweenMain_Shown(object sender, EventArgs e)
-        {
-            try
-            {
-                using (ControlTransaction.Update(this.PostBrowser))
-                {
-                    PostBrowser.Url = new Uri("about:blank");
-                    PostBrowser.DocumentText = "";       //発言詳細部初期化
-                }
-            }
-            catch (Exception)
-            {
-            }
-
+        private async void TweenMain_Shown(object sender, EventArgs e)
+        {
             NotifyIcon1.Visible = true;
 
             if (this.IsNetworkAvailable())
@@ -11009,10 +9976,10 @@ namespace OpenTween
                     this.GetListTimelineAllAsync(),
                 };
 
-                if (this._cfgCommon.StartupFollowers)
+                if (SettingManager.Common.StartupFollowers)
                     loadTasks.Add(this.RefreshFollowerIdsAsync());
 
-                if (this._cfgCommon.GetFav)
+                if (SettingManager.Common.GetFav)
                     loadTasks.Add(this.GetFavoritesAsync());
 
                 var allTasks = Task.WhenAll(loadTasks);
@@ -11036,7 +10003,7 @@ namespace OpenTween
                 if (ApplicationSettings.VersionInfoUrl != null)
                 {
                     //バージョンチェック(引数:起動時チェックの場合はtrue・・・チェック結果のメッセージを表示しない)
-                    if (this._cfgCommon.StartupVersion)
+                    if (SettingManager.Common.StartupVersion)
                         await this.CheckNewVersion(true);
                 }
                 else
@@ -11057,7 +10024,7 @@ namespace OpenTween
                 // 取得失敗の場合は再試行する
                 var reloadTasks = new List<Task>();
 
-                if (!tw.GetFollowersSuccess && this._cfgCommon.StartupFollowers)
+                if (!tw.GetFollowersSuccess && SettingManager.Common.StartupFollowers)
                     reloadTasks.Add(this.RefreshFollowerIdsAsync());
 
                 if (!tw.GetNoRetweetSuccess)
@@ -11095,9 +10062,11 @@ namespace OpenTween
             //公式RT
             if (this.ExistCurrentPost)
             {
-                if (_curPost.IsProtect)
+                if (!_curPost.CanRetweetBy(this.twitterApi.CurrentUserId))
                 {
-                    MessageBox.Show("Protected.");
+                    if (this._curPost.IsProtect)
+                        MessageBox.Show("Protected.");
+
                     _DoFavRetweetFlags = false;
                     return;
                 }
@@ -11121,12 +10090,7 @@ namespace OpenTween
                 }
                 else
                 {
-                    if (_curPost.IsDm || _curPost.IsMe)
-                    {
-                        _DoFavRetweetFlags = false;
-                        return;
-                    }
-                    if (!this._cfgCommon.RetweetNoConfirm)
+                    if (!SettingManager.Common.RetweetNoConfirm)
                     {
                         string Questiontext = Properties.Resources.RetweetQuestion1;
                         if (_DoFavRetweetFlags) Questiontext = Properties.Resources.FavoritesRetweetQuestionText2;
@@ -11142,7 +10106,7 @@ namespace OpenTween
                 foreach (int idx in _curList.SelectedIndices)
                 {
                     PostClass post = GetCurTabPost(idx);
-                    if (!post.IsMe && !post.IsProtect && !post.IsDm)
+                    if (post.CanRetweetBy(this.twitterApi.CurrentUserId))
                         statusIds.Add(post.StatusId);
                 }
 
@@ -11221,6 +10185,8 @@ namespace OpenTween
 
         private async void DumpPostClassToolStripMenuItem_Click(object sender, EventArgs e)
         {
+            this.tweetDetailsView.DumpPostClass = this.DumpPostClassToolStripMenuItem.Checked;
+
             if (_curPost != null)
                 await this.DispSelectedPost(true);
         }
@@ -11235,12 +10201,12 @@ namespace OpenTween
 
         private void ToolStripMenuItemUrlAutoShorten_CheckedChanged(object sender, EventArgs e)
         {
-            this._cfgCommon.UrlConvertAuto = ToolStripMenuItemUrlAutoShorten.Checked;
+            SettingManager.Common.UrlConvertAuto = ToolStripMenuItemUrlAutoShorten.Checked;
         }
 
         private void ContextMenuPostMode_Opening(object sender, CancelEventArgs e)
         {
-            ToolStripMenuItemUrlAutoShorten.Checked = this._cfgCommon.UrlConvertAuto;
+            ToolStripMenuItemUrlAutoShorten.Checked = SettingManager.Common.UrlConvertAuto;
         }
 
         private void TraceOutToolStripMenuItem_Click(object sender, EventArgs e)
@@ -11260,7 +10226,8 @@ namespace OpenTween
         private void TabRenameMenuItem_Click(object sender, EventArgs e)
         {
             if (string.IsNullOrEmpty(_rclickTabName)) return;
-            TabRename(ref _rclickTabName);
+
+            TabRename(_rclickTabName, out var _);
         }
 
         private async void BitlyToolStripMenuItem_Click(object sender, EventArgs e)
@@ -11314,7 +10281,7 @@ namespace OpenTween
             await this.FollowCommand(id);
         }
 
-        private async Task FollowCommand(string id)
+        internal async Task FollowCommand(string id)
         {
             using (var inputName = new InputTabName())
             {
@@ -11354,7 +10321,7 @@ namespace OpenTween
             await this.RemoveCommand(id, false);
         }
 
-        private async Task RemoveCommand(string id, bool skipInput)
+        internal async Task RemoveCommand(string id, bool skipInput)
         {
             if (!skipInput)
             {
@@ -11397,7 +10364,7 @@ namespace OpenTween
             await this.ShowFriendship(id);
         }
 
-        private async Task ShowFriendship(string id)
+        internal async Task ShowFriendship(string id)
         {
             using (var inputName = new InputTabName())
             {
@@ -11459,7 +10426,7 @@ namespace OpenTween
             MessageBox.Show(result);
         }
 
-        private async Task ShowFriendship(string[] ids)
+        internal async Task ShowFriendship(string[] ids)
         {
             foreach (string id in ids)
             {
@@ -11554,70 +10521,6 @@ namespace OpenTween
                 return !this.tw.Configuration.NonUsernamePaths.Contains(name.ToLowerInvariant());
         }
 
-        private string GetUserId()
-        {
-            Match m = Regex.Match(this._postBrowserStatusText, @"^https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)(/status(es)?/[0-9]+)?$");
-            if (m.Success && IsTwitterId(m.Result("${ScreenName}")))
-                return m.Result("${ScreenName}");
-            else
-                return null;
-        }
-
-        private async void FollowContextMenuItem_Click(object sender, EventArgs e)
-        {
-            string name = GetUserId();
-            if (name != null)
-                await this.FollowCommand(name);
-        }
-
-        private async void RemoveContextMenuItem_Click(object sender, EventArgs e)
-        {
-            string name = GetUserId();
-            if (name != null)
-                await this.RemoveCommand(name, false);
-        }
-
-        private async void FriendshipContextMenuItem_Click(object sender, EventArgs e)
-        {
-            string name = GetUserId();
-            if (name != null)
-                await this.ShowFriendship(name);
-        }
-
-        private async void FriendshipAllMenuItem_Click(object sender, EventArgs e)
-        {
-            MatchCollection ma = Regex.Matches(this.PostBrowser.DocumentText, @"href=""https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)(/status(es)?/[0-9]+)?""");
-            List<string> ids = new List<string>();
-            foreach (Match mu in ma)
-            {
-                if (mu.Result("${ScreenName}").ToLower() != tw.Username.ToLower())
-                {
-                    ids.Add(mu.Result("${ScreenName}"));
-                }
-            }
-
-            await this.ShowFriendship(ids.ToArray());
-        }
-
-        private async void ShowUserStatusContextMenuItem_Click(object sender, EventArgs e)
-        {
-            string name = GetUserId();
-            if (name != null)
-                await this.ShowUserStatus(name);
-        }
-
-        private void SearchPostsDetailToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            string name = GetUserId();
-            if (name != null) AddNewTabForUserTimeline(name);
-        }
-
-        private void SearchAtPostsDetailToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            string name = GetUserId();
-            if (name != null) AddNewTabForSearch("@" + name);
-        }
-
         private void IdeographicSpaceToSpaceToolStripMenuItem_Click(object sender, EventArgs e)
         {
             ModifySettingCommon = true;
@@ -11816,7 +10719,7 @@ namespace OpenTween
                         for (int i = 2; i <= 100; i++)
                         {
                             if (!_statuses.ContainsTab(renamed)) break;
-                            renamed = TabName + i.ToString();
+                            renamed = TabName + i;
                         }
                         tb.TabName = renamed;
 
@@ -11834,7 +10737,7 @@ namespace OpenTween
                     for (int i = 1; i < int.MaxValue; i++)
                     {
                         if (!_statuses.ContainsTab(renamed)) break;
-                        renamed = tb.TabName + "(" + i.ToString() + ")";
+                        renamed = tb.TabName + "(" + i + ")";
                     }
                     tb.TabName = renamed;
 
@@ -11874,91 +10777,16 @@ namespace OpenTween
             await this.doMoveToRTHome();
         }
 
-        private void IdFilterAddMenuItem_Click(object sender, EventArgs e)
+        private void ListManageUserContextToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            string name = GetUserId();
-            if (name != null)
-            {
-                string tabName;
-
-                //未選択なら処理終了
-                if (_curList.SelectedIndices.Count == 0) return;
-
-                //タブ選択(or追加)
-                if (!SelectTab(out tabName)) return;
-
-                var tab = (FilterTabModel)this._statuses.Tabs[tabName];
-
-                bool mv;
-                bool mk;
-                if (tab.TabType != MyCommon.TabUsageType.Mute)
-                {
-                    this.MoveOrCopy(out mv, out mk);
-                }
-                else
-                {
-                    // ミュートタブでは常に MoveMatches を true にする
-                    mv = true;
-                    mk = false;
-                }
-
-                PostFilterRule fc = new PostFilterRule();
-                fc.FilterName = name;
-                fc.UseNameField = true;
-                fc.MoveMatches = mv;
-                fc.MarkMatches = mk;
-                fc.UseRegex = false;
-                fc.FilterByUrl = false;
-                tab.AddFilter(fc);
-
-                this.ApplyPostFilters();
-                SaveConfigsTabs();
-            }
+            var screenName = this._curPost?.ScreenName;
+            if (screenName != null)
+                this.ListManageUserContext(screenName);
         }
 
-        private async void ListManageUserContextToolStripMenuItem_Click(object sender, EventArgs e)
+        public void ListManageUserContext(string screenName)
         {
-            string user;
-
-            ToolStripMenuItem menuItem = (ToolStripMenuItem)sender;
-
-            if (menuItem.Owner == this.ContextMenuPostBrowser)
-            {
-                user = GetUserId();
-                if (user == null) return;
-            }
-            else if (this._curPost != null)
-            {
-                user = this._curPost.ScreenName;
-            }
-            else
-            {
-                return;
-            }
-
-            if (TabInformations.GetInstance().SubscribableLists.Count == 0)
-            {
-                try
-                {
-                    using (var dialog = new WaitingDialog(Properties.Resources.ListsGetting))
-                    {
-                        var cancellationToken = dialog.EnableCancellation();
-
-                        var task = this.tw.GetListsApi();
-                        await dialog.WaitForAsync(this, task);
-
-                        cancellationToken.ThrowIfCancellationRequested();
-                    }
-                }
-                catch (OperationCanceledException) { return; }
-                catch (WebApiException ex)
-                {
-                    MessageBox.Show("Failed to get lists. (" + ex.Message + ")");
-                    return;
-                }
-            }
-
-            using (MyLists listSelectForm = new MyLists(user, this.tw))
+            using (var listSelectForm = new MyLists(screenName, this.twitterApi))
             {
                 listSelectForm.ShowDialog(this);
             }
@@ -11991,20 +10819,6 @@ namespace OpenTween
             }
         }
 
-        private void UseHashtagMenuItem_Click(object sender, EventArgs e)
-        {
-            Match m = Regex.Match(this._postBrowserStatusText, @"^https?://twitter.com/search\?q=%23(?<hash>.+)$");
-            if (m.Success)
-            {
-                HashMgr.SetPermanentHash("#" + Uri.UnescapeDataString(m.Result("${hash}")));
-                HashStripSplitButton.Text = HashMgr.UseHash;
-                HashToggleMenuItem.Checked = true;
-                HashToggleToolStripMenuItem.Checked = true;
-                //使用ハッシュタグとして設定
-                ModifySettingCommon = true;
-            }
-        }
-
         private void StatusLabel_DoubleClick(object sender, EventArgs e)
         {
             MessageBox.Show(StatusLabel.TextHistory, "Logs", MessageBoxButtons.OK, MessageBoxIcon.None);
@@ -12021,7 +10835,7 @@ namespace OpenTween
             {
                 return;
             }
-            this.TopMost = this._cfgCommon.AlwaysTop;
+            this.TopMost = SettingManager.Common.AlwaysTop;
             if (rslt == DialogResult.Cancel) return;
             if (!string.IsNullOrEmpty(HashMgr.UseHash))
             {
@@ -12077,6 +10891,16 @@ namespace OpenTween
             HashToggleMenuItem_Click(null, null);
         }
 
+        public void SetPermanentHashtag(string hashtag)
+        {
+            HashMgr.SetPermanentHash("#" + hashtag);
+            HashStripSplitButton.Text = HashMgr.UseHash;
+            HashToggleMenuItem.Checked = true;
+            HashToggleToolStripMenuItem.Checked = true;
+            //使用ハッシュタグとして設定
+            ModifySettingCommon = true;
+        }
+
         private void MenuItemOperate_DropDownOpening(object sender, EventArgs e)
         {
             if (ListTab.SelectedTab == null) return;
@@ -12133,32 +10957,21 @@ namespace OpenTween
                 this.OpenFavotterOpMenuItem.Enabled = true;
                 this.ShowRelatedStatusesMenuItem2.Enabled = true;  //PublicSearchの時問題出るかも
 
-                if (_curPost.IsMe)
+                if (!_curPost.CanRetweetBy(this.twitterApi.CurrentUserId))
                 {
-                    this.RtOpMenuItem.Enabled = false;  //公式RTは無効に
-                    this.RtUnOpMenuItem.Enabled = true;
-                    this.QtOpMenuItem.Enabled = true;
-                    this.FavoriteRetweetMenuItem.Enabled = false;  //公式RTは無効に
-                    this.FavoriteRetweetUnofficialMenuItem.Enabled = true;
+                    this.RtOpMenuItem.Enabled = false;
+                    this.RtUnOpMenuItem.Enabled = false;
+                    this.QtOpMenuItem.Enabled = false;
+                    this.FavoriteRetweetMenuItem.Enabled = false;
+                    this.FavoriteRetweetUnofficialMenuItem.Enabled = false;
                 }
                 else
                 {
-                    if (_curPost.IsProtect)
-                    {
-                        this.RtOpMenuItem.Enabled = false;
-                        this.RtUnOpMenuItem.Enabled = false;
-                        this.QtOpMenuItem.Enabled = false;
-                        this.FavoriteRetweetMenuItem.Enabled = false;
-                        this.FavoriteRetweetUnofficialMenuItem.Enabled = false;
-                    }
-                    else
-                    {
-                        this.RtOpMenuItem.Enabled = true;
-                        this.RtUnOpMenuItem.Enabled = true;
-                        this.QtOpMenuItem.Enabled = true;
-                        this.FavoriteRetweetMenuItem.Enabled = true;
-                        this.FavoriteRetweetUnofficialMenuItem.Enabled = true;
-                    }
+                    this.RtOpMenuItem.Enabled = true;
+                    this.RtUnOpMenuItem.Enabled = true;
+                    this.QtOpMenuItem.Enabled = true;
+                    this.FavoriteRetweetMenuItem.Enabled = true;
+                    this.FavoriteRetweetUnofficialMenuItem.Enabled = true;
                 }
             }
 
@@ -12337,79 +11150,16 @@ namespace OpenTween
             }
         }
 
-        private Task ShowUserStatus(string id, bool ShowInputDialog)
+        internal Task ShowUserStatus(string id, bool ShowInputDialog)
         {
             return this.doShowUserStatus(id, ShowInputDialog);
         }
 
-        private Task ShowUserStatus(string id)
+        internal Task ShowUserStatus(string id)
         {
             return this.doShowUserStatus(id, true);
         }
 
-        private async void FollowToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            if (NameLabel.Tag != null)
-            {
-                string id = (string)NameLabel.Tag;
-                if (id != tw.Username)
-                {
-                    await this.FollowCommand(id);
-                }
-            }
-        }
-
-        private async void UnFollowToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            if (NameLabel.Tag != null)
-            {
-                string id = (string)NameLabel.Tag;
-                if (id != tw.Username)
-                {
-                    await this.RemoveCommand(id, false);
-                }
-            }
-        }
-
-        private async void ShowFriendShipToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            if (NameLabel.Tag != null)
-            {
-                string id = (string)NameLabel.Tag;
-                if (id != tw.Username)
-                {
-                    await this.ShowFriendship(id);
-                }
-            }
-        }
-
-        private async void ShowUserStatusToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            if (NameLabel.Tag != null)
-            {
-                string id = (string)NameLabel.Tag;
-                await this.ShowUserStatus(id, false);
-            }
-        }
-
-        private void SearchPostsDetailNameToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            if (NameLabel.Tag != null)
-            {
-                string id = (string)NameLabel.Tag;
-                AddNewTabForUserTimeline(id);
-            }
-        }
-
-        private void SearchAtPostsDetailNameToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            if (NameLabel.Tag != null)
-            {
-                string id = (string)NameLabel.Tag;
-                AddNewTabForSearch("@" + id);
-            }
-        }
-
         private async void ShowProfileMenuItem_Click(object sender, EventArgs e)
         {
             if (_curPost != null)
@@ -12465,6 +11215,8 @@ namespace OpenTween
                 this.StatusText.Dock = DockStyle.Fill;
             }
 
+            this.tweetDetailsView.Owner = this;
+
             this.TimerTimeline.Elapsed += this.TimerTimeline_Elapsed;
             this._hookGlobalHotkey.HotkeyPressed += _hookGlobalHotkey_HotkeyPressed;
             this.gh.NotifyClicked += GrowlHelper_Callback;
@@ -12476,6 +11228,8 @@ namespace OpenTween
             this.ImageSelector.Enabled = false;
             this.ImageSelector.FilePickDialog = OpenFileDialog1;
 
+            this.workerProgress = new Progress<string>(x => this.StatusLabel.Text = x);
+
             this.ReplaceAppName();
             this.InitializeShortcuts();
         }
@@ -12497,24 +11251,6 @@ namespace OpenTween
             }
         }
 
-        private void UserPicture_MouseEnter(object sender, EventArgs e)
-        {
-            this.UserPicture.Cursor = Cursors.Hand;
-        }
-
-        private void UserPicture_MouseLeave(object sender, EventArgs e)
-        {
-            this.UserPicture.Cursor = Cursors.Default;
-        }
-
-        private async void UserPicture_DoubleClick(object sender, EventArgs e)
-        {
-            if (NameLabel.Tag != null)
-            {
-                await this.OpenUriInBrowserAsync(MyCommon.TwitterUrl + NameLabel.Tag.ToString());
-            }
-        }
-
         private void SplitContainer2_MouseDoubleClick(object sender, MouseEventArgs e)
         {
             this.MultiLineMenuItem.PerformClick();
@@ -12582,8 +11318,7 @@ namespace OpenTween
                 ModifySettingCommon = true;
                 SaveConfigsAll(true);
 
-                if (ImageSelector.ServiceName.Equals("Twitter"))
-                    this.StatusText_TextChanged(null, null);
+                this.StatusText_TextChanged(null, null);
             }
         }
 
@@ -12597,28 +11332,35 @@ namespace OpenTween
         /// </summary>
         private void ProcClipboardFromStatusTextWhenCtrlPlusV()
         {
-            if (Clipboard.ContainsText())
-            {
-                // clipboardにテキストがある場合は貼り付け処理
-                this.StatusText.Paste(Clipboard.GetText());
-            }
-            else if (Clipboard.ContainsImage())
+            try
             {
-                // 画像があるので投稿処理を行う
-                if (MessageBox.Show(Properties.Resources.PostPictureConfirm3,
-                                   Properties.Resources.PostPictureWarn4,
-                                   MessageBoxButtons.OKCancel,
-                                   MessageBoxIcon.Question,
-                                   MessageBoxDefaultButton.Button2)
-                               == DialogResult.OK)
+                if (Clipboard.ContainsText())
+                {
+                    // clipboardにテキストがある場合は貼り付け処理
+                    this.StatusText.Paste(Clipboard.GetText());
+                }
+                else if (Clipboard.ContainsImage())
                 {
-                    // clipboardから画像を取得
-                    using (var image = Clipboard.GetImage())
+                    // 画像があるので投稿処理を行う
+                    if (MessageBox.Show(Properties.Resources.PostPictureConfirm3,
+                                       Properties.Resources.PostPictureWarn4,
+                                       MessageBoxButtons.OKCancel,
+                                       MessageBoxIcon.Question,
+                                       MessageBoxDefaultButton.Button2)
+                                   == DialogResult.OK)
                     {
-                        this.ImageSelector.BeginSelection(image);
+                        // clipboardから画像を取得
+                        using (var image = Clipboard.GetImage())
+                        {
+                            this.ImageSelector.BeginSelection(image);
+                        }
                     }
                 }
             }
+            catch (ExternalException ex)
+            {
+                MessageBox.Show(ex.Message);
+            }
         }
 #endregion
 
@@ -12634,29 +11376,6 @@ namespace OpenTween
         public bool ModifySettingLocal { get; set; }
         public bool ModifySettingAtId { get; set; }
 
-        private async void SourceLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
-        {
-            var sourceUri = (Uri)this.SourceLinkLabel.Tag;
-            if (sourceUri != null && e.Button == MouseButtons.Left)
-            {
-                await this.OpenUriInBrowserAsync(sourceUri.AbsoluteUri);
-            }
-        }
-
-        private void SourceLinkLabel_MouseEnter(object sender, EventArgs e)
-        {
-            var sourceUri = (Uri)this.SourceLinkLabel.Tag;
-            if (sourceUri != null)
-            {
-                StatusLabelUrl.Text = MyCommon.ConvertToReadableUrl(sourceUri.AbsoluteUri);
-            }
-        }
-
-        private void SourceLinkLabel_MouseLeave(object sender, EventArgs e)
-        {
-            SetStatusLabelUrl();
-        }
-
         private void MenuItemCommand_DropDownOpening(object sender, EventArgs e)
         {
             if (this.ExistCurrentPost && !_curPost.IsDm)
@@ -12750,9 +11469,10 @@ namespace OpenTween
             this._statuses.AddTab(tabRelated);
             this.AddNewTab(tabRelated, startup: false);
 
+            TabPage tabPage;
             for (int i = 0; i < this.ListTab.TabPages.Count; i++)
             {
-                var tabPage = this.ListTab.TabPages[i];
+                tabPage = this.ListTab.TabPages[i];
                 if (tabName == tabPage.Text)
                 {
                     this.ListTab.SelectedIndex = i;
@@ -12761,6 +11481,24 @@ namespace OpenTween
             }
 
             await this.GetRelatedTweetsAsync(tabRelated);
+
+            tabPage = this.ListTab.TabPages.Cast<TabPage>()
+                .FirstOrDefault(x => x.Text == tabRelated.TabName);
+
+            if (tabPage != null)
+            {
+                // TODO: 非同期更新中にタブが閉じられている場合を厳密に考慮したい
+
+                var listView = (DetailsListView)tabPage.Tag;
+                var targetPost = tabRelated.TargetPost;
+                var index = tabRelated.IndexOf(targetPost.RetweetedId ?? targetPost.StatusId);
+
+                if (index != -1 && index < listView.Items.Count)
+                {
+                    listView.SelectedIndices.Add(index);
+                    listView.Items[index].Focused = true;
+                }
+            }
         }
 
         private void CacheInfoMenuItem_Click(object sender, EventArgs e)
@@ -12779,23 +11517,23 @@ namespace OpenTween
         }
 
 #region "Userstream"
-        private void tw_PostDeleted(object sender, PostDeletedEventArgs e)
+        private async void tw_PostDeleted(object sender, PostDeletedEventArgs e)
         {
             try
             {
                 if (InvokeRequired && !IsDisposed)
                 {
-                    Invoke((Action) (async () =>
-                           {
-                               this._statuses.RemovePostFromAllTabs(e.StatusId, setIsDeleted: true);
-                               if (_curTab != null && _statuses.Tabs[_curTab.Text].Contains(e.StatusId))
-                               {
-                                   this.PurgeListViewItemCache();
-                                   ((DetailsListView)_curTab.Tag).Update();
-                                   if (_curPost != null && _curPost.StatusId == e.StatusId)
-                                       await this.DispSelectedPost(true);
-                               }
-                           }));
+                    await this.InvokeAsync(async () =>
+                    {
+                        this._statuses.RemovePostFromAllTabs(e.StatusId, setIsDeleted: true);
+                        if (_curTab != null && _statuses.Tabs[_curTab.Text].Contains(e.StatusId))
+                        {
+                            this.PurgeListViewItemCache();
+                            ((DetailsListView)_curTab.Tag).Update();
+                            if (_curPost != null && _curPost.StatusId == e.StatusId)
+                                await this.DispSelectedPost(true);
+                        }
+                    });
                     return;
                 }
             }
@@ -12813,14 +11551,14 @@ namespace OpenTween
 
         private async void tw_NewPostFromStream(object sender, EventArgs e)
         {
-            if (this._cfgCommon.ReadOldPosts)
+            if (SettingManager.Common.ReadOldPosts)
             {
                 _statuses.SetReadHomeTab(); //新着時未読クリア
             }
 
-            int rsltAddCount = _statuses.DistributePosts();
+            this._statuses.DistributePosts();
 
-            if (this._cfgCommon.UserstreamPeriod > 0) return;
+            if (SettingManager.Common.UserstreamPeriod > 0) return;
 
             // userStreamsRefreshing が 0 (インクリメント後は1) であれば RefreshTimeline を実行
             if (Interlocked.Increment(ref this.userStreamsRefreshing) == 1)
@@ -12837,13 +11575,13 @@ namespace OpenTween
             }
         }
 
-        private void tw_UserStreamStarted(object sender, EventArgs e)
+        private async void tw_UserStreamStarted(object sender, EventArgs e)
         {
             try
             {
                 if (InvokeRequired && !IsDisposed)
                 {
-                    Invoke((Action)(() => this.tw_UserStreamStarted(sender, e)));
+                    await this.InvokeAsync(() => this.tw_UserStreamStarted(sender, e));
                     return;
                 }
             }
@@ -12862,13 +11600,13 @@ namespace OpenTween
             StatusLabel.Text = "UserStream Started.";
         }
 
-        private void tw_UserStreamStopped(object sender, EventArgs e)
+        private async void tw_UserStreamStopped(object sender, EventArgs e)
         {
             try
             {
                 if (InvokeRequired && !IsDisposed)
                 {
-                    Invoke((Action)(() => this.tw_UserStreamStopped(sender, e)));
+                    await this.InvokeAsync(() => this.tw_UserStreamStopped(sender, e));
                     return;
                 }
             }
@@ -12901,13 +11639,13 @@ namespace OpenTween
             }
         }
 
-        private void tw_UserStreamEventArrived(object sender, UserStreamEventReceivedEventArgs e)
+        private async void tw_UserStreamEventArrived(object sender, UserStreamEventReceivedEventArgs e)
         {
             try
             {
                 if (InvokeRequired && !IsDisposed)
                 {
-                    Invoke((Action)(() => this.tw_UserStreamEventArrived(sender, e)));
+                    await this.InvokeAsync(() => this.tw_UserStreamEventArrived(sender, e));
                     return;
                 }
             }
@@ -12950,7 +11688,7 @@ namespace OpenTween
                 //if (SettingDialog.DispUsername) NotifyIcon1.BalloonTipTitle = tw.Username + " - "; else NotifyIcon1.BalloonTipTitle = "";
                 //NotifyIcon1.BalloonTipTitle += Application.ProductName + " [" + ev.Event.ToUpper() + "] by " + ((string)(!string.IsNullOrEmpty(ev.Username) ? ev.Username : ""), string);
                 StringBuilder title = new StringBuilder();
-                if (this._cfgCommon.DispUsername)
+                if (SettingManager.Common.DispUsername)
                 {
                     title.Append(tw.Username);
                     title.Append(" - ");
@@ -12965,7 +11703,7 @@ namespace OpenTween
                 title.Append("] by ");
                 if (!string.IsNullOrEmpty(ev.Username))
                 {
-                    title.Append(ev.Username.ToString());
+                    title.Append(ev.Username);
                 }
                 else
                 {
@@ -12983,7 +11721,7 @@ namespace OpenTween
                     text = " ";
                 }
                 //NotifyIcon1.ShowBalloonTip(500);
-                if (this._cfgCommon.IsUseNotifyGrowl)
+                if (SettingManager.Common.IsUseNotifyGrowl)
                 {
                     gh.Notify(GrowlHelper.NotifyType.UserStreamEvent,
                               ev.Id.ToString(), title.ToString(), text);
@@ -12998,10 +11736,10 @@ namespace OpenTween
             }
 
             //サウンド再生
-            string snd = this._cfgCommon.EventSoundFile;
-            if (!_initial && this._cfgCommon.PlaySound && !string.IsNullOrEmpty(snd))
+            string snd = SettingManager.Common.EventSoundFile;
+            if (!_initial && SettingManager.Common.PlaySound && !string.IsNullOrEmpty(snd))
             {
-                if ((ev.Eventtype & this._cfgCommon.EventNotifyFlag) != 0 && IsMyEventNotityAsEventType(ev))
+                if ((ev.Eventtype & SettingManager.Common.EventNotifyFlag) != 0 && IsMyEventNotityAsEventType(ev))
                 {
                     try
                     {
@@ -13103,7 +11841,7 @@ namespace OpenTween
             {
                 evtDialog.Activate();
             }
-            this.TopMost = this._cfgCommon.AlwaysTop;
+            this.TopMost = SettingManager.Common.AlwaysTop;
         }
 #endregion
 
@@ -13132,44 +11870,6 @@ namespace OpenTween
             await this.OpenUriInBrowserAsync(MyCommon.TwitterUrl + tw.Username);
         }
 
-        private async Task doTranslation(string str)
-        {
-            if (string.IsNullOrEmpty(str))
-                return;
-
-            var bing = new Bing();
-            try
-            {
-                var translatedText = await bing.TranslateAsync(str,
-                    langFrom: null,
-                    langTo: this._cfgCommon.TranslateLanguage);
-
-                this.PostBrowser.DocumentText = this.createDetailHtml(translatedText);
-            }
-            catch (HttpRequestException e)
-            {
-                this.StatusLabel.Text = "Err:" + e.Message;
-            }
-            catch (OperationCanceledException)
-            {
-                this.StatusLabel.Text = "Err:Timeout";
-            }
-        }
-
-        private async void TranslationToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            if (!this.ExistCurrentPost)
-                return;
-
-            await this.doTranslation(this._curPost.TextFromApi);
-        }
-
-        private async void SelectionTranslationToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            var text = this.PostBrowser.GetSelectedText();
-            await this.doTranslation(text);
-        }
-
         private bool ExistCurrentPost
         {
             get
@@ -13250,13 +11950,13 @@ namespace OpenTween
 
         private async Task OpenUserAppointUrl()
         {
-            if (this._cfgCommon.UserAppointUrl != null)
+            if (SettingManager.Common.UserAppointUrl != null)
             {
-                if (this._cfgCommon.UserAppointUrl.Contains("{ID}") || this._cfgCommon.UserAppointUrl.Contains("{STATUS}"))
+                if (SettingManager.Common.UserAppointUrl.Contains("{ID}") || SettingManager.Common.UserAppointUrl.Contains("{STATUS}"))
                 {
                     if (_curPost != null)
                     {
-                        string xUrl = this._cfgCommon.UserAppointUrl;
+                        string xUrl = SettingManager.Common.UserAppointUrl;
                         xUrl = xUrl.Replace("{ID}", _curPost.ScreenName);
 
                         var statusId = _curPost.RetweetedId ?? _curPost.StatusId;
@@ -13267,7 +11967,7 @@ namespace OpenTween
                 }
                 else
                 {
-                    await this.OpenUriInBrowserAsync(this._cfgCommon.UserAppointUrl);
+                    await this.OpenUriInBrowserAsync(SettingManager.Common.UserAppointUrl);
                 }
             }
         }
@@ -13277,51 +11977,11 @@ namespace OpenTween
             await this.OpenUserAppointUrl();
         }
 
-        private void SourceCopyMenuItem_Click(object sender, EventArgs e)
-        {
-            string selText = SourceLinkLabel.Text;
-            try
-            {
-                Clipboard.SetDataObject(selText, false, 5, 100);
-            }
-            catch (Exception ex)
-            {
-                MessageBox.Show(ex.Message);
-            }
-        }
-
-        private void SourceUrlCopyMenuItem_Click(object sender, EventArgs e)
-        {
-            var sourceUri = (Uri)this.SourceLinkLabel.Tag;
-            try
-            {
-                Clipboard.SetDataObject(sourceUri.AbsoluteUri, false, 5, 100);
-            }
-            catch (Exception ex)
-            {
-                MessageBox.Show(ex.Message);
-            }
-        }
-
-        private void ContextMenuSource_Opening(object sender, CancelEventArgs e)
-        {
-            if (_curPost == null || !ExistCurrentPost || _curPost.IsDm)
-            {
-                SourceCopyMenuItem.Enabled = false;
-                SourceUrlCopyMenuItem.Enabled = false;
-            }
-            else
-            {
-                SourceCopyMenuItem.Enabled = true;
-                SourceUrlCopyMenuItem.Enabled = true;
-            }
-        }
-
-        private void GrowlHelper_Callback(object sender, GrowlHelper.NotifyCallbackEventArgs e)
+        private async void GrowlHelper_Callback(object sender, GrowlHelper.NotifyCallbackEventArgs e)
         {
             if (Form.ActiveForm == null)
             {
-                this.BeginInvoke((Action) (() =>
+                await this.InvokeAsync(() =>
                 {
                     this.Visible = true;
                     if (this.WindowState == FormWindowState.Minimized) this.WindowState = FormWindowState.Normal;
@@ -13335,7 +11995,7 @@ namespace OpenTween
                     {
                         if (!this.GoStatus(e.StatusId)) this.StatusText.Focus();
                     }
-                }));
+                });
             }
         }
 
@@ -13384,13 +12044,13 @@ namespace OpenTween
 
         private void ContextMenuColumnHeader_Opening(object sender, CancelEventArgs e)
         {
-            this.IconSizeNoneToolStripMenuItem.Checked = this._cfgCommon.IconSize == MyCommon.IconSizes.IconNone;
-            this.IconSize16ToolStripMenuItem.Checked = this._cfgCommon.IconSize == MyCommon.IconSizes.Icon16;
-            this.IconSize24ToolStripMenuItem.Checked = this._cfgCommon.IconSize == MyCommon.IconSizes.Icon24;
-            this.IconSize48ToolStripMenuItem.Checked = this._cfgCommon.IconSize == MyCommon.IconSizes.Icon48;
-            this.IconSize48_2ToolStripMenuItem.Checked = this._cfgCommon.IconSize == MyCommon.IconSizes.Icon48_2;
+            this.IconSizeNoneToolStripMenuItem.Checked = SettingManager.Common.IconSize == MyCommon.IconSizes.IconNone;
+            this.IconSize16ToolStripMenuItem.Checked = SettingManager.Common.IconSize == MyCommon.IconSizes.Icon16;
+            this.IconSize24ToolStripMenuItem.Checked = SettingManager.Common.IconSize == MyCommon.IconSizes.Icon24;
+            this.IconSize48ToolStripMenuItem.Checked = SettingManager.Common.IconSize == MyCommon.IconSizes.Icon48;
+            this.IconSize48_2ToolStripMenuItem.Checked = SettingManager.Common.IconSize == MyCommon.IconSizes.Icon48_2;
 
-            this.LockListSortOrderToolStripMenuItem.Checked = this._cfgCommon.SortOrderLock;
+            this.LockListSortOrderToolStripMenuItem.Checked = SettingManager.Common.SortOrderLock;
         }
 
         private void IconSizeNoneToolStripMenuItem_Click(object sender, EventArgs e)
@@ -13420,11 +12080,11 @@ namespace OpenTween
 
         private void ChangeListViewIconSize(MyCommon.IconSizes iconSize)
         {
-            if (this._cfgCommon.IconSize == iconSize) return;
+            if (SettingManager.Common.IconSize == iconSize) return;
 
             var oldIconCol = _iconCol;
 
-            this._cfgCommon.IconSize = iconSize;
+            SettingManager.Common.IconSize = iconSize;
             ApplyListViewIconSize(iconSize);
 
             if (_iconCol != oldIconCol)
@@ -13443,11 +12103,23 @@ namespace OpenTween
         private void LockListSortToolStripMenuItem_Click(object sender, EventArgs e)
         {
             var state = this.LockListSortOrderToolStripMenuItem.Checked;
-            if (this._cfgCommon.SortOrderLock == state) return;
+            if (SettingManager.Common.SortOrderLock == state) return;
 
-            this._cfgCommon.SortOrderLock = state;
+            SettingManager.Common.SortOrderLock = state;
 
             ModifySettingCommon = true;
         }
+
+        private void tweetDetailsView_StatusChanged(object sender, TweetDetailsViewStatusChengedEventArgs e)
+        {
+            if (!string.IsNullOrEmpty(e.StatusText))
+            {
+                this.StatusLabelUrl.Text = e.StatusText;
+            }
+            else
+            {
+                this.SetStatusLabelUrl();
+            }
+        }
     }
 }