OSDN Git Service

TabInformations.MuteTabプロパティを追加しTabsからミュートタブを除外
[opentween/open-tween.git] / OpenTween / Tween.cs
index 0579ecd..860a2af 100644 (file)
@@ -250,8 +250,6 @@ namespace OpenTween
             }
         }
 
-        private int _curItemIndex;
-        private PostClass _curPost;
         private bool _isColumnChanged = false;
 
         private const int MAX_WORKER_THREADS = 20;
@@ -291,9 +289,9 @@ namespace OpenTween
         {
             public long OriginalId;
             public long InReplyToId;
-            public TabPage OriginalTab;
+            public TabModel OriginalTab;
 
-            public ReplyChain(long originalId, long inReplyToId, TabPage originalTab)
+            public ReplyChain(long originalId, long inReplyToId, TabModel originalTab)
             {
                 this.OriginalId = originalId;
                 this.InReplyToId = inReplyToId;
@@ -302,7 +300,7 @@ namespace OpenTween
         }
 
         private Stack<ReplyChain> replyChains; //[, ]でのリプライ移動の履歴
-        private Stack<(TabPage, PostClass)> selectPostChains = new Stack<(TabPage, PostClass)>(); //ポスト選択履歴
+        private Stack<(TabModel, PostClass)> selectPostChains = new Stack<(TabModel, PostClass)>(); //ポスト選択履歴
 
         public TabModel CurrentTab
             => this._statuses.SelectedTab;
@@ -316,6 +314,9 @@ namespace OpenTween
         public DetailsListView CurrentListView
             => (DetailsListView)this.CurrentTabPage.Tag;
 
+        public PostClass CurrentPost
+            => this.CurrentTab.SelectedPost;
+
         //検索処理タイプ
         internal enum SEARCHTYPE
         {
@@ -1056,21 +1057,16 @@ namespace OpenTween
             if (this._statuses.GetTabByType<FavoritesTabModel>() == null)
                 this._statuses.AddTab(new FavoritesTabModel());
 
-            if (this._statuses.GetTabByType<MuteTabModel>() == null)
+            if (this._statuses.MuteTab == null)
                 this._statuses.AddTab(new MuteTabModel());
 
-            foreach (var tab in _statuses.Tabs.Values)
+            foreach (var tab in _statuses.Tabs)
             {
-                // ミュートタブは表示しない
-                if (tab.TabType == MyCommon.TabUsageType.Mute)
-                    continue;
-
                 if (!AddNewTab(tab, startup: true))
                     throw new TabException(Properties.Resources.TweenMain_LoadText1);
             }
 
             this._statuses.SelectTab(this.ListTab.SelectedTab.Text);
-            _curItemIndex = -1;
 
             MyCommon.TwitterApiInfo.AccessLimitUpdated += TwitterApiStatus_AccessLimitUpdated;
             Microsoft.Win32.SystemEvents.TimeChanged += SystemEvents_TimeChanged;
@@ -1595,21 +1591,12 @@ namespace OpenTween
 
             return new ListViewSelection
             {
-                SelectedStatusIds = this.GetSelectedStatusIds(listView, tab),
+                SelectedStatusIds = tab.SelectedStatusIds,
                 FocusedStatusId = this.GetFocusedStatusId(listView, tab),
                 SelectionMarkStatusId = this.GetSelectionMarkStatusId(listView, tab),
             };
         }
 
-        private long[] GetSelectedStatusIds(DetailsListView listView, TabModel tab)
-        {
-            var selectedIndices = listView.SelectedIndices;
-            if (selectedIndices.Count > 0 && selectedIndices.Count < 61)
-                return tab.GetStatusIdAt(selectedIndices.Cast<int>());
-            else
-                return null;
-        }
-
         private long? GetFocusedStatusId(DetailsListView listView, TabModel tab)
         {
             var index = listView.FocusedItem?.Index ?? -1;
@@ -1932,25 +1919,24 @@ namespace OpenTween
         private void MyList_SelectedIndexChanged(object sender, EventArgs e)
         {
             var listView = this.CurrentListView;
-            if (!listView.Equals(sender) || listView.SelectedIndices.Count != 1) return;
+            if (listView != sender)
+                return;
 
-            _curItemIndex = listView.SelectedIndices[0];
-            if (_curItemIndex > listView.VirtualListSize - 1) return;
+            var indices = listView.SelectedIndices.Cast<int>().ToArray();
+            this.CurrentTab.SelectPosts(indices);
 
-            try
-            {
-                this._curPost = GetCurTabPost(_curItemIndex);
-            }
-            catch (ArgumentException)
-            {
+            if (listView.SelectedIndices.Count != 1)
                 return;
-            }
+
+            var index = listView.SelectedIndices[0];
+            if (index > listView.VirtualListSize - 1) return;
 
             this.PushSelectPostChain();
 
-            this._statuses.SetReadAllTab(_curPost.StatusId, read: true);
+            var post = this.CurrentPost;
+            this._statuses.SetReadAllTab(post.StatusId, read: true);
             //キャッシュの書き換え
-            ChangeCacheStyleRead(true, _curItemIndex);   //既読へ(フォント、文字色)
+            ChangeCacheStyleRead(true, index); // 既読へ(フォント、文字色)
 
             ColorizeList();
             _colorize = true;
@@ -2027,7 +2013,7 @@ namespace OpenTween
             if (_anchorFlag)
                 _post = _anchorPost;
             else
-                _post = _curPost;
+                _post = this.CurrentPost;
 
             if (_post == null) return;
 
@@ -2052,7 +2038,7 @@ namespace OpenTween
             if (_anchorFlag)
                 _post = _anchorPost;
             else
-                _post = _curPost;
+                _post = this.CurrentPost;
 
             PostClass tPost = GetCurTabPost(Index);
 
@@ -2133,7 +2119,8 @@ namespace OpenTween
                 }
             }
 
-            if (this.ExistCurrentPost && StatusText.Text.Trim() == string.Format("RT @{0}: {1}", _curPost.ScreenName, _curPost.TextFromApi))
+            var currentPost = this.CurrentPost;
+            if (this.ExistCurrentPost && StatusText.Text.Trim() == string.Format("RT @{0}: {1}", currentPost.ScreenName, currentPost.TextFromApi))
             {
                 DialogResult rtResult = MessageBox.Show(string.Format(Properties.Resources.PostButton_Click1, Environment.NewLine),
                                                                "Retweet",
@@ -2487,7 +2474,8 @@ namespace OpenTween
                         this.ChangeCacheStyleRead(post.IsRead, idx);
                 }
 
-                if (statusId == this._curPost.StatusId)
+                var currentPost = this.CurrentPost;
+                if (currentPost != null && statusId == currentPost.StatusId)
                     await this.DispSelectedPost(true); // 選択アイテム再表示
             }
         }
@@ -2601,7 +2589,8 @@ namespace OpenTween
                         }
                     }
 
-                    if (successIds.Contains(this._curPost.StatusId))
+                    var currentPost = this.CurrentPost;
+                    if (currentPost != null && successIds.Contains(currentPost.StatusId))
                         await this.DispSelectedPost(true); // 選択アイテム再表示
                 }
             }
@@ -2967,8 +2956,9 @@ namespace OpenTween
                     await this.FavoriteChange(true);
                     break;
                 case 2:
-                    if (_curPost != null)
-                        await this.ShowUserStatus(_curPost.ScreenName, false);
+                    var post = this.CurrentPost;
+                    if (post != null)
+                        await this.ShowUserStatus(post.ScreenName, false);
                     break;
                 case 3:
                     await ShowUserTimeline();
