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