diff -r 000000000000 -r f58d6ec98e88 aknlayoutcompiler/src/MLCompData.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/aknlayoutcompiler/src/MLCompData.cpp Thu Dec 17 09:14:18 2009 +0200 @@ -0,0 +1,1312 @@ +/* +* Copyright (c) 2002-2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +* +*/ + + +#include "MLCompData.h" +#include "MLCompDataParse.h" +#include "MLCompData2Cdl.h" +#include "MLAttributes.h" + +#include "LayoutCompilerErr.h" +#include "CodeGenConsts.h" +#include "UsefulDefinitions.h" + +#include "Akndef.hrh" + +#include +#include +#include +#include + + +// +// const data +// + +const string KCompDataPaneOutputOrder[] = {"C", "l", "t", "r", "b", "W", "H"}; +const string KCompDataPaneOutputOrderMirrored[] = {"C", "r", "t", "l", "b", "W", "H"}; +const int KCompDataPaneOutputOrderSize = ARRAY_LEN(KCompDataPaneOutputOrder); + +const string KCompDataGraphicOutputOrder[] = {"NumCols", "NumRows", "C", "l", "t", "r", "b", "W", "H"}; +const string KCompDataGraphicOutputOrderMirrored[] = {"NumCols", "NumRows", "C", "r", "t", "l", "b", "W", "H"}; +const int KCompDataGraphicOutputOrderSize = ARRAY_LEN(KCompDataGraphicOutputOrder); + +const string KCompDataTextOutputOrder[] = {"NumCols", "NumRows", "C", "l", "t", "r", "b", "W", "H", "J", "Font"}; +const string KCompDataTextOutputOrderMirrored[] = {"NumCols", "NumRows", "C", "r", "t", "l", "b", "W", "H", "J", "Font"}; +const int KCompDataTextOutputOrderSize = ARRAY_LEN(KCompDataTextOutputOrder); + +const string KCompDataKeywordParamHeight = "H"; +const string KCompDataKeywordParamType = "Type"; +const string KCompDataKeywordParamFont = "Font"; +const string KCompDataKeywordParamNumCols = "NumCols"; +const string KCompDataKeywordParamNumRows = "NumRows"; +const string KCompDataKeywordScreenContents = "Screen Contents"; + +const string KCompDataKeywordUnderscore = "_"; +const string KCompDataKeywordLineNameSuffixGraphic = "g"; +const string KCompDataKeywordLineNameSuffixText = "t"; + +const string KCompDataSearchCollectionNumeric = "0123456789"; +const string KCompDataBadValue = "Bad Value"; +const string KCompDataLayoutEmpty = "ELayoutEmpty"; +const string KCompDataUnknown = "unknown"; + +const string KCompDataCellNameLeft("l"); +const string KCompDataCellNameRight("r"); +const string KCompDataCellNameJustification("J"); + +const string KAttributeNameStyle1 = "style_1"; +const string KAttributeNameStyle2 = "style_2"; +const string KAttributeNameStyle3 = "style_3"; +const string KAttributeNameStyle1Plain = "plain"; +const string KAttributeNameStyle1Bold = "bold"; +const string KAttributeNameStyle3Outline = "outline"; + +const string KAttributeNameNumberOfColumns = "Number_of_columns"; +const string KAttributeNameNumberOfRows = "Number_of_rows"; +const string KAttributeNameNumberOfRowsColsAuto = "AUTO"; + + +// +// TMLCompDataValues +// + +TMLCompDataValues::TMLCompDataValues() + : + iLine(NULL), + iName(KCompDataBadValue) + { + } + +TMLCompDataValues::TMLCompDataValues(TMLCompDataLine* aLine) + : + iLine(aLine), + iName(aLine->iName) + { + } + +bool TMLCompDataValues::operator==(const TMLCompDataValues& aOther) const + { + typedef const map TBase; + bool eq = + iName == aOther.iName && + (*static_cast(this) == aOther); + return eq; + } + +TMLCompDataValues::~TMLCompDataValues() + { + } + +bool TMLCompDataValues::Merge(TMLCompDataLine* aLine, string aName, TMLCompDataValues& aOtherValues, bool aMirrorMerge) + { + iLine = aLine; + iName = aName; // we may be swapping l and r + + // create missing values in this line if needed + for (iterator pOtherVal=aOtherValues.begin(); pOtherVal!=aOtherValues.end(); ++pOtherVal) + { + TMLCompDataZoomLevels& otherZoomLevels = pOtherVal->second; + TMLCompDataZoomLevels& thisZoomLevels = (*this)[pOtherVal->first]; + thisZoomLevels = otherZoomLevels; // we want exactly the correct number of calcs from the other cell + if(aMirrorMerge) + { + if(iName == KCompDataCellNameJustification) + { + // reverse the justification + for(TMLCompDataZoomLevels::iterator pCalcs = thisZoomLevels.begin(); pCalcs != thisZoomLevels.end(); ++pCalcs) + { + TMLCompDataCalcs& calcs = pCalcs->second; + for(TMLCompDataCalcs::iterator pVal = calcs.begin(); pVal != calcs.end(); ++pVal) + pVal->second = MirrorJustificationValue(pVal->second); + } + } + } + } + return true; + } + +const string KParamLimitNames[] = { "NumCols", "NumRows" }; +const string KHorizNames[] = { "l", "r", "W" }; +const string KVertNames[] = { "t", "b", "H", "Font" }; +const set KParamLimitNamesSet(KParamLimitNames, ARRAY_END(KParamLimitNames)); +const set KHorizNamesSet(KHorizNames, ARRAY_END(KHorizNames)); +const set KVertNamesSet(KVertNames, ARRAY_END(KVertNames)); + +TMLCompDataValues::TCompDataCellType TMLCompDataValues::Type(string aName) + { + TMLCompDataValues::TCompDataCellType type; + if(KParamLimitNamesSet.find(aName) != KParamLimitNamesSet.end()) + { + type = TMLCompDataValues::ECellTypeParamLimit; + } + else if(KHorizNamesSet.find(aName) != KHorizNamesSet.end()) + { + type = TMLCompDataValues::ECellTypeCol; + } + else if(KVertNamesSet.find(aName) != KVertNamesSet.end()) + { + type = TMLCompDataValues::ECellTypeRow; + } + else + { + type = TMLCompDataValues::ECellTypeDefault; + } + return type; + } + + +string TMLCompDataValues::MirrorJustificationValue(const string& aValue) + { + int val = CdlTkUtil::ParseInt(aValue); + if(val == ELayoutAlignLeft) + val = ELayoutAlignRight; + else if(val == ELayoutAlignRight) + val = ELayoutAlignLeft; + return CdlTkUtil::IntToString(val); + } + + +void TMLCompDataValues::Compile(const string& aCellName) + { + // ensure that missing varieties are filled with null values + // we assume that each variety is present in all zoom levels that are defined + if(iLine) // screen contents isn't contained in a line + { + int thisSize = size(); + int numVarieties = iLine->MaxVariety() + 1; // get zero based index + int maximum = max(numVarieties, thisSize); + int maxMulti; + switch(TMLCompDataValues::Type(aCellName)) + { + case ECellTypeCol: + maxMulti = iLine->NumCols(); + break; + case ECellTypeRow: + maxMulti = iLine->NumRows(); + break; + default: + maxMulti = 1; + break; + } + for(int ii = 0; ii < maximum; ii++) + { + // operator[] fills in missing values + TMLCompDataZoomLevels& zoomLevels = (*this)[ii]; + for(TMLCompDataZoomLevels::iterator pCalcs = zoomLevels.begin(); pCalcs != zoomLevels.end(); ++pCalcs) + { + TMLCompDataCalcs& calcs = pCalcs->second; + if(ii < numVarieties) + { + if(calcs.size() > maxMulti) + { + // Handle the case where data from a merged instance has too many calcs + TMLCompDataCalcs::iterator start = calcs.find(maxMulti); + TMLCompDataCalcs::iterator end = calcs.end(); + calcs.erase(start, end); + } + } + else + { + // get rid of varieties from instances that we have merged onto + calcs.clear(); + } + } + } + } + } + +string TMLCompDataValues::CppValue(const string& aValue) + { + if (aValue.size()) + return aValue; + else + return KCompDataLayoutEmpty; + } + +// +// TMLCompDataParentInfoSelector +// +TMLCompDataParentInfoSelector::TMLCompDataParentInfoSelector() + { + + } + +TMLCompDataParentInfoSelector::TMLCompDataParentInfoSelector(int aParentId, int aParentVariety) + : + iParentId(aParentId), + iParentVariety(aParentVariety) + { + + } + +// +// TMLCompDataParentInfo +// + +TMLCompDataParentInfo::TMLCompDataParentInfo() + : + iLine(0) + { + + } + +TMLCompDataParentInfo::TMLCompDataParentInfo(TMLCompDataLine* aLine) + : + iLine(aLine) + { + + } + +TMLCompDataParentInfo::~TMLCompDataParentInfo() + { + + } + +void TMLCompDataParentInfo::Merge(const TMLCompDataParentInfo& aOther) + { + for (const_iterator pOtherVariety = aOther.begin(); pOtherVariety != aOther.end(); ++pOtherVariety) + { + int varietyIndex = pOtherVariety->first; + const TMLCompDataParentInfoSelector& selector = pOtherVariety->second; + insert(make_pair(varietyIndex, selector)); + } + } + +// +// TMLCompDataLine +// + +TMLCompDataLine::TMLCompDataLine() +: iId(0), + iIsUnique(true), + iIsMirroredHorizontally(false), + iType(EUnknownComponent), + iName(KCompDataUnknown), + iDrawingOrder(-1), + iMaxVariety(0), + iParentTable(0), + iParentInfo(0), + iAttributeInfo(0), + iNumCols(1), + iNumRows(1), + iNeedsOptions(false), + iNeedsCols(false), + iNeedsRows(false), + iGlobalIndex(0) + { + + } + +TMLCompDataLine::TMLCompDataLine(const TMLCompDataLine& aOther) + { + if(this == &aOther) + return; + *this = aOther; // this will take a copy of the owning pointer + if(aOther.iParentInfo) // if it wasn't zero + iParentInfo = new TMLCompDataParentInfo(*(aOther.iParentInfo)); // we don't want to take ownership, so make our own copy + if(aOther.iAttributeInfo) // if it wasn't zero + iAttributeInfo = new TMLCompDataAttributeInfo(*(aOther.iAttributeInfo)); // we don't want to take ownership, so make our own copy + + for (iterator pVal = begin(); pVal != end(); ++pVal) + { + TMLCompDataValues& val = pVal->second; + val.iLine = this; + } + iParentTable = 0; // will be set during compile + } + +bool TMLCompDataLine::operator==(const TMLCompDataLine& aOther) const + { + return (Name() == aOther.Name()) && ValuesEqual(aOther); + } + +TMLCompDataLine::~TMLCompDataLine() + { + delete iParentInfo; + delete iAttributeInfo; + } + +bool TMLCompDataLine::lessthan(TMLCompDataLine* aLeft, TMLCompDataLine* aRight) + { + string pureNameLeft = aLeft->NameDiscountingSuffix(); + string pureNameRight = aRight->NameDiscountingSuffix(); + if(pureNameLeft != pureNameRight) + { + return (aLeft->iName) < (aRight->iName); + } + else + { + int left = CdlTkUtil::ParseInt(aLeft->NameSuffix()); + int right = CdlTkUtil::ParseInt(aRight->NameSuffix()); + return left < right; + } + } + +bool TMLCompDataLine::ValuesEqual(const TMLCompDataLine& aOther) const + { + bool eq = true; + const_iterator pVal, pOther; + for (pVal = begin(), pOther = aOther.begin(); + eq && pVal != end() && pOther != aOther.end(); + ++pVal, ++pOther) + { + eq = (*pVal == *pOther); + } + eq = eq && pVal == end() && pOther == aOther.end(); + return eq; + } + +string TMLCompDataLine::Name() const + { + return iName; + } + +bool TMLCompDataLine::Merge(TMLCompDataLine& aOtherLine) + { + bool compatible = + (iId == aOtherLine.iId) || + (iName == aOtherLine.iName) || + (iType == aOtherLine.iType); + if(compatible) + { + iDrawingOrder = aOtherLine.iDrawingOrder; + iMaxVariety = aOtherLine.iMaxVariety; + iIsMirroredHorizontally |= aOtherLine.iIsMirroredHorizontally; // in the case of an elaf layout merging onto an abrw layout, the chirality will be preserved + iNeedsOptions |= aOtherLine.iNeedsOptions; + + if(!iParentInfo) + { + // must be screen... + iParentInfo = new TMLCompDataParentInfo(); + } + if(aOtherLine.iParentInfo) + { + iParentInfo->Merge(*(aOtherLine.iParentInfo)); + } + + if(!iAttributeInfo) + { + // must be screen... + iAttributeInfo = new TMLCompDataAttributeInfo(); + } + if(aOtherLine.iAttributeInfo) + { + iAttributeInfo->Merge(*(aOtherLine.iAttributeInfo)); + } + + // for the API, we need to know if there are any multi-value components in either orientation + iNeedsCols = iNeedsCols || aOtherLine.iNeedsCols; + iNeedsRows = iNeedsRows || aOtherLine.iNeedsRows; + // however, we want exactly the correct number of calcs from the other cell + iNumCols = aOtherLine.iNumCols; + iNumRows = aOtherLine.iNumRows; + + // if this line has no values, then we must do a mirror merge + bool mirrorMerge = empty() && iIsMirroredHorizontally; + + // create missing values in this line if needed + for (TMLCompDataLine::iterator pOtherValues=aOtherLine.begin(); pOtherValues!=aOtherLine.end(); ++pOtherValues) + { + string index = pOtherValues->first; + if(mirrorMerge) + { + // flip left and right + if(index == KCompDataCellNameLeft) + index = KCompDataCellNameRight; + else if(index == KCompDataCellNameRight) + index = KCompDataCellNameLeft; + } + + (*this)[index].Merge(this, index, pOtherValues->second, mirrorMerge); + } + } + return compatible; + } + +TMLAttributeZoomLevels* TMLCompDataLine::GetAttributeZoomLevels(string aAttribName, int aVariety) + { + TMLAttributeZoomLevels* found = 0; + TMLCompData& data = *(iParentTable->iTables); + TMLAttributes& attributes = *(data.iAttributes); + int attribId = attributes.iNames[aAttribName]; + if(attribId == 0) + throw GeneralErr(string("Attribute name not found: ") + aAttribName); + // find out from attribute info which attribute set we need + // but if there is none specified, we don't need to search + if(iAttributeInfo) + { + TMLCompDataAttributeInfoSelector& selector = (*iAttributeInfo)[aVariety]; + // go to parent straight away, as parent always stores attribute data for its children + found = GetParentAttributeZoomLevels(selector.iAttributeSetName, attribId, aVariety); + } + return found; + } + +TMLAttributeZoomLevels* TMLCompDataLine::GetParentAttributeZoomLevels(string aAttribSetName, int aAttribId, int aVariety) + { + TMLAttributeZoomLevels* found = NULL; + TMLCompDataParentInfo::iterator pFoundSelector = iParentInfo->find(aVariety); + if(pFoundSelector != iParentInfo->end()) + { + const TMLCompDataParentInfoSelector& parentInfoSelector = pFoundSelector->second; + if(iParentTable && iParentTable->iParentLine) + { + found = iParentTable->iParentLine->FindAttributeZoomLevels(aAttribSetName, aAttribId); + if(!found) + { + // recurse to next parent container + int variety = parentInfoSelector.iParentVariety; + iParentTable->iParentLine->GetParentAttributeZoomLevels(aAttribSetName, aAttribId, variety); + } + } + } + return found; + } + +TMLAttributeZoomLevels* TMLCompDataLine::FindAttributeZoomLevels(string aAttribSetName, int aAttribId) + { + TMLCompData& data = *(iParentTable->iTables); + TMLAttributes& attributes = *(data.iAttributes); + int id = iId; + TMLAttributes::iterator foundAttributeSetComponent = attributes.find(id); + if(foundAttributeSetComponent != attributes.end()) + { + TMLAttributeSetComponent& component = foundAttributeSetComponent->second; + TMLAttributeSet* pSet = component[aAttribSetName]; + if(pSet) + { + TMLAttributeSet& attributeSet = *pSet; + TMLAttributeSet::iterator foundAttrib = attributeSet.find(aAttribId); + if(foundAttrib != attributeSet.end()) + { + return &(foundAttrib->second); + } + } + } + return NULL; + } + +void TMLCompDataLine::Compile() + { + // compile values + for(iterator pVal = begin(); pVal != end(); ++pVal) + { + (pVal->second).Compile(pVal->first); + } + CompileParamLimits(TMLCompDataValues::ECellTypeCol, KCompDataKeywordParamNumCols); + CompileParamLimits(TMLCompDataValues::ECellTypeRow, KCompDataKeywordParamNumRows); + CompileFontHeights(); + } + +void TMLCompDataLine::CompileParamLimits(TMLCompDataValues::TCompDataCellType aParamLimitType, const string& aParamLimitCellName) + { + TMLCompDataValues paramLimits(this); + + for(iterator pValues = begin(); pValues != end(); ++pValues) + { + string cellName = pValues->first; + if(TMLCompDataValues::Type(cellName) == aParamLimitType) + { + // calculate the param limits for this cell + TMLCompDataValues& values = pValues->second; + for(TMLCompDataValues::iterator pZoomLevels = values.begin(); pZoomLevels != values.end(); ++pZoomLevels) + { + int nextVariety = pZoomLevels->first; + TMLCompDataZoomLevels& zoomLevels = pZoomLevels->second; + TMLCompDataZoomLevels& paramLimitsZoomLevels = paramLimits[nextVariety]; + for(TMLCompDataZoomLevels::iterator pCalcs = zoomLevels.begin(); pCalcs != zoomLevels.end(); ++pCalcs) + { + // accumulate the largest size of calc into the param limit + int zoomLevel = pCalcs->first; + int nextParamLimit = pCalcs->second.size(); + TMLCompDataCalcs& paramLimitCalcs = paramLimitsZoomLevels[zoomLevel]; + string& paramLimit = paramLimitCalcs[0]; + int currentParamLimit = CdlTkUtil::ParseInt(paramLimit); + if(nextParamLimit > currentParamLimit) + paramLimit = CdlTkUtil::IntToString(nextParamLimit); + } + if(!paramLimitsZoomLevels.size()) + { + // there were no defined values for this variety, but we know we'll + // insert an empty value at least + TMLCompDataCalcs& paramLimitCalcs = paramLimitsZoomLevels[EAknUiZoomNormal]; + paramLimitCalcs.insert(make_pair(0, CdlTkUtil::IntToString(1))); + } + } + } + } + insert(make_pair(aParamLimitCellName, paramLimits)); + } + +void TMLCompDataLine::CompileFontHeights() + { + if(iType == ETextComponent) + { + TMLCompDataValues font(this); + + TMLCompDataValues types = (*this)[KCompDataKeywordParamType]; + TMLCompDataValues heights = (*this)[KCompDataKeywordParamHeight]; + + // note that these are the number of varieties, there may be zoom level and then rows inside + int numTypeVarieties = types.size(); + int numHeightVarieties = heights.size(); + + for(TMLCompDataValues::iterator pZoomLevels = heights.begin(); pZoomLevels != heights.end(); ++pZoomLevels) + { + int nextVariety = pZoomLevels->first; + TMLAttributeZoomLevels* style1ZoomLevels = GetAttributeZoomLevels(KAttributeNameStyle1, nextVariety); + TMLAttributeZoomLevels* style3ZoomLevels = GetAttributeZoomLevels(KAttributeNameStyle3, nextVariety); + TMLCompDataZoomLevels& heightsZoomLevels = pZoomLevels->second; + TMLCompDataZoomLevels& typesZoomLevels = types[nextVariety]; + TMLCompDataZoomLevels& fontZoomLevels = font[nextVariety]; + + for(TMLCompDataZoomLevels::iterator pHeightCalcs = heightsZoomLevels.begin(); pHeightCalcs != heightsZoomLevels.end(); ++pHeightCalcs) + { + // if the types don't have zoom data, fall back to normal zoom + int zoomIndex = pHeightCalcs->first; + int numTypesZoomLevels = typesZoomLevels.size(); + int typeZoomIndex = numTypesZoomLevels > 1 ? zoomIndex : EAknUiZoomNormal; + TMLCompDataCalcs& typeCalcs = typesZoomLevels[typeZoomIndex]; + + // get attribute data + int outline = 0; + int posture = 0; + int weight = 0; + if(style1ZoomLevels) + { + string style1 = (*style1ZoomLevels)[pHeightCalcs->first]; + if(style1 == KAttributeNameStyle1Bold) + weight = 1; + } + if(style3ZoomLevels) + { + string style3 = (*style3ZoomLevels)[pHeightCalcs->first]; + if(style3 == KAttributeNameStyle3Outline) + outline = 1; + } + + // we want to have a font id for each height, even if the spec + // has not specified the type each time + TMLCompDataCalcs& fontCalcs = fontZoomLevels[pHeightCalcs->first]; + TMLCompDataCalcs& next = pHeightCalcs->second; + for(TMLCompDataCalcs::iterator pHeightCalc = next.begin(); pHeightCalc != next.end(); ++pHeightCalc) + { + // for undefined type, let font provider use default, + // and always choose the first type for a multi value item + int calcIndex = pHeightCalc->first; + int type = numTypeVarieties > 0 ? CdlTkUtil::ParseInt(typeCalcs[0]) : ELayoutCompilerFontCategoryUndefined; + int height = numHeightVarieties > 0 ? CdlTkUtil::ParseInt(pHeightCalc->second) : 0; + int fontId = EncodeFontId(height, outline, posture, weight, type); + fontCalcs[calcIndex] = CdlTkUtil::IntToString(fontId); + } + } + } + insert(make_pair(string(KCompDataKeywordParamFont), font)); + } + } + +int TMLCompDataLine::EncodeFontId(int aHeight, int aOutline, int aPosture, int aWeight, int aCategory) const + { + // + // 31 | 30 - 21 | 20 - 07 | 06 | 05 | 04 | 03 - 00 + // encoded | text pane height 0-1023 | | outline | posture | weight | category + + int encodedMasked = 1 << 31; + int heightMasked = aHeight << 21; + + int outlineMasked = aOutline << 6; + int postureMasked = aPosture << 5; + int weightMasked = aWeight << 4; + int categoryMasked = aCategory; + + return(encodedMasked | heightMasked | outlineMasked | postureMasked | weightMasked | categoryMasked); + } + +bool TMLCompDataLine::MatchParams(const TMLCompDataLine& aLine) const + { + if (NeedsOptions() != aLine.NeedsOptions()) + return false; + if (NeedsCols() != aLine.NeedsCols()) + return false; + if (NeedsRows() != aLine.NeedsRows()) + return false; + return true; + } + +bool TMLCompDataLine::MatchNameDiscountingSuffix(const TMLCompDataLine& aLine) const + { + // we are trying to compare whether the names are the same apart from a trailing number + string pureName = NameDiscountingSuffix(); + string pureNameOther = aLine.NameDiscountingSuffix(); + string ending = pureName.substr(pureName.find_last_not_of(KCompDataKeywordUnderscore)); + + bool namesMatch = (pureName == pureNameOther); + bool correctEnding = (ending == KCompDataKeywordLineNameSuffixGraphic || ending == KCompDataKeywordLineNameSuffixText); + return (namesMatch && correctEnding); + } + +bool TMLCompDataLine::MatchType(const TMLCompDataLine& aLine) const + { + // first check that the type is equivalent + bool equivalent = false; + switch(iType) + { + case ETextComponent: + { + if(aLine.iType == ETextComponent) + { + equivalent = true; + } + break; + } + case EScreenComponent: + case EContainerComponent: + case EPaneComponent: + case EGraphicComponent: + { + if(aLine.iType == EScreenComponent + || aLine.iType == EContainerComponent + || aLine.iType == EPaneComponent + || aLine.iType == EGraphicComponent) + { + equivalent = true; + } + break; + } + case EUnknownComponent: + default: + { + if(aLine.iType == EUnknownComponent) + { + equivalent = true; + } + break; + } + } + + return equivalent; + } + +string TMLCompDataLine::NameDiscountingSuffix() const + { + int lastNonNumericPos = iName.find_last_not_of(KCompDataSearchCollectionNumeric); + int length = lastNonNumericPos + 1; + return iName.substr(0, length); + } + +string TMLCompDataLine::NameSuffix() const + { + int lastNonNumericPos = iName.find_last_not_of(KCompDataSearchCollectionNumeric); + int suffixPos = lastNonNumericPos + 1; + return iName.substr(suffixPos); + } + +bool TMLCompDataLine::NeedsParams() const + { + return iNeedsOptions || iNeedsCols || iNeedsRows; + } + +bool TMLCompDataLine::NeedsOptions() const + { + return iNeedsOptions; + } + +bool TMLCompDataLine::NeedsCols() const + { + return iNeedsCols; + } + +bool TMLCompDataLine::NeedsRows() const + { + return iNeedsRows; + } + +int TMLCompDataLine::MaxVariety() const + { + return iMaxVariety; + } + +int TMLCompDataLine::NumCols() const + { + return iNumCols; + } + +int TMLCompDataLine::NumRows() const + { + return iNumRows; + } + + +void TMLCompDataLine::SetMaxVariety(int aMaxVariety) + { + iMaxVariety = aMaxVariety; + if(iMaxVariety > 0) // zero based + iNeedsOptions = true; + } + +void TMLCompDataLine::SetNumCols(int aNumCols) + { + iNumCols = aNumCols; + if(iNumCols > 1) + iNeedsCols = true; + } + +void TMLCompDataLine::SetNumRows(int aNumRows) + { + iNumRows = aNumRows; + if(iNumRows > 1) + iNeedsRows = true; + } + +void TMLCompDataLine::SetNeedsCols(bool aNeeds) + { + iNeedsCols = aNeeds; + } + +void TMLCompDataLine::SetNeedsRows(bool aNeeds) + { + iNeedsRows = aNeeds; + } + +// +// TMLCompDataAttributeInfoSelector +// +TMLCompDataAttributeInfoSelector::TMLCompDataAttributeInfoSelector() + { + + } + +TMLCompDataAttributeInfoSelector::TMLCompDataAttributeInfoSelector(string aAttributeSetName) + : + iAttributeSetName(aAttributeSetName) + { + + } + +// +// TMLCompDataAttributeInfo +// + +TMLCompDataAttributeInfo::TMLCompDataAttributeInfo() + : + iLine(0) + { + + } + +TMLCompDataAttributeInfo::TMLCompDataAttributeInfo(TMLCompDataLine* aLine) + : + iLine(aLine) + { + + } + +TMLCompDataAttributeInfo::~TMLCompDataAttributeInfo() + { + + } + +void TMLCompDataAttributeInfo::Merge(const TMLCompDataAttributeInfo& aOther) + { + for (const_iterator pOtherVariety = aOther.begin(); pOtherVariety != aOther.end(); ++pOtherVariety) + { + int varietyIndex = pOtherVariety->first; + const TMLCompDataAttributeInfoSelector& selector = pOtherVariety->second; + insert(make_pair(varietyIndex, selector)); + } + } + + + +// +// TMLCompDataTable::TMLCompDataSubTable +// + +bool TMLCompDataTable::TMLCompDataSubTable::NeedsParams() const + { + return iNeedsOption || iNeedsCol || iNeedsRow; + } + + +// +// TMLCompDataTable +// + +TMLCompDataTable::TMLCompDataTable(TMLCompData* aTables) + : + iTables(aTables), + iParentLine(NULL), + iFirstLineGlobalIndex(-1), + iAppend(false), + iId(0), + iNeedsP(false), + iNeedsIndex(false) + { + } + +TMLCompDataTable::TMLCompDataTable(TMLCompData* aTables, const TMLCompDataTable& aOther) + : + iTables(aTables), + iParentLine(NULL), + iFirstLineGlobalIndex(aOther.iFirstLineGlobalIndex), + iAppend(aOther.iAppend), iColumnNames(aOther.iColumnNames), iName(aOther.iName), + iParentName(aOther.iParentName), + iId(aOther.iId) + { + for (const_iterator pLine = aOther.begin(); pLine != aOther.end(); ++pLine) + push_back(new TMLCompDataLine(**pLine)); + } + +TMLCompDataTable::~TMLCompDataTable() + { + for (iterator pLine = begin(); pLine != end(); ++pLine) + delete *pLine; + } + +bool TMLCompDataTable::lessthan(TMLCompDataTable* aLeft, TMLCompDataTable* aRight) + { + return (aLeft->iId) < (aRight->iId); + } + +string TMLCompDataTable::Name() + { + return iName; + } + +TMLCompDataLine* TMLCompDataTable::FindLine(const string& aName) + { + for (iterator pLine = begin(); pLine != end(); ++pLine) + { + TMLCompDataLine& line = **pLine; + string paramLimitsName = MLCompDataToCdl::LineParamLimitsApiName(line); + // first check the lines for a direct match + // then try the param limits instead + if (line.Name() == aName || + (line.NeedsParams() && paramLimitsName == aName)) + return *pLine; + } + return 0; + } + +TMLCompDataTable::TMLCompDataSubTable* TMLCompDataTable::FindSubTable(const string& aName) + { + for(TMLCompDataSubTables::iterator pSub = iSubTables.begin(); pSub != iSubTables.end(); ++pSub) + { + TMLCompDataSubTable& sub = **pSub; + string subTableName = MLCompDataToCdl::SubTableApiName(sub); + string subTableLimitsName = MLCompDataToCdl::SubTableLimitsApiName(sub); + string paramLimitsName = MLCompDataToCdl::SubTableParamLimtsApiName(sub); + TMLCompDataLine& line = *((*this)[0]); + // first check the lines for a direct match + // then try the param limits instead + if (subTableName == aName || + subTableLimitsName == aName || + (sub.NeedsParams() && paramLimitsName == aName)) // need to check whether the subtable needs params + return ⊂ + } + return 0; + } + +void TMLCompDataTable::Merge(TMLCompDataTable& aOther) + { + for (iterator pOtherLine = aOther.begin(); pOtherLine != aOther.end(); ) + { + TMLCompDataLine* found = FindLine((*pOtherLine)->Name()); + if(found) + { + found->Merge(**pOtherLine); + delete *pOtherLine; + pOtherLine = aOther.erase(pOtherLine); + } + else + { + push_back(*pOtherLine); + (*pOtherLine)->iParentTable = this; + pOtherLine = aOther.erase(pOtherLine); + } + } + } + + +void TMLCompDataTable::Compile() + { + SetDefaultColumnNames(); + sort(begin(), end(), TMLCompDataLine::lessthan); + + iNeedsIndex = false; + iNeedsP = false; + for (iterator pLine = begin(); pLine != end(); ++pLine) + { + (*pLine)->Compile(); + } + BuildSubTables(); + NormalizeSubTables(); + } + +void TMLCompDataTable::BuildSubTables() + { + DestroySubTables(); + + int count = size(); + if(count > 0) + { + TMLCompDataSubTable* subTable = 0; + for (int i=0; iNameSuffix() == "1" && firstLine->MatchNameDiscountingSuffix(line) && firstLine->MatchType(line)) + { + subTable->iName = line.NameDiscountingSuffix(); + } + else // only terminate the subtable if the lines don't match, or if the first line isn't numbered "1" + { + if (subTable->size() > 1) + iSubTables.push_back(subTable); + else + delete subTable; + subTable = new TMLCompDataSubTable; + } + } + else + { + subTable = new TMLCompDataSubTable; + } + subTable->iNeedsOption |= line.NeedsOptions(); + subTable->iNeedsCol |= line.NeedsCols(); + subTable->iNeedsRow |= line.NeedsRows(); + subTable->push_back(i); + } + + if (subTable->size() > 1) + { + iSubTables.push_back(subTable); + } + else + delete subTable; + } + } + +void TMLCompDataTable::NormalizeSubTables() + { + for(TMLCompDataSubTables::iterator pSub = iSubTables.begin(); pSub != iSubTables.end(); ++pSub) + { + TMLCompDataSubTable& sub = **pSub; + for(TMLCompDataSubTable::iterator pLineId = sub.begin(); pLineId != sub.end(); ++pLineId) + { + TMLCompDataLine& line = *((*this)[*pLineId]); + + line.iNeedsOptions |= sub.iNeedsOption; + line.iNeedsCols |= sub.iNeedsCol; + line.iNeedsRows |= sub.iNeedsRow; + } + } + } + + +void TMLCompDataTable::DestroySubTables() + { + for (TMLCompDataSubTables::iterator pSub = iSubTables.begin(); pSub != iSubTables.end(); ++pSub) + delete *pSub; + iSubTables.clear(); + } + + +const string KValueNames[] = { "Font", "C", "l", "r", "W", "J", "t", "r", "b", "H" }; +const set KValueNamesSet(KValueNames, ARRAY_END(KValueNames)); + +bool TMLCompDataTable::IsValueColumn(string aName) + { + return KValueNamesSet.find(aName) != KValueNamesSet.end(); + } + +const string KNumericNames[] = { "C", "l", "r", "W", "t", "r", "b", "H" }; +const set KNumericNamesSet(KNumericNames, ARRAY_END(KNumericNames)); + +bool TMLCompDataTable::IsNumericColumn(string aName) + { + return KNumericNamesSet.find(aName) != KNumericNamesSet.end(); + } + +const string KHorizontalColumnNames[] = { "l", "r", "W"}; +const set KHorizontalNamesSet(KHorizontalColumnNames, ARRAY_END(KHorizontalColumnNames)); + +bool TMLCompDataTable::IsHorizontalColumn(string aName) + { + return KHorizontalNamesSet.find(aName) != KHorizontalNamesSet.end(); + } + +const string KVerticalColumnNames[] = {"t", "b", "H" }; +const set KVerticalNamesSet(KVerticalColumnNames, ARRAY_END(KVerticalColumnNames)); + +bool TMLCompDataTable::IsVerticalColumn(string aName) + { + return KVerticalNamesSet.find(aName) != KVerticalNamesSet.end(); + } + + +const string KPaneColumnNames[] = {"Item", "C", "l", "t", "r", "b", "W", "H", "Remarks"}; +const string KGraphicColumnNames[] = {"Item", "C", "l", "t", "r", "b", "W", "H", "Remarks"}; +const string KTextColumnNames[] = {"Font", "C", "l", "r", "t", "b", "W", "H", "J", "Remarks"}; + +void TMLCompDataTable::SetDefaultColumnNames() + { + iColumnNames.clear(); + iColumnNames.insert(iColumnNames.end(), KPaneColumnNames, ARRAY_END(KTextColumnNames)); // superset + } + +TMLCompDataTable::TMLCompDataSubTable::TMLCompDataSubTable() +: + iNeedsOption(false), + iNeedsCol(false), + iNeedsRow(false) + { + } + + +// +// TMLCompData +// + +TMLCompData::TMLCompData() + : + iCanBeMirror(false), + iIsBaseInstance(false), + iAttributes(0) + { + } + +TMLCompData::TMLCompData(const TMLCompData& aOther) + { + *this = aOther; + } + +TMLCompData& TMLCompData::operator=(const TMLCompData& aOther) + { + if (this != &aOther) + { + iName = aOther.iName; + iCanBeMirror = aOther.iCanBeMirror; + for (const_iterator pTab = aOther.begin(); pTab != aOther.end(); ++pTab) + push_back(new TMLCompDataTable(this, **pTab)); + Compile(); + } + return *this; + } + +TMLCompData::~TMLCompData() + { + for (iterator pTab = begin(); pTab != end(); ++pTab) + delete *pTab; + DeleteComponents(); + delete iAttributes; + } + +TMLCompDataLine* TMLCompData::FindComponent(const string& aName) const + { + for (TMLComponents::const_iterator pComp = iComponents.begin(); pComp != iComponents.end(); ++pComp) + { + TMLCompDataLine* line = pComp->second; + if (line->Name() == aName) + return line; + } + + return 0; + } + +TMLCompDataLine* TMLCompData::FindLine(const string& aName) const + { + for (const_iterator pTab = begin(); pTab != end(); ++pTab) + { + TMLCompDataLine* line = (*pTab)->FindLine(aName); + if (line) + return line; + } + + return 0; + } + +TMLCompDataTable* TMLCompData::FindTable(const string& aName) const + { + for (const_iterator pTab = begin(); pTab != end(); ++pTab) + { + if ((*pTab)->Name() == aName) + return *pTab; + } + + return 0; + } + +TMLCompDataTable* TMLCompData::FindTable(int aId) const + { + for (const_iterator pTab = begin(); pTab != end(); ++pTab) + { + if ((*pTab)->iId == aId) + return *pTab; + } + + return 0; + } + +TMLCompDataTable::TMLCompDataSubTable* TMLCompData::FindSubTable(const string& aName) const + { + for (const_iterator pTab = begin(); pTab != end(); ++pTab) + { + TMLCompDataTable::TMLCompDataSubTable* sub = (*pTab)->FindSubTable(aName); + if (sub) + return sub; + } + + return 0; + } + + +void TMLCompData::Merge(TMLCompData& aOther) + { + iName = aOther.iName; + iCanBeMirror |= aOther.iCanBeMirror; // in the case of an elaf layout merging onto an abrw layout, the chirality will be preserved + MergeComponents(aOther); + } + +void TMLCompData::MergeComponents(TMLCompData& aOther) + { + for (TMLComponents::iterator pOtherLine = aOther.iComponents.begin(); pOtherLine != aOther.iComponents.end(); ++pOtherLine) + { + TMLCompDataLine& otherLine = *(pOtherLine->second); + TMLCompDataLine* found = FindComponent(otherLine.iName); + if(found) + { + found->Merge(otherLine); + } + else + { + TMLCompDataLine* newLine = new TMLCompDataLine(otherLine); + iComponents.insert(make_pair(otherLine.iId, newLine)); + } + } + } + +void TMLCompData::Compile() + { + CreateTables(); + + // now add a special table for the screen contents + TMLCompDataTable* topTab = new TMLCompDataTable(this); + topTab->iId = -1; + topTab->iName = KCompDataKeywordScreenContents; + + // then insert each line into its parent + for (TMLComponents::iterator pComp2 = iComponents.begin(); pComp2 != iComponents.end(); ++pComp2) + { + TMLCompDataLine& line = *(pComp2->second); + if(line.iType == TMLCompDataLine::EScreenComponent) + { + line.iParentTable = topTab; + topTab->push_back(&line); + } + else + { + bool parentFound = false; + int parentId = 0; + if(line.iParentInfo) + { + TMLCompDataParentInfo& parentInfo = *(line.iParentInfo); + TMLCompDataParentInfoSelector& selector = (parentInfo.begin())->second; // we ignore the varieties for now + parentId = selector.iParentId; + TMLCompDataTable* parentTable = FindTable(parentId); + TMLCompDataLine* parentLine = iComponents[parentId]; + if(parentTable) + { + line.iParentTable = parentTable; + // copy the pointer from the components table + parentTable->push_back(&line); + parentFound = true; + // now insert the table into its place in the tree + parentTable->iParentLine = iComponents[parentId]; + } + else + { + parentFound = false; + } + } + if(!parentFound) + { + string errorText = string(" TMLCompData::Compile() - can't find parent component: "); + errorText += CdlTkUtil::IntToString(parentId); + throw GeneralErr(errorText); + } + } + } + push_back(topTab); + + // remember not to delete the components, as we have taken copies! + iComponents.clear(); + + // now compile the tables + iterator pTab; + for (pTab = begin(); pTab != end(); ++pTab) + (*pTab)->Compile(); + + // now sort the tables + sort(begin(), end(), TMLCompDataTable::lessthan); + } + +void TMLCompData::CreateTables() + { + // from the list of components, first create a table for each pane + for (TMLComponents::iterator pComp = iComponents.begin(); pComp != iComponents.end(); ++pComp) + { + TMLCompDataLine& line = *(pComp->second); + switch(line.iType) + { + case TMLCompDataLine::EScreenComponent: + case TMLCompDataLine::EContainerComponent: + case TMLCompDataLine::EPaneComponent: + { + TMLCompDataTable* tab = new TMLCompDataTable(this); + tab->iId = line.iId; + tab->iName = line.iName; + push_back(tab); + break; + } + case TMLCompDataLine::EGraphicComponent: + case TMLCompDataLine::ETextComponent: + { + // text and graphic components are not panes + // and are therefore not represented in our internal object model as tables + break; + } + default: + { + cout << "TMLCompData::CreateTables() - uncategorised component\n"; + break; + } + } + } + } + +void TMLCompData::DeleteComponents() + { + for (TMLComponents::iterator pComp = iComponents.begin(); pComp != iComponents.end(); ++pComp) + delete pComp->second; + } + +// End of File