TerminalManager.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "TerminalManager.h"
  5. #include "CustomScpExplorer.h"
  6. #include "LogMemo.h"
  7. #include "NonVisual.h"
  8. #include "WinConfiguration.h"
  9. #include "UserInterface.h"
  10. #include <Log.h>
  11. #include <OperationStatus.h>
  12. #include <Common.h>
  13. #include <ScpMain.h>
  14. #include <TextsWin.h>
  15. //---------------------------------------------------------------------------
  16. #pragma package(smart_init)
  17. //---------------------------------------------------------------------------
  18. TTerminalManager * TTerminalManager::FInstance = NULL;
  19. //---------------------------------------------------------------------------
  20. TTerminalManager * __fastcall TTerminalManager::Instance()
  21. {
  22. if (!FInstance)
  23. {
  24. FInstance = new TTerminalManager();
  25. }
  26. return FInstance;
  27. }
  28. //---------------------------------------------------------------------------
  29. void __fastcall TTerminalManager::DestroyInstance()
  30. {
  31. assert(FInstance);
  32. SAFE_DESTROY(FInstance);
  33. }
  34. //---------------------------------------------------------------------------
  35. __fastcall TTerminalManager::TTerminalManager() :
  36. TTerminalList(Configuration)
  37. {
  38. FLogMemo = NULL;
  39. FActiveTerminal = NULL;
  40. FScpExplorer = NULL;
  41. FDestroying = false;
  42. FTerminalPendingAction = tpNull;
  43. assert(Application && !Application->OnException);
  44. Application->OnException = ApplicationException;
  45. assert(Configuration && !Configuration->OnChange);
  46. Configuration->OnChange = ConfigurationChange;
  47. FOnLastTerminalClosed = NULL;
  48. FOnTerminalListChanged = NULL;
  49. FTerminalList = new TStringList();
  50. }
  51. //---------------------------------------------------------------------------
  52. __fastcall TTerminalManager::~TTerminalManager()
  53. {
  54. FreeAll();
  55. assert(!ScpExplorer);
  56. assert(Configuration->OnChange == ConfigurationChange);
  57. Configuration->OnChange = NULL;
  58. assert(Application && (Application->OnException == ApplicationException));
  59. Application->OnException = NULL;
  60. delete FTerminalList;
  61. }
  62. //---------------------------------------------------------------------------
  63. TTerminal * __fastcall TTerminalManager::NewTerminal(TSessionData * Data)
  64. {
  65. FTerminalList->Clear();
  66. TTerminal * Terminal = TTerminalList::NewTerminal(Data);
  67. try
  68. {
  69. Terminal->OnQueryUser = TerminalQueryUser;
  70. if (!ActiveTerminal)
  71. {
  72. ActiveTerminal = Terminal;
  73. }
  74. }
  75. catch(...)
  76. {
  77. FreeTerminal(Terminal);
  78. throw;
  79. }
  80. if (OnTerminalListChanged)
  81. {
  82. OnTerminalListChanged(this);
  83. }
  84. return Terminal;
  85. }
  86. //---------------------------------------------------------------------------
  87. void __fastcall TTerminalManager::FreeActiveTerminal()
  88. {
  89. if (FTerminalPendingAction == tpNull)
  90. {
  91. assert(ActiveTerminal);
  92. FreeTerminal(ActiveTerminal);
  93. }
  94. else
  95. {
  96. assert(FTerminalPendingAction == tpNone);
  97. FTerminalPendingAction = tpFree;
  98. }
  99. }
  100. //---------------------------------------------------------------------------
  101. bool __fastcall TTerminalManager::ConnectActiveTerminal()
  102. {
  103. TTerminalPendingAction Action;
  104. bool Result;
  105. do
  106. {
  107. Action = tpNull;
  108. Result = false;
  109. try
  110. {
  111. assert(ActiveTerminal);
  112. bool ShowLogPending = false;
  113. if (Configuration->Logging && (WinConfiguration->LogView == lvWindow))
  114. {
  115. if (WinConfiguration->LogWindowOnStartup)
  116. {
  117. RequireLogForm(LogMemo);
  118. }
  119. else
  120. {
  121. ShowLogPending = true;
  122. }
  123. }
  124. TOperationStatusForm * Form = new TOperationStatusForm(Application);
  125. Busy(true);
  126. try
  127. {
  128. Form->SecureShell = ActiveTerminal;
  129. Form->Show();
  130. ActiveTerminal->Open();
  131. ActiveTerminal->DoStartup();
  132. }
  133. __finally
  134. {
  135. Busy(false);
  136. delete Form;
  137. }
  138. if (ScpExplorer)
  139. {
  140. assert(ActiveTerminal->Status == sshReady);
  141. TerminalReady();
  142. }
  143. WinConfiguration->ClearTemporaryLoginData();
  144. if (LogForm && (WinConfiguration->LogView != lvWindow))
  145. {
  146. FreeLogForm();
  147. }
  148. if (ShowLogPending)
  149. {
  150. RequireLogForm(LogMemo);
  151. }
  152. Result = true;
  153. }
  154. catch(Exception & E)
  155. {
  156. assert(FTerminalPendingAction == tpNull);
  157. FTerminalPendingAction = tpNone;
  158. try
  159. {
  160. ShowExtendedException(&E, this);
  161. Action = FTerminalPendingAction;
  162. }
  163. __finally
  164. {
  165. FTerminalPendingAction = tpNull;
  166. }
  167. }
  168. }
  169. while (Action == tpReconnect);
  170. if (Action == tpFree)
  171. {
  172. FreeActiveTerminal();
  173. }
  174. return Result;
  175. }
  176. //---------------------------------------------------------------------------
  177. void __fastcall TTerminalManager::ReconnectActiveTerminal()
  178. {
  179. assert(ActiveTerminal);
  180. TTerminal * Terminal;
  181. if (ScpExplorer)
  182. {
  183. TSessionData * Data = new TSessionData(ActiveTerminal->SessionData->Name);
  184. try
  185. {
  186. Data->Assign(ActiveTerminal->SessionData);
  187. if (ScpExplorer->Terminal == ActiveTerminal)
  188. {
  189. ScpExplorer->UpdateSessionData(Data);
  190. }
  191. Terminal = NewTerminal(Data);
  192. }
  193. __finally
  194. {
  195. delete Data;
  196. }
  197. }
  198. else
  199. {
  200. // otherwise the ScpExplorer would be created already
  201. assert(ActiveTerminal->Status < sshReady);
  202. Terminal = NewTerminal(ActiveTerminal->SessionData);
  203. }
  204. try
  205. {
  206. FreeTerminal(ActiveTerminal);
  207. ActiveTerminal = Terminal;
  208. if (FTerminalPendingAction == tpNull)
  209. {
  210. ConnectActiveTerminal();
  211. }
  212. else
  213. {
  214. FTerminalPendingAction = tpReconnect;
  215. }
  216. }
  217. catch(...)
  218. {
  219. FreeTerminal(Terminal);
  220. throw;
  221. }
  222. }
  223. //---------------------------------------------------------------------------
  224. void __fastcall TTerminalManager::FreeAll()
  225. {
  226. FDestroying = true;
  227. try
  228. {
  229. while (Count)
  230. {
  231. FreeTerminal(Terminals[0]);
  232. }
  233. }
  234. __finally
  235. {
  236. FDestroying = false;
  237. }
  238. }
  239. //---------------------------------------------------------------------------
  240. void __fastcall TTerminalManager::FreeTerminal(TTerminal * Terminal)
  241. {
  242. try
  243. {
  244. Terminal->Active = false;
  245. }
  246. __finally
  247. {
  248. int Index = IndexOf(Terminal);
  249. FTerminalList->Clear();
  250. Extract(Terminal);
  251. if (ActiveTerminal && (Terminal == ActiveTerminal))
  252. {
  253. if ((Count > 0) && !FDestroying)
  254. {
  255. for (int i = 0; i < Count; i++)
  256. {
  257. if (Terminals[i]->Status == sshReady)
  258. {
  259. ActiveTerminal = Terminals[i];
  260. break;
  261. }
  262. }
  263. if (ActiveTerminal == Terminal)
  264. {
  265. ActiveTerminal = Terminals[Index];
  266. }
  267. }
  268. else
  269. {
  270. ActiveTerminal = NULL;
  271. }
  272. }
  273. else
  274. {
  275. SaveTerminal(Terminal);
  276. }
  277. delete Terminal;
  278. if (OnTerminalListChanged)
  279. {
  280. OnTerminalListChanged(this);
  281. }
  282. }
  283. }
  284. //---------------------------------------------------------------------------
  285. void __fastcall TTerminalManager::SetScpExplorer(TCustomScpExplorerForm * value)
  286. {
  287. if (ScpExplorer != value)
  288. {
  289. // changing explorer is not supported yet
  290. assert(!ScpExplorer || !value);
  291. FScpExplorer = value;
  292. if (FScpExplorer)
  293. {
  294. assert(!OnChangeTerminal);
  295. FScpExplorer->Terminal = ActiveTerminal;
  296. FOnLastTerminalClosed = FScpExplorer->LastTerminalClosed;
  297. FOnTerminalListChanged = FScpExplorer->TerminalListChanged;
  298. }
  299. else
  300. {
  301. FOnLastTerminalClosed = NULL;
  302. FOnTerminalListChanged = NULL;
  303. }
  304. }
  305. }
  306. //---------------------------------------------------------------------------
  307. void __fastcall TTerminalManager::SetActiveTerminal(TTerminal * value)
  308. {
  309. if (ActiveTerminal != value)
  310. {
  311. if (ActiveTerminal && ScpExplorer)
  312. {
  313. assert(!ScpExplorer->Terminal || (ScpExplorer->Terminal == ActiveTerminal));
  314. if (ScpExplorer->Terminal == ActiveTerminal)
  315. {
  316. ScpExplorer->UpdateSessionData();
  317. }
  318. }
  319. TTerminal * PActiveTerminal = ActiveTerminal;
  320. FActiveTerminal = NULL;
  321. if (OnChangeTerminal)
  322. {
  323. OnChangeTerminal(this);
  324. }
  325. FActiveTerminal = value;
  326. if (ActiveTerminal)
  327. {
  328. Application->Title = FMTLOAD(APP_CAPTION, (ActiveTerminalTitle, AppName));
  329. }
  330. else
  331. {
  332. // moved from else block of next if (ActiveTerminal) statement
  333. // so ScpExplorer can update its caption
  334. Application->Title = AppName;
  335. }
  336. if (ScpExplorer)
  337. {
  338. if (ActiveTerminal && (ActiveTerminal->Status == sshReady))
  339. {
  340. TerminalReady();
  341. }
  342. else
  343. {
  344. ScpExplorer->Terminal = NULL;
  345. }
  346. }
  347. if (PActiveTerminal && !PActiveTerminal->Active)
  348. {
  349. SaveTerminal(PActiveTerminal);
  350. }
  351. if (ActiveTerminal)
  352. {
  353. if (!PActiveTerminal)
  354. {
  355. CreateLogMemo();
  356. }
  357. assert(LogMemo);
  358. LogMemo->SessionLog = ActiveTerminal->Log;
  359. }
  360. else
  361. {
  362. if (LogForm)
  363. {
  364. FreeLogForm();
  365. }
  366. FreeLogMemo();
  367. if (OnLastTerminalClosed)
  368. {
  369. OnLastTerminalClosed(this);
  370. }
  371. }
  372. }
  373. }
  374. //---------------------------------------------------------------------------
  375. void __fastcall TTerminalManager::SaveTerminal(TTerminal * Terminal)
  376. {
  377. if (!Terminal->SessionData->Name.IsEmpty())
  378. {
  379. TSessionData * Data;
  380. Data = (TSessionData *)StoredSessions->FindByName(Terminal->SessionData->Name);
  381. if (Data)
  382. {
  383. Data->Assign(Terminal->SessionData);
  384. StoredSessions->Save();
  385. }
  386. }
  387. }
  388. //---------------------------------------------------------------------------
  389. void __fastcall TTerminalManager::CreateLogMemo()
  390. {
  391. assert(!FLogMemo);
  392. assert(ActiveTerminal);
  393. FLogMemo = new TLogMemo(Application);
  394. try
  395. {
  396. FLogMemo->SessionLog = ActiveTerminal->Log;
  397. FLogMemo->PopupMenu = NonVisualDataModule->LogMemoPopup;
  398. }
  399. catch (...)
  400. {
  401. delete FLogMemo;
  402. throw;
  403. }
  404. }
  405. //---------------------------------------------------------------------------
  406. void __fastcall TTerminalManager::FreeLogMemo()
  407. {
  408. assert(LogMemo);
  409. LogMemo->PopupMenu = NULL;
  410. SAFE_DESTROY(FLogMemo);
  411. }
  412. //---------------------------------------------------------------------------
  413. void __fastcall TTerminalManager::ApplicationException(TObject * Sender, Exception * E)
  414. {
  415. ShowExtendedException(E, Sender);
  416. }
  417. //---------------------------------------------------------------------------
  418. void __fastcall TTerminalManager::TerminalQueryUser(TObject * /*Sender*/,
  419. const AnsiString Query, TStrings * MoreMessages, int Answers,
  420. int Params, int & Answer, TQueryType Type)
  421. {
  422. AnsiString AQuery = Query;
  423. if (Params & qpFatalAbort)
  424. {
  425. AQuery = FMTLOAD(WARN_FATAL_ERROR, (AQuery));
  426. }
  427. int MessageParams = 0;
  428. if (Params & qpNeverAskAgainCheck)
  429. {
  430. MessageParams |= mpNeverAskAgainCheck;
  431. }
  432. if (Params & qpAllowContinueOnError)
  433. {
  434. MessageParams |= mpAllowContinueOnError;
  435. }
  436. if (ScpExplorer)
  437. {
  438. Answer = ScpExplorer->MoreMessageDialog(AQuery, MoreMessages, Type, Answers, 0, MessageParams);
  439. }
  440. else
  441. {
  442. Answer = MoreMessageDialog(AQuery, MoreMessages, Type, Answers, 0, MessageParams);
  443. }
  444. }
  445. //---------------------------------------------------------------------------
  446. void __fastcall TTerminalManager::ConfigurationChange(TObject * /*Sender*/)
  447. {
  448. assert(Configuration);
  449. assert(Configuration == WinConfiguration);
  450. if (!Application->Terminated && Configuration->Logging &&
  451. (WinConfiguration->LogView == lvWindow))
  452. {
  453. if (ActiveTerminal)
  454. {
  455. RequireLogForm(LogMemo);
  456. }
  457. }
  458. else
  459. {
  460. FreeLogForm();
  461. }
  462. if (ActiveTerminal)
  463. {
  464. assert(ActiveTerminal->Log);
  465. ActiveTerminal->Log->ReflectSettings();
  466. }
  467. if (ScpExplorer)
  468. {
  469. ScpExplorer->ConfigurationChanged();
  470. }
  471. }
  472. //---------------------------------------------------------------------------
  473. void __fastcall TTerminalManager::TerminalReady()
  474. {
  475. ScpExplorer->Terminal = ActiveTerminal;
  476. if (OnChangeTerminal)
  477. {
  478. OnChangeTerminal(this);
  479. }
  480. }
  481. //---------------------------------------------------------------------------
  482. TStrings * __fastcall TTerminalManager::GetTerminalList()
  483. {
  484. if (FTerminalList->Count != Count)
  485. {
  486. for (int i = 0; i < Count; i++)
  487. {
  488. AnsiString NameN;
  489. AnsiString Name = Terminals[i]->SessionData->SessionName;
  490. int Number = 1;
  491. NameN = Name;
  492. while (FTerminalList->IndexOf(NameN) >= 0)
  493. {
  494. Number++;
  495. NameN = FORMAT("%s (%d)", (Name, Number));
  496. }
  497. if (Number > 1)
  498. {
  499. Name = FORMAT("%s (%d)", (Name, Number));
  500. }
  501. FTerminalList->AddObject(Name, Terminals[i]);
  502. }
  503. }
  504. return FTerminalList;
  505. }
  506. //---------------------------------------------------------------------------
  507. int __fastcall TTerminalManager::GetActiveTerminalIndex()
  508. {
  509. return ActiveTerminal ? IndexOf(ActiveTerminal) : -1;
  510. }
  511. //---------------------------------------------------------------------------
  512. AnsiString __fastcall TTerminalManager::GetActiveTerminalTitle()
  513. {
  514. AnsiString Result = ActiveTerminal ?
  515. TerminalList->Strings[IndexOf(ActiveTerminal)] : AnsiString("");
  516. return Result;
  517. }