/*------------------------------------------------------------------------------*
 * File Name: tree_utils.c	 													*
 * Creation: May 07, 2003														*
 * Purpose: define tree utility functions										*
 * Copyright (c)2005 OriginLab Corp.											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	CPY v7.5785 12/19/03 QA70-5738 GETN_BOX_COMBO_CHANGE_NEEDED					*
 *  Danice 2/25/04 QA70-6032 PRESENTATION_MANAGER_NEED							*
 *  Danice 3/7/04 v8.0832 ADD_LEVEL_CONTROL										*
 *  Danice 3/8/04 v8.0833 ADD_CLEAR_TREE										*
 *  Danice 4/27/04 QA70-6332 v8.0863 ADD_COPY_VALUE_TO_ATTRIBUTE				*
 *	Frank  4/29/04	QA70-6222 v8.0863 ADD_FUNCT_DEAL_IDATTRIB_AND_VALUE			*
 *	CPY 5/24/04 CHANGE_PARAM_NEED_REUSE_TREE									*
 *	EJP 06-07-2004 v8.0853 QA70-6472 FILE_INFO_IN_PAGE							*
 *	Frank 06/16/04	v8.0890	TREE_SET_VALUE_FROM_VECTOR							*
 *  SY 07/07/2004 QA70-6641 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL					*
 *  Forest 09/09/04 QA70-6682 TREE_READ_AND_SAVE_BRANCH_CHECKBOX                *
 *  Forest 09/11/04 QA70-6682 CHECKING_IF_ID_DUPLICATE                          *
 *  Danice 9/13/04 v8.0132 MOVE_UTILITY_FUNCTION_TO_TREE_UTILS					*
 *	Frank 9/15/04 QA70-6903	ADD_OUTPUT_TREE_TO_TABLE_STRING						*	
 *  Danice 9/24/04 QA70-6891 v8.0139 ADD_BRANCH_CONTROL							*
 *	Frank 9/30/04 QA70-6903	MODIF_TREETABLE_TITLE_OUPUT							*	
 *	Frank 10/10/04 QA70-6903	SUPPORT_MULTI_LEVEL_NODE_OUTPUT					*	
 *	Frank 11/10/04 v8.0160 QA70-6086   REMEMBER_LAST_USE_FUNCTION				*
 *  Danicee 11/15/04 QA70-7169 v8.0163 TREE_ROW_SHOW_ALTERNATE_COLORS			*
 *	Frank 11/23/04 v8.0167 			CHECK_TREE_TABLE_TYPE_VISIABLE				*
 *  Danice 12/1/04 QA70-6891 v8.0168 GET_TREENODE_STOP_ATTRIBUTE_OPTION			*
 *  Frank 12/14/04 AUTO_SET_MULTILINE_EDIT_SHOW_RANGE							*
 *  Frank 12/15/04 TREE_GET_NODE_BY_NODEID_OR_DATAID							*
 *  Frank 12/27/04 TREE_TABEL_SHOW_MULTI_LAYER_TABEL							*
 *	Frank 01/18/05 v8.0184b SUPPORT_DISPLAY_FORMATS_NULL_NOT_JUSTIFY			*
 *	Frank 1/21/05 MOVE_GET_LABEL_FUNCTION_FROM_STATIC							*
 *	Frank 1/27/05	TREE_INI_SECTION_NAME_SHOULD_TAGNAME						*
 *	Frank 3/2/05 QA70-7455	COPY_TREE_SUPPORT_DUPLICATE_ID_WITH_REPEAT_ATTRIB	*
 *  Forest 03/02/05 QA70-7456	COPY_TREE_USING_FILTER							*
 *  DG 3/17/05 v8.0206 CLEAN_DOUBLE_STORAGE										*
 *	AW 03/21/05 v8.0208 CLEAN_GET_TREE_NODE										*
 *	EJP 2005-03-31 v8.0214 QA70-6816 SHOW_IMPORT_FILE_INFO_IN_USER_VAR_DLG		*
 *  Forest 4/1/05 TREE_FILTER_BY_ATTRIB_MATCH									*
 * Frank 4/2/05		NEW_METHOD_CHECK_NODE_EMPTY									*
 * Frank 4/15/05 FIX_BRANCH_CHECK_BOX_APPEAR_WHEN_CLICK_ADVANCED				*
 *	ML 4/15/2005 XVAR_DATA_CHANGE_ATT											*
 *  DG 4/20/05 v8.0223 REWRITE_TREE_GET_NODE									*
 *	Frank 6/2/05		SET_ROOT_ATTRIB_OF_FOLDER_LIST							*
 *	Frank 6/21/05 ADD_FOLDERS_AND_PAGES_TO_TREE									*
 *	Frank 6/30/05	ADD_COUNT_TREENODE_BY_ATTRIBUTE								*
 *	Frank 7/25/06 CHECK_REPEATID_OUT_OF_RANGE									*
 *	DSC 8/25/05 TREENODE_FIND_NODE_BY_DATAID									*
 *	DSC 8/30/05 OCTREE_FIND_NODE_BY_ID_AND_REPEAT_ID_RETURN_VALUE				*
 *	Jasmine 09/17/05 v8.0308 SET_AND_GET_THEME_FILE_NAME						*
 *	DSC 9/13/05 MOVE_TREE_COUNT_ITEMS_TO_VC										*
 *	Kevin 10/11/05 CONVERT_TO_OUTPUT_TREE										*
 *	Frank 10/17/06 ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT							*
 *	Kevin 10/28/05 SUPPORT_LINE_UP_IN_ONE_STRING	 							*
 *	Frank 11/09/05 SHOULD_ADD_ONE_IF_ADD_LAST		 							*
 *  Frank 11/11/05 ADD_REPEAT_ID_COMBINE_ERROR_OUT								*
 *  Iris 11/14/05 ADD_AUX_DISPLAY_INFO											*
 *  Frank 11/14/05 NO_OPERATOR_CONTROL_IN_BROWSER								*
 *  Frank 11/18/05 SHOULD_HAVE_DISPLAY_FORMAT_WHEN_CONVERT_TREE_TO_TABLE		*
 *  Frank 11/18/05 ADD_EQUAL_IF_IO_NODE_IN										*
 *  Frank 11/21/05 HIDE_NODE_NAME_OUTPUT_TO_STR									*
 *	Kevin 11/24/05	ADD_TREE_FIND_MAX_DATA_ID_FUNCTION							*
 *	Jasmine 01/13/06 TREE_COUNT_ITEMS_BY_STTRIBUTE_CHECK_VALIDITY				*
 *	ML 1/13/2006 XVARIABLEBASE_TO_VC											*
 *	ML 2/17/2006 INTERACTIVE_CONTROL_MENUS										*
 *	Hong 08/04/06 THEME_TREE_GET_NODE_BY_ID										*
 *	Hong 08/04/06 THEME_TREE_GET_NODE_BY_INDEX									*
 *	CPY 14/04/06 TEMP_VC_HEADER_TO_SPEED_UP_OC_COMPILE							*
 *	Iris 4/27/06 VS_CODES_FAIL_TO_WORK_ROLLBACK_OC_CODES						*
 *  James 06/06/06 v8.0421 ADD_FOLDER_PAGES_ADD_PAGES                           *
 *	Cheney 6-15-06 FIX_BUG_WHEN_NROW_LESS_THAN_NPOSITION						*
 *	EJP 2006-07-07 v8.0440 QA70-8697 XFUNC_BASED_IMPORT							*
 *  James 07/12/06 v8.0441 ADD_FOLDER_PAGES_ADD_PAGES_REMOVE_CODE               *
 *  Joe  7/17/06 HIDE_EMPTY_TABLE                                               *
 *  Hong 7/18/06 FIX_RETURN_ERROR												*
 *  Iris 8/15/06 NOT_SHOW_FOOTNOTE_NAME_PREFIX									*
 *  Joseph 10/11/06 ADD_NODE_AFETER_LAST_NODE									*
 *  Iris 12/15/2006 v8.0526 SEPARATE_REPORT_BROKEN_IN_NLSF						*
 *  Hong 12/25/06 SAVE_TIME_IN_ORGANIZER_USE_LOCAL_TIME							*
 *  Hong 12/30/06 FIX_ERROR_CARE_CASE_SENSITIVE_OR_NOT							*
 *	Jasmine 01/17/07 GET_TREE_NODE_PATH											*
 *	Jasmine 01/17/07 QA70-9273 SHOW_USER_TREE_INFO_IN_USER_VAR_DLG				*
 *	Jasmine 01/17/07 ADD_$_FOR_STRVAL											*
 *	Jasmine 01/18/07 QA70-9273 MODIFICATION_FOR_USER_VAR_DLG					*
 *	Jasmine 01/19/07 QA70-9287 GET_INI_STORAGE_ONLY								*
 *	ML 1/30/2007 QA70-9318 P2 PREPARING_RANGE_XF_ARG_WITH_FACTOR				*
 *	Jasmine 02/06/07 REPLACE_NOT_ONLY_ORIGIN_STORAGE_BUT_ROOT_TAGNAME			*
 *  Arvin 03/09/07 RUNTIME_ERROR_WHEN_TREENODE_NOT_EXIST						*
 *	Jasmine 03/20/07 AVOID_BAD_STRUCTURE_ASCII_STORAGE							*
 *	AW 05/02/07 QA80-9716 v8.0612 FIX_fuSetDouble_DISPLAY_PROBLEM				*
 *	TD 5-4-07 QA80-9724 THEME_TREE_WITH_LABELS_FOR_READABILITY					*
 *	EJP 2007-05-31 v8.0631 LOAD_REG_VALUE_NEED_DEFAULT							*
 *	Echo 6/1/07	SUPPORT_CTRL_SELECT												*
 *	Sim 06-07-2007 SUPPORT_RENAME_TREE_TAGNAME									*
 *	Jake 06/26/07 SUPPORT_COMBO_LIST_FOR_PATH									*
 *	Sim 07-02-2007 FIX_DUPLICATE_RECENT_FILE_LIST								*
 *	Jasmine 07/04/07 DONOT_SET_COMBO_ATTRIB_IF_GET_NO_PATH						*
 *	Jasmine 09/08/07 HARD_CODE_TO_SET_DATE_DISPLAY_								*
 *	Hong 09/08/07 v8.0699 MORE_OPTION_TO_DUMP_MAP_INFO_FOR_COMBO_NODE			*
 *	Hong 10/26/07 QA80-10364 PATH_CTRL_SHOULD_NOT_APEEND_FILENAME				*
 *	Folger 11/17/07 LOCALIZE_IMPORT_FILE_INFO									*
 *	Folger 12/28/07 TREE_TAGNAME_OPERATION_MOVE_TO_VC							*
 *	Arvin 01/07/08 QA70-10903 ADD_CHECK_ALL_BOX_FOR_BRANCH						*
 *	Folger 03/05/08 QA80-11192 CENTRALIZE_THEME_TREE_SETTING_KNOWLEDGE			*
 *	Hong 07/02/08 v8.0895 GET_RID_OF_CHECKING_NODE_VALID_EVERY_CALL				*
 *	Hong 08/29/08 v8.0932 IMPROVE_DEBUG											*
 *	Hong 10/24/08 v8.0960b FIX_NEW_NLFIT_FUNCTION_LIST_LOST_ITEM_NEW_DOT_DOT_DOT*
 *	Kyle 10/31/08 QA80-12452  SUPPORT_INPUT_DATA_FORM_OPTION_FOR_NPH_TESTS		*
 *	Hong 11/14/08 v8.0971b DISABLE_OPTIONS_INSTEAD_OF_HIDDEN_IT_FOR_BASELINE_OUTPUT_OPTIONS
 *	Sim 12-23-2008 QA80-12836 SUPPORT_FILE_BROWSER_BUTTON						*
 *	Folger 03/18/09 QA80-13261-P2 NEW_ADDED_AUTO_FOR_XF_VARIABLE_FAILS_TO_COMPATIBLE_WITH_OLD_THEME
 *	Kyle 03/31/2009 QA80-3224 NEW_OPTION_TO_SUPPORT_LINEAR_FIT_WITH_ERROR_BAR	*
 *	Hong 04/13/09 QA80-13280 RUNTIME_ERROR_WHEN_APPEND_CUSTOMIZED_OPTION_TO_EXPORT_GRAPH
 *	Folger 04/15/09 QA80-13454 SPECIAL_ATTRIBUTES_SHOULD_BE_CORRECTLY_UPDATED_WHEN_USE_OLD_THEME_AND_OP
 *	Kenny 04/30/2009 ADD_OPTION_TO_OUT_TREE_TO_SUPPORT_MORE_OUTPUT_STYLE		*
 *	Kenny 06/10/2009 USE_ASCII_CODES_FOR_OUT_TREE_INSTEAD						*
 *	Sophy 8/7/2009 QA80-14101 SET_GETN_NODES_AS_UNDEFINED_WHEN_SEL_MULTI_COLS_WITH_DIFF_PROPERTY
 *	Kyle 08/13/2009 SET_COLUMN_VALUES_SUPPORT_DEFINE_VARIABLES_IN_BASIC_DATA_TYPE*
 *	Folger 08/19/09 QA80-14168 LABTALK_TREE_NICE_DUMPING						*
 *	Kyle 08/26/2009 QA80-14190 DEFINE_VARIABLE_FROM_COLUMN_LABELS_IN_SCV_DB		*
 *	Kenny 09/03/2009 QA81-14241 DEFINE_VARIABLE_NEED_MORE_IMPROVEMENTS			*
 *	Kenny 09/24/2009 QA81-14241 INSERT_USER_DEF_PARAM_SHOULD_USE_CORRECT_INDEX	*
 *	Sophy 10/9/2009 QA80-14190-P1 COL_LABELS_WITH_ONLY_WHITE_SPACES_MIXED_WITH_NUMERIC_SHOULD_BE_TREATED_AS_TEXT
 *	Kenny 11/26/2009 QA81-14748 INSERT_VAR_DLG_FAILED_TO_SHOW_IMPORT_FILE_LEVEL_INFO*
 *	Kenny 12/22/2009 QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE*
 *	Kyle 02/02/2010 QA80-15056 NEED_INSERT_LABEL_FOR_TEXT_OBJECT				*
 *	Kyle 02/04/2010 READ_SHEET_INPORT_FILE_INFO									*
 *	Hong 05/17/10 ORG-131 MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET			*
 *------------------------------------------------------------------------------*/
 
#include <origin.h> // main Origin C header that is precompiled and already include most headers 

#pragma labtalk(0) //--- CPY 7/26/05 hide all functions in this file from LT access, as XF should be used instead

#include <OC_Res.h>		///Danice MOVE_UTILITY_FUNCTION_TO_TREE_UTILS
////////////////////////////////////////////////////////////////////////////////////
/// Hong 7/13/06	TURN_ON_VC_CODE
///Frank 9/15/04 QA70-6903	ADD_OUTPUT_TREE_TO_TABLE_STRING	
#include <..\Originlab\TreeTable.h>
///End	ADD_OUTPUT_TREE_TO_TABLE_STRING	
/// end TURN_ON_VC_CODE

//#include <OCTreeUtils2.h> //CPY 14/04/06 TEMP_VC_HEADER_TO_SPEED_UP_OC_COMPILE
#include <OCTreeUtils.h>	//Hong 7/26/06 MOVE_TEMP_HEADER

#define PAGE_INFO_EXPORT		"Export"
///	Hong 7/13/06	TURN_ON_VC_CODE
#define _TREE_UTILS_FROM_HONG_DLL
/// end TURN_ON_VC_CODE

///------------- SY 03/25/2004 move to OCTreeUtils.h
///#define CHECK_IF_ID_DUPLICATE	///Forest 09/11/04 QA70-6682 CHECKING_IF_ID_DUPLICATE
///#define MAX_REPEAT_ID_VALUE		1000
///-------------

////////////////////////////////////////////////////////////////////////////////////
// start your functions here

//------ CPY 5/24/04 CHANGE_PARAM_NEED_REUSE_TREE
// call this function to get a node and it will add if not present
/** > Tree
	get a tree node and check if it is already present, if not, create it first
*/
TreeNode tree_check_get_node(TreeNode& tr, LPCSTR lpcszTag, int nID, LPCSTR lpcszAttribName, LPCSTR lpcszAttribVal) // = 0 = NULL = NULL
{
	/// ML 1/13/2006 XVARIABLEBASE_TO_VC
	/*
	TreeNode		trNode = tr.GetNode(lpcszTag);
	if ( !trNode.IsValid() )
		trNode = tr.AddNode(lpcszTag);
	
	if(nID > 0)
		trNode.ID = nID;
	if(lpcszAttribName && lpcszAttribVal)
		trNode.SetAttribute(lpcszAttribName, lpcszAttribVal);
	
	return trNode;
	*/

	TreeNode		trNode;
	octree_tree_check_get_node(&trNode, &tr, lpcszTag, nID, lpcszAttribName, lpcszAttribVal);
	return trNode;
	/// end XVARIABLEBASE_TO_VC
}
//------

///Sophy 10/18/2010 ORG-1277 ADO_DATABASEIMPORT_NEED_GET_NODE_BY_LABEL
TreeNode tree_check_get_node_by_label(TreeNode& tr, LPCSTR lpcszLabel, BOOL bCaseSensitive/* = FALSE*/)
{
	TreeNode	trNode;
	if ( tr )
		octree_tree_check_get_node_by_attribute(&trNode, &tr, STR_LABEL_ATTRIB, lpcszLabel, bCaseSensitive);
	return trNode;
}
///end ADO_DATABASEIMPORT_NEED_GET_NODE_BY_LABEL


TreeNode tree_check_get_node_by_dataid(TreeNode& trParent, LPCSTR lpcszTag, int nDataID, LPCSTR lpcszLableAttrib, LPCSTR lpcszAttribVal )//=NULL,=NULL
{
	string strAttributeName(lpcszLableAttrib);
	string strAttributeVal(lpcszAttribVal);
	
	TreeNode trNew = tree_get_node_by_dataid(trParent, nDataID);
	
	if(!trNew)
	{	
		trNew = trParent.AddNode(lpcszTag);
		if((!strAttributeName.IsEmpty())&&(!strAttributeVal.IsEmpty()))
			trNew.SetAttribute(strAttributeName, strAttributeVal);
		
		if(nDataID>0)
			trNew.DataID = nDataID;	
	}

	return trNew;
}
TreeNode tree_get_ini_section(TreeNode &trIni, LPCSTR lpcszSection)
{
	TreeNode trNull; // return invalid tree node
	////Frank 1/26/05 v8.0185 here if false, should return NULL treeNode, not false.
	if( !trIni || NULL == lpcszSection )
		//return false;
		return trNull;
	TreeNode trIniSection;
	foreach(trIniSection in trIni.Children)
	{
		///Frank 1/27/05	TREE_INI_SECTION_NAME_SHOULD_TAGNAME
		//if( trIniSection.Name.IsValid() && 0 == lstrcmpi(lpcszSection, trIniSection.Name.strVal) )
		if( trIniSection.IsValid() && 0 == lstrcmpi(lpcszSection, trIniSection.tagName) )
		///End	TREE_INI_SECTION_NAME_SHOULD_TAGNAME
			return trIniSection;
	}
	//TreeNode trNull; // return invalid tree node
	return trNull;
}

bool tree_read_ini(TreeNode &trIni, LPCSTR lpcszFile)
{
	if( !trIni || NULL == lpcszFile )
		return false;
	INIFile iniFile(lpcszFile);
	return tree_read_ini(trIni, iniFile);
}

bool tree_read_ini(TreeNode &trIni, INIFile &iniFile)
{
	if( !trIni )
		return false;
	StringArray saIniSections;
	iniFile.GetSectionNames(saIniSections);
	for( int i = 0; i < saIniSections.GetSize(); i++ )
		tree_read_ini_section(trIni, iniFile, saIniSections[i]);
	return true;
}

bool tree_read_ini_section(TreeNode &trIni, LPCSTR lpcszFile, LPCSTR lpcszSection)
{
	if( !trIni || NULL == lpcszFile || NULL == lpcszSection )
		return false;
	INIFile iniFile(lpcszFile);
	return tree_read_ini_section(trIni, iniFile, lpcszSection);
}

bool tree_read_ini_section(TreeNode &trIni, INIFile &iniFile, LPCSTR lpcszSection)
{
	if( !trIni || NULL == lpcszSection )
		return false;
	
	string str = lpcszSection;
	str.MakeValidCName('S');
	
	TreeNode trIniSection = tree_get_ini_section(trIni, str);
	if( trIniSection )
	{
		trIniSection.Reset();
	}
	else // section not found
	{
		trIniSection = trIni.AddNode(str);
	}
	if( !trIniSection )
		return false;

	// If section name is not a valid identifier name
	// then store the original name in the label attribute.
	if( str.Compare(lpcszSection) )
	{
		trIniSection.SetAttribute(STR_LABEL_ATTRIB, lpcszSection);
	}
	
	TreeNode trIniKey;
	StringArray saIniKeyNames;
	iniFile.GetKeyNames(saIniKeyNames, lpcszSection);
	for( int i = 0; i < saIniKeyNames.GetSize(); i++ )
	{
		str = saIniKeyNames[i];
		str.MakeValidCName('K');

		trIniKey = trIniSection.AddNode(str);
		if( trIniKey )
		{
			if( str.Compare(saIniKeyNames[i]) )
				trIniKey.SetAttribute(STR_LABEL_ATTRIB, saIniKeyNames[i]);
			trIniKey.strVal = iniFile.ReadString(lpcszSection, saIniKeyNames[i]);
		}
	}
	return true;
}

/// Iris 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
//bool tree_write_ini(TreeNode &trIni, LPCSTR lpcszFile, bool bClearSections)
bool tree_write_ini(TreeNode &trIni, LPCSTR lpcszFile, bool bClearSections, bool bLabelAsKey)
///end DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
{
	if( !trIni || NULL == lpcszFile )
		return false;
	INIFile iniFile(lpcszFile);
	/// Iris 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
	//return tree_write_ini(trIni, iniFile, bClearSections);
	return tree_write_ini(trIni, iniFile, bClearSections, bLabelAsKey);
}

/// Iris 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
//bool tree_write_ini(TreeNode &trIni, INIFile &iniFile, bool bClearSections)
bool tree_write_ini(TreeNode &trIni, INIFile &iniFile, bool bClearSections, bool bLabelAsKey)
///end DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
{
	if( !trIni )
		return false;
	TreeNode trIniSection;
	foreach(trIniSection in trIni.Children)
	{
		/// Iris 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
		//tree_write_ini_section(trIniSection, iniFile, bClearSections);
		tree_write_ini_section(trIniSection, iniFile, bClearSections, bLabelAsKey);
		///end DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
	}
	return true;
}

/// Iris 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
//bool tree_write_ini_section(TreeNode &trIniSection, INIFile &iniFile, bool bClearSection)
bool tree_write_ini_section(TreeNode &trIniSection, INIFile &iniFile, bool bClearSection, bool bLabelAsKey)
{
	if( !trIniSection )
		return false;
	
	/// Iris 5/29/06 NOT_ACCESS_ORIGINSTORAGE_ROOT
	if( 0 == trIniSection.tagName.CompareNoCase("OriginStorage") ) //if the root node is OriginStorage, the following codes will cuase runtime error
		trIniSection = trIniSection.FirstNode;
	///End NOT_ACCESS_ORIGINSTORAGE_ROOT

	///Joseph/Iris 06/25/2007 v8.0648 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
	//section also should support label as key
	/*
	/// Iris 06/06/06 EXPORT_PAGE_XF   let the format of image ini file is same as 75
	//string strSection;
	//if( !trIniSection.GetAttribute(STR_LABEL_ATTRIB, strSection) || strSection.IsEmpty() )
		//strSection = trIniSection.tagName;
	string 	strSection = trIniSection.tagName;
	///End EXPORT_PAGE_XF
	*/
    string 	strSection;// = trIniSection.tagName;
	if(bLabelAsKey)
	{
		trIniSection.GetAttribute(STR_LABEL_ATTRIB, strSection);
	}
	else
	{
		strSection = trIniSection.tagName;
	}
	///End DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
	
	if( bClearSection )
		iniFile.WriteString(strSection, NULL, NULL); // delete ini file section

	string strKey;
	TreeNode trIniKey;
	foreach(trIniKey in trIniSection.Children)
	{
		/// Hong 04/13/09 QA80-13280 RUNTIME_ERROR_WHEN_APPEND_CUSTOMIZED_OPTION_TO_EXPORT_GRAPH
		if ( trIniKey.FirstNode )
			continue;
		/// end RUNTIME_ERROR_WHEN_APPEND_CUSTOMIZED_OPTION_TO_EXPORT_GRAPH
		///Alex/Iris 11/10/06 FIX_COLOR_TRANSLATION_FOR_PDF
		//some node export to ini has space in Origin75,and tagname can't have space 
		/*
		/// Iris 5/30/06 EXPORT_PAGE_XF 
		//the XF options tree node includes GetN label to show more detail for user, Use tagName only here to keep consist with Origin75
		//if( !trIniKey.GetAttribute(STR_LABEL_ATTRIB, strKey) || strKey.IsEmpty() )
		//	strKey = trIniKey.tagName;
		strKey = trIniKey.tagName;
		///End EXPORT_PAGE_XF
		*/
		// Iris 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
		/*
		int nTemp;
		if( trIniKey.GetAttribute(STR_COMPLEX_ININAME_ATTRIBUTE, nTemp))
			trIniKey.GetAttribute(STR_LABEL_ATTRIB, strKey);
		if(strKey.IsEmpty())
			strKey = trIniKey.tagName;
		*/
		strKey = trIniKey.tagName;
		if(bLabelAsKey)
		{
			trIniKey.GetAttribute(STR_LABEL_ATTRIB, strKey);
		}
		else
		{
			int nTemp = 0;
			if( trIniKey.GetAttribute(STR_COMPLEX_ININAME_ATTRIBUTE, nTemp) && 1 == nTemp)
				trIniKey.GetAttribute(STR_LABEL_ATTRIB, strKey);				
		}
		///end DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
		///End FIX_COLOR_TRANSLATION_FOR_PDF
		
		iniFile.WriteString(strSection, strKey, trIniKey.strVal);
		
		strKey.Empty();	///Alex/Iris 11/10/06 FIX_COLOR_TRANSLATION_FOR_PDF
	}
	return true;
}

/// Iris 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
//bool tree_write_ini_section(TreeNode &trIniSection, LPCSTR lpcszFile, bool bClearSection)
bool tree_write_ini_section(TreeNode &trIniSection, LPCSTR lpcszFile, bool bClearSection, bool bLabelAsKey = true)
///end DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
{
	if( !trIniSection || NULL == lpcszFile )
		return false;
	INIFile iniFile(lpcszFile);
	/// Iris 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
	//return tree_write_ini_section(trIniSection, iniFile, bClearSection);
	return tree_write_ini_section(trIniSection, iniFile, bClearSection, bLabelAsKey);
	//end DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
}

///////////////////////////////////////
///// read/write image export settings
///////////////////////////////////////
void	tree_add_enum_data_ids_by_base_id(TreeNode& tr, int& nIndex, int nBaseID)
{
	foreach(TreeNode trN in tr.Children)
	{		
		nIndex++;
		trN.DataID = nBaseID + nIndex;
		if(trN.GetNodeCount() > 0) // branch node
			tree_add_enum_data_ids_by_base_id(trN, nIndex, nBaseID);
	}
}

bool tree_read_image_export_settings(TreeNode &trSettings, LPCSTR lpcszFormat)
{
	string str(lpcszFormat);;
	LabTalk.Image.Export.GetIni("a", "b", str);
	char szFile[MAX_PATH], szSec[MAX_PATH];
	if( !LT_get_str("%a", szFile, MAX_PATH) || !LT_get_str("%b", szSec, MAX_PATH) )
		return false;
	bool bRet;
	if( szSec[0] ) // if ini section specified
		bRet = tree_read_ini_section(trSettings, szFile, szSec);
	else
		bRet = tree_read_ini(trSettings, szFile);	
			
	return bRet;
}

