/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ ////////////////////////////////////////////////////////////////////////////// // // // plProgressMgr Functions // // // //// History ///////////////////////////////////////////////////////////////// // // // 10.26.2001 mcn - Created // // // ////////////////////////////////////////////////////////////////////////////// #include #include "hsTypes.h" #include "plProgressMgr.h" #include "hsTimer.h" #include "../plPipeline/plPlates.h" #include "../Apps/plClient/res/resource.h" #include ////////////////////////////////////////////////////////////////////////////// //// plProgressMgr Functions ///////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// plProgressMgr *plProgressMgr::fManager = nil; int plProgressMgr::fImageRotation[] = { IDR_LOADING_01, IDR_LOADING_18, IDR_LOADING_17, IDR_LOADING_16, IDR_LOADING_15, IDR_LOADING_14, IDR_LOADING_13, IDR_LOADING_12, IDR_LOADING_11, IDR_LOADING_10, IDR_LOADING_09, IDR_LOADING_08, IDR_LOADING_07, IDR_LOADING_06, IDR_LOADING_05, IDR_LOADING_04, IDR_LOADING_03, IDR_LOADING_02 }; int plProgressMgr::fStaticTextIDs[] = { 0, IDR_LOADING_UPDATETEXT, }; //// Constructor & Destructor //////////////////////////////////////////////// plProgressMgr::plProgressMgr() { fOperations = nil; fManager = this; fCallbackProc = nil; fCurrentStaticText = kNone; } plProgressMgr::~plProgressMgr() { while( fOperations != nil ) delete fOperations; fManager = nil; } //// RegisterOperation /////////////////////////////////////////////////////// plOperationProgress* plProgressMgr::RegisterOperation(hsScalar length, const char *title, StaticText staticTextType, bool isRetry, bool alwaysDrawText) { return IRegisterOperation(length, title, staticTextType, isRetry, false, alwaysDrawText); } plOperationProgress* plProgressMgr::RegisterOverallOperation(hsScalar length, const char *title, StaticText staticTextType, bool alwaysDrawText) { return IRegisterOperation(length, title, staticTextType, false, true, alwaysDrawText); } plOperationProgress* plProgressMgr::IRegisterOperation(hsScalar length, const char *title, StaticText staticTextType, bool isRetry, bool isOverall, bool alwaysDrawText) { if (fOperations == nil) { fCurrentStaticText = staticTextType; Activate(); } plOperationProgress *op = TRACKED_NEW plOperationProgress( length ); op->SetTitle( title ); if (fOperations) { fOperations->fBack = op; op->fNext = fOperations; } fOperations = op; if (isRetry) hsSetBits(op->fFlags, plOperationProgress::kRetry); if (isOverall) hsSetBits(op->fFlags, plOperationProgress::kOverall); if (alwaysDrawText) hsSetBits(op->fFlags, plOperationProgress::kAlwaysDrawText); IUpdateCallbackProc( op ); return op; } void plProgressMgr::IUnregisterOperation(plOperationProgress* op) { plOperationProgress* last = nil; plOperationProgress* cur = fOperations; while (cur) { if (cur == op) { if (cur->fNext) cur->fNext->fBack = last; if (last) last->fNext = cur->fNext; else fOperations = cur->fNext; break; } last = cur; cur = cur->fNext; } if (fOperations == nil) { fCurrentStaticText = kNone; Deactivate(); } } //// IUpdateCallbackProc ///////////////////////////////////////////////////// void plProgressMgr::IUpdateFlags(plOperationProgress* progress) { // Init update is done, clear it and set first update if (hsCheckBits(progress->fFlags, plOperationProgress::kInitUpdate)) { hsClearBits(progress->fFlags, plOperationProgress::kInitUpdate); hsSetBits(progress->fFlags, plOperationProgress::kFirstUpdate); } // First update is done, clear it else if (hsCheckBits(progress->fFlags, plOperationProgress::kFirstUpdate)) hsClearBits(progress->fFlags, plOperationProgress::kFirstUpdate); } void plProgressMgr::IUpdateCallbackProc(plOperationProgress* progress) { // Update the parent, if necessary plOperationProgress* parentProgress = progress->GetNext(); while (parentProgress && parentProgress->IsOverallProgress()) { parentProgress->IChildUpdateBegin(progress); parentProgress = parentProgress->GetNext(); } // Update everyone who wants to know about progress IDerivedCallbackProc(progress); if (fCallbackProc != nil) fCallbackProc(progress); IUpdateFlags(progress); parentProgress = progress->GetNext(); while (parentProgress && parentProgress->IsOverallProgress()) { parentProgress->IChildUpdateEnd(progress); parentProgress = parentProgress->GetNext(); } } //// SetCallbackProc ///////////////////////////////////////////////////////// plProgressMgrCallbackProc plProgressMgr::SetCallbackProc( plProgressMgrCallbackProc proc ) { plProgressMgrCallbackProc old = fCallbackProc; fCallbackProc = proc; return old; } //// CancelAllOps //////////////////////////////////////////////////////////// void plProgressMgr::CancelAllOps( void ) { plOperationProgress *op; for( op = fOperations; op != nil; op = op->GetNext() ) op->SetCancelFlag( true ); fCurrentStaticText = kNone; } int plProgressMgr::GetLoadingFrameID(int index) { if (index < (sizeof(fImageRotation) / sizeof(int))) return fImageRotation[index]; else return fImageRotation[0]; } int plProgressMgr::GetStaticTextID(StaticText staticTextType) { return fStaticTextIDs[staticTextType]; } ////////////////////////////////////////////////////////////////////////////// //// plOperationProgress //////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// plOperationProgress::plOperationProgress( hsScalar length ) : fMax(length), fValue(0), fNext(nil), fBack(nil), fContext(0), fFlags(kInitUpdate), fStartTime(hsTimer::GetSeconds()), fElapsedSecs(0), fRemainingSecs(0), fAmtPerSec(0.f) { memset( fStatusText, 0, sizeof( fStatusText ) ); memset( fTitle, 0, sizeof( fTitle ) ); } plOperationProgress::~plOperationProgress() { hsSetBits(fFlags, kLastUpdate); if (!IsOverallProgress()) plProgressMgr::GetInstance()->IUpdateCallbackProc(this); plProgressMgr::GetInstance()->IUnregisterOperation(this); } void plOperationProgress::IUpdateStats() { double curTime = hsTimer::GetSeconds(); double elapsed = 0; if (curTime > fStartTime) elapsed = curTime - fStartTime; else elapsed = fStartTime - curTime; hsScalar progress = GetProgress(); if (elapsed > 0) fAmtPerSec = progress / hsScalar(elapsed); else fAmtPerSec = 0; fElapsedSecs = (UInt32)elapsed; if (progress < fMax) fRemainingSecs = (UInt32)((fMax - progress) / fAmtPerSec); else fRemainingSecs = 0; } void plOperationProgress::IChildUpdateBegin(plOperationProgress* child) { if (child->IsFirstUpdate() && child->IsRetry()) { // We're retrying this file, so update the overall stats to reflect the additional download fMax += child->GetMax(); } fValue += child->GetProgress(); IUpdateStats(); } void plOperationProgress::IChildUpdateEnd(plOperationProgress* child) { // If we're aborting, modify the total bytes to reflect any data we didn't download if (hsCheckBits(child->fFlags, plOperationProgress::kAborting)) fMax += child->GetProgress() - child->GetMax(); else if (!child->IsLastUpdate()) fValue -= child->GetProgress(); } //// Increment /////////////////////////////////////////////////////////////// void plOperationProgress::Increment( hsScalar byHowMuch ) { fValue += byHowMuch; if( fValue > fMax ) fValue = fMax; IUpdateStats(); plProgressMgr::GetInstance()->IUpdateCallbackProc( this ); } //// SetHowMuch ////////////////////////////////////////////////////////////// void plOperationProgress::SetHowMuch( hsScalar howMuch ) { fValue = howMuch; if( fValue > fMax ) fValue = fMax; IUpdateStats(); plProgressMgr::GetInstance()->IUpdateCallbackProc( this ); } //// SetStatusText /////////////////////////////////////////////////////////// void plOperationProgress::SetStatusText( const char *text ) { if( text != nil ) strncpy( fStatusText, text, sizeof( fStatusText ) ); else fStatusText[ 0 ] = 0; } //// SetTitle //////////////////////////////////////////////////////////////// void plOperationProgress::SetTitle( const char *text ) { if (text != nil) { strncpy(fTitle, text, sizeof(fTitle)); } else fTitle[0] = 0; } //// SetLength /////////////////////////////////////////////////////////////// void plOperationProgress::SetLength( hsScalar length ) { fMax = length; if( fValue > fMax ) fValue = fMax; IUpdateStats(); plProgressMgr::GetInstance()->IUpdateCallbackProc( this ); } void plOperationProgress::SetAborting() { hsSetBits(fFlags, kAborting); plProgressMgr::GetInstance()->IUpdateCallbackProc(this); fMax = fValue = 0.f; hsClearBits(fFlags, kAborting); } void plOperationProgress::SetRetry() { hsSetBits(fFlags, kRetry); hsSetBits(fFlags, kFirstUpdate); }