QueueController.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <Common.h>
  5. #include <CoreMain.h>
  6. #include <Queue.h>
  7. #include <TextsWin.h>
  8. #include <GUITools.h>
  9. #include <WinConfiguration.h>
  10. #include "QueueController.h"
  11. #include <BaseUtils.hpp>
  12. //---------------------------------------------------------------------------
  13. #pragma package(smart_init)
  14. //---------------------------------------------------------------------------
  15. __fastcall TQueueController::TQueueController(TListView * ListView)
  16. {
  17. FListView = ListView;
  18. DebugAssert(FListView != NULL);
  19. DebugAssert(FListView->OnDblClick == NULL);
  20. FListView->OnDblClick = QueueViewDblClick;
  21. DebugAssert(FListView->OnKeyDown == NULL);
  22. FListView->OnKeyDown = QueueViewKeyDown;
  23. DebugAssert(FListView->OnCustomDrawItem == NULL);
  24. FListView->OnCustomDrawItem = QueueViewCustomDrawItem;
  25. FQueueStatus = NULL;
  26. FOnChange = NULL;
  27. RememberConfiguration();
  28. }
  29. //---------------------------------------------------------------------------
  30. __fastcall TQueueController::~TQueueController()
  31. {
  32. DebugAssert(FListView->OnDblClick == QueueViewDblClick);
  33. FListView->OnDblClick = NULL;
  34. DebugAssert(FListView->OnKeyDown == QueueViewKeyDown);
  35. FListView->OnKeyDown = NULL;
  36. DebugAssert(FListView->OnCustomDrawItem == QueueViewCustomDrawItem);
  37. FListView->OnCustomDrawItem = NULL;
  38. }
  39. //---------------------------------------------------------------------------
  40. TQueueItemProxy * __fastcall TQueueController::QueueViewItemToQueueItem(
  41. TListItem * Item, bool * Detail)
  42. {
  43. // previously this method was based on ActiveCount and DoneCount,
  44. // as if we were inconfident about validity of Item->Data pointers,
  45. // not sure why
  46. TQueueItemProxy * QueueItem = static_cast<TQueueItemProxy *>(Item->Data);
  47. if (Detail != NULL)
  48. {
  49. (*Detail) = false;
  50. int Index = Item->Index;
  51. if (Index > 0)
  52. {
  53. TQueueItemProxy * PrevQueueItem = static_cast<TQueueItemProxy *>(Item->Data);
  54. if (PrevQueueItem == QueueItem)
  55. {
  56. (*Detail) = true;
  57. }
  58. }
  59. }
  60. return QueueItem;
  61. }
  62. //---------------------------------------------------------------------------
  63. TQueueOperation __fastcall TQueueController::DefaultOperation()
  64. {
  65. TQueueItemProxy * QueueItem;
  66. if (FListView->ItemFocused != NULL)
  67. {
  68. QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);
  69. switch (QueueItem->Status)
  70. {
  71. case TQueueItem::qsPending:
  72. return qoItemExecute;
  73. case TQueueItem::qsQuery:
  74. return qoItemQuery;
  75. case TQueueItem::qsError:
  76. return qoItemError;
  77. case TQueueItem::qsPrompt:
  78. return qoItemPrompt;
  79. case TQueueItem::qsProcessing:
  80. return qoItemPause;
  81. case TQueueItem::qsPaused:
  82. return qoItemResume;
  83. }
  84. }
  85. return qoNone;
  86. }
  87. //---------------------------------------------------------------------------
  88. bool __fastcall TQueueController::AllowOperation(
  89. TQueueOperation Operation, void ** Param)
  90. {
  91. TQueueItemProxy * QueueItem = NULL;
  92. if (FListView->ItemFocused != NULL)
  93. {
  94. QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);
  95. }
  96. switch (Operation)
  97. {
  98. case qoItemUserAction:
  99. return (QueueItem != NULL) && TQueueItem::IsUserActionStatus(QueueItem->Status);
  100. case qoItemQuery:
  101. return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsQuery);
  102. case qoItemError:
  103. return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsError);
  104. case qoItemPrompt:
  105. return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsPrompt);
  106. case qoItemDelete:
  107. return (QueueItem != NULL);
  108. case qoItemExecute:
  109. return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsPending);
  110. case qoItemUp:
  111. return (QueueItem != NULL) &&
  112. (QueueItem->Status == TQueueItem::qsPending) &&
  113. // it's not first pending item,
  114. // this is based on assumption that pending items occupy single line always
  115. (FListView->ItemFocused->Index > 0) &&
  116. (QueueViewItemToQueueItem(FListView->Items->Item[FListView->ItemFocused->Index - 1])->Status == TQueueItem::qsPending);
  117. case qoItemDown:
  118. return (QueueItem != NULL) &&
  119. (QueueItem->Status == TQueueItem::qsPending) &&
  120. (FListView->ItemFocused->Index < (FListView->Items->Count - 1));
  121. case qoItemPause:
  122. return (QueueItem != NULL) &&
  123. (QueueItem->Status == TQueueItem::qsProcessing);
  124. case qoItemResume:
  125. return (QueueItem != NULL) &&
  126. (QueueItem->Status == TQueueItem::qsPaused);
  127. case qoItemSpeed:
  128. {
  129. bool Result = (QueueItem != NULL) && (QueueItem->Status != TQueueItem::qsDone);
  130. if (Result && (Param != NULL))
  131. {
  132. Result = QueueItem->GetCPSLimit(*reinterpret_cast<unsigned long *>(Param));
  133. }
  134. return Result;
  135. }
  136. case qoPauseAll:
  137. case qoResumeAll:
  138. {
  139. TQueueItem::TStatus Status =
  140. (Operation == qoPauseAll) ? TQueueItem::qsProcessing : TQueueItem::qsPaused;
  141. bool Result = false;
  142. // can be NULL when action update is triggered while disconnecting
  143. if (FQueueStatus != NULL)
  144. {
  145. for (int i = FQueueStatus->DoneCount; !Result && (i < FQueueStatus->DoneAndActiveCount); i++)
  146. {
  147. QueueItem = FQueueStatus->Items[i];
  148. Result = (QueueItem->Status == Status);
  149. }
  150. }
  151. return Result;
  152. }
  153. case qoDeleteAllDone:
  154. return (FQueueStatus != NULL) && (FQueueStatus->DoneCount > 0);
  155. case qoDeleteAll:
  156. return (FQueueStatus != NULL) && (FQueueStatus->Count > 0);
  157. default:
  158. DebugFail();
  159. return false;
  160. }
  161. }
  162. //---------------------------------------------------------------------------
  163. void __fastcall TQueueController::ExecuteOperation(TQueueOperation Operation,
  164. void * Param)
  165. {
  166. TQueueItemProxy * QueueItem = NULL;
  167. if (FListView->ItemFocused != NULL)
  168. {
  169. QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);
  170. }
  171. switch (Operation)
  172. {
  173. case qoItemUserAction:
  174. case qoItemQuery:
  175. case qoItemError:
  176. case qoItemPrompt:
  177. if (QueueItem != NULL)
  178. {
  179. QueueItem->ProcessUserAction();
  180. }
  181. break;
  182. case qoItemExecute:
  183. if (QueueItem != NULL)
  184. {
  185. QueueItem->ExecuteNow();
  186. }
  187. break;
  188. case qoItemUp:
  189. case qoItemDown:
  190. if (QueueItem != NULL)
  191. {
  192. QueueItem->Move(Operation == qoItemUp);
  193. }
  194. break;
  195. case qoItemDelete:
  196. if (QueueItem != NULL)
  197. {
  198. QueueItem->Delete();
  199. }
  200. break;
  201. case qoItemPause:
  202. if (QueueItem != NULL)
  203. {
  204. QueueItem->Pause();
  205. }
  206. break;
  207. case qoItemResume:
  208. if (QueueItem != NULL)
  209. {
  210. QueueItem->Resume();
  211. }
  212. break;
  213. case qoItemSpeed:
  214. if (QueueItem != NULL)
  215. {
  216. QueueItem->SetCPSLimit(reinterpret_cast<unsigned long>(Param));
  217. }
  218. break;
  219. case qoPauseAll:
  220. case qoResumeAll:
  221. {
  222. for (int i = FQueueStatus->DoneCount; i < FQueueStatus->DoneAndActiveCount; i++)
  223. {
  224. QueueItem = FQueueStatus->Items[i];
  225. if ((Operation == qoPauseAll) && (QueueItem->Status == TQueueItem::qsProcessing))
  226. {
  227. QueueItem->Pause();
  228. }
  229. else if ((Operation == qoResumeAll) && (QueueItem->Status == TQueueItem::qsPaused))
  230. {
  231. QueueItem->Resume();
  232. }
  233. }
  234. }
  235. break;
  236. case qoDeleteAllDone:
  237. case qoDeleteAll:
  238. {
  239. int Count = (Operation == qoDeleteAll) ? FQueueStatus->Count : FQueueStatus->DoneCount;
  240. for (int i = 0; i < Count; i++)
  241. {
  242. QueueItem = FQueueStatus->Items[i];
  243. QueueItem->Delete();
  244. }
  245. }
  246. break;
  247. default:
  248. DebugFail();
  249. break;
  250. }
  251. }
  252. //---------------------------------------------------------------------------
  253. void __fastcall TQueueController::FillQueueViewItem(TListItem * Item,
  254. TQueueItemProxy * QueueItem, bool Detail, bool OnlyLine)
  255. {
  256. DebugAssert(!Detail || (QueueItem->Status != TQueueItem::qsPending));
  257. DebugAssert((Item->Data == NULL) || (Item->Data == QueueItem));
  258. Item->Data = QueueItem;
  259. UnicodeString ProgressStr;
  260. int Image = -1;
  261. switch (QueueItem->Status)
  262. {
  263. case TQueueItem::qsDone:
  264. ProgressStr = LoadStr(QUEUE_DONE);
  265. break;
  266. case TQueueItem::qsPending:
  267. ProgressStr = LoadStr(QUEUE_PENDING);
  268. break;
  269. case TQueueItem::qsConnecting:
  270. ProgressStr = LoadStr(QUEUE_CONNECTING);
  271. break;
  272. case TQueueItem::qsQuery:
  273. ProgressStr = LoadStr(QUEUE_QUERY);
  274. Image = 4;
  275. break;
  276. case TQueueItem::qsError:
  277. ProgressStr = LoadStr(QUEUE_ERROR);
  278. Image = 5;
  279. break;
  280. case TQueueItem::qsPrompt:
  281. ProgressStr = LoadStr(QUEUE_PROMPT);
  282. Image = 6;
  283. break;
  284. case TQueueItem::qsPaused:
  285. ProgressStr = LoadStr(QUEUE_PAUSED);
  286. Image = 7;
  287. break;
  288. }
  289. bool BlinkHide = QueueItemNeedsFrequentRefresh(QueueItem) &&
  290. !QueueItem->ProcessingUserAction &&
  291. ((GetTickCount() % MSecsPerSec) >= (MSecsPerSec/2));
  292. int State = -1;
  293. UnicodeString Values[6];
  294. TFileOperationProgressType * ProgressData = QueueItem->ProgressData;
  295. TQueueItem::TInfo * Info = QueueItem->Info;
  296. if (!Detail && Info->Primary)
  297. {
  298. switch (Info->Operation)
  299. {
  300. case foCopy:
  301. State = ((Info->Side == osLocal) ? 2 : 0);
  302. break;
  303. case foMove:
  304. State = ((Info->Side == osLocal) ? 3 : 1);
  305. break;
  306. }
  307. if (!OnlyLine)
  308. {
  309. Image = -1;
  310. ProgressStr = L"";
  311. }
  312. // If both are empty, it's bootstrap item => do not show anything
  313. if (!Info->Source.IsEmpty() || !Info->Destination.IsEmpty())
  314. {
  315. // cannot use ProgressData->Temp as it is set only after the transfer actually starts
  316. Values[0] = Info->Source.IsEmpty() ? LoadStr(PROGRESS_TEMP_DIR) : Info->Source;
  317. Values[1] = Info->Destination.IsEmpty() ? LoadStr(PROGRESS_TEMP_DIR) : Info->Destination;
  318. }
  319. __int64 TotalTransferred = QueueItem->TotalTransferred;
  320. if (TotalTransferred >= 0)
  321. {
  322. Values[2] =
  323. FormatPanelBytes(TotalTransferred, WinConfiguration->FormatSizeBytes);
  324. }
  325. if (ProgressData != NULL)
  326. {
  327. if (ProgressData->Operation == Info->Operation)
  328. {
  329. if (QueueItem->Status != TQueueItem::qsDone)
  330. {
  331. if (ProgressData->TotalSizeSet)
  332. {
  333. Values[3] = FormatDateTimeSpan(Configuration->TimeFormat, ProgressData->TotalTimeLeft());
  334. }
  335. else
  336. {
  337. Values[3] = FormatDateTimeSpan(Configuration->TimeFormat, ProgressData->TimeElapsed());
  338. }
  339. Values[4] = FORMAT(L"%s/s", (FormatBytes(ProgressData->CPS())));
  340. }
  341. if (ProgressStr.IsEmpty())
  342. {
  343. ProgressStr = FORMAT(L"%d%%", (ProgressData->OverallProgress()));
  344. }
  345. }
  346. else if (ProgressData->Operation == foCalculateSize)
  347. {
  348. ProgressStr = LoadStr(QUEUE_CALCULATING_SIZE);
  349. }
  350. }
  351. Values[5] = ProgressStr;
  352. }
  353. else
  354. {
  355. if (ProgressData != NULL)
  356. {
  357. if ((Info->Side == osRemote) || !ProgressData->Temp)
  358. {
  359. Values[0] = ProgressData->FileName;
  360. }
  361. else
  362. {
  363. Values[0] = ExtractFileName(ProgressData->FileName);
  364. }
  365. if (ProgressData->Operation == Info->Operation)
  366. {
  367. Values[2] =
  368. FormatPanelBytes(ProgressData->TransferredSize, WinConfiguration->FormatSizeBytes);
  369. if (ProgressStr.IsEmpty())
  370. {
  371. ProgressStr = FORMAT(L"%d%%", (ProgressData->TransferProgress()));
  372. }
  373. }
  374. }
  375. Values[5] = ProgressStr;
  376. }
  377. Item->StateIndex = (!BlinkHide ? State : -1);
  378. Item->ImageIndex = (!BlinkHide ? Image : -1);
  379. for (size_t Index = 0; Index < LENOF(Values); Index++)
  380. {
  381. if (Index < static_cast<size_t>(Item->SubItems->Count))
  382. {
  383. Item->SubItems->Strings[Index] = Values[Index];
  384. }
  385. else
  386. {
  387. Item->SubItems->Add(Values[Index]);
  388. }
  389. }
  390. }
  391. //---------------------------------------------------------------------------
  392. TListItem * __fastcall TQueueController::InsertItemFor(TQueueItemProxy * QueueItem, int Index)
  393. {
  394. TListItem * Item;
  395. if (Index == FListView->Items->Count)
  396. {
  397. Item = FListView->Items->Add();
  398. }
  399. else if (FListView->Items->Item[Index]->Data != QueueItem)
  400. {
  401. Item = FListView->Items->Insert(Index);
  402. }
  403. else
  404. {
  405. Item = FListView->Items->Item[Index];
  406. DebugAssert(Item->Data == QueueItem);
  407. }
  408. return Item;
  409. }
  410. //---------------------------------------------------------------------------
  411. void __fastcall TQueueController::UpdateQueueStatus(
  412. TTerminalQueueStatus * QueueStatus)
  413. {
  414. FQueueStatus = QueueStatus;
  415. if (FQueueStatus != NULL)
  416. {
  417. TQueueItemProxy * QueueItem;
  418. TListItem * Item;
  419. int Index = 0;
  420. for (int ItemIndex = 0; ItemIndex < FQueueStatus->Count; ItemIndex++)
  421. {
  422. QueueItem = FQueueStatus->Items[ItemIndex];
  423. int Index2 = Index;
  424. while ((Index2 < FListView->Items->Count) &&
  425. (FListView->Items->Item[Index2]->Data != QueueItem))
  426. {
  427. Index2++;
  428. }
  429. if (Index2 < FListView->Items->Count)
  430. {
  431. while (Index < Index2)
  432. {
  433. FListView->Items->Delete(Index);
  434. Index2--;
  435. }
  436. }
  437. Item = InsertItemFor(QueueItem, Index);
  438. bool HasDetailsLine = UseDetailsLine(ItemIndex, QueueItem);
  439. FillQueueViewItem(Item, QueueItem, false, !HasDetailsLine);
  440. Index++;
  441. DebugAssert((QueueItem->Status != TQueueItem::qsPending) ==
  442. (ItemIndex < FQueueStatus->DoneAndActiveCount));
  443. if (HasDetailsLine)
  444. {
  445. Item = InsertItemFor(QueueItem, Index);
  446. FillQueueViewItem(Item, QueueItem, true, false);
  447. Index++;
  448. }
  449. }
  450. while (Index < FListView->Items->Count)
  451. {
  452. FListView->Items->Delete(Index);
  453. }
  454. }
  455. else
  456. {
  457. FListView->Items->Clear();
  458. }
  459. DoChange();
  460. }
  461. //---------------------------------------------------------------------------
  462. bool __fastcall TQueueController::UseDetailsLine(int ItemIndex, TQueueItemProxy * QueueItem)
  463. {
  464. return
  465. (ItemIndex >= FQueueStatus->DoneCount) &&
  466. (ItemIndex < FQueueStatus->DoneAndActiveCount) &&
  467. QueueItem->Info->Primary &&
  468. !QueueItem->Info->SingleFile &&
  469. ((QueueItem->ProgressData == NULL) || !QueueItem->ProgressData->Done);
  470. }
  471. //---------------------------------------------------------------------------
  472. void __fastcall TQueueController::RefreshQueueItem(TQueueItemProxy * QueueItem)
  473. {
  474. TListItem * NextListItem = NULL;
  475. TListItem * ListItem;
  476. ListItem = FListView->FindData(0, QueueItem, true, false);
  477. DebugAssert(ListItem != NULL);
  478. int Index = ListItem->Index;
  479. if (Index + 1 < FListView->Items->Count)
  480. {
  481. NextListItem = FListView->Items->Item[Index + 1];
  482. if (NextListItem->Data != QueueItem)
  483. {
  484. NextListItem = NULL;
  485. }
  486. }
  487. bool HasDetailsLine = UseDetailsLine(QueueItem->Index, QueueItem);
  488. FillQueueViewItem(ListItem, QueueItem, false, !HasDetailsLine);
  489. if (HasDetailsLine)
  490. {
  491. if (NextListItem == NULL)
  492. {
  493. NextListItem = FListView->Items->Insert(Index + 1);
  494. }
  495. FillQueueViewItem(NextListItem, QueueItem, true, false);
  496. }
  497. else
  498. {
  499. if (NextListItem != NULL)
  500. {
  501. NextListItem->Delete();
  502. }
  503. }
  504. DoChange();
  505. }
  506. //---------------------------------------------------------------------------
  507. bool __fastcall TQueueController::QueueItemNeedsFrequentRefresh(
  508. TQueueItemProxy * QueueItem)
  509. {
  510. return
  511. (TQueueItem::IsUserActionStatus(QueueItem->Status) ||
  512. (QueueItem->Status == TQueueItem::qsPaused));
  513. }
  514. //---------------------------------------------------------------------------
  515. void __fastcall TQueueController::DoChange()
  516. {
  517. if (FOnChange != NULL)
  518. {
  519. FOnChange(NULL);
  520. }
  521. }
  522. //---------------------------------------------------------------------------
  523. void __fastcall TQueueController::QueueViewDblClick(TObject * /*Sender*/)
  524. {
  525. TQueueOperation Operation = DefaultOperation();
  526. if (Operation != qoNone)
  527. {
  528. ExecuteOperation(Operation);
  529. }
  530. }
  531. //---------------------------------------------------------------------------
  532. void __fastcall TQueueController::QueueViewKeyDown(TObject * /*Sender*/,
  533. WORD & Key, TShiftState /*Shift*/)
  534. {
  535. if (Key == VK_RETURN)
  536. {
  537. TQueueOperation Operation = DefaultOperation();
  538. if (Operation != qoNone)
  539. {
  540. ExecuteOperation(Operation);
  541. }
  542. Key = 0;
  543. }
  544. else if (Key == VK_DELETE)
  545. {
  546. ExecuteOperation(qoItemDelete);
  547. Key = 0;
  548. }
  549. }
  550. //---------------------------------------------------------------------------
  551. void __fastcall TQueueController::QueueViewCustomDrawItem(TCustomListView * Sender,
  552. TListItem * Item, TCustomDrawState /*State*/, bool & /*DefaultDraw*/)
  553. {
  554. TQueueItemProxy * QueueItem = QueueViewItemToQueueItem(Item);
  555. if (QueueItem->Status == TQueueItem::qsDone)
  556. {
  557. Sender->Canvas->Font->Color = clGrayText;
  558. }
  559. }
  560. //---------------------------------------------------------------------------
  561. bool __fastcall TQueueController::GetEmpty()
  562. {
  563. return (FQueueStatus == NULL) || (FQueueStatus->Count == 0);
  564. }
  565. //---------------------------------------------------------------------------
  566. void __fastcall TQueueController::RememberConfiguration()
  567. {
  568. FFormatSizeBytes = WinConfiguration->FormatSizeBytes;
  569. }
  570. //---------------------------------------------------------------------------
  571. bool __fastcall TQueueController::NeedRefresh()
  572. {
  573. bool Result = (WinConfiguration->FormatSizeBytes != FFormatSizeBytes);
  574. RememberConfiguration();
  575. return Result;
  576. }