bool tree_write_image_export_settings(TreeNode &trSettings, LPCSTR lpcszFormat, bool bClearSections)
{
	string str(lpcszFormat);;
	//LabTalk.Image.Export.GetIni("a", "b", lpcszFormat);
	LabTalk.Image.Export.GetIni("a", "b", str);
	char szFile[MAX_PATH], szSec[MAX_PATH];
	if( !LT_get_str("%a", szFile, MAX_PATH) || !LT_get_str("%b", szSec, MAX_PATH) )
		return false;
	bool bRet;
	bool bLabelAsKey = false; /// Iris 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
	if( szSec[0] ) // if ini section specified
	{
		/// Iris 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
		//bRet = tree_write_ini_section(trSettings, szFile, bClearSections);//, szSec);
		bRet = tree_write_ini_section(trSettings, szFile, bClearSections, bLabelAsKey);
		///end DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
	}
	else
	{
		/// Iris 06/25/2007 v8.0648 DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
		//bRet = tree_write_ini(trSettings, szFile, bClearSections);
		bRet = tree_write_ini(trSettings, szFile, bClearSections, bLabelAsKey);
		///end DEFAULT_LOGIC_WRITE_INIT_SHOULD_MAKE_CONSISTENCE_WITH_READ_INIT
	}
	return bRet;
}

bool tree_get_page_image_export_settings(TreeNode &trSettings, Page &pg, LPCSTR lpcszFormat)
{
	/* This old code used page's ini storage
	pg.Info.Add(PAGE_INFO_EXPORT);
	storage st;
	st = pg.GetStorage(PAGE_INFO_EXPORT);
	if( st && st.GetSection(lpcszFormat, trSettings) )
		return true;
	return false;
	*/
	string str;
	str.Format(PAGE_INFO_EXPORT"%s", lpcszFormat);
	/// EJP 06-07-2004 v8.0853 QA70-6472 FILE_INFO_IN_PAGE
	/* Move code to a more general function for use by others.
	vector<byte> vb;
	if( pg.GetMemory(str, vb) )
	{
		if( str.SetBytes(vb) )
		{
			trSettings.XML = str;
			return true;
		}
	}
	return false;
	*/
	return tree_get_binary_storage(trSettings, pg, str);
	/// end FILE_INFO_IN_PAGE
}
///Frank 03/14/05 QA70-7470	REMOVE_ARGUMET_NOT_SECTION_IN_PAGE_INFO	
//bool tree_set_page_image_export_settings(TreeNode &trSettings, Page &pg, LPCSTR lpcszFormat, bool bClearSection)
bool tree_set_page_image_export_settings(TreeNode &trSettings, Page &pg, LPCSTR lpcszFormat)
///End	REMOVE_ARGUMET_NOT_SECTION_IN_PAGE_INFO	
{
	/* This old code used page's ini storage
	pg.Info.Add(PAGE_INFO_EXPORT);
	storage st;
	st = pg.GetStorage(PAGE_INFO_EXPORT);
	if( st )
	{
		if( bClearSection )
		{
			//---temp code until st.RemoveSection is implemented
			string strSection = lpcszFormat;
			pg.Info.Export.RemoveSection(strSection);
			//---
			//st.RemoveSection(lpcszFormat);
		}
		if( st.SetSection(lpcszFormat, trSettings) )
			return true;
	}
	return false;
	*/
	/// EJP 06-07-2004 v8.0853 QA70-6472 FILE_INFO_IN_PAGE
	/* Move code to a more general function for use by others.
	string str = trSettings.XML;
	vector<byte> vb;
	if( str.GetBytes(vb) )
	{
		str.Format(PAGE_INFO_EXPORT"%s", lpcszFormat);
		return pg.SetMemory(str, vb);
	}
	return false;
	*/
	string strStorage;
	strStorage.Format(PAGE_INFO_EXPORT"%s", lpcszFormat);
	return tree_put_binary_storage(trSettings, pg, strStorage);
	/// end FILE_INFO_IN_PAGE
}

///////////////////////////////////////
///// general tree related utilities
///////////////////////////////////////

///------ Folger 08/19/09 QA80-14168 LABTALK_TREE_NICE_DUMPING
/////Kenny 04/29/2009 ADD_OPTION_TO_OUT_TREE_TO_SUPPORT_MORE_OUTPUT_STYLE
//
//struct OutTreeSetting
//{
	//bool	bShowLine;
	//bool	bAlwaysShowTagName;
	//string	strOutText;
//};
//
//#define STR_SIMPLE_EMPTY_GAP			"  "
//#define STR_NO_PARALLEL_LINE_GAP		"    "
/////Kenny 06/10/2009 USE_ASCII_CODES_FOR_OUT_TREE_INSTEAD
//// #define STR_PARALLEL_LINE_GAP			"©¦  "
//// #define STR_MIDDLE_SIBLING_MARK			"©À©¤"
//// #define STR_LAST_SIBLING_MARK			"©¸©¤"
//#define STR_PARALLEL_LINE_GAP			" |  "
//#define STR_MIDDLE_SIBLING_MARK			" |--"
//#define STR_LAST_SIBLING_MARK			" |--"
/////End USE_ASCII_CODES_FOR_OUT_TREE_INSTEAD
//#define STR_EQUAL_TEXT_MARK				" = "
//#define STR_OUT_TREE_NEW_LINE			"\n"	//	"\r\n"
//
//static BOOL _concat_out_tree_text(TreeNode& tn, OutTreeSetting& ots, int nLevel)
//{
	///* An example output preview (with line)
	//Root
	//|--Background
	//|   |--Dimension
	//|      |--Left = 16.600000000000001
	//|      |--Top = 10.
	//|      |--Right = 12.4
	//|      |--Bottom = 15.200000000000001
	//|--Dimension
	//*/
	//if (!tn)
		//return FALSE;
//
	//if ( nLevel < 0 )
		//return TRUE;
//
	//string strOutLine;
//
	//const bool bIsRoot			= 0 == nLevel;
	//const bool bIsLeaf			= tn.FirstNode ? false : true;
	//const bool bIsLastSibling	= tn.NextNode ? false : true;
//
	//if ( !bIsRoot )
	//{
		//if (ots.bShowLine)
		//{
			//TreeNode tnTmp = tn;
			//for(int ii = 0; ii < nLevel-1; ii++)
			//{
				//TreeNode& tnParent = tnTmp.Parent();
				//const bool bParentIsLastSibling	= tnParent.NextNode ? false : true;
	//
				////  since the following line of code does not works, we may update the next two line if this is fixed
				////	strOutLine = (bParentIsLastSibling ? STR_SIMPLE_EMPTY_GAP : STR_PARALLEL_LINE_GAP) + strOutLine;
				//const string strGap = bParentIsLastSibling ? STR_NO_PARALLEL_LINE_GAP : STR_PARALLEL_LINE_GAP;
				//strOutLine = strGap + strOutLine;
				//tnTmp = tnParent;
			//}
			//strOutLine += bIsLastSibling ? STR_LAST_SIBLING_MARK : STR_MIDDLE_SIBLING_MARK;
		//}
		//else
		//{
			//for(int ii = 0; ii < nLevel-1; ii++)
			//{
				//strOutLine += STR_SIMPLE_EMPTY_GAP;
			//}
		//}
	//}
//
	//string strLabelText;
	//if( !ots.bAlwaysShowTagName && tn.GetAttribute(STR_LABEL_ATTRIB, strLabelText) && !strLabelText.IsEmpty() )
		//strOutLine += strLabelText;
	//else
		//strOutLine += tn.tagName;
//
	//if ( bIsLeaf )
		//strOutLine += STR_EQUAL_TEXT_MARK + tn.Text;
//
	//ots.strOutText += strOutLine + STR_OUT_TREE_NEW_LINE;
//
	//return TRUE;
//}
//
//static bool _pre_order_out_tree(TreeNode& tnRoot, OutTreeSetting& ots, int nLevel = 0)
//{
	//if ( !tnRoot )
		//return false;
	//
	//if( !_concat_out_tree_text(tnRoot, ots, nLevel) )
		//return false;
//
	//const bool bIsBranchNode = tnRoot.FirstNode ? true : false;
//
	//if (bIsBranchNode)
	//{
		//foreach(TreeNode cNode in tnRoot.Children)
		//{
			//_pre_order_out_tree(cNode, ots, nLevel+1);
		//}
	//}
	//return true;
//}
/////End ADD_OPTION_TO_OUT_TREE_TO_SUPPORT_MORE_OUTPUT_STYLE
//
/////Kenny 04/30/2009 ADD_OPTION_TO_OUT_TREE_TO_SUPPORT_MORE_OUTPUT_STYLE
////bool out_tree(TreeNode& tr, int nLevel) // = 0
//bool out_tree(TreeNode& tr, bool bShowLine /*= true*/, bool bAlwaysShowTagName /*= false*/)
/////End ADD_OPTION_TO_OUT_TREE_TO_SUPPORT_MORE_OUTPUT_STYLE
//{
	/////Kenny 04/30/2009 ADD_OPTION_TO_OUT_TREE_TO_SUPPORT_MORE_OUTPUT_STYLE
	/////// Iris 10/20/06 GET_RUNTIME_ERROR_FOR_INVALID_TREE
	//////if(NULL==tr)
	////if(!tr)
		////return false;
	////
	////for(int ii = 0; ii < nLevel; ii++)
		////printf("  ");
	////
	///////Iris 06/30/05 PRINT_LABEL_FOR_LEFT_NODE
	////string strLabel;
	////if(!tr.GetAttribute(STR_LABEL_ATTRIB, strLabel))
		////strLabel = tr.tagName;
	///////end PRINT_LABEL_FOR_LEFT_NODE
	////if(tr.GetNodeCount() > 0) // branch node
	////{
		///////Iris 06/30/05 PRINT_LABEL_FOR_LEFT_NODE
		//////string strLabel;
		//////if(!tr.GetAttribute(STR_LABEL_ATTRIB, strLabel))
			//////strLabel = tr.tagName;
		///////end PRINT_LABEL_FOR_LEFT_NODE
		////printf("%s\n", strLabel);
		////foreach(TreeNode cNode in tr.Children)
			////out_tree(cNode, nLevel+1);
	////}
	////else // leaf node
		///////Iris 06/30/05 PRINT_LABEL_FOR_LEFT_NODE
		//////printf("%s = %s\n", tr.tagName, tr.Text);		
		////printf("%s = %s\n", strLabel, tr.Text);
		///////end PRINT_LABEL_FOR_LEFT_NODE
//
	////return true;
	//OutTreeSetting ots;
	//ots.bShowLine = bShowLine;
	//ots.bAlwaysShowTagName = bAlwaysShowTagName;
//
	//bool bRet = _pre_order_out_tree(tr, ots, -1);
	//out_str(ots.strOutText);
//
	//return bRet;
	/////End ADD_OPTION_TO_OUT_TREE_TO_SUPPORT_MORE_OUTPUT_STYLE
//}
bool out_tree(TreeNode& tr, bool bShowLine /*= true*/, bool bAlwaysShowTagName /*= false*/, string* pstrOut/* = NULL*/)
{
	DWORD	dwOptions = 0;
	if ( bShowLine )
		dwOptions |= OTR_SHOW_LINE_AS_CONNECTOR;
	if ( !bAlwaysShowTagName )
		dwOptions |= OTR_USE_LABEL;
	return okutil_out_tree(&tr, 0, dwOptions, pstrOut);
}
///------ End LABTALK_TREE_NICE_DUMPING

///DSC 9/13/05 MOVE_TREE_COUNT_ITEMS_TO_VC
/*
static void treeNode_count(TreeNode& trNode, int& nLeafs, int& nBranches)
{	
	if(trNode.GetNodeCount() > 0 || trNode.ID == ONODETYPE_BRANCH) // branch node
	{
		int nSubBranches = 0;
		nBranches++;
		nLeafs += tree_count_items(trNode, &nSubBranches);
		nBranches += nSubBranches;
	}
	else
	{
		DWORD dwID = trNode.ID;
		DWORD dwBranchBits = ONODETYPE_BRANCH | ONODETYPE_BRANCH_COMPOSITE | ONODETYPE_BRANCH_DIALOG;
		if(dwID && (dwID & dwBranchBits)) // skip branch nodes
		{
			//out_int("skipped ", dwID);
			return;
		}
		//else
		//	out_int("not skipped ", dwID);
		nLeafs++;
	}
}
*/
///end MOVE_TREE_COUNT_ITEMS_TO_VC

// count number of leafs in the given tree
// if lpnSections given, then count the number of branches that contain these leafs
int tree_count_items(TreeNode& tr, int* lpnSections)// = NULL);
{
	///DSC 9/13/05 MOVE_TREE_COUNT_ITEMS_TO_VC
	/*
	if(NULL==tr)
		return -1;
	
	int nLeafs = 0;
	//
	if(NULL==lpnSections)
	{
		if(tr.GetAttribute(THEME_COUNT_NAME, nLeafs))
			return nLeafs;
		
	}
	
	int nBranches = 0;
	foreach(TreeNode trN in tr.Children)
	{
		treeNode_count(trN, nLeafs, nBranches);
	}
	if(lpnSections)
		*lpnSections = nBranches;
	
	return nLeafs;
	*/
	return okutil_tree_count_items(&tr, lpnSections);
	///end MOVE_TREE_COUNT_ITEMS_TO_VC
}
///------Frank 6/30/05	ADD_COUNT_TREENODE_BY_ATTRIBUTE
/// Hong 05/26/07 v8.0870 IRIS_REQUIRE_VERSION_NO_RECURSIVE
//int tree_count_items_by_attribute(TreeNode& tr, LPCSTR lpcszAttribute, LPCSTR lpcszValue, bool bMissingIsMatch )// = NULL, NULL, = true);
int tree_count_items_by_attribute(TreeNode& tr, LPCSTR lpcszAttribute, LPCSTR lpcszValue, bool bMissingIsMatch, bool bRecursive)// = NULL, NULL, true, true
/// end IRIS_REQUIRE_VERSION_NO_RECURSIVE
{
	//---- CPY 1/29/06 XFBASE_MOVE_OC_TO_VC
	/*
	///Jasmine 01/13/06 TREE_COUNT_ITEMS_BY_STTRIBUTE_CHECK_VALIDITY
	if(!tr)
		return -1;
	///End
	int nCount = 0;
	string strAttriValue;
	foreach(TreeNode cNode in tr.Children)
	{
		if(lpcszAttribute == NULL)
			nCount++;
		else
		{
			bool bFound = cNode.GetAttribute(lpcszAttribute, strAttriValue);
			if(lpcszValue== NULL || ((bMissingIsMatch && !bFound) || (bFound && lstrcmp(lpcszValue, strAttriValue )==0)))
				nCount++;
		}
		
		if(cNode.GetNodeCount() > 0) // branch node
			nCount += tree_count_items_by_attribute(cNode, lpcszAttribute, lpcszValue, bMissingIsMatch);
	}
	return nCount;
	*/
	/// Hong 05/26/07 v8.0870 IRIS_REQUIRE_VERSION_NO_RECURSIVE
	//return octree_count_items_by_attribute(&tr, lpcszAttribute, lpcszValue, bMissingIsMatch);
	return octree_count_items_by_attribute(&tr, lpcszAttribute, lpcszValue, bMissingIsMatch, bRecursive);
	/// end IRIS_REQUIRE_VERSION_NO_RECURSIVE
	//-----
}
///------End	ADD_COUNT_TREENODE_BY_ATTRIBUTE
//	copy attribute from TreeNode trSrc to trDest
//	Return:
//		true if trSrc has given attribute and is copied to trDest
bool tree_node_copy_attribute(const TreeNode& trSrc, TreeNode& trDest, LPCSTR lpcszAttribute)
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 7/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	string str;
	if(trSrc.GetAttribute(lpcszAttribute, str))
	{
		trDest.SetAttribute(lpcszAttribute, str);
		return true;
	}
	return false;
#else //_TREE_UTILS_FROM_HONG_DLL
	return octree_node_copy_attribute(&trSrc, &trDest, lpcszAttribute);
#endif //_TREE_UTILS_FROM_HONG_DLL	///Hong 7/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}

///------DG REWRITE_TREE_GET_NODE : move tree_get_node fully to VC level, keep the converting part in OC level
/*
///Danice 3/7/04 v8.0832 ADD_LEVEL_CONTROL
// consider a linearized tree and return node at given row number, with nRow = 0 to return the root
#ifndef _TREE_UTILS_FROM_DLL	/// SY 07/07/2004 QA70-6641 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
///---DG 3/18/05 CLEAN_DOUBLE_STORAGE
TreeNode tree_get_node(TreeNode& trRoot, int nRow, int nStopLevel, LPCSTR lpcszStopAttribute, bool bStopAtLastBranch, int nCurrentLevel, int* lpInc) //-1, NULL, false, 0, NULL
{
	bool bHasAttribute = NULL != lpcszStopAttribute && 0 != strcmp(lpcszStopAttribute, "");
	bool bSkipLeaf = bStopAtLastBranch && !bHasAttribute;
	bool bFolderOnly = bStopAtLastBranch && bHasAttribute;
	bool bSkipSubNode = !bStopAtLastBranch && bHasAttribute;
	
	TreeNode trJunk;
	if(!trRoot.IsValid() || nRow < 0)
		return trJunk;
	
	///DG 3/21/05 : ignore top node
	bool bCheckStop = (0 <= nStopLevel) ? TRUE : FALSE;
	int nIndex = (lpInc)? *lpInc : -1;
	if(!bCheckStop || nCurrentLevel <= nStopLevel)
	{
		string strTemp;
		foreach(TreeNode trN in trRoot.Children)
		{
			bool bLeaf = trN.GetNodeCount() < 1;
			if(bFolderOnly && !trN.GetAttribute(lpcszStopAttribute, strTemp)) //folder node marked by attribute
				//return trJunk; //not folder node	///DG 3/25/05 bug, should not return
				continue;	//not folder node
			else if(bLeaf && bSkipLeaf)
				//return trJunk; //skip leaf	///DG 3/23/05 bug, should not return
				continue;	//skip leaf
			
			nIndex++;
			if(nIndex == nRow)
				return trN;	//found, return
			else if(!bLeaf)
			{
				if(!(bSkipSubNode && trN.GetAttribute(lpcszStopAttribute, strTemp)))
				{
					//don't skip subnode
					TreeNode cNode = tree_get_node(trN, nRow, nStopLevel, lpcszStopAttribute, bStopAtLastBranch, nCurrentLevel+1, &nIndex);
					if(cNode)
						return cNode;
				}
			}
		}
	}
	if(lpInc)
		*lpInc = nIndex;
	///end
	return trJunk;
}
///end CLEAN_DOUBLE_STORAGE
#else //_TREE_UTILS_FROM_DLL
///---DG 3/18/05 CLEAN_DOUBLE_STORAGE
TreeNode tree_get_node(TreeNode& trRoot, int nRow, int nStopLevel, LPCSTR lpcszStopAttribute, bool bStopAtLastBranch, int nCurrentLevel, int* lpInc) //-1, NULL, false, 0, NULL
{
	TreeNode tr;
	/// AW 03/21/05 v8.0208 CLEAN_GET_TREE_NODE
	//octree_get_node(&trRoot, &tr, nRow, nStopLevel, lpcszStopAttribute, bStopAtLastBranch);
	octree_get_node(&trRoot, &tr, nRow, nStopLevel, lpcszStopAttribute, bStopAtLastBranch, nCurrentLevel, lpInc);
	/// AW 03/21/05 v8.0208 CLEAN_GET_TREE_NODE
	
	return tr;
}
*/
TreeNode tree_get_node(TreeNode& trRoot, int nRow, DWORD dwCntrl, LPCSTR lpcszAttribute) //=0, NULL
{
	TreeNode tr;
	int		nCurrentRow=0; //must begin from 0
	
	bool	bCheckStop				= dwCntrl & ATRN_STOP_LEVEL ? true : false;
	int 	nStopLevel 				= bCheckStop ? (int)LOBYTE(dwCntrl) : -1;
	bool 	bUseAttributeAsStop 	= dwCntrl & ATRN_LOOP_MARDED_NODE_ONLY ? false : true;
	bool 	bSkipLeaf 				= dwCntrl & ATRN_SKIP_LEAFS ? true : false;
	
	octree_get_node(&trRoot, &tr, nRow, &nCurrentRow, nStopLevel, lpcszAttribute, bUseAttributeAsStop, bSkipLeaf);
	return tr;
}

int tree_copy_values(const TreeNode& trSrc, TreeNode& trDest, WORD wOptions)// = TREE_COPY_SKIP_HIDDEN | TREE_COPY_ATTRIB_ENABLE
{
	return octree_copy_values(&trSrc, &trDest, wOptions);
}

//		walk all nodes, look for nodes with ID, and apply it to destination tree nodes that has same ID
int tree_copy_values_by_id(const TreeNode& trSrc, TreeNode& trDest)
{
	/// Hong 07/02/08 v8.0895 GET_RID_OF_CHECKING_NODE_VALID_EVERY_CALL
	ASSERT(trDest);
	if ( !trDest || !trSrc || !trSrc.FirstNode )
		return 0;
	/// end GET_RID_OF_CHECKING_NODE_VALID_EVERY_CALL
	///Joseph 01/28/07 COPY_SHOULD_SUPPORT_BRANCH_USE_ATTRIB
	//return octree_copy_values_by_id(&trSrc, &trDest);
	/// Hong 08/29/08 v8.0932 IMPROVE_DEBUG
	//return octree_copy_values_by_id(&trSrc, &trDest, false, NULL, NULL, false);
	int		nRet = octree_copy_values_by_id(&trSrc, &trDest, false, NULL, NULL, false);
	ASSERT(nRet >= 0); // I find lots of code do NOT check return value, and let error skip silently which make debug hard
	return nRet;
	/// end IMPROVE_DEBUG
	///End COPY_SHOULD_SUPPORT_BRANCH_USE_ATTRIB
}


//---- CPY 5/30/03 QA70-4577 EVENT_HANDLER_NEED_DIALOG_AND_VALUE_UPDATE

/**
	walk all tree nodes to delete specified attribute
	Parameters:
		tr = TreeNode to walk
		lpcszAttribute = attribute name to delete
	Returns:
		total number of nodes the specified attribute is deleted	
*/
int tree_remove_attribute(TreeNode& tr, LPCSTR lpcszAttribute)
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 26/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL  /// Iris 5/12/06 FO_NOT_WORK_ROLLBACK_TO_ORIGINAL_CODE
	int nCount = 0;
	foreach(TreeNode cNode in tr.Children)
	{
		if(cNode.RemoveAttribute(lpcszAttribute))
			nCount++;
			
		
		if(cNode.GetNodeCount() > 0) // branch node
			nCount += tree_remove_attribute(cNode, lpcszAttribute);
	}
	return nCount;
#else	//_TREE_UTILS_FROM_HONG_DLL	
	return octree_remove_attribute(&tr, lpcszAttribute);
#endif//_TREE_UTILS_FROM_HONG_DLL ///Hong 26/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}

bool tree_node_changed(TreeNode& trNode, bool bSet, LPCSTR lpcszOldValue) // = false, = NULL
{
	return octree_node_changed(&trNode, bSet, lpcszOldValue);
}

static void tree_node_get_value(TreeNode& trNode, string& strVal)
{
	if(trNode.GetNodeCount() > 0) // branch node
		strVal.Empty();
	else
		strVal = trNode.strVal;
}
	
void tree_get_node_names(TreeNode& tr, vector<string>& vs, bool bSubNodeOnly) // = false
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 26/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	string strVal;
	foreach(TreeNode cNode in tr.Children)
	{		
		strVal=cNode.tagName;
		vs.Add(strVal);
		if(!bSubNodeOnly && cNode.GetNodeCount() > 0) // branch node
			tree_get_node_names(cNode, vs, bSubNodeOnly);
	}
#else//_TREE_UTILS_FROM_HONG_DLL
	octree_get_node_names(&tr, &vs, bSubNodeOnly);
#endif//_TREE_UTILS_FROM_HONG_DLL ///Hong 26/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}

void tree_get_values(TreeNode& tr, vector<string>& vs, bool bSubNodeOnly)// = false
{
	octree_get_values(&tr, &vs, bSubNodeOnly);
}


int tree_node_get_int(TreeNode& tr, int nDefault)// = -1)
{
	if(tr)
		return tr.nVal;
	
	return nDefault;
}

 

//---- CPY v7.5785 12/19/03 QA70-5738 GETN_BOX_COMBO_CHANGE_NEEDED
int tree_update_changes(TreeNode& tr, const vector<string>& vs)
{
	return octree_update_changes(&tr, &vs);
}

void tree_get_attributes(TreeNode& tr, vector<string>& vs, LPCSTR lpcszAttribute, bool bSubNodeOnly)// = false
{
	octree_get_attributes(&tr, &vs, lpcszAttribute, bSubNodeOnly);
}
//---- end GETN_BOX_COMBO_CHANGE_NEEDED
	
///Danice MOVE_UTILITY_FUNCTION_TO_TREE_UTILS
//TD 3-30-04 MOVED FROM TREE_UTILS.h
///Danice 2/25/04 QA70-6032 PRESENTATION_MANAGER_NEED
#define ID_FOLDER 10 // later will need icon id
static int _get_page_ID(Page& pg)
{
	return 12; // later, will get actual icon id to use as page id based on page type
}

static bool _add_folder_pages(TreeNode& tr, Folder& fldParent, DWORD dwPageTypeFilter)
{
	int	iNode = 0;
	int iFolder = 1;
	string str;
	
	///James 06/06/06 v8.0421 ADD_FOLDER_PAGES_ADD_PAGES 
	int	iPage = 1;
	
	foreach(PageBase pg in fldParent.Pages)
	{
		//check filter later
		//if(pg.GetType() != nPageTypeToExclude)
		str = "Page" + iPage++;
		///-----James 6/6/06 NO_OPERATOR_CONTROL_IN_BROWSER
		//TreeNode tnp = tn.AddNode(str, _get_page_ID(pg));
		TreeNode tnp = tr.AddNode(str,  get_page_display_id(pg.GetType()));
		///-----End NO_OPERATOR_CONTROL_IN_BROWSER
		iNode++;
		tnp.SetAttribute(STR_NAME_ATTRIB, pg.GetName());// LT name, short name, tagName for pages
		tnp.SetAttribute(STR_LABEL_ATTRIB, pg.Label);
			
		///-----James 6/6/06 NO_OPERATOR_CONTROL_IN_BROWSER
		if( LOWORD(dwPageTypeFilter)  - pg.GetType() == 0)
			tnp.SetAttribute(STR_DISPLAY_ATTRIB, get_page_display_id(pg.GetType()));				
		///-----End NO_OPERATOR_CONTROL_IN_BROWSER
	}	
	/// End ADD_FOLDER_PAGES_ADD_PAGES 
	
	foreach(Folder fld in fldParent.Subfolders)
	{
		str = "Folder" + iFolder++;
		TreeNode	tn = tr.AddNode(str, ID_FOLDER);
		iNode++;
		tn.SetAttribute(STR_LABEL_ATTRIB, fld.GetName());
		tn.SetAttribute(STR_PATH_ATTRIB, fld.GetPath());
		tn.SetAttribute(STR_DISPLAY_ATTRIB, IDI_FOLDER_CLOSED);/// TD 3-23-04 QA70-6053 PICTURE_IN_OC
		
		_add_folder_pages(tn, fld, dwPageTypeFilter);
		
		///James 06/07/12 v8.0441 ADD_FOLDER_PAGES_ADD_PAGES_REMOVE_CODE 
		/*int	iPage = 1;
		foreach(PageBase pg in fld.Pages)
		{
			//check filter later
			//if(pg.GetType() != nPageTypeToExclude)
			str = "Page" + iPage++;
			///-----Frank 11/14/05 NO_OPERATOR_CONTROL_IN_BROWSER
			//TreeNode tnp = tn.AddNode(str, _get_page_ID(pg));
			TreeNode tnp = tn.AddNode(str,  get_page_display_id(pg.GetType()));
			///-----End NO_OPERATOR_CONTROL_IN_BROWSER
			iNode++;
			tnp.SetAttribute(STR_NAME_ATTRIB, pg.GetName());// LT name, short name, tagName for pages
			tnp.SetAttribute(STR_LABEL_ATTRIB, pg.Label);
			
			///-----Frank 11/14/05 NO_OPERATOR_CONTROL_IN_BROWSER
			if( LOWORD(dwPageTypeFilter)  - pg.GetType() == 0)
				tnp.SetAttribute(STR_DISPLAY_ATTRIB, get_page_display_id(pg.GetType()));				
			///-----End NO_OPERATOR_CONTROL_IN_BROWSER
		}*/
		/// End ADD_FOLDER_PAGES_ADD_PAGES_REMOVE_CODE 
	}
	return 0 == iNode ? false : true;
}

