| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705 | //---------------------------------------------------------------------------#include <vcl.h>#pragma hdrstop#include <Common.h>#include <CoreMain.h>#include <Queue.h>#include <TextsWin.h>#include <GUITools.h>#include <WinConfiguration.h>#include "QueueController.h"#include <BaseUtils.hpp>//---------------------------------------------------------------------------#pragma package(smart_init)//---------------------------------------------------------------------------__fastcall TQueueController::TQueueController(TListView * ListView){  FListView = ListView;  DebugAssert(FListView != NULL);  DebugAssert(FListView->OnDblClick == NULL);  FListView->OnDblClick = QueueViewDblClick;  DebugAssert(FListView->OnKeyDown == NULL);  FListView->OnKeyDown = QueueViewKeyDown;  DebugAssert(FListView->OnCustomDrawItem == NULL);  FListView->OnCustomDrawItem = QueueViewCustomDrawItem;  FQueueStatus = NULL;  FOnChange = NULL;  RememberConfiguration();}//---------------------------------------------------------------------------__fastcall TQueueController::~TQueueController(){  DebugAssert(FListView->OnDblClick == QueueViewDblClick);  FListView->OnDblClick = NULL;  DebugAssert(FListView->OnKeyDown == QueueViewKeyDown);  FListView->OnKeyDown = NULL;  DebugAssert(FListView->OnCustomDrawItem == QueueViewCustomDrawItem);  FListView->OnCustomDrawItem = NULL;}//---------------------------------------------------------------------------TQueueItemProxy * __fastcall TQueueController::QueueViewItemToQueueItem(TListItem * Item){  // previously this method was based on ActiveCount and DoneCount,  // as if we were inconfident about validity of Item->Data pointers,  // not sure why  return static_cast<TQueueItemProxy *>(Item->Data);}//---------------------------------------------------------------------------TQueueOperation __fastcall TQueueController::DefaultOperation(){  TQueueItemProxy * QueueItem;  if (FListView->ItemFocused != NULL)  {    QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);    switch (QueueItem->Status)    {      case TQueueItem::qsPending:        return qoItemExecute;      case TQueueItem::qsQuery:        return qoItemQuery;      case TQueueItem::qsError:        return qoItemError;      case TQueueItem::qsPrompt:        return qoItemPrompt;      case TQueueItem::qsProcessing:        return qoItemPause;      case TQueueItem::qsPaused:        return qoItemResume;    }  }  return qoNone;}//---------------------------------------------------------------------------bool __fastcall TQueueController::AllowOperation(  TQueueOperation Operation, void ** Param){  TQueueItemProxy * QueueItem = NULL;  if (FListView->ItemFocused != NULL)  {    QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);  }  switch (Operation)  {    case qoItemUserAction:      return (QueueItem != NULL) && TQueueItem::IsUserActionStatus(QueueItem->Status);    case qoItemQuery:      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsQuery);    case qoItemError:      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsError);    case qoItemPrompt:      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsPrompt);    case qoItemDelete:      return (QueueItem != NULL);    case qoItemExecute:      return (QueueItem != NULL) && (QueueItem->Status == TQueueItem::qsPending);    case qoItemUp:      return (QueueItem != NULL) &&        (QueueItem->Status == TQueueItem::qsPending) &&        // it's not first pending item,        // this is based on assumption that pending items occupy single line always        (FListView->ItemFocused->Index > 0) &&        (QueueViewItemToQueueItem(FListView->Items->Item[FListView->ItemFocused->Index - 1])->Status == TQueueItem::qsPending);    case qoItemDown:      return (QueueItem != NULL) &&        (QueueItem->Status == TQueueItem::qsPending) &&        (FListView->ItemFocused->Index < (FListView->Items->Count - 1));    case qoItemPause:      return (QueueItem != NULL) &&        (QueueItem->Status == TQueueItem::qsProcessing);    case qoItemResume:      return (QueueItem != NULL) &&        (QueueItem->Status == TQueueItem::qsPaused);    case qoItemSpeed:      {        bool Result =          (QueueItem != NULL) && (QueueItem->Status != TQueueItem::qsDone) &&          TFileOperationProgressType::IsTransferOperation(QueueItem->Info->Operation);        if (Result && (Param != NULL))        {          Result = QueueItem->GetCPSLimit(*reinterpret_cast<unsigned long *>(Param));        }        return Result;      }    case qoPauseAll:    case qoResumeAll:      {        TQueueItem::TStatus Status =          (Operation == qoPauseAll) ? TQueueItem::qsProcessing : TQueueItem::qsPaused;        bool Result = false;        // can be NULL when action update is triggered while disconnecting        if (FQueueStatus != NULL)        {          for (int i = FQueueStatus->DoneCount; !Result && (i < FQueueStatus->DoneAndActiveCount); i++)          {            QueueItem = FQueueStatus->Items[i];            Result = (QueueItem->Status == Status);          }        }        return Result;      }    case qoDeleteAllDone:      return (FQueueStatus != NULL) && (FQueueStatus->DoneCount > 0);    case qoDeleteAll:      return (FQueueStatus != NULL) && (FQueueStatus->Count > 0);    default:      DebugFail();      return false;  }}//---------------------------------------------------------------------------void __fastcall TQueueController::ExecuteOperation(TQueueOperation Operation,  void * Param){  TQueueItemProxy * QueueItem = NULL;  if (FListView->ItemFocused != NULL)  {    QueueItem = QueueViewItemToQueueItem(FListView->ItemFocused);  }  switch (Operation)  {    case qoItemUserAction:    case qoItemQuery:    case qoItemError:    case qoItemPrompt:      if (QueueItem != NULL)      {        QueueItem->ProcessUserAction();      }      break;    case qoItemExecute:      if (QueueItem != NULL)      {        QueueItem->ExecuteNow();      }      break;    case qoItemUp:    case qoItemDown:      if (QueueItem != NULL)      {        QueueItem->Move(Operation == qoItemUp);      }      break;    case qoItemDelete:      if (QueueItem != NULL)      {        QueueItem->Delete();      }      break;    case qoItemPause:      if (QueueItem != NULL)      {        QueueItem->Pause();      }      break;    case qoItemResume:      if (QueueItem != NULL)      {        QueueItem->Resume();      }      break;    case qoItemSpeed:      if (QueueItem != NULL)      {        QueueItem->SetCPSLimit(reinterpret_cast<unsigned long>(Param));      }      break;    case qoPauseAll:    case qoResumeAll:      {        for (int i = FQueueStatus->DoneCount; i < FQueueStatus->DoneAndActiveCount; i++)        {          QueueItem = FQueueStatus->Items[i];          if ((Operation == qoPauseAll) && (QueueItem->Status == TQueueItem::qsProcessing))          {            QueueItem->Pause();          }          else if ((Operation == qoResumeAll) && (QueueItem->Status == TQueueItem::qsPaused))          {            QueueItem->Resume();          }        }      }      break;    case qoDeleteAllDone:    case qoDeleteAll:      {        int Count = (Operation == qoDeleteAll) ? FQueueStatus->Count : FQueueStatus->DoneCount;        for (int i = 0; i < Count; i++)        {          QueueItem = FQueueStatus->Items[i];          QueueItem->Delete();        }      }      break;    default:      DebugFail();      break;  }}//---------------------------------------------------------------------------static UnicodeString GetTime(TFileOperationProgressType * ProgressData){  UnicodeString Result;  if (ProgressData->TotalSizeSet)  {    Result = FormatDateTimeSpan(ProgressData->TotalTimeLeft());  }  else  {    Result = FormatDateTimeSpan(ProgressData->TimeElapsed());  }  return Result;}//---------------------------------------------------------------------------static UnicodeString GetOverallProgress(TFileOperationProgressType * ProgressData){  return FORMAT(L"%d%%", (ProgressData->OverallProgress()));}//---------------------------------------------------------------------------void __fastcall TQueueController::FillQueueViewItem(TListItem * Item,  TQueueItemProxy * QueueItem, bool Detail, bool OnlyLine){  DebugAssert(!Detail || (QueueItem->Status != TQueueItem::qsPending));  DebugAssert((Item->Data == NULL) || (Item->Data == QueueItem));  Item->Data = QueueItem;  UnicodeString ProgressStr;  int Image = -1;  switch (QueueItem->Status)  {    case TQueueItem::qsDone:      ProgressStr = LoadStr(QUEUE_DONE);      break;    case TQueueItem::qsPending:      ProgressStr = LoadStr(QUEUE_PENDING);      break;    case TQueueItem::qsConnecting:      ProgressStr = LoadStr(QUEUE_CONNECTING);      break;    case TQueueItem::qsQuery:      ProgressStr = LoadStr(QUEUE_QUERY);      Image = 4;      break;    case TQueueItem::qsError:      ProgressStr = LoadStr(QUEUE_ERROR);      Image = 5;      break;    case TQueueItem::qsPrompt:      ProgressStr = LoadStr(QUEUE_PROMPT);      Image = 6;      break;    case TQueueItem::qsPaused:      ProgressStr = LoadStr(QUEUE_PAUSED);      Image = 7;      break;  }  bool BlinkHide = QueueItemNeedsFrequentRefresh(QueueItem) &&    !QueueItem->ProcessingUserAction &&    ((GetTickCount() % MSecsPerSec) >= (MSecsPerSec/2));  int State = -1;  UnicodeString Values[6];  TFileOperationProgressType * ProgressData = QueueItem->ProgressData;  TQueueItem::TInfo * Info = QueueItem->Info;  if (SimpleOperation(QueueItem))  {    DebugAssert(!Detail && Info->Primary);    State = 8;    if ((ProgressData != NULL) && (QueueItem->Status != TQueueItem::qsDone))    {      Values[0] = ProgressData->FileName;      Values[3] = GetTime(ProgressData);      if (ProgressStr.IsEmpty())      {        if (ProgressData->Count > 1)        {          ProgressStr = GetOverallProgress(ProgressData);        }        else        {          ProgressStr = LoadStr(QUEUE_DELETING);        }      }    }    else    {      Values[0] = Info->Source;    }    Values[5] = ProgressStr;  }  else if (!Detail && Info->Primary)  {    switch (Info->Operation)    {      case foCopy:        State = ((Info->Side == osLocal) ? 2 : 0);        break;      case foMove:        State = ((Info->Side == osLocal) ? 3 : 1);        break;      default:        DebugFail();    }    if (!OnlyLine)    {      Image = -1;      ProgressStr = L"";    }    // If both are empty, it's bootstrap item => do not show anything    if (!Info->Source.IsEmpty() || !Info->Destination.IsEmpty())    {      // cannot use ProgressData->Temp as it is set only after the transfer actually starts      Values[0] = Info->Source.IsEmpty() ? LoadStr(PROGRESS_TEMP_DIR) : Info->Source;      Values[1] = Info->Destination.IsEmpty() ? LoadStr(PROGRESS_TEMP_DIR) : Info->Destination;    }    __int64 TotalTransferred = QueueItem->TotalTransferred;    if (TotalTransferred >= 0)    {      Values[2] =        FormatPanelBytes(TotalTransferred, WinConfiguration->FormatSizeBytes);    }    if (ProgressData != NULL)    {      if (ProgressData->Operation == Info->Operation)      {        if (QueueItem->Status != TQueueItem::qsDone)        {          Values[3] = GetTime(ProgressData);          Values[4] = FORMAT(L"%s/s", (FormatBytes(ProgressData->CPS())));        }        if (ProgressStr.IsEmpty())        {          ProgressStr = GetOverallProgress(ProgressData);        }      }      else if (ProgressData->Operation == foCalculateSize)      {        ProgressStr = LoadStr(QUEUE_LISTING);      }    }    Values[5] = ProgressStr;  }  else  {    if (ProgressData != NULL)    {      if ((Info->Side == osRemote) || !ProgressData->Temp)      {        Values[0] = ProgressData->FileName;      }      else      {        Values[0] = ExtractFileName(ProgressData->FileName);      }      if (ProgressData->Operation == Info->Operation)      {        Values[2] =          FormatPanelBytes(ProgressData->TransferredSize, WinConfiguration->FormatSizeBytes);        if (ProgressStr.IsEmpty())        {          ProgressStr = FORMAT(L"%d%%", (ProgressData->TransferProgress()));        }      }    }    Values[5] = ProgressStr;  }  Item->StateIndex = (!BlinkHide ? State : -1);  Item->ImageIndex = (!BlinkHide ? Image : -1);  for (size_t Index = 0; Index < LENOF(Values); Index++)  {    if (Index < static_cast<size_t>(Item->SubItems->Count))    {      Item->SubItems->Strings[Index] = Values[Index];    }    else    {      Item->SubItems->Add(Values[Index]);    }  }}//---------------------------------------------------------------------------TListItem * __fastcall TQueueController::InsertItemFor(TQueueItemProxy * QueueItem, int Index){  TListItem * Item;  if (Index == FListView->Items->Count)  {    Item = FListView->Items->Add();  }  else if (FListView->Items->Item[Index]->Data != QueueItem)  {    Item = FListView->Items->Insert(Index);  }  else  {    Item = FListView->Items->Item[Index];    DebugAssert(Item->Data == QueueItem);  }  return Item;}//---------------------------------------------------------------------------void __fastcall TQueueController::UpdateQueueStatus(  TTerminalQueueStatus * QueueStatus){  FQueueStatus = QueueStatus;  if (FQueueStatus != NULL)  {    TQueueItemProxy * QueueItem;    TListItem * Item;    int Index = 0;    for (int ItemIndex = 0; ItemIndex < FQueueStatus->Count; ItemIndex++)    {      QueueItem = FQueueStatus->Items[ItemIndex];      int Index2 = Index;      while ((Index2 < FListView->Items->Count) &&             (FListView->Items->Item[Index2]->Data != QueueItem))      {        Index2++;      }      if (Index2 < FListView->Items->Count)      {        while (Index < Index2)        {          FListView->Items->Delete(Index);          Index2--;        }      }      Item = InsertItemFor(QueueItem, Index);      bool HasDetailsLine = UseDetailsLine(ItemIndex, QueueItem);      FillQueueViewItem(Item, QueueItem, false, !HasDetailsLine);      Index++;      DebugAssert((QueueItem->Status != TQueueItem::qsPending) ==        (ItemIndex < FQueueStatus->DoneAndActiveCount));      if (HasDetailsLine)      {        Item = InsertItemFor(QueueItem, Index);        FillQueueViewItem(Item, QueueItem, true, false);        Index++;      }    }    while (Index < FListView->Items->Count)    {      FListView->Items->Delete(Index);    }  }  else  {    FListView->Items->Clear();  }  DoChange();}//---------------------------------------------------------------------------bool TQueueController::SimpleOperation(TQueueItemProxy * QueueItem){  return (QueueItem->Info->Operation == foDelete); // basically any non-transfer, but we support delete now only}//---------------------------------------------------------------------------bool __fastcall TQueueController::UseDetailsLine(int ItemIndex, TQueueItemProxy * QueueItem){  return    (ItemIndex >= FQueueStatus->DoneCount) &&    (ItemIndex < FQueueStatus->DoneAndActiveCount) &&    QueueItem->Info->Primary &&    !QueueItem->Info->SingleFile &&    !SimpleOperation(QueueItem) &&    ((QueueItem->ProgressData == NULL) || !QueueItem->ProgressData->Done);}//---------------------------------------------------------------------------void __fastcall TQueueController::RefreshQueueItem(TQueueItemProxy * QueueItem){  TListItem * NextListItem = NULL;  TListItem * ListItem;  ListItem = FListView->FindData(0, QueueItem, true, false);  DebugAssert(ListItem != NULL);  int Index = ListItem->Index;  if (Index + 1 < FListView->Items->Count)  {    NextListItem = FListView->Items->Item[Index + 1];    if (NextListItem->Data != QueueItem)    {      NextListItem = NULL;    }  }  bool HasDetailsLine = UseDetailsLine(QueueItem->Index, QueueItem);  FillQueueViewItem(ListItem, QueueItem, false, !HasDetailsLine);  if (HasDetailsLine)  {    if (NextListItem == NULL)    {      NextListItem = FListView->Items->Insert(Index + 1);    }    FillQueueViewItem(NextListItem, QueueItem, true, false);  }  else  {    if (NextListItem != NULL)    {      NextListItem->Delete();    }  }  DoChange();}//---------------------------------------------------------------------------bool __fastcall TQueueController::QueueItemNeedsFrequentRefresh(  TQueueItemProxy * QueueItem){  return    (TQueueItem::IsUserActionStatus(QueueItem->Status) ||     (QueueItem->Status == TQueueItem::qsPaused));}//---------------------------------------------------------------------------void __fastcall TQueueController::DoChange(){  if (FOnChange != NULL)  {    FOnChange(NULL);  }}//---------------------------------------------------------------------------void __fastcall TQueueController::QueueViewDblClick(TObject * /*Sender*/){  TQueueOperation Operation = DefaultOperation();  if (Operation != qoNone)  {    ExecuteOperation(Operation);  }}//---------------------------------------------------------------------------void __fastcall TQueueController::QueueViewKeyDown(TObject * /*Sender*/,  WORD & Key, TShiftState /*Shift*/){  if (Key == VK_RETURN)  {    TQueueOperation Operation = DefaultOperation();    if (Operation != qoNone)    {      ExecuteOperation(Operation);    }    Key = 0;  }  else if (Key == VK_DELETE)  {    ExecuteOperation(qoItemDelete);    Key = 0;  }}//---------------------------------------------------------------------------void __fastcall TQueueController::QueueViewCustomDrawItem(TCustomListView * Sender,  TListItem * Item, TCustomDrawState /*State*/, bool & /*DefaultDraw*/){  TQueueItemProxy * QueueItem = QueueViewItemToQueueItem(Item);  if (QueueItem->Status == TQueueItem::qsDone)  {    Sender->Canvas->Font->Color = clGrayText;  }}//---------------------------------------------------------------------------bool __fastcall TQueueController::GetEmpty(){  return (FQueueStatus == NULL) || (FQueueStatus->Count == 0);}//---------------------------------------------------------------------------void __fastcall TQueueController::RememberConfiguration(){  FFormatSizeBytes = WinConfiguration->FormatSizeBytes;}//---------------------------------------------------------------------------bool __fastcall TQueueController::NeedRefresh(){  bool Result = (WinConfiguration->FormatSizeBytes != FFormatSizeBytes);  RememberConfiguration();  return Result;}//---------------------------------------------------------------------------TQueueItemProxy * __fastcall TQueueController::GetFocusedPrimaryItem(){  TQueueItemProxy * Result = NULL;  TListItem * PrimaryItemOfFocused = FListView->ItemFocused;  if (PrimaryItemOfFocused != NULL)  {    while (!QueueViewItemToQueueItem(PrimaryItemOfFocused)->Info->Primary &&           DebugAlwaysTrue(PrimaryItemOfFocused->Index > 0))    {      PrimaryItemOfFocused = FListView->Items->Item[PrimaryItemOfFocused->Index - 1];    }    Result = QueueViewItemToQueueItem(PrimaryItemOfFocused);  }  return Result;}
 |