aknlayoutcompiler/src/Layout.cpp
changeset 0 f58d6ec98e88
child 1 b700e12870ca
equal deleted inserted replaced
-1:000000000000 0:f58d6ec98e88
       
     1 /*
       
     2 * Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *    
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 #include "Layout.h"
       
    21 #include "LayoutCompilerErr.h"
       
    22 #include "CodeGenConsts.h"
       
    23 #include "UsefulDefinitions.h"
       
    24 
       
    25 #include <set>
       
    26 #include <sstream>
       
    27 #include <iostream>
       
    28 
       
    29 // TValues
       
    30 
       
    31 TValues::TValues()
       
    32 : iLine(0), iName("Bad Value")
       
    33 	{
       
    34 	}
       
    35 
       
    36 TValues::TValues(TLayoutLine* aLine, string aName)
       
    37 : iLine(aLine), iName(aName), iNeedsIndex(0)
       
    38 	{
       
    39 	}
       
    40 
       
    41 bool TValues::operator==(const TValues& aOther) const
       
    42 	{
       
    43 	typedef const vector<string> TBase;
       
    44 	bool eq =
       
    45 		iName == aOther.iName &&
       
    46 		iParam == aOther.iParam &&
       
    47 		iNeedsP == aOther.iNeedsP &&
       
    48 		iNeedsIndex == aOther.iNeedsIndex &&
       
    49 		(*static_cast<TBase*>(this) == aOther);
       
    50 	return eq;
       
    51 	}
       
    52 
       
    53 void TValues::Merge(TValues& aValues)
       
    54 	{
       
    55 	clear();
       
    56 	insert(begin(), aValues.begin(), aValues.end());
       
    57 	}
       
    58 
       
    59 void TValues::Compile()
       
    60 	{
       
    61 	iNeedsP = false;
       
    62 	if (!TLayoutTable::IsValueColumn(iName))
       
    63 		return;
       
    64 
       
    65 	for (iterator it = begin(); it != end(); ++it)
       
    66 		{
       
    67 		bool back2IsAlphaNum = false;
       
    68 		bool back1IsAlphaNum = false;
       
    69 		bool back1IsP = false;
       
    70 		for (string::iterator pC = it->begin(); pC!=it->end(); ++pC)
       
    71 			{
       
    72 			bool IsAlphaNum = (
       
    73 				('A' <= *pC && *pC <= 'Z') || 
       
    74 				('a' <= *pC && *pC <= 'z') ||
       
    75 				('0' <= *pC && *pC <= '9') ||
       
    76 				*pC == '_');
       
    77 
       
    78 			if (!back2IsAlphaNum && back1IsP && !IsAlphaNum)
       
    79 				iNeedsP = true;
       
    80 
       
    81 			back1IsP = *pC == 'p';
       
    82 			back2IsAlphaNum = back1IsAlphaNum;
       
    83 			back1IsAlphaNum = IsAlphaNum;
       
    84 			}
       
    85 
       
    86 		if (!back2IsAlphaNum && back1IsP)
       
    87 			iNeedsP = true;
       
    88 		}
       
    89 	iNeedsIndex = (size() > 1);
       
    90 	}
       
    91 
       
    92 string TValues::ParamName() const
       
    93 	{
       
    94 	if (iParam.length())
       
    95 		return iParam;
       
    96 	else
       
    97 		return KParamNameBase + iName;
       
    98 	}
       
    99 
       
   100 string TValues::CppValue(const string& aValue)
       
   101 	{
       
   102 	if (aValue.size())
       
   103 		return aValue;
       
   104 	else
       
   105 		return "ELayoutEmpty";
       
   106 	}
       
   107 
       
   108 
       
   109 //  TLayoutLine
       
   110 
       
   111 TLayoutLine::TLayoutLine( TLayoutTable* aTable, int aId )
       
   112 :	iTable(aTable), 
       
   113 	iId(aId), 
       
   114 	iIsUnique(true), 
       
   115 	iIsMirroredHorizontally(false),
       
   116 	iIsMergedIdentical(false)
       
   117 	{}
       
   118 
       
   119 TLayoutLine::TLayoutLine(TLayoutTable* aTable, const TLayoutLine& aOther)
       
   120 	{
       
   121 	*this = aOther;
       
   122 	iTable = aTable;
       
   123 	for (iterator pVal = begin(); pVal != end(); ++pVal)
       
   124 		{
       
   125 		TValues& val = pVal->second;
       
   126 		val.iLine = this;
       
   127 		}
       
   128 	}
       
   129 
       
   130 #ifdef RD_SHOW_ALL_AKNLAYOUTCOMPILER_WARNINGS
       
   131 void TLayoutLine::WarnMergeMismatch(TLayoutLine& aLine)
       
   132 #else
       
   133 void TLayoutLine::WarnMergeMismatch(TLayoutLine& /* aLine */)
       
   134 #endif
       
   135 	{
       
   136     // Merge mismatch warnings are not shown from old lay files.
       
   137 #ifdef RD_SHOW_ALL_AKNLAYOUTCOMPILER_WARNINGS
       
   138 	string name = Name();
       
   139 	if (name.empty())
       
   140 		name = TableName();
       
   141 	else
       
   142 		name = iTable->iName + " | " + name;
       
   143 	cerr << "WARNING merge mismatch: " << iTable->iTables->iName << " | " << name;
       
   144 	cerr << " vs " << aLine.iTable->iTables->iName << endl;
       
   145 #endif
       
   146 	}
       
   147 
       
   148 void TLayoutLine::Merge(TLayout::TMergeMode aMergeMode, TLayoutLine& aLine)
       
   149 	{
       
   150 	iIsMergedIdentical = (*this == aLine) && (aMergeMode == TLayout::KMergeModeVariant);
       
   151 	if (iIsMergedIdentical)
       
   152 		return;
       
   153 
       
   154 	bool similar = (Name() == aLine.Name());
       
   155 	iterator pVal;
       
   156 
       
   157 	if (similar && aMergeMode == TLayout::KMergeModeVariant && aLine.iTable->iTables->iCanBeMirror)
       
   158 		{
       
   159 		// need to check to see if the parametrisations are mirrored
       
   160 		// first check for P
       
   161 		bool lr_p = (find("l")->second.iNeedsP && aLine["r"].iNeedsP);
       
   162 		bool rl_p = (find("r")->second.iNeedsP && aLine["l"].iNeedsP);
       
   163 		
       
   164 		// check if they both params are valid
       
   165 		bool lr_both = (find("l")->second.iNeedsIndex && aLine["r"].iNeedsIndex);
       
   166 		bool rl_both = (find("r")->second.iNeedsIndex && aLine["l"].iNeedsIndex);
       
   167 
       
   168 		// check if params are the same
       
   169 		bool lr_same = (find("l")->second.iParam == aLine["r"].iParam);
       
   170 		bool rl_same = (find("r")->second.iParam == aLine["l"].iParam);
       
   171 
       
   172 		// only mirrored if both are valid and same
       
   173 		bool lr = lr_p || (lr_both && lr_same);
       
   174 		bool rl = rl_p || (rl_both && rl_same);
       
   175 
       
   176 		// if either or both are parametrised the same way, need to swap; doesn't matter if 
       
   177 		// both attribs have same param, as swapping it won't make any difference.
       
   178 		if(rl || lr)
       
   179 			{
       
   180 			iIsMirroredHorizontally = true;
       
   181 			}
       
   182 		}
       
   183 
       
   184 	if (similar)
       
   185 		{
       
   186 		for (pVal=begin(); pVal!=end(); ++pVal)
       
   187 			{
       
   188 			TValues& val = pVal->second;
       
   189 			string cell = pVal->first;
       
   190 			if (iIsMirroredHorizontally)
       
   191 				{
       
   192 				if (cell == "l")
       
   193 					cell = "r";
       
   194 				else if (cell == "r")
       
   195 					cell = "l";
       
   196 				}
       
   197 
       
   198 			TValues& other = aLine[cell];
       
   199 			if (val.size() != other.size() || 
       
   200 				val.iNeedsIndex != other.iNeedsIndex || 
       
   201 				val.iNeedsP != other.iNeedsP)
       
   202 				{
       
   203 				similar = false;
       
   204 				}
       
   205 			}
       
   206 		}
       
   207 
       
   208 	if (!similar)
       
   209 		WarnMergeMismatch(aLine);
       
   210 
       
   211 	switch(aMergeMode)
       
   212 		{
       
   213 	case TLayout::KMergeModeMerge:
       
   214 	case TLayout::KMergeModeUnion:
       
   215 		if (similar)
       
   216 			{
       
   217 			for (pVal=begin(); pVal!=end(); ++pVal)
       
   218 				pVal->second.Merge(aLine[pVal->first]);
       
   219 			}
       
   220 		else
       
   221 			{
       
   222 			clear();
       
   223 			copy(aLine.begin(), aLine.end(), inserter(*this, begin()));
       
   224 			for (pVal=begin(); pVal!=end(); ++pVal)
       
   225 				pVal->second.iLine = this;
       
   226 			}
       
   227 		break;
       
   228 	case TLayout::KMergeModeVariant:
       
   229 		clear();
       
   230 		copy(aLine.begin(), aLine.end(), inserter(*this, begin()));
       
   231 		for (pVal=begin(); pVal!=end(); ++pVal)
       
   232 			pVal->second.iLine = this;
       
   233 		break;
       
   234 		}
       
   235 	}
       
   236 
       
   237 bool TLayoutLine::operator==(const TLayoutLine& aOther) const
       
   238 	{
       
   239 	return (Name() == aOther.Name()) && ValuesEqual(aOther);
       
   240 	}
       
   241 
       
   242 bool TLayoutLine::ValuesEqual(const TLayoutLine& aOther) const
       
   243 	{
       
   244 	bool eq = true;
       
   245 	const_iterator pVal, pOther;
       
   246 	for (pVal = begin(), pOther = aOther.begin(); 
       
   247 		 eq && pVal != end() && pOther != aOther.end(); 
       
   248 		 ++pVal, ++pOther)
       
   249 		{
       
   250 		eq = (*pVal == *pOther);
       
   251 		}
       
   252 	eq = eq && pVal == end() && pOther == aOther.end();
       
   253 	return eq;
       
   254 	}
       
   255 
       
   256 string TLayoutLine::Name() const
       
   257 	{
       
   258 	if (find("Item") != end())
       
   259 		return find("Item")->second[0];
       
   260 	else
       
   261 		return "";
       
   262 	}
       
   263 
       
   264 string TLayoutLine::TableName() const
       
   265 	{
       
   266 	stringstream name;
       
   267 	name << iTable->Name() << "_Line_" << iId;
       
   268 	return name.str();
       
   269 	}
       
   270 
       
   271 void TLayoutLine::Compile()
       
   272 	{
       
   273 	iNeedsP = false;
       
   274 	iNeedsIndex = false;
       
   275 
       
   276 	for (iterator pVal = begin(); pVal != end(); ++pVal)
       
   277 		{
       
   278 		TValues& val = pVal->second;
       
   279 		val.Compile();
       
   280 
       
   281 		if (val.iNeedsP)
       
   282 			iNeedsP = true;
       
   283 		if (val.iNeedsIndex)
       
   284 			iNeedsIndex = true;
       
   285 		}
       
   286 	}
       
   287 
       
   288 bool TLayoutLine::MatchParams(const TLayoutLine& aLine) const
       
   289 	{
       
   290 	if (iNeedsP != aLine.iNeedsP)
       
   291 		return false;
       
   292 
       
   293 	for (const_iterator pVal = begin(), pOther = aLine.begin(); pVal != end(); ++pVal, ++pOther)
       
   294 		{
       
   295 		const TValues& val = pVal->second;
       
   296 		const TValues& other = pOther->second;
       
   297 		if (val.iNeedsIndex != other.iNeedsIndex || val.ParamName() != other.ParamName())
       
   298 			return false;
       
   299 		}
       
   300 
       
   301 	return true;
       
   302 	}
       
   303 
       
   304 
       
   305 //
       
   306 // TLayoutTable
       
   307 //
       
   308 
       
   309 
       
   310 
       
   311 TLayoutTable::TLayoutTable(TLayout* aTables)
       
   312 : iTables(aTables), iType(EUnknownTable), iParent(0), iFirstLineGlobalIndex(-1), iAppend(false), iNoSubTables(false)
       
   313 	{
       
   314 	}
       
   315 
       
   316 TLayoutTable::TLayoutTable(TLayout* aTables, const TLayoutTable& aOther)
       
   317 : iTables(aTables), iType(aOther.iType), iParent(0), 
       
   318   iFirstLineGlobalIndex(aOther.iFirstLineGlobalIndex), 
       
   319   iAppend(aOther.iAppend), iColumnNames(aOther.iColumnNames), iName(aOther.iName),
       
   320   iParentName(aOther.iParentName), iNoSubTables(aOther.iNoSubTables)
       
   321 	{
       
   322 	for (const_iterator it = aOther.begin(); it != aOther.end(); ++it)
       
   323 		push_back(new TLayoutLine(this, **it));
       
   324 	}
       
   325 
       
   326 TLayoutTable::~TLayoutTable()
       
   327 	{
       
   328 	for (iterator it = begin(); it != end(); ++it)
       
   329 		delete *it;
       
   330 	DestroySubTables();
       
   331 	}
       
   332 
       
   333 void TLayoutTable::Merge(TLayout::TMergeMode aMergeMode, TLayoutTable& aTable)
       
   334 	{
       
   335 	if (aTable.iAppend)
       
   336 		{
       
   337 		insert(end(), aTable.begin(), aTable.end());
       
   338 		aTable.clear();
       
   339 		for (iterator pLine = begin(); pLine != end(); ++pLine)
       
   340 			(*pLine)->iTable = this;
       
   341 		}
       
   342 	else
       
   343 		{
       
   344 		// merge lines
       
   345 		iterator pNew = aTable.begin();
       
   346 		switch(aMergeMode)
       
   347 			{
       
   348 			case TLayout::KMergeModeMerge:
       
   349 				{
       
   350 				if (size() == aTable.size())
       
   351 					{
       
   352 					for (iterator pLine = begin(); pLine != end(); ++pLine)
       
   353 						{
       
   354 						(*pLine)->Merge(aMergeMode, **pNew);
       
   355 						pNew++;
       
   356 						}
       
   357 					}
       
   358 				else
       
   359 					{
       
   360 					// move the other tables contents to here
       
   361 					iterator pLine;
       
   362 					for (pLine = begin(); pLine != end(); ++pLine)
       
   363 						delete *pLine;
       
   364 					clear();
       
   365 					insert(begin(), aTable.begin(), aTable.end());
       
   366 					aTable.clear();
       
   367 					for (pLine = begin(); pLine != end(); ++pLine)
       
   368 						(*pLine)->iTable = this;
       
   369 					}
       
   370 					break;
       
   371 				}
       
   372 			case TLayout::KMergeModeVariant:
       
   373 				{
       
   374 				iterator pLine;
       
   375 				// need to merge the matching lines but append the extra ones [LMB 11-10-2002]
       
   376 				for (pLine = begin(); pLine != end() && pNew != aTable.end(); ++pLine)
       
   377 					{
       
   378 					(*pLine)->Merge(aMergeMode, **pNew);
       
   379 					pNew++;
       
   380 					}
       
   381 				insert(end(), pNew, aTable.end());
       
   382 				aTable.clear();
       
   383 				for (pLine = begin(); pLine != end(); ++pLine)
       
   384 					(*pLine)->iTable = this;
       
   385 				break;
       
   386 				}
       
   387 			case TLayout::KMergeModeUnion:
       
   388 				{
       
   389 				int index = 0;
       
   390 				for (; pNew != aTable.end(); ++pNew)
       
   391 					{
       
   392 					bool found = false;
       
   393 					for (iterator pLine = begin()+index; pLine != end(); ++pLine)
       
   394 						{
       
   395 						if ((*pLine)->Name() == (*pNew)->Name())
       
   396 							{
       
   397 							(*pLine)->Merge(aMergeMode, **pNew);
       
   398 							found = true;
       
   399 							break;
       
   400 							}
       
   401 						}
       
   402 					if (found)
       
   403 						{
       
   404 						delete *pNew;
       
   405 						}
       
   406 					else
       
   407 						{
       
   408 						if ((*pNew)->Name().empty())
       
   409 							{
       
   410 							throw GeneralErr(Name() + " can't union merge unnamed line");
       
   411 							}
       
   412 						push_back(*pNew);
       
   413 						(*pNew)->iTable = this;
       
   414 						if ((*pNew)->iId != size())
       
   415 							iNoSubTables = true;
       
   416 						(*pNew)->iId = size();
       
   417 						}
       
   418 					if (index+1 < size())
       
   419 						index++;
       
   420 					}
       
   421 				aTable.clear();
       
   422 				}
       
   423 			}
       
   424 		}
       
   425 	}
       
   426 
       
   427 string TLayoutTable::Name()
       
   428 	{
       
   429 	return iName;
       
   430 	}
       
   431 
       
   432 TLayoutLine* TLayoutTable::FindLine(const string& aName)
       
   433 	{
       
   434 	for (iterator it = begin(); it != end(); ++it)
       
   435 		if ((*it)->Name() == aName)
       
   436 			return *it;
       
   437 	return 0;
       
   438 	}
       
   439 
       
   440 void TLayoutTable::Compile()
       
   441 	{
       
   442 	if (iType == EUnknownTable && iColumnNames.size() && iColumnNames[0].size())
       
   443 		{
       
   444 		if (iColumnNames[0] == "Item")
       
   445 			iType = EWindowTable;
       
   446 		else
       
   447 			iType = ETextTable;
       
   448 		}
       
   449 
       
   450 	SetDefaultColumnNames();
       
   451 
       
   452 	iParent = iTables->FindLine(iParentName);
       
   453 
       
   454 	iNeedsIndex = false;
       
   455 	iNeedsP = false;
       
   456 	for (iterator it = begin(); it != end(); ++it)
       
   457 		{
       
   458 		(*it)->Compile();
       
   459 		if ((*it)->iNeedsIndex)
       
   460 			iNeedsIndex = true;
       
   461 		if ((*it)->iNeedsP)
       
   462 			iNeedsP = true;
       
   463 		}
       
   464 
       
   465 	BuildSubTables();
       
   466 	}
       
   467 
       
   468 void TLayoutTable::BuildSubTables()
       
   469 	{
       
   470 	DestroySubTables();
       
   471 
       
   472 	if (iNoSubTables)
       
   473 		return;
       
   474 
       
   475 	int count = size();
       
   476 	TLayoutSubTable* subTable = 0;
       
   477 	for (int i=0; i<count; i++)
       
   478 		{
       
   479 		TLayoutLine& line = *(*this)[i];
       
   480 		if (subTable)
       
   481 			{
       
   482 			TLayoutLine* firstLine = (*this)[(*subTable)[0]];
       
   483 			if (!firstLine->MatchParams(line))
       
   484 				{
       
   485 				if (subTable->size() > 1)
       
   486 					iSubTables.push_back(subTable);
       
   487 				else
       
   488 					delete subTable;
       
   489 				subTable = new TLayoutSubTable;
       
   490 				}
       
   491 			}
       
   492 		else
       
   493 			{
       
   494 			subTable = new TLayoutSubTable;
       
   495 			}
       
   496 		subTable->iIsMergedIdentical = subTable->iIsMergedIdentical && line.iIsMergedIdentical;
       
   497 		subTable->push_back(i);
       
   498 		}
       
   499 
       
   500 	if (subTable->size() > 1)
       
   501 		iSubTables.push_back(subTable);
       
   502 	else
       
   503 		delete subTable;
       
   504 
       
   505 /*
       
   506 	for (int i=0; i<count; i++)
       
   507 		{
       
   508 		bool inserted = false;
       
   509 		TLayoutLine& nextLine = *(*this)[i];
       
   510 		for (TLayoutSubTables::iterator it = iSubTables.begin(); it != iSubTables.end(); ++it)
       
   511 			{
       
   512 			TLayoutLine* line = (*this)[*((*it)->begin())];
       
   513 			if (line->MatchParams(*(*this)[i]))
       
   514 				{
       
   515 				TLayoutSubTable& subTab = **it;
       
   516 				subTab.push_back(i);
       
   517 				subTab.iIsMergedIdentical = subTab.iIsMergedIdentical && nextLine.iIsMergedIdentical;
       
   518 				inserted = true;
       
   519 				}
       
   520 			}
       
   521 
       
   522 		if (!inserted)
       
   523 			{
       
   524 			TLayoutSubTable* subTable = new TLayoutSubTable;
       
   525 			subTable->push_back(i);
       
   526 			subTable->iIsMergedIdentical = nextLine.iIsMergedIdentical;
       
   527 			iSubTables.push_back(subTable);
       
   528 			}
       
   529 		}
       
   530 
       
   531 	TLayoutSubTables::iterator it = iSubTables.begin();
       
   532 	while (it != iSubTables.end())
       
   533 		{
       
   534 		if ((*it)->size() == 1)
       
   535 			it = iSubTables.erase(it);
       
   536 		else
       
   537 			++it;
       
   538 		}
       
   539 */
       
   540 	}
       
   541 
       
   542 void TLayoutTable::DestroySubTables()
       
   543 	{
       
   544 	for (TLayoutSubTables::iterator it = iSubTables.begin(); it != iSubTables.end(); ++it)
       
   545 		delete *it;
       
   546 	iSubTables.clear();
       
   547 	}
       
   548 
       
   549 const string KValueNames[] = { "Font", "C", "l", "r", "B", "W", "J", "t", "r", "b", "H" };
       
   550 const set<string> KValueNamesSet(KValueNames, ARRAY_END(KValueNames));
       
   551 
       
   552 bool TLayoutTable::IsValueColumn(string aName)
       
   553 	{
       
   554 	return KValueNamesSet.find(aName) != KValueNamesSet.end();
       
   555 	}
       
   556 
       
   557 const string KNumericNames[] = { "C", "l", "r", "B", "W", "t", "r", "b", "H" };
       
   558 const set<string> KNumericNamesSet(KNumericNames, ARRAY_END(KNumericNames));
       
   559 
       
   560 bool TLayoutTable::IsNumericColumn(string aName)
       
   561 	{
       
   562 	return KNumericNamesSet.find(aName) != KNumericNamesSet.end();
       
   563 	}
       
   564 
       
   565 const string KWindowColumnNames[] = {"Item", "C", "l", "t", "r", "b", "W", "H", "Remarks"};
       
   566 const string KTextColumnNames[] = {"Font", "C", "l", "r", "B", "W", "J", "Remarks"};
       
   567 
       
   568 void TLayoutTable::SetDefaultColumnNames()
       
   569 	{
       
   570 	iColumnNames.clear();
       
   571 	if (iType == EWindowTable)
       
   572 		{
       
   573 		iColumnNames.insert(iColumnNames.end(), KWindowColumnNames, ARRAY_END(KWindowColumnNames));
       
   574 		}
       
   575 	else
       
   576 		{
       
   577 		iColumnNames.insert(iColumnNames.end(), KTextColumnNames, ARRAY_END(KTextColumnNames));
       
   578 		}
       
   579 	}
       
   580 
       
   581 bool TLayoutTable::IsWorthATableIndex()
       
   582 	{
       
   583 	return iSubTables.size() != 0;
       
   584 	}
       
   585 
       
   586 
       
   587 TLayoutTable::TLayoutSubTable::TLayoutSubTable()
       
   588 : iIsMergedIdentical(true)
       
   589 	{
       
   590 	}
       
   591 
       
   592 //
       
   593 // TLayout
       
   594 //
       
   595 
       
   596 TLayout::TLayout()
       
   597 : iCanBeMirror(false)
       
   598 	{
       
   599 	}
       
   600 
       
   601 TLayout::TLayout(const TLayout& aOther)
       
   602 	{
       
   603 	*this = aOther;
       
   604 	}
       
   605 
       
   606 TLayout& TLayout::operator=(const TLayout& aOther)
       
   607 	{
       
   608 	if (this != &aOther)
       
   609 		{
       
   610 		iName = aOther.iName;
       
   611 		iCanBeMirror = aOther.iCanBeMirror;
       
   612 		for (const_iterator it = aOther.begin(); it != aOther.end(); ++it)
       
   613 			push_back(new TLayoutTable(this, **it));
       
   614 		Compile();
       
   615 		}
       
   616 	return *this;
       
   617 	}
       
   618 
       
   619 TLayout::~TLayout()
       
   620 	{
       
   621 	for (iterator it = begin(); it != end(); ++it)
       
   622 		delete *it;
       
   623 	}
       
   624 
       
   625 void TLayout::Merge(TLayout::TMergeMode aMergeMode, TLayout& aLayout)
       
   626 	{
       
   627 	if (iName.empty())
       
   628 		iName = aLayout.iName;
       
   629 
       
   630 	for (iterator pNew = aLayout.begin(); pNew != aLayout.end();)
       
   631 		{
       
   632 		iterator pTab;
       
   633 		for (pTab = begin(); pTab != end(); ++pTab)
       
   634 			{
       
   635 			if ((*pTab)->Name() == (*pNew)->Name())
       
   636 				break;
       
   637 			}
       
   638 
       
   639 		if (pTab == end())
       
   640 			{
       
   641 			push_back(*pNew);
       
   642 			(*pNew)->iTables = this;
       
   643 			pNew = aLayout.erase(pNew);
       
   644 			}
       
   645 		else
       
   646 			{
       
   647 			(*pTab)->Merge(aMergeMode, **pNew);
       
   648 			++pNew;
       
   649 			}
       
   650 		}
       
   651 
       
   652 	Compile();
       
   653 	}
       
   654 
       
   655 TLayoutLine* TLayout::FindLine(const string& aName)
       
   656 	{
       
   657 	for (iterator it = begin(); it != end(); ++it)
       
   658 		{
       
   659 		TLayoutLine* line = (*it)->FindLine(aName);
       
   660 		if (line)
       
   661 			return line;
       
   662 		}
       
   663 
       
   664 	return 0;
       
   665 	}
       
   666 
       
   667 void TLayout::Compile()
       
   668 	{
       
   669 	iterator pTab;
       
   670 	for (pTab = begin(); pTab != end(); ++pTab)
       
   671 		(*pTab)->Compile();
       
   672 
       
   673 	// set uniqueness for lines
       
   674 	multiset<string> names;
       
   675 	for (pTab = begin(); pTab != end(); ++pTab)
       
   676 		{
       
   677 		TLayoutTable& tab = **pTab;
       
   678 		for (TLayoutTable::iterator pLine = tab.begin(); pLine != tab.end(); ++pLine)
       
   679 			names.insert((*pLine)->Name());
       
   680 		}
       
   681 
       
   682 	for (pTab = begin(); pTab != end(); ++pTab)
       
   683 		{
       
   684 		TLayoutTable& tab = **pTab;
       
   685 		for (TLayoutTable::iterator pLine = tab.begin(); pLine != tab.end(); ++pLine)
       
   686 			{
       
   687 			TLayoutLine& line = **pLine;
       
   688 			const string& name = line.Name();
       
   689 			if (name[0] == 'q')
       
   690 				{
       
   691 				line.iIsUnique = false;
       
   692 				}
       
   693 			else 
       
   694 				{
       
   695 				line.iIsUnique = (names.count(name) == 1);
       
   696 				}
       
   697 			}
       
   698 		}
       
   699 
       
   700 	}
       
   701 
       
   702 
       
   703 // End of File