bool tree_get_project_folders_and_pages(TreeNode &tr, DWORD dwPageTypeFilter)// = 0)
{
	PageBase	pg;
		
	Folder	rtFolder = Project.RootFolder;

	tr.project.ID = 0;// we may need a diff ID for project root later.
	tr.project.SetAttribute(STR_LABEL_ATTRIB, rtFolder.GetName());
	tr.project.SetAttribute(STR_DISPLAY_ATTRIB, IDI_FOLDER_CLOSED);/// Frank 6/2/05		SET_ROOT_ATTRIB_OF_FOLDER_LIST
	
	return _add_folder_pages(tr.project, rtFolder, dwPageTypeFilter);
}
///end MOVE_UTILITY_FUNCTION_TO_TREE_UTILS
///------Frank 6/21/05 ADD_FOLDERS_AND_PAGES_TO_TREE
//bool tree_get_folders_and_pages(TreeNode& trParent, Folder& fldFolder, DWORD dwPageTypeFilter)
int tree_get_folders_and_pages(Folder& fldFolder, TreeNode& trParent, TreeNode &trNewFolder, DWORD dwPageTypeFilter)
{
	int nRow =0;
	
	if(!trParent)
		return nRow;
	int nCount = trParent.GetNodeCount() +1;
	string str = "Folder" + nCount;
	TreeNode trFolder ;
	if(trParent.GetNodeCount() <= 0)
	{
		nRow++;
		trFolder = trParent.AddNode( str, ID_FOLDER);
	}
	else
	{
		TreeNode trBeforeNode;
		string 	strBeforeName ;
		foreach(TreeNode cNode in trParent.Children)
		{
			nRow++;
			strBeforeName = get_node_label(cNode);
			//if(strBeforeName.Compare(fldFolder.GetName()) >= 0)
			string strTemp;
			if(strBeforeName.Compare(fldFolder.GetName()) >= 0 || !cNode.GetAttribute(STR_DISPLAY_ATTRIB,strTemp)) ///Folder tree should add before page, so after check the node with out display attribute, mean page node
			{
				trBeforeNode = cNode;
				break;
			}
			int nSection , nNodeCount;
			//nNodeCount = tree_count_items(cNode, &nSection);
			nNodeCount = tree_count_items_by_attribute(cNode, STR_DISPLAY_ATTRIB);
			nRow += nSection + nNodeCount;
		}
		
		//trFolder = trParent.InsertNode(trBeforeNode, str, ID_FOLDER);
		if(!trBeforeNode)
		///Frank 11/09/05 SHOULD_ADD_ONE_IF_ADD_LAST
			//trFolder = trParent.AddNode( str, ID_FOLDER);
		{
			trFolder = trParent.AddNode( str, ID_FOLDER);
			nRow++;
		}
		///End5 SHOULD_ADD_ONE_IF_ADD_LAST
		else
			trFolder = trParent.InsertNode(trBeforeNode, str, ID_FOLDER);			
	}

	trFolder.SetAttribute(STR_LABEL_ATTRIB, fldFolder.GetName());
	trFolder.SetAttribute(STR_PATH_ATTRIB, fldFolder.GetPath());
	trFolder.SetAttribute(STR_DISPLAY_ATTRIB, IDI_FOLDER_CLOSED);
	
	_add_folder_pages(trFolder, fldFolder, dwPageTypeFilter);
	trNewFolder = trFolder;
	return nRow;
}
///------End ADD_FOLDERS_AND_PAGES_TO_TREE

// TD 3-30-04 PM_FUNCTIONS_MOVED
///Danice 3/8/04 v8.0833 ADD_CLEAR_TREE
void tree_clear_all_value(TreeNode& tr)
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 26/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	foreach(TreeNode tn in tr.Children)
	{
		if(!tn.FirstNode)
		{
			tn.strVal="";
			continue;
		}
		tree_clear_all_value(tn);
	}
#else//_TREE_UTILS_FROM_HONG_DLL
	octree_clear_all_value(&tr);
#endif//_TREE_UTILS_FROM_HONG_DLL ///Hong 26/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}
///END ADD_CLEAR_TREE

///DG ATTRIBUTE_EXIST_IN_TREE_NODE
bool tree_check_attribute_value_exist(const TreeNode& tr, LPCSTR lpcszVal, LPCSTR lpcszAttrib, bool bCaseSensitive, bool bRecursive) //=false, false
{
	TreeNode trFind=tr.FindNodeByAttribute(lpcszAttrib, lpcszVal, bRecursive, bCaseSensitive);
	return trFind.IsValid();
}
///end ATTRIBUTE_EXIST_IN_TREE_NODE

///Danice 4/27/04 QA70-6332 v8.0863 ADD_COPY_VALUE_TO_ATTRIBUTE

