elementsengine.cpp

来自「series60 应用程序开发的源代码 series60 应用程序开发的源代码」· C++ 代码 · 共 344 行

CPP
344
字号
/**
*
* @brief Asynchronous test engine to verify the functionality of the Elements project
*
* Copyright (c) EMCC Software Ltd 2003
* @version 1.0
*/

// INCLUDE FILES

// Class include
#include "elementsengine.h"

// System includes
#include <e32cons.h>
#include <s32file.h>

// User includes
#include "elementrarray.h"
#include "elementcarray.h"
#include "csvfileloader.h"
#include "chemicalelement.h"


// ===================== CONSTANTS ==========================

_LIT(KMetalsFileName, "C:\\metals.csv");
_LIT(KNonMetalsFileName, "C:\\nonmetals.csv");
_LIT(KSemiMetalsFileName, "C:\\semimetals.csv");
_LIT(KTxtLoaded, "Loaded ");
_LIT(KTxtLoadedReturn, " loaded\n");
_LIT(KTxtSemiMetals, "Semimetals");
_LIT(KTxtNonMetals, "Nonmetals");
_LIT(KTxtMetals, "Metals");
_LIT(KTxtTestFileName, "C:\\elements");
_LIT(KTxtStoreTestFileName, "C:\\elementsstore");
const TInt KPanicLoadFailed = 1;
const TInt KPanicWrongElementCount = 2;
const TInt KPanicSampleElementSymbolInWrongPlace = 3;
const TInt KPanicSampleElementAtomicNumberInWrongPlace = 4;
_LIT(KTxtSampleElementSymbol, "Nd");
const TInt KMaxFeedbackLen = 100;
const TInt KNumberOfCsvFilesToLoad = 3;
const TInt KUidMetalsStreamId = 0x101F613F;
const TInt KUidNonmetalsStreamId = 0x101F6140;
const TInt KUidSemimetalsStreamId = 0x101F6141;
const TInt KExpectedElementCount = 118;


// ================= MEMBER FUNCTIONS =======================

CElementsEngine::CElementsEngine(CConsoleBase& aConsole) :
iConsole(aConsole)
{
}

CElementsEngine::~CElementsEngine()
{
    delete iMetalsCsvFileLoader;
    delete iNonMetalsCsvFileLoader;
    delete iSemiMetalsCsvFileLoader;
    delete iElementList;
    delete iStore;
    delete iRootDictionary;
    iFs.Close();
}

CElementsEngine* CElementsEngine::NewLC(CConsoleBase& aConsole)
{
    CElementsEngine* self = new (ELeave) CElementsEngine(aConsole);
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
}

CElementsEngine* CElementsEngine::NewL(CConsoleBase& aConsole)
{
    CElementsEngine* self = CElementsEngine::NewLC(aConsole);
    CleanupStack::Pop(self);
    return self;
}

void CElementsEngine::ConstructL()
{
    User::LeaveIfError(iFs.Connect());
    iElementList = new (ELeave) CElementRArray();
    //iElementList = CElementCArray::NewL();
}

void CElementsEngine::LoadFromCsvFilesL()
{
    delete iMetalsCsvFileLoader;
    iMetalsCsvFileLoader = 0;
    iMetalsCsvFileLoader = CCsvFileLoader::NewL(iFs, *iElementList, *this, KMetalsFileName);
    iMetalsCsvFileLoader->Start();

    delete iNonMetalsCsvFileLoader;
    iNonMetalsCsvFileLoader = 0;
    iNonMetalsCsvFileLoader = CCsvFileLoader::NewL(iFs, *iElementList, *this, KNonMetalsFileName);
    iNonMetalsCsvFileLoader->Start();

    delete iSemiMetalsCsvFileLoader;
    iSemiMetalsCsvFileLoader = 0;
    iSemiMetalsCsvFileLoader = CCsvFileLoader::NewL(iFs, *iElementList, *this, KSemiMetalsFileName);
    iSemiMetalsCsvFileLoader->Start();
}

void CElementsEngine::NotifyElementLoaded(TInt aNewElementIndex)
{
    //Start with KTxtLoaded...
    TBuf<KMaxFeedbackLen> loadedFeedbackString(KTxtLoaded);
    //...append the name of the new element...
    loadedFeedbackString.Append((iElementList->At(aNewElementIndex)).Name());
    //...append a new line...
    loadedFeedbackString.Append(KTxtNewLine);
    //...and print to the console
    iConsole.Printf(loadedFeedbackString);
}

