Bläddra i källkod

Disconnect/Reconnect Session commands + Tab of a session that fails to connect/reconnect is not closed

Source commit: 546c99291ae6bc7a109fb54d172f2937d2f58630
Martin Prikryl 6 år sedan
förälder
incheckning
ea24ee3405

+ 4 - 4
source/components/ThemePageControl.cpp

@@ -122,7 +122,7 @@ void __fastcall TThemePageControl::PaintWindow(HDC DC)
   ::SendMessage(Handle, TCM_ADJUSTRECT, FALSE, (LPARAM)&PageRect);
 
   ClientRect.Top = PageRect.Top - 2;
-  DrawThemesXpTabItem(DC, -1, ClientRect, true, 0);
+  DrawThemesXpTabItem(DC, -1, ClientRect, true, 0, false);
 
   // 2nd paint the inactive tabs
 
@@ -165,12 +165,12 @@ void __fastcall TThemePageControl::DrawThemesXpTab(HDC DC, int Tab)
   {
     State = TIS_SELECTED;
   }
-  DrawThemesXpTabItem(DC, Tab, Rect, false, State);
+  DrawThemesXpTabItem(DC, Tab, Rect, false, State, Shadowed);
 }
 //----------------------------------------------------------------------------------------------------------
 // This function draws Themes Tab control parts: a) Tab-Body and b) Tab-tabs
 void __fastcall TThemePageControl::DrawThemesXpTabItem(HDC DC, int Item,
-  const TRect & Rect, bool Body, int State)
+  const TRect & Rect, bool Body, int State, bool Shadowed)
 {
   TSize Size = Rect.Size;
 
@@ -210,7 +210,7 @@ void __fastcall TThemePageControl::DrawThemesXpTabItem(HDC DC, int Item,
 
   if (!Body && (Item >= 0))
   {
-    DrawTabItem(DCMem, Item, Rect, RectItemMem, (State == TIS_SELECTED), (State == TIS_DISABLED));
+    DrawTabItem(DCMem, Item, Rect, RectItemMem, (State == TIS_SELECTED), Shadowed);
   }
 
   // Blit image to the screen

+ 1 - 1
source/components/ThemePageControl.h

@@ -48,7 +48,7 @@ protected:
 
 private:
   void __fastcall DrawThemesXpTab(HDC DC, int Tab);
-  void __fastcall DrawThemesXpTabItem(HDC DC, int Item, const TRect & Rect, bool Body, int State);
+  void __fastcall DrawThemesXpTabItem(HDC DC, int Item, const TRect & Rect, bool Body, int State, bool Selected);
   void __fastcall DrawTabItem(HDC DC, int Item, TRect TabRect, TRect Rect, bool Selected, bool Shadowed);
   void __fastcall DrawThemesPart(HDC DC, int PartId, int StateId, LPCWSTR PartNameID, LPRECT Rect);
   void __fastcall InvalidateTab(int Index);

+ 7 - 3
source/components/UnixDirView.cpp

@@ -507,7 +507,8 @@ void __fastcall TUnixDirView::SetDriveView(TCustomUnixDriveView * Value)
 void __fastcall TUnixDirView::DoSetTerminal(TTerminal * value, bool Replace)
 {
   DebugUsedParam(Replace);
-  if (FTerminal != value)
+  if ((FTerminal != value) ||
+      ((FTerminal != NULL) && !FTerminal->Active)) // Abused by TCustomScpExplorerForm::DisconnectSession
   {
     if (FTerminal)
     {
@@ -549,6 +550,10 @@ void __fastcall TUnixDirView::DoSetTerminal(TTerminal * value, bool Replace)
         DoStartReadDirectory(FTerminal); // just for style and the assertions
         DoReadDirectoryImpl(FTerminal, false);
       }
+      else
+      {
+        PathChanged(); // To clear path combo box
+      }
     }
     UpdatePathLabel();
   }
@@ -586,10 +591,9 @@ void __fastcall TUnixDirView::DoReadDirectoryImpl(TObject * /*Sender*/, bool Rel
   FLoading = false;
 
 #ifndef DESIGN_ONLY
+  CancelEdit();
   if (Terminal->Active)
   {
-    CancelEdit();
-
     if (ReloadOnly)
     {
       Reload(false);

+ 5 - 3
source/components/UnixDriveView.cpp

@@ -74,11 +74,11 @@ void __fastcall TCustomUnixDriveView::CreateWnd()
 //---------------------------------------------------------------------------
 void __fastcall TCustomUnixDriveView::SetTerminal(TTerminal * value)
 {
-  if (FTerminal != value)
+  #ifndef DESIGN_ONLY
+  if ((FTerminal != value) || ((FTerminal != NULL) && !FTerminal->Active)) // Abused by TCustomScpExplorerForm::DisconnectSession
   {
     FTerminal = value;
     Items->Clear();
-    #ifndef DESIGN_ONLY
     // If terminal is not active initially, we will never load fixed paths, when it become active.
     // But actually terminal is not active here, only when we are replacing an abandoned terminal
     // with a dummy one (which will never become active)
@@ -93,8 +93,10 @@ void __fastcall TCustomUnixDriveView::SetTerminal(TTerminal * value)
         }
       }
     }
-    #endif
   }
+  #else
+  DebugUsedParam(value);
+  #endif
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomUnixDriveView::SetDirView(TUnixDirView * Value)

+ 55 - 6
source/forms/CustomScpExplorer.cpp

@@ -612,7 +612,7 @@ void __fastcall TCustomScpExplorerForm::TerminalChanged(bool Replaced)
       }
     }
 
-    if (!Replaced)
+    if (!Replaced && Terminal->Active)
     {
       InitStatusBar();
     }
@@ -1675,7 +1675,7 @@ bool __fastcall TCustomScpExplorerForm::DirViewEnabled(TOperationSide Side)
 {
   DebugAssert(GetSide(Side) == osRemote);
   DebugUsedParam(Side);
-  return (Terminal != NULL);
+  return (Terminal != NULL) && Terminal->Active;
 }
 //---------------------------------------------------------------------------
 bool __fastcall TCustomScpExplorerForm::GetEnableFocusedOperation(
@@ -4837,6 +4837,30 @@ void __fastcall TCustomScpExplorerForm::CloseSession()
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::DisconnectSession()
+{
+  if (CanCloseQueue())
+  {
+    TManagedTerminal * ManagedTerminal = dynamic_cast<TManagedTerminal *>(Terminal);
+    TTerminalManager::Instance()->DisconnectActiveTerminal();
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::TerminalDisconnected()
+{
+  RemoteDirView->Terminal = Terminal;
+  UpdateRemotePathComboBox(false);
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::ReconnectSession()
+{
+  if (DebugAlwaysTrue(!Terminal->Active))
+  {
+    TTerminalManager::Instance()->ReconnectActiveTerminal();
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::OpenStoredSession(TSessionData * Data)
 {
   if (OpenInNewWindow())
@@ -6544,6 +6568,7 @@ void __fastcall TCustomScpExplorerForm::DoTerminalListChanged()
       {
         TabSheet->ImageIndex = FNewSessionTabImageIndex;
         TabSheet->Tag = 0; // not really needed
+        TabSheet->Shadowed = false;
         // We know that we are at the last page, otherwise we could not call this (it assumes that new session tab is the last one)
         UpdateNewSessionTab();
       }
@@ -7001,6 +7026,10 @@ void __fastcall TCustomScpExplorerForm::ShowExtendedException(
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::TerminalReady()
 {
+  if (Terminal->Active)
+  {
+    InitStatusBar();
+  }
   // cannot rely on active page being page for active terminal,
   // as it can happen that active page is the "new session" page
   // (e.g. when reconnecting active terminal, while login dialog
@@ -8259,7 +8288,7 @@ UnicodeString __fastcall TCustomScpExplorerForm::FileStatusBarText(
   {
     Result = FormatIncrementalSearchStatus(FIncrementalSearch, FIncrementalSearchHaveNext);
   }
-  else if (!IsSideLocalBrowser(Side) && (Terminal == NULL))
+  else if (!IsSideLocalBrowser(Side) && ((Terminal == NULL) || (dynamic_cast<TManagedTerminal *>(Terminal)->Disconnected)))
   {
     // noop
   }
@@ -8414,15 +8443,24 @@ void __fastcall TCustomScpExplorerForm::UpdateControls()
   // See also EnableControl
   if (Showing)
   {
-    bool HasTerminal = (Terminal != NULL) && Terminal->Active;
-    if (HasTerminal)
+    if (Terminal != NULL)
     {
       // Update path when it changes
       if ((SessionsPageControl->ActivePage != NULL) && (GetSessionTabTerminal(SessionsPageControl->ActivePage) == Terminal))
       {
         UpdateSessionTab(SessionsPageControl->ActivePage);
       }
+    }
 
+    NonVisualDataModule->ReconnectSessionAction->Update();
+    ReconnectToolbar->Visible = NonVisualDataModule->ReconnectSessionAction->Visible;
+    // ReconnectSessionAction is hidden when disabled, so enabling it actualy resizes the toolbar
+    CenterReconnectToolbar();
+
+    bool HasTerminal = (Terminal != NULL) && Terminal->Active;
+
+    if (HasTerminal)
+    {
       // TODO needed yet with second local browser?
       if (!RemoteDirView->Enabled)
       {
@@ -8970,6 +9008,12 @@ void __fastcall TCustomScpExplorerForm::CMShowingChanged(TMessage & Message)
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::CenterReconnectToolbar()
+{
+  ReconnectToolbar->Left = (ReconnectToolbar->Parent->ClientWidth - ReconnectToolbar->Width) / 2;
+  ReconnectToolbar->Top = (ReconnectToolbar->Parent->ClientHeight - ReconnectToolbar->Height) / 2;
+}
+//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::FormConstrainedResize(
   TObject * /*Sender*/, int & MinWidth, int & MinHeight, int & MaxWidth,
   int & MaxHeight)
@@ -9309,7 +9353,7 @@ void __fastcall TCustomScpExplorerForm::UpdateRemotePathComboBox(bool TextOnly)
     try
     {
       Items->Clear();
-      if (Terminal != NULL)
+      if ((Terminal != NULL) && !RemoteDirView->Path.IsEmpty())
       {
         UnicodeString APath = UnixExcludeTrailingBackslash(RemoteDirView->Path);
         while (!IsUnixRootPath(APath))
@@ -10554,3 +10598,8 @@ void __fastcall TCustomScpExplorerForm::RemoteStatusBarMouseDown(TObject *, TMou
   CountClicksForWindowPrint(this);
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::RemoteDirViewResize(TObject *)
+{
+  CenterReconnectToolbar();
+}
+//---------------------------------------------------------------------------

+ 16 - 0
source/forms/CustomScpExplorer.dfm

@@ -92,6 +92,7 @@ object CustomScpExplorerForm: TCustomScpExplorerForm
         OnExit = DirViewExit
         OnKeyDown = DirViewKeyDown
         OnKeyPress = DirViewKeyPress
+        OnResize = RemoteDirViewResize
         NortonLike = nlOff
         UnixColProperties.ExtWidth = 20
         UnixColProperties.TypeVisible = False
@@ -118,6 +119,21 @@ object CustomScpExplorerForm: TCustomScpExplorerForm
         OnDisplayProperties = RemoteDirViewDisplayProperties
         OnRead = RemoteDirViewRead
       end
+      object ReconnectToolbar: TTBXToolbar
+        Left = 136
+        Top = 112
+        Width = 107
+        Height = 21
+        Caption = 'ReconnectToolbar'
+        Images = GlyphsModule.ExplorerImages
+        Options = [tboShowHint]
+        ParentShowHint = False
+        ShowHint = True
+        TabOrder = 1
+        object TBXItem254: TTBXItem
+          Action = NonVisualDataModule.ReconnectSessionAction
+        end
+      end
     end
     object RemoteDrivePanel: TPanel
       Left = 0

+ 7 - 0
source/forms/CustomScpExplorer.h

@@ -103,6 +103,8 @@ __published:
   TTBXItem *QueueDeleteAllDoneQueueToolbarItem;
   TTBXItem *TBXItem173;
   TApplicationEvents *ApplicationEvents;
+  TTBXToolbar *ReconnectToolbar;
+  TTBXItem *TBXItem254;
   void __fastcall ApplicationMinimize(TObject * Sender);
   void __fastcall ApplicationRestore(TObject * Sender);
   void __fastcall RemoteDirViewContextPopup(TObject *Sender,
@@ -203,6 +205,7 @@ __published:
   void __fastcall ApplicationEventsModalBegin(TObject *Sender);
   void __fastcall DirViewChangeFocus(TObject *Sender, TListItem *Item);
   void __fastcall RemoteStatusBarMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y);
+  void __fastcall RemoteDirViewResize(TObject *Sender);
 
 private:
   TTerminal * FTerminal;
@@ -678,6 +681,7 @@ protected:
   TListItem * __fastcall SearchFile(const UnicodeString & Text, bool SkipCurrent, bool Reverse);
   void __fastcall CMDialogKey(TWMKeyDown & Message);
   DYNAMIC void __fastcall Deactivate();
+  void __fastcall CenterReconnectToolbar();
 
 public:
   virtual __fastcall ~TCustomScpExplorerForm();
@@ -712,6 +716,8 @@ public:
   void __fastcall DuplicateSession();
   void __fastcall RenameSession();
   void __fastcall CloseSession();
+  void __fastcall DisconnectSession();
+  void __fastcall ReconnectSession();
   void __fastcall OpenDirectory(TOperationSide Side);
   virtual void __fastcall HomeDirectory(TOperationSide Side);
   void __fastcall ReloadDirectory(TOperationSide Side);
@@ -748,6 +754,7 @@ public:
   UnicodeString __fastcall GetQueueProgressTitle();
   void __fastcall LastTerminalClosed(TObject * Sender);
   void __fastcall TerminalRemoved(TObject * Sender);
+  void __fastcall TerminalDisconnected();
   void __fastcall TerminalListChanged(TObject * Sender);
   void __fastcall ApplicationTitleChanged();
   unsigned int __fastcall MoreMessageDialog(const UnicodeString Message,

+ 7 - 3
source/forms/NonVisual.cpp

@@ -136,7 +136,7 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
     return;
   }
   void * Param;
-  #define HasTerminal (ScpExplorer->Terminal != NULL)
+  #define HasTerminal (ScpExplorer->Terminal != NULL) && ScpExplorer->Terminal->Active
   // CURRENT DIRVIEW
   #define EnabledSelectedOperation (ScpExplorer->EnableSelectedOperation[osCurrent])
   #define EnabledFocusedOperation (ScpExplorer->EnableFocusedOperation[osCurrent])
@@ -400,7 +400,9 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
   UPD(SiteManagerAction, true)
   UPD(DuplicateSessionAction, HasTerminal)
   UPD(RenameSessionAction, HasTerminal)
-  UPD(CloseSessionAction, HasTerminal)
+  UPD(CloseSessionAction2, (ScpExplorer->Terminal != NULL))
+  UPDEX1(DisconnectSessionAction, HasTerminal, DisconnectSessionAction->Visible = (ScpExplorer->Terminal == NULL) || !dynamic_cast<TManagedTerminal *>(ScpExplorer->Terminal)->Disconnected)
+  UPDEX1(ReconnectSessionAction, (ScpExplorer->Terminal != NULL) && dynamic_cast<TManagedTerminal *>(ScpExplorer->Terminal)->Disconnected, ReconnectSessionAction->Visible = ReconnectSessionAction->Enabled)
   UPD(SavedSessionsAction2, true)
   UPD(WorkspacesAction, StoredSessions->HasAnyWorkspace())
   UPD(OpenedSessionsAction, HasTerminal)
@@ -717,7 +719,9 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
     EXE(SiteManagerAction, ScpExplorer->NewSession(true))
     EXE(DuplicateSessionAction, ScpExplorer->DuplicateSession())
     EXE(RenameSessionAction, ScpExplorer->RenameSession())
-    EXE(CloseSessionAction, ScpExplorer->CloseSession())
+    EXE(CloseSessionAction2, ScpExplorer->CloseSession())
+    EXE(DisconnectSessionAction, ScpExplorer->DisconnectSession())
+    EXE(ReconnectSessionAction, ScpExplorer->ReconnectSession())
     EXE(SavedSessionsAction2, CreateSessionListMenu(SavedSessionsAction2))
     EXE(WorkspacesAction, CreateWorkspacesMenu(WorkspacesAction))
     EXE(OpenedSessionsAction, CreateOpenedSessionListMenu(OpenedSessionsAction))

+ 24 - 4
source/forms/NonVisual.dfm

@@ -622,16 +622,30 @@ object NonVisualDataModule: TNonVisualDataModule
         'Site Manager|Opens site manager (hold down Shift to open site ma' +
         'nager in new window)'
     end
-    object CloseSessionAction: TAction
+    object CloseSessionAction2: TAction
       Tag = 15
       Category = 'Session'
-      Caption = '&Disconnect'
-      Hint = 'Close session|Terminate current session'
+      Caption = '&Close Session'
+      Hint = 'Close session|Terminate the current session and close the tab'
       ImageIndex = 26
       SecondaryShortCuts.Strings = (
         'Ctrl+W')
       ShortCut = 24644
     end
+    object DisconnectSessionAction: TAction
+      Tag = 15
+      Category = 'Session'
+      Caption = '&Disconnect Session'
+      Hint = 
+        'Disconnect session|Disconnect the current session, but keep the ' +
+        'tab opened'
+    end
+    object ReconnectSessionAction: TAction
+      Tag = 15
+      Category = 'Session'
+      Caption = '&Reconnect Session'
+      Hint = 'Reconnect session|Reconnect the current disconnected session'
+    end
     object SavedSessionsAction2: TAction
       Tag = 15
       Category = 'Session'
@@ -3009,7 +3023,13 @@ object NonVisualDataModule: TNonVisualDataModule
     Left = 480
     Top = 176
     object TBXItem124: TTBXItem
-      Action = CloseSessionAction
+      Action = CloseSessionAction2
+    end
+    object TBXItem79: TTBXItem
+      Action = DisconnectSessionAction
+    end
+    object TBXItem80: TTBXItem
+      Action = ReconnectSessionAction
     end
     object TBXItem219: TTBXItem
       Action = DuplicateSessionAction

+ 5 - 1
source/forms/NonVisual.h

@@ -110,7 +110,7 @@ __published:    // IDE-managed Components
   TTimer *SessionIdleTimer;
   TAction *NewSessionAction;
   TAction *SiteManagerAction;
-  TAction *CloseSessionAction;
+  TAction *CloseSessionAction2;
   TAction *SavedSessionsAction2;
   TAction *WorkspacesAction;
   TAction *ExplorerSessionBandAction;
@@ -620,6 +620,10 @@ __published:    // IDE-managed Components
   TTBXItem *TBXItem78;
   TAction *CurrentCopyAction;
   TAction *FileColorsPreferencesAction;
+  TAction *DisconnectSessionAction;
+  TTBXItem *TBXItem79;
+  TAction *ReconnectSessionAction;
+  TTBXItem *TBXItem80;
   void __fastcall ExplorerActionsUpdate(TBasicAction *Action, bool &Handled);
   void __fastcall ExplorerActionsExecute(TBasicAction *Action, bool &Handled);
   void __fastcall SessionIdleTimerTimer(TObject *Sender);

+ 8 - 2
source/forms/ScpCommander.dfm

@@ -415,7 +415,13 @@ inherited ScpCommanderForm: TScpCommanderForm
           Action = NonVisualDataModule.NewSessionAction
         end
         object TBXItem115: TTBXItem
-          Action = NonVisualDataModule.CloseSessionAction
+          Action = NonVisualDataModule.CloseSessionAction2
+        end
+        object TBXItem252: TTBXItem
+          Action = NonVisualDataModule.DisconnectSessionAction
+        end
+        object TBXItem253: TTBXItem
+          Action = NonVisualDataModule.ReconnectSessionAction
         end
         object TBXItem218: TTBXItem
           Action = NonVisualDataModule.DuplicateSessionAction
@@ -843,7 +849,7 @@ inherited ScpCommanderForm: TScpCommanderForm
         Action = NonVisualDataModule.DuplicateSessionAction
       end
       object TBXItem124: TTBXItem
-        Action = NonVisualDataModule.CloseSessionAction
+        Action = NonVisualDataModule.CloseSessionAction2
       end
       object TBXItem125: TTBXItem
         Action = NonVisualDataModule.SaveCurrentSessionAction2

+ 2 - 0
source/forms/ScpCommander.h

@@ -433,6 +433,8 @@ __published:
   TTBXItem *TBXItem245;
   TTBXSeparatorItem *TBXSeparatorItem64;
   TTBXItem *TBXItem251;
+  TTBXItem *TBXItem252;
+  TTBXItem *TBXItem253;
   void __fastcall SplitterMoved(TObject *Sender);
   void __fastcall SplitterCanResize(TObject *Sender, int &NewSize,
     bool &Accept);

+ 9 - 3
source/forms/ScpExplorer.dfm

@@ -134,7 +134,7 @@ inherited ScpExplorerForm: TScpExplorerForm
         object TBXSeparatorItem1: TTBXSeparatorItem
         end
         object TBXItem1: TTBXItem
-          Action = NonVisualDataModule.CloseSessionAction
+          Action = NonVisualDataModule.CloseSessionAction2
         end
         object TBXItem2: TTBXItem
           Action = NonVisualDataModule.CloseApplicationAction
@@ -291,7 +291,13 @@ inherited ScpExplorerForm: TScpExplorerForm
           Action = NonVisualDataModule.NewSessionAction
         end
         object TBXItem115: TTBXItem
-          Action = NonVisualDataModule.CloseSessionAction
+          Action = NonVisualDataModule.CloseSessionAction2
+        end
+        object TBXItem162: TTBXItem
+          Action = NonVisualDataModule.DisconnectSessionAction
+        end
+        object TBXItem163: TTBXItem
+          Action = NonVisualDataModule.ReconnectSessionAction
         end
         object TBXItem90: TTBXItem
           Action = NonVisualDataModule.DuplicateSessionAction
@@ -765,7 +771,7 @@ inherited ScpExplorerForm: TScpExplorerForm
         Action = NonVisualDataModule.DuplicateSessionAction
       end
       object TBXItem124: TTBXItem
-        Action = NonVisualDataModule.CloseSessionAction
+        Action = NonVisualDataModule.CloseSessionAction2
       end
       object TBXItem125: TTBXItem
         Action = NonVisualDataModule.SaveCurrentSessionAction2

+ 2 - 0
source/forms/ScpExplorer.h

@@ -320,6 +320,8 @@ __published:
   TTBXItem *TBXItem127;
   TTBXSeparatorItem *TBXSeparatorItem43;
   TTBXItem *TBXItem161;
+  TTBXItem *TBXItem162;
+  TTBXItem *TBXItem163;
   void __fastcall RemoteDirViewUpdateStatusBar(TObject *Sender,
           const TStatusFileInfo &FileInfo);
   void __fastcall UnixPathComboBoxBeginEdit(TTBEditItem *Sender,

+ 24 - 7
source/windows/TerminalManager.cpp

@@ -31,7 +31,7 @@ __fastcall TManagedTerminal::TManagedTerminal(TSessionData * SessionData,
   TConfiguration * Configuration) :
   TTerminal(SessionData, Configuration),
   LocalExplorerState(NULL), RemoteExplorerState(NULL),
-  ReopenStart(0), DirectoryLoaded(Now()), TerminalThread(NULL)
+  ReopenStart(0), DirectoryLoaded(Now()), TerminalThread(NULL), Disconnected(false)
 {
   StateData = new TSessionData(L"");
   StateData->Assign(SessionData);
@@ -249,6 +249,7 @@ void __fastcall TTerminalManager::DoConnectTerminal(TTerminal * Terminal, bool R
           ManagedTerminal->ReopenStart = Now();
         }
 
+        ManagedTerminal->Disconnected = false;
         DebugAssert(ManagedTerminal->TerminalThread == NULL);
         ManagedTerminal->TerminalThread = TerminalThread;
       }
@@ -391,7 +392,7 @@ bool __fastcall TTerminalManager::ConnectActiveTerminalImpl(bool Reopen)
 
   if (Action == tpFree)
   {
-    FreeActiveTerminal();
+    DisconnectActiveTerminal();
   }
 
   return Result;
@@ -447,6 +448,10 @@ bool __fastcall TTerminalManager::ConnectActiveTerminal()
 void __fastcall TTerminalManager::DisconnectActiveTerminal()
 {
   DebugAssert(ActiveTerminal);
+  if (ActiveTerminal->Active)
+  {
+    ActiveTerminal->Close();
+  }
 
   int Index = IndexOf(ActiveTerminal);
 
@@ -457,6 +462,15 @@ void __fastcall TTerminalManager::DisconnectActiveTerminal()
   FQueues->Items[Index] = NewQueue;
   ScpExplorer->Queue = NewQueue;
   delete OldQueue;
+
+  dynamic_cast<TManagedTerminal *>(ActiveTerminal)->Disconnected = true;
+  if (ScpExplorer != NULL)
+  {
+    TerminalReady(); // in case it was never connected
+    ScpExplorer->TerminalDisconnected();
+  }
+  // disconnecting duplidate session removes need to distinguish the only connected session with short path
+  DoTerminalListChanged();
 }
 //---------------------------------------------------------------------------
 void __fastcall TTerminalManager::ReconnectActiveTerminal()
@@ -484,7 +498,7 @@ void __fastcall TTerminalManager::ReconnectActiveTerminal()
   }
   catch(...)
   {
-    FreeActiveTerminal();
+    DisconnectActiveTerminal();
     throw;
   }
 }
@@ -611,7 +625,7 @@ void __fastcall TTerminalManager::DoSetActiveTerminal(TTerminal * value, bool Au
     UpdateAppTitle();
     if (ScpExplorer)
     {
-      if (ActiveTerminal && (ActiveTerminal->Status == ssOpened))
+      if (ActiveTerminal && ((ActiveTerminal->Status == ssOpened) || dynamic_cast<TManagedTerminal *>(ActiveTerminal)->Disconnected))
       {
         TerminalReady();
       }
@@ -662,7 +676,9 @@ void __fastcall TTerminalManager::DoSetActiveTerminal(TTerminal * value, bool Au
       }
     }
 
-    if ((ActiveTerminal != NULL) && !ActiveTerminal->Active)
+
+    if ((ActiveTerminal != NULL) && !ActiveTerminal->Active &&
+        !dynamic_cast<TManagedTerminal *>(ActiveTerminal)->Disconnected)
     {
       ConnectActiveTerminal();
     }
@@ -1320,13 +1336,14 @@ UnicodeString __fastcall TTerminalManager::GetTerminalTitle(TTerminal * Terminal
   if (Unique)
   {
     int Index = IndexOf(Terminal);
-    // not for background transfer sessions
-    if (Index >= 0)
+    // not for background transfer sessions and disconnected sessions
+    if ((Index >= 0) && Terminal->Active)
     {
       for (int Index2 = 0; Index2 < Count; Index2++)
       {
         UnicodeString Name = Terminals[Index2]->SessionData->SessionName;
         if ((Terminals[Index2] != Terminal) &&
+            Terminals[Index2]->Active &&
             SameText(Name, Result))
         {
           UnicodeString Path = GetTerminalShortPath(Terminal);

+ 3 - 0
source/windows/TerminalManager.h

@@ -28,6 +28,9 @@ public:
   TDateTime DirectoryLoaded;
   TTerminalThread * TerminalThread;
   TDateTime QueueOperationStart;
+  // To distinguish sessions that were explicitly disconnected and
+  // should not be reconnected when their tab is activated.
+  bool Disconnected;
 };
 //---------------------------------------------------------------------------
 class TTerminalManager : public TTerminalList

+ 2 - 1
source/windows/UserInterface.cpp

@@ -228,6 +228,7 @@ void __fastcall ShowExtendedExceptionEx(TTerminal * Terminal,
     {
       if (ForActiveTerminal)
       {
+        DebugAssert(!Terminal->Active);
         Manager->DisconnectActiveTerminal();
       }
 
@@ -355,7 +356,7 @@ void __fastcall ShowExtendedExceptionEx(TTerminal * Terminal,
     {
       if (ForActiveTerminal)
       {
-        Manager->FreeActiveTerminal();
+        Manager->DisconnectActiveTerminal();
       }
     }
   }