/// YuI 11/01/04 VC_IMPLEMENTED_FindNodeByAttribute_NEED_RECURSION
/*
TreeNode tree_get_node_by_attributes(TreeNode tr, LPCSTR lpcszAttribute, LPCSTR lpcszAttributeVal, bool bRecursive, bool bCaseSensitive)	//=true, =false
{
	string strFind;
	foreach(TreeNode cNode in tr.Children)
	{		
		if(cNode.GetAttribute(lpcszAttribute, strFind))
		{
			if(bCaseSensitive)
			{
				if(0 == strFind.Compare(lpcszAttributeVal))
					return cNode;
			}
			else if(0 == strFind.CompareNoCase(lpcszAttributeVal))
				return cNode;
		}	
		if(bRecursive && cNode.GetNodeCount() > 0) // branch node
		{
			TreeNode trFind = tree_get_node_by_attributes(cNode, lpcszAttribute, lpcszAttributeVal, bRecursive, bCaseSensitive);
			if(trFind)
				return trFind;
		}
	}
	TreeNode junk;
	return junk;
}
*/
/// end VC_IMPLEMENTED_FindNodeByAttribute_NEED_RECURSION
//----------------------------- CPY 8/10/04 QA70-6784 v8.0115 GET_INCOMING_OPERATION_CHANGE
TreeNode tree_get_node_by_id(const TreeNode& tr, int nID, bool bRecursive) // = false
{	
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 26/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL  /// Iris 4/27/06 VS_CODES_FAIL_TO_WORK_ROLLBACK_OC_CODES
	foreach(TreeNode cNode in tr.Children)
	{	
		/// Iris 6/04/05
		//if(nID == cNode.ID)
		if(nID == cNode.ID || nID == cNode.DataID)
			return cNode;
		if(bRecursive && cNode.GetNodeCount() > 0) // branch node
		{
			TreeNode trFind = tree_get_node_by_id(cNode, nID, true);
			if(trFind)
				return trFind;
		}
	}
	TreeNode junk;
	return junk;
#else//_TREE_UTILS_FROM_HONG_DLL
	TreeNode trFind;
	bool bRet = octree_get_node_by_id(&tr, &trFind, nID, bRecursive);
	return trFind;
#endif//_TREE_UTILS_FROM_HONG_DLL ///Hong 26/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}
//-----------------------------

bool tree_copy_values_to_attributes(TreeNode& trSrc, TreeNode& trDest, LPCSTR lpcsz2ndAttributeToTransfer, LPCSTR lpcszDestAttribute, LPCSTR lpcszAttributeToMatch, bool bRecursive, bool bAllMatched, bool bCaseSensitive)	//=NULL, =NULL, =true, =true, =false
{
	return octree_copy_values_to_attributes_by_attribute_matching(&trSrc, &trDest, lpcszDestAttribute, lpcszAttributeToMatch, lpcsz2ndAttributeToTransfer, bRecursive,bAllMatched,bCaseSensitive);
}
///END ADD_COPY_VALUE_TO_ATTRIBUTE

//------- CPY 11/6/04
//	copy the same values to all tree nodes with specified attributes matching one of the given values
bool tree_set_attributes(TreeNode& trDest, const vector<int>& vnAttributeVals, LPCSTR lpcszValToCopy, LPCSTR lpcszDestAttribute, LPCSTR lpcszAttributeToMatch, bool bRecursive)// = NULL,  = true;
{
	/// ML 1/13/2006 XVARIABLEBASE_TO_VC
	/*
	Tree trSrc;
	TreeNode trN;
	string strAttribMatch = lpcszAttributeToMatch;
	if(strAttribMatch.IsEmpty())
		strAttribMatch = STR_DATAID_ATTRIB;
	
	for(int ii = 0; ii < vnAttributeVals.GetSize(); ii++)
	{
		string strNode;strNode.Format("n%d", ii);
		trN = trSrc.AddNode(strNode, ii + 1);
		trN.SetAttribute(strAttribMatch,vnAttributeVals[ii]);
		trN.strVal = lpcszValToCopy;
	}
	return tree_copy_values_to_attributes(trSrc, trDest, NULL, lpcszDestAttribute, lpcszAttributeToMatch, bRecursive);
	*/

	return octree_set_attributes(&trDest, &vnAttributeVals, lpcszValToCopy, lpcszDestAttribute, lpcszAttributeToMatch, bRecursive);
	/// end XVARIABLEBASE_TO_VC
}
//-------

///Iris 01/14/05 FIX_BRANCH_NOT_WORKING
/*
static bool _check_branch_hidden_node(TreeNode& trNode)
{
	if( TRGP_BRANCH == trNode.ID && 0 == trNode.Show)
		return true;
	else
		return false;
}
*/
///end FIX_BRANCH_NOT_WORKING




//------------------------------------------------------ CPY 4/22/05 QA70-7651 DESC_STATS_ON_ROWS_CLEAN
/*
///Iris 12/31/04 IMPROVE_ACCESS_ADVANCED_IDS_FUNC
static void _reset_GUI_values(TreeNode& trNode)
{
	int nTypeID = trNode.ID;
	switch(nTypeID)
	{
	case TRGP_CHECK:
	case TRGP_ENUM_LIST:
			trNode.nVal = 0;
			break;
	///Iris 01/14/05 FIX_BRANCH_NOT_WORKING
	case TRGP_BRANCH:
		///----Frank 4/15/05 FIX_BRANCH_CHECK_BOX_APPEAR_WHEN_CLICK_ADVANCED
		//trNode.Use = 0;
		if(trNode.Use == 1)
			trNode.Use = 0;
		///----End FIX_BRANCH_CHECK_BOX_APPEAR_WHEN_CLICK_ADVANCED
		
		foreach(TreeNode trChild in trNode.Children)
			_reset_GUI_values(trChild);
			break;
	///end FIX_BRANCH_NOT_WORKING
	default:
		break;			
	}
}

void tree_GUI_reset_hidden_values(TreeNode& tr, const vector<int>& vnAttributeVals)
{
	foreach(TreeNode trNode in tr.Children)
	{
		///Iris 01/14/05 FIX_BRANCH_NOT_WORKING
		//if(trNode.GetNodeCount()>0 && _check_branch_hidden_node(trNode))
			//tree_GUI_reset_hidden_values(trNode, vnAttributeVals);
		//else
		//{
		///end FIX_BRANCH_NOT_WORKING
		
			int nID;
			trNode.GetAttribute(STR_DATAID_ATTRIB, nID);
			vector<uint> vnIndex;
			if( 0 != vnAttributeVals.Find(vnIndex, nID) && 0 == trNode.Show)
				_reset_GUI_values(trNode);
	}
	
}
*/
static void _reset_GETN_value(TreeNode& trNode)
{
	int nTypeID = trNode.ID;
	switch(nTypeID)
	{
	case TRGP_CHECK:
	case TRGP_ENUM_LIST:
		trNode.nVal = 0;
		break;
	///Iris 01/14/05 FIX_BRANCH_NOT_WORKING
	case TRGP_BRANCH:
		///----Frank 4/15/05 FIX_BRANCH_CHECK_BOX_APPEAR_WHEN_CLICK_ADVANCED
		//trNode.Use = 0;
		///Iris 4/25/05 CHANGE_CHECK_USE_METHOD
		//if(trNode.Use == 1)  
		int nUse;
		if(trNode.GetAttribute(STR_USE_ATTRIB, nUse))
			trNode.Use = 0;
		///----End FIX_BRANCH_CHECK_BOX_APPEAR_WHEN_CLICK_ADVANCED
		break;
	///end FIX_BRANCH_NOT_WORKING
	default:
		break;			
	}
}

int tree_GETN_reset_hidden_values(TreeNode& tr, const vector<int>& vnDataIDsToReset, bool bRecursive)
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 7/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	int nDataID;
	int nCount = 0;
	foreach(TreeNode trNode in tr.Children)
	{
		nDataID = trNode.DataID;
		if(nDataID > 0 && find_in_list(nDataID, vnDataIDsToReset, true) >= 0)
		{
			_reset_GETN_value(trNode);
			nCount++;
		}
		if(bRecursive && trNode.GetNodeCount() > 0)
			nCount += tree_GETN_reset_hidden_values(trNode, vnDataIDsToReset, bRecursive);
	}
	return nCount;
#else //_TREE_UTILS_FROM_HONG_DLL
	return octree_GETN_reset_hidden_values(&tr, &vnDataIDsToReset, bRecursive); 
#endif //_TREE_UTILS_FROM_HONG_DLL ///Hong 7/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}
//------------------------------------------------------ end CPY 4/22/05 QA70-7651 DESC_STATS_ON_ROWS_CLEAN

	

int tree_get_values_with_ids(const TreeNode& trSetting, vector<int>& vnIDs, vector<string>& vsValues, bool bIncludeSub, bool bCheckChange, int nRepeatBranchID)// = true, = false, =0
{
	string strError;
	/// TD 5-4-07 QA80-9724 THEME_TREE_WITH_LABELS_FOR_READABILITY
	//int nNumIds =  octree_get_values_with_ids(&trSetting, &vnIDs, &vsValues, bIncludeSub, bCheckChange, nRepeatBranchID, NULL, true, &strError);
	int nNumIds =  octree_get_values_with_ids(&trSetting, &vnIDs, &vsValues, NULL, bIncludeSub, bCheckChange, nRepeatBranchID, NULL, true, &strError);
	/// end THEME_TREE_WITH_LABELS_FOR_READABILITY
	
	if( !strError.IsEmpty() )
	{
		strError.WriteLine(WRITE_COMPILER_OUTPUT);
	}
	
	return nNumIds;
}

/// TD 5-4-07 QA80-9724 THEME_TREE_WITH_LABELS_FOR_READABILITY
int tree_get_values_with_ids_and_labels(const TreeNode& trSetting, vector<int>& vnIDs, vector<string>& vsValues, vector<string>& vsLabels, bool bIncludeSub, bool bCheckChange, int nRepeatBranchID)// =true, false, 0
{
	string strError;
	int nNumIds =  octree_get_values_with_ids(&trSetting, &vnIDs, &vsValues, &vsLabels, bIncludeSub, bCheckChange, nRepeatBranchID, NULL, true, &strError);
	
	if( !strError.IsEmpty() )
	{
		strError.WriteLine(WRITE_COMPILER_OUTPUT);
	}
	
	return nNumIds;
}
/// end THEME_TREE_WITH_LABELS_FOR_READABILITY



/**
		walk all nodes, look for nodes with matching ID, and apply value, if the have same ID, will 
		just save the first one ID corresponding value.
	Parameters:
		trSetting = a source tree
		vnIDs = vector of IDs.
		vsValues = vector of string values, must be the same size of vnIDs.
	Returns:
		number of matching found nodes,
		if return -1 mean input tree node not invalid,
		-2 mean the pairs of vector size to 0;
		-3 when the pair vector not the same size,
 */
///Frank 3/2/05 QA70-7455	COPY_TREE_SUPPORT_DUPLICATE_ID_WITH_REPEAT_ATTRIB
//int tree_set_values_by_ids(TreeNode& trSetting, const vector<int>& vnIDs, const vector<string>& vsValues)//, bool* pbUsed=NULL)
///------ Folger 03/18/09 QA80-13261-P2 NEW_ADDED_AUTO_FOR_XF_VARIABLE_FAILS_TO_COMPATIBLE_WITH_OLD_THEME
//int tree_set_values_by_ids(TreeNode& trSetting, const vector<int>& vnIDs, const vector<string>& vsValues, int nRepeatBranchID, int* pnDuplicateID)
///------ Folger 04/15/09 QA80-13454 SPECIAL_ATTRIBUTES_SHOULD_BE_CORRECTLY_UPDATED_WHEN_USE_OLD_THEME_AND_OP
//int tree_set_values_by_ids(TreeNode& trSetting, const vector<int>& vnIDs, const vector<string>& vsValues, int nRepeatBranchID, int* pnDuplicateID, BOOL bResetAutoIfNeeded/* = FALSE*/)
int tree_set_values_by_ids(TreeNode& trSetting, const vector<int>& vnIDs, const vector<string>& vsValues, int nRepeatBranchID, int* pnDuplicateID, DWORD dwCntrl/* = 0*/)
///------ End SPECIAL_ATTRIBUTES_SHOULD_BE_CORRECTLY_UPDATED_WHEN_USE_OLD_THEME_AND_OP
///------ End NEW_ADDED_AUTO_FOR_XF_VARIABLE_FAILS_TO_COMPATIBLE_WITH_OLD_THEME
///End	COPY_TREE_SUPPORT_DUPLICATE_ID_WITH_REPEAT_ATTRIB
{
	/// Frank 11/11/05 ADD_REPEAT_ID_COMBINE_ERROR_OUT								
	//return octree_set_values_by_ids(&trSetting, &vnIDs, &vsValues, nRepeatBranchID, pnDuplicateID);
	string strError;
	///------ Folger 03/18/09 QA80-13261-P2 NEW_ADDED_AUTO_FOR_XF_VARIABLE_FAILS_TO_COMPATIBLE_WITH_OLD_THEME
	//int nNumIds =  octree_set_values_by_ids(&trSetting, &vnIDs, &vsValues, nRepeatBranchID, pnDuplicateID, false, NULL, &strError);
	///------ Folger 04/15/09 QA80-13454 SPECIAL_ATTRIBUTES_SHOULD_BE_CORRECTLY_UPDATED_WHEN_USE_OLD_THEME_AND_OP
	//int nNumIds =  octree_set_values_by_ids(&trSetting, &vnIDs, &vsValues, nRepeatBranchID, pnDuplicateID, false, NULL, &strError, bResetAutoIfNeeded);
	int nNumIds =  octree_set_values_by_ids(&trSetting, &vnIDs, &vsValues, nRepeatBranchID, pnDuplicateID, false, NULL, &strError, dwCntrl);
	///------ End SPECIAL_ATTRIBUTES_SHOULD_BE_CORRECTLY_UPDATED_WHEN_USE_OLD_THEME_AND_OP
	///------ End NEW_ADDED_AUTO_FOR_XF_VARIABLE_FAILS_TO_COMPATIBLE_WITH_OLD_THEME
	
	if( !strError.IsEmpty() )
	{
		strError.WriteLine(WRITE_COMPILER_OUTPUT);
	}
	return nNumIds;
	///End ADD_REPEAT_ID_COMBINE_ERROR_OUT								
}

/**
		save the id-value pair into file
	Parameters:
		lpcszFilename = full file name to store data pairs
		vnIDs = vector of IDs.
		vsValues = vector of string values, must be the same size of vnIDs.
	Returns:
		true if succeed
 */
/// TD 5-4-07 QA80-9724 THEME_TREE_WITH_LABELS_FOR_READABILITY
//bool tree_save_values_with_ids(LPCSTR lpcszFullFilename, const vector<int> vnIDs, const vector<string>& vsValues, LPCSTR lpcszTreeNodeComment )
bool tree_save_values_with_ids(LPCSTR lpcszFullFilename, const vector<int> vnIDs, const vector<string>& vsValues, const vector<string>& vsLabels, LPCSTR lpcszTreeNodeComment )
/// end THEME_TREE_WITH_LABELS_FOR_READABILITY
{
	/// TD 4-19-06 VC_FUNCTIONS_TO_LAUNCH_XFN_GETN
	if(NULL == vsLabels)   /// TD 5-4-07 QA80-9724 THEME_TREE_WITH_LABELS_FOR_READABILITY
		return  octree_tree_save_values_with_ids(lpcszFullFilename, &vnIDs, &vsValues, lpcszTreeNodeComment);
	return 	octree_tree_save_values_with_ids(lpcszFullFilename, &vnIDs, &vsValues, lpcszTreeNodeComment, &vsLabels);  /// TD 5-4-07 QA80-9724 THEME_TREE_WITH_LABELS_FOR_READABILITY
	/// end VC_FUNCTIONS_TO_LAUNCH_XFN_GETN
	//chech input
	string strFileName = lpcszFullFilename;
	if( strFileName.IsEmpty() )
		return false;
	
	if( 0 == vnIDs.GetSize() || 0 == vsValues.GetSize() )
		return false;
	
	if( vnIDs.GetSize() != vsValues.GetSize() )
		return false;
	
	// Construct a tree.
	int nIndex;
	Tree trIDValuePair;
	
	//------ Folger 03/05/08 QA80-11192 CENTRALIZE_THEME_TREE_SETTING_KNOWLEDGE
	//trIDValuePair = trIDValuePair.AddTextNode( "Settings", "Settings", 0 );
	trIDValuePair = trIDValuePair.AddTextNode( THEME_TREE_SETTINGS, THEME_TREE_SETTINGS, 0 );
	//------
	
	for( nIndex = 0; nIndex < vnIDs.GetSize(); nIndex++ )
	{
		string strTag;
		strTag.Format( "node%d", vnIDs[nIndex] );
		trIDValuePair.AddTextNode( vsValues[nIndex], strTag, vnIDs[nIndex] );
	}
	
	if(lpcszTreeNodeComment != NULL)
		trIDValuePair.SetAttribute( STR_COMMENT_ATTRIB ,lpcszTreeNodeComment);
	
	bool bRet = trIDValuePair.Save( lpcszFullFilename );
	
	return bRet;
}

/**
		read the id-value pair from file
	Parameters:
		lpcszFullFilename = full file name to store data pairs
		vnIDs = vector of IDs.
		vsValues = vector of string values, must be the same size of vnIDs.
	Returns:
		true if succeed
 */
bool tree_read_values_with_ids(LPCSTR lpcszFullFilename, vector<int>& vnIDs, vector<string>& vsValues , string &strComment)
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 7/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	//chech input
	if(NULL  == lpcszFullFilename )
		return false;
	
	vnIDs.RemoveAll();
	vsValues.RemoveAll();
	
	//Transfer tagName & strVal to vnIDs & vsValues
	Tree trIDValuePair;			
	TreeNode trnValue;
	
	if( !trIDValuePair.Load( lpcszFullFilename ) )
		return false;
	
	foreach( trnValue in trIDValuePair.Children )
	{
		string strID = trnValue.tagName;
		strID.TrimLeft( "node" );
		vnIDs.Add( atoi(strID) );
		vsValues.Add( trnValue.strVal );
	}
	
	string strTreeNodeComment;
	if(trIDValuePair.GetAttribute(STR_COMMENT_ATTRIB, strTreeNodeComment) && strComment != NULL)
		strComment = strTreeNodeComment;
	
	return true;
#else //_TREE_UTILS_FROM_HONG_DLL
	if(strComment == NULL)
		return octree_tree_read_values_with_ids(lpcszFullFilename, &vnIDs, &vsValues);
	return octree_tree_read_values_with_ids(lpcszFullFilename, &vnIDs, &vsValues , &strComment);
#endif //_TREE_UTILS_FROM_HONG_DLL ///Hong 7/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}

//End		ADD_FUNCT_DEAL_IDATTRIB_AND_VALUE
///////////////////////////////////////////////////////////
// page.info and tree 
///////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
////////// Info Variables and TreeNode utilities ////////////
/////////////////////////////////////////////////////////////
#define STR_USER	"User"
#define STR_VARS	"Variables"
static string make_link_var_str(string& strStorage, string& strSection, string& strItem, int nPlotInLayer)
{
	string str;
	if(nPlotInLayer < NPLOT_FOR_WKS)
	{
		if(strStorage.CompareNoCase(STR_USER) == 0 && strSection.CompareNoCase(STR_VARS) == 0)
			str.Format("%%(%d, @W,%s)", nPlotInLayer, strItem);
		else
			str.Format("%%(%d, @W,%s.%s.%s)", nPlotInLayer, strStorage, strSection, strItem);
	}
	else
	{
		if(strStorage.CompareNoCase(STR_USER) == 0 && strSection.CompareNoCase(STR_VARS) == 0)
			str.Format("%%(%%H, @W,%s)", strItem);
		else
			str.Format("%%(%%H, @W,%s.%s.%s)", strStorage, strSection, strItem);
	}		
	return str;
}

/// Hong 05/17/10 ORG-131 MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
static void _tree_add_info_into_section(TreeNode& trList, TreeNode& trSrc, string& strStorage, string& strSection, int nPlotInLayer)
{
	foreach(TreeNode trSrcItem in trSrc.Children)
	{
		if ( trSrcItem.GetNodeCount() )
		{
			TreeNode	trNode = trList.AddNode(trSrcItem.tagName);
			_tree_add_info_into_section(trNode, trSrcItem, strStorage, strSection, nPlotInLayer);
			continue;
		}
		string strItem = trSrcItem.tagName;
		string strStorageItem = strItem;
		///Jasmine 01/18/07 QA70-9273 MODIFICATION_FOR_USER_VAR_DLG
		//STR_DATA_ATTRIB for the old dlg
		//STR_PATH_ATTRIB for cell
		TreeNode tr1;
		tr1 = trList.AddTextNode(trSrcItem.strVal, strItem);
		string strPath;
		tree_get_level(tr1, strPath);
		strPath.Delete(0, strPath.Find('.') + 1);
		/// Kenny 12/22/2009 QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
		//int nID;
		//if(trSrcItem.GetAttribute(STR_ID_ATTRIB, nID) && TRGP_STR == nID)
		int nID = ONODETYPE_INVALID;
		if(trSrcItem.GetAttribute(STR_ID_ATTRIB, nID) && IS_TEXT_NODE_ID(nID) )
		/// End QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
		{
			strStorageItem += "$";
			strPath += "$";
		}
		
		//TreeNode tr1;
		//tr1 = trList.AddTextNode(trSrcItem.strVal, strItem);
		if(nPlotInLayer >= 0)
		{
			tr1.SetAttribute(STR_DATA_ATTRIB, make_link_var_str(strStorage, strSection, strStorageItem, nPlotInLayer));
			tr1.SetAttribute(STR_PATH_ATTRIB, strPath);
			///Kyle 08/13/2009 SET_COLUMN_VALUES_SUPPORT_DEFINE_VARIABLES_IN_BASIC_DATA_TYPE, copy node id to be returned from InsertUserVarEx
			if(nID != ONODETYPE_INVALID)
				tr1.ID = nID;
			///End SET_COLUMN_VALUES_SUPPORT_DEFINE_VARIABLES_IN_BASIC_DATA_TYPE
		}
		///End MODIFICATION_FOR_USER_VAR_DLG
		///Jasmine 09/08/07 HARD_CODE_TO_SET_DATE_DISPLAY_
		if(0 == strItem.CompareNoCase("FILEDATE"))
			tree_set_date_node(tr1);
		///End HARD_CODE_TO_SET_DATE_DISPLAY_
	}
}
/// end MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET

	
//nPlotInLayer >=0 will add Data attribute into node for labtalk substition notation,
static bool tree_info_add_section(TreeNode& trNode, TreeNode& trSrc, string& strStorage, string& strSection, int nPlotInLayer)
{
	string strFolder = strStorage + "." + strSection;
	
	TreeNode trList = trNode.AddNode(strFolder);
	/// Hong 05/17/10 ORG-131 MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
	/*
	foreach(TreeNode trSrcItem in trSrc.Children)
	{
		if(trSrcItem.GetNodeCount())	///Jasmine 03/20/07 AVOID_BAD_STRUCTURE_ASCII_STORAGE, skip branch node
			continue;
		string strItem = trSrcItem.tagName;
		string strStorageItem = strItem;
		///Jasmine 01/18/07 QA70-9273 MODIFICATION_FOR_USER_VAR_DLG
		//STR_DATA_ATTRIB for the old dlg
		//STR_PATH_ATTRIB for cell
		TreeNode tr1;
		tr1 = trList.AddTextNode(trSrcItem.strVal, strItem);
		string strPath;
		tree_get_level(tr1, strPath);
		strPath.Delete(0, strPath.Find('.') + 1);
		/// Kenny 12/22/2009 QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
		//int nID;
		//if(trSrcItem.GetAttribute(STR_ID_ATTRIB, nID) && TRGP_STR == nID)
		int nID = ONODETYPE_INVALID;
		if(trSrcItem.GetAttribute(STR_ID_ATTRIB, nID) && IS_TEXT_NODE_ID(nID) )
		/// End QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
		{
			strStorageItem += "$";
			strPath += "$";
		}
		
		//TreeNode tr1;
		//tr1 = trList.AddTextNode(trSrcItem.strVal, strItem);
		if(nPlotInLayer >= 0)
		{
			tr1.SetAttribute(STR_DATA_ATTRIB, make_link_var_str(strStorage, strSection, strStorageItem, nPlotInLayer));
			tr1.SetAttribute(STR_PATH_ATTRIB, strPath);
			///Kyle 08/13/2009 SET_COLUMN_VALUES_SUPPORT_DEFINE_VARIABLES_IN_BASIC_DATA_TYPE, copy node id to be returned from InsertUserVarEx
			if(nID != ONODETYPE_INVALID)
				tr1.ID = nID;
			///End SET_COLUMN_VALUES_SUPPORT_DEFINE_VARIABLES_IN_BASIC_DATA_TYPE
		}
		///End MODIFICATION_FOR_USER_VAR_DLG
		///Jasmine 09/08/07 HARD_CODE_TO_SET_DATE_DISPLAY_
		if(0 == strItem.CompareNoCase("FILEDATE"))
			tree_set_date_node(tr1);
		///End HARD_CODE_TO_SET_DATE_DISPLAY_
	}
	*/
	_tree_add_info_into_section(trList, trSrc, strStorage, strSection, nPlotInLayer);
	/// end MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
	return true;
}

//bool tree_add_info(TreeNode& trNode, const OriginObject& orgObj, const string& strName, const string& strLabel, int nPlotInLayer) // = -1
bool tree_add_info(TreeNode& trNode, const OriginObject& orgObj, LPCSTR lpcszObjName, LPCSTR lpcszObjLabel, int nObjIndex ) // = NULL, = NULL, = -1
{
	//--- Iris 01/14/2009 oc auto test code fund invalid trNode cause runtime error, to fix.
	if( !trNode )
		return false;
	//--- 
	if(!orgObj)
		return false;
	TreeNode trPage;
	string strName = lpcszObjName;
	if(!strName.IsEmpty())
	{
		string strLabel = lpcszObjLabel;
		
		trPage = trNode.AddNode(strName);
		trPage.SetAttribute(STR_LABEL_ATTRIB, strLabel);
	}
	else
		trPage = trNode;
	
	///Jasmine 01/19/07 QA70-9287 GET_INI_STORAGE_ONLY
	vector<string> vsStoreNames;
	if(orgObj.GetStorageNames(vsStoreNames, STORAGE_TYPE_INI))
	{
		for(int ii = 0; ii < vsStoreNames.GetSize(); ii++)
		{
			/*don't get binary storage here
			/// EJP 2005-04-04 v8.0214 QA70-6816 SHOW_IMPORT_FILE_INFO_IN_USER_VAR_DLG
			if( 0 == vsStoreNames[ii].CompareNoCase("Files") )
			{
				Page pg(strName);
				if( pg )
					tree_add_import_file_info(trPage, pg, nObjIndex);
				continue;
			}
			/// end SHOW_IMPORT_FILE_INFO_IN_USER_VAR_DLG
			*/
	///End GET_INI_STORAGE_ONLY
			storage st;
			st = orgObj.GetStorage(vsStoreNames[ii]);
			vector<string> vsSectionNames;
			if(st.GetSectionNames(vsSectionNames))
			{
				for(int jj = 0; jj < vsSectionNames.GetSize(); jj++)
				{
					Tree trTemp;
					if(st.GetSection(vsSectionNames[jj], trTemp))
						tree_info_add_section(trPage, trTemp, vsStoreNames[ii], vsSectionNames[jj], nObjIndex);
				}
			}
		}
		return trPage.GetNodeCount()> 0? true : false;
	}
	return false;
}

////////////////////////////////////////////////////////////////////////
/////////// Saving and Loading of settings /////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
#define	STR_DEFAULT_SETTINGS_FILE_EXTENSION			"xml"
static string get_default_settings_folder_name(int nCategory)
{
	// must match enum {SETTINGS_MAIN, SETTINGS_GUI};
	vector<string> vsCategorys = {"", "GUI"};
	string strSubFolder;
	if(nCategory >= 0 && nCategory < vsCategorys.GetSize())
		strSubFolder = vsCategorys[nCategory];
	
	string strFolder = "DefaultSettings";
	if(!strSubFolder.IsEmpty())
		strFolder += "\\" + strSubFolder;
	
	return strFolder;  
}

void	save_default_settings(TreeNode& tr, LPCSTR lpcszClassName, int nCategory)
{
	string	strPath = GetAppPath() + get_default_settings_folder_name(nCategory);
	if( CheckMakePath(strPath) )
	{
		ASSERT(strPath.IsPath());
		string strFileName;
		strFileName.Format("%s\\%s.%s", strPath, lpcszClassName, STR_DEFAULT_SETTINGS_FILE_EXTENSION);
		Tree trTemp;
		trTemp = tr;
		tree_remove_attribute(trTemp, STR_COMBO_ATTRIB);//CPY 5/31/03, this will make the xml file smaller and easier to read
		trTemp.Save(strFileName);
	}
}

/////////// dialog check boxes settings are stored in registry
static 	DWORD byte_array_to_bits(const vector<byte>& vn)
{
	DWORD dwTemp = 0;
	for(int ii = 0; ii < vn.GetSize(); ii++)
	{
		if(vn[ii] > 0)
			dwTemp += 1 << ii;
	}
	return dwTemp;
}
static void bits_to_byte_array(DWORD dw, vector<byte>& vn)
{
	vn.SetSize(0);
	DWORD dwTest = 1;
	for(int ii = 0; ii < 32; ii++)
	{
		if(dw & dwTest)
			vn.Add(1);
		else
			vn.Add(0);
		
		dwTest<<=1;
	}
}
#define STR_REG_DIALOGS "\\Dialogs\\"
#define STR_REG_CHECKBOX_KEY "CheckBoxes"

bool dlg_save_to_registry(LPCSTR lpcszSecName, LPCSTR lpcszValName, DWORD dwVal)
{
	Registry reg(HKEY_CURRENT_USER);
	string strKey = GetRegKey() + STR_REG_DIALOGS;
	strKey+= lpcszSecName;

	reg.SetValue(strKey, lpcszValName, dwVal);
	return true;
}

/// EJP 2007-05-31 v8.0631 LOAD_REG_VALUE_NEED_DEFAULT
///bool dlg_load_registry(LPCSTR lpcszSecName, LPCSTR lpcszValName, DWORD& dwVal)
bool dlg_load_registry(LPCSTR lpcszSecName, LPCSTR lpcszValName, DWORD& dwVal, DWORD dwDefault) // = 0
/// end LOAD_REG_VALUE_NEED_DEFAULT
{
	Registry reg(HKEY_CURRENT_USER);
	string strKey = GetRegKey() + STR_REG_DIALOGS;
	strKey+= lpcszSecName;
	if(reg.GetValue(strKey, lpcszValName, dwVal))
		return true;

	/// EJP 2007-05-31 v8.0631 LOAD_REG_VALUE_NEED_DEFAULT
	///dwVal = 0;
	dwVal = dwDefault;
	/// end LOAD_REG_VALUE_NEED_DEFAULT
	return false;
}
///Frank 11/10/04 v8.0160 QA70-6086   REMEMBER_LAST_USE_FUNCTION
bool dlg_save_to_registry(LPCSTR lpcszSecName, LPCSTR lpcszValName, LPCSTR lpcstrVal)
{
	Registry reg(HKEY_CURRENT_USER);
	string strKey = GetRegKey() + STR_REG_DIALOGS;
	strKey+= lpcszSecName;

	reg.SetValue(strKey, lpcszValName, lpcstrVal);
	return true;
}

/// EJP 2007-05-31 v8.0631 LOAD_REG_VALUE_NEED_DEFAULT
///bool dlg_load_registry(LPCSTR lpcszSecName, LPCSTR lpcszValName, string& strVal)
bool dlg_load_registry(LPCSTR lpcszSecName, LPCSTR lpcszValName, string& strVal, LPCSTR lpcszDefault) // = NULL
/// end LOAD_REG_VALUE_NEED_DEFAULT
{
	Registry reg(HKEY_CURRENT_USER);
	string strKey = GetRegKey() + STR_REG_DIALOGS;
	strKey+= lpcszSecName;
	if(reg.GetValue(strKey, lpcszValName, strVal))
		return true;

	/// EJP 2007-05-31 v8.0631 LOAD_REG_VALUE_NEED_DEFAULT
	if( lpcszDefault )
		strVal = lpcszDefault;
	/// end LOAD_REG_VALUE_NEED_DEFAULT
	return false;
}
///End   REMEMBER_LAST_USE_FUNCTION
//save the given array of boolean values into a single DWORD in the registry
bool save_default_checkboxes(LPCSTR lpcszDlgName, const vector<byte>& vbValues, LPCSTR lpcszValName) // = NULL
{
	string strValName = lpcszValName;
	if(strValName.IsEmpty())
		strValName = STR_REG_CHECKBOX_KEY;
	
	return dlg_save_to_registry(lpcszDlgName, strValName, byte_array_to_bits(vbValues));
}
//retrive a array of boolean values saved by save_default_checkboxes in the registry
bool load_default_checkboxes(LPCSTR lpcszDlgName, vector<byte>& vbValues, LPCSTR lpcszValName) // = NULL
{
	string strValName = lpcszValName;
	if(strValName.IsEmpty())
		strValName = STR_REG_CHECKBOX_KEY;
	
	DWORD dwVal = 0;
	if(dlg_load_registry(lpcszDlgName, strValName, dwVal))
	{
		bits_to_byte_array(dwVal, vbValues);
		return true;
	}
	return false;
}

/// EJP 06-07-2004 v8.0853 QA70-6472 FILE_INFO_IN_PAGE
/// AW 10/03/06	QA80-9015 THEME_IN_XF
//bool tree_get_binary_storage(TreeNode& trn, Page& pgSource, LPCSTR lpcszName)
bool tree_get_binary_storage(TreeNode& trn, OriginObject& ObjSource, LPCSTR lpcszName)
/// END THEME_IN_XF

{
	/// ML 2/17/2006 INTERACTIVE_CONTROL_MENUS
	/*
	vector<byte> vb;
	if( pgSource.GetMemory(lpcszName, vb) )
	{
		if( trn.XML.SetBytes(vb) )
			return true;
	}
	return false;
	*/
	
	/// AW 10/03/06	QA80-9015 THEME_IN_XF
	//return pgSource.GetBinaryStorage(lpcszName, trn);
	return ObjSource.GetBinaryStorage(lpcszName, trn);
	/// END THEME_IN_XF

	/// end INTERACTIVE_CONTROL_MENUS
}

/// AW 10/03/06	QA80-9015 THEME_IN_XF
//bool tree_put_binary_storage(TreeNode& trn, Page& pgTarget, LPCSTR lpcszName)
bool tree_put_binary_storage(TreeNode& trn, OriginObject& ObjTarget, LPCSTR lpcszName)
/// END THEME_IN_XF
{
	/// ML 2/17/2006 INTERACTIVE_CONTROL_MENUS
	/*
	if(!trn)	///DG 3/7/08
		return false;
	vector<byte> vb;
	if( trn.XML.GetBytes(vb) )
	{
		if( pgTarget.SetMemory(lpcszName, vb) )
			return true;
	}
	return false;
	*/
	/// AW 10/03/06	QA80-9015 THEME_IN_XF
	//return pgTarget.PutBinaryStorage(lpcszName, trn);
	return ObjTarget.PutBinaryStorage(lpcszName, trn);
	/// END THEME_IN_XF

	
	/// end INTERACTIVE_CONTROL_MENUS
}
/// end FILE_INFO_IN_PAGE



//----------- CPY 6/15/04 QA70-6294 OC_DATA_PLOT_SEL_INFO_CONSOLIDATION
static int tree_get_collection_indices(const TreeNode& tr, LPCSTR lpcszPrefix, vector<uint>& vn)
{
   TreeNodeCollection tnc(tr, lpcszPrefix);
   
	char szNodePrefix[MAXLINE];
	int nn;
	string str;
	foreach(TreeNode tn in tnc)
	{
		str = tn.tagName;
		nn = string_to_prefix_end_number(szNodePrefix, str);
		if(lstrlen(szNodePrefix) == str.GetLength()) // not broken up
			return -1;
		vn.Add(nn);
	}
	return vn.GetSize();
}
		
		
//	scan the current tree node for all child notes and find the next child node tag name
//	The first child is used to get the enumeration prefix. If the first child is not in the form of enumerated node, we return -1
int tree_get_next_enum_tag_name(const TreeNode& tr, string& strTag)
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 7/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	if(!tr)
		return -1;
	TreeNode trn = tr.FirstNode;
	if(!trn)
		return -1;
	
	string str = trn.tagName;
	char szNodePrefix[MAXLINE];
	int nn = string_to_prefix_end_number(szNodePrefix, str);
	if(lstrlen(szNodePrefix) == str.GetLength()) // not broken up
		return -1;
	
	vector<uint> vn;
	if(tree_get_collection_indices(tr, szNodePrefix, vn) < 0)
		return -1;
	
	vn.Sort();
	// we assume index 1,2,3,4
	for(int ii = 0; ii < vn.GetSize(); ii++)
	{
		if(vn[ii] != ii+1)
			break;
	}
	ii++;
	if(strTag)
	{
		strTag = szNodePrefix;
		strTag += ii;
	}
	return ii;
#else //_TREE_UTILS_FROM_HONG_DLL 
	return octree_get_next_enum_tag_name( &tr, &strTag);
#endif ///_TREE_UTILS_FROM_HONG_DLL ///Hong 7/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}

///Danice 9/24/04 ADD_BRANCH_CONTROL
//----- CPY 6/16/04 QA70-6294 OC_INPUT_DATA_NODE_CLEANUP
//	set the attributes to all nodes in the given tree
//void tree_set_attribute_to_all_nodes(TreeNode& tr, LPCSTR lpcszAttrib, LPCSTR lpcszAttribVal, bool b1stLevelChildrenOnly) //=false
void tree_set_attribute_to_all_nodes(TreeNode& tr, LPCSTR lpcszAttrib, LPCSTR lpcszAttribVal, bool b1stLevelChildrenOnly, bool bBranchOnly) //=false, =false
{
#ifndef _TREE_UTILS_FROM_HONG_DLL// _TREE_UTILS_FROM_DLL ///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	bool bBranchNode = tr.GetNodeCount() > 0 ? true : false;
	//if(!b1stLevelChildrenOnly)
	if(!b1stLevelChildrenOnly && (!bBranchOnly || bBranchNode))	///Danice ADD_BRANCH_CONTROL
		tr.SetAttribute(lpcszAttrib, lpcszAttribVal);
	
	//if(tr.GetNodeCount() > 0) // branch node
	if(bBranchNode)
	{
		foreach(TreeNode cNode in tr.Children)
		{
			if(b1stLevelChildrenOnly)
			{
				if(!bBranchOnly || cNode.GetNodeCount() > 0 )	///Danice ADD_BRANCH_CONTROL
					cNode.SetAttribute(lpcszAttrib, lpcszAttribVal);
			}
			else
				tree_set_attribute_to_all_nodes(cNode, lpcszAttrib, lpcszAttribVal, b1stLevelChildrenOnly, bBranchOnly);
		}
	}
#else// _TREE_UTILS_FROM_HONG_DLL	
	octree_set_attribute_to_all_nodes(&tr, lpcszAttrib, lpcszAttribVal, b1stLevelChildrenOnly, bBranchOnly);
#endif// _TREE_UTILS_FROM_HONG_DLL	///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}
//-----


//------------ end OC_DATA_PLOT_SEL_INFO_CONSOLIDATION
///end ADD_BRANCH_CONTROL


//------- CPY 8/30/04 QA70-6667 RESULT_SHEET_QUERY
//	append tr2 into tr1 with all children and all attributes
int tree_append_children(TreeNode& tr1, const TreeNode& tr2, LPCSTR lpcszPrefix)
{
#ifndef _TREE_UTILS_FROM_HONG_DLL// _TREE_UTILS_FROM_DLL ///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	TreeNodeCollection tnc1(tr1, lpcszPrefix);
	int nMaxID = -1;
	foreach(TreeNode cn1 in tnc1)
	{
		if(cn1.ID > nMaxID)
			nMaxID = cn1.ID;
	}
	nMaxID++; // = 0 if collection is empty
	
	TreeNode trn;
	TreeNodeCollection tnc2(tr2, lpcszPrefix);
	foreach(TreeNode cNode in tnc2)
	{
		trn = cNode.Clone();
		if(nMaxID > 0)
			trn.ID = nMaxID++;
		tr1.AddNode(trn);
	}
	return nMaxID;
#else // _TREE_UTILS_FROM_HONG_DLL	
	return octree_append_children(&tr1, &tr2, lpcszPrefix);
#endif // _TREE_UTILS_FROM_HONG_DLL	///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}
///Frank 1/21/05 MOVE_GET_LABEL_FUNCTION_FROM_STATIC
//static string get_node_label(const TreeNode& tr, bool bCheckUseLabel)
string get_node_label(const TreeNode& tr, bool bGetLabelFirst)
///End MOVE_GET_LABEL_FUNCTION_FROM_STATIC
{
#ifndef _TREE_UTILS_FROM_HONG_DLL// _TREE_UTILS_FROM_DLL ///Hong 26/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	if(!tr)
		return "";
	
	if(!bGetLabelFirst)
		return tr.tagName;
	
	string strLabel;
	if(tr.GetAttribute(STR_LABEL_ATTRIB, strLabel))
		return strLabel;
	
	return tr.tagName;
#else// _TREE_UTILS_FROM_HONG_DLL
	return octree_get_node_label(&tr, bGetLabelFirst);
#endif// _TREE_UTILS_FROM_HONG_DLL	///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}

///Kevin 10/09/05 MERGE_TWO_DUMP_TREE_TO_STR_FUNCTION 
/*
static int dump_tree_to_str(int nLevel, const TreeNode& tr, string& str, bool bSkipHidden, bool bSimpleTypesOnly, bool bCheckUseLabel)
{
	if(!tr)
		return 0;
	if(bSkipHidden && tr.Show == 0)
		return 0;

	for(int ii = 0; ii < nLevel; ii++)
		str += "  ";

	int nCount = 0;
	double	dAttribute;
	if(tr.GetNodeCount() > 0) // branch node
	{
		if(!bSkipHidden || tr.Show != 0)
		{
			///Frank 9/29/05 v8.0311 CHANGE_ENTER_TO_ENTER_WITH_RETURN_CHAR
			//str += get_node_label(tr, bCheckUseLabel) +"\n";
			str += get_node_label(tr, bCheckUseLabel) +"\r\n";
			///End CHANGE_ENTER_TO_ENTER_WITH_RETURN_CHAR
			foreach(TreeNode cNode in tr.Children)
					nCount += dump_tree_to_str(nLevel+1, cNode, str, bSkipHidden, bSimpleTypesOnly, bCheckUseLabel);
		}
	}
	else // leaf node
	{
		if(!bSkipHidden || tr.Show != 0)
		{
			string strTemp;
			strTemp.Format("%s = %s\r\n", get_node_label(tr, bCheckUseLabel), tr.Text);
			str += strTemp;
			nCount++
		}
		else
			///Frank 9/29/05 v8.0311 CHANGE_ENTER_TO_ENTER_WITH_RETURN_CHAR
			//str += "\n";
			str += "\r\n";
			///End CHANGE_ENTER_TO_ENTER_WITH_RETURN_CHAR
	}

	return nCount;
}
*/
///End MERGE_TWO_DUMP_TREE_TO_STR_FUNCTION
	
//	output contents of tree to a string
// tr.Show is checked and skip if bSkipHidden
//-------

///Kevin 10/10/05 MERGE_TREE_TO_STR_FUNCTION
/*
int tree_to_str(const TreeNode& tr, string& str, bool bSkipHidden, bool bSimpleTypesOnly, bool bCheckUseLabel)
{
	str.Empty(); // CPY 10/7/05 OUTPUT_LOG_SAW_DUPILCATE_RESULTS
	///Kevin 10/09/05 MERGE_TWO_DUMP_TREE_TO_STR_FUNCTION
	//return dump_tree_to_str(0, tr, str, bSkipHidden,  bSimpleTypesOnly, bCheckUseLabel);
	return dump_tree_to_str(0, tr, str, NULL, bSkipHidden,  bSimpleTypesOnly, bCheckUseLabel);
	///End MERGE_TWO_DUMP_TREE_TO_STR_FUNCTION
}
*/
///End MERGE_TREE_TO_STR_FUNCTION

/// Iris 5/22/06 FOOTNODE_WORK_IN_NOTE_WIN
bool tree_is_foot_node(const TreeNode &trN)
{
	return is_in_ids_range(trN, IDE_FOOTNOTE_BEGIN, IDE_FOOTNOTE_END);
}

static string	_tree_check_get_footnode_string(const TreeNode &trNode, int nXoffset)
{
	string str;
	foreach(TreeNode trN in trNode.Children)
	{
		if( tree_is_foot_node(trN) ) // to check is footnode or not
		{
			string	strXoffset;
			for(int nn=0; nn<nXoffset; nn++)
			{
				strXoffset += " ";
			}
			
			string	strFoot = trN.strVal;
			vector<string> vsFoots;
			strFoot.GetTokens(vsFoots, '\n');
			for(int nLine = 0; nLine < vsFoots.GetSize(); nLine++)
			{
				str += strXoffset + vsFoots[nLine] + "\n";
			}
		}
	}
	return str;	
}
///End FOOTNODE_WORK_IN_NOTE_WIN


///Frank 9/15/04 QA70-6903	ADD_OUTPUT_TREE_TO_TABLE_STRING	
//string	tree_one_treetable_to_str(TreeNode &trNode,vector<int> &vnDisplayFormat,bool bSkipHidden,bool bTranspose, int nXoffset ,int nExtraSpace , bool bLev1AsCols , string strDoubleValueFormat )
string	tree_one_treetable_to_str(TreeNode &trNode,vector<int> &vnDisplayFormat,bool bSkipHidden,bool bTranspose, int nXoffset ,int nExtraSpace , bool bLev1AsCols , string strDoubleValueFormat )
{
	if(!trNode)
		return "";
	///Frank 10/27/04 v8.0156  MATRIX_OR_VECTOR_TREENODE_OUTPUT_STRING
	int nDataType = TREENODE_DATA_TYPE_NORMAL; 
	nDataType = check_tree_table_type(trNode);///Frank 11/23/04 v8.0167 			CHECK_TREE_TABLE_TYPE_VISIABLE	
	///Remove STR_ATTRIB_DATATYPE, just judge the first node type id.
	/*
	if(trNode.GetAttribute(STR_ATTRIB_DATATYPE,nDataType))
		if(nDataType == 1 )
			nDataType = TREENODE_DATA_TYPE_VECTOR;
		else
			if(nDataType == 2)
				nDataType =	TREENODE_DATA_TYPE_MATRIX;
	*/
	//TreeTable	trTable(trNode, vnDisplayFormat,bSkipHidden, bTranspose, bLev1AsCols, strDoubleValueFormat);
	TreeTable	trTable(trNode, vnDisplayFormat,bSkipHidden, bTranspose, bLev1AsCols, strDoubleValueFormat, nDataType);
	///End  MATRIX_OR_VECTOR_TREENODE_OUTPUT_STRING
	
	/// Iris 5/22/06 FOOTNODE_WORK_IN_NOTE_WIN
	//return trTable.GetTable(nExtraSpace , nXoffset) + "\n" ;
	string 	str = trTable.GetTable(nExtraSpace , nXoffset);
	str += _tree_check_get_footnode_string(trNode, nXoffset) + "\n";	
	return str;
	///End FOOTNODE_WORK_IN_NOTE_WIN
	
}

///Frank 11/23/04 v8.0167 			CHECK_TREE_TABLE_TYPE_VISIABLE	
int check_tree_table_type(TreeNode &trTable)
{
	TreeNode trNode ;
	
	if(trTable.GetNodeCount()> 0)
	{
		trNode = trTable.FirstNode;
		return check_tree_table_type(trNode);
	}
	else
		trNode = trTable;
		
	int nTypeID = trNode.TypeID;
	
	///Frank 11/23/04 #7013: Special types are the only types which has this ID, 
	///this ID only is used internally for non simple types. 
	if(TNVAL_TYPE_INVALID < nTypeID && nTypeID< TNVAL_TYPE_POINTER || nTypeID < 0)
		return TREENODE_DATA_TYPE_NORMAL;

	if(TNVAL_TYPE_BIT_VECTOR <= nTypeID && nTypeID < TNVAL_TYPE_VARIANT_VECTOR )
		return TREENODE_DATA_TYPE_VECTOR;
	
	if(	TNVAL_TYPE_BIT_MATRIX <= nTypeID && nTypeID < TNVAL_TYPE_VARIANT_MATRIX )
		return TREENODE_DATA_TYPE_MATRIX;
	
	return -1;
}

///Iris 01/03/05 SET_GRAPH_HIDDEN_FOR_STRDUMP
/*
///Frank 12/27/04 TREE_TABEL_SHOW_MULTI_LAYER_TABEL
///User tagname to judge the treenode is graph or not, if yes, will not out put as string,
///use this method is because 1: If the treenode without picture, can't get TypeID, the TypeID will exist just when treeNode as pictureholder.
static bool is_graph_node(TreeNode& trNode)
{
	return  -1 == trNode.tagName.Find("Graph")? false : true;
}
///End TREE_TABEL_SHOW_MULTI_LAYER_TABEL
///If return false mean unable disaply table as text.
bool can_show_tree_table(TreeNode &trTable)
{
	TreeNode trNode ;
	if(trTable.GetNodeCount()> 0)
	{
		trNode = trTable.FirstNode;
		return can_show_tree_table(trNode);
	}
	else
		trNode = trTable;
	
	int nTypeID = trNode.TypeID;
	///Just picture can not show as text.
	if(	TNVAL_TYPE_PICTURE != nTypeID )
		return true;
	
   return false;
}
///End		CHECK_TREE_TABLE_TYPE_VISIABLE	
*/
///end SET_GRAPH_HIDDEN_FOR_STRDUMP

/// Iris 11/14/05 ADD_AUX_DISPLAY_INFO
/////Frank 10/17/06 ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT
////static int dump_tree_to_str(int nLevel, const TreeNode& tr, string& str, vector<int> &vnTableFormat, bool bSkipHidden, bool bSimpleTypesOnly, bool bCheckUseLabel, bool bIncludeParentNamePrefix)
//static int dump_tree_to_str(int nLevel, const TreeNode& tr, string& str, vector<int> &vnTableFormat, bool bSkipHidden, bool bSimpleTypesOnly, bool bCheckUseLabel, bool bIncludeParentNamePrefix,string strDoubleValueFormat )
static int dump_tree_to_str(int nLevel, const TreeNode& tr, string& str, vector<int> &vnTableFormat, bool bSkipHidden, bool bSimpleTypesOnly, bool bCheckUseLabel, bool bIncludeParentNamePrefix, string strDoubleValueFormat, bool bIncludeAuxDisplayInfo)
/////End ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT
///End ADD_AUX_DISPLAY_INFO
{
	if(!tr)
		return 0;
	if(bSkipHidden && tr.Show == 0)
		return 0;

	str_pad_char(str, lstrlen(str) + nLevel*2, DISPLAY_RIGHT);
	
	int nCount = 0;
	double	dAttribute;
	string 	strTitle;
	int nTableType;
	double dAttributeTemp;
	if(tr.GetNodeCount() > 0) // branch node
	{
		if(!bSkipHidden || tr.Show != 0)
		{
			nLevel++;
			///Frank 10/10/04 QA70-6903	SUPPORT_MULTI_LEVEL_NODE_OUTPUT
			//str += get_node_label(tr, bCheckUseLabel) + "\n";
		
		///Kevin 10/11/05 CONVERT_TO_OUTPUT_TREE	
			///----Frank 11/21/05 HIDE_NODE_NAME_OUTPUT_TO_STR
			//if( !bIncludeParentNamePrefix )
			int nIO;
			if( !bIncludeParentNamePrefix && !tr.GetAttribute(STR_HIDE_NODE_NAME_ATTRIB, nIO))
			///----End HIDE_NODE_NAME_OUTPUT_TO_STR
		///End CONVERT_TO_OUTPUT_TREE	
			{
				strTitle = get_node_label(tr, bCheckUseLabel);
				strTitle = str_pad_char(strTitle, lstrlen(strTitle) + (nLevel-1)*2,DISPLAY_RIGHT);
				
				///End	SUPPORT_MULTI_LEVEL_NODE_OUTPUT
				///-----Frank 11/18/05 ADD_EQUAL_IF_IO_NODE_IN
				string strTemp;
				if(tr.GetAttribute(STR_XF_VAR_IO_ATTRIB, strTemp))
					strTitle += " = ";
				///-----End ADD_EQUAL_IF_IO_NODE_IN
				
				str += strTitle + "\n";
			}
			foreach(TreeNode cNode in tr.Children)
				///Frank 11/23/04 v8.0167 			CHECK_TREE_TABLE_TYPE_VISIABLE	
				//if(cNode.GetAttribute(TREE_Table, dAttribute) )//&&( (uint)dAttribute  & GETNBRANCH_TABLE ))///Frank 11/11/04 Remove state of compare Branch attribute, 
				//if( can_show_tree_table(cNode))
				//if(!is_graph_node(cNode))  ///Iris 01/03/05 SET_GRAPH_HIDDEN_FOR_STRDUMP
				///End		CHECK_TREE_TABLE_TYPE_VISIABLE	
				//{

				///Kevin 10/09/05 MERGE_TWO_DUMP_TREE_TO_STR_FUNCTION
					///Frank 12/27/04 TREE_TABEL_SHOW_MULTI_LAYER_TABEL
					//if(cNode.GetAttribute(TREE_Table, dAttribute) )//&&( can_show_tree_table(cNode)))
					//if(cNode.GetAttribute(TREE_Table, dAttribute) && ( cNode.FirstNode && !cNode.FirstNode.GetAttribute(TREE_Table, dAttributeTemp) ))//&&( can_show_tree_table(cNode)))
					///End TREE_TABEL_SHOW_MULTI_LAYER_TABEL
					///------Frank 11/14/05 NO_OPERATOR_CONTROL_IN_BROWSER
					//if(cNode.GetAttribute(TREE_Table, dAttribute) && ( cNode.FirstNode && !cNode.FirstNode.GetAttribute(TREE_Table, dAttributeTemp) )
						//&& (NULL != vnTableFormat) )//&&( can_show_tree_table(cNode)))
					if(cNode.GetAttribute(TREE_Table, dAttribute) && ( cNode.FirstNode && !cNode.FirstNode.GetAttribute(TREE_Table, dAttributeTemp) ))
					///-----End NO_OPERATOR_CONTROL_IN_BROWSER
				///End MERGE_TWO_DUMP_TREE_TO_STR_FUNCTION
					{
						if(bSkipHidden && cNode.Show == 0)
							//break;
							continue;////Frank 9/30/04 QA70-6903	MODIF_TREETABLE_TITLE_OUPUT	
						
						bool	bTranspose = true;
						if(GETNBRANCH_TRANSPOSE &  (uint)dAttribute)
							bTranspose = false ;
						string strCNodeLabel = get_node_label(cNode, bCheckUseLabel);
						strCNodeLabel = str_pad_char(strCNodeLabel, lstrlen(strCNodeLabel) + nLevel*2, DISPLAY_RIGHT) ;
					///Kevin 10/10/05 v8.315 CHANGE_ENTER_TO_ENTER_WITH_RETURN_CHAR_MORE	
						///Frank 9/29/05 v8.0311 CHANGE_ENTER_TO_ENTER_WITH_RETURN_CHAR
						//str += strCNodeLabel + "\n"+ tree_to_treetable_str(cNode ,vnTableFormat, bSkipHidden,bTranspose, (nLevel+1)*2 , 2) + "\n";
						//str += strCNodeLabel + "\r\n"+ tree_one_treetable_to_str(cNode ,vnTableFormat, bSkipHidden,bTranspose, (nLevel+1)*2 , 2) + "\n";
						///End CHANGE_ENTER_TO_ENTER_WITH_RETURN_CHAR

						///Frank 10/17/06 ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT
						//str += strCNodeLabel + "\r\n"+ tree_one_treetable_to_str(cNode ,vnTableFormat, bSkipHidden,bTranspose, (nLevel+1)*2 , 2) + "\r\n";
						str += strCNodeLabel + "\n"+ tree_one_treetable_to_str(cNode ,vnTableFormat, bSkipHidden,bTranspose, (nLevel+1)*2 , 2,true, strDoubleValueFormat) + "\n";
						///End ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT
					///End CHANGE_ENTER_TO_ENTER_WITH_RETURN_CHAR_MORE
						nCount += 1;
					}
					else
						/// Iris 11/14/05 ADD_AUX_DISPLAY_INFO
						/////Frank 10/17/06 ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT
						////nCount += dump_tree_to_str(nLevel, cNode, str,vnTableFormat, bSkipHidden, bSimpleTypesOnly, bCheckUseLabel, bIncludeParentNamePrefix);
						//nCount += dump_tree_to_str(nLevel, cNode, str,vnTableFormat, bSkipHidden, bSimpleTypesOnly, bCheckUseLabel, bIncludeParentNamePrefix, strDoubleValueFormat);
						nCount += dump_tree_to_str(nLevel, cNode, str,vnTableFormat, bSkipHidden, bSimpleTypesOnly, bCheckUseLabel, bIncludeParentNamePrefix, strDoubleValueFormat, bIncludeAuxDisplayInfo);
						/////End ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT
						///End ADD_AUX_DISPLAY_INFO
				//}
		}
	}
	else // leaf node
	{
		if(!bSkipHidden || tr.Show != 0)
		{
			string strTemp;
		///Kevin 10/11/05 MODIFY_TREE_LEAF_FORMAT	
			//strTemp.Format("%s = %s\r\n", get_node_label(tr, bCheckUseLabel), tr.Text);

			///Frank 10/17/06 ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT
			/*
			if(bIncludeParentNamePrefix)
				strTemp.Format("%s.%s = %s\r\n", get_node_label(tr.Parent(), bCheckUseLabel), get_node_label(tr, bCheckUseLabel), tr.Text);
			else
				strTemp.Format("%s = %s\r\n", get_node_label(tr, bCheckUseLabel), tr.Text);
			*/
			string strTrValue = tr.Text;
		
		///Kevin 10/28/05 SUPPORT_LINE_UP_IN_ONE_STRING
			//this block of code is used to check whether strTrValue has '\n'or not, and to add spaces in front of it to
			//make the output string line up.

			vector<string>	vsTest;
			strTrValue.GetTokens(vsTest, '\n');
			
			bool 	bIncludeTreeNodeNamePrefix = !tree_is_foot_node(tr); /// Iris 8/15/06 NOT_SHOW_FOOTNOTE_NAME_PREFIX
			
			for(int ii = 1;ii < vsTest.GetSize();ii++)
			{
				/// Iris 8/15/06 NOT_SHOW_FOOTNOTE_NAME_PREFIX
				//int length = get_node_label(tr, bCheckUseLabel).GetLength() + strlen(" = ");
				int length = bIncludeTreeNodeNamePrefix? get_node_label(tr, bCheckUseLabel).GetLength() + strlen(" = ") : 0;
				///end NOT_SHOW_FOOTNOTE_NAME_PREFIX
				vsTest[ii] = str_pad_char(vsTest[ii], lstrlen(vsTest[ii]) + (nLevel) * 2 + length, DISPLAY_RIGHT);
			}
			strTrValue.SetTokens(vsTest, '\n');
		///End	SUPPORT_LINE_UP_IN_ONE_STRING

			if(is_numeric(strTrValue))// && !strDoubleValueFormat.IsEmpty()) //CPY 2/22/06 QA70-4523 TEXT_OUTPUT_CONSISTENT_NUMERIC_DISPLAY, this check does not make sense
			{
				double dTemp = atof(strTrValue);
				strTrValue = ftoa(dTemp,strDoubleValueFormat );
			}
			if(bIncludeTreeNodeNamePrefix)/// Iris 8/15/06 NOT_SHOW_FOOTNOTE_NAME_PREFIX
			{				
				if(bIncludeParentNamePrefix)
					strTemp.Format("%s.%s = %s\n", get_node_label(tr.Parent(), bCheckUseLabel), get_node_label(tr, bCheckUseLabel),strTrValue);
				else
					strTemp.Format("%s = %s\n", get_node_label(tr, bCheckUseLabel), strTrValue);
			}
			/// Iris 8/15/06 NOT_SHOW_FOOTNOTE_NAME_PREFIX
			else
			{
				strTemp.Format("%s\n", strTrValue);
			}	
			///end NOT_SHOW_FOOTNOTE_NAME_PREFIX
			///End ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT

			/// Iris 11/14/05 ADD_AUX_DISPLAY_INFO
			string strValMoreInfo;
			if(bIncludeAuxDisplayInfo && tr.GetAttribute(STR_AUX_DISPLAY_INFO, strValMoreInfo) && !is_numeric(strValMoreInfo) && !strValMoreInfo.IsEmpty() )
			{
				strTemp.TrimRight('\n');
				strTemp += " (" + strValMoreInfo + ")\n";
			}
			///End ADD_AUX_DISPLAY_INFO
			
			strTemp = str_pad_char(strTemp, lstrlen(strTemp) + (nLevel) * 2, DISPLAY_RIGHT);
		///End MODIFY_TREE_LEAF_FORMAT
			str += strTemp;
			nCount++
		}
		else
			str += "\n";
	}

	return nCount;
}
/// Iris 11/14/05 ADD_AUX_DISPLAY_INFO
/////Kevin 10/11/05 CONVERT_TO_OUTPUT_TREE
////int tree_to_str(const TreeNode& tr, string& str, vector<int> &vnDisplayFormat, bool bSkipHidden, bool bSimpleTypesOnly, bool bCheckUseLabel)
/////Frank 10/17/06 ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT
////int tree_to_str(const TreeNode& tr, string& str, vector<int> &vnDisplayFormat, bool bSkipHidden, bool bSimpleTypesOnly, bool bCheckUseLabel, bool bIncludeParentNamePrefix)
//int tree_to_str(const TreeNode& tr, string& str, vector<int> &vnDisplayFormat, bool bSkipHidden, bool bSimpleTypesOnly, bool bCheckUseLabel, bool bIncludeParentNamePrefix, string strDoubleValueFormat)
/// ML 1/13/2006 XVARIABLEBASE_TO_VC
//int tree_to_str(const TreeNode& tr, string& str, vector<int> &vnDisplayFormat, bool bSkipHidden, bool bSimpleTypesOnly, bool bCheckUseLabel, bool bIncludeParentNamePrefix, string strDoubleValueFormat, bool bIncludeAuxDisplayInfo)
/// Hong 09/08/07 v8.0699 MORE_OPTION_TO_DUMP_MAP_INFO_FOR_COMBO_NODE
/*
int tree_to_str(const TreeNode& tr, string& str, vector<int> &vnDisplayFormat, bool bSkipHidden, bool bSimpleTypesOnly, bool bCheckUseLabel, bool bIncludeParentNamePrefix, LPCSTR lpcszDoubleValueFormat, bool bIncludeAuxDisplayInfo)
/// end XVARIABLEBASE_TO_VC
/////End ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT
/////End CONVERT_TO_OUTPUT_TREE
///End ADD_AUX_DISPLAY_INFO
{
///Joseph 11/07/06  BUG_IN_OC_LEVEL_TREE_TO_STR   temp code
#ifndef _TREE_UTILS_FROM_HONG_DLL  ///Hong 7/11/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
///End BUG_IN_OC_LEVEL_TREE_TO_STR
	/// ML 1/13/2006 XVARIABLEBASE_TO_VC
	string		strDoubleValueFormat = lpcszDoubleValueFormat;//lpcszDoubleValueFormat ? lpcszDoubleValueFormat : "*"; CPY 2/22/06 QA70-4523 TEXT_OUTPUT_CONSISTENT_NUMERIC_DISPLAY
	/// end XVARIABLEBASE_TO_VC
	str.Empty();	//Kevin 10/10/05 OUTPUT_LOG_SAW_DUPILCATE_RESULTS
	
	///Frank 01/18/05 v8.0184b SUPPORT_DISPLAY_FORMATS_NULL_NOT_JUSTIFY
*/	/*
	///Frank 10/12/04 v8.0147  MORE_SUPPORT_SUBHEADER_TITLE	
	vector<int> vnDispFormatTemp= { DISPLAY_CENTER, DISPLAY_RIGHT, DISPLAY_RIGHT};
	if(vnDisplayFormat != NULL)
		vnDispFormatTemp = vnDisplayFormat;
	///End  MORE_SUPPORT_SUBHEADER_TITLE	
	return dump_tree_to_str(0, tr, str, vnDispFormatTemp, bSkipHidden, bSimpleTypesOnly, bCheckUseLabel);
	*/
/*	//return dump_tree_to_str(0, tr, str, NULL, bSkipHidden, bSimpleTypesOnly, bCheckUseLabel);
	
	/// Iris 11/14/05 ADD_AUX_DISPLAY_INFO
	/////Frank 10/17/06 ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT
	////return dump_tree_to_str(0, tr, str, vnDisplayFormat, bSkipHidden, bSimpleTypesOnly, bCheckUseLabel, bIncludeParentNamePrefix );
	//return dump_tree_to_str(0, tr, str, vnDisplayFormat, bSkipHidden, bSimpleTypesOnly, bCheckUseLabel, bIncludeParentNamePrefix, strDoubleValueFormat);
	//return dump_tree_to_str(0, tr, str, vnDisplayFormat, bSkipHidden, bSimpleTypesOnly, bCheckUseLabel, bIncludeParentNamePrefix, strDoubleValueFormat, bIncludeAuxDisplayInfo );
	///Frank 11/18/05 SHOULD_HAVE_DISPLAY_FORMAT_WHEN_CONVERT_TREE_TO_TABLE
	vector<int> vnDispFormatTemp= { DISPLAY_CENTER, DISPLAY_RIGHT, DISPLAY_RIGHT};
	if(vnDisplayFormat != NULL)
		vnDispFormatTemp = vnDisplayFormat;
	return dump_tree_to_str(0, tr, str, vnDispFormatTemp, bSkipHidden, bSimpleTypesOnly, bCheckUseLabel, bIncludeParentNamePrefix, strDoubleValueFormat, bIncludeAuxDisplayInfo );
	///End SHOULD_HAVE_DISPLAY_FORMAT_WHEN_CONVERT_TREE_TO_TABLE	
	/////End ADD_DOUBLE_OUTPUR_FORMAT_IN_TREE_OUT
	/////End SUPPORT_DISPLAY_FORMATS_NULL_NOT_JUSTIFY
	///End ADD_AUX_DISPLAY_INFO
///Joseph 11/07/06  BUG_IN_OC_LEVEL_TREE_TO_STR  temp code
#else //_TREE_UTILS_FROM_HONG_DLL
	 return octree_tree_to_str(&tr, &str, &vnDisplayFormat, bSkipHidden, bSimpleTypesOnly, bCheckUseLabel, bIncludeParentNamePrefix, lpcszDoubleValueFormat, bIncludeAuxDisplayInfo);
#endif //_TREE_UTILS_FROM_HONG_DLL  ///Hong 7/11/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
///End BUG_IN_OC_LEVEL_TREE_STR
}
*/
int tree_to_str(const TreeNode& tr, string& str, vector<int> &vnDisplayFormat, DWORD dwCtrl, LPCSTR lpcszDoubleValueFormat) // = TREE2STR_DEFAULT, NULL
{
	/// Hong 12/10/07 v8.0765 FIX_RUNTIME_ERROR_BY_REFER_NULL
	//return octree_tree_to_str(&tr, &str, &vnDisplayFormat, dwCtrl, lpcszDoubleValueFormat);
	vector<int>* pvnDisplayFormat = NULL;
	if ( &vnDisplayFormat != NULL )
		pvnDisplayFormat = &vnDisplayFormat;
	
	return octree_tree_to_str(&tr, &str, pvnDisplayFormat, dwCtrl, lpcszDoubleValueFormat);
	/// end FIX_RUNTIME_ERROR_BY_REFER_NULL
}
/// end MORE_OPTION_TO_DUMP_MAP_INFO_FOR_COMBO_NODE
	
///End	ADD_OUTPUT_TREE_TO_TABLE_STRING	
///---Frank v8.0147	10/14/04			CENTRALIZE_FO_FUNCTION_TO_TREE_UTLIS
//Update NLSF file on user folder
/**
	update specified lines of ini file.
Example:
	StringArray saLines;
	int iError = ReadFileLines(saLines, "C:\\Origin80\\Origin.ini");
Parameters:
	iniFile= The file you want to update
	lpcszSectionName = Name of Section to update
	lpcszKeyName = Name of key to update, if equal to NULL, will remove the section .
	lpcszValue = Value you want to update of the key, if NULL, will delete the key.
Return:
	Returns true for success or false not.  
*/
bool update_ini_line(INIFile &iniFile, LPCSTR lpcszSectionName, LPCSTR lpcszKeyName, LPCSTR lpcszValue)
{
	if( lpcszSectionName == NULL )
	{
		return false
	};
	iniFile.WriteString(lpcszSectionName, lpcszKeyName, lpcszValue);
	return true;
}
/*
void get_ini_keys_and_values(INIFile &iniNLSF,LPCSTR lpcszSection, StringArray &saKeys, StringArray &saValues  )
{
	saKeys.RemoveAll();
	saValues.RemoveAll();
	
	int nKeysCount = iniNLSF.GetKeyNames(saKeys, lpcszSection);
	saValues.SetSize(nKeysCount);
	
	for(int nIndex = 0 ; nIndex < nKeysCount ; nIndex++)
		saValues[nIndex] = iniNLSF.ReadString(lpcszSection, saKeys[nIndex]);
}
*/
///---End			CENTRALIZE_FO_FUNCTION_TO_TREE_UTLIS
///Frank 11/1/04	v8.0157	GET_NUMERICA_VECTOR_OR_MATRIX_FROM_TREENODE	
bool	get_numerica_vector_treenode(TreeNode &tr, vector<double> &vd)
{
	int nTypeId = tr.TypeID;
	switch(nTypeId) 
	{
	case	TNVAL_TYPE_DOUBLE_VECTOR:
		vd = tr.dVals;
		break;
	case	TNVAL_TYPE_FLOAT_VECTOR:
		vd = (vector) tr.fVals;
		break;
	case	TNVAL_TYPE_SHORT_VECTOR:
		vd = (vector) tr.sVals;
		break;
	case	TNVAL_TYPE_INT_VECTOR:
		vd = (vector) tr.nVals;
		break;
	default :
		return false;
	}
	return true;
}
bool get_numerica_matrix_treenode( TreeNode &tr, matrixbase &matNum)
{
	int nTypeId;
	nTypeId = tr.TypeID;
	switch(nTypeId)
	{
	case	TNVAL_TYPE_DOUBLE_MATRIX:
		matNum = tr.dVals2;
		break;
	case	TNVAL_TYPE_FLOAT_MATRIX:
		//matrix<float> matF;
		//matF = tr.fVals2;
		//matNum = matF;
		matNum = tr.fVals2;
		break;
	case	TNVAL_TYPE_INT_MATRIX:
		//matrix<int> matI;
		//matI = tr.nVals2;
		//matNum = matI;
		matNum = tr.nVals2;
		break;
	case	TNVAL_TYPE_SHORT_MATRIX:
		//matrix<short> matS;
		//matS = tr.sVals2;
		//matNum = matS;
		matNum = tr.sVals2;
		break;
	case	TNVAL_TYPE_CHAR_MATRIX:
	default:
		return false;
	}
	return true;
}
///End	GET_NUMERICA_VECTOR_OR_MATRIX_FROM_TREENODE	
///Jasmine 01/17/07 GET_TREE_NODE_PATH
///Danice 11/15/04 QA70-7169 TREE_ROW_SHOW_ALTERNATE_COLORS
int tree_get_level(const TreeNode &trNode, string* pstrPath)
{
	if(!trNode)
		return -1;
	string strPath = trNode.tagName;
	int nLevel=0;
	for(TreeNode trParent=trNode.Parent(); trParent.IsValid(); trParent=trParent.Parent())
	{
		string strTemp;
		strTemp = trParent.tagName;
		strPath = strTemp + "." + strPath;
		nLevel++;
	}
	if(pstrPath)
		*pstrPath = strPath;
	return nLevel;
}
///end
///End GET_TREE_NODE_PATH
///Frank 12/15/04 TREE_GET_NODE_BY_NODEID_OR_DATAID	
TreeNode tree_get_node_by_dataid(TreeNode& tr, int nDataID, bool bRecursive, int nSeacherLevel) // = false, 0
{
#ifndef _TREE_UTILS_FROM_DLL /// SY 03/25/2005 QA70-7543 v8.0212 OCTREE_FIND_NODE_BY_ATTRIBUTE

	bool bGetNodeInSubLevel = false;
	if(nSeacherLevel>0)
		bGetNodeInSubLevel = true;
	foreach(TreeNode cNode in tr.Children)
	{		
		//if(nDataID == cNode.DataID )
		if(nDataID == cNode.DataID && !bGetNodeInSubLevel)
			return cNode;
		//if(bRecursive && cNode.GetNodeCount() > 0) // branch node
		if((bRecursive || bGetNodeInSubLevel) && cNode.GetNodeCount() > 0) // branch node
		{
			//TreeNode trFind = tree_get_node_by_dataid(cNode, nDataID, true, nSeacherLevel-1 );
			TreeNode trFind = tree_get_node_by_dataid(cNode, nDataID, bRecursive, nSeacherLevel-1 );
			if(trFind)
				return trFind;
		}
	}
	TreeNode junk;
	return junk;

/// SY 03/25/2005 QA70-7543 v8.0212 OCTREE_FIND_NODE_BY_ATTRIBUTE
#else // _TREE_UTILS_FROM_DLL
	TreeNode cNode;
	
	octree_find_node(&tr, &cNode, STR_DATAID_ATTRIB, nDataID, bRecursive, nSeacherLevel);
	
	return cNode;

#endif // _TREE_UTILS_FROM_DLL
/// end OCTREE_FIND_NODE_BY_ATTRIBUTE
}

///DSC 8/25/05 TREENODE_FIND_NODE_BY_DATAID
TreeNode tree_find_node_by_dataID(TreeNode tr, int nID, int nIDParent, int nParentRepeatID , int nIDGrandParent, int nGrandParentRepeatID)
{
	/// ML 1/13/2006 XVARIABLEBASE_TO_VC
	/*
	TreeNode cNode;
	
	int nRet = octree_find_node_ex(&tr, &cNode, STR_DATAID_ATTRIB, nID, nIDParent, nParentRepeatID, nIDGrandParent, nGrandParentRepeatID);
	
	///DSC 8/30/05 OCTREE_FIND_NODE_BY_ID_AND_REPEAT_ID_RETURN_VALUE
	// return cNode;
	if(0==nRet)//success
		return cNode;
	else
	{
		TreeNode trNull;
		return trNull;	
	}
	///end OCTREE_FIND_NODE_BY_ID_AND_REPEAT_ID_RETURN_VALUE
	*/
	TreeNode		trRet;
	octree_find_node_by_dataID(&trRet, &tr, nID, nIDParent, nParentRepeatID, nIDGrandParent, nGrandParentRepeatID);
	return trRet;
	/// end XVARIABLEBASE_TO_VC
}
///end TREENODE_FIND_NODE_BY_DATAID

TreeNode tree_get_node_by_nodeid(TreeNode& trSource, int nNodeD, int nSeacherLevel) // , 0
{
#ifndef _TREE_UTILS_FROM_DLL /// SY 03/25/2005 QA70-7543 v8.0212 OCTREE_FIND_NODE_BY_ATTRIBUTE

	foreach(TreeNode cNode in trSource.Children)
	{
		TreeNode	trNode;
		if(cNode.GetNodeCount()>0&& nSeacherLevel>0)
		{
			trNode=tree_get_node_by_nodeid(cNode,nNodeD,nSeacherLevel-1 );
			if(!trNode)
				continue;
			else
				return trNode;
		}
		int nIDCurrent;
		if(cNode.GetAttribute(STR_ID_ATTRIB, nIDCurrent)&& nIDCurrent == nNodeD)
			return cNode;
	}
	
	TreeNode trNull;
	return trNull;

/// SY 03/25/2005 QA70-7543 v8.0212 OCTREE_FIND_NODE_BY_ATTRIBUTE
#else // _TREE_UTILS_FROM_DLL
	TreeNode cNode;
	
	octree_find_node(&trSource, &cNode, STR_ID_ATTRIB, nNodeD, false, nSeacherLevel);
	
	return cNode;

#endif // _TREE_UTILS_FROM_DLL
/// end OCTREE_FIND_NODE_BY_ATTRIBUTE
}

int tree_set_values_by_nodeids(TreeNode& trSetting, const vector<int>& vnNodeIDs, const vector<string>& vsValues)//, bool* pbUsed=NULL)
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	//Check input
	if( !trSetting.IsValid() )
		return -1;
	
	if( 0 == vnNodeIDs.GetSize() || 0 == vsValues.GetSize() )
		return -2;
	
	if( vnNodeIDs.GetSize() != vsValues.GetSize() )
		return -3;
	
	// Deal with children.
	TreeNode tn;
	int iIndexID, nNum;
	foreach( tn in trSetting.Children )
	{
		if(  tn.GetNodeCount() > 0 )
		{
			nNum += tree_set_values_by_nodeids( tn, vnNodeIDs, vsValues );
		}
		else
		{
			// Scan IDs and Values
			int nID;
			if(tn.GetAttribute(STR_ID_ATTRIB, nID ))
				for( iIndexID = 0; iIndexID < vnNodeIDs.GetSize(); iIndexID++ )
				{
					if( vnNodeIDs[iIndexID] == nID )
					{
						nNum ++;
						tn.strVal = vsValues[iIndexID];
						break;
					}
				}	
		}
	}
	return nNum;
#else//_TREE_UTILS_FROM_HONG_DLL
	return octree_set_values_by_nodeids( &trSetting, &vnNodeIDs, &vsValues);
#endif//_TREE_UTILS_FROM_HONG_DLL ///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}
///End TREE_GET_NODE_BY_NODEID_OR_DATAID	
//------- CPY 11/26/04 OUTPUT_FIT_CURVES_TO_SOURCE_SHEET
// return total number of nodes set to be hidden
/// Hong 06/18/07 v8.0643 FIX_XF_SHOW_HELP_BY_LT_ERROR_SHOW_HIDDEN_NODE
//int tree_hide_empty_nodes(TreeNode tr, bool bRecursive)
int tree_hide_empty_nodes(TreeNode tr, bool bRecursive, bool bRemoveShowAttrib) // = true, = true
/// end FIX_XF_SHOW_HELP_BY_LT_ERROR_SHOW_HIDDEN_NODE
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	int nCount = 0;
	foreach(TreeNode cNode in tr.Children)
	{
		if(cNode.GetNodeCount() > 0)
		{
			if(bRecursive)
				/// Hong 06/18/07 v8.0643 FIX_XF_SHOW_HELP_BY_LT_ERROR_SHOW_HIDDEN_NODE
				//nCount += tree_hide_empty_nodes(cNode);
				nCount += tree_hide_empty_nodes(cNode, bRecursive, bRemoveShowAttrib);
				/// end FIX_XF_SHOW_HELP_BY_LT_ERROR_SHOW_HIDDEN_NODE
		}
		else
		{
			///Frank 4/2/05		NEW_METHOD_CHECK_NODE_EMPTY
			//if(cNode.strVal.IsEmpty())
			if(cNode.IsEmpty())
			///End		NEW_METHOD_CHECK_NODE_EMPTY
			{
				cNode.Show = false;
				nCount++;
			}
			/// Hong 06/18/07 v8.0643 FIX_XF_SHOW_HELP_BY_LT_ERROR_SHOW_HIDDEN_NODE
			//else
			else if ( bRemoveShowAttrib )
			/// end FIX_XF_SHOW_HELP_BY_LT_ERROR_SHOW_HIDDEN_NODE
				cNode.RemoveAttribute(STR_SHOW_ATTRIB);
		}
	}
	return nCount;
#else//_TREE_UTILS_FROM_HONG_DLL
	/// Hong 06/18/07 v8.0643 FIX_XF_SHOW_HELP_BY_LT_ERROR_SHOW_HIDDEN_NODE
	//return octree_hide_empty_nodes( &tr, bRecursive ); 
	return octree_hide_empty_nodes( &tr, bRecursive, bRemoveShowAttrib ); 
	/// end FIX_XF_SHOW_HELP_BY_LT_ERROR_SHOW_HIDDEN_NODE
#endif//_TREE_UTILS_FROM_HONG_DLL ///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}
//------

///Danice TREE_ROW_SHOW_ALTERNATE_COLORS
string get_GetN_background_colors(uint& nLeafFirstColor, uint& nLeafSecondColor, vector<uint>& vnBranchColors)
{
	string strColors=(string)nLeafFirstColor+"|"+(string)nLeafSecondColor;
	for(int ii=0; ii<vnBranchColors.GetSize(); ii++)
	{
		strColors+="|"+(string)vnBranchColors[ii];
	}
	return strColors;
}
///end TREE_ROW_SHOW_ALTERNATE_COLORS


#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
//---- CPY 12/17/04 SHOW_MISSING_MASED_TABLES_IF_NOT_EMPTY
//	scan all child nodes and see if any not empty, then set the specified bit in the given attribute
///Hong 7/18/06 FIX_RETURN_ERROR 
//bool tree_set_attribute_bit_if_not_empty(TreeNode& tr, LPCSTR lpcszAttribute, DWORD dwBit, bool bRecursive)
bool tree_set_attribute_bit_if_not_empty(TreeNode& tr, LPCSTR lpcszAttribute, DWORD dwBit, bool bRecursive, int& nCount)
///end FIX_RETURN_ERROR
{
	///Hong 7/18/06 FIX_RETURN_ERROR 
	/*
	int nCount = 0;
	foreach(TreeNode cNode in tr.Children)
	{
		if(cNode.GetNodeCount() > 0)
		{
			if(bRecursive)
				nCount += tree_set_attribute_bit_if_not_empty(cNode, lpcszAttribute, dwBit, true)? 1:0;
		}
		*/
	foreach(TreeNode cNode in tr.Children)
	{
		int iNodeCount = 0;
		if(cNode.GetNodeCount() > 0)
		{
			if(bRecursive)
			{
				tree_set_attribute_bit_if_not_empty(cNode, lpcszAttribute, dwBit, bRecursive, iNodeCount);
				nCount += iNodeCount;
			}
		}
	///end FIX_RETURN_ERROR
		else
		{
			///Frank 4/2/05		NEW_METHOD_CHECK_NODE_EMPTY
			//if(!cNode.strVal.IsEmpty())
			if(!cNode.IsEmpty())
			///End		NEW_METHOD_CHECK_NODE_EMPTY
			{
				nCount++;
				break;
			}
		}
	}
	if(nCount)
	{
		int nVal= 0;
		if(tr.GetAttribute(lpcszAttribute, nVal))
		{
			nVal |= dwBit;
			tr.SetAttribute(lpcszAttribute, nVal);
		/// Hong 7/13/06 FIX_ERROR_RETURN_CASE
		//}
		//return true;
			return true;
		}
		/// end FIX_ERROR_RETURN_CASE
	}
	return false;
	return octree_set_attribute_bit_if_not_empty( &tr, lpcszAttribute, dwBit, bRecursive, &nCount ); 
}
#endif//_TREE_UTILS_FROM_HONG_DLL ///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
//----

//------ CPY 1/7/05 DERIVED_PARAMETERS_READ_SAVE_PROBLEM
void _trim_str(string& str)
{
	str.TrimLeft();
	str.TrimRight();
}

// XML str cannot have \r\n, so multiline will be just \n separated
bool tree_key_value_pairs_str_to_branch(TreeNode& tr, LPCSTR lpcszMultiline, char cKVSep, char cLineSep) // '=', '\n'
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	tr.Reset(true);// keep attributes in case there is any
	string strMultiline = lpcszMultiline;
	vector<string> vsItems;
	strMultiline.GetTokens(vsItems, cLineSep);
	for(int ii = 0; ii < vsItems.GetSize(); ii++)
	{
		string str = vsItems[ii];
		int nPos = str.Find(cKVSep);
		if(nPos > 0)
		{
			string strTag = str.Left(nPos);
			string strVal = str.Mid(nPos + 1);
			_trim_str(strTag);
			_trim_str(strVal);
			tr.AddTextNode(strVal, strTag);
		}
	}
	return tr.GetNodeCount() > 0? true:false;
#else //_TREE_UTILS_FROM_HONG_DLL
	return octree_key_value_pairs_str_to_branch(&tr, lpcszMultiline, cKVSep, cLineSep);
#endif //_TREE_UTILS_FROM_HONG_DLL ///Hong 12/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}
// tag1 = val1
// tag2 = val2
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 26/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL  ///Iris 4/29/06 VS_CODES_FAIL_TO_WORK_ROLLBACK_OC_CODES
bool tree_branch_to_key_value_pairs_str(const TreeNode& tr, string& strMultiline, string strKVSep, string strLineSep) //" = ", "\n"
{
	strMultiline.Empty();
	if(!tr)
		return false;
	if(tr.GetNodeCount() < 1)
		return false;
	foreach(TreeNode trN in tr.Children)
	{
		strMultiline += trN.tagName;
		strMultiline += strKVSep;
		strMultiline += trN.strVal;
		strMultiline += strLineSep;
	}
	return true;
///Iris 4/29/06 VS_CODES_FAIL_TO_WORK_ROLLBACK_OC_CODES
//#else//_TREE_UTILS_FROM_HONG_DLL
//	return octree_branch_to_key_value_pairs_str(&tr, &strMultiline, strKVSep, strLineSep);
//End VS_CODES_FAIL_TO_WORK_ROLLBACK_OC_CODES
}
#endif//_TREE_UTILS_FROM_HONG_DLL ///Hong 26/04/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL

///Jasmine 09/17/05 v8.0308 SET_AND_GET_THEME_FILE_NAME
bool tree_set_theme_file_name(TreeNode &tr, LPCSTR lpcszThemeFileName)
{
	/// TD 4-19-06 VC_FUNCTIONS_TO_LAUNCH_XFN_GETN
	return  octree_tree_set_theme_file_name(&tr, lpcszThemeFileName);
	/// end VC_FUNCTIONS_TO_LAUNCH_XFN_GETN
	if(!tr)
		return false;
	if(lpcszThemeFileName)
		tr.SetAttribute(STR_THEME_FILE_ATTRIB, lpcszThemeFileName);
	else
		tr.RemoveAttribute(STR_THEME_FILE_ATTRIB); 
	return true;
}

bool tree_get_theme_file_name(TreeNode &tr, string &strThemeFileName)
{
	/// TD 4-19-06 VC_FUNCTIONS_TO_LAUNCH_XFN_GETN
	return  octree_tree_get_theme_file_name(&tr, &strThemeFileName);
	/// end VC_FUNCTIONS_TO_LAUNCH_XFN_GETN
	strThemeFileName = "";
	if(!tr)
		return false;
	return tr.GetAttribute(STR_THEME_FILE_ATTRIB, strThemeFileName);
}
///End SET_AND_GET_THEME_FILE_NAME

///Frank 1/26/05	GETN_DLG_ADVANCED_CHECK_SAVE
bool tree_set_or_remove_attribute(TreeNode &tr, LPCSTR lpcszAttribute, bool bAdd, LPCSTR lpcszAttribValue )
{
	if(bAdd)
	{
		string strAttrib =lpcszAttribValue;
		if(strAttrib.IsEmpty())
			strAttrib = "1";
		return tr.SetAttribute(lpcszAttribute, strAttrib);
	}
	else
		return tr.RemoveAttribute(lpcszAttribute);
}
///End	GETN_DLG_ADVANCED_CHECK_SAVE


/// ML 4/15/2005 XVAR_DATA_CHANGE_ATT
#define		STR_CHANGED_DATA_ATT			"DChng"

// nValue <= 0 to get, otherwise to set.
// If nValue == 0, it will get it and remove it (if there) at the same time!
// If nValue < 0, it will only get. 
bool	tree_changed_data(TreeNode &tn, int nValue)
{
	if (nValue <= 0)		// getting
	{
		string		str;
		if (!tn.GetAttribute(STR_CHANGED_DATA_ATT, str))
			return false;
		
		if (nValue == 0)
			tree_set_or_remove_attribute(tn, STR_CHANGED_DATA_ATT, false);
		
		// We don't care about its value. The presence is enough to return true.
		return true;
	}
	else
	{
		string		str = "1";		// the actual value not really used
		tree_set_or_remove_attribute(tn, STR_CHANGED_DATA_ATT, true, str);
	}
	
	return true;
}
/// end XVAR_DATA_CHANGE_ATT

///Forest 03/02/05 QA70-7456	COPY_TREE_USING_FILTER

bool tree_copy_by_filter(TreeNode& trDest, const TreeNode& trSrc, int nUnitNodeID,
						int nIncludeMode, int nIncludeNodeID, const vector<string>& vsIncludeValues,
						int nExcludeMode, int nExcludeNodeID, const vector<string>& vsExcludeValues)
{
	//return	octree_copy_by_filter(&trDest, &trSrc, nUnitNodeID,	nIncludeMode, nIncludeNodeID, &vsIncludeValues,	nExcludeMode, nExcludeNodeID, &vsExcludeValues);///Forest 4/1/05 QA70-7456 AVOID_CLONE_OF_TREE
	trDest.Replace(trSrc);
	return	octree_filter(&trDest, nUnitNodeID,	nIncludeMode, nIncludeNodeID, &vsIncludeValues,	nExcludeMode, nExcludeNodeID, &vsExcludeValues);
}							
///End COPY_TREE_USING_FILTER


int tree_get_theme_type(TreeNode& tr)
{
	/// TD 4-19-06 VC_FUNCTIONS_TO_LAUNCH_XFN_GETN
	return  octree_tree_get_theme_type(&tr);
	/// end VC_FUNCTIONS_TO_LAUNCH_XFN_GETN
	int 	nThemeType;
	if(tr && tr.GetAttribute(STR_THEME_TYPE_ATTRIB, nThemeType))
		return nThemeType;
	
	return THTYPE_ANALYSIS;
}

///Frank 3/31/05 TREE_MOVE_NODE_TO_POSITION
//bool tree_move_node(TreeNode &tr, int nRow, int nPosition , int nStopLevel, LPCSTR lpcszStopAttribute , bool bStopAtLastBranch, int nCurrentLevel ) ///DG 4/20/05 REWRITE_TREE_GET_NODE
bool tree_move_node(TreeNode &tr, int nRow, int nPosition, DWORD dwCntrl, LPCSTR lpcszAttribute) //=-1, 0, NULL
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 7/07/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	if(!tr.IsValid())
		return false;
	
	///---DG REWRITE_TREE_GET_NODE
	//TreeNode trMoveNode = tree_get_node(tr, nRow, nStopLevel, lpcszStopAttribute , bStopAtLastBranch, nCurrentLevel);
	TreeNode trMoveNode = tree_get_node(tr, nRow, dwCntrl, lpcszAttribute);
	
	if(!trMoveNode.IsValid())
		return false;
	
	//TreeNode trMovedBeforeNode = tree_get_node(tr, nPosition, nStopLevel, lpcszStopAttribute , bStopAtLastBranch, nCurrentLevel);
	TreeNode trMovedBeforeNode = tree_get_node(tr, nPosition, dwCntrl, lpcszAttribute);
	///---end REWRITE_TREE_GET_NODE
	
	TreeNode trMovedParent;
	TreeNode trMoveClone;
	
	if(trMovedBeforeNode.IsValid())
	{
		trMovedParent = trMovedBeforeNode.Parent();
		///---Cheney 6-15-06 FIX_BUG_WHEN_NROW_LESS_THAN_NPOSITION
		//when nRow < nPosition, at first copy the nRowth Node and insert the copy node to nPosition,
		//then remove the nRowth Node. in the end, the copy Node will go to nPosition - 1.
		//trMoveClone = trMovedParent.InsertNode(trMovedBeforeNode, trMoveNode.tagName);
		///Joseph 10/11/06 ADD_NODE_AFETER_LAST_NODE
		//trMoveClone = (nRow > nPosition) ? trMovedParent.InsertNode(trMovedBeforeNode, trMoveNode.tagName) 
							//: trMovedParent.InsertNode(trMovedBeforeNode.NextNode, trMoveNode.tagName);
		if(nRow > nPosition) 
		{
			trMoveClone = trMovedParent.InsertNode(trMovedBeforeNode, trMoveNode.tagName);
		}
		else
		{
			if(trMovedBeforeNode.NextNode.IsValid())
			{
				trMoveClone = trMovedParent.InsertNode(trMovedBeforeNode.NextNode, trMoveNode.tagName);
			}
			else
			{
				trMoveClone = trMovedParent.AddNode(trMoveNode.tagName);	
			}
		}
		///End ADD_NODE_AFETER_LAST_NODE
		///--- end 	FIX_BUG_WHEN_NROW_GREATER_THAN_NPOSITION				
	}	
	else
		if(nPosition <0 )
		{
			///Add the row to the end to tr.
			trMovedParent = tr;
			trMoveClone = trMovedParent.AddNode( trMoveNode.tagName);
		}
	
	if(!trMoveClone.IsValid())
		return false;
	
	trMoveClone.Replace(trMoveNode, true);

	trMoveNode.Remove();
	
	return true;
#else //_TREE_UTILS_FROM_HONG_DLL
	return octree_move_node(&tr, nRow, nPosition, dwCntrl, lpcszAttribute); 
#endif //_TREE_UTILS_FROM_HONG_DLL ///Hong 7/07/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}
///End TREE_MOVE_NODE_TO_POSITION

///DG 4/7/05
string tree_get_enum_node_name(TreeNode &trNode, string strPrefix)
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 09/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL /// Iris 5/12/06 FO_NOT_WORK_ROLLBACK_TO_ORIGINAL_CODE
	vector<string> vsNodeNames;
	tree_get_node_names(trNode, vsNodeNames, true);
	int nNum=get_list_enum_number(vsNodeNames, strPrefix);
	string strNum= 0==nNum ? "" : (string)nNum;
	return strPrefix+strNum;
#else///_TREE_UTILS_FROM_HONG_DLL
	string strOut;
	octree_get_enum_node_name(&trNode, &strOut, strPrefix);	
	return strOut;
#endif///_TREE_UTILS_FROM_HONG_DLL ///Hong 09/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL 
}
///Hong 8/01/06 ADD_POSTFIX_SUPPORT
//string tree_get_enum_attribute_value(TreeNode &trNode, string strAttribute, string strPrefix)
string tree_get_enum_attribute_value(TreeNode &trNode, string strAttribute, string strPrefix, string strPostfix)
///end ADD_POSTFIX_SUPPORT
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 09/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL /// Iris 5/12/06 FO_NOT_WORK_ROLLBACK_TO_ORIGINAL_CODE
	vector<string> vsAttribVals;
	tree_get_attributes(trNode, vsAttribVals, strAttribute, true);
	//int nNum=get_list_enum_number(vsAttribVals, strPrefix);
	int nNum=get_list_enum_number(vsAttribVals, strPrefix, strPostfix);//Hong 8/01/06 ADD_POSTFIX_SUPPORT 
	string strNum= 0==nNum ? "" : (string)nNum;
	return strPrefix+strNum;
#else///_TREE_UTILS_FROM_HONG_DLL
	string strOut;
	//octree_get_enum_attribute_value(&trNode, &strOut, strAttribute, strPrefix);
	octree_get_enum_attribute_value(&trNode, &strOut, strAttribute, strPrefix, strPostfix);//Hong 8/01/06 ADD_POSTFIX_SUPPORT
	return strOut;
#endif///_TREE_UTILS_FROM_HONG_DLL ///Hong 09/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL 
}
///end

/// EJP 2005-03-31 v8.0214 QA70-6816 SHOW_IMPORT_FILE_INFO_IN_USER_VAR_DLG
int tree_add_import_file_info(TreeNode& tnTarget, Page& pgSource, int nSrc) // = 0
{
	Tree tnFileInfo;
	if( tree_get_binary_storage(tnFileInfo, pgSource, IFI_BINARY_STORAGE_NAME) )
	{
		foreach( TreeNode tnChild in tnFileInfo.Children )
		{
			string strNode = tnChild.tagName;
			if( strNode.GetLength() > 4 ) // 4=File
			{
				string str = strNode.Left(4);
				if( str.CompareNoCase("File") == 0 )
				{
					strNode.Delete(0, 4);
					int nFile = atoi(strNode);
					tree_set_import_file_node_data_attrib(tnChild, nFile, NULL, nSrc);
					tnTarget.AddNode(tnChild);
				}
			}
		}
	}
	return 0;
}

///Kyle 02/04/2010 READ_SHEET_INPORT_FILE_INFO
int tree_add_obj_import_file_info(const OriginObject& obj, TreeNode& tr)
{
	if( !obj || !tr)
		return -1;

	Tree trColFileInfo;
	if( get_import_file_info(obj, trColFileInfo) )
	{
		_set_data_attrib(trColFileInfo, SIFI_BINARY_STORAGE_NAME, "%H");
		TreeNode trFileInfo = tr.AddNode("FileInfo");
		trFileInfo.Replace(trColFileInfo, true, true);
		
		trFileInfo.SetAttribute(STR_LABEL_ATTRIB, _L("Imported File"));
	}
	return 0;
}
///End READ_SHEET_INPORT_FILE_INFO

/// Kenny 11/26/2009 QA81-14748 INSERT_VAR_DLG_FAILED_TO_SHOW_IMPORT_FILE_LEVEL_INFO
#define CHECK_UPDATE_NODE_ID(_nID, _str)	\
			if ( is_str_numeric_integer(_str) )\
				_nID = ONODETYPE_EDIT_BOX_NUMERIC_INT;\
			else	\
				_nID = TRGP_DOUBLE;
/// End QA81-14748 INSERT_VAR_DLG_FAILED_TO_SHOW_IMPORT_FILE_LEVEL_INFO

int tree_set_import_file_node_data_attrib(TreeNode& tnParent, int nFile, LPCSTR lpcszPrefix, int nSrc) // = NULL, 0
{
	string strPrefix;
	if( lpcszPrefix )
		strPrefix.Format("%s.", lpcszPrefix);
	
	string strFormat;
	if( nSrc > 0 )
		strFormat.Format("%%%%(%d,@WF%%d,%%s)", nSrc);
	else
		strFormat = "%%(%%H,@WF%d,%s)";

	string strNodePath;
	foreach( TreeNode tnChild in tnParent.Children )
	{
		strNodePath.Format("%s%s", strPrefix, tnChild.tagName);
		
		if( tnChild.GetNodeCount() > 0 )
		{
			tree_set_import_file_node_data_attrib(tnChild, nFile, strNodePath, nSrc);
		}
		else
		{
			///Jasmine 01/18/07 QA70-9273 MODIFICATION_FOR_USER_VAR_DLG
			///Jasmine 01/17/07 ADD_$_FOR_STRVAL
			string strDataValue, str = tnChild.Text;
			strDataValue.Format(strFormat, nFile, strNodePath);
			tnChild.SetAttribute(STR_DATA_ATTRIB, strDataValue);
			/// Kenny 11/26/2009 QA81-14748 INSERT_VAR_DLG_FAILED_TO_SHOW_IMPORT_FILE_LEVEL_INFO
			//int nID;
			int nID = ONODETYPE_INVALID;
			/// End QA81-14748 INSERT_VAR_DLG_FAILED_TO_SHOW_IMPORT_FILE_LEVEL_INFO
			/// Kenny 12/22/2009 QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
			//if(!is_numeric(str) || (tnChild.GetAttribute(STR_ID_ATTRIB, nID) && TRGP_STR == nID))
			tnChild.GetAttribute(STR_ID_ATTRIB, nID);
			if( !is_numeric(str) || IS_TEXT_NODE_ID(nID) )
			/// End QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
			{
				/// Kenny 11/26/2009 QA81-14748 INSERT_VAR_DLG_FAILED_TO_SHOW_IMPORT_FILE_LEVEL_INFO
				/// Kenny 12/22/2009 QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
				//nID = TRGP_STR;
				// If the string is not a number and the id of it is invalid, we can assume it as a text node
				if ( ONODETYPE_INVALID == nID )
					nID = TRGP_STR;
				/// End QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
				/// End QA81-14748 INSERT_VAR_DLG_FAILED_TO_SHOW_IMPORT_FILE_LEVEL_INFO
				strNodePath += "$";
			}
			/// Kenny 11/26/2009 QA81-14748 INSERT_VAR_DLG_FAILED_TO_SHOW_IMPORT_FILE_LEVEL_INFO
			if ( ONODETYPE_INVALID == nID )
			{
				CHECK_UPDATE_NODE_ID(nID, str);
			}
			tnChild.ID = nID;
			/// End QA81-14748 INSERT_VAR_DLG_FAILED_TO_SHOW_IMPORT_FILE_LEVEL_INFO
			///End _FOR_STRVAL
			tnChild.SetAttribute(STR_PATH_ATTRIB, "File" + nFile + "." + strNodePath);
			///End MODIFICATION_FOR_USER_VAR_DLG
		}
	}
	return 0;
}
/// end SHOW_IMPORT_FILE_INFO_IN_USER_VAR_DLG
///Jasmine 01/17/07 QA70-9273 SHOW_USER_TREE_INFO_IN_USER_VAR_DLG
int tree_add_user_tree_info(TreeNode& tr, OriginObject& obj)
{
	///Kyle 08/27/2009 QA80-14210 CLEAN_CODE_TO_FIX_RUNTIME_ERROR_WHEN_TREE_INVALID
	if(!tr)
		return -1;
	///End CLEAN_CODE_TO_FIX_RUNTIME_ERROR_WHEN_TREE_INVALID
	Tree trStorage;
	if(tree_get_binary_storage(trStorage, obj, "TREE"))
	{
		///Jasmine 12/28/09 QA81-14845-S1 ACCESS_SOURCE_BOOK_SHEET_COLUMN_FROM_PLOT
		//string strRange;
		//obj.GetRangeString(strRange);
		//if(!strRange.Right(1).Compare("!"))
			//strRange.TrimRight('!');
		//if(!strRange.Right(1).Compare("]"))
		//{
			//strRange.TrimRight(']');
			//strRange.TrimLeft('[');
		//}
		//_set_data_attrib(trStorage, "tree", strRange);
		_set_data_attrib(trStorage, "tree", "%H");
		///End ACCESS_SOURCE_BOOK_SHEET_COLUMN_FROM_PLOT
		TreeNode trUser = tr.AddNode("UserTree");
		trUser.Replace(trStorage, true, true);
	}
	return 1;
}
static void _set_data_attrib(TreeNode& tr, string strRoot, string strObj)
{
	if(!tr.GetNodeCount())
	{
		string strData;
		tree_get_level(tr, &strData);
		///Jasmine 02/06/07 REPLACE_NOT_ONLY_ORIGIN_STORAGE_BUT_ROOT_TAGNAME
		//string strDel = "OriginStorage";//replace OriginStorage with given tagname
		int nIndex = strData.Find(".");//strDel
		if(-1 < nIndex)
			strData.Delete(0, nIndex);//strDel.GetLength()
		///End REPLACE_NOT_ONLY_ORIGIN_STORAGE_BUT_ROOT_TAGNAME
		strData = strRoot + strData;
		/// Kenny 01/04/2010 QA81-14748-P2 MORE_WORK_ON_INSERT_VAL_FOR_MULTILINE_NODE
		//int nID;
		int nID = ONODETYPE_INVALID;
		/// End QA81-14748-P2 MORE_WORK_ON_INSERT_VAL_FOR_MULTILINE_NODE
		string str = tr.Text;
		/// Kenny 12/22/2009 QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
// 		if(!is_numeric(str) || (tr.GetAttribute(STR_ID_ATTRIB, nID) && TRGP_STR == nID))
// 		{
// 			nID = TRGP_STR;				///Kyle 08/13/2009 SET_COLUMN_VALUES_SUPPORT_DEFINE_VARIABLES_IN_BASIC_DATA_TYPE
// 			strData += "$";
// 		}
		tr.GetAttribute(STR_ID_ATTRIB, nID);
		if( !is_numeric(str) || IS_TEXT_NODE_ID(nID) )
		{
			if ( ONODETYPE_INVALID == nID )
				nID = TRGP_STR;
			strData += "$";
		}
		/// End QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
		///Kyle 08/13/2009 SET_COLUMN_VALUES_SUPPORT_DEFINE_VARIABLES_IN_BASIC_DATA_TYPE
		else if(nID == ONODETYPE_INVALID)
		{
			/// Kenny 11/26/2009 QA81-14748 INSERT_VAR_DLG_FAILED_TO_SHOW_IMPORT_FILE_LEVEL_INFO
			//nID = TRGP_DOUBLE;
			CHECK_UPDATE_NODE_ID(nID, str);
			/// End QA81-14748 INSERT_VAR_DLG_FAILED_TO_SHOW_IMPORT_FILE_LEVEL_INFO
		}
		///End SET_COLUMN_VALUES_SUPPORT_DEFINE_VARIABLES_IN_BASIC_DATA_TYPE
		str.Format("%%(%s, @W,%s)", strObj, strData);
		tr.SetAttribute(STR_DATA_ATTRIB, str);//%(obj name, @W, tree.branch.leaf)
		tr.SetAttribute(STR_PATH_ATTRIB, strData);//tree.branch.leaf	///Jasmine 01/18/07 QA70-9273 MODIFICATION_FOR_USER_VAR_DLG
		tr.ID = nID;				///Kyle 08/13/2009 SET_COLUMN_VALUES_SUPPORT_DEFINE_VARIABLES_IN_BASIC_DATA_TYPE
	}
	foreach(TreeNode cNode in tr.Children)
	{
		_set_data_attrib(cNode, strRoot, strObj);
	}
	return;
}
///End SHOW_USER_TREE_INFO_IN_USER_VAR_DLG

///Kyle 08/26/2009 QA80-14190 DEFINE_VARIABLE_FROM_COLUMN_LABELS_IN_SCV_DB
/// Kenny 09/27/2009 QA81-14241 INSERT_USER_DEF_PARAM_SHOULD_USE_CORRECT_INDEX
// static bool _label_path_from_type(const Grid& grid, int nType, string& strLabel, string& strPath)
// {
// 	strLabel.Empty();
// 	strPath.Empty();
// 	
// 	if(nType >= RCLT_PARAM && nType < RCLT_PARAM + PARAMS_MAX_NUM)
// 	{
// 		int nOffset = nType - RCLT_PARAM;
// 		strPath = "P" + (nOffset>0 ?  (string)nOffset : "");
// 		strLabel = _L(E_STR_PARAMETERS) + (nOffset>0 ?  (string)nOffset : "");
// 		
// 	}
// 	else if(nType >= RCLT_UDL && nType < RCLT_UDL + UDL_MAX_NUM)
// 	{
// 		int nOffset = nType - RCLT_UDL;
// 		strPath = "D" + (nOffset>0 ?  (string)nOffset : "");
// 		vector<string> vsNames;
// 		grid.GetUserDefinedLabelNames(vsNames);
// 		if(nOffset < vsNames.GetSize() )
// 			strLabel = vsNames[nOffset];
// 	}
// 	else
// 	{
// 		switch(nType)
// 		{
// 		case RCLT_LONG_NAME:
// 			strPath = "L";
// 			strLabel = _L(E_STR_LONGNAME);
// 			break;
// 		case RCLT_UNIT:
// 			strPath = "U";
// 			strLabel = _L(E_STR_UNITS);
// 			break;
// 		case RCLT_COMMENT:
// 			strPath = "C";
// 			strLabel = _L(E_STR_COMMENTS);
// 			break;
// 		default:
// 			return false;
// 		}
// 	}
// 	return true;
// }

typedef string (*PFN_GET_LABEL_NAME_BY_TYPE)(const int nType, const Worksheet& wks = NULL);

static bool _get_col_label_path(const Worksheet& wks, const int nType, string& strLabel, string& strPath)
{
	int nCharOffset = -1;
	int nTypeChar = okutil_cvt_col_label_type_to_char(nType, &nCharOffset);
	strPath.Format("%c", nTypeChar);
	if ( nCharOffset >= 0 )
		strPath += (nCharOffset+1);
	PFN_GET_LABEL_NAME_BY_TYPE pfn_get_label_name_by_type = Project.FindFunction("get_label_name_by_type", "OriginLab\\WksColLabels");
	if ( pfn_get_label_name_by_type )
		strLabel = pfn_get_label_name_by_type(nType, wks);
	return true;
}
/// End QA81-14241 INSERT_USER_DEF_PARAM_SHOULD_USE_CORRECT_INDEX

int tree_add_column_labels_info(TreeNode& tr, const Column& col)
{
	if(!tr || !col)
		return -1;
	Worksheet wks;
	col.GetParent(wks);
	if(!wks)
		return -2;
	/// Kenny 09/27/2009 QA81-14241 INSERT_USER_DEF_PARAM_SHOULD_USE_CORRECT_INDEX
// 	Grid grid;
// 	if( !grid.Attach(wks) )
// 		return -3;
	/// End QA81-14241 INSERT_USER_DEF_PARAM_SHOULD_USE_CORRECT_INDEX

	int n1OffsetColIndex = 1 + col.GetIndex();		///Kyle 02/02/2010 QA80-15056 NEED_INSERT_LABEL_FOR_TEXT_OBJECT
	
	Tree trTmp;
	for(int nType = RCLT_LONG_NAME; nType <= RCLT_MAX_TYPE; nType++)
	{
		if(nType==RCLT_SAMPLE_RATE || nType==RCLT_SPARKLINE)
			continue;
		string strLabel, strPath, strValue;
		/// Kenny 09/27/2009 QA81-14241 INSERT_USER_DEF_PARAM_SHOULD_USE_CORRECT_INDEX
		//if( col.GetExtendedLabel(strValue, nType) && !strValue.IsEmpty() && _label_path_from_type(grid, nType, strLabel, strPath) )
		if( col.GetExtendedLabel(strValue, nType) && !strValue.IsEmpty() && _get_col_label_path(wks, nType, strLabel, strPath) )
		/// End QA81-14241 INSERT_USER_DEF_PARAM_SHOULD_USE_CORRECT_INDEX
		{
			TreeNode trLabel = trTmp.AddNode(strPath);
			trLabel.SetAttribute(STR_LABEL_ATTRIB, strLabel);

			trLabel.strVal = strValue;
			int nID = ONODETYPE_INVALID;
			///Sophy 10/9/2009 QA80-14190-P1 COL_LABELS_WITH_ONLY_WHITE_SPACES_MIXED_WITH_NUMERIC_SHOULD_BE_TREATED_AS_TEXT
			//Sophy, in VC level CEditableProperty set the value on control only when cvt_str_to_double return none 0, which internally call LABUTIL_cvtstr2real to do the parsing
			//is_str_numeric interally call LABUTIL_cvtstr2real too. But is_numeric internally depend on the result of is_str_none_numeric, which call LABUTIL_strip to remove all white spaces before parsing.
			//E.g. strVal = "12 6", is_numeric will return true, while is_str_numeric will return false.
			//So as to keep them consistent, I change to use is_str_numeric.
			//if(is_numeric(strValue))
			if ( is_str_numeric(strValue) )
			///end COL_LABELS_WITH_ONLY_WHITE_SPACES_MIXED_WITH_NUMERIC_SHOULD_BE_TREATED_AS_TEXT
				nID = TRGP_DOUBLE;
			else
			{
				/// Kenny 12/22/2009 QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
				//nID = TRGP_STR;
				nID = ONODETYPE_EDIT_BOX_MULTILINE_TEXT;
				/// End QA81-14748-P2 INSERT_USER_VAR_DLG_FAILS_TO_SHOW_MULTILINE_NODE
			}
			trLabel.ID = nID;

			///Kyle 02/02/2010 QA80-15056 NEED_INSERT_LABEL_FOR_TEXT_OBJECT
			string strDataValue;
			strDataValue.Format("%%(%%H,%d,%s)", n1OffsetColIndex, strPath);
			trLabel.SetAttribute(STR_DATA_ATTRIB, strDataValue);
			///End NEED_INSERT_LABEL_FOR_TEXT_OBJECT

			/// Kenny 09/03/2009 QA81-14241 DEFINE_VARIABLE_NEED_MORE_IMPROVEMENTS
// 			strPath.Format("[%s]", strPath);
// 			if(nID == TRGP_STR)
// 				strPath += "$";
			strPath.Format("[%s]$", strPath);
			/// End QA81-14241 DEFINE_VARIABLE_NEED_MORE_IMPROVEMENTS
			trLabel.SetAttribute(STR_PATH_ATTRIB, strPath);
		}
	}
	if(trTmp.GetNodeCount() > 0)
	{
		TreeNode trLabels = tr.AddNode("Labels");
		trLabels.Replace(trTmp, true, true);
	}
	return 0;
}
///End DEFINE_VARIABLE_FROM_COLUMN_LABELS_IN_SCV_DB

///Forest 4/1/05 TREE_FILTER_BY_ATTRIB_MATCH
bool	tree_filter_by_attrib_match(TreeNode& tr, int iUnitNodeID, LPCSTR lpcstrAttrib, LPCSTR lpcstrPattern, bool bCaseSensitive)
{
	return	octree_filter_by_attrib_match(&tr, iUnitNodeID, lpcstrAttrib, lpcstrPattern, bCaseSensitive);
}

bool	tree_filter_by_attrib_find(TreeNode& tr, int iUnitNodeID, LPCSTR lpcstrAttrib, LPCSTR lpcstrSub, bool bCaseSensitive, bool bMustBeginWith)
{
	return	octree_filter_by_attrib_find(&tr, iUnitNodeID, lpcstrAttrib, lpcstrSub, bCaseSensitive, bMustBeginWith);
}
///End TREE_FILTER_BY_ATTRIB_MATCH

///Sophy 8/7/2009 QA80-14101 SET_GETN_NODES_AS_UNDEFINED_WHEN_SEL_MULTI_COLS_WITH_DIFF_PROPERTY
int		tree_remove_children_by_attrib(TreeNode& tr, LPCSTR lpcszAttrib, int nAttribVal, bool bRecursive/* = true*/)
{
	if ( !tr )
		return -1;
	
	int nRemoved = 0;
	foreach ( TreeNode trSubNode in tr.Children )
	{
		if ( bRecursive )
			nRemoved += tree_remove_children_by_attrib(trSubNode, lpcszAttrib, nAttribVal, bRecursive);
		
		int nNodeAttrib = 0;
		if ( trSubNode.GetAttribute(lpcszAttrib, nNodeAttrib) && nNodeAttrib == nAttribVal )
		{
			nRemoved++;
			trSubNode.Remove();
		}
	}
	return nRemoved;
}
///end SET_GETN_NODES_AS_UNDEFINED_WHEN_SEL_MULTI_COLS_WITH_DIFF_PROPERTY
///Frank 4/5/05 GUI_ADVANCED_SETTING_FROM_FILE
bool tree_set_advanced_settings_file(TreeNode &trGUI, string strFileName = "")
{
	if(!strFileName.IsEmpty())
		return	trGUI.SetAttribute(STR_GUI_THEME_FILE_ATTRIB, strFileName);
	return false;
}
string tree_get_advanced_settings_file(TreeNode &trGUI)
{
	string strFileName ;
	trGUI.GetAttribute(STR_GUI_THEME_FILE_ATTRIB, strFileName);
	return strFileName;
}

bool 	is_in_ids_range(TreeNode &trNode, int nBeginID, int nEndID, int nOffset)
{
#ifndef _TREE_UTILS_FROM_HONG_DLL ///Hong 7/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
	if(!trNode)
		return false;
	
	if(nBeginID > nEndID || nBeginID<0 || nEndID<0)
		return false;
	
	int nID = trNode.ID;
	if( nID>= nBeginID && nID <= nEndID + nOffset)
		return true;

	return false;
#else//_TREE_UTILS_FROM_HONG_DLL
	return octree_is_in_ids_range(&trNode, nBeginID, nEndID, nOffset);
#endif//_TREE_UTILS_FROM_HONG_DLL ///Hong 7/05/06 MOVE_OC_TREE_UTILITY_TO_VC_LEVEL
}
///End	GUI_ADVANCED_SETTING_FROM_FILE

/// Iris 12/14/05 INIT_CONTROL_LEVEL_LIST_ON_LEVEL_NAME_CHANGE
TreeNode tree_get_root_node(TreeNode& tr)
{
	TreeNode trRoot, trTemp;
	trTemp = tr;
	while(trTemp)
	{
		trRoot = trTemp;
		trTemp = trRoot.Parent();
	}
	return trRoot;
}
///End INIT_CONTROL_LEVEL_LIST_ON_LEVEL_NAME_CHANGE

/// YuI 08/15/06 MORE_WORK_ON_STATISTICAL_PLOTS
TreeNode	tree_stats_get_boxchart_box_node(TreeNode& trStats)
{
	TreeNode trBoxChart = tree_check_get_node(trStats, "BoxChart");
	return tree_check_get_node(trBoxChart, "Box");
}

TreeNode	tree_stats_get_boxchart_whisker_node(TreeNode& trStats)
{
	TreeNode trBoxChart = tree_check_get_node(trStats, "BoxChart");
	return tree_check_get_node(trBoxChart, "Whsiker");
}

void	tree_stats_get_set_box_info(TreeNode& trStats, double& dTop, double& dTopX, double& dBottom, double& dBottomX, double& dCenter, BOOL bGet)
{
	TreeNode trBox = tree_stats_get_boxchart_box_node(trStats);
	if( bGet )
	{
		dCenter = trBox.Center.dVal;
		dTop = trBox.Top.dVal;
		dTopX = trBox.TopX.dVal;
		dBottom = trBox.Bottom.dVal;
		dBottomX = trBox.BottomX.dVal;
	}
	else
	{
		trBox.Center.dVal = dCenter;
		trBox.Top.dVal = dTop;
		trBox.TopX.dVal = dTopX;
		trBox.Bottom.dVal = dBottom;
		trBox.BottomX.dVal = dBottomX;
	}
}

void	tree_stats_get_set_whisker_info(TreeNode& trStats, double& dTop, double& dBottom, BOOL bGet)
{
	TreeNode trWhisker = tree_stats_get_boxchart_whisker_node(trStats);
	if( bGet )
	{
		dTop = trWhisker.Top.dVal;
		dBottom = trWhisker.Bottom.dVal;
	}
	else
	{
		trWhisker.Top.dVal = dTop;
		trWhisker.Bottom.dVal = dBottom;
	}
}

void	tree_stats_get_set_stats_results(TreeNode& trStats, DescStatResults& dsr, double& dMin, double& dMax, BOOL bGet)
{
	if( bGet )
	{
		dsr = trStats.Results;
		dMin = trStats.Results.Min.dVal;
		dMax = trStats.Results.Max.dVal;
	}
	else
	{
		trStats.Results = dsr;
		trStats.Results.Min.dVal = dMin;
		trStats.Results.Max.dVal = dMax;
	}
}

void	tree_stats_get_set_counts(TreeNode& trStats, vector& vCounts, BOOL bGet)
{
	if( bGet )
	{
		vCounts = trStats.Counts.dVals;
	}
	else
	{
		trStats.Counts.dVals = vCounts;
	}
}

void	tree_stats_get_set_percentiles(TreeNode& trStats, vector& vPercentiles, BOOL bGet)
{
	if( bGet )
	{
		vPercentiles = trStats.Percentiles.dVals;
	}
	else
	{
		trStats.Percentiles.dVals = vPercentiles;
	}
}

void	tree_stats_get_set_bin_info(TreeNode& trStats, double& dMin, double& dMax, double& dSize, BOOL bGet)
{
	if( bGet )
	{
		///Arvin 03/09/07 RUNTIME_ERROR_WHEN_TREENODE_NOT_EXIST
		//dMin = trStats.Bin.Min.dVal;
		//dMax = trStats.Bin.Max.dVal;
		//dSize = trStats.Bin.Size.dVal;
		TreeNode trBin = trStats.Bin;
		if(trBin)
		{
			dMin = trBin.Min.dVal;
			dMax = trBin.Max.dVal;
			dSize = trBin.Size.dVal;
		}
		///end RUNTIME_ERROR_WHEN_TREENODE_NOT_EXIST
	}
	else
	{
		trStats.Bin.Min.dVal = dMin;
		trStats.Bin.Max.dVal = dMax;
		trStats.Bin.Size.dVal = dSize;
	}
}
/// end MORE_WORK_ON_STATISTICAL_PLOTS

/// YuI 04/17/06 CENTRALIZATION_STATS_INPUT_DATA_TREE_CONVERTING
BOOL	tree_stats_convert_input_data(TreeNode& tr, int nType)
{
	switch( nType )
	{
		case SIDT_INVAR:
			tr.SetAttribute(STR_COMBO_ATTRIB, _L("1st Data Range|2nd Data Range"));
			/// ML 1/30/2007 QA70-9318 P2 PREPARING_RANGE_XF_ARG_WITH_FACTOR
			tr.SetAttribute(STR_ATT_XFGETN_RANGE_DESIGS, "XX");
			/// end PREPARING_RANGE_XF_ARG_WITH_FACTOR
			break;
		case SIDT_INGROUP:
			///Echo 6/1/07	SUPPORT_CTRL_SELECT
			tr.SetAttribute(STR_COMBO_ATTRIB, _L("Group Range|Data Range"));
			tr.SetAttribute(STR_ATT_XFGETN_RANGE_DESIGS, "FX");
			/*
			tr.SetAttribute(STR_COMBO_ATTRIB, "Data Range|Group Range");
			/// ML 1/30/2007 QA70-9318 P2 PREPARING_RANGE_XF_ARG_WITH_FACTOR
			tr.SetAttribute(STR_ATT_XFGETN_RANGE_DESIGS, "XF");
			/// end PREPARING_RANGE_XF_ARG_WITH_FACTOR
			*/
			///end SUPPORT_CTRL_SELECT
			break;
		break;
	}
	
	return FALSE;
}
/// end CENTRALIZATION_STATS_INPUT_DATA_TREE_CONVERTING

/// Iris 5/30/06 EXPORT_PAGE_XF
TreeNode tree_get_node_by_tagname(const TreeNode& tr, LPCSTR lpcszTagName, bool bRecursive, bool bCaseSensitive, bool bSkipBranch)
{
	//------ Folger 12/28/07 TREE_TAGNAME_OPERATION_MOVE_TO_VC
	/*
	string 	strName = tr.tagName;
	if( !bSkipBranch || tr.GetNodeCount() == 0 )
	{
		/// Hong 12/30/06 FIX_ERROR_CARE_CASE_SENSITIVE_OR_NOT
		//if(0 == strName.Compare(lpcszTagName))
			//return tr;
		int nRet;
		if(bCaseSensitive)
			nRet = strName.Compare(lpcszTagName);
		else
			nRet = strName.CompareNoCase(lpcszTagName);
		if( 0 == nRet )
			return tr;
		/// end FIX_ERROR_CARE_CASE_SENSITIVE_OR_NOT
	}
	if(bRecursive && tr.GetNodeCount() > 0) // branch node
	{
		foreach(TreeNode trNode in tr.Children)
		{	
			TreeNode trFind = tree_get_node_by_tagname(trNode, lpcszTagName, true, bCaseSensitive, bSkipBranch);
			if(trFind)
				return trFind;
		}
	}
	TreeNode junk;
	return junk;
	*/
	TreeNode trReturn;
	octree_get_node_by_tagname(&tr, &trReturn, lpcszTagName, bRecursive, bCaseSensitive, bSkipBranch);
	return trReturn;
	//------
}
//------ Folger 12/28/07 TREE_TAGNAME_OPERATION_MOVE_TO_VC
/*
int _tree_get_ids_with_tagnames(const TreeNode& tr, vector<string>& vsTagNames, vector<int>& vnIDs, bool bRecursive, bool bSkipBranch = true)
{
	int nCount=0;
	foreach(TreeNode trNode in tr.Children)
	{
		if( !bSkipBranch || trNode.GetNodeCount() == 0 )
		{
			vsTagNames.Add(trNode.tagName);
			vnIDs.Add(trNode.DataID);
			nCount++;
		}
		if(bRecursive && trNode.GetNodeCount() > 0) // branch node
		{
			nCount += _tree_get_ids_with_tagnames(trNode, vsTagNames, vnIDs, true);
		}
	}
	return nCount;
}

int _tree_set_ids_by_tagnames(TreeNode& tr, const vector<string>& vsTagNames, const vector<int>& vnIDs, bool bSkipBranch = false)
{
	int nCount=0;
	for(int nn=0; nn<vsTagNames.GetSize(); nn++)
	{
		TreeNode trFind = tree_get_node_by_tagname(tr, vsTagNames[nn], true, false, bSkipBranch);
		if(!trFind)
			continue;
		
		trFind.DataID = vnIDs[nn];
		nCount++;
	}
	return nCount;
}
*/
//------

int tree_copy_ids_by_tagname(const TreeNode& trSrc, TreeNode& trDest, bool bSkipBranch)
{
	//------ Folger 12/28/07 TREE_TAGNAME_OPERATION_MOVE_TO_VC
	/*
	vector<string> 	vsTagNames;
	vector<int> 	vnIDs;	
	int nCount = _tree_get_ids_with_tagnames(trSrc, vsTagNames, vnIDs, true, bSkipBranch);
	if(0 == nCount)
		return nCount;
	
	return _tree_set_ids_by_tagnames(trDest, vsTagNames, vnIDs, bSkipBranch);		
	*/
	return octree_copy_ids_by_tagname(&trSrc, &trDest, bSkipBranch);
	//------
}
///End EXPORT_PAGE_XF

//---- CPY 7/18/06 for debugging only
void _dump_vec(LPCSTR lpcsz, vector<int>& vn)
{
	printf("%s:", lpcsz);
	for(int ii = 0; ii < vn.GetSize(); ii++)
		printf(" %d", vn[ii]);
	out_str("");
}
void tree_dump_vec_node(LPCSTR lpcsz,TreeNode& tr)
{
	vector<int> vn;
	vn = tr.nVals;
	_dump_vec(lpcsz, vn);
}
//---- end CPY 7/18/06

int  tree_find_attributes_by_ID(const TreeNode& tr, DWORD nID, LPCSTR lpcszAttibute, vector<int>& vnAttribVals, bool bRecursive)
{
	int nCount=0;
	foreach(TreeNode trNode in tr.Children)
	{
		if(nID == trNode.ID)
		{
			int nVal;
			if(trNode.GetAttribute(lpcszAttibute, nVal))
				vnAttribVals.Add(nVal);
			nCount++;
		}
		if(bRecursive && trNode.GetNodeCount() > 0) // branch node
		{
			nCount += tree_find_attributes_by_ID(trNode, nID, lpcszAttibute, vnAttribVals, true);
		}
	}
	return nCount;
}

/// Hong 9/14/06 REMOVE_IMPORT_RELATED_TO_FU_UTILS
/*
/// EJP 2006-07-07 v8.0440 QA70-8697 XFUNC_BASED_IMPORT, Move code to here from FileImport.c
#if _OC_VER >= 0x0800
bool impinfo_InitTree(Page& pgTarget, int nImportMode)
{
	int nFile = 1; // first node

	Tree tr;
	if( tree_get_binary_storage(tr, pgTarget, IFI_BINARY_STORAGE_NAME) )
	{
		if( ASCIMP_MODE_REPLACE_DATA == nImportMode )
		{
			tr.Reset(); // empty tree
		}
		else // appending data, new file node
		{
			nFile = tr.GetNodeCount() + 1;
		}
	}

	string str;
	str.Format(IFI_FILE_NODE_ENUM_NAME, nFile);
	tr.AddNode(str);
	
	if( tree_put_binary_storage(tr, pgTarget, IFI_BINARY_STORAGE_NAME) )
		return true;
	return false;
}

bool impinfo_GetLastFileNode(Page& pgSource, TreeNode& trTarget)
{
	Tree tr;
	if( tree_get_binary_storage(tr, pgSource, IFI_BINARY_STORAGE_NAME) )
	{
		trTarget = tr.LastNode;
		return true;
	}
	return false;
}

bool impinfo_SetLastFileNode(Page& pgTarget, TreeNode& trFile)
{
	Tree tr;
	if( tree_get_binary_storage(tr, pgTarget, IFI_BINARY_STORAGE_NAME) )
	{
		TreeNode trn;
		trn = tr.LastNode;
		if( trn && trn.Replace(trFile, TRUE) )
			return tree_put_binary_storage(tr, pgTarget, IFI_BINARY_STORAGE_NAME);
	}
	return false;
}

bool impinfo_FilterNameToLastFileNode(Page& pgTarget, LPCSTR lpcszFilterFile)
{
	Tree trFile;
	if( impinfo_GetLastFileNode(pgTarget, trFile) )
	{
		trFile.Info.FilterFile.strVal = lpcszFilterFile;
		return impinfo_SetLastFileNode(pgTarget, trFile);
	}
	return false;
}
*/
/// end REMOVE_IMPORT_RELATED_TO_FU_UTILS
//---- CPY 10/1/04 ADD_DATE_DISPLAY_INFO_FOR_WKBOOK_ORGANIZER
static void tree_set_date_node(TreeNode& tr, string strFormat = "D9") // short plus hh::mm
{
	tr.ID = TRGP_DOUBLE;
	tr.SetAttribute(STR_ATTRIB_NUMFMT, strFormat);
}
//----	
///---Sim 02-06-2007 ADD_RANGE_INFO_TO_BASE_INFO
//bool impinfo_FileInfoToFileNode(TreeNode& trFile, LPCSTR lpcszDataFile, int nFileType)
bool impinfo_FileInfoToFileNode(TreeNode& trFile, LPCSTR lpcszDataFile, int nFileType, const TreeNode& trRange)// = 0, NULL
///---END ADD_RANGE_INFO_TO_BASE_INFO
{
	if( !trFile || !lpcszDataFile )
		return FALSE;

	double dJulianDate = 0.0;

	SYSTEMTIME st;
	//GetSystemTime(&st); 
	get_current_time(st, true);// Hong 12/25/06 SAVE_TIME_IN_ORGANIZER_USE_LOCAL_TIME
	SystemTimeToJulianDate(&dJulianDate, &st);
	trFile.Info.ImportDate.dVal = dJulianDate;
	//------ Folger 11/17/07 LOCALIZE_IMPORT_FILE_INFO
	trFile.Info.SetAttribute(STR_LABEL_ATTRIB, _L("Info"));
	trFile.Info.ImportDate.SetAttribute(STR_LABEL_ATTRIB, _L("Import Date"));
	//------ End LOCALIZE_IMPORT_FILE_INFO
	
	WIN32_FILE_ATTRIBUTE_DATA fad;
	/// Hong 12/06/07 v8.0762 IMPORT_SUPPORT_RELATIVE_PATH_FOR_REIMPORT_SAMPLE_REQUIREMENT
	//if( GetFileAttributesEx(lpcszDataFile, 0, &fad) )
	if( GetFileAttributesEx(cvt_predefined_path_to_real_path(lpcszDataFile), 0, &fad) )
	/// end IMPORT_SUPPORT_RELATIVE_PATH_FOR_REIMPORT_SAMPLE_REQUIREMENT
	{
		/// Hong 12/25/06 SAVE_TIME_IN_ORGANIZER_USE_LOCAL_TIME
		//SYSTEMTIME st;
		//if( FileTimeToSystemTime(&fad.ftLastWriteTime, &st) )
		FILETIME localFiletime;
		if( FileTimeToLocalFileTime(&fad.ftLastWriteTime, &localFiletime) )
			if( FileTimeToSystemTime(&localFiletime, &st) )
		/// end SAVE_TIME_IN_ORGANIZER_USE_LOCAL_TIME
				SystemTimeToJulianDate(&dJulianDate, &st);
	}
	else
		dJulianDate = 0.0;

	trFile.Info.FileName.strVal = GetFileName(lpcszDataFile);
	trFile.Info.FilePath.strVal = lpcszDataFile;
	trFile.Info.FileDate.dVal = dJulianDate;
	//------ Folger 11/17/07 LOCALIZE_IMPORT_FILE_INFO
	trFile.Info.FileName.SetAttribute(STR_LABEL_ATTRIB, _L("File Name"));
	trFile.Info.FilePath.SetAttribute(STR_LABEL_ATTRIB, _L("File Path"));
	trFile.Info.FileDate.SetAttribute(STR_LABEL_ATTRIB, _L("File Date"));
	//------ End LOCALIZE_IMPORT_FILE_INFO
	///Hong 8/03/06 CHANGE_FILE_TYPE_NUM_TO_STRING
	//trFile.Info.FileType.nVal = nFileType;
	switch(nFileType)
	{
	case FILTER_TYPE_ASCII:
		trFile.Info.FileType.strVal = STR_FILTER_TYPE_ASCII;
		break;
	case FILTER_TYPE_BINARY:
		trFile.Info.FileType.strVal = STR_FILTER_TYPE_BINARY;
		break;
	case FILTER_TYPE_USERDEFINED:
		trFile.Info.FileType.strVal = STR_FILTER_TYPE_USERDEFINED;
		break;
	case FILTER_TYPE_XFUNC:
		trFile.Info.FileType.strVal = STR_FILTER_TYPE_XFUNC;
		break;
	case FILTER_TYPE_UNKNOWN:
		trFile.Info.FileType.strVal = STR_FILTER_TYPE_UNKNOWN;
		break;
	default:
		break;
	}
	
	trFile.Info.FileType.SetAttribute(STR_LABEL_ATTRIB, _L("File Type"));		//------ Folger 11/17/07 LOCALIZE_IMPORT_FILE_INFO
	
	///end CHANGE_FILE_TYPE_NUM_TO_STRING
//	trFile.Info.FilterFile.strVal = "";
	//---- CPY 10/1/04 ADD_DATE_DISPLAY_INFO_FOR_WKBOOK_ORGANIZER
	tree_set_date_node(trFile.Info.FileDate);
	tree_set_date_node(trFile.Info.ImportDate);
	//----
	
	///---Sim 02-06-2007 ADD_RANGE_INFO_TO_BASE_INFO
	if ( NULL != (&trRange) )
	{
		trFile.Info.DataRange.Replace(trRange, TRUE, TRUE);
		///---Sim 03-07-2007 QA80-9435 ADD_DATA_ID_FOR_DATA_RANGE_TREE
		trFile.Info.DataRange.SetAttribute(STR_DATAID_ATTRIB, ID_FILEINFO_DATARANGE);
		///---END QA80-9435 ADD_DATA_ID_FOR_DATA_RANGE_TREE
		trFile.Info.DataRange.SetAttribute(STR_LABEL_ATTRIB, _L("Data Range"));		//------ Folger 11/17/07 LOCALIZE_IMPORT_FILE_INFO
	}
	///---END ADD_RANGE_INFO_TO_BASE_INFO
	
	return TRUE;
}
/// Hong 9/14/06 REMOVE_IMPORT_RELATED_TO_FU_UTILS
/*
int impinfo_HeaderVariablesToFileNode(TreeNode& tnFile, const StringArray& saVarNames, const StringArray& saVarValues)
{
	for( int n = 0; n < saVarNames.GetSize(); n++ )
		tnFile.Variables.Header.AddTextNode(saVarValues[n], saVarNames[n]);
	return 0;
}

int impinfo_FileNameVariablesToFileNode(TreeNode& tnFile, const StringArray& saVarNames, const StringArray& saVarValues)
{
	for( int n = 0; n < saVarNames.GetSize(); n++ )
		tnFile.Variables.FileName.AddTextNode(saVarValues[n], saVarNames[n]);
	return 0;
}

///Hong 8/04/06 ADD_FILTER_INFO
//bool impinfo_AddFile(Layer& lyTarget, LPCSTR lpcszDataFile, TreeNode& tnInfo, int nImportMode, int nImportType)
bool impinfo_AddFile(Layer& lyTarget, LPCSTR lpcszDataFile, TreeNode& tnInfo, int nImportMode, int nImportType, TreeNode& trFilter)
///edn ADD_FILTER_INFO
{
	Page pgTarget;
	lyTarget.GetParent(pgTarget);
	if( pgTarget )
	{
		impinfo_InitTree(pgTarget, nImportMode);
	
		Tree trFile;
		impinfo_GetLastFileNode(pgTarget, trFile);
		impinfo_FileInfoToFileNode(trFile, lpcszDataFile, nImportType);
		
		if( tnInfo )
		{
			TreeNode trNode = tnInfo.FirstNode;
			while( trNode )
			{
				trFile.AddNode(trNode, true);
				trNode = trNode.NextNode;
			}
		}
		///Hong 8/04/06 ADD_FILTER_INFO
		if( trFilter )
		{
			////  AW 08/23/06 ADD_FILTER_FILENAME
			trFile.Info.FilterFileName.strVal = trFilter.FileName.strVal; 
			if ( FILTER_TYPE_XFUNC == nImportType )
			{
				//trFile.Info.FileType.strVal = trFilter.XFunction.Name.strVal;	
				trFile.Info.FileType.strVal = trFilter.XFunction.strName.strVal;//Hong 9/11/06 GET_NAME_USE_NEW_STRUCTURE	
			}
			/// END ADD_FILTER_FILENAME
				
			TreeNode trFilterInfo = trFile.AddNode("FilterInfo");
			TreeNode trNode1 = trFilter.FirstNode;
			while( trNode1 )
			{
				trFilterInfo.AddNode(trNode1, true);
				trNode1 = trNode1.NextNode;
			}
		}
		///edn ADD_FILTER_INFO
		impinfo_SetLastFileNode(pgTarget, trFile);
		return true;
	}
	return false;
}
#endif // _OC_VER >= 0x0800
/// end XFUNC_BASED_IMPORT
*/
/// end REMOVE_IMPORT_RELATED_TO_FU_UTILS

///---Sim 08-29-2006 SUPPORT_GET_VALUE_USE_REFERENCE
/*
///Hong 8/24/06 MOVE_OFILTER_UTILS_TO_TREE_UTILS
int tree_get_int_value_by_id(const TreeNode& tr, int nID, int nDefault)
{
	int nVal = nDefault;
	TreeNode trFind;
	bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
	if(bRet)
		nVal = trFind.nVal;
	return nVal;
}
bool tree_set_int_value_by_id(TreeNode& tr, int nID, int nVal)
{
	TreeNode trFind;
	bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
	if(bRet)
		trFind.nVal = nVal;
	return bRet;
}
double tree_get_double_value_by_id(const TreeNode& tr, int nID, double dDefault)
{
	double dVal = dDefault;
	TreeNode trFind;
	bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
	if(bRet)
		dVal = trFind.dVal;
	return dVal;
}
bool tree_set_double_value_by_id(TreeNode& tr, int nID, double dVal)
{
	TreeNode trFind;
	bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
	if(bRet)
		trFind.dVal = dVal;
	return bRet;
}
bool tree_get_string_value_by_id(const TreeNode& tr, int nID, string strDefault)
{
	TreeNode trFind;
	bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
	if(bRet)
		strVal = trFind.strVal;
	return bRet;
}
bool tree_set_string_value_by_id(TreeNode& tr, int nID, LPCSTR szVal)
{
	TreeNode trFind;
	bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
	if(bRet)
		trFind.strVal = szVal;
	return bRet;
}
BOOL tree_get_flag_value_by_id(const TreeNode& tr, DWORD dwFlag, BOOL bDefault) // = 0
{
	int nValue;
	TreeNode trFind;
	if(octree_get_node_by_id(&tr, &trFind, IDE_FLT_FLAGS, true))
	{
		nValue = trFind.nVal; 
		DWORD dwFlags = (DWORD)nValue;
		return (dwFlags & dwFlag ? TRUE : FALSE);
	}
	return bDefault;
}

bool tree_set_flag_value_by_id(TreeNode& tr, DWORD dwFlag, BOOL bSet) // = TRUE
{

	int nValue;
	TreeNode trFind;
	bool bRet = octree_get_node_by_id(&tr, &trFind, IDE_FLT_FLAGS, true);
	if(bRet)
	{
		nValue = 0;
		DWORD dwFlags = (DWORD)nValue;
		if( bSet )
			dwFlags |= dwFlag;
		else
			dwFlags &= ~dwFlag;
		nValue = dwFlags;
		trFind.nVal = nValue;
	}
	return bRet;
}
///end MOVE_OFILTER_UTILS_TO_TREE_UTILS
*/
bool tree_getr_int_value_by_id(const TreeNode &tr, int nID, int &nVal)
{
	///---Sim 09-13-2006 CHECK_TREE_NODE
	bool bRet = false;
	if ( tr && tr.IsValid() )
	{
		TreeNode trFind;
		//bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		if(bRet)
			nVal = trFind.nVal;
	}
	///---END CHECK_TREE_NODE
	return bRet;
}
int tree_get_int_value_by_id(const TreeNode &tr, int nID, int nDefault)// = 0
{
	int nVal = nDefault;
	///---Sim 09-13-2006 CHECK_TREE_NODE will check in calling function
	//if(tr)	//CPY 9/12/2006 IMP_WAV_SEE_RUNTIME_ERR, added check for tr, as it might be invalid if trFilter is not specified
	///---END CHECK_TREE_NODE
	tree_getr_int_value_by_id(tr, nID, nVal);
	return nVal;
}
bool tree_set_int_value_by_id(TreeNode &tr, int nID, int nVal)
{
	///---Sim 09-13-2006 CHECK_TREE_NODE
	bool bRet = false;
	if ( tr && tr.IsValid() )
	{
		TreeNode trFind;
		//bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		if(bRet)
			trFind.nVal = nVal;
	}
	///---END CHECK_TREE_NODE
	return bRet;
}

bool tree_getr_double_value_by_id(const TreeNode &tr, int nID, double &dVal)
{
	///---Sim 09-13-2006 CHECK_TREE_NODE
	bool bRet = false;
	if ( tr && tr.IsValid() )
	{
		TreeNode trFind;
		//bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		if(bRet)
			dVal = trFind.dVal;
	}
	///---END CHECK_TREE_NODE
	return bRet;
}
double tree_get_double_value_by_id(const TreeNode &tr, int nID, double dDefault)// = 0.0
{
	double dVal = dDefault;
	tree_getr_double_value_by_id(tr, nID, dVal);
	return dVal;
}
bool tree_set_double_value_by_id(TreeNode &tr, int nID, double dVal)
{
	///---Sim 09-13-2006 CHECK_TREE_NODE
	bool bRet = false;
	if ( tr && tr.IsValid() )
	{
		TreeNode trFind;
		//bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		if(bRet)
		{
			trFind.dVal = dVal;
			trFind.ID = TRGP_DOUBLE;		/// AW 05/02/07 QA80-9716 v8.0612 FIX_fuSetDouble_DISPLAY_PROBLEM
		}
	}
	///---END CHECK_TREE_NODE
	return bRet;
}

bool tree_getr_string_value_by_id(const TreeNode &tr, int nID, string &strVal)
{
	///---Sim 09-13-2006 CHECK_TREE_NODE
	bool bRet = false;
	if ( tr && tr.IsValid() )
	{
		TreeNode trFind;
		//bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		if(bRet)
			strVal = trFind.strVal;
	}
	///---END CHECK_TREE_NODE
	return bRet;
}
string tree_get_string_value_by_id(const TreeNode &tr, int nID, string strDefault)// = ""
{
	string strVal = strDefault;
	tree_getr_string_value_by_id(tr, nID, strVal);
	return strVal;
}
bool tree_set_string_value_by_id(TreeNode &tr, int nID, LPCSTR szVal)
{
	///---Sim 09-13-2006 CHECK_TREE_NODE
	bool bRet = false;
	if ( tr && tr.IsValid() )
	{
		TreeNode trFind;
		//bool bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		bRet = octree_get_node_by_id(&tr, &trFind, nID, true);
		if(bRet)
			trFind.strVal = szVal;
	}
	///---END CHECK_TREE_NODE
	return bRet;
}
bool tree_getr_flag_value_by_id(const TreeNode &tr, DWORD dwFlag, BOOL &bSet)
{
	///---Sim 09-13-2006 CHECK_TREE_NODE
	bool bRet = false;
	if ( tr && tr.IsValid() )
	{
		int nValue;
		TreeNode trFind;
		//bool bRet = octree_get_node_by_id(&tr, &trFind, IDE_IMP_FLAGS, true);
		bRet = octree_get_node_by_id(&tr, &trFind, IDE_IMP_FLAGS, true);
		if(bRet)
		{
			nValue = trFind.nVal; 
			DWORD dwFlags = (DWORD)nValue;
			bSet = (dwFlags & dwFlag ? TRUE : FALSE);
		}
	}
	///---END CHECK_TREE_NODE
	return bRet;
}
BOOL tree_get_flag_value_by_id(const TreeNode &tr, DWORD dwFlag, BOOL bDefault) // = 0
{
	BOOL bSet = bDefault;
	tree_getr_flag_value_by_id(tr, dwFlag, bSet);
	return bSet;
}
bool tree_set_flag_value_by_id(TreeNode &tr, DWORD dwFlag, BOOL bSet) // = TRUE
{
	///---Sim 09-13-2006 CHECK_TREE_NODE
	bool bRet = false;
	if ( tr && tr.IsValid() )
	{
		int nValue;
		TreeNode trFind;
		//bool bRet = octree_get_node_by_id(&tr, &trFind, IDE_IMP_FLAGS, true);
		bRet = octree_get_node_by_id(&tr, &trFind, IDE_IMP_FLAGS, true);
		if(bRet)
		{
			nValue = trFind.nVal; 
			DWORD dwFlags = (DWORD)nValue;
			if( bSet )
				dwFlags |= dwFlag;
			else
				dwFlags &= ~dwFlag;
			nValue = dwFlags;
			trFind.nVal = nValue;
		}
	}
	///---END CHECK_TREE_NODE
	return bRet;
}
///---END SUPPORT_GET_VALUE_USE_REFERENCE



/// ML 10/7/2004 MULTIPLE_DATASET_OPER_TREATMENT
// Returns a value from MDINPUT_* enum.
// Optionally it puts into *pnOutMode a value from MDOUT_*. 
int		tree_get_oper_multidata_modes(TreeNode &trGUI, int *pnOutMode)
{
	int		modeMDInput = MDINPUT_DEFAULT;
	if ( trGUI.InputData.IsValid() )
	{
		modeMDInput = trGUI.InputData.Use;
		
		/// YuI 12/04/06 can not blindly use nUse
		// have to do some translation depending on contents of combo
		// may move to VC so that function populating combo and doing 
		//	translation is either the same or close in code (easier to maintain)
		int nDataMode = 0;
		if( trGUI.InputData.GetAttribute(STR_INPUT_DATA_MODE_ATTRIB, nDataMode) )
		{
			//---- Iris 12/15/2006 v8.0526 SEPARATE_REPORT_BROKEN_IN_NLSF
			//if( nDataMode >= INPUTDATA_RANGES_CAN_COMBINE && modeMDInput == MDINPUT_INDEPENDENT_SEPARATE )
			if( nDataMode == INPUTDATA_RANGES_CAN_COMBINE && modeMDInput == MDINPUT_INDEPENDENT_SEPARATE )
			//----
			{
				modeMDInput = MDINPUT_CMBND_SIMPLE;
			}
		}
		/// end YuI
	}
	
	if ( pnOutMode )
	{
		//if (modeMDInput == MDINPUT_INDEPENDENT)
		if( modeMDInput == MDINPUT_INDEPENDENT_SEPARATE)	/// Iris 1/26/06 QA70-8388 INDEP_DATA_CONSOLID_OR_SEP_REPORT
		{
			if ( trGUI.Output.IsValid() )
			{
				*pnOutMode = trGUI.Output.Use;
			}
			else
			{
				*pnOutMode = MDOUT_DEFAULT;
			}
		}
		else
		{
			*pnOutMode = MDOUT_CONSOLIDATED;
		}
	}
	
	return modeMDInput;
}

bool tree_is_true(const TreeNode& tr, LPCSTR lpcszTag)
{
	TreeNode trN;
	if(NULL == lpcszTag)
		trN = tr;
	else
		trN = tr.GetNode(lpcszTag);	
	
	if(trN && trN.ID != TRGP_BRANCH)
		return trN.nVal;	
	if(trN && trN.ID == TRGP_BRANCH)
		return trN.Use;
	
	return false;
}

///Joseph 03/01/07 GET_SUBNODE_INDEX_FROM_TAGNAME
//if there is subnode which tagname is the proper name, return the index, else return -1;
int tree_get_subnode_index(TreeNode& trParent, LPCSTR lpcszName)
{
	string strName(lpcszName);
	if(!trParent || trParent.GetNodeCount() <= 0 || (strName.IsEmpty()))
		return -1;
	
	if(strName.IsEmpty())
		return -1;
	int nIndex = 0;
	foreach(TreeNode trNode in trParent.Children)
	{
		if(strName.Compare(trNode.tagName) == 0)
			return nIndex;
		nIndex++;
	}
	return -1;
}
///End GET_SUBNODE_INDEX_FROM_TAGNAME


///Sandy 2007-3-12 move from xfgraph_utils.h
//add to check node by dataid
bool tree_check_get_node_by_dataid(TreeNode& trParent, TreeNode& trNew, LPCSTR lpcszTag, int nDataID, int nID, LPCSTR lpcszLableAttrib) // = 0 = NULL = NULL
{

	string strLabel(lpcszLableAttrib);
	
	if(strLabel.IsEmpty())
		strLabel = lpcszTag;
	
	trNew = tree_get_node_by_dataid(trParent, nDataID);
	

	if(!trNew)
	{
		///----- Leo 2006-3-8 SAME_TAG_NAME_BUG
		//trNew  = tree_check_get_node(trParent, lpcszTag, nID, STR_LABEL_ATTRIB, strLabel );
		
		trNew = trParent.AddNode(lpcszTag);
		
		trNew.SetAttribute(STR_LABEL_ATTRIB, strLabel);
		
		//----- end
		
		trNew.DataID = nDataID;
		
		return false;
	}

	return true;

}


//-------- CPY 5/7/07 AUTO_TO_USE_IN_GENERAL_GETN
int tree_check_replace_auto(TreeNode& tr, double dValToReplace)
{
	int nRet = octree_get_auto_support(&tr);
	if(1==nRet)
		tr.dVal = dValToReplace;
	
	return nRet;
}
//--------

//----- Iris 06/01/2007 v8.0631 want to use them in xf, so moved from wksOperation.c
void	tree_add_more_labels(TreeNode &trParent, vector<string> &vstrFactors, int nStartIndex, LPCSTR lpcszLastLabel) //=0,NULL
{
	string		strAttName;
	int			nNumFactors = vstrFactors.GetSize();
	for (int ifct = nStartIndex; ifct < nNumFactors; ifct++)
	{
		strAttName.Format(STR_SUB_HEADER_ATTRIB_PREFIX "%d", ifct);
		trParent.SetAttribute(strAttName, vstrFactors[ifct]);
	}
	
	if(lpcszLastLabel) //CPY 6/8/04 
	{
		strAttName.Format(STR_SUB_HEADER_ATTRIB_PREFIX "%d", ifct);
		trParent.SetAttribute(strAttName, lpcszLastLabel);
	}
}

// This function can set both STR_LABEL_ATTRIB (if index < 0) and DATAFACT_ATTRIBUTE_PREFIX<index> 
// attributes which are used for column/row headings
void	tree_add_one_label(TreeNode &trParent, LPCTSTR lpcszLabel, int index)
{
	string		strAttName;
	if (index < 0)
		strAttName = STR_LABEL_ATTRIB;
	else
		strAttName.Format(STR_SUB_HEADER_ATTRIB_PREFIX "%d", index);
	
	trParent.SetAttribute(strAttName, lpcszLabel);
}
//-----

///---Sim 06-07-2007 SUPPORT_RENAME_TREE_TAGNAME
bool tree_rename_tags(TreeNode& trRoot, const StringArray& saOldTagNames, const StringArray& saNewTagNames)
{
	if ( !trRoot )
		return false;
	if ( 0 == trRoot.GetNodeCount() )
		return true;
	
	Tree trNew;
	//trNew.Replace(trRoot.Clone(), FALSE);
	TreeNode trNodeNew = trNew;
	
	string strTagName;
	int nIndex;
	
	TreeNode trNode = trRoot.FirstNode;
	
	// deep travel
	int nLevel = 1;
	while ( nLevel > 0 )
	{
		strTagName = trNode.tagName;
		// replace tagname
		nIndex = saOldTagNames.Find(strTagName);
		if ( nIndex >= 0 )
			strTagName = saNewTagNames[nIndex];
		
		// copy node data
		TreeNode tr = trNodeNew.AddNode(strTagName);
		tr.Replace(trNode, FALSE, TRUE);
		
		// find next node
		if ( trNode.FirstNode ) // next level
		{	
			trNode = trNode.FirstNode;
			trNodeNew = tr;
			nLevel++;
		}
		else if ( trNode.NextNode ) // same level
		{	
			trNode = trNode.NextNode;
		}
		else // previous level
		{	
			do
			{
				trNode = trNode.Parent();
				trNodeNew = trNodeNew.Parent();
				nLevel--;				
			}while ( !trNode.NextNode && nLevel > 0 );
			
			trNode = trNode.NextNode;			
		}
	}
	
	//trRoot.Replace(trNew.Clone(), TRUE);
	trRoot.Replace(trNew, TRUE, TRUE, TRUE);
	
	return true;
}
///---END SUPPORT_RENAME_TREE_TAGNAME


//----Jake 06/26/07 SUPPORT_COMBO_LIST_FOR_PATH
/// Hong 10/26/07 QA80-10364 PATH_CTRL_SHOULD_NOT_APEEND_FILENAME
//bool tree_set_browse_combo_attrib(TreeNode trNode, LPCSTR lpcszClassName, bool bIncSpecialFolder)
bool tree_set_browse_combo_attrib(TreeNode trNode, LPCSTR lpcszClassName, bool bIncSpecialFolder, bool bAppendFilename) // = NULL, true, true
/// end PATH_CTRL_SHOULD_NOT_APEEND_FILENAME
{
	//----Jake 06/28/07 SET_LAST_XFNAME_AS_DEFAULT_KEY_NAME
	string strClassName = lpcszClassName;
	if(strClassName.IsEmpty())
	{
		char szLastXFName[MAXFULLPATH];
		LT_get_str(LTVAR_LAST_XF, szLastXFName, MAXFULLPATH);
		strClassName = szLastXFName;
	}
	//----end SET_LAST_XFNAME_AS_DEFAULT_KEY_NAME
	
	string	strAttr;
	if(!trNode.GetAttribute(STR_COMBO_ATTRIB, strAttr))
		return false;
	///---Sim 07-02-2007 FIX_DUPLICATE_RECENT_FILE_LIST
	//strAttr += "|:|";
	int nPos;
	nPos = strAttr.Find(STR_ATTR_BROWSE_COMBO_LIST_DELIMITER);
	if ( nPos >= 0 )
	{
		strAttr = strAttr.Left(nPos); // remove last recent list
	}
	
	strAttr += STR_ATTR_BROWSE_COMBO_LIST_DELIMITER;
	///---END FIX_DUPLICATE_RECENT_FILE_LIST
	
	vector<string> vsPathList;
	/// Iris 07/03/2007 v8.0654 USAGE_OF_BROWSER_COMBO_NOT_CONSISTENT_IN_FILE_AND_PATH_CONTROL
	//get_path_list(strClassName, vsPathList,bOnlyRecent);
	string	strPath = trNode.strVal;
	strPath = cvt_predefined_path_to_real_path(strPath);
	///Jasmine 07/04/07 DONOT_SET_COMBO_ATTRIB_IF_GET_NO_PATH
	/// Hong 10/26/07 QA80-10364 PATH_CTRL_SHOULD_NOT_APEEND_FILENAME
	//if(1 > get_path_list(strClassName, vsPathList,bIncSpecialFolder, GetFileName(strPath)))
	string strFilename = bAppendFilename ? GetFileName(strPath) : "";
	if(1 > get_path_list(strClassName, vsPathList,bIncSpecialFolder, strFilename))
	/// end PATH_CTRL_SHOULD_NOT_APEEND_FILENAME
		return false;
	//End DONOT_SET_COMBO_ATTRIB_IF_GET_NO_PATH
	///end USAGE_OF_BROWSER_COMBO_NOT_CONSISTENT_IN_FILE_AND_PATH_CONTROL
	
	string strListString;
	strListString.SetTokens(vsPathList,'|');
	strListString.Insert(0,strAttr);
	
	trNode.ID = ONODETYPE_BROWSECOMBO;
	trNode.SetAttribute(STR_COMBO_ATTRIB, strListString);
	return true;
}
//----end SUPPORT_COMBO_LIST_FOR_PATH

///---Sim 12-23-2008 QA80-12836 SUPPORT_FILE_BROWSER_BUTTON
bool tree_set_file_browse_combo_attrib(TreeNode trNode, const vector<string>& vsFiles)
{
	string	strAttr;
	if(!trNode.GetAttribute(STR_COMBO_ATTRIB, strAttr))
		return false;
	
	int nPos;
	nPos = strAttr.Find(STR_ATTR_BROWSE_COMBO_LIST_DELIMITER);
	if ( nPos >= 0 )
	{
		strAttr = strAttr.Left(nPos); // remove last recent list
	}
	
	strAttr += STR_ATTR_BROWSE_COMBO_LIST_DELIMITER;
	
	string strListString;
	strListString.SetTokens(vsFiles,'|');
	strListString.Insert(0,strAttr);
	
	trNode.ID = ONODETYPE_BROWSECOMBO;
	trNode.SetAttribute(STR_COMBO_ATTRIB, strListString);
	return true;
}
bool tree_set_file_browse_combo_more_attrib(TreeNode trNode, LPCSTR lpcszPath, LPCSTR lpcszFileFilter)
{
	string	strAttr;
	if(!trNode.GetAttribute(STR_COMBO_ATTRIB, strAttr))
		return false;
	
	if ( lpcszPath )
	{
		trNode.SetAttribute(STR_BROWSER_COMBO_FILE_PATH, lpcszPath);
	}
	
	int nExtGroupEnd = strAttr.Find(STR_ATTR_BROWSE_COMBO_LIST_DELIMITER);
	if ( nExtGroupEnd >= 0 )
	{
		int nExtGroupBegin = strAttr.Find(STR_ATTR_FILE_EXT_GROUP_DELIMITER);
		if ( nExtGroupBegin >= 0 && nExtGroupBegin < nExtGroupEnd )
		{
			//nExtGroupBegin += strlen(STR_ATTR_FILE_EXT_GROUP_DELIMITER);
			strAttr.Delete(nExtGroupBegin, nExtGroupEnd - nExtGroupBegin);
			nExtGroupEnd = nExtGroupBegin;
		}
		
		string strExtFilter;
		strExtFilter += STR_ATTR_FILE_EXT_GROUP_DELIMITER;
		strExtFilter += lpcszFileFilter;
		strAttr.Insert(nExtGroupEnd, strExtFilter);
		
		if( !trNode.SetAttribute(STR_COMBO_ATTRIB, strAttr) )
			return false;
		return true;
	}
	
	return false;
}
///---END QA80-12836 SUPPORT_FILE_BROWSER_BUTTON

/// Iris 07/03/2007 v8.0654 USAGE_OF_BROWSER_COMBO_NOT_CONSISTENT_IN_FILE_AND_PATH_CONTROL
/*
///Jake 06/28/07 MOVE_CODE_FROM_EXPORT_XFS
//---Jake 06/27/07 STORE_USER_FILE_NAME
void tree_set_only_file_name_attrib(TreeNode& trPath, LPCSTR lpcszFileName)
{
	string strOnlyFileName = GetFileName(lpcszFileName);
	trPath.SetAttribute(STR_ONLY_FILENAME_ATTRIB,strOnlyFileName);
}
//---end STORE_USER_FILE_NAME

//----Jake 06/28/07 SET_PATH_STRING_TO_GETNTREE
bool tree_check_set_real_path(TreeNode& trPath)
{
	string		strPath = trPath.strVal;
	int nID = okutil_cvt_str_to_predefined_type(strPath);
	if( nID != PDS_INVALID && nID != PDS_USER)
	{
		strPath = cvt_predefined_path_to_real_path(strPath);
		string strFileName;
		if(!trPath.GetAttribute(STR_ONLY_FILENAME_ATTRIB,strFileName))
			return false;
		strPath = GetFilePath(strPath) + strFileName;
		trPath.strVal = strPath;
	}
	return true;
}
//----end SET_PATH_STRING_TO_GETNTREE
///end MOVE_CODE_FROM_EXPORT_XFS
*/
///end USAGE_OF_BROWSER_COMBO_NOT_CONSISTENT_IN_FILE_AND_PATH_CONTROL

///Arvin 01/07/08 QA70-10903 ADD_CHECK_ALL_BOX_FOR_BRANCH
bool tree_set_branch_attribute_for_branch(TreeNode& trBranch, int dwBranchAttr)
{
	if(!trBranch || trBranch.Children.Count() < 1)
		return false;
	
	int dwAttrTemp = 0;
	trBranch.GetAttribute(STR_ATTRIB_BRANCH, dwAttrTemp);
	dwBranchAttr |= dwAttrTemp;
	trBranch.SetAttribute(STR_ATTRIB_BRANCH, dwBranchAttr);
	return true;
}
///END ADD_CHECK_ALL_BOX_FOR_BRANCH	

/// Iris 4/23/2008 NOT_GENERAGE_TABLE_IF_NOT_REPORT_TO_IMPROVE_NLSF_SPEED
bool	tree_GUI_are_all_uncheck(const TreeNode& trBranch)
{	
	bool		bNoChecked = true;	
	
	if(	!trBranch )
		return bNoChecked;// branch is valid means no this node on GUI, then no checked node of course
	
	int			nUse;
	if( trBranch.GetAttribute(STR_USE_ATTRIB, nUse) && 0 == nUse)
		return bNoChecked;
	
	foreach(TreeNode trN in trBranch.Children)
	{
		if( (trN.ID == TRGP_CHECK || trN.ID == TRGP_BRANCH)
			&& tree_is_true(trN) 
			&& trN.Show ) //no check hidden node since this funciton only work on GUI node
			{
				bNoChecked = false;
			}
	}
	
	return bNoChecked;
}
///end NOT_GENERAGE_TABLE_IF_NOT_REPORT_TO_IMPROVE_NLSF_SPEED

/// Hong 10/24/08 v8.0960b FIX_NEW_NLFIT_FUNCTION_LIST_LOST_ITEM_NEW_DOT_DOT_DOT
bool	tree_is_editable(const TreeNode& trNode)
{
	if ( !trNode )
		return false;
	/// Hong 11/14/08 v8.0971b DISABLE_OPTIONS_INSTEAD_OF_HIDDEN_IT_FOR_BASELINE_OUTPUT_OPTIONS
	/*
	int		nAttribVal;
	if ( trNode.GetAttribute(STR_ENABLE_ATTRIB, nAttribVal) && ENABLE == nAttribVal )
		return true;
	
	return false;
	*/
	int		nAttribVal;
	if ( trNode.GetAttribute(STR_ENABLE_ATTRIB, nAttribVal) && ENABLE != nAttribVal )
		return false;
	
	return true;
	/// end DISABLE_OPTIONS_INSTEAD_OF_HIDDEN_IT_FOR_BASELINE_OUTPUT_OPTIONS
}
/// end FIX_NEW_NLFIT_FUNCTION_LIST_LOST_ITEM_NEW_DOT_DOT_DOT

/// Hong 11/14/08 v8.0971b DISABLE_OPTIONS_INSTEAD_OF_HIDDEN_IT_FOR_BASELINE_OUTPUT_OPTIONS
bool	tree_is_visible(const TreeNode& trNode)
{
	if ( !trNode )
		return false;
	BOOL		bShow;
	if ( trNode.GetAttribute(STR_SHOW_ATTRIB, bShow) &&  TRUE != bShow )
		return false;
	
	return true;
}
/// end DISABLE_OPTIONS_INSTEAD_OF_HIDDEN_IT_FOR_BASELINE_OUTPUT_OPTIONS

///Kyle 10/31/08 QA80-12452  SUPPORT_INPUT_DATA_FORM_OPTION_FOR_NPH_TESTS
BOOL	tree_stats_convert_input_data_indexed_raw(TreeNode& tr, int nType)
{
	int nOption = 0;
	tr.GetAttribute(STR_INTERACTIVE_CONTROL_OPTIONS_ATTRIB, nOption);
	switch( nType )
	{
		case SIDT_INVAR:
			tr.SetAttribute(STR_COMBO_ATTRIB, "");
			tr.SetAttribute(STR_ATT_XFGETN_RANGE_DESIGS, "X");
			tr.SetAttribute(STR_INTERACTIVE_CONTROL_OPTIONS_ATTRIB, nOption & ~(ICOPT_RESTRICT_TO_ONE_DATA | ICOPT_ALLOW_MULTIPLE_DATA_2));
			break;
		case SIDT_INGROUP:
			tr.SetAttribute(STR_COMBO_ATTRIB, _L("Group Range|Data Range"));
			tr.SetAttribute(STR_ATT_XFGETN_RANGE_DESIGS, "FX");
			tr.SetAttribute(STR_INTERACTIVE_CONTROL_OPTIONS_ATTRIB, nOption | ICOPT_RESTRICT_TO_ONE_DATA | ICOPT_ALLOW_MULTIPLE_DATA_2);
			break;
		break;
	}
	return FALSE;
}
///End SUPPORT_INPUT_DATA_FORM_OPTION_FOR_NPH_TESTS

///Kyle 03/31/2009 QA80-3224 NEW_OPTION_TO_SUPPORT_LINEAR_FIT_WITH_ERROR_BAR
void tree_uncheck_all_hidden_check_boxes(TreeNode tr, bool bIsParentHidden)
{
	if(!tr)
		return;

	if(bIsParentHidden || !tr.Show)			// hidden node
	{
		if(tr.ID == TRGP_BRANCH)			// branch
		{
			int			nUse;
			if( tr.GetAttribute(STR_USE_ATTRIB, nUse) && nUse)
				tr.Use = 0;
		}
		else if(tr.ID == TRGP_CHECK)		// 
			tr.nVal = 0;
	}

	bIsParentHidden = bIsParentHidden || !tr.Show;

	foreach(TreeNode trn in tr.Children)
		tree_uncheck_all_hidden_check_boxes(trn, bIsParentHidden);
}
///End NEW_OPTION_TO_SUPPORT_LINEAR_FIT_WITH_ERROR_BAR
