aknlayoutcompiler/src/Layout.cpp
changeset 0 f58d6ec98e88
child 1 b700e12870ca
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/aknlayoutcompiler/src/Layout.cpp	Thu Dec 17 09:14:18 2009 +0200
@@ -0,0 +1,703 @@
+/*
+* Copyright (c) 2002 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 "Layout.h"
+#include "LayoutCompilerErr.h"
+#include "CodeGenConsts.h"
+#include "UsefulDefinitions.h"
+
+#include <set>
+#include <sstream>
+#include <iostream>
+
+// TValues
+
+TValues::TValues()
+: iLine(0), iName("Bad Value")
+	{
+	}
+
+TValues::TValues(TLayoutLine* aLine, string aName)
+: iLine(aLine), iName(aName), iNeedsIndex(0)
+	{
+	}
+
+bool TValues::operator==(const TValues& aOther) const
+	{
+	typedef const vector<string> TBase;
+	bool eq =
+		iName == aOther.iName &&
+		iParam == aOther.iParam &&
+		iNeedsP == aOther.iNeedsP &&
+		iNeedsIndex == aOther.iNeedsIndex &&
+		(*static_cast<TBase*>(this) == aOther);
+	return eq;
+	}
+
+void TValues::Merge(TValues& aValues)
+	{
+	clear();
+	insert(begin(), aValues.begin(), aValues.end());
+	}
+
+void TValues::Compile()
+	{
+	iNeedsP = false;
+	if (!TLayoutTable::IsValueColumn(iName))
+		return;
+
+	for (iterator it = begin(); it != end(); ++it)
+		{
+		bool back2IsAlphaNum = false;
+		bool back1IsAlphaNum = false;
+		bool back1IsP = false;
+		for (string::iterator pC = it->begin(); pC!=it->end(); ++pC)
+			{
+			bool IsAlphaNum = (
+				('A' <= *pC && *pC <= 'Z') || 
+				('a' <= *pC && *pC <= 'z') ||
+				('0' <= *pC && *pC <= '9') ||
+				*pC == '_');
+
+			if (!back2IsAlphaNum && back1IsP && !IsAlphaNum)
+				iNeedsP = true;
+
+			back1IsP = *pC == 'p';
+			back2IsAlphaNum = back1IsAlphaNum;
+			back1IsAlphaNum = IsAlphaNum;
+			}
+
+		if (!back2IsAlphaNum && back1IsP)
+			iNeedsP = true;
+		}
+	iNeedsIndex = (size() > 1);
+	}
+
+string TValues::ParamName() const
+	{
+	if (iParam.length())
+		return iParam;
+	else
+		return KParamNameBase + iName;
+	}
+
+string TValues::CppValue(const string& aValue)
+	{
+	if (aValue.size())
+		return aValue;
+	else
+		return "ELayoutEmpty";
+	}
+
+
+//  TLayoutLine
+
+TLayoutLine::TLayoutLine( TLayoutTable* aTable, int aId )
+:	iTable(aTable), 
+	iId(aId), 
+	iIsUnique(true), 
+	iIsMirroredHorizontally(false),
+	iIsMergedIdentical(false)
+	{}
+
+TLayoutLine::TLayoutLine(TLayoutTable* aTable, const TLayoutLine& aOther)
+	{
+	*this = aOther;
+	iTable = aTable;
+	for (iterator pVal = begin(); pVal != end(); ++pVal)
+		{
+		TValues& val = pVal->second;
+		val.iLine = this;
+		}
+	}
+
+#ifdef RD_SHOW_ALL_AKNLAYOUTCOMPILER_WARNINGS
+void TLayoutLine::WarnMergeMismatch(TLayoutLine& aLine)
+#else
+void TLayoutLine::WarnMergeMismatch(TLayoutLine& /* aLine */)
+#endif
+	{
+    // Merge mismatch warnings are not shown from old lay files.
+#ifdef RD_SHOW_ALL_AKNLAYOUTCOMPILER_WARNINGS
+	string name = Name();
+	if (name.empty())
+		name = TableName();
+	else
+		name = iTable->iName + " | " + name;
+	cerr << "WARNING merge mismatch: " << iTable->iTables->iName << " | " << name;
+	cerr << " vs " << aLine.iTable->iTables->iName << endl;
+#endif
+	}
+
+void TLayoutLine::Merge(TLayout::TMergeMode aMergeMode, TLayoutLine& aLine)
+	{
+	iIsMergedIdentical = (*this == aLine) && (aMergeMode == TLayout::KMergeModeVariant);
+	if (iIsMergedIdentical)
+		return;
+
+	bool similar = (Name() == aLine.Name());
+	iterator pVal;
+
+	if (similar && aMergeMode == TLayout::KMergeModeVariant && aLine.iTable->iTables->iCanBeMirror)
+		{
+		// need to check to see if the parametrisations are mirrored
+		// first check for P
+		bool lr_p = (find("l")->second.iNeedsP && aLine["r"].iNeedsP);
+		bool rl_p = (find("r")->second.iNeedsP && aLine["l"].iNeedsP);
+		
+		// check if they both params are valid
+		bool lr_both = (find("l")->second.iNeedsIndex && aLine["r"].iNeedsIndex);
+		bool rl_both = (find("r")->second.iNeedsIndex && aLine["l"].iNeedsIndex);
+
+		// check if params are the same
+		bool lr_same = (find("l")->second.iParam == aLine["r"].iParam);
+		bool rl_same = (find("r")->second.iParam == aLine["l"].iParam);
+
+		// only mirrored if both are valid and same
+		bool lr = lr_p || (lr_both && lr_same);
+		bool rl = rl_p || (rl_both && rl_same);
+
+		// if either or both are parametrised the same way, need to swap; doesn't matter if 
+		// both attribs have same param, as swapping it won't make any difference.
+		if(rl || lr)
+			{
+			iIsMirroredHorizontally = true;
+			}
+		}
+
+	if (similar)
+		{
+		for (pVal=begin(); pVal!=end(); ++pVal)
+			{
+			TValues& val = pVal->second;
+			string cell = pVal->first;
+			if (iIsMirroredHorizontally)
+				{
+				if (cell == "l")
+					cell = "r";
+				else if (cell == "r")
+					cell = "l";
+				}
+
+			TValues& other = aLine[cell];
+			if (val.size() != other.size() || 
+				val.iNeedsIndex != other.iNeedsIndex || 
+				val.iNeedsP != other.iNeedsP)
+				{
+				similar = false;
+				}
+			}
+		}
+
+	if (!similar)
+		WarnMergeMismatch(aLine);
+
+	switch(aMergeMode)
+		{
+	case TLayout::KMergeModeMerge:
+	case TLayout::KMergeModeUnion:
+		if (similar)
+			{
+			for (pVal=begin(); pVal!=end(); ++pVal)
+				pVal->second.Merge(aLine[pVal->first]);
+			}
+		else
+			{
+			clear();
+			copy(aLine.begin(), aLine.end(), inserter(*this, begin()));
+			for (pVal=begin(); pVal!=end(); ++pVal)
+				pVal->second.iLine = this;
+			}
+		break;
+	case TLayout::KMergeModeVariant:
+		clear();
+		copy(aLine.begin(), aLine.end(), inserter(*this, begin()));
+		for (pVal=begin(); pVal!=end(); ++pVal)
+			pVal->second.iLine = this;
+		break;
+		}
+	}
+
+bool TLayoutLine::operator==(const TLayoutLine& aOther) const
+	{
+	return (Name() == aOther.Name()) && ValuesEqual(aOther);
+	}
+
+bool TLayoutLine::ValuesEqual(const TLayoutLine& 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 TLayoutLine::Name() const
+	{
+	if (find("Item") != end())
+		return find("Item")->second[0];
+	else
+		return "";
+	}
+
+string TLayoutLine::TableName() const
+	{
+	stringstream name;
+	name << iTable->Name() << "_Line_" << iId;
+	return name.str();
+	}
+
+void TLayoutLine::Compile()
+	{
+	iNeedsP = false;
+	iNeedsIndex = false;
+
+	for (iterator pVal = begin(); pVal != end(); ++pVal)
+		{
+		TValues& val = pVal->second;
+		val.Compile();
+
+		if (val.iNeedsP)
+			iNeedsP = true;
+		if (val.iNeedsIndex)
+			iNeedsIndex = true;
+		}
+	}
+
+bool TLayoutLine::MatchParams(const TLayoutLine& aLine) const
+	{
+	if (iNeedsP != aLine.iNeedsP)
+		return false;
+
+	for (const_iterator pVal = begin(), pOther = aLine.begin(); pVal != end(); ++pVal, ++pOther)
+		{
+		const TValues& val = pVal->second;
+		const TValues& other = pOther->second;
+		if (val.iNeedsIndex != other.iNeedsIndex || val.ParamName() != other.ParamName())
+			return false;
+		}
+
+	return true;
+	}
+
+
+//
+// TLayoutTable
+//
+
+
+
+TLayoutTable::TLayoutTable(TLayout* aTables)
+: iTables(aTables), iType(EUnknownTable), iParent(0), iFirstLineGlobalIndex(-1), iAppend(false), iNoSubTables(false)
+	{
+	}
+
+TLayoutTable::TLayoutTable(TLayout* aTables, const TLayoutTable& aOther)
+: iTables(aTables), iType(aOther.iType), iParent(0), 
+  iFirstLineGlobalIndex(aOther.iFirstLineGlobalIndex), 
+  iAppend(aOther.iAppend), iColumnNames(aOther.iColumnNames), iName(aOther.iName),
+  iParentName(aOther.iParentName), iNoSubTables(aOther.iNoSubTables)
+	{
+	for (const_iterator it = aOther.begin(); it != aOther.end(); ++it)
+		push_back(new TLayoutLine(this, **it));
+	}
+
+TLayoutTable::~TLayoutTable()
+	{
+	for (iterator it = begin(); it != end(); ++it)
+		delete *it;
+	DestroySubTables();
+	}
+
+void TLayoutTable::Merge(TLayout::TMergeMode aMergeMode, TLayoutTable& aTable)
+	{
+	if (aTable.iAppend)
+		{
+		insert(end(), aTable.begin(), aTable.end());
+		aTable.clear();
+		for (iterator pLine = begin(); pLine != end(); ++pLine)
+			(*pLine)->iTable = this;
+		}
+	else
+		{
+		// merge lines
+		iterator pNew = aTable.begin();
+		switch(aMergeMode)
+			{
+			case TLayout::KMergeModeMerge:
+				{
+				if (size() == aTable.size())
+					{
+					for (iterator pLine = begin(); pLine != end(); ++pLine)
+						{
+						(*pLine)->Merge(aMergeMode, **pNew);
+						pNew++;
+						}
+					}
+				else
+					{
+					// move the other tables contents to here
+					iterator pLine;
+					for (pLine = begin(); pLine != end(); ++pLine)
+						delete *pLine;
+					clear();
+					insert(begin(), aTable.begin(), aTable.end());
+					aTable.clear();
+					for (pLine = begin(); pLine != end(); ++pLine)
+						(*pLine)->iTable = this;
+					}
+					break;
+				}
+			case TLayout::KMergeModeVariant:
+				{
+				iterator pLine;
+				// need to merge the matching lines but append the extra ones [LMB 11-10-2002]
+				for (pLine = begin(); pLine != end() && pNew != aTable.end(); ++pLine)
+					{
+					(*pLine)->Merge(aMergeMode, **pNew);
+					pNew++;
+					}
+				insert(end(), pNew, aTable.end());
+				aTable.clear();
+				for (pLine = begin(); pLine != end(); ++pLine)
+					(*pLine)->iTable = this;
+				break;
+				}
+			case TLayout::KMergeModeUnion:
+				{
+				int index = 0;
+				for (; pNew != aTable.end(); ++pNew)
+					{
+					bool found = false;
+					for (iterator pLine = begin()+index; pLine != end(); ++pLine)
+						{
+						if ((*pLine)->Name() == (*pNew)->Name())
+							{
+							(*pLine)->Merge(aMergeMode, **pNew);
+							found = true;
+							break;
+							}
+						}
+					if (found)
+						{
+						delete *pNew;
+						}
+					else
+						{
+						if ((*pNew)->Name().empty())
+							{
+							throw GeneralErr(Name() + " can't union merge unnamed line");
+							}
+						push_back(*pNew);
+						(*pNew)->iTable = this;
+						if ((*pNew)->iId != size())
+							iNoSubTables = true;
+						(*pNew)->iId = size();
+						}
+					if (index+1 < size())
+						index++;
+					}
+				aTable.clear();
+				}
+			}
+		}
+	}
+
+string TLayoutTable::Name()
+	{
+	return iName;
+	}
+
+TLayoutLine* TLayoutTable::FindLine(const string& aName)
+	{
+	for (iterator it = begin(); it != end(); ++it)
+		if ((*it)->Name() == aName)
+			return *it;
+	return 0;
+	}
+
+void TLayoutTable::Compile()
+	{
+	if (iType == EUnknownTable && iColumnNames.size() && iColumnNames[0].size())
+		{
+		if (iColumnNames[0] == "Item")
+			iType = EWindowTable;
+		else
+			iType = ETextTable;
+		}
+
+	SetDefaultColumnNames();
+
+	iParent = iTables->FindLine(iParentName);
+
+	iNeedsIndex = false;
+	iNeedsP = false;
+	for (iterator it = begin(); it != end(); ++it)
+		{
+		(*it)->Compile();
+		if ((*it)->iNeedsIndex)
+			iNeedsIndex = true;
+		if ((*it)->iNeedsP)
+			iNeedsP = true;
+		}
+
+	BuildSubTables();
+	}
+
+void TLayoutTable::BuildSubTables()
+	{
+	DestroySubTables();
+
+	if (iNoSubTables)
+		return;
+
+	int count = size();
+	TLayoutSubTable* subTable = 0;
+	for (int i=0; i<count; i++)
+		{
+		TLayoutLine& line = *(*this)[i];
+		if (subTable)
+			{
+			TLayoutLine* firstLine = (*this)[(*subTable)[0]];
+			if (!firstLine->MatchParams(line))
+				{
+				if (subTable->size() > 1)
+					iSubTables.push_back(subTable);
+				else
+					delete subTable;
+				subTable = new TLayoutSubTable;
+				}
+			}
+		else
+			{
+			subTable = new TLayoutSubTable;
+			}
+		subTable->iIsMergedIdentical = subTable->iIsMergedIdentical && line.iIsMergedIdentical;
+		subTable->push_back(i);
+		}
+
+	if (subTable->size() > 1)
+		iSubTables.push_back(subTable);
+	else
+		delete subTable;
+
+/*
+	for (int i=0; i<count; i++)
+		{
+		bool inserted = false;
+		TLayoutLine& nextLine = *(*this)[i];
+		for (TLayoutSubTables::iterator it = iSubTables.begin(); it != iSubTables.end(); ++it)
+			{
+			TLayoutLine* line = (*this)[*((*it)->begin())];
+			if (line->MatchParams(*(*this)[i]))
+				{
+				TLayoutSubTable& subTab = **it;
+				subTab.push_back(i);
+				subTab.iIsMergedIdentical = subTab.iIsMergedIdentical && nextLine.iIsMergedIdentical;
+				inserted = true;
+				}
+			}
+
+		if (!inserted)
+			{
+			TLayoutSubTable* subTable = new TLayoutSubTable;
+			subTable->push_back(i);
+			subTable->iIsMergedIdentical = nextLine.iIsMergedIdentical;
+			iSubTables.push_back(subTable);
+			}
+		}
+
+	TLayoutSubTables::iterator it = iSubTables.begin();
+	while (it != iSubTables.end())
+		{
+		if ((*it)->size() == 1)
+			it = iSubTables.erase(it);
+		else
+			++it;
+		}
+*/
+	}
+
+void TLayoutTable::DestroySubTables()
+	{
+	for (TLayoutSubTables::iterator it = iSubTables.begin(); it != iSubTables.end(); ++it)
+		delete *it;
+	iSubTables.clear();
+	}
+
+const string KValueNames[] = { "Font", "C", "l", "r", "B", "W", "J", "t", "r", "b", "H" };
+const set<string> KValueNamesSet(KValueNames, ARRAY_END(KValueNames));
+
+bool TLayoutTable::IsValueColumn(string aName)
+	{
+	return KValueNamesSet.find(aName) != KValueNamesSet.end();
+	}
+
+const string KNumericNames[] = { "C", "l", "r", "B", "W", "t", "r", "b", "H" };
+const set<string> KNumericNamesSet(KNumericNames, ARRAY_END(KNumericNames));
+
+bool TLayoutTable::IsNumericColumn(string aName)
+	{
+	return KNumericNamesSet.find(aName) != KNumericNamesSet.end();
+	}
+
+const string KWindowColumnNames[] = {"Item", "C", "l", "t", "r", "b", "W", "H", "Remarks"};
+const string KTextColumnNames[] = {"Font", "C", "l", "r", "B", "W", "J", "Remarks"};
+
+void TLayoutTable::SetDefaultColumnNames()
+	{
+	iColumnNames.clear();
+	if (iType == EWindowTable)
+		{
+		iColumnNames.insert(iColumnNames.end(), KWindowColumnNames, ARRAY_END(KWindowColumnNames));
+		}
+	else
+		{
+		iColumnNames.insert(iColumnNames.end(), KTextColumnNames, ARRAY_END(KTextColumnNames));
+		}
+	}
+
+bool TLayoutTable::IsWorthATableIndex()
+	{
+	return iSubTables.size() != 0;
+	}
+
+
+TLayoutTable::TLayoutSubTable::TLayoutSubTable()
+: iIsMergedIdentical(true)
+	{
+	}
+
+//
+// TLayout
+//
+
+TLayout::TLayout()
+: iCanBeMirror(false)
+	{
+	}
+
+TLayout::TLayout(const TLayout& aOther)
+	{
+	*this = aOther;
+	}
+
+TLayout& TLayout::operator=(const TLayout& aOther)
+	{
+	if (this != &aOther)
+		{
+		iName = aOther.iName;
+		iCanBeMirror = aOther.iCanBeMirror;
+		for (const_iterator it = aOther.begin(); it != aOther.end(); ++it)
+			push_back(new TLayoutTable(this, **it));
+		Compile();
+		}
+	return *this;
+	}
+
+TLayout::~TLayout()
+	{
+	for (iterator it = begin(); it != end(); ++it)
+		delete *it;
+	}
+
+void TLayout::Merge(TLayout::TMergeMode aMergeMode, TLayout& aLayout)
+	{
+	if (iName.empty())
+		iName = aLayout.iName;
+
+	for (iterator pNew = aLayout.begin(); pNew != aLayout.end();)
+		{
+		iterator pTab;
+		for (pTab = begin(); pTab != end(); ++pTab)
+			{
+			if ((*pTab)->Name() == (*pNew)->Name())
+				break;
+			}
+
+		if (pTab == end())
+			{
+			push_back(*pNew);
+			(*pNew)->iTables = this;
+			pNew = aLayout.erase(pNew);
+			}
+		else
+			{
+			(*pTab)->Merge(aMergeMode, **pNew);
+			++pNew;
+			}
+		}
+
+	Compile();
+	}
+
+TLayoutLine* TLayout::FindLine(const string& aName)
+	{
+	for (iterator it = begin(); it != end(); ++it)
+		{
+		TLayoutLine* line = (*it)->FindLine(aName);
+		if (line)
+			return line;
+		}
+
+	return 0;
+	}
+
+void TLayout::Compile()
+	{
+	iterator pTab;
+	for (pTab = begin(); pTab != end(); ++pTab)
+		(*pTab)->Compile();
+
+	// set uniqueness for lines
+	multiset<string> names;
+	for (pTab = begin(); pTab != end(); ++pTab)
+		{
+		TLayoutTable& tab = **pTab;
+		for (TLayoutTable::iterator pLine = tab.begin(); pLine != tab.end(); ++pLine)
+			names.insert((*pLine)->Name());
+		}
+
+	for (pTab = begin(); pTab != end(); ++pTab)
+		{
+		TLayoutTable& tab = **pTab;
+		for (TLayoutTable::iterator pLine = tab.begin(); pLine != tab.end(); ++pLine)
+			{
+			TLayoutLine& line = **pLine;
+			const string& name = line.Name();
+			if (name[0] == 'q')
+				{
+				line.iIsUnique = false;
+				}
+			else 
+				{
+				line.iIsUnique = (names.count(name) == 1);
+				}
+			}
+		}
+
+	}
+
+
+// End of File