void CElementsEngine::NotifyLoadCompleted(TInt aCompletionStatus, const CCsvFileLoader& aLoader)
{
    __ASSERT_ALWAYS(aCompletionStatus == KErrNone, Panic(KPanicLoadFailed));
    TBuf<KMaxFeedbackLen> completedFeedbackString;

    if (&aLoader == iMetalsCsvFileLoader)
    {
        completedFeedbackString = KTxtMetals;
    }

    else if (&aLoader == iNonMetalsCsvFileLoader)
    {
        completedFeedbackString = KTxtNonMetals;
    }

    else
    {
        completedFeedbackString = KTxtSemiMetals;
    }

    completedFeedbackString.Append(KTxtLoadedReturn);

    iConsole.Printf(completedFeedbackString);

    iFilesCompleted++;

    if (iFilesCompleted == KNumberOfCsvFilesToLoad)
    {
        CActiveScheduler::Stop();    //Loading is completed--stop the scheduler
        TestElementList();            //Carry out some simple tests on the data
    }
}

void CElementsEngine::TestElementList()
{
    __ASSERT_ALWAYS(iElementList->NumberOfElements() == KExpectedElementCount, Panic(KPanicWrongElementCount));

    TRAPD(err, iElementList->SortBySymbolL());
    __ASSERT_ALWAYS(!err, Panic(err));
    TInt sampleElementSymbolLocationWhenSortedBySymbol = 0;
    TRAP(err, sampleElementSymbolLocationWhenSortedBySymbol = 
        iElementList->FindElementBySymbolL(KTxtSampleElementSymbol));
    __ASSERT_ALWAYS(!err, Panic(err));
    __ASSERT_ALWAYS(sampleElementSymbolLocationWhenSortedBySymbol == 61,
        Panic(KPanicSampleElementSymbolInWrongPlace));

    TRAP(err, iElementList->SortByAtomicNumberL());
    __ASSERT_ALWAYS(!err, Panic(err));
    TInt sampleElementSymbolLocationWhenSortedByAtomicNumber = 0;
    TRAP(err, sampleElementSymbolLocationWhenSortedByAtomicNumber = 
        iElementList->FindElementBySymbolL(KTxtSampleElementSymbol));
    __ASSERT_ALWAYS(!err, Panic(err));
    __ASSERT_ALWAYS(sampleElementSymbolLocationWhenSortedByAtomicNumber == 59,
        Panic(KPanicSampleElementAtomicNumberInWrongPlace));
    
    TRAP(err, TestElementListStreamingL());
    __ASSERT_ALWAYS(!err, Panic(err));


    //etc...
}

void CElementsEngine::TestElementListStreamingL()
{
    RFileWriteStream writeStream;
    User::LeaveIfError(writeStream.Create(iFs, KTxtTestFileName, EFileWrite));
    writeStream.PushL();
    iElementList->ExternalizeL(writeStream);
    writeStream.CommitL();
    writeStream.Pop();
    writeStream.Release();

    iElementList->DeleteAllElements();
    __ASSERT_ALWAYS(iElementList->NumberOfElements() == 0, Panic(KPanicWrongElementCount));

    RFileReadStream readStream;
    User::LeaveIfError(readStream.Open(iFs, KTxtTestFileName, EFileRead));
    readStream.PushL();
    iElementList->InternalizeL(readStream);
    readStream.Pop();
    readStream.Close();

    __ASSERT_ALWAYS(iElementList->NumberOfElements() == KExpectedElementCount, Panic(KPanicWrongElementCount));

    User::LeaveIfError(iFs.Delete(KTxtTestFileName));

    //Now test Stores
    CreateStoreL();
    CreateRootDictionaryL();
    WriteElementsToStoreL();
    WriteRootDictionaryL();

    //Delete all of the elements
    iElementList->DeleteAllElements();
    __ASSERT_ALWAYS(iElementList->NumberOfElements() == 0, Panic(KPanicWrongElementCount));

    //delete the store to free resources before we can delete the file
    delete iStore;
    iStore = 0;

    //Now read them back from the store
    ReadElementsFromStoreL();
    __ASSERT_ALWAYS(iElementList->NumberOfElements() == KExpectedElementCount, Panic(KPanicWrongElementCount));


    User::LeaveIfError(iFs.Delete(KTxtStoreTestFileName));
}

void CElementsEngine::CreateStoreL()
{
    CFileStore* store = CDirectFileStore::CreateLC(iFs, KTxtStoreTestFileName, EFileWrite);
    store->SetTypeL(TUidType(store->Layout()));
    CleanupStack::Pop();    //store
    iStore = store;
}