@@ -3004,13 +2994,13 @@ namespace OpenTween
         private async Task FavoriteChange(bool FavAdd, bool multiFavoriteChangeDialogEnable = true)
         {
             var tab = this.CurrentTab;
-            var listView = this.CurrentListView;
+            var posts = tab.SelectedPosts;
 
             //trueでFavAdd,falseでFavRemove
-            if (tab.TabType == MyCommon.TabUsageType.DirectMessage || listView.SelectedIndices.Count == 0
+            if (tab.TabType == MyCommon.TabUsageType.DirectMessage || posts.Length == 0
                 || !this.ExistCurrentPost) return;
 
-            if (listView.SelectedIndices.Count > 1)
+            if (posts.Length > 1)
             {
                 if (FavAdd)
                 {
@@ -3036,7 +3026,7 @@ namespace OpenTween
 
             if (FavAdd)
             {
-                var selectedPost = this.GetCurTabPost(listView.SelectedIndices[0]);
+                var selectedPost = posts.Single();
                 if (selectedPost.IsFav)
                 {
                     this.StatusLabel.Text = Properties.Resources.FavAddToolStripMenuItem_ClickText4;
@@ -3047,10 +3037,7 @@ namespace OpenTween
             }
             else
             {
-                var selectedPosts = listView.SelectedIndices.Cast<int>()
-                    .Select(x => this.GetCurTabPost(x))
-                    .Where(x => x.IsFav);
-
+                var selectedPosts = posts.Where(x => x.IsFav);
                 var statusIds = selectedPosts.Select(x => x.StatusId).ToArray();
                 if (statusIds.Length == 0)
                 {
@@ -3076,18 +3063,18 @@ namespace OpenTween
 
         private async void MoveToHomeToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            var listView = this.CurrentListView;
-            if (listView.SelectedIndices.Count > 0)
-                await this.OpenUriInBrowserAsync(MyCommon.TwitterUrl + GetCurTabPost(listView.SelectedIndices[0]).ScreenName);
-            else if (listView.SelectedIndices.Count == 0)
+            var post = this.CurrentPost;
+            if (post != null)
+                await this.OpenUriInBrowserAsync(MyCommon.TwitterUrl + post.ScreenName);
+            else
                 await this.OpenUriInBrowserAsync(MyCommon.TwitterUrl);
         }
 
         private async void MoveToFavToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            var listView = this.CurrentListView;
-            if (listView.SelectedIndices.Count > 0)
-                await this.OpenUriInBrowserAsync(MyCommon.TwitterUrl + "#!/" + GetCurTabPost(listView.SelectedIndices[0]).ScreenName + "/favorites");
+            var post = this.CurrentPost;
+            if (post != null)
+                await this.OpenUriInBrowserAsync(MyCommon.TwitterUrl + "#!/" + post.ScreenName + "/favorites");
         }
 
         private void TweenMain_ClientSizeChanged(object sender, EventArgs e)
@@ -3207,9 +3194,10 @@ namespace OpenTween
             this.PurgeListViewItemCache();
 
             var tab = this.CurrentTab;
-            if (tab.AllCount > 0 && this._curPost != null)
+            var post = this.CurrentPost;
+            if (tab.AllCount > 0 && post != null)
             {
-                var idx = tab.IndexOf(this._curPost.StatusId);
+                var idx = tab.IndexOf(post.StatusId);
                 if (idx > -1)
                 {
                     this.SelectListItem(list, idx);
@@ -3263,7 +3251,8 @@ namespace OpenTween
                 UnreadStripMenuItem.Enabled = true;
             }
             var tab = this.CurrentTab;
-            if (tab.TabType == MyCommon.TabUsageType.DirectMessage || !this.ExistCurrentPost || _curPost.IsDm)
+            var post = this.CurrentPost;
+            if (tab.TabType == MyCommon.TabUsageType.DirectMessage || !this.ExistCurrentPost || post.IsDm)
             {
                 FavAddToolStripMenuItem.Enabled = false;
                 FavRemoveToolStripMenuItem.Enabled = false;
@@ -3283,7 +3272,7 @@ namespace OpenTween
                 StatusOpenMenuItem.Enabled = true;
                 ShowRelatedStatusesMenuItem.Enabled = true;  //PublicSearchの時問題出るかも
 
-                if (!_curPost.CanRetweetBy(this.twitterApi.CurrentUserId))
+                if (!post.CanRetweetBy(this.twitterApi.CurrentUserId))
                 {
                     ReTweetStripMenuItem.Enabled = false;
                     ReTweetUnofficialStripMenuItem.Enabled = false;
@@ -3308,8 +3297,7 @@ namespace OpenTween
             //{
             //    RefreshMoreStripMenuItem.Enabled = false;
             //}
-            if (!this.ExistCurrentPost
-                || _curPost.InReplyToStatusId == null)
+            if (!this.ExistCurrentPost || post.InReplyToStatusId == null)
             {
                 RepliedStatusOpenMenuItem.Enabled = false;
             }
@@ -3317,7 +3305,7 @@ namespace OpenTween
             {
                 RepliedStatusOpenMenuItem.Enabled = true;
             }
-            if (!this.ExistCurrentPost || string.IsNullOrEmpty(_curPost.RetweetedBy))
+            if (!this.ExistCurrentPost || string.IsNullOrEmpty(post.RetweetedBy))
             {
                 MoveToRTHomeMenuItem.Enabled = false;
             }
@@ -3328,8 +3316,8 @@ namespace OpenTween
 
             if (this.ExistCurrentPost)
             {
-                this.DeleteStripMenuItem.Enabled = this._curPost.CanDeleteBy(this.tw.UserId);
-                if (this._curPost.RetweetedByUserId == this.tw.UserId)
+                this.DeleteStripMenuItem.Enabled = post.CanDeleteBy(this.tw.UserId);
+                if (post.RetweetedByUserId == this.tw.UserId)
                     this.DeleteStripMenuItem.Text = Properties.Resources.DeleteMenuText2;
                 else
                     this.DeleteStripMenuItem.Text = Properties.Resources.DeleteMenuText1;
@@ -3344,15 +3332,10 @@ namespace OpenTween
 
         private async Task doStatusDelete()
         {
-            var currentListView = this.CurrentListView;
-
-            if (currentListView.SelectedIndices.Count == 0)
+            var posts = this.CurrentTab.SelectedPosts;
+            if (posts.Length == 0)
                 return;
 
-            var posts = currentListView.SelectedIndices.Cast<int>()
-                .Select(x => this.GetCurTabPost(x))
-                .ToArray();
-
             // 選択されたツイートの中に削除可能なものが一つでもあるか
             if (!posts.Any(x => x.CanDeleteBy(this.tw.UserId)))
                 return;
@@ -3365,6 +3348,7 @@ namespace OpenTween
             if (ret != DialogResult.OK)
                 return;
 
+            var currentListView = this.CurrentListView;
             var focusedIndex = currentListView.FocusedItem?.Index ?? currentListView.TopItem?.Index ?? 0;
 
             using (ControlTransaction.Cursor(this, Cursors.WaitCursor))
@@ -3423,8 +3407,6 @@ namespace OpenTween
                     this.StatusLabel.Text = Properties.Resources.DeleteStripMenuItem_ClickText3; // 失敗
 
                 this.PurgeListViewItemCache();
-                this._curPost = null;
-                this._curItemIndex = -1;
 
                 foreach (var tabPage in this.ListTab.TabPages.Cast<TabPage>())
                 {
@@ -3435,7 +3417,7 @@ namespace OpenTween
                     {
                         listView.VirtualListSize = tab.AllCount;
 
-                        if (tabPage == this.CurrentTabPage)
+                        if (tab.TabName == this.CurrentTabName)
                         {
                             listView.SelectedIndices.Clear();
 
@@ -3471,14 +3453,13 @@ namespace OpenTween
 
         private void ReadedStripMenuItem_Click(object sender, EventArgs e)
         {
-            var listView = this.CurrentListView;
-            using (ControlTransaction.Update(listView))
+            using (ControlTransaction.Update(this.CurrentListView))
             {
                 var tab = this.CurrentTab;
-                foreach (int idx in listView.SelectedIndices)
+                foreach (var statusId in tab.SelectedStatusIds)
                 {
-                    var post = tab[idx];
-                    this._statuses.SetReadAllTab(post.StatusId, read: true);
+                    this._statuses.SetReadAllTab(statusId, read: true);
+                    var idx = tab.IndexOf(statusId);
                     ChangeCacheStyleRead(true, idx);
                 }
                 ColorizeList();
@@ -3498,14 +3479,13 @@ namespace OpenTween
 
         private void UnreadStripMenuItem_Click(object sender, EventArgs e)
         {
-            var listView = this.CurrentListView;
-            using (ControlTransaction.Update(listView))
+            using (ControlTransaction.Update(this.CurrentListView))
             {
                 var tab = this.CurrentTab;
-                foreach (int idx in listView.SelectedIndices)
+                foreach (var statusId in tab.SelectedStatusIds)
                 {
-                    var post = tab[idx];
-                    this._statuses.SetReadAllTab(post.StatusId, read: false);
+                    this._statuses.SetReadAllTab(statusId, read: false);
+                    var idx = tab.IndexOf(statusId);
                     ChangeCacheStyleRead(false, idx);
                 }
                 ColorizeList();
@@ -3934,26 +3914,26 @@ namespace OpenTween
             //追加したタブをアクティブに
             ListTab.SelectedIndex = ListTab.TabPages.Count - 1;
             //検索条件の設定
-            ComboBox cmb = (ComboBox)ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"];
+            var tabPage = this.CurrentTabPage;
+            ComboBox cmb = (ComboBox)tabPage.Controls["panelSearch"].Controls["comboSearch"];
             cmb.Items.Add(searchWord);
             cmb.Text = searchWord;
             SaveConfigsTabs();
             //検索実行
-            this.SearchButton_Click(ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"], null);
+            this.SearchButton_Click(tabPage.Controls["panelSearch"].Controls["comboSearch"], null);
         }
 
         private async Task ShowUserTimeline()
         {
             if (!this.ExistCurrentPost) return;
-            await this.AddNewTabForUserTimeline(_curPost.ScreenName);
+            await this.AddNewTabForUserTimeline(this.CurrentPost.ScreenName);
         }
 
         private void SearchComboBox_KeyDown(object sender, KeyEventArgs e)
         {
             if (e.KeyCode == Keys.Escape)
             {
-                var relTp = this.CurrentTabPage;
-                RemoveSpecifiedTab(relTp.Text, false);
+                RemoveSpecifiedTab(this.CurrentTabName, false);
                 SaveConfigsTabs();
                 e.SuppressKeyPress = true;
             }
@@ -4230,7 +4210,7 @@ namespace OpenTween
             using (ControlTransaction.Layout(this))
             using (ControlTransaction.Layout(_tabPage, false))
             {
-                if (this.ListTab.SelectedTab == _tabPage)
+                if (this.CurrentTabName == TabName)
                 {
                     this.ListTab.SelectTab((this._beforeSelectedTab != null && this.ListTab.TabPages.Contains(this._beforeSelectedTab)) ? this._beforeSelectedTab : this.ListTab.TabPages[0]);
                     this._beforeSelectedTab = null;
@@ -4299,12 +4279,7 @@ namespace OpenTween
                 _listCustom.SmallImageList = null;
                 _listCustom.ListViewItemSorter = null;
 
-                //キャッシュのクリア
-                if (this.CurrentTabPage.Equals(_tabPage))
-                {
-                    _curItemIndex = -1;
-                    _curPost = null;
-                }
+                // キャッシュのクリア
                 this.PurgeListViewItemCache();
             }
 
@@ -4339,7 +4314,7 @@ namespace OpenTween
                 if (!dragEnableRectangle.Contains(e.Location))
                 {
                     //タブが多段の場合にはMouseDownの前の段階で選択されたタブの段が変わっているので、このタイミングでカーソルの位置からタブを判定出来ない。
-                    tn = ListTab.SelectedTab.Text;
+                    tn = this.CurrentTabName;
                 }
 
                 if (string.IsNullOrEmpty(tn)) return;
@@ -4377,8 +4352,9 @@ namespace OpenTween
             SetMainWindowTitle();
             SetStatusLabelUrl();
             SetApiStatusLabel();
-            if (ListTab.Focused || ((Control)ListTab.SelectedTab.Tag).Focused) this.Tag = ListTab.Tag;
-            TabMenuControl(ListTab.SelectedTab.Text);
+            if (ListTab.Focused || ((Control)this.CurrentTabPage.Tag).Focused)
+                this.Tag = ListTab.Tag;
+            TabMenuControl(this.CurrentTabName);
             this.PushSelectPostChain();
             await DispSelectedPost();
         }
@@ -4402,21 +4378,19 @@ namespace OpenTween
                 }
             }
 
-            var currentTabPage = this.CurrentTabPage;
-
             //列幅、列並びを他のタブに設定
             foreach (TabPage tb in ListTab.TabPages)
             {
-                if (!tb.Equals(currentTabPage))
+                if (tb.Text == this.CurrentTabName)
+                    continue;
+
+                if (tb.Tag != null && tb.Controls.Count > 0)
                 {
-                    if (tb.Tag != null && tb.Controls.Count > 0)
+                    DetailsListView lst = (DetailsListView)tb.Tag;
+                    for (int i = 0; i < lst.Columns.Count; i++)
                     {
-                        DetailsListView lst = (DetailsListView)tb.Tag;
-                        for (int i = 0; i < lst.Columns.Count; i++)
-                        {
-                            lst.Columns[dispOrder[i]].DisplayIndex = i;
-                            lst.Columns[i].Width = currentListView.Columns[i].Width;
-                        }
+                        lst.Columns[dispOrder[i]].DisplayIndex = i;
+                        lst.Columns[i].Width = currentListView.Columns[i].Width;
                     }
                 }
             }
@@ -4792,10 +4766,11 @@ namespace OpenTween
             }
 
             // A cache miss, so create a new ListViewItem and pass it back.
-            TabPage tb = (TabPage)((DetailsListView)sender).Parent;
+            var tabPage = (TabPage)((DetailsListView)sender).Parent;
+            var tab = this._statuses.Tabs[tabPage.Text];
             try
             {
-                e.Item = this.CreateItem(tb, _statuses.Tabs[tb.Text][e.ItemIndex], e.ItemIndex);
+                e.Item = this.CreateItem(tab, tab[e.ItemIndex], e.ItemIndex);
             }
             catch (Exception)
             {
@@ -4822,10 +4797,10 @@ namespace OpenTween
 
             var cacheLength = endIndex - startIndex + 1;
 
-            var tabPage = this.CurrentTabPage;
+            var tab = this.CurrentTab;
             var posts = tabInfo[startIndex, endIndex]; //配列で取得
             var listItems = Enumerable.Range(0, cacheLength)
-                .Select(x => this.CreateItem(tabPage, posts[x], startIndex + x))
+                .Select(x => this.CreateItem(tab, posts[x], startIndex + x))
                 .ToArray();
 
             var listCache = new ListViewItemCache
@@ -4846,7 +4821,7 @@ namespace OpenTween
         private void PurgeListViewItemCache()
             => Interlocked.Exchange(ref this._listItemCache, null);
 
-        private ListViewItem CreateItem(TabPage Tab, PostClass Post, int Index)
+        private ListViewItem CreateItem(TabModel tab, PostClass Post, int Index)
         {
             StringBuilder mk = new StringBuilder();
             //if (Post.IsDeleted) mk.Append("×");
@@ -4883,10 +4858,15 @@ namespace OpenTween
             itm.Tag = Post;
 
             bool read = Post.IsRead;
-            //未読管理していなかったら既読として扱う
-            if (!_statuses.Tabs[Tab.Text].UnreadManage || !SettingManager.Common.UnreadManage) read = true;
+            // 未読管理していなかったら既読として扱う
+            if (!tab.UnreadManage || !SettingManager.Common.UnreadManage)
+                read = true;
+
             ChangeItemStyleRead(read, itm, Post, null);
-            if (Tab.Equals(this.CurrentTabPage)) ColorizeList(itm, Index);
+
+            if (tab.TabName == this.CurrentTabName)
+                this.ColorizeList(itm, Index);
+
             return itm;
         }
 
@@ -4898,8 +4878,6 @@ namespace OpenTween
             using (ControlTransaction.Cursor(this, Cursors.WaitCursor))
             {
                 this.PurgeListViewItemCache();
-                this._curPost = null;
-                this._curItemIndex = -1;
                 this._statuses.FilterAll();
 
                 foreach (TabPage tabPage in this.ListTab.TabPages)
@@ -5213,8 +5191,7 @@ namespace OpenTween
                 return;
             }
 
-            var listView = this.CurrentListView;
-            var selectedIndex = listView.SelectedIndices.Count != 0 ? listView.SelectedIndices[0] : -1;
+            var selectedIndex = tab.SelectedIndex;
 
             int startIndex;
             switch (searchType)
@@ -5261,6 +5238,7 @@ namespace OpenTween
                 return;
             }
 
+            var listView = this.CurrentListView;
             this.SelectListItem(listView, foundIndex);
             listView.EnsureVisible(foundIndex);
         }
@@ -5507,12 +5485,9 @@ namespace OpenTween
         private async void StatusOpenMenuItem_Click(object sender, EventArgs e)
         {
             var tab = this.CurrentTab;
-            var listView = this.CurrentListView;
-            if (listView.SelectedIndices.Count > 0 && tab.TabType != MyCommon.TabUsageType.DirectMessage)
-            {
-                var post = tab[listView.SelectedIndices[0]];
+            var post = this.CurrentPost;
+            if (post != null && tab.TabType != MyCommon.TabUsageType.DirectMessage)
                 await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(post));
-            }
         }
 
         private async void VerUpMenuItem_Click(object sender, EventArgs e)
@@ -5671,18 +5646,19 @@ namespace OpenTween
 
         private async Task DispSelectedPost(bool forceupdate)
         {
-            if (this.CurrentListView.SelectedIndices.Count == 0 || _curPost == null)
+            var currentPost = this.CurrentPost;
+            if (currentPost == null)
                 return;
 
             var oldDisplayPost = this.displayPost;
-            this.displayPost = this._curPost;
+            this.displayPost = currentPost;
 
-            if (!forceupdate && this._curPost.Equals(oldDisplayPost))
+            if (!forceupdate && currentPost.Equals(oldDisplayPost))
                 return;
 
             var loadTasks = new List<Task>
             {
-                this.tweetDetailsView.ShowPostDetails(this._curPost),
+                this.tweetDetailsView.ShowPostDetails(currentPost),
             };
 
             this.SplitContainer3.Panel2Collapsed = true;
@@ -5693,7 +5669,7 @@ namespace OpenTween
                 oldTokenSource?.Cancel();
 
                 var token = this.thumbnailTokenSource.Token;
-                loadTasks.Add(this.tweetThumbnail1.ShowThumbnailAsync(_curPost, token));
+                loadTasks.Add(this.tweetThumbnail1.ShowThumbnailAsync(currentPost, token));
             }
 
             try
@@ -5717,7 +5693,7 @@ namespace OpenTween
             var tab = this.CurrentTab;
             if (tab.TabType == MyCommon.TabUsageType.PublicSearch)
             {
-                Control pnl = ListTab.SelectedTab.Controls["panelSearch"];
+                Control pnl = this.CurrentTabPage.Controls["panelSearch"];
                 if (pnl.Controls["comboSearch"].Focused ||
                     pnl.Controls["comboLang"].Focused ||
                     pnl.Controls["buttonSearch"].Focused) return;
@@ -6085,8 +6061,8 @@ namespace OpenTween
                     .Do(() => this.doReTweetOfficial(isConfirm: true)),
 
                 ShortcutCommand.Create(Keys.Alt | Keys.P)
-                    .OnlyWhen(() => this._curPost != null)
-                    .Do(() => this.doShowUserStatus(_curPost.ScreenName, ShowInputDialog: false)),
+                    .OnlyWhen(() => this.CurrentPost != null)
+                    .Do(() => this.doShowUserStatus(this.CurrentPost.ScreenName, ShowInputDialog: false)),
 
                 ShortcutCommand.Create(Keys.Alt | Keys.Up)
                     .Do(() => this.tweetDetailsView.ScrollDownPostBrowser(forward: false)),
@@ -6137,11 +6113,12 @@ namespace OpenTween
                 ShortcutCommand.Create(Keys.Control | Keys.Shift | Keys.Up)
                     .FocusedOn(FocusedControl.StatusText)
                     .Do(() => {
-                        var listView = this.CurrentListView;
-                        if (listView.VirtualListSize != 0 &&
-                            listView.SelectedIndices.Count > 0 && listView.SelectedIndices[0] > 0)
+                        var tab = this.CurrentTab;
+                        var selectedIndex = tab.SelectedIndex;
+                        if (selectedIndex != -1 && selectedIndex > 0)
                         {
-                            var idx = listView.SelectedIndices[0] - 1;
+                            var listView = this.CurrentListView;
+                            var idx = selectedIndex - 1;
                             SelectListItem(listView, idx);
                             listView.EnsureVisible(idx);
                         }
@@ -6150,11 +6127,12 @@ namespace OpenTween
                 ShortcutCommand.Create(Keys.Control | Keys.Shift | Keys.Down)
                     .FocusedOn(FocusedControl.StatusText)
                     .Do(() => {
-                        var listView = this.CurrentListView;
-                        if (listView.VirtualListSize != 0 && listView.SelectedIndices.Count > 0
-                            && listView.SelectedIndices[0] < listView.VirtualListSize - 1)
+                        var tab = this.CurrentTab;
+                        var selectedIndex = tab.SelectedIndex;
+                        if (selectedIndex != -1 && selectedIndex < tab.AllCount - 1)
                         {
-                            var idx = listView.SelectedIndices[0] + 1;
+                            var listView = this.CurrentListView;
+                            var idx = selectedIndex + 1;
                             SelectListItem(listView, idx);
                             listView.EnsureVisible(idx);
                         }
@@ -6311,9 +6289,8 @@ namespace OpenTween
             var tab = this.CurrentTab;
             bool IsProtected = false;
             var isDm = tab.TabType == MyCommon.TabUsageType.DirectMessage;
-            foreach (int idx in this.CurrentListView.SelectedIndices)
+            foreach (var post in tab.SelectedPosts)
             {
-                var post = tab[idx];
                 if (post.IsDeleted) continue;
                 if (!isDm)
                 {
@@ -6352,11 +6329,8 @@ namespace OpenTween
                 return;
 
             var copyUrls = new List<string>();
-            foreach (int idx in this.CurrentListView.SelectedIndices)
-            {
-                var post = tab[idx];
+            foreach (var post in tab.SelectedPosts)
                 copyUrls.Add(MyCommon.GetStatusUrl(post));
-            }
 
             if (copyUrls.Count == 0)
                 return;
@@ -6373,46 +6347,50 @@ namespace OpenTween
 
         private void GoFav(bool forward)
         {
-            var listView = this.CurrentListView;
-            if (listView.VirtualListSize == 0) return;
+            var tab = this.CurrentTab;
+            if (tab.AllCount == 0)
+                return;
+
+            var selectedIndex = tab.SelectedIndex;
+
             int fIdx = 0;
             int toIdx = 0;
             int stp = 1;
 
             if (forward)
             {
-                if (listView.SelectedIndices.Count == 0)
+                if (selectedIndex == -1)
                 {
                     fIdx = 0;
                 }
                 else
                 {
-                    fIdx = listView.SelectedIndices[0] + 1;
-                    if (fIdx > listView.VirtualListSize - 1) return;
+                    fIdx = selectedIndex + 1;
+                    if (fIdx > tab.AllCount - 1) return;
                 }
-                toIdx = listView.VirtualListSize;
+                toIdx = tab.AllCount;
                 stp = 1;
             }
             else
             {
-                if (listView.SelectedIndices.Count == 0)
+                if (selectedIndex == -1)
                 {
-                    fIdx = listView.VirtualListSize - 1;
+                    fIdx = tab.AllCount - 1;
                 }
                 else
                 {
-                    fIdx = listView.SelectedIndices[0] - 1;
+                    fIdx = selectedIndex - 1;
                     if (fIdx < 0) return;
                 }
                 toIdx = -1;
                 stp = -1;
             }
 
-            var tab = this.CurrentTab;
             for (int idx = fIdx; idx != toIdx; idx += stp)
             {
                 if (tab[idx].IsFav)
                 {
+                    var listView = this.CurrentListView;
                     SelectListItem(listView, idx);
                     listView.EnsureVisible(idx);
                     break;
@@ -6422,18 +6400,15 @@ namespace OpenTween
 
         private void GoSamePostToAnotherTab(bool left)
         {
-            var listView = this.CurrentListView;
-            if (listView.SelectedIndices.Count == 0)
-                return;
-
             var tab = this.CurrentTab;
 
             // Directタブは対象外(見つかるはずがない)
             if (tab.TabType == MyCommon.TabUsageType.DirectMessage)
                 return;
 
-            var selectedIndex = listView.SelectedIndices[0];
-            var selectedStatusId = tab.GetStatusIdAt(selectedIndex);
+            var selectedStatusId = tab.SelectedStatusId;
+            if (selectedStatusId == -1)
+                return;
 
             int fIdx, toIdx, stp;
 
@@ -6478,7 +6453,7 @@ namespace OpenTween
                 if (foundIndex != -1)
                 {
                     ListTab.SelectedIndex = tabidx;
-                    listView = this.CurrentListView;
+                    var listView = this.CurrentListView;
                     SelectListItem(listView, foundIndex);
                     listView.EnsureVisible(foundIndex);
                     return;
@@ -6488,12 +6463,13 @@ namespace OpenTween
 
         private void GoPost(bool forward)
         {
-            var listView = this.CurrentListView;
-            if (listView.SelectedIndices.Count == 0 || _curPost == null)
+            var tab = this.CurrentTab;
+            var currentPost = this.CurrentPost;
+
+            if (currentPost == null)
                 return;
 
-            var tab = this.CurrentTab;
-            var selectedIndex = listView.SelectedIndices[0];
+            var selectedIndex = tab.SelectedIndex;
 
             int fIdx, toIdx, stp;
 
@@ -6513,13 +6489,13 @@ namespace OpenTween
             }
 
             string name = "";
-            if (_curPost.RetweetedId == null)
+            if (currentPost.RetweetedId == null)
             {
-                name = _curPost.ScreenName;
+                name = currentPost.ScreenName;
             }
             else
             {
-                name = _curPost.RetweetedBy;
+                name = currentPost.RetweetedBy;
             }
             for (int idx = fIdx; idx != toIdx; idx += stp)
             {
@@ -6528,6 +6504,7 @@ namespace OpenTween
                 {
                     if (post.ScreenName == name)
                     {
+                        var listView = this.CurrentListView;
                         SelectListItem(listView, idx);
                         listView.EnsureVisible(idx);
                         break;
@@ -6537,6 +6514,7 @@ namespace OpenTween
                 {
                     if (post.RetweetedBy == name)
                     {
+                        var listView = this.CurrentListView;
                         SelectListItem(listView, idx);
                         listView.EnsureVisible(idx);
                         break;
@@ -6547,12 +6525,11 @@ namespace OpenTween
 
         private void GoRelPost(bool forward)
         {
-            var listView = this.CurrentListView;
-            if (listView.SelectedIndices.Count == 0)
-                return;
-
             var tab = this.CurrentTab;
-            var selectedIndex = listView.SelectedIndices[0];
+            var selectedIndex = tab.SelectedIndex;
+
+            if (selectedIndex == -1)
+                return;
 
             int fIdx, toIdx, stp;
 
@@ -6573,8 +6550,9 @@ namespace OpenTween
 
             if (!_anchorFlag)
             {
-                if (_curPost == null) return;
-                _anchorPost = _curPost;
+                var currentPost = this.CurrentPost;
+                if (currentPost == null) return;
+                _anchorPost = currentPost;
                 _anchorFlag = true;
             }
             else
@@ -6594,6 +6572,7 @@ namespace OpenTween
                     post.ReplyToList.Any(x => x.UserId == _anchorPost.UserId) ||
                     post.ReplyToList.Any(x => x.UserId == _anchorPost.RetweetedByUserId))
                 {
+                    var listView = this.CurrentListView;
                     SelectListItem(listView, idx);
                     listView.EnsureVisible(idx);
                     break;
@@ -6710,21 +6689,25 @@ namespace OpenTween
 
         private async Task GoInReplyToPostTree()
         {
-            if (_curPost == null) return;
-
             var curTabClass = this.CurrentTab;
+            var currentPost = this.CurrentPost;
+
+            if (currentPost == null)
+                return;
 
-            if (curTabClass.TabType == MyCommon.TabUsageType.PublicSearch && _curPost.InReplyToStatusId == null && _curPost.TextFromApi.Contains("@"))
+            if (curTabClass.TabType == MyCommon.TabUsageType.PublicSearch && currentPost.InReplyToStatusId == null && currentPost.TextFromApi.Contains("@"))
             {
                 try
                 {
-                    var post = await tw.GetStatusApi(false, _curPost.StatusId);
+                    var post = await tw.GetStatusApi(false, currentPost.StatusId);
 
-                    _curPost.InReplyToStatusId = post.InReplyToStatusId;
-                    _curPost.InReplyToUser = post.InReplyToUser;
-                    _curPost.IsReply = post.IsReply;
+                    currentPost.InReplyToStatusId = post.InReplyToStatusId;
+                    currentPost.InReplyToUser = post.InReplyToUser;
+                    currentPost.IsReply = post.IsReply;
                     this.PurgeListViewItemCache();
-                    this.CurrentListView.RedrawItems(_curItemIndex, _curItemIndex, false);
+
+                    var index = curTabClass.SelectedIndex;
+                    this.CurrentListView.RedrawItems(index, index, false);
                 }
                 catch (WebApiException ex)
                 {
@@ -6732,21 +6715,20 @@ namespace OpenTween
                 }
             }
 
-            if (!(this.ExistCurrentPost && _curPost.InReplyToUser != null && _curPost.InReplyToStatusId != null)) return;
+            if (!(this.ExistCurrentPost && currentPost.InReplyToUser != null && currentPost.InReplyToStatusId != null)) return;
 
-            if (replyChains == null || (replyChains.Count > 0 && replyChains.Peek().InReplyToId != _curPost.StatusId))
+            if (replyChains == null || (replyChains.Count > 0 && replyChains.Peek().InReplyToId != currentPost.StatusId))
             {
                 replyChains = new Stack<ReplyChain>();
             }
-            replyChains.Push(new ReplyChain(_curPost.StatusId, _curPost.InReplyToStatusId.Value, this.CurrentTabPage));
+            replyChains.Push(new ReplyChain(currentPost.StatusId, currentPost.InReplyToStatusId.Value, curTabClass));
 
             int inReplyToIndex;
             string inReplyToTabName;
-            long inReplyToId = _curPost.InReplyToStatusId.Value;
-            string inReplyToUser = _curPost.InReplyToUser;
-            //Dictionary<long, PostClass> curTabPosts = curTabClass.Posts;
+            var inReplyToId = currentPost.InReplyToStatusId.Value;
+            var inReplyToUser = currentPost.InReplyToUser;
 
-            var inReplyToPosts = from tab in _statuses.Tabs.Values
+            var inReplyToPosts = from tab in _statuses.Tabs
                                  orderby tab != curTabClass
                                  from post in tab.Posts.Values
                                  where post.StatusId == inReplyToId
@@ -6761,7 +6743,7 @@ namespace OpenTween
                 {
                     await Task.Run(async () =>
                     {
-                        var post = await tw.GetStatusApi(false, _curPost.InReplyToStatusId.Value)
+                        var post = await tw.GetStatusApi(false, currentPost.InReplyToStatusId.Value)
                             .ConfigureAwait(false);
                         post.IsRead = true;
 
@@ -6791,7 +6773,7 @@ namespace OpenTween
             TabPage tabPage = this.ListTab.TabPages.Cast<TabPage>().First((tp) => { return tp.Text == inReplyToTabName; });
             DetailsListView listView = (DetailsListView)tabPage.Tag;
 
-            if (this.CurrentTabPage != tabPage)
+            if (this.CurrentTabName != inReplyToTabName)
             {
                 this.ListTab.SelectTab(tabPage);
             }
@@ -6802,23 +6784,24 @@ namespace OpenTween
 
         private void GoBackInReplyToPostTree(bool parallel = false, bool isForward = true)
         {
-            if (_curPost == null) return;
-
             var curTabClass = this.CurrentTab;
-            //Dictionary<long, PostClass> curTabPosts = curTabClass.Posts;
+            var currentPost = this.CurrentPost;
+
+            if (currentPost == null)
+                return;
 
             if (parallel)
             {
-                if (_curPost.InReplyToStatusId != null)
+                if (currentPost.InReplyToStatusId != null)
                 {
                     var posts = from t in _statuses.Tabs
-                                from p in t.Value.Posts
-                                where p.Value.StatusId != _curPost.StatusId && p.Value.InReplyToStatusId == _curPost.InReplyToStatusId
-                                let indexOf = t.Value.IndexOf(p.Value.StatusId)
+                                from p in t.Posts
+                                where p.Value.StatusId != currentPost.StatusId && p.Value.InReplyToStatusId == currentPost.InReplyToStatusId
+                                let indexOf = t.IndexOf(p.Value.StatusId)
                                 where indexOf > -1
                                 orderby isForward ? indexOf : indexOf * -1
-                                orderby t.Value != curTabClass
-                                select new {Tab = t.Value, Post = p.Value, Index = indexOf};
+                                orderby t != curTabClass
+                                select new {Tab = t, Post = p.Value, Index = indexOf};
                     try
                     {
                         var postList = posts.ToList();
@@ -6830,7 +6813,8 @@ namespace OpenTween
                                 postList.RemoveAt(index);
                             }
                         }
-                        var post = postList.FirstOrDefault((pst) => { return pst.Tab == curTabClass && isForward ? pst.Index > _curItemIndex : pst.Index < _curItemIndex; });
+                        var currentIndex = this.CurrentTab.SelectedIndex;
+                        var post = postList.FirstOrDefault((pst) => { return pst.Tab == curTabClass && isForward ? pst.Index > currentIndex : pst.Index < currentIndex; });
                         if (post == null) post = postList.FirstOrDefault((pst) => { return pst.Tab != curTabClass; });
                         if (post == null) post = postList.First();
                         this.ListTab.SelectTab(this.ListTab.TabPages.Cast<TabPage>().First((tp) => { return tp.Text == post.Tab.TabName; }));
@@ -6849,13 +6833,13 @@ namespace OpenTween
                 if (replyChains == null || replyChains.Count < 1)
                 {
                     var posts = from t in _statuses.Tabs
-                                from p in t.Value.Posts
-                                where p.Value.InReplyToStatusId == _curPost.StatusId
-                                let indexOf = t.Value.IndexOf(p.Value.StatusId)
+                                from p in t.Posts
+                                where p.Value.InReplyToStatusId == currentPost.StatusId
+                                let indexOf = t.IndexOf(p.Value.StatusId)
                                 where indexOf > -1
                                 orderby indexOf
-                                orderby t.Value != curTabClass
-                                select new {Tab = t.Value, Index = indexOf};
+                                orderby t != curTabClass
+                                select new {Tab = t, Index = indexOf};
                     try
                     {
                         var post = posts.First();
@@ -6872,26 +6856,35 @@ namespace OpenTween
                 else
                 {
                     ReplyChain chainHead = replyChains.Pop();
-                    if (chainHead.InReplyToId == _curPost.StatusId)
+                    if (chainHead.InReplyToId == currentPost.StatusId)
                     {
-                        int idx = _statuses.Tabs[chainHead.OriginalTab.Text].IndexOf(chainHead.OriginalId);
-                        if (idx == -1)
+                        var tab = chainHead.OriginalTab;
+                        if (!this._statuses.Tabs.Contains(tab))
                         {
                             replyChains = null;
                         }
                         else
                         {
-                            try
+                            var idx = tab.IndexOf(chainHead.OriginalId);
+                            if (idx == -1)
                             {
-                                ListTab.SelectTab(chainHead.OriginalTab);
+                                replyChains = null;
                             }
-                            catch (Exception)
+                            else
                             {
-                                replyChains = null;
+                                var tabPage = this.ListTab.TabPages.Cast<TabPage>().First(x => x.Text == tab.TabName);
+                                try
+                                {
+                                    ListTab.SelectTab(tabPage);
+                                }
+                                catch (Exception)
+                                {
+                                    replyChains = null;
+                                }
+                                var listView = this.CurrentListView;
+                                SelectListItem(listView, idx);
+                                listView.EnsureVisible(idx);
                             }
-                            var listView = this.CurrentListView;
-                            SelectListItem(listView, idx);
-                            listView.EnsureVisible(idx);
                         }
                     }
                     else
@@ -6908,24 +6901,25 @@ namespace OpenTween
             if (this.selectPostChains.Count > 1)
             {
                 var idx = -1;
-                TabPage tp = null;
+                TabModel foundTab = null;
 
                 do
                 {
                     try
                     {
                         this.selectPostChains.Pop();
-                        var (tabPage, post) = this.selectPostChains.Peek();
+                        var (tab, post) = this.selectPostChains.Peek();
 
-                        if (!this.ListTab.TabPages.Contains(tabPage)) continue;  //該当タブが存在しないので無視
+                        if (!this._statuses.Tabs.Contains(tab))
+                            continue; // 該当タブが存在しないので無視
 
                         if (post != null)
                         {
-                            idx = this._statuses.Tabs[tabPage.Text].IndexOf(post.StatusId);
+                            idx = tab.IndexOf(post.StatusId);
                             if (idx == -1) continue;  //該当ポストが存在しないので無視
                         }
 
-                        tp = tabPage;
+                        foundTab = tab;
 
                         this.selectPostChains.Pop();
                     }
@@ -6937,7 +6931,7 @@ namespace OpenTween
                 }
                 while (this.selectPostChains.Count > 1);
 
-                if (tp == null)
+                if (foundTab == null)
                 {
                     //状態がおかしいので処理を中断
                     //履歴が残り1つであればクリアしておく
@@ -6946,8 +6940,10 @@ namespace OpenTween
                     return;
                 }
 
-                DetailsListView lst = (DetailsListView)tp.Tag;
-                this.ListTab.SelectedTab = tp;
+                var tabPage = this.ListTab.TabPages.Cast<TabPage>().First(x => x.Text == foundTab.TabName);
+                var lst = (DetailsListView)tabPage.Tag;
+                this.ListTab.SelectedTab = tabPage;
+
                 if (idx > -1)
                 {
                     SelectListItem(lst, idx);
@@ -6959,25 +6955,27 @@ namespace OpenTween
 
         private void PushSelectPostChain()
         {
-            var currentTabPage = this.CurrentTabPage;
+            var currentTab = this.CurrentTab;
+            var currentPost = this.CurrentPost;
+
             int count = this.selectPostChains.Count;
             if (count > 0)
             {
-                var (tabPage, post) = this.selectPostChains.Peek();
-                if (tabPage == currentTabPage)
+                var (tab, post) = this.selectPostChains.Peek();
+                if (tab == currentTab)
                 {
-                    if (post == this._curPost) return;  //最新の履歴と同一
+                    if (post == currentPost) return;  //最新の履歴と同一
                     if (post == null) this.selectPostChains.Pop();  //置き換えるため削除
                 }
             }
             if (count >= 2500) TrimPostChain();
-            this.selectPostChains.Push((currentTabPage, this._curPost));
+            this.selectPostChains.Push((currentTab, currentPost));
         }
 
         private void TrimPostChain()
         {
             if (this.selectPostChains.Count <= 2000) return;
-            var p = new Stack<(TabPage, PostClass)>(2000);
+            var p = new Stack<(TabModel, PostClass)>(2000);
             for (int i = 0; i < 2000; i++)
             {
                 p.Push(this.selectPostChains.Pop());
@@ -6992,37 +6990,45 @@ namespace OpenTween
         private bool GoStatus(long statusId)
         {
             if (statusId == 0) return false;
-            for (int tabidx = 0; tabidx < ListTab.TabCount; tabidx++)
-            {
-                if (_statuses.Tabs[ListTab.TabPages[tabidx].Text].TabType != MyCommon.TabUsageType.DirectMessage && _statuses.Tabs[ListTab.TabPages[tabidx].Text].Contains(statusId))
-                {
-                    int idx = _statuses.Tabs[ListTab.TabPages[tabidx].Text].IndexOf(statusId);
-                    ListTab.SelectedIndex = tabidx;
-                    var listView = this.CurrentListView;
-                    SelectListItem(listView, idx);
-                    listView.EnsureVisible(idx);
-                    return true;
-                }
-            }
-            return false;
+
+            var tab = this._statuses.Tabs
+                .Where(x => x.TabType != MyCommon.TabUsageType.DirectMessage)
+                .Where(x => x.Contains(statusId))
+                .FirstOrDefault();
+
+            if (tab == null)
+                return false;
+
+            var index = tab.IndexOf(statusId);
+
+            var tabPage = this.ListTab.TabPages.Cast<TabPage>().First(x => x.Text == tab.TabName);
+            this.ListTab.SelectedTab = tabPage;
+
+            var listView = this.CurrentListView;
+            this.SelectListItem(listView, index);
+            listView.EnsureVisible(index);
+
+            return true;
         }
 
         private bool GoDirectMessage(long statusId)
         {
             if (statusId == 0) return false;
-            for (int tabidx = 0; tabidx < ListTab.TabCount; tabidx++)
-            {
-                if (_statuses.Tabs[ListTab.TabPages[tabidx].Text].TabType == MyCommon.TabUsageType.DirectMessage && _statuses.Tabs[ListTab.TabPages[tabidx].Text].Contains(statusId))
-                {
-                    int idx = _statuses.Tabs[ListTab.TabPages[tabidx].Text].IndexOf(statusId);
-                    ListTab.SelectedIndex = tabidx;
-                    var listView = this.CurrentListView;
-                    SelectListItem(listView, idx);
-                    listView.EnsureVisible(idx);
-                    return true;
-                }
-            }
-            return false;
+
+            var tab = this._statuses.GetTabByType<DirectMessagesTabModel>();
+            var index = tab.IndexOf(statusId);
+
+            if (index == -1)
+                return false;
+
+            var tabPage = this.ListTab.TabPages.Cast<TabPage>().First(x => x.Text == tab.TabName);
+            this.ListTab.SelectedTab = tabPage;
+
+            var listView = this.CurrentListView;
+            this.SelectListItem(listView, index);
+            listView.EnsureVisible(index);
+
+            return true;
         }
 
         private void MyList_MouseClick(object sender, MouseEventArgs e)
@@ -7187,7 +7193,7 @@ namespace OpenTween
 
             var tabs = this.ListTab.TabPages.Cast<TabPage>()
                 .Select(x => this._statuses.Tabs[x.Text])
-                .Append(this._statuses.GetTabByType(MyCommon.TabUsageType.Mute));
+                .Append(this._statuses.MuteTab);
 
             foreach (var tab in tabs)
             {
@@ -7274,11 +7280,10 @@ namespace OpenTween
                 if (!SaveFileDialog1.ValidateNames) return;
                 using (StreamWriter sw = new StreamWriter(SaveFileDialog1.FileName, false, Encoding.UTF8))
                 {
-                    var listView = this.CurrentListView;
                     if (rslt == DialogResult.Yes)
                     {
                         //All
-                        for (int idx = 0; idx < listView.VirtualListSize; idx++)
+                        for (int idx = 0; idx < tab.AllCount; idx++)
                         {
                             var post = tab[idx];
                             string protect = "";
@@ -7295,9 +7300,8 @@ namespace OpenTween
                     }
                     else
                     {
-                        foreach (int idx in listView.SelectedIndices)
+                        foreach (var post in this.CurrentTab.SelectedPosts)
                         {
-                            var post = tab[idx];
                             string protect = "";
                             if (post.IsProtect) protect = "Protect";
                             sw.WriteLine(post.Nickname + "\t" +
@@ -7460,16 +7464,20 @@ namespace OpenTween
 
             using (ControlTransaction.Layout(this.ListTab))
             {
-                var mTp = this.ListTab.TabPages[targetIndex];
-                this.ListTab.TabPages.Remove(mTp);
+                var tab = this._statuses.Tabs[targetIndex];
+                var tabPage = this.ListTab.TabPages[targetIndex];
+
+                this.ListTab.TabPages.Remove(tabPage);
 
                 if (targetIndex < baseIndex)
                     baseIndex--;
 
-                if (isBeforeBaseTab)
-                    ListTab.TabPages.Insert(baseIndex, mTp);
-                else
-                    ListTab.TabPages.Insert(baseIndex + 1, mTp);
+                if (!isBeforeBaseTab)
+                    baseIndex++;
+
+                this._statuses.MoveTab(baseIndex, tab);
+
+                ListTab.TabPages.Insert(baseIndex, tabPage);
             }
 
             SaveConfigsTabs();
@@ -7483,24 +7491,26 @@ namespace OpenTween
             if (!this.ExistCurrentPost) return;
 
             var tab = this.CurrentTab;
-            var listView = this.CurrentListView;
+            var selectedPosts = tab.SelectedPosts;
 
             // 複数あてリプライはReplyではなく通常ポスト
             //↑仕様変更で全部リプライ扱いでOK(先頭ドット付加しない)
             //090403暫定でドットを付加しないようにだけ修正。単独と複数の処理は統合できると思われる。
             //090513 all @ replies 廃止の仕様変更によりドット付加に戻し(syo68k)
 
-            if (listView.SelectedIndices.Count > 0)
+            if (selectedPosts.Length > 0)
             {
                 // アイテムが1件以上選択されている
-                if (listView.SelectedIndices.Count == 1 && !isAll && this.ExistCurrentPost)
+                if (selectedPosts.Length == 1 && !isAll && this.ExistCurrentPost)
                 {
+                    var post = selectedPosts.Single();
+
                     // 単独ユーザー宛リプライまたはDM
                     if ((tab.TabType == MyCommon.TabUsageType.DirectMessage && isAuto) || (!isAuto && !isReply))
                     {
                         // ダイレクトメッセージ
                         this.inReplyTo = null;
-                        StatusText.Text = "D " + _curPost.ScreenName + " " + StatusText.Text;
+                        StatusText.Text = "D " + post.ScreenName + " " + StatusText.Text;
                         StatusText.SelectionStart = StatusText.Text.Length;
                         StatusText.Focus();
                         return;
@@ -7508,12 +7518,12 @@ namespace OpenTween
                     if (string.IsNullOrEmpty(StatusText.Text))
                     {
                         //空の場合
-                        var inReplyToStatusId = this._curPost.RetweetedId ?? this._curPost.StatusId;
-                        var inReplyToScreenName = this._curPost.ScreenName;
+                        var inReplyToStatusId = post.RetweetedId ?? post.StatusId;
+                        var inReplyToScreenName = post.ScreenName;
                         this.inReplyTo = (inReplyToStatusId, inReplyToScreenName);
 
                         // ステータステキストが入力されていない場合先頭に@ユーザー名を追加する
-                        StatusText.Text = "@" + _curPost.ScreenName + " ";
+                        StatusText.Text = "@" + post.ScreenName + " ";
                     }
                     else
                     {
@@ -7522,13 +7532,13 @@ namespace OpenTween
                         if (isAuto)
                         {
                             //1件選んでEnter or DoubleClick
-                            if (StatusText.Text.Contains("@" + _curPost.ScreenName + " "))
+                            if (StatusText.Text.Contains("@" + post.ScreenName + " "))
                             {
-                                if (this.inReplyTo?.ScreenName == _curPost.ScreenName)
+                                if (this.inReplyTo?.ScreenName == post.ScreenName)
                                 {
                                     //返信先書き換え
-                                    var inReplyToStatusId = this._curPost.RetweetedId ?? this._curPost.StatusId;
-                                    var inReplyToScreenName = this._curPost.ScreenName;
+                                    var inReplyToStatusId = post.RetweetedId ?? post.StatusId;
+                                    var inReplyToScreenName = post.ScreenName;
                                     this.inReplyTo = (inReplyToStatusId, inReplyToScreenName);
                                 }
                                 return;
@@ -7540,15 +7550,15 @@ namespace OpenTween
                                 {
                                     // 複数リプライ
                                     this.inReplyTo = null;
-                                    StatusText.Text = StatusText.Text.Insert(2, "@" + _curPost.ScreenName + " ");
+                                    StatusText.Text = StatusText.Text.Insert(2, "@" + post.ScreenName + " ");
                                 }
                                 else
                                 {
                                     // 単独リプライ
-                                    var inReplyToStatusId = this._curPost.RetweetedId ?? this._curPost.StatusId;
-                                    var inReplyToScreenName = this._curPost.ScreenName;
+                                    var inReplyToStatusId = post.RetweetedId ?? post.StatusId;
+                                    var inReplyToScreenName = post.ScreenName;
                                     this.inReplyTo = (inReplyToStatusId, inReplyToScreenName);
-                                    StatusText.Text = "@" + _curPost.ScreenName + " " + StatusText.Text;
+                                    StatusText.Text = "@" + post.ScreenName + " " + StatusText.Text;
                                 }
                             }
                             else
@@ -7556,15 +7566,14 @@ namespace OpenTween
                                 //文頭@
                                 // 複数リプライ
                                 this.inReplyTo = null;
-                                StatusText.Text = ". @" + _curPost.ScreenName + " " + StatusText.Text;
-                                //StatusText.Text = "@" + _curPost.ScreenName + " " + StatusText.Text;
+                                StatusText.Text = ". @" + post.ScreenName + " " + StatusText.Text;
                             }
                         }
                         else
                         {
                             //1件選んでCtrl-Rの場合(返信先操作せず)
                             int sidx = StatusText.SelectionStart;
-                            string id = "@" + _curPost.ScreenName + " ";
+                            string id = "@" + post.ScreenName + " ";
                             if (sidx > 0)
                             {
                                 if (StatusText.Text.Substring(sidx - 1, 1) != " ")
@@ -7611,9 +7620,8 @@ namespace OpenTween
                             sTxt = ". " + sTxt;
                             this.inReplyTo = null;
                         }
-                        for (int cnt = 0; cnt < listView.SelectedIndices.Count; cnt++)
+                        foreach (var post in selectedPosts)
                         {
-                            PostClass post = tab[listView.SelectedIndices[cnt]];
                             if (!sTxt.Contains("@" + post.ScreenName + " "))
                             {
                                 sTxt = sTxt.Insert(2, "@" + post.ScreenName + " ");
@@ -7625,15 +7633,15 @@ namespace OpenTween
                     else
                     {
                         //C-S-r or C-r
-                        if (listView.SelectedIndices.Count > 1)
+
+                        if (selectedPosts.Length > 1)
                         {
                             //複数ポスト選択
 
                             string ids = "";
                             int sidx = StatusText.SelectionStart;
-                            for (int cnt = 0; cnt < listView.SelectedIndices.Count; cnt++)
+                            foreach (var post in selectedPosts)
                             {
-                                PostClass post = tab[listView.SelectedIndices[cnt]];
                                 if (!ids.Contains("@" + post.ScreenName + " ") && post.UserId != tw.UserId)
                                 {
                                     ids += "@" + post.ScreenName + " ";
@@ -7690,7 +7698,7 @@ namespace OpenTween
 
                             string ids = "";
                             int sidx = StatusText.SelectionStart;
-                            PostClass post = _curPost;
+                            var post = selectedPosts.Single();
                             if (!ids.Contains("@" + post.ScreenName + " ") && post.UserId != tw.UserId)
                             {
                                 ids += "@" + post.ScreenName + " ";
@@ -7718,8 +7726,8 @@ namespace OpenTween
                             if (string.IsNullOrEmpty(StatusText.Text))
                             {
                                 //未入力の場合のみ返信先付加
-                                var inReplyToStatusId = this._curPost.RetweetedId ?? this._curPost.StatusId;
-                                var inReplyToScreenName = this._curPost.ScreenName;
+                                var inReplyToStatusId = post.RetweetedId ?? post.StatusId;
+                                var inReplyToScreenName = post.ScreenName;
                                 this.inReplyTo = (inReplyToStatusId, inReplyToScreenName);
 
                                 StatusText.Text = ids;
@@ -8079,7 +8087,7 @@ namespace OpenTween
                     if (tabUsage == MyCommon.TabUsageType.PublicSearch)
                     {
                         ListTab.SelectedIndex = ListTab.TabPages.Count - 1;
-                        ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"].Focus();
+                        this.CurrentTabPage.Controls["panelSearch"].Controls["comboSearch"].Focus();
                     }
                     if (tabUsage == MyCommon.TabUsageType.Lists)
                     {
@@ -8097,13 +8105,13 @@ namespace OpenTween
                 fltDialog.Owner = this;
 
                 //選択発言を元にフィルタ追加
-                foreach (int idx in this.CurrentListView.SelectedIndices)
+                foreach (var post in this.CurrentTab.SelectedPosts)
                 {
                     //タブ選択(or追加)
                     if (!SelectTab(out var tabName)) return;
 
                     fltDialog.SetCurrent(tabName);
-                    var post = this.CurrentTab[idx];
+
                     if (post.RetweetedId == null)
                     {
                         fltDialog.AddNewFilter(post.ScreenName, post.TextFromApi);
@@ -8119,10 +8127,6 @@ namespace OpenTween
 
             this.ApplyPostFilters();
             SaveConfigsTabs();
-
-            var listView = this.CurrentListView;
-            if (listView.SelectedIndices.Count > 0)
-                _curPost = this.CurrentTab[listView.SelectedIndices[0]];
         }
 
         protected override bool ProcessDialogKey(Keys keyData)
@@ -8221,14 +8225,14 @@ namespace OpenTween
 
         private void IDRuleMenuItem_Click(object sender, EventArgs e)
         {
-            var listView = this.CurrentListView;
+            var tab = this.CurrentTab;
+            var selectedPosts = tab.SelectedPosts;
 
-            //未選択なら処理終了
-            if (listView.SelectedIndices.Count == 0) return;
+            // 未選択なら処理終了
+            if (selectedPosts.Length == 0)
+                return;
 
-            var tab = this.CurrentTab;
-            var screenNameArray = listView.SelectedIndices.Cast<int>()
-                .Select(x => tab[x])
+            var screenNameArray = selectedPosts
                 .Select(x => x.RetweetedId != null ? x.RetweetedBy : x.ScreenName)
                 .ToArray();
 
@@ -8249,13 +8253,13 @@ namespace OpenTween
 
         private void SourceRuleMenuItem_Click(object sender, EventArgs e)
         {
-            var listView = this.CurrentListView;
-            if (listView.SelectedIndices.Count == 0)
+            var tab = this.CurrentTab;
+            var selectedPosts = tab.SelectedPosts;
+
+            if (selectedPosts.Length == 0)
                 return;
 
-            var tab = this.CurrentTab;
-            var sourceArray = listView.SelectedIndices.Cast<int>()
-                .Select(x => tab[x].Source).ToArray();
+            var sourceArray = selectedPosts.Select(x => x.Source).ToArray();
 
             this.AddFilterRuleBySource(sourceArray);
         }
@@ -8350,7 +8354,7 @@ namespace OpenTween
                     tabName = dialog.SelectedTab?.TabName;
                 }
 
-                ListTab.SelectedTab.Focus();
+                this.CurrentTabPage.Focus();
                 //新規タブを選択→タブ作成
                 if (tabName == null)
                 {
@@ -8567,8 +8571,6 @@ namespace OpenTween
                 _anchorPost = null;
                 _anchorFlag = false;
                 this.PurgeListViewItemCache();
-                _curItemIndex = -1;
-                _curPost = null;
             }
             foreach (TabPage tb in ListTab.TabPages)
             {
@@ -8598,7 +8600,7 @@ namespace OpenTween
                 SettingManager.Common.DispLatestPost != MyCommon.DispTitleEnum.Ver &&
                 SettingManager.Common.DispLatestPost != MyCommon.DispTitleEnum.OwnStatus)
             {
-                foreach (var tab in _statuses.Tabs.Values)
+                foreach (var tab in _statuses.Tabs)
                 {
                     ur += tab.UnreadCount;
                     al += tab.AllCount;
@@ -8661,7 +8663,7 @@ namespace OpenTween
             StringBuilder slbl = new StringBuilder(256);
             try
             {
-                foreach (var tab in _statuses.Tabs.Values)
+                foreach (var tab in _statuses.Tabs)
                 {
                     ur += tab.UnreadCount;
                     al += tab.AllCount;
@@ -9012,28 +9014,29 @@ namespace OpenTween
 
         private async Task doRepliedStatusOpen()
         {
-            if (this.ExistCurrentPost && _curPost.InReplyToUser != null && _curPost.InReplyToStatusId != null)
+            var currentPost = this.CurrentPost;
+            if (this.ExistCurrentPost && currentPost.InReplyToUser != null && currentPost.InReplyToStatusId != null)
             {
                 if (MyCommon.IsKeyDown(Keys.Shift))
                 {
-                    await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(_curPost.InReplyToUser, _curPost.InReplyToStatusId.Value));
+                    await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(currentPost.InReplyToUser, currentPost.InReplyToStatusId.Value));
                     return;
                 }
-                if (_statuses.ContainsKey(_curPost.InReplyToStatusId.Value))
+                if (_statuses.ContainsKey(currentPost.InReplyToStatusId.Value))
                 {
-                    PostClass repPost = _statuses[_curPost.InReplyToStatusId.Value];
+                    PostClass repPost = _statuses[currentPost.InReplyToStatusId.Value];
                     MessageBox.Show($"{repPost.ScreenName} / {repPost.Nickname}   ({repPost.CreatedAt.ToLocalTimeString()})" + Environment.NewLine + repPost.TextFromApi);
                 }
                 else
                 {
                     foreach (TabModel tb in _statuses.GetTabsByType(MyCommon.TabUsageType.Lists | MyCommon.TabUsageType.PublicSearch))
                     {
-                        if (tb == null || !tb.Contains(_curPost.InReplyToStatusId.Value)) break;
-                        PostClass repPost = _statuses[_curPost.InReplyToStatusId.Value];
+                        if (tb == null || !tb.Contains(currentPost.InReplyToStatusId.Value)) break;
+                        PostClass repPost = _statuses[currentPost.InReplyToStatusId.Value];
                         MessageBox.Show($"{repPost.ScreenName} / {repPost.Nickname}   ({repPost.CreatedAt.ToLocalTimeString()})" + Environment.NewLine + repPost.TextFromApi);
                         return;
                     }
-                    await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(_curPost.InReplyToUser, _curPost.InReplyToStatusId.Value));
+                    await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(currentPost.InReplyToUser, currentPost.InReplyToStatusId.Value));
                 }
             }
         }
@@ -9328,20 +9331,18 @@ namespace OpenTween
 
         private void MenuStrip1_MenuDeactivate(object sender, EventArgs e)
         {
+            var currentTabPage = this.CurrentTabPage;
             if (this.Tag != null) // 設定された戻り先へ遷移
             {
-                if (this.Tag == this.ListTab.SelectedTab)
-                    ((Control)this.ListTab.SelectedTab.Tag).Select();
+                if (this.Tag == currentTabPage)
+                    ((Control)currentTabPage.Tag).Select();
                 else
                     ((Control)this.Tag).Select();
             }
             else // 戻り先が指定されていない (初期状態) 場合はタブに遷移
             {
-                if (ListTab.SelectedIndex > -1 && ListTab.SelectedTab.HasChildren)
-                {
-                    this.Tag = ListTab.SelectedTab.Tag;
-                    ((Control)this.Tag).Select();
-                }
+                this.Tag = currentTabPage.Tag;
+                ((Control)this.Tag).Select();
             }
             // フォーカスがメニューに遷移したかどうかを表すフラグを降ろす
             MenuStrip1.Tag = null;
@@ -9733,16 +9734,6 @@ namespace OpenTween
             this._statuses.SelectTab(_tab.Text);
 
             var listView = this.CurrentListView;
-            if (listView.SelectedIndices.Count > 0)
-            {
-                _curItemIndex = listView.SelectedIndices[0];
-                _curPost = GetCurTabPost(_curItemIndex);
-            }
-            else
-            {
-                _curItemIndex = -1;
-                _curPost = null;
-            }
 
             _anchorPost = null;
             _anchorFlag = false;
@@ -9942,23 +9933,24 @@ namespace OpenTween
             //公式RT
             if (this.ExistCurrentPost)
             {
-                if (!_curPost.CanRetweetBy(this.twitterApi.CurrentUserId))
+                var selectedPosts = this.CurrentTab.SelectedPosts;
+
+                if (selectedPosts.Any(x => !x.CanRetweetBy(this.twitterApi.CurrentUserId)))
                 {
-                    if (this._curPost.IsProtect)
+                    if (selectedPosts.Any(x => x.IsProtect))
                         MessageBox.Show("Protected.");
 
                     _DoFavRetweetFlags = false;
                     return;
                 }
 
-                var listView = this.CurrentListView;
-                if (listView.SelectedIndices.Count > 15)
+                if (selectedPosts.Length > 15)
                 {
                     MessageBox.Show(Properties.Resources.RetweetLimitText);
                     _DoFavRetweetFlags = false;
                     return;
                 }
-                else if (listView.SelectedIndices.Count > 1)
+                else if (selectedPosts.Length > 1)
                 {
                     string QuestionText = Properties.Resources.RetweetQuestion2;
                     if (_DoFavRetweetFlags) QuestionText = Properties.Resources.FavoriteRetweetQuestionText1;
@@ -9984,13 +9976,7 @@ namespace OpenTween
                     }
                 }
 
-                var statusIds = new List<long>();
-                foreach (int idx in listView.SelectedIndices)
-                {
-                    PostClass post = GetCurTabPost(idx);
-                    if (post.CanRetweetBy(this.twitterApi.CurrentUserId))
-                        statusIds.Add(post.StatusId);
-                }
+                var statusIds = selectedPosts.Select(x => x.StatusId).ToList();
 
                 await this.RetweetAsync(statusIds);
             }
@@ -10019,11 +10005,12 @@ namespace OpenTween
 
         private async Task FavoritesRetweetUnofficial()
         {
-            if (this.ExistCurrentPost && !_curPost.IsDm)
+            var post = this.CurrentPost;
+            if (this.ExistCurrentPost && !post.IsDm)
             {
                 _DoFavRetweetFlags = true;
                 var favoriteTask = this.FavoriteChange(true);
-                if (!_curPost.IsProtect && _DoFavRetweetFlags)
+                if (!post.IsProtect && _DoFavRetweetFlags)
                 {
                     _DoFavRetweetFlags = false;
                     doReTweetUnofficial();
@@ -10069,7 +10056,7 @@ namespace OpenTween
         {
             this.tweetDetailsView.DumpPostClass = this.DumpPostClassToolStripMenuItem.Checked;
 
-            if (_curPost != null)
+            if (this.CurrentPost != null)
                 await this.DispSelectedPost(true);
         }
 
@@ -10182,7 +10169,7 @@ namespace OpenTween
 
         private async void FollowCommandMenuItem_Click(object sender, EventArgs e)
         {
-            var id = _curPost?.ScreenName ?? "";
+            var id = this.CurrentPost?.ScreenName ?? "";
 
             await this.FollowCommand(id);
         }
@@ -10222,7 +10209,7 @@ namespace OpenTween
 
         private async void RemoveCommandMenuItem_Click(object sender, EventArgs e)
         {
-            var id = _curPost?.ScreenName ?? "";
+            var id = this.CurrentPost?.ScreenName ?? "";
 
             await this.RemoveCommand(id, false);
         }
@@ -10265,7 +10252,7 @@ namespace OpenTween
 
         private async void FriendshipMenuItem_Click(object sender, EventArgs e)
         {
-            var id = _curPost?.ScreenName ?? "";
+            var id = this.CurrentPost?.ScreenName ?? "";
 
             await this.ShowFriendship(id);
         }
@@ -10420,10 +10407,11 @@ namespace OpenTween
         {
             if (this.ExistCurrentPost)
             {
-                if (_curPost.IsDm ||
-                    !StatusText.Enabled) return;
+                var post = this.CurrentPost;
+                if (post.IsDm || !StatusText.Enabled)
+                    return;
 
-                if (_curPost.IsProtect)
+                if (post.IsProtect)
                 {
                     MessageBox.Show("Protected.");
                     return;
@@ -10433,7 +10421,7 @@ namespace OpenTween
 
                 this.inReplyTo = null;
 
-                StatusText.Text += " " + MyCommon.GetStatusUrl(_curPost);
+                StatusText.Text += " " + MyCommon.GetStatusUrl(post);
 
                 (this.StatusText.SelectionStart, this.StatusText.SelectionLength) = selection;
                 StatusText.Focus();
@@ -10445,25 +10433,26 @@ namespace OpenTween
             //RT @id:内容
             if (this.ExistCurrentPost)
             {
-                if (_curPost.IsDm || !StatusText.Enabled)
+                var post = this.CurrentPost;
+                if (post.IsDm || !StatusText.Enabled)
                     return;
 
-                if (_curPost.IsProtect)
+                if (post.IsProtect)
                 {
                     MessageBox.Show("Protected.");
                     return;
                 }
-                string rtdata = _curPost.Text;
+                string rtdata = post.Text;
                 rtdata = CreateRetweetUnofficial(rtdata, this.StatusText.Multiline);
 
                 var selection = (this.StatusText.SelectionStart, this.StatusText.SelectionLength);
 
                 // 投稿時に in_reply_to_status_id を付加する
-                var inReplyToStatusId = this._curPost.RetweetedId ?? this._curPost.StatusId;
-                var inReplyToScreenName = this._curPost.ScreenName;
+                var inReplyToStatusId = post.RetweetedId ?? post.StatusId;
+                var inReplyToScreenName = post.ScreenName;
                 this.inReplyTo = (inReplyToStatusId, inReplyToScreenName);
 
-                StatusText.Text += " RT @" + _curPost.ScreenName + ": " + rtdata;
+                StatusText.Text += " RT @" + post.ScreenName + ": " + rtdata;
 
                 (this.StatusText.SelectionStart, this.StatusText.SelectionLength) = selection;
                 StatusText.Focus();
@@ -10583,7 +10572,8 @@ namespace OpenTween
                         // 関連発言なら既存のタブを置き換える
                         tb.TabName = relatedTab.TabName;
                         this.ClearTab(tb.TabName, false);
-                        _statuses.Tabs[tb.TabName] = tb;
+
+                        this._statuses.ReplaceTab(tb);
 
                         for (int i = 0; i < ListTab.TabPages.Count; i++)
                         {
@@ -10646,15 +10636,9 @@ namespace OpenTween
 
         private async Task doMoveToRTHome()
         {
-            var listView = this.CurrentListView;
-            if (listView.SelectedIndices.Count > 0)
-            {
-                PostClass post = GetCurTabPost(listView.SelectedIndices[0]);
-                if (post.RetweetedId != null)
-                {
-                    await this.OpenUriInBrowserAsync("https://twitter.com/" + GetCurTabPost(listView.SelectedIndices[0]).RetweetedBy);
-                }
-            }
+            var post = this.CurrentPost;
+            if (post != null && post.RetweetedId != null)
+                await this.OpenUriInBrowserAsync("https://twitter.com/" + post.RetweetedBy);
         }
 
         private async void MoveToRTHomeMenuItem_Click(object sender, EventArgs e)
@@ -10662,7 +10646,7 @@ namespace OpenTween
 
         private void ListManageUserContextToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            var screenName = this._curPost?.ScreenName;
+            var screenName = this.CurrentPost?.ScreenName;
             if (screenName != null)
                 this.ListManageUserContext(screenName);
         }
@@ -10812,7 +10796,8 @@ namespace OpenTween
             }
 
             var tab = this.CurrentTab;
-            if (tab.TabType == MyCommon.TabUsageType.DirectMessage || !this.ExistCurrentPost || _curPost.IsDm)
+            var post = this.CurrentPost;
+            if (tab.TabType == MyCommon.TabUsageType.DirectMessage || !this.ExistCurrentPost || post.IsDm)
             {
                 this.FavOpMenuItem.Enabled = false;
                 this.UnFavOpMenuItem.Enabled = false;
@@ -10831,7 +10816,7 @@ namespace OpenTween
                 this.OpenStatusOpMenuItem.Enabled = true;
                 this.ShowRelatedStatusesMenuItem2.Enabled = true;  //PublicSearchの時問題出るかも
 
-                if (!_curPost.CanRetweetBy(this.twitterApi.CurrentUserId))
+                if (!post.CanRetweetBy(this.twitterApi.CurrentUserId))
                 {
                     this.RtOpMenuItem.Enabled = false;
                     this.RtUnOpMenuItem.Enabled = false;
@@ -10857,8 +10842,7 @@ namespace OpenTween
             {
                 this.RefreshPrevOpMenuItem.Enabled = false;
             }
-            if (!this.ExistCurrentPost
-                || _curPost.InReplyToStatusId == null)
+            if (!this.ExistCurrentPost || post.InReplyToStatusId == null)
             {
                 OpenRepSourceOpMenuItem.Enabled = false;
             }
@@ -10866,7 +10850,7 @@ namespace OpenTween
             {
                 OpenRepSourceOpMenuItem.Enabled = true;
             }
-            if (!this.ExistCurrentPost || string.IsNullOrEmpty(_curPost.RetweetedBy))
+            if (!this.ExistCurrentPost || string.IsNullOrEmpty(post.RetweetedBy))
             {
                 OpenRterHomeMenuItem.Enabled = false;
             }
@@ -10877,7 +10861,7 @@ namespace OpenTween
 
             if (this.ExistCurrentPost)
             {
-                this.DelOpMenuItem.Enabled = this._curPost.CanDeleteBy(this.tw.UserId);
+                this.DelOpMenuItem.Enabled = post.CanDeleteBy(this.tw.UserId);
             }
         }
 
@@ -10939,8 +10923,10 @@ namespace OpenTween
                 this.CopySTOTMenuItem.Enabled = true;
                 this.CopyURLMenuItem.Enabled = true;
                 this.CopyUserIdStripMenuItem.Enabled = true;
-                if (_curPost.IsDm) this.CopyURLMenuItem.Enabled = false;
-                if (_curPost.IsProtect) this.CopySTOTMenuItem.Enabled = false;
+
+                var post = this.CurrentPost;
+                if (post.IsDm) this.CopyURLMenuItem.Enabled = false;
+                if (post.IsProtect) this.CopySTOTMenuItem.Enabled = false;
             }
         }
 
@@ -10948,7 +10934,7 @@ namespace OpenTween
             => this.SetNotifyIconText();
 
         private async void UserStatusToolStripMenuItem_Click(object sender, EventArgs e)
-            => await this.ShowUserStatus(this._curPost?.ScreenName ?? "");
+            => await this.ShowUserStatus(this.CurrentPost?.ScreenName ?? "");
 
         private async Task doShowUserStatus(string id, bool ShowInputDialog)
         {
@@ -11017,9 +11003,10 @@ namespace OpenTween
 
         private async void ShowProfileMenuItem_Click(object sender, EventArgs e)
         {
-            if (_curPost != null)
+            var post = this.CurrentPost;
+            if (post != null)
             {
-                await this.ShowUserStatus(_curPost.ScreenName, false);
+                await this.ShowUserStatus(post.ScreenName, false);
             }
         }
 
@@ -11028,7 +11015,8 @@ namespace OpenTween
             if (!this.ExistCurrentPost)
                 return;
 
-            var statusId = this._curPost.RetweetedId ?? this._curPost.StatusId;
+            var post = this.CurrentPost;
+            var statusId = post.RetweetedId ?? post.StatusId;
             TwitterStatus status;
 
             using (var dialog = new WaitingDialog(Properties.Resources.RtCountMenuItem_ClickText1))
@@ -11109,9 +11097,6 @@ namespace OpenTween
         private void SplitContainer2_MouseDoubleClick(object sender, MouseEventArgs e)
             => this.MultiLinePullDownMenuItem.PerformClick();
 
-        public PostClass CurPost
-            => this._curPost;
-
 #region "画像投稿"
         private void ImageSelectMenuItem_Click(object sender, EventArgs e)
         {
@@ -11223,7 +11208,8 @@ namespace OpenTween
 
         private void MenuItemCommand_DropDownOpening(object sender, EventArgs e)
         {
-            if (this.ExistCurrentPost && !_curPost.IsDm)
+            var post = this.CurrentPost;
+            if (this.ExistCurrentPost && !post.IsDm)
                 RtCountMenuItem.Enabled = true;
             else
                 RtCountMenuItem.Enabled = false;
@@ -11239,8 +11225,9 @@ namespace OpenTween
 
         private void CopyUserId()
         {
-            if (_curPost == null) return;
-            string clstr = _curPost.ScreenName;
+            var post = this.CurrentPost;
+            if (post == null) return;
+            var clstr = post.ScreenName;
             try
             {
                 Clipboard.SetDataObject(clstr, false, 5, 100);
@@ -11253,11 +11240,12 @@ namespace OpenTween
 
         private async void ShowRelatedStatusesMenuItem_Click(object sender, EventArgs e)
         {
-            if (this.ExistCurrentPost && !_curPost.IsDm)
+            var post = this.CurrentPost;
+            if (this.ExistCurrentPost && !post.IsDm)
             {
                 try
                 {
-                    await this.OpenRelatedTab(this._curPost);
+                    await this.OpenRelatedTab(post);
                 }
                 catch (TabException ex)
                 {
@@ -11373,7 +11361,8 @@ namespace OpenTween
                         {
                             this.PurgeListViewItemCache();
                             this.CurrentListView.Update();
-                            if (_curPost != null && _curPost.StatusId == e.StatusId)
+                            var post = this.CurrentPost;
+                            if (post != null && post.StatusId == e.StatusId)
                                 await this.DispSelectedPost(true);
                         }
                     });
@@ -11696,9 +11685,8 @@ namespace OpenTween
         {
             get
             {
-                if (_curPost == null) return false;
-                if (_curPost.IsDeleted) return false;
-                return true;
+                var post = this.CurrentPost;
+                return post != null && !post.IsDeleted;
             }
         }
 
@@ -11707,7 +11695,7 @@ namespace OpenTween
 
         private string GetUserIdFromCurPostOrInput(string caption)
         {
-            var id = _curPost?.ScreenName ?? "";
+            var id = this.CurrentPost?.ScreenName ?? "";
 
             using (InputTabName inputName = new InputTabName())
             {
@@ -11781,12 +11769,13 @@ namespace OpenTween
             {
                 if (SettingManager.Common.UserAppointUrl.Contains("{ID}") || SettingManager.Common.UserAppointUrl.Contains("{STATUS}"))
                 {
-                    if (_curPost != null)
+                    var post = this.CurrentPost;
+                    if (post != null)
                     {
                         string xUrl = SettingManager.Common.UserAppointUrl;
-                        xUrl = xUrl.Replace("{ID}", _curPost.ScreenName);
+                        xUrl = xUrl.Replace("{ID}", post.ScreenName);
 
-                        var statusId = _curPost.RetweetedId ?? _curPost.StatusId;
+                        var statusId = post.RetweetedId ?? post.StatusId;
                         xUrl = xUrl.Replace("{STATUS}", statusId.ToString());
 
                         await this.OpenUriInBrowserAsync(xUrl);