QueueController.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  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 "QueueController.h"
  10. #include <BaseUtils.hpp>
  11. //---------------------------------------------------------------------------
  12. #pragma package(smart_init)
  13. //---------------------------------------------------------------------------
  14. __fastcall TQueueController::TQueueController(TListView * ListView)
  15. {
  16. FListView = ListView;
  17. assert(FListView != NULL);
  18. assert(FListView->OnDblClick == NULL);
  19. FListView->OnDblClick = QueueViewDblClick;
  20. assert(FListView->OnKeyDown == NULL);
  21. FListView->OnKeyDown = QueueViewKeyDown;
  22. assert(FListView->OnCustomDrawItem == NULL);
  23. FListView->OnCustomDrawItem = QueueViewCustomDrawItem;
  24. FQueueStatus = NULL;
  25. FOnChange = NULL;
  26. }
  27. //---------------------------------------------------------------------------
  28. __fastcall TQueueController::~TQueueController()
  29. {
  30. assert(FListView->OnDblClick == QueueViewDblClick);
  31. FListView->OnDblClick = NULL;
  32. assert(FListView->OnKeyDown == QueueViewKeyDown);
  33. FListView->OnKeyDown = NULL;
  34. assert(FListView->OnCustomDrawItem == QueueViewCustomDrawItem);
  35. FListView->OnCustomDrawItem = NULL;
  36. }
  37. //---------------------------------------------------------------------------
  38. TQueueItemProxy * __fastcall TQueueController::QueueViewItemToQueueItem(
  39. TListItem * Item, bool * Detail)
  40. {
  41. // previously this method was based on ActiveCount and DoneCount,
  42. // as if we were inconfident about validity of Item->Data pointers,
  43. // not sure why
  44. TQueueItemProxy * QueueItem = static_cast<TQueueItemProxy *>(Item->Data);
  45. if (Detail != NULL)
  46. {
  47. (*Detail) = false;
  48. int Index = Item->Index;
  49. if (Index > 0)
  50. {
  51. TQueueItemProxy * PrevQueueItem = static_cast<TQueueItemProxy *>(Item->Data);
  52. if (PrevQueueItem == QueueItem)
  53. {
  54. (*Detail) = true;
  55. }
  56. }
  57. }
  58. return QueueItem;
  59. }
  60. //---------------------------------------------------------------------------
  61. TQueueOperation __fastcall TQueueController::DefaultOperation()
  62. {
  63. TQueueItemProxy * QueueItem;
  64. if (FListView->ItemFocused != NULL)
  65. {
  66. QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);
  67. switch (QueueItem->Status)
  68. {
  69. case TQueueItem::qsPending:
  70. return qoItemExecute;
  71. case TQueueItem::qsQuery:
  72. return qoItemQuery;
  73. case TQueueItem::qsError:
  74. return qoItemError;
  75. case TQueueItem::qsPrompt:
  76. return qoItemPrompt;
  77. case TQueueItem::qsProcessing:
  78. return qoItemPause;
  79. case TQueueItem::qsPaused:
  80. return qoItemResume;
  81. }
  82. }
  83. return qoNone;
  84. }
  85. //---------------------------------------------------------------------------
  86. bool __fastcall TQueueController::AllowOperation(
  87. TQueueOperation Operation, void ** Param)
  88. {
  89. TQueueItemProxy * QueueItem = NULL;
  90. if (FListView->ItemFocused != NULL)
  91. {
  92. QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);
  93. }
  94. switch (Operation)
  95. {
  96. case qoItemUserAction:
  97. return (QueueItem != NULL) && TQueueItem::IsUserActionStatus(QueueItem->Status);
  98. case qoItemQuery:
  99. return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsQuery);
  100. case qoItemError:
  101. return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsError);
  102. case qoItemPrompt:
  103. return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsPrompt);
  104. case qoItemDelete:
  105. return (QueueItem != NULL);
  106. case qoItemExecute:
  107. return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsPending);
  108. case qoItemUp:
  109. return (QueueItem != NULL) &&
  110. (QueueItem->Status == TQueueItem::qsPending) &&
  111. // it's not first pending item,
  112. // this is based on assumption that pending items occupy single line always
  113. (FListView->ItemFocused->Index > 0) &&
  114. (QueueViewItemToQueueItem(FListView->Items->Item[FListView->ItemFocused->Index - 1])->Status == TQueueItem::qsPending);
  115. case qoItemDown:
  116. return (QueueItem != NULL) &&
  117. (QueueItem->Status == TQueueItem::qsPending) &&
  118. (FListView->ItemFocused->Index < (FListView->Items->Count - 1));
  119. case qoItemPause:
  120. return (QueueItem != NULL) &&
  121. (QueueItem->Status == TQueueItem::qsProcessing);
  122. case qoItemResume:
  123. return (QueueItem != NULL) &&
  124. (QueueItem->Status == TQueueItem::qsPaused);
  125. case qoItemSpeed:
  126. {
  127. bool Result = (QueueItem != NULL) && (QueueItem->Status != TQueueItem::qsDone);
  128. if (Result && (Param != NULL))
  129. {
  130. *Param = reinterpret_cast<void *>(QueueItem->ProgressData != NULL ?
  131. QueueItem->ProgressData->CPSLimit : 0);
  132. }
  133. return Result;
  134. }
  135. case qoPauseAll:
  136. case qoResumeAll:
  137. {
  138. TQueueItem::TStatus Status =
  139. (Operation == qoPauseAll) ? TQueueItem::qsProcessing : TQueueItem::qsPaused;
  140. bool Result = false;
  141. // can be NULL when action update is triggered while disconnecting
  142. if (FQueueStatus != NULL)
  143. {
  144. for (int i = FQueueStatus->DoneCount; !Result && (i < FQueueStatus->DoneAndActiveCount); i++)
  145. {
  146. QueueItem = FQueueStatus->Items[i];
  147. Result = (QueueItem->Status == Status);
  148. }
  149. }
  150. return Result;
  151. }
  152. case qoDeleteAllDone:
  153. return (FQueueStatus != NULL) && (FQueueStatus->DoneCount > 0);
  154. default:
  155. assert(false);
  156. return false;
  157. }
  158. }
  159. //---------------------------------------------------------------------------
  160. void __fastcall TQueueController::ExecuteOperation(TQueueOperation Operation,
  161. void * Param)
  162. {
  163. TQueueItemProxy * QueueItem = NULL;
  164. if (FListView->ItemFocused != NULL)
  165. {
  166. QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);
  167. }
  168. switch (Operation)
  169. {
  170. case qoItemUserAction:
  171. case qoItemQuery:
  172. case qoItemError:
  173. case qoItemPrompt:
  174. if (QueueItem != NULL)
  175. {
  176. QueueItem->ProcessUserAction();
  177. }
  178. break;
  179. case qoItemExecute:
  180. if (QueueItem != NULL)
  181. {
  182. QueueItem->ExecuteNow();
  183. }
  184. break;
  185. case qoItemUp:
  186. case qoItemDown:
  187. if (QueueItem != NULL)
  188. {
  189. QueueItem->Move(Operation == qoItemUp);
  190. }
  191. break;
  192. case qoItemDelete:
  193. if (QueueItem != NULL)
  194. {
  195. QueueItem->Delete();
  196. }
  197. break;
  198. case qoItemPause:
  199. if (QueueItem != NULL)
  200. {
  201. QueueItem->Pause();
  202. }
  203. break;
  204. case qoItemResume:
  205. if (QueueItem != NULL)
  206. {
  207. QueueItem->Resume();
  208. }
  209. break;
  210. case qoItemSpeed:
  211. if (QueueItem != NULL)
  212. {
  213. QueueItem->SetCPSLimit(reinterpret_cast<unsigned long>(Param));
  214. }
  215. break;
  216. case qoPauseAll:
  217. case qoResumeAll:
  218. {
  219. for (int i = FQueueStatus->DoneCount; i < FQueueStatus->DoneAndActiveCount; i++)
  220. {
  221. QueueItem = FQueueStatus->Items[i];
  222. if ((Operation == qoPauseAll) && (QueueItem->Status == TQueueItem::qsProcessing))
  223. {
  224. QueueItem->Pause();
  225. }
  226. else if ((Operation == qoResumeAll) && (QueueItem->Status == TQueueItem::qsPaused))
  227. {
  228. QueueItem->Resume();
  229. }
  230. }
  231. }
  232. break;
  233. case qoDeleteAllDone:
  234. {
  235. for (int i = 0; i < FQueueStatus->DoneCount; i++)
  236. {
  237. QueueItem = FQueueStatus->Items[i];
  238. QueueItem->Delete();
  239. }
  240. }
  241. break;
  242. default:
  243. assert(false);
  244. break;
  245. }
  246. }
  247. //---------------------------------------------------------------------------
  248. void __fastcall TQueueController::FillQueueViewItem(TListItem * Item,
  249. TQueueItemProxy * QueueItem, bool Detail)
  250. {
  251. assert(!Detail || (QueueItem->Status != TQueueItem::qsPending));
  252. assert((Item->Data == NULL) || (Item->Data == QueueItem));
  253. Item->Data = QueueItem;
  254. UnicodeString ProgressStr;
  255. int Image = -1;
  256. switch (QueueItem->Status)
  257. {
  258. case TQueueItem::qsDone:
  259. ProgressStr = LoadStr(QUEUE_DONE);
  260. break;
  261. case TQueueItem::qsPending:
  262. ProgressStr = LoadStr(QUEUE_PENDING);
  263. break;
  264. case TQueueItem::qsConnecting:
  265. ProgressStr = LoadStr(QUEUE_CONNECTING);
  266. break;
  267. case TQueueItem::qsQuery:
  268. ProgressStr = LoadStr(QUEUE_QUERY);
  269. Image = 4;
  270. break;
  271. case TQueueItem::qsError:
  272. ProgressStr = LoadStr(QUEUE_ERROR);
  273. Image = 5;
  274. break;
  275. case TQueueItem::qsPrompt:
  276. ProgressStr = LoadStr(QUEUE_PROMPT);
  277. Image = 6;
  278. break;
  279. case TQueueItem::qsPaused:
  280. ProgressStr = LoadStr(QUEUE_PAUSED);
  281. Image = 7;
  282. break;
  283. }
  284. bool BlinkHide = QueueItemNeedsFrequentRefresh(QueueItem) &&
  285. !QueueItem->ProcessingUserAction &&
  286. ((GetTickCount() % MSecsPerSec) >= (MSecsPerSec/2));
  287. int State = -1;
  288. UnicodeString Values[6];
  289. TFileOperationProgressType * ProgressData = QueueItem->ProgressData;
  290. TQueueItem::TInfo * Info = QueueItem->Info;
  291. if (!Detail)
  292. {
  293. switch (Info->Operation)
  294. {
  295. case foCopy:
  296. State = ((Info->Side == osLocal) ? 2 : 0);
  297. break;
  298. case foMove:
  299. State = ((Info->Side == osLocal) ? 3 : 1);
  300. break;
  301. }
  302. // cannot use ProgressData->Temp as it is set only after the transfer actually starts
  303. Values[0] = Info->Source.IsEmpty() ? LoadStr(PROGRESS_TEMP_DIR) : Info->Source;
  304. Values[1] = Info->Destination.IsEmpty() ? LoadStr(PROGRESS_TEMP_DIR) : Info->Destination;
  305. __int64 TotalTransferred = QueueItem->TotalTransferred;
  306. if (TotalTransferred >= 0)
  307. {
  308. Values[2] = FormatBytes(TotalTransferred);
  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. Image = -1;
  341. if (ProgressData != NULL)
  342. {
  343. if ((Info->Side == osRemote) || !ProgressData->Temp)
  344. {
  345. Values[0] = ProgressData->FileName;
  346. }
  347. else
  348. {
  349. Values[0] = ExtractFileName(ProgressData->FileName);
  350. }
  351. if (ProgressData->Operation == Info->Operation)
  352. {
  353. Values[2] = FormatBytes(ProgressData->TransferedSize);
  354. Values[5] = FORMAT(L"%d%%", (ProgressData->TransferProgress()));
  355. }
  356. }
  357. else
  358. {
  359. Values[0] = ProgressStr;
  360. }
  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. assert(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. FillQueueViewItem(Item, QueueItem, false);
  424. Index++;
  425. assert((QueueItem->Status != TQueueItem::qsPending) ==
  426. (ItemIndex < FQueueStatus->DoneAndActiveCount));
  427. if (UseDetailsLine(ItemIndex, QueueItem))
  428. {
  429. Item = InsertItemFor(QueueItem, Index);
  430. FillQueueViewItem(Item, QueueItem, true);
  431. Index++;
  432. }
  433. }
  434. while (Index < FListView->Items->Count)
  435. {
  436. FListView->Items->Delete(Index);
  437. }
  438. }
  439. else
  440. {
  441. FListView->Items->Clear();
  442. }
  443. DoChange();
  444. }
  445. //---------------------------------------------------------------------------
  446. bool __fastcall TQueueController::UseDetailsLine(int ItemIndex, TQueueItemProxy * QueueItem)
  447. {
  448. return
  449. (ItemIndex >= FQueueStatus->DoneCount) &&
  450. (ItemIndex < FQueueStatus->DoneAndActiveCount) &&
  451. !QueueItem->Info->SingleFile;
  452. }
  453. //---------------------------------------------------------------------------
  454. void __fastcall TQueueController::RefreshQueueItem(TQueueItemProxy * QueueItem)
  455. {
  456. TListItem * NextListItem = NULL;
  457. TListItem * ListItem;
  458. ListItem = FListView->FindData(0, QueueItem, true, false);
  459. assert(ListItem != NULL);
  460. int Index = ListItem->Index;
  461. if (Index + 1 < FListView->Items->Count)
  462. {
  463. NextListItem = FListView->Items->Item[Index + 1];
  464. if (NextListItem->Data != QueueItem)
  465. {
  466. NextListItem = NULL;
  467. }
  468. }
  469. FillQueueViewItem(ListItem, QueueItem, false);
  470. if (UseDetailsLine(QueueItem->Index, QueueItem))
  471. {
  472. if (NextListItem == NULL)
  473. {
  474. NextListItem = FListView->Items->Insert(Index + 1);
  475. }
  476. FillQueueViewItem(NextListItem, QueueItem, true);
  477. }
  478. DoChange();
  479. }
  480. //---------------------------------------------------------------------------
  481. bool __fastcall TQueueController::QueueItemNeedsFrequentRefresh(
  482. TQueueItemProxy * QueueItem)
  483. {
  484. return
  485. (TQueueItem::IsUserActionStatus(QueueItem->Status) ||
  486. (QueueItem->Status == TQueueItem::qsPaused));
  487. }
  488. //---------------------------------------------------------------------------
  489. void __fastcall TQueueController::DoChange()
  490. {
  491. if (FOnChange != NULL)
  492. {
  493. FOnChange(NULL);
  494. }
  495. }
  496. //---------------------------------------------------------------------------
  497. void __fastcall TQueueController::QueueViewDblClick(TObject * /*Sender*/)
  498. {
  499. TQueueOperation Operation = DefaultOperation();
  500. if (Operation != qoNone)
  501. {
  502. ExecuteOperation(Operation);
  503. }
  504. }
  505. //---------------------------------------------------------------------------
  506. void __fastcall TQueueController::QueueViewKeyDown(TObject * /*Sender*/,
  507. WORD & Key, TShiftState /*Shift*/)
  508. {
  509. if (Key == VK_RETURN)
  510. {
  511. TQueueOperation Operation = DefaultOperation();
  512. if (Operation != qoNone)
  513. {
  514. ExecuteOperation(Operation);
  515. }
  516. Key = 0;
  517. }
  518. else if (Key == VK_DELETE)
  519. {
  520. ExecuteOperation(qoItemDelete);
  521. Key = 0;
  522. }
  523. }
  524. //---------------------------------------------------------------------------
  525. void __fastcall TQueueController::QueueViewCustomDrawItem(TCustomListView * Sender,
  526. TListItem * Item, TCustomDrawState /*State*/, bool & /*DefaultDraw*/)
  527. {
  528. TQueueItemProxy * QueueItem = QueueViewItemToQueueItem(Item);
  529. if (QueueItem->Status == TQueueItem::qsDone)
  530. {
  531. Sender->Canvas->Font->Color = clGrayText;
  532. }
  533. }
  534. //---------------------------------------------------------------------------
  535. bool __fastcall TQueueController::GetEmpty()
  536. {
  537. return (FQueueStatus == NULL) || (FQueueStatus->Count == 0);
  538. }