void CElementsEngine::CreateRootDictionaryL()
{
    iRootDictionary = CStreamDictionary::NewL();
}


void CElementsEngine::Panic(TInt aReason)
{
    _LIT(KTxtElementsPanicCategory, "Elements");
    User::Panic(KTxtElementsPanicCategory, aReason);
}

void CElementsEngine::WriteElementsToStoreL() const
{
    //First, write out the different element types to separate streams
    TStreamId metalsStreamId = WriteSpecificElementTypeToStoreL(CChemicalElement::EMetallic);
    TStreamId nonmetalsStreamId = WriteSpecificElementTypeToStoreL(CChemicalElement::ENonmetallic);
    TStreamId semimetalsStreamId = WriteSpecificElementTypeToStoreL(CChemicalElement::ESemimetallic);

    //Now assign their IDs to the dictionary store
    iRootDictionary->AssignL(TUid::Uid(KUidMetalsStreamId), metalsStreamId);
    iRootDictionary->AssignL(TUid::Uid(KUidNonmetalsStreamId), nonmetalsStreamId);
    iRootDictionary->AssignL(TUid::Uid(KUidSemimetalsStreamId), semimetalsStreamId);
}

void CElementsEngine::ReadElementsFromStoreL()
{
    //Open the store
    //(Pretend we don't have this already!)
    CFileStore* store = CDirectFileStore::OpenLC(iFs, KTxtStoreTestFileName, EFileRead);

    //Create and internalise the dictionary from the root stream:
    //(Pretend we don't have this already!)
    CStreamDictionary* dictionary = CStreamDictionary::NewLC();
    RStoreReadStream dictionaryStream;
    dictionaryStream.OpenLC(*store, store->Root());    //dictionary stream is the root stream
    dictionaryStream >> *dictionary;    //Stream in the dictionary
    CleanupStack::PopAndDestroy();        //dictionaryStream

    //Now use the dictionary to look up the stream ids
    TStreamId metalsStreamId = dictionary->At(TUid::Uid(KUidMetalsStreamId));
    TStreamId nonmetalsStreamId = dictionary->At(TUid::Uid(KUidNonmetalsStreamId));
    TStreamId semimetalsStreamId = dictionary->At(TUid::Uid(KUidSemimetalsStreamId));
    CleanupStack::PopAndDestroy(dictionary);

    //Read in each stream
    RStoreReadStream stream;
    stream.OpenLC(*store, metalsStreamId);
    stream >> *iElementList;        //Cleanup stack used because >> can leave!
    CleanupStack::PopAndDestroy();    //stream

    stream.OpenLC(*store, nonmetalsStreamId);
    stream >> *iElementList;        //Cleanup stack used because >> can leave!
    CleanupStack::PopAndDestroy();    //stream

    stream.OpenLC(*store, semimetalsStreamId);
    stream >> *iElementList;        //Cleanup stack used because >> can leave!
    CleanupStack::PopAndDestroy();    //stream

    CleanupStack::PopAndDestroy(store);
}

void CElementsEngine::WriteRootDictionaryL() const
{
    RStoreWriteStream root;
    TStreamId id = root.CreateLC(*iStore);
    root << *iRootDictionary;
    root.CommitL();
    CleanupStack::PopAndDestroy();    //root
    iStore->SetRootL(id);
    iStore->CommitL();
}

TStreamId CElementsEngine::WriteSpecificElementTypeToStoreL(CChemicalElement::TElementType aElementType) const
{
    //First make an element list containing only the specified element type
    //(Could just use an RArray "raw," but then I'd have to write my own exernalizer!)
    CElementList* list = new (ELeave) CElementRArray;
    CleanupStack::PushL(list);

    for (TInt i = 0; i < iElementList->NumberOfElements() ;i++)
    {
        const CChemicalElement& element = iElementList->At(i);
        if (element.Type() != aElementType)
        {
            //Not the right type
            continue;
        }

        //Now make a copy of this element
        CChemicalElement* copy = CChemicalElement::NewLC(element.Name(), element.Symbol(),
            element.AtomicNumber(), element.RelativeAtomicMass(), aElementType, element.Radioactive());
        list->AppendL(copy);
        CleanupStack::Pop(copy);    //Ownership transferred to list which is already on stack
    }

    //Now we have a list with its own copies, we can externalise it
    RStoreWriteStream stream;
    TStreamId id = stream.CreateLC(*iStore);
    stream << *list;
    stream.CommitL();

    //deleting list is safe, since it has its own copies of the elements!
    CleanupStack::PopAndDestroy(2, list);    //stream, list
    return id;
}


// End of File

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?