/*------------------------------------------------------------------------------*
 * File Name: LTCustomMenuEditorDlg.c											*
 * Creation: Kenny 04/14/2009													*
 * Purpose: OriginC Source file													*
 * Copyright (c) OriginLab Corp. 2009											*
 * All Rights Reserved															*
 *																				*
 * Modification Log:															*
 *	Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS					*
 *	Kyle 06/08/2009 QA70-13423 SUPORT_GET_MENU_TEXT_FROM_OC						*
 *	Kyle 06/12/2009 QA70-13423 NEW_TAB_FOR_EDITING_OMC_LIST						*
 *	Kyle 12/16/2009 QA80-14794-P3 WRONG_SELECTED_LEVEL_AFTER_REORDER			*
 *	Sim 01-22-2010 QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU					*
 *	CPY 2012-02-12 CHANGE_CUSTOM_MENU_DEFAULT_TO_INSERT							*
 *	ML 2/15/2010 QA70-15113 81SR1_OMC_FILES_SHOULD_ALWAYS_APPEND_BUT_NEW_SHOULD_INSERT_BEFORE_WINDOW
 *	Kyle 02/26/2010 QA80-15138 KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC
 *------------------------------------------------------------------------------*/

#include <Origin.h>
#include "DialogEx.h"

#include "INIFileEx.h"		///Kyle 06/12/2009 QA70-13423 NEW_TAB_FOR_EDITING_OMC_LIST

#include "SplitterControl.h"
#include "DynaSplitter.h"
#include "GridTableControl.h"
#include <Array.h>

/*----------------------------------------------------------------------------*/
/* Global Macros/Enums/Defines
/*----------------------------------------------------------------------------*/

#define STR_DLG_NAME_E 							"Custom Menu Organizer"
#define STR_DLG_NAME 							_L(STR_DLG_NAME_E)

////////////////////////////////////////////////////////////////////////////////
// shared marco with VC level
// will be moved to OC_const.h later
////////////////////////////////////////////////////////////////////////////////
#define STR_CUSTOM_MENUS_XML					"LTCustomMenus.xml"

#define STR_CUSTOM_MENU_DEFAULT_ROOT			"Custom Menu"

#define STR_TAG_NAME_PREFIX_MENUITEM			"item"
#define STR_TAG_NAME_PREFIX_POPUP				"popup"
#define STR_TAG_NAME_PREFIX_SEPARATOR			"sep"

// sub node of menu item
#define STR_MENUITEM_TAG_NAME_MENU_TEXT			"menutext"
#define STR_MENUITEM_TAG_NAME_LT_SCRIPT			"LT"
#define STR_MENUITEM_TAG_NAME_LT_ENABLE			"LTEnable"
#define STR_MENUITEM_TAG_NAME_TOOL_BUTTON		"tlb"
#define STR_MENUITEM_TAG_NAME_PROMPT			"Prompt"

// attribute of popup
#define STR_POPUP_TEXT_ATTRIB					"text"
#define STR_POPUP_TAG_ATTRIB					"tag"
#define STR_WINDOW_TYPE_ATTRIB					"wndType"
#define STR_FILE_ENABLE_ATTRIB					"FileEnable"

#define CUSTOM_MENU_MAX_MAIN_POPUP				3			///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS

///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
#define CUSTOM_MENU_MAX_COMMAND_ITEMS			0x2F		// only 48 ids for custom menus of each wnd type
#define CUSTOM_MENU_MAX_SUB_POPUP				CUSTOM_MENU_MAX_COMMAND_ITEMS			// not including the main popups
#define CUSTOM_MENU_MAX_SEPARATOR				CUSTOM_MENU_MAX_COMMAND_ITEMS

#define CUSTOM_MENU_MAX_POPUP_DEPTH				4
///End CHECK_NUMBERS_OF_EACH_MENU_TYPE


////////////////////////////////////////////////////////////////////////////////

///Kyle 06/12/2009 QA70-13423 NEW_TAB_FOR_EDITING_OMC_LIST
#define STR_SPLITTER_DISABLE_TIPS				_L("No OMC Configs, Please go to the first tab to add some configs")
///End NEW_TAB_FOR_EDITING_OMC_LIST

#define STR_ROW_LIST_TOOL_TIPS					_L("Right-click to add/insert/delete menu")

#define STR_MENU_ITEM_SEPARATOR					_L("----- Separator -----")

#define STR_HINT_NO_MAIN_POPUP					_L("Please right click the left panel to add Popup.|Maximum main popup menus are 3.|Maximum sub popup menus, command items and separators are 48.|Maximum depth of popup menus is 5")
#define STR_NO_SELECTION						_L("No Selection")

// Please do NOT change the order and value of these enum elements'!!
enum NodeTagType
{
	MENU_NODE_TAG_INVALID		= -1, 

	MENU_NODE_TAG_POPUP			= 0, 
	MENU_NODE_TAG_ITEM			= 1, 
	MENU_NODE_TAG_SEP			= 2,

	MENU_NODE_TAG_TEXT			= 3, 
	MENU_NODE_TAG_LT			= 4, 
	MENU_NODE_TAG_LT_ENABLE		= 5,
	MENU_NODE_TAG_TLB			= 6,
	MENU_NODE_TAG_PROMPT		= 7,
};

enum AttribType
{
	ATTRIB_TYPE_INVALID			= -1,
	ATTRIB_TYPE_POPUP_TEXT		= 0,
	ATTRIB_TYPE_POPUP_TAG		= 1,
	ATTRIB_TYPE_WND_TYPE		= 2,
};

#define TRIM_EXTRA_TREE_NODE

enum ContextMenuCmd
{
	CUSTOM_MENU_INVALID 			= 0,					///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
	CUSTOM_MENU_ADD_ITEM,
	CUSTOM_MENU_ADD_SEPARATOR,
	CUSTOM_MENU_ADD_POPUP,

	CUSTOM_MENU_INSERT_ITEM,
	CUSTOM_MENU_INSERT_SEPARATOR,
	CUSTOM_MENU_INSERT_POPUP,
	
	CUSTOM_MENU_DUPLICATE,
	CUSTOM_MENU_MOVE_TO,
	CUSTOM_MENU_DELETE,
	
	CUSTOM_MENU_CUT,
	CUSTOM_MENU_COPY,
	CUSTOM_MENU_PASTE_BEFORE,
	CUSTOM_MENU_PASTE_AFTER,
	CUSTOM_MENU_PASTE_INSIDE,
	
	CUSTOM_MENU_NEW_MAIN_POPUP,								///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
};
#define STR_CUSTOM_MENU_INVALID						""
#define STR_CUSTOM_MENU_ADD_ITEM				_L("Add Item")
#define STR_CUSTOM_MENU_ADD_SEPARATOR			_L("Add Separator")
#define STR_CUSTOM_MENU_ADD_POPUP				_L("Add Popup")
#define STR_CUSTOM_MENU_INSERT_ITEM				_L("Insert Item")
#define STR_CUSTOM_MENU_INSERT_SEPARATOR		_L("Insert Separator")
#define STR_CUSTOM_MENU_INSERT_POPUP			_L("Insert Popup")
#define STR_CUSTOM_MENU_DUPLICATE				_L("Duplicate")
#define STR_CUSTOM_MENU_MOVE_TO					_L("Move To")
#define STR_CUSTOM_MENU_DELETE					_L("Delete")
#define STR_CUSTOM_MENU_CUT						_L("Cut")
#define STR_CUSTOM_MENU_COPY					_L("Copy")
#define STR_CUSTOM_MENU_PASTE_BEFORE			_L("Paste Before")
#define STR_CUSTOM_MENU_PASTE_AFTER				_L("Paste After")
#define STR_CUSTOM_MENU_PASTE_INSIDE			_L("Paste Inside")
#define STR_CUSTOM_MENU_NEW_MAIN_POPUP			_L("New Main Popup")
				
enum GUITreeID
{
	CM_TEXT_ID = 1,
	CM_TAG_ID,
	CM_WND_TYPE_ID,

	CM_LT_ID,
	CM_LT_ENABLE_ID,
	CM_TLB_ID,
	CM_PROMPT_ID,
};


#define STR_CM_MOVE_TO_BEFORE				"Before"
#define STR_CM_MOVE_TO_AFTER				"After"
#define STR_CM_MOVE_TO_INSIDE				"Inside"
enum
{
	CM_MOVE_TO_BEFORE,
	CM_MOVE_TO_AFTER,
	CM_MOVE_TO_INSIDE,
};

#define STR_GUI_LABEL_POPUP_TEXT		_L("Popup Text")
#define STR_GUI_LABEL_POPUP_TAG			_L("Merge Tag")
#define STR_GUI_LABEL_WND_TYPE			_L("Window Type")
#define STR_GUI_LABEL_ITEM_TEXT			_L("Item Text")
#define STR_GUI_LABEL_LT_SCRIPT			_L("LabTalk Script")
#define STR_GUI_LABEL_LT_ENABLE			_L("Item Enable Condition")
#define STR_GUI_LABEL_TLB				_L("Tool Button")
#define STR_GUI_LABEL_PROMPT			_L("Status Bar Text")

#define STR_GUI_LABEL_WORKBOOK_TYPE		_L("Workbook")
#define STR_GUI_LABEL_GRAPH_TYPE		_L("Graph")
#define STR_GUI_LABEL_MATRIX_TYPE		_L("Matrix")

enum
{
	WND_TYPE_WKS,
	WND_TYPE_GRAPH,
	WND_TYPE_MATRIX,
};

#define STR_MAIN_POPUP_TEXT_PREFIX		"Custom"			///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
#define STR_MERGE_TAG_HINTS				_L("Use to merge the sub popups under the same popup")

///Kyle 06/12/2009 QA70-13423 NEW_TAB_FOR_EDITING_OMC_LIST
#define STR_WARNING_SWITCH_MENU_LEVEL_BY_OMC	_L("LabTalk-based menu modificatons have been executed. Do you want to clear these modifications and use Custom Menu Editor to modify menus?")
///End NEW_TAB_FOR_EDITING_OMC_LIST

#define STR_MSG_SAVE_IN_SYSTEM_FOLGER 		_L("Can not save in system folder.")
#define STR_MSG_SAVE_IN_GROUP_FOLGER 		_L("Can not save in group folder.")


enum
{
	//EDIT_OMC_CONFIG_TAB,			///Kyle 06/12/2009 QA70-13423 NEW_TAB_FOR_EDITING_OMC_LIST
	ADD_CUSTOM_MENUS_TAB,
	HIDE_BUILT_IN_MENUS_TAB,
};

//#define STR_EDIT_OMC_CONFIG_TAB			_L("OMC Configuration List")			///Kyle 06/12/2009 QA70-13423 NEW_TAB_FOR_EDITING_OMC_LIST
#define STR_ADD_CUSTOM_MENUS_TAB		_L("Add Custom Menu")
#define STR_HIDE_BUILT_IN_MENUS_TAB		_L("Hide Built-in Menus")
//efine STR_HIDE_BUILT_IN_HINTS			_L("Enter number to specify which menu item to be hidden. Multiple submenu items should be separated using space\n-1 =  whole menu, i = ith submenu\nExample: 1, 2, 4 (to hide 1st, 2nd, 4th submenu item.)")
#define STR_HIDE_BUILT_IN_HINTS			_L("Check the checkbox to show the menu item on the Menu\nUncheck the main menu to hide the whole menu")

struct CustomMenuClipboard
{
	bool bUse;
	//int nRow;
	//TreeNode trToMove;
	bool bCut;
};
#define STR_BEING_CUT_ATTRIB			"BeingCutAttrib"

#define WM_USER_CUSTOM_MENU_EDITOR_UPDATE_WINDOW_TEXT		(WM_USER + 1090)


/*----------------------------------------------------------------------------*/
/* Declaration/Definition of MenuTreeNode
/*----------------------------------------------------------------------------*/

#define MENU_NODE_SET_ATTRIBUTE(lpcszAttribName, lpcszAttribVal)	( lpcszAttribVal && IsValid() && SetAttribute(lpcszAttribName, lpcszAttribVal) )

class MenuTreeNode : public TreeNode
{
public:
	MenuTreeNode(const TreeNode& tn, BOOL bTagNameCaseSensitive = TRUE)
		: TreeNode(tn)
	{
		m_bTagNameCaseSensitive = bTagNameCaseSensitive;
	}
	~MenuTreeNode()
	{
		;
	}
	BOOL Init(int nParentNodeTagType)
	{
		bool bNeedToSetText		= true;
		bool bNeedToSetStop		= false;

		int nNodeTagType = CheckGetMenuNodeType(nParentNodeTagType);
		if ( MENU_NODE_TAG_INVALID != nNodeTagType )
		{
			if ( MENU_NODE_TAG_ITEM == nNodeTagType )
				bNeedToSetStop = true;
			else if ( MENU_NODE_TAG_POPUP != nNodeTagType && MENU_NODE_TAG_SEP != nNodeTagType )
			{	// menu item's sub node
				bNeedToSetText = false;
			}
		}
		else	// invalid menu node
		{
#ifdef	TRIM_EXTRA_TREE_NODE
			return Remove();
#else
			return FALSE;
#endif
		}

		BOOL bSuccess = TRUE;
		if (MENU_NODE_TAG_ITEM == nNodeTagType)
		{
			bSuccess &= SetLTScript( GetLTScript() );
			bSuccess &= SetLTEnable( GetLTEnable() );
			bSuccess &= SetToolBar( GetToolBar() );
			bSuccess &= SetPrompt( GetPrompt() );
		}
		if ( bNeedToSetText )
		{
			string strText = GetText();
			if ( strText.IsEmpty() && MENU_NODE_TAG_SEP == nNodeTagType )
				strText = STR_MENU_ITEM_SEPARATOR;
			bSuccess &= SetText(strText);
		}

		if ( bNeedToSetStop)
			bSuccess &= SetStopListAttribute();
		return bSuccess;
	}
	int GetMenuNodeType()
	{
		int nNodeType = MENU_NODE_TAG_INVALID;
		if ( IsValid() )
		{
			static vector<string> vsMenuNodeTags = 
			{
				STR_TAG_NAME_PREFIX_POPUP,STR_TAG_NAME_PREFIX_MENUITEM,STR_TAG_NAME_PREFIX_SEPARATOR,
				STR_MENUITEM_TAG_NAME_MENU_TEXT,STR_MENUITEM_TAG_NAME_LT_SCRIPT,STR_MENUITEM_TAG_NAME_LT_ENABLE,STR_MENUITEM_TAG_NAME_TOOL_BUTTON, STR_MENUITEM_TAG_NAME_PROMPT
			};
			nNodeType = vsMenuNodeTags.Find(tagName, 0, m_bTagNameCaseSensitive);
		}
		return nNodeType;
	}
	int CheckGetMenuNodeType(int nParentNodeTagType)
	{
		BOOL bIsValidMenuNode = FALSE;
		const int nNodeTagType = GetMenuNodeType();

		if ( MENU_NODE_TAG_INVALID != nNodeTagType )
		{
			switch ( nNodeTagType )
			{
			case MENU_NODE_TAG_POPUP:
				// A popup may be the root node, so its parent node can be invalid.
				bIsValidMenuNode = ( MENU_NODE_TAG_INVALID == nParentNodeTagType || MENU_NODE_TAG_POPUP == nParentNodeTagType ); 
				break;
			case MENU_NODE_TAG_ITEM:
			case MENU_NODE_TAG_SEP:
				bIsValidMenuNode = ( MENU_NODE_TAG_POPUP == nParentNodeTagType );
				break;
			default:	// menu item's sub node
				bIsValidMenuNode = ( MENU_NODE_TAG_ITEM == nParentNodeTagType );
				break;
			}
		}
		return bIsValidMenuNode ? nNodeTagType : MENU_NODE_TAG_INVALID;
	}
	string GetText()
	{
		string strText = "";
		if ( IsValid() )
		{
			if ( !GetAttribute(STR_LABEL_ATTRIB, strText) )
				SetAttribute(STR_LABEL_ATTRIB, strText);
			if ( strText.IsEmpty() )
			{
				const int nNodeType = GetMenuNodeType();
				switch ( nNodeType )
				{
				case MENU_NODE_TAG_POPUP:
					if ( !GetAttribute(STR_POPUP_TEXT_ATTRIB, strText) )
						SetAttribute(STR_POPUP_TEXT_ATTRIB, strText);
					break;
				case MENU_NODE_TAG_ITEM:
					strText = CheckGetSubNodeText(STR_MENUITEM_TAG_NAME_MENU_TEXT);
					break;
				case MENU_NODE_TAG_SEP:
					break;
				default:
					strText = GetNodeText();
					break;
				}
			}
		}
		return strText;
	}
	BOOL SetText(LPCSTR lpcszText)
	{
		BOOL bSuccess = TRUE;
		if (lpcszText)
		{
			const int nNodeType = GetMenuNodeType();
			if ( MENU_NODE_TAG_POPUP == nNodeType)
				bSuccess = SetAttribute(STR_POPUP_TEXT_ATTRIB, lpcszText);
			else if ( MENU_NODE_TAG_ITEM == nNodeType)
				bSuccess = CheckSetSubNodeText(STR_MENUITEM_TAG_NAME_MENU_TEXT, lpcszText);

			bSuccess &= SetAttribute(STR_LABEL_ATTRIB, lpcszText);
		}
		return bSuccess;
	}
	void GetWndType(BOOL& bWorkbook, BOOL& bGraph, BOOL& bMatrix)
	{
		bWorkbook = bGraph = bMatrix = FALSE;
		if( IsValid() )
		{
			string strWndType = "";
			if( !GetAttribute(STR_WINDOW_TYPE_ATTRIB, strWndType) )
			{
				strWndType = WndTypeToString(TRUE, TRUE, TRUE);
				SetAttribute(STR_WINDOW_TYPE_ATTRIB, strWndType);
			}
			StringToWndType(strWndType, bWorkbook, bGraph, bMatrix);
		}
	}
	void SetWndType(BOOL bWorkbook, BOOL bGraph, BOOL bMatrix)
	{
		//string strWndType = WndTypeToString(bWorkbook, bGraph, bMatrix);
		//MENU_NODE_SET_ATTRIBUTE(STR_WINDOW_TYPE_ATTRIB, strWndType);
		SetWndType(WndTypeToString(bWorkbook, bGraph, bMatrix));
	}

	string GetMergeTag()
	{
		string strMergeTag = "";
		if( IsValid() && !GetAttribute(STR_POPUP_TAG_ATTRIB, strMergeTag) )
			SetAttribute(STR_POPUP_TAG_ATTRIB, strMergeTag);
		return strMergeTag;
	}
	BOOL SetMergeTag(LPCSTR lpcszMergeTag)
	{
		return MENU_NODE_SET_ATTRIBUTE(STR_POPUP_TAG_ATTRIB, lpcszMergeTag);
	}
	string GetLTScript()
	{
		return CheckGetSubNodeText(STR_MENUITEM_TAG_NAME_LT_SCRIPT);
	}
	BOOL SetLTScript(LPCSTR lpcszLTScript)
	{
		return CheckSetSubNodeText(STR_MENUITEM_TAG_NAME_LT_SCRIPT, lpcszLTScript);
	}
	string GetLTEnable()
	{
		return CheckGetSubNodeText(STR_MENUITEM_TAG_NAME_LT_ENABLE);
	}
	BOOL SetLTEnable(LPCSTR lpcszLTEnable)
	{
		return CheckSetSubNodeText(STR_MENUITEM_TAG_NAME_LT_ENABLE, lpcszLTEnable);
	}
	string GetToolBar()
	{
		return CheckGetSubNodeText(STR_MENUITEM_TAG_NAME_TOOL_BUTTON);
	}
	BOOL SetToolBar(LPCSTR lpcszToolBar)
	{
		return CheckSetSubNodeText(STR_MENUITEM_TAG_NAME_TOOL_BUTTON, lpcszToolBar);
	}
	string GetPrompt()
	{
		return CheckGetSubNodeText(STR_MENUITEM_TAG_NAME_PROMPT);
	}
	BOOL SetPrompt(LPCSTR lpcszPrompt)
	{
		return CheckSetSubNodeText(STR_MENUITEM_TAG_NAME_PROMPT, lpcszPrompt);
	}
	BOOL SetStopListAttribute()
	{
		return MENU_NODE_SET_ATTRIBUTE(STR_STOP_ATTRIB, "1");
	}

	int GetAttributeType(LPCSTR lpcszAttribName)
	{
		int nAttribType = ATTRIB_TYPE_INVALID;
		if ( IsValid() )
		{
			static vector<string> vsAttribNames = { STR_POPUP_TEXT_ATTRIB, STR_POPUP_TAG_ATTRIB, STR_WINDOW_TYPE_ATTRIB };
			nAttribType = vsAttribNames.Find(lpcszAttribName, 0, m_bTagNameCaseSensitive);
		}
		return nAttribType;
	}
	int TrimExtraAttribute()
	{
		if ( !IsValid() )
			return 0;

		int nTrimAttribCount = 0;
		const int nNodeTagType = GetMenuNodeType();

		vector<string> vsAttribNames;
		GetAttributeNames(vsAttribNames);

		for (int ii = 0; ii < vsAttribNames.GetSize(); ++ii)
		{
			const string& strAttribName = vsAttribNames[ii];
			const int nAttribType = GetAttributeType(strAttribName);

			switch ( nNodeTagType )
			{
			case MENU_NODE_TAG_POPUP:
				if ( ATTRIB_TYPE_POPUP_TEXT == nAttribType || ATTRIB_TYPE_POPUP_TAG == nAttribType )
					continue;
				// No break here! A popup can also has wndType attribute.
			case MENU_NODE_TAG_ITEM:
				if ( ATTRIB_TYPE_WND_TYPE == nAttribType )
					continue;
				break;
			default:	// sep/iteminfo/invalid
				break;
			}

			nTrimAttribCount += RemoveAttribute( strAttribName );
		}
		return nTrimAttribCount;
	}

	TreeNode AddOrInsertNode(int nAddOrInsertNodeType, BOOL bInsert)
	{
		TreeNode tnNewItem = NULL;
		if ( IsValid() )
		{
			string strTagName;
			switch(nAddOrInsertNodeType)
			{
			case MENU_NODE_TAG_ITEM:
				strTagName = STR_TAG_NAME_PREFIX_MENUITEM;
				break;
			case MENU_NODE_TAG_POPUP:
				strTagName = STR_TAG_NAME_PREFIX_POPUP;
				break;
			case MENU_NODE_TAG_SEP:
				strTagName = STR_TAG_NAME_PREFIX_SEPARATOR;
				break;
			default:
				return tnNewItem;
			}

			int nParentNodeTagType;
			if(bInsert)
			{
				TreeNode tnParent = Parent();
				MenuTreeNode mtnParent(tnParent);
				nParentNodeTagType = mtnParent.GetMenuNodeType();
				if( tnParent )
					tnNewItem = tnParent.InsertNode(*this, strTagName);
			}
			else
			{
				nParentNodeTagType = GetMenuNodeType();
				tnNewItem = AddNode(strTagName);
			}

			MenuTreeNode mtnNew(tnNewItem);
			mtnNew.Init( nParentNodeTagType );
		}
		return tnNewItem;
	}
protected:
/*
	string GetWndType()
	{
		string strWndType = "";
		if( IsValid() )
		{
			if( !GetAttribute(STR_WINDOW_TYPE_ATTRIB, strWndType) )
			{
				strWndType = WndTypeToString(TRUE, TRUE, TRUE);
				SetAttribute(STR_WINDOW_TYPE_ATTRIB, strWndType);
			}
		}
		return strWndType;
	}
*/
	BOOL SetWndType(LPCSTR lpcszWndType)
	{
		return MENU_NODE_SET_ATTRIBUTE(STR_WINDOW_TYPE_ATTRIB, lpcszWndType);
	}
	string WndTypeToString(BOOL bWorkbook, BOOL bGraph, BOOL bMatrix)
	{
		string strWndType = "";
		if (bGraph)
			strWndType += 'G';
		if (bWorkbook)
			strWndType += 'W';
		if (bMatrix)
			strWndType += 'M';
		return strWndType;
	}
	void StringToWndType(LPCSTR lpcszWndType, BOOL& bWorkbook, BOOL& bGraph, BOOL& bMatrix)
	{
		string strWndType = lpcszWndType;
		bGraph		= ( strWndType.Find('G') >= 0 );
		bWorkbook	= ( strWndType.Find('W') >= 0 );
		bMatrix		= ( strWndType.Find('M') >= 0 );
	}

	BOOL CheckSetSubNodeText(LPCSTR lpcszTagName, LPCSTR lpcszTextVal)
	{
		BOOL bSuccess = FALSE;
		if ( lpcszTagName && lpcszTextVal && IsValid() )
		{
			TreeNode tnSubNode = tree_check_get_node(*this, lpcszTagName);
			if (!tnSubNode)
				ASSERT(FALSE);
			else
				bSuccess = tnSubNode.SetNodeText(lpcszTextVal);
		}
		return bSuccess;
	}
	string CheckGetSubNodeText(LPCSTR lpcszTagName)
	{
		string strText;
		if ( lpcszTagName && IsValid() )
		{
			TreeNode tnSubNode = tree_check_get_node(*this, lpcszTagName);
			if (!tnSubNode)
				ASSERT(FALSE);
			else
				strText = tnSubNode.GetNodeText();
		}
		return strText;
	}
private:
		BOOL m_bTagNameCaseSensitive;
};

/*----------------------------------------------------------------------------*/
/* Declaration/Definition of MenuEditorSplitterBase
/*----------------------------------------------------------------------------*/

class MenuEditorSplitterBase : public TreeDynaSplitter
{
public:
	MenuEditorSplitterBase()
	{
		m_strConfigXMLFilePath	= GetAppPath(FALSE) + STR_CUSTOM_MENUS_XML;
		//m_nCurSelRow			= -1;
		m_nLastSelRow			= -1;
	}
	~MenuEditorSplitterBase()
	{
		;
	}
public:
	//BOOL OnExport()
	//{
		//if(!m_trMenuTree)
			//return false;
		//string strFilename = "*.omc", strDlgName = _L("Export Custom Menus");
		//string strConfigXMLFilePath = GetSaveAsBox( "*.omc OMC Files", GetAppPath(FALSE), strFilename, strDlgName);
		//if(strConfigXMLFilePath.IsEmpty())
			//return false;
//
		//Tree trMenuTree;
		//trMenuTree.Replace(m_trMenuTree);
		//trimMenuTreeExtraAttribute(trMenuTree);
//
		//return trMenuTree.Save(strConfigXMLFilePath);
	//}

	///Kyle 06/12/2009 QA70-13423 NEW_TAB_FOR_EDITING_OMC_LIST
	virtual BOOL	SetCustomMenuConfig(const TreeNode& trConfig)
	{
		m_nLastSelRow = -1;
		SetDirty(false, false);
		m_trMenuTree.Reset();
		if(trConfig)
			m_trMenuTree.Replace(trConfig, true, true);

		checkSetMenuItemsNumbers();

		bool bRet = InitMenuTree();
		return bRet;
	}
	
	bool	GetCustomMenuConfig(Tree& trConfig)
	{
		trConfig.Replace(m_trMenuTree);
		trimMenuTreeExtraAttribute(trConfig);
		return true;
	}
	
	bool		IsDirty()
	{
		return m_bDirty;
	}
	
	void		SetDirty(bool bDirty = true, bool bUpdateWndText = true)
	{
		if(m_bDirty != bDirty)
		{
			m_bDirty = bDirty;
			if(bUpdateWndText)
			{
				Window win(GetParent().GetSafeHwnd());
				if(win)
					win.PostMessage(WM_USER_CUSTOM_MENU_EDITOR_UPDATE_WINDOW_TEXT);
			}
		}
	}
	///End NEW_TAB_FOR_EDITING_OMC_LIST

	virtual BOOL LoadCustomMenuConfig()
	{
		BOOL bRet = m_trMenuTree.Load(m_strConfigXMLFilePath);
		if(!bRet)
			m_trMenuTree.Reset();
		///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
		//if (!bRet)
		//{
			//m_trMenuTree.Reset();
			//MenuTreeNode mtn(m_trMenuTree);
			//mtn.SetText(STR_CUSTOM_MENU_DEFAULT_ROOT);
		//}
		///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
		/*
		int nMainPopup = 0;
		foreach(TreeNode tr in m_trMenuTree.Children)
		{
			if(MENU_NODE_TAG_POPUP != GetNodeType(tr))
			{
				tr.Remove();
			}
			else
			{
				nMainPopup ++;
				if(nMainPopup > CUSTOM_MENU_MAX_MAIN_POPUP)
					tr.Remove();
			}
		}
		*/
		checkSetMenuItemsNumbers();
		///End CHECK_NUMBERS_OF_EACH_MENU_TYPE
		///End SUPPORT_UP_TO_THREE_CUSTOM_MENUS
		bRet = InitMenuTree();
		return bRet;
	}
	virtual BOOL SaveCustomMenuConfig()
	{
		BOOL bRet = FALSE;
		///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
		//if (m_trMenuTree && m_trMenuTree.FirstNode)
		if (m_trMenuTree)
		///End SUPPORT_UP_TO_THREE_CUSTOM_MENUS
		{
			trimMenuTreeExtraAttribute(m_trMenuTree);
			
			///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
			//TreeNode tnRoot = m_trMenuTree.FirstNode.Clone();
			//m_trMenuTree.Reset();
			//m_trMenuTree.Replace( tnRoot, TRUE, TRUE);
			///End SUPPORT_UP_TO_THREE_CUSTOM_MENUS

			bRet = m_trMenuTree.Save(m_strConfigXMLFilePath);
		}
		return bRet;
	}

	virtual string GetConfigXMLFilePath() { return m_strConfigXMLFilePath; }

	//virtual int GetSelectedRow(bool* pbGetIsChanged = NULL) 
	//{
		//int nNewlySelectedRow = TreeDynaSplitter::GetSelectedRow();
		//if (pbGetIsChanged)
			//*pbGetIsChanged = (m_nCurSelRow != nNewlySelectedRow);
		//m_nCurSelRow = nNewlySelectedRow;
		//return m_nCurSelRow;
	//}

	virtual void SelectRow(int nRow, bool bCheckExpanded = false) 
	{
		/////Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
		////m_nCurSelRow = -1;
		//if(GetMainPopupCount() == 0)			// will select -1 no matter what nRow is
			//m_nCurSelRow = 0;
		//else
			//m_nCurSelRow = -1;
		/////End SUPPORT_UP_TO_THREE_CUSTOM_MENUS
		
		// keep last selected row, and make sure after TreeDynaSplitter::SelectRow(nRow) m_nLastSelRow != GetSelectedRow()
		m_nLastSelRow = GetSelectedRow();
		//if(m_nLastSelRow == nRow)
		//	m_nLastSelRow = -1;
		//if(GetMainPopupCount() == 0 || nRow < 0)			// will select -1 no matter what nRow is
		//	m_nLastSelRow = 0;

		TreeDynaSplitter::SelectRow(nRow);
		//GetSelectedRow();
	}
	virtual int GetNodeType(const TreeNode& tn) 
	{
		MenuTreeNode mtn(tn);
		return mtn.GetMenuNodeType();
	}

	TreeNode GetTreeNode(int nRow)
	{
		const DWORD dwCntrl = 0;
		return tree_get_node(m_trMenuTree, nRow, dwCntrl, STR_STOP_ATTRIB);
	}
	void UpdateList()
	{
		TreeDynaSplitter::UpdateList( STR_STOP_ATTRIB, NOT_SET_STOP_LEVEL );
	}

	//TreeNode& GetCurSelNode(bool* pbGetIsChanged = NULL)
	TreeNode& GetCurSelNode()
	{
		//bool bIsChanged;
		//int nSelectedRow = GetSelectedRow(&bIsChanged);
//
		//if(bIsChanged)
			//m_tnCurSelNode = GetTreeNode( m_nCurSelRow );
//
		//if(pbGetIsChanged)
			//*pbGetIsChanged = bIsChanged;
//
		//return m_tnCurSelNode;
		m_tnCurSelNode = GetTreeNode( GetSelectedRow() );
		return m_tnCurSelNode;
	}

	Tree& GetMenuTree() { return m_trMenuTree; }

	BOOL GetMenuEnumLabelText(TreeNode& tnSub, string& strLabelText)
	{
		MenuTreeNode mtn(tnSub);
		const int nNodeTagType = mtn.GetMenuNodeType();
		if ( MENU_NODE_TAG_POPUP == nNodeTagType || MENU_NODE_TAG_ITEM == nNodeTagType )
		{
			bool bDefault = false;
			string strPrefix = strLabelText;
			if(strPrefix.IsEmpty())			// default
			{
				bDefault = true;
				if(MENU_NODE_TAG_POPUP == nNodeTagType)
				{
					if(MainPopup(tnSub))
						strPrefix = STR_MAIN_POPUP_TEXT_PREFIX;
					else
						strPrefix = STR_TAG_NAME_PREFIX_POPUP;
				}
				else
				{
					strPrefix = STR_TAG_NAME_PREFIX_MENUITEM;
				}
			}

			TreeNode tnParent = tnSub.Parent();
			if (tnParent)
			{
				//if(bDefault)
				//{
					//int nLevel = tree_get_level(tnParent);
					//if(nLevel > 0)
						//strPrefix += (string)nLevel;
				//}
				//if(bDefault && bMainPopup)
				//{
					//vector<string> vs;
					//tree_get_attributes(tnParent, vs, STR_LABEL_ATTRIB, true);
					//for(int ii=1; ii<=CUSTOM_MENU_MAX_MAIN_POPUP; ii++)
					//{
						//strLabelText = strPrefix + (string)ii;
						//if(vs.Find(strLabelText, 0, true) < 0)
							//break;
					//}
				//}
				if(bDefault)
				{
					vector<string> vs;
					tree_get_attributes(tnParent, vs, STR_LABEL_ATTRIB, true);
					int nTotal = vs.GetSize()+1;
					for(int ii=1; ii<=nTotal; ii++)
					{
						strLabelText = strPrefix + (string)ii;
						if(vs.Find(strLabelText, 0, true) < 0)
							break;
					}
				}
				else
				{
					octree_get_enum_attribute_value(&tnParent, &strLabelText, STR_LABEL_ATTRIB, strPrefix);
				}
			}
			else
			{
				strLabelText = strPrefix;
			}
		}
		else
			return FALSE;
		return TRUE;
	}
	BOOL SetMenuEnumText(TreeNode& tnSub)
	{
		string strText = "";
		if ( GetMenuEnumLabelText(tnSub, strText) )
		{
			MenuTreeNode mtn(tnSub);
			mtn.SetText(strText);
			return TRUE;
		}
		return FALSE;
	}
	TreeNode AddOrInsertMenu(TreeNode& tnSub, int nAddOrInsertNodeType, BOOL bInsert)
	{
		MenuTreeNode mtn(tnSub);
		TreeNode tnNewItem = mtn.AddOrInsertNode(nAddOrInsertNodeType, bInsert);
		if ( tnNewItem )
		{
			if ( MENU_NODE_TAG_SEP != nAddOrInsertNodeType )
			{
				SetMenuEnumText(tnNewItem);
			}
		}
		return tnNewItem;
	}
	
	///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
	TreeNode NewMainPopup()
	{
		return AddOrInsertMenu(m_trMenuTree, MENU_NODE_TAG_POPUP, false);
	}
	///End SUPPORT_UP_TO_THREE_CUSTOM_MENUS
protected:

	bool CheckMenuText(const TreeNode& trCurSel, string strText, bool *pbChanged = NULL)
	{
		int nNodeTagType = GetNodeType(trCurSel);
		if(nNodeTagType != MENU_NODE_TAG_POPUP && nNodeTagType != MENU_NODE_TAG_ITEM)
			return false;

		MenuTreeNode mtn(trCurSel);
		bool bChanged = (0 != strText.Compare( mtn.GetText() ));
		if(pbChanged)
			*pbChanged = bChanged;

		if(!bChanged)			// 
			return true;
		if(strText.IsEmpty())
			return false;
		
		TreeNode trParent = trCurSel.Parent();
		if(!trParent)			
			return false;		// should never come here

		foreach(TreeNode trn in trParent.Children)
		{
			if( nNodeTagType == GetNodeType(trn) )
			{
				MenuTreeNode mtnTemp(trn);
				if( 0 == strText.Compare(mtnTemp.GetText()) )
					return false;
			}
		}
		return true;
	}

	BOOL InitMenuTree()
	{
		///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
		//TreeNode tnClone = m_trMenuTree.Clone();
		//m_trMenuTree.Reset();
//
		//TreeNode tnRoot = AddOrInsertMenu(m_trMenuTree, MENU_NODE_TAG_POPUP, FALSE);
		//tnRoot.Replace( tnClone, TRUE, TRUE);
		///End SUPPORT_UP_TO_THREE_CUSTOM_MENUS

		StringArray vsPopupNames;
		StringArray vsItemNames;

		BOOL bSuccess = trimInitMenuTree(m_trMenuTree, vsPopupNames, vsItemNames);
		if (bSuccess)
			bSuccess = setMenuTreeTextIfEmpty(m_trMenuTree, vsPopupNames, vsItemNames);

		return bSuccess;
	}

	///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
	bool MainPopup(TreeNode& trn)
	{
		string str;
		return octree_get_level(&str, &trn, NULL, false) == 1;
	}
	
	int 	GetMainPopupCount()
	{
		return (m_trMenuTree.IsValid() ? m_trMenuTree.GetNodeCount() : 0);
	}
	
	int GetSubItemCount(const TreeNode& trPopup)
	{
		if(!trPopup)
			return -1;
		int nCount = 0;
		if(MENU_NODE_TAG_POPUP == GetNodeType(trPopup))
		{
			///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
			//foreach(TreeNode trSub in trPopup.Children)
			//{
				//nCount += 1 + GetSubItemCount(trSub);
			//}
			int nPopups, nCmdItems, nSeparators;
			if(GetSubItemCount(trPopup, &nPopups, &nCmdItems, &nSeparators))
				nCount = nPopups + nCmdItems + nSeparators;
			///End CHECK_NUMBERS_OF_EACH_MENU_TYPE
		}
		else
			nCount = 0;
		
		return nCount;
		
	}

	int 	GetAllItemCount()
	{
		int nCount = 0;
		foreach(TreeNode trPopup in m_trMenuTree.Children)
		{
			nCount += (1 + GetSubItemCount(trPopup) );
		}
		return nCount;
	}
	///End SUPPORT_UP_TO_THREE_CUSTOM_MENUS
	
	///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
	int GetDepth(const TreeNode& trMenu, bool bPopupDepthOnly)
	{
	//	return 0;	// the function have error with TreeNode, not to check the depth just for testing, will handle it later
		
		if(!trMenu)
			return -1;
		if(MENU_NODE_TAG_POPUP != GetNodeType(trMenu))
		{
			return bPopupDepthOnly ? 0 : 1;
		}
		int nMaxSubDepth = 0;
		
		foreach(TreeNode trSub in trMenu.Children)
		{
			int nn = GetDepth(trSub, bPopupDepthOnly);
			if(nMaxSubDepth < nn)
				nMaxSubDepth = nn;
		}
		return nMaxSubDepth + 1;
	}

	bool GetMenuItemsCount(const TreeNode& trMenu, int *pnPopups, int *pnCmdItems, int *pnSeparators)
	{
		switch(GetNodeType(trMenu))
		{
		case MENU_NODE_TAG_POPUP:
			GetSubItemCount(trMenu, pnPopups, pnCmdItems, pnSeparators);
			if(pnPopups)
				*pnPopups = *pnPopups+1;		// the current popup
			break;
		case MENU_NODE_TAG_ITEM:
			if(pnPopups)
				*pnPopups = 0;
			if(pnCmdItems)
				*pnCmdItems = 1;
			if(pnSeparators)
				*pnSeparators = 0;
			break;
		case MENU_NODE_TAG_SEP:
			if(pnPopups)
				*pnPopups = 0;
			if(pnCmdItems)
				*pnCmdItems = 0;
			if(pnSeparators)
				*pnSeparators = 1;
			break;
		default:
			return false;
		}
		return true;
	}

	bool GetSubItemCount(const TreeNode& trPopup, int *pnPopups, int *pnCmdItems, int *pnSeparators)
	{
		if(!trPopup || MENU_NODE_TAG_POPUP != GetNodeType(trPopup))
			return false;

		int nPopups = 0,
			nCmdItems = 0,
			nSeparators = 0;
		foreach(TreeNode trSub in trPopup.Children)
		{
			switch(GetNodeType(trSub))
			{
			case MENU_NODE_TAG_POPUP:
				nPopups++;
				int nSubPopups, nSubCmdItems, nSubSeparators;
				if(GetSubItemCount(trSub, &nSubPopups, &nSubCmdItems, &nSubSeparators))
				{
					nPopups += nSubPopups;
					nCmdItems += nSubCmdItems;
					nSeparators += nSubSeparators;
				}
				break;

			case MENU_NODE_TAG_ITEM:
				nCmdItems++;
				break;

			case MENU_NODE_TAG_SEP:
				nSeparators++;
				break;
			}
		}

		if(pnPopups)
			*pnPopups = nPopups;
		if(pnCmdItems)
			*pnCmdItems = nCmdItems;
		if(pnSeparators)
			*pnSeparators = nSeparators;

		return true;
	}
	///End CHECK_NUMBERS_OF_EACH_MENU_TYPE


private:

	///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
	void checkSetMenuItemsNumbers()
	{
		m_nNumSubPopups = 0;
		m_nNumCmdItems = 0;
		m_nNumSeparator = 0;

		int nMainPopup = 0;
		foreach(TreeNode tr in m_trMenuTree.Children)
		{
			if(MENU_NODE_TAG_POPUP != GetNodeType(tr))
			{
				tr.Remove();
			}
			else
			{
				nMainPopup ++;
				if(nMainPopup > CUSTOM_MENU_MAX_MAIN_POPUP)
				{
					tr.Remove();
				}
				else
				{
					int nPopups, nCmdItems, nSeparators;
					GetSubItemCount(tr, &nPopups, &nCmdItems, &nSeparators);
					
					m_nNumSubPopups += nPopups;
					m_nNumCmdItems += nCmdItems;
					m_nNumSeparator += nSeparators;
				}
			}
		}
	}
	///End CHECK_NUMBERS_OF_EACH_MENU_TYPE


	BOOL trimInitMenuTree(TreeNode& tn, StringArray& vsPopupNames, StringArray& vsItemNames, int nParentNodeTagType = MENU_NODE_TAG_POPUP)
	{
		// Trim the invalid TreeNode or return false, depends on TRIM_EXTRA_TREE_NODE
		// Set an empty text name for popup/item that with relative attribute/subnode missed
		// Set the stop attribute for exclusively showing the specific menu tree
		// Get all the valid popup/item names and save to vsPopupNames/vsItemNames
		foreach(TreeNode cNode in tn.Children)
		{
			MenuTreeNode mtn(cNode);

			if ( !mtn.Init(nParentNodeTagType) )
				return FALSE;

			const int nNodeTagType = mtn.GetMenuNodeType();

			if ( MENU_NODE_TAG_POPUP == nNodeTagType || MENU_NODE_TAG_ITEM == nNodeTagType )
			{
				string strText = mtn.GetText();
				if ( !strText.IsEmpty() )
				{
					if(MENU_NODE_TAG_POPUP == nNodeTagType)
						vsPopupNames.Add(strText);
					else if(MENU_NODE_TAG_ITEM == nNodeTagType)
						vsItemNames.Add(strText);
				}
			}

			if( cNode.GetNodeCount() > 0 ) // branch node
			{
				if ( !trimInitMenuTree(cNode, vsPopupNames, vsItemNames, nNodeTagType) )
					return FALSE;
			}
		}
		return TRUE;
	}
	BOOL setMenuTreeTextIfEmpty(TreeNode& tnSub, StringArray& vsPopupNames, StringArray& vsItemNames)
	{
		foreach(TreeNode cNode in tnSub.Children)
		{
			MenuTreeNode mtn(cNode);
			int nNodeTagType = mtn.GetMenuNodeType();

			// trimInit() should has been called beforehand, so all node would be valid.
			if ( MENU_NODE_TAG_INVALID == nNodeTagType )
			{
				ASSERT(FALSE);
				return FALSE;
			}

			if ( MENU_NODE_TAG_POPUP != nNodeTagType && MENU_NODE_TAG_ITEM != nNodeTagType )	// may be a separator or item's sub node
				continue;

			string strText = mtn.GetText();

			if ( strText.IsEmpty() )
			{
				int nIndex;
				if ( MENU_NODE_TAG_POPUP == nNodeTagType )
				{
					strText = STR_TAG_NAME_PREFIX_POPUP;
					nIndex = get_list_enum_number(vsPopupNames, STR_TAG_NAME_PREFIX_POPUP);
				}
				else	// must be MENU_NODE_TAG_ITEM
				{
					strText = STR_TAG_NAME_PREFIX_MENUITEM;
					nIndex = get_list_enum_number(vsItemNames, STR_TAG_NAME_PREFIX_MENUITEM);
				}

				if (0 != nIndex)
					strText.Format("%s%d", strText, nIndex);

				if ( MENU_NODE_TAG_POPUP == nNodeTagType )
					vsPopupNames.Add(strText);
				else
					vsItemNames.Add(strText);

				mtn.SetText(strText);
			}

			if( cNode.GetNodeCount() > 0 ) // branch node
			{
				if( !setMenuTreeTextIfEmpty(cNode, vsPopupNames, vsItemNames) )
					return FALSE;
			}
		}
		return TRUE;
	}

	BOOL trimMenuTreeExtraAttribute(TreeNode& tnSub)
	{
		foreach(TreeNode cNode in tnSub.Children)
		{
			MenuTreeNode mtn(cNode);
			int nNodeTagType = mtn.GetMenuNodeType();

			if ( MENU_NODE_TAG_INVALID == nNodeTagType )
			{
				ASSERT(FALSE);
				return FALSE;
			}

			mtn.TrimExtraAttribute();

			if( cNode.GetNodeCount() > 0 ) // branch node
			{
				if( !trimMenuTreeExtraAttribute(cNode) )
					return FALSE;
			}
		}
		return TRUE;
	}
	
protected:
	///Kyle 06/12/2009 QA70-13423 NEW_TAB_FOR_EDITING_OMC_LIST
	bool			m_bDirty;
	///End NEW_TAB_FOR_EDITING_OMC_LIST
	Tree			m_trMenuTree;
	TreeNode		m_tnCurSelNode;
	string			m_strConfigXMLFilePath;
	//int 			m_nCurSelRow;
	// only to be used in OnListRowChange to check if the selected row changed and will change it to the current selected row if changed, so in SelectRow will set it as the last sel row
	int 			m_nLastSelRow;
	
	///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
	int 			m_nNumSubPopups;
	int 			m_nNumCmdItems;
	int 			m_nNumSeparator;
	///End CHECK_NUMBERS_OF_EACH_MENU_TYPE
};

/*----------------------------------------------------------------------------*/
/* Declaration/Definition of MenuEditorSplitter control
/*----------------------------------------------------------------------------*/

class MenuEditorSplitter : public MenuEditorSplitterBase
{
public:
	MenuEditorSplitter()
	{
	}
	~MenuEditorSplitter()
	{
	}
public:
	///Kyle 06/12/2009 QA70-13423 NEW_TAB_FOR_EDITING_OMC_LIST
	BOOL	SetCustomMenuConfig(const TreeNode& trConfig)
	{
		BOOL bRet = MenuEditorSplitterBase::SetCustomMenuConfig(trConfig);
		if(bRet)
		{
			SetReady(false);	// this is needed in case GUI refresh problem
			SetListTree( GetMenuTree() );
			if(GetMainPopupCount() > 0)
			{
				UpdateList();
				//int nCurSelRow = LoadSetting("CurrentSelRow", 0, STR_DLG_NAME_E);
				//SelectRow(nCurSelRow, true);
			}
			else
			{
				m_MenuTreeCtrl.ClearAll();
				//ShowInfo();				// no list row selection change event
			}
			// always remove selections
			SelectRow(-1);
			ShowInfo();
			SetReady(true);
		}
		return bRet;
	}
	///End NEW_TAB_FOR_EDITING_OMC_LIST

	BOOL LoadCustomMenuConfig()
	{
		BOOL bRet = MenuEditorSplitterBase::LoadCustomMenuConfig();
		if ( bRet )
		{
			SetReady(false);	// this is needed in case GUI refresh problem
			///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
			//SetListTree( GetMenuTree() );
			//UpdateList();
			//m_MenuTreeCtrl.SetCollapsed(0, flexOutlineExpanded);
			//SelectRow(0);
			if(GetMainPopupCount() > 0)
			{
				SetListTree( GetMenuTree() );
				UpdateList();
				//m_MenuTreeCtrl.SetCollapsed(0, flexOutlineExpanded);
				//SelectRow(0);
				int nCurSelRow = LoadSetting("CurrentSelRow", 0, STR_DLG_NAME_E);
				SelectRow(nCurSelRow, true);
			}
			else
			{
				ShowInfo();				// no list row selection change event
			}
			///End SUPPORT_UP_TO_THREE_CUSTOM_MENUS
			SetReady(true);
		}
		return bRet;
	}

	//virtual
	void SelectRow(int nRow, bool bCheckExpanded = false)
	{
		// expand the row to select
		if(bCheckExpanded)
		{
			int nRowToExpand = m_MenuTreeCtrl.GetParent(nRow);
			while(nRowToExpand >= 0)
			{
				m_MenuTreeCtrl.SetCollapsed(nRowToExpand, flexOutlineExpanded);
				nRowToExpand = m_MenuTreeCtrl.GetParent(nRowToExpand);
			}
		}
		MenuEditorSplitterBase::SelectRow(nRow, bCheckExpanded);
		if(m_nLastSelRow == GetSelectedRow())
		{
			m_nLastSelRow = m_MenuTreeCtrl.GetNumRows() + m_MenuTreeCtrl.GetRowOffset();
		}
	}

protected:
	EVENTS_BEGIN
		ON_INIT(OnInitSplitter)
		ON_DESTROY(OnDestroy)
		ON_READY(OnReady)
		ON_SIZE(OnCtrlResize)

		ON_GRID_ROW_COL_CHANGE(GetMainPaneID(), OnListRowChange)
		ON_GETNDLG_MSGS( GetTreeEditPaneID() )
		ON_GRID_DBLCLICK(GetMainPaneID(), OnDBClickList)
		ON_GRID_AFTER_EDIT(GetMainPaneID(), OnAfterEditList)
		ON_CONTEXTMENU(OnShowMenu)	
		ON_USER_MSG(WM_USER_TREEEDITOR_VALUE_CHANGE, OnAfterValueChange)
		ON_KEY(GetMainPaneID(), OnKey)
	EVENTS_END

	BOOL OnInitSplitter()
	{
		TreeDynaSplitter::OnInitSplitter(&m_MenuTreeCtrl);
		m_MenuTreeCtrl.SetAllowSelection(true);
		m_MenuTreeCtrl.SetSelection(flexSelectionListBox);
		m_MenuTreeCtrl.SetColDataType(0, flexDTString);
		m_MenuTreeCtrl.SetToolTipsText(STR_ROW_LIST_TOOL_TIPS);			//==>it doesn't work, may not the right position to add this
		
		clearCustomMenuClipboard();
		return TRUE;
	}
	BOOL OnDestroy()
	{
		//SaveSetting("CurrentSelRow", GetSelectedRow(), STR_DLG_NAME_E);
		return TreeDynaSplitter::OnDestroy();
	}
	BOOL OnReady()
	{
		return TRUE;
	}
	BOOL OnCtrlResize(int nType, int cx, int cy)
	{
		DynaDlg::OnResize(nType, cx, cy);
		return TRUE;
	}
	void OnListRowChange(Control ctrl)
	{
		//bool bIsCurSelChanged;
		/////Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
		////if( GetCurSelNode(&bIsCurSelChanged) && bIsCurSelChanged )
		//GetCurSelNode(&bIsCurSelChanged);
		//if( bIsCurSelChanged )
		/////End SUPPORT_UP_TO_THREE_CUSTOM_MENUS
			//ShowInfo();
		int nCurSelRow = GetSelectedRow();
		if(m_nLastSelRow != nCurSelRow)
		{
			m_nLastSelRow = nCurSelRow;
			ShowInfo();
		}
	}
	void OnDBClickList(Control flxControl)
	{
		setCurSelItemEditable();
	}
	
	void OnAfterEditList(Control flxControl, int nRow, int nCol)
	{
		MenuTreeNode mtnCurSel( GetCurSelNode() );
		if( !mtnCurSel )
			return;

		string strNew = m_MenuTreeCtrl.GetCell(nRow, nCol);
		string strOld;

		strOld = mtnCurSel.GetText();

		bool bChanged;
		if(CheckMenuText(mtnCurSel, strNew, &bChanged))
		{
			if(bChanged)
			{
				mtnCurSel.SetText(strNew);
				SetDirty();
			}
		}
		else
		{
			m_MenuTreeCtrl.SetCell(nRow, nCol, strOld);
		}

		m_MenuTreeCtrl.SetEditable(flexEDNone);
		ShowInfo();
	}
	BOOL OnShowMenu(UINT nResIDCtrl, int nx, int ny)
	{
		if(GetMainPaneID() != nResIDCtrl)
			return FALSE;

		int nRow, nCol;
		m_MenuTreeCtrl.GetMouseCell(nRow, nCol);
		vector<uint> vnRows;
		m_MenuTreeCtrl.GetSelRows(vnRows);
		vector<uint> vec;
		if(nRow < 0 && m_MenuTreeCtrl.GetNumRows()>0)
			m_MenuTreeCtrl.RemoveSelection();
		else if( vnRows.Find(vec, nRow)<=0)
			m_MenuTreeCtrl.SelRow(nRow);

		vector<int> vnCmds;
		vector<bool> vbEnables;
		vector<string> vsTexts;
		if(!checkGetCurrValidCmds(vnCmds, vsTexts, vbEnables))
			return FALSE;
		CustomContextMenu myMenu(vnCmds, vsTexts, vbEnables);

		int nCmd = 0;
		myMenu.TrackPopupMenu(0, nx, ny, GetSafeHwnd(), &nCmd);
		
		bool bRet = false;
		//bool bClearClipboard = true;
		switch(nCmd)
		{
		case CUSTOM_MENU_ADD_ITEM:
		case CUSTOM_MENU_ADD_SEPARATOR:
		case CUSTOM_MENU_ADD_POPUP:
		case CUSTOM_MENU_INSERT_ITEM:
		case CUSTOM_MENU_INSERT_SEPARATOR:
		case CUSTOM_MENU_INSERT_POPUP:
			bRet = onAddOrInsert(nCmd);
			if(bRet)
				SetDirty();
			break;

		case CUSTOM_MENU_NEW_MAIN_POPUP:
			bRet = newMainPopup();
			if(bRet)
				SetDirty();
			break;

		case CUSTOM_MENU_DUPLICATE:
			bRet = duplicateCurrent();
			if(bRet)
				SetDirty();
			break;

		//case CUSTOM_MENU_MOVE_TO:
			//int nRowTo, nMoveToOption;
			//bool bRet = openMoveToDlg(nRow, nRowTo);
			//if(bRet)
				//bRet = pasteMenu(nRow, nRowTo, nMoveToOption, true);
			//break;

		case CUSTOM_MENU_DELETE:
			bRet = deleteCurrent();
			if(bRet)
				SetDirty();
			break;
			
		case CUSTOM_MENU_CUT:
		case CUSTOM_MENU_COPY:
			bRet = setCustomMenuClipboard(nRow, CUSTOM_MENU_CUT == nCmd);
			break;

		case CUSTOM_MENU_PASTE_BEFORE:
		case CUSTOM_MENU_PASTE_AFTER:
		case CUSTOM_MENU_PASTE_INSIDE:
			bRet = onPasteMenu(nCmd);
			if(bRet)
				SetDirty();
			break;

		default:
			return FALSE;
		}

		return bRet;
	}

	void ShowInfo()
	{
		TreeNode tnCurSel = GetCurSelNode();
		///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
		//if(!tnCurSel)
			//return;
		///End SUPPORT_UP_TO_THREE_CUSTOM_MENUS
		int nCurrSelType = GetNodeType(tnCurSel);

		SetReady(false);
		m_paramTree.Reset();
		switch(nCurrSelType)
		{
		case MENU_NODE_TAG_POPUP:
			getPopupInfo(m_paramTree, tnCurSel);
			break;
		case MENU_NODE_TAG_ITEM:
			getItemInfo(m_paramTree, tnCurSel);
			break;
		case MENU_NODE_TAG_SEP:
			getSeparatorInfo(m_paramTree, tnCurSel);
			break;
		default:
			getInvalidInfo(m_paramTree);///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
			break;
		}

		UpdateDynaControl(true, GETNEVENT_ON_INIT, false, 0, false);
		SetReady(true);

		// These code may help solving the refresh problem.
		RECT rtWnd;
		GetClientRect(&rtWnd);
		InvalidateRect(GetSafeHwnd(), &rtWnd, TRUE );
	}
	void OnAfterValueChange(int nRow, int nCol)
	{
		TreeNode trInfo = tree_get_node(m_paramTree, nRow);
		if( !GetCurSelNode() || !trInfo )
			return;

		TreeNode tnCurSel = GetCurSelNode();
		MenuTreeNode mtn(tnCurSel);

		int nCurrSelType = GetNodeType(tnCurSel);
		int nID = trInfo.DataID;
		
		string strNewValue = trInfo.strVal;
		switch(nID)
		{
		case CM_TEXT_ID:
			bool bChanged;
			if(CheckMenuText(tnCurSel, strNewValue, &bChanged))
			{
				if(bChanged)
				{
					mtn.SetText(strNewValue);
					m_MenuTreeCtrl.SetCell(GetSelectedRow(), 0, strNewValue);

					SetDirty();
				}
			}
			else
			{
				string strOldValue;
				trInfo.GetAttribute(STR_CHANGED_ATTRIB, strOldValue);
				trInfo.strVal = strOldValue;
			}
			break;
			
		case CM_TAG_ID:
			if(nCurrSelType != MENU_NODE_TAG_POPUP)
			{
				ASSERT(FALSE);
			}
			else
			{
				mtn.SetMergeTag(strNewValue);
				SetDirty();
			}
			break;
			
		case CM_WND_TYPE_ID:
			{
				BOOL bGraph		= m_paramTree.WndType.Graph.nVal;
				BOOL bWorkbook	= m_paramTree.WndType.Wkb.nVal;
				BOOL bMatrix	= m_paramTree.WndType.Mat.nVal;

				//const int nWndTypeNum = bGraph + bWorkbook + bMatrix;
				//if (0 == nWndTypeNum)
				//{
					//trInfo.nVal = 1;
					//break;
				//}

				//strNewValue = WndTypeToString(bWorkbook, bGraph, bMatrix);
				//mtn.SetWndType(strNewValue);
				mtn.SetWndType(bWorkbook, bGraph, bMatrix);
				SetDirty();
			}
			break;
			
		case CM_LT_ID:
			mtn.SetLTScript(strNewValue);
			SetDirty();
			break;
			
		case CM_LT_ENABLE_ID:
			mtn.SetLTEnable(strNewValue);
			SetDirty();
			break;
			
		case CM_TLB_ID:
			mtn.SetToolBar(strNewValue);
			SetDirty();
			break;
		
		case CM_PROMPT_ID:
			mtn.SetPrompt(strNewValue);
			SetDirty();
			break;
		default:
			ASSERT(FALSE);
			return;

		}
	}
	BOOL OnKey(Control ctrl, UINT msg, UINT wParam, UINT lParam)
	{
		if( msg == WM_KEYDOWN )
		{
			if ( VK_DELETE == wParam )
			{
				bool bRet = deleteCurrent();
				if(bRet)
					SetDirty();
			}
			else if ( VK_F2 == wParam )
			{
				setCurSelItemEditable();
			}
		}

		return FALSE; // return FALSE for not eating message for Enter key in Input window
	}
private:
	BOOL setCurSelItemEditable()
	{
		const int nNodeTagType = GetNodeType( GetCurSelNode() );
		if( MENU_NODE_TAG_POPUP != nNodeTagType && MENU_NODE_TAG_ITEM != nNodeTagType )
			return FALSE;
		m_MenuTreeCtrl.SetEditable(flexEDKbdMouse);
		return TRUE;
	}

	void getPopupInfo(TreeNode& tr, const TreeNode& trPopup)
	{
		MenuTreeNode mtnPopup(trPopup);
		if(!mtnPopup)
			return;

		string strText		= mtnPopup.GetText();
		//string strWndType	= mtnPopup.GetWndType();
		string strTag		= mtnPopup.GetMergeTag();

		BOOL bGraph, bWorkbook, bMatrix;
		mtnPopup.GetWndType(bWorkbook, bGraph, bMatrix);
		//StringToWndType(strWndType, bWorkbook, bGraph, bMatrix);
		//strWndType = WndTypeToString(bWorkbook, bGraph, bMatrix);
		
		GETN_USE(tr)
		GETN_STR(ItemText, STR_GUI_LABEL_POPUP_TEXT, strText) 			GETN_ID(CM_TEXT_ID)
		GETN_BEGIN_BRANCH(WndType, STR_GUI_LABEL_WND_TYPE)		//GETN_CHECKBOX_BRANCH(1)
		GETN_OPTION_BRANCH(GETNBRANCH_OPEN)
			GETN_CHECK(Wkb, STR_GUI_LABEL_WORKBOOK_TYPE, bWorkbook)		GETN_ID(CM_WND_TYPE_ID)
			GETN_CHECK(Graph, STR_GUI_LABEL_GRAPH_TYPE, bGraph)			GETN_ID(CM_WND_TYPE_ID)
			GETN_CHECK(Mat, STR_GUI_LABEL_MATRIX_TYPE, bMatrix)			GETN_ID(CM_WND_TYPE_ID)
		GETN_END_BRANCH(WndType)

		if(needMergeTag(trPopup))
		{
			GETN_STR(Tag, STR_GUI_LABEL_POPUP_TAG, strTag)				GETN_ID(CM_TAG_ID)
			GETN_STR(Hint, STR_MERGE_TAG_HINTS, "") 					GETN_HINT
		}
	}
	void getItemInfo(TreeNode& tr, const TreeNode& trItem)
	{
		MenuTreeNode mtnItem(trItem);
		if(!mtnItem)
			return;

		string strText		= mtnItem.GetText();
		//string strWndType	= mtnItem.GetWndType();
		string strLT		= mtnItem.GetLTScript();
		string strLTEnable	= mtnItem.GetLTEnable();
		string strTlb		= mtnItem.GetToolBar();
		string strPrompt = mtnItem.GetPrompt();

		BOOL bGraph, bWorkbook, bMatrix;
		mtnItem.GetWndType(bWorkbook, bGraph, bMatrix);
		//StringToWndType(strWndType, bWorkbook, bGraph, bMatrix);
		//strWndType = WndTypeToString(bWorkbook, bGraph, bMatrix);

		GETN_USE(tr)
		GETN_STR(ItemText, STR_GUI_LABEL_ITEM_TEXT, strText)			GETN_ID(CM_TEXT_ID)
		GETN_MULTILINE_TEXT(LT, STR_GUI_LABEL_LT_SCRIPT, strLT)			GETN_ID(CM_LT_ID)
		GETN_MULTILINE_EDIT_DISPLAY_ROW_HEIGHT_RANGE("10-30")
		GETN_CURRENT_SUBNODE.SetAttribute(STR_MULTI_EDT_EXPSHR_ATTRIB, 1);
		GETN_STR(LTEnable, STR_GUI_LABEL_LT_ENABLE, strLTEnable)		GETN_ID(CM_LT_ENABLE_ID)
		//GETN_STR(tlb, STR_GUI_LABEL_TLB, strTlb)						GETN_ID(CM_TLB_ID)
		GETN_STR(Prompt, STR_GUI_LABEL_PROMPT, strPrompt)				GETN_ID(CM_PROMPT_ID)

		GETN_BEGIN_BRANCH(WndType, STR_GUI_LABEL_WND_TYPE)		//GETN_CHECKBOX_BRANCH(0)
		GETN_OPTION_BRANCH(GETNBRANCH_OPEN)
			GETN_CHECK(Wkb, STR_GUI_LABEL_WORKBOOK_TYPE, bWorkbook)		GETN_ID(CM_WND_TYPE_ID)
			GETN_CHECK(Graph, STR_GUI_LABEL_GRAPH_TYPE, bGraph)			GETN_ID(CM_WND_TYPE_ID)
			GETN_CHECK(Mat, STR_GUI_LABEL_MATRIX_TYPE, bMatrix)			GETN_ID(CM_WND_TYPE_ID)
		GETN_END_BRANCH(WndType)
	}

	///Kyle 06/12/2009 QA70-13423 NEW_TAB_FOR_EDITING_OMC_LIST
	void getSplitterDisableInfo(TreeNode& tr)
	{
		GETN_USE(tr)
		GETN_STR(Hint, STR_SPLITTER_DISABLE_TIPS, "") 			GETN_HINT
	}
	///End NEW_TAB_FOR_EDITING_OMC_LIST

	
	void getSeparatorInfo(TreeNode& tr, const TreeNode& trSeparator)
	{
		GETN_USE(tr)
		GETN_STR(Hint, STR_MENU_ITEM_SEPARATOR, "") 			GETN_HINT
	}
	
	///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
	void getInvalidInfo(TreeNode& tr)
	{
		GETN_USE(tr)
		if(GetMainPopupCount() == 0)
		{
			// multiple hints
			string str = STR_HINT_NO_MAIN_POPUP;
			vector<string> vsHints;
			str.GetTokens(vsHints, '|');
			for(int ii=0; ii<vsHints.GetSize(); ii++)
			{
				GETN_STR(Hint, vsHints[ii], "")			GETN_HINT
			}
		}
		else
		{
			GETN_STR(Hint, STR_NO_SELECTION, "")				GETN_HINT
		}
	}
	///End SUPPORT_UP_TO_THREE_CUSTOM_MENUS
	
	BOOL duplicateCurrent()
	{
		if( !GetCurSelNode() )
			return FALSE;
		
		TreeNode trCurSel = GetCurSelNode();
		TreeNode trParent = trCurSel.Parent();
		if(!trParent)
			return false;
		
		string strTagName = "Empty";
		TreeNode trNew;
		if(trCurSel.NextNode)
			trNew = trParent.InsertNode(trCurSel.NextNode, strTagName);
		else
			trNew = trParent.AddNode(strTagName);
		if(!trNew)
			return false;
		trNew.Replace(trCurSel);
		trNew.RemoveAttribute(STR_BEING_CUT_ATTRIB);			// the current may in clipboard
		
		// rename
		MenuTreeNode mtn(trNew);
		string strNewText = mtn.GetText();
		if( GetMenuEnumLabelText(trNew, strNewText) )
			mtn.SetText(strNewText);
		
		int nRow 		= GetSelectedRow(),
			nLevel 		= m_MenuTreeCtrl.GetLevel(nRow);
		///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
		//nRow += 1+GetSubItemCount(trCurSel);
		int nPopups, nCmdItems, nSeparators;
		GetMenuItemsCount(trNew, &nPopups, &nCmdItems, &nSeparators);
		m_nNumSubPopups += (nPopups - (MainPopup(trNew)? 1 : 0));
		m_nNumCmdItems += nCmdItems;
		m_nNumSeparator += nSeparators;

		nRow += (nPopups + nCmdItems + nSeparators);
		///End CHECK_NUMBERS_OF_EACH_MENU_TYPE

		m_MenuTreeCtrl.AddTreeNodes(trNew, 0, STR_STOP_ATTRIB, nLevel, &nRow);
		
		return true;
	}
	
	BOOL deleteCurrent()
	{
		/*
		if( !GetCurSelNode() )
			return FALSE;

		int nRowStart 		= GetSelectedRow();
		TreeNode tnCurSel = GetCurSelNode();
		int nCount = 1 + GetSubItemCount(tnCurSel);
		
		for(int nDelRow = (nRowStart + nCount - 1); nDelRow >= nRowStart; nDelRow--)
			m_MenuTreeCtrl.DeleteRow(nDelRow);

		BOOL bRet = tnCurSel.Remove();
		SelectRow(nRowStart);
		*/
		BOOL bRet = false;
		vector<uint> vnRows;
		m_MenuTreeCtrl.GetSelRows(vnRows);
		vnRows.Sort();
		int ii=0;
		int nDelRows = 0;
		while(ii < vnRows.GetSize())
		{
			int nRow = vnRows[ii] - nDelRows;
			TreeNode tnSel = GetTreeNode(nRow);

			///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
			//int nCount = 1 + GetSubItemCount(tnSel);
			int nPopups, nCmdItems, nSeparators;
			GetMenuItemsCount(tnSel, &nPopups, &nCmdItems, &nSeparators);
			m_nNumSubPopups -= (nPopups - (MainPopup(tnSel) ? 1 : 0));
			m_nNumCmdItems -= nCmdItems;
			m_nNumSeparator -= nSeparators;

			int nCount = nPopups + nCmdItems + nSeparators;
			///End CHECK_NUMBERS_OF_EACH_MENU_TYPE

			for(int nDelRow = (nRow + nCount - 1); nDelRow >= nRow; nDelRow--)
				m_MenuTreeCtrl.DeleteRow(nDelRow);
			bRet = tnSel.Remove();

			nDelRows += nCount;
			while(ii<vnRows.GetSize() && vnRows[ii]<nRow+nDelRows)
				ii++;
		}
		if(vnRows.GetSize())
		{
			int nNewSelRow = vnRows[0];
			if(nNewSelRow >= m_MenuTreeCtrl.GetNumRows() + m_MenuTreeCtrl.GetRowOffset())
			{
				nNewSelRow = m_MenuTreeCtrl.GetNumRows() + m_MenuTreeCtrl.GetRowOffset() - 1;
				
				int nParentRow = m_MenuTreeCtrl.GetParent(nNewSelRow);
				while(nParentRow >= 0)
				{
					if(m_MenuTreeCtrl.GetCollapsed(nParentRow) != flexOutlineExpanded)
						nNewSelRow = nParentRow;
					nParentRow = m_MenuTreeCtrl.GetParent(nParentRow);
				}
			}
			SelectRow(nNewSelRow);
			
			Control ctrl;
			OnListRowChange(ctrl);
		}

		return bRet;
	}
	
	BOOL onAddOrInsert(int nCmd)
	{
		//TreeNode tnCurSel = GetCurSelNode();
		int nAddMenuType;
		bool bInsert;
		switch(nCmd)
		{
		case CUSTOM_MENU_ADD_ITEM:
			nAddMenuType = MENU_NODE_TAG_ITEM;
			bInsert = false;
			break;
			
		case CUSTOM_MENU_ADD_SEPARATOR:
			nAddMenuType = MENU_NODE_TAG_SEP;
			bInsert = false;
			break;
			
		case CUSTOM_MENU_ADD_POPUP:
			nAddMenuType = MENU_NODE_TAG_POPUP;
			bInsert = false;
			break;
			
		case CUSTOM_MENU_INSERT_ITEM:
			nAddMenuType = MENU_NODE_TAG_ITEM;
			bInsert = true;
			break;
			
		case CUSTOM_MENU_INSERT_SEPARATOR:
			nAddMenuType = MENU_NODE_TAG_SEP;
			bInsert = true;
			break;
			
		case CUSTOM_MENU_INSERT_POPUP:
			nAddMenuType = MENU_NODE_TAG_POPUP;
			bInsert = true;
			break;
		default:
			return false;
		}

		return addPopupOrItem(GetSelectedRow(), nAddMenuType, bInsert);
	}
	
	BOOL addPopupOrItem(int nRow, int nMenuType, bool bInsert)
	{
		TreeNode trSel = GetTreeNode(nRow);
		if( !trSel )
			return FALSE;
		if(!bInsert && MENU_NODE_TAG_POPUP != GetNodeType(trSel))
			return FALSE;
		
		int nLevel 		= m_MenuTreeCtrl.GetLevel(nRow),
			nSubItem	= GetSubItemCount(trSel);
			
		TreeNode tnNew = AddOrInsertMenu(trSel, nMenuType, bInsert);
		MenuTreeNode mtnNew(tnNew);
		if(!tnNew)
			return FALSE;
		///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
		switch(nMenuType)
		{
		case MENU_NODE_TAG_POPUP:
			if(!MainPopup(tnNew))
				m_nNumSubPopups++;
			break;
		case MENU_NODE_TAG_ITEM:
			m_nNumCmdItems++;
			break;
		case MENU_NODE_TAG_SEP:
			m_nNumSeparator++;
			break;
		}
		///End CHECK_NUMBERS_OF_EACH_MENU_TYPE
		
		if(!bInsert)	// add to the current popup
		{
			m_MenuTreeCtrl.SetCollapsed(nRow, flexOutlineExpanded);
			nRow += nSubItem + 1;
			nLevel++;
		}
		int nFromRow = nRow;
		m_MenuTreeCtrl.AddTreeNodes(tnNew, 0, STR_STOP_ATTRIB, nLevel, &nFromRow);

		SelectRow(nRow);
		Control ctrl;
		OnListRowChange(ctrl);

		return TRUE;
	}
	
	bool newMainPopup()
	{
		TreeNode tnNew = NewMainPopup();
		if(!tnNew)
			return false;
		m_MenuTreeCtrl.AddTreeNodes(tnNew, 0, STR_STOP_ATTRIB, 0, NULL);

		SelectRow(GetAllItemCount()-1);		// select the last row
		Control ctrl;
		OnListRowChange(ctrl);

		return TRUE;
	}

	bool openMoveToDlg(int nRowFrom, int& nRowTo)
	{
		ASSERT(false);
		return false;
	}
	
	bool moveMenuAllowed(int nRow, bool bCut)
	{
		// always allow if the row is valid
		return GetTreeNode(nRow).IsValid();
	}
	
	bool pasteMenuAllowed(int nRowSrc, int nRowDest, int nMoveToOption, bool bCut)
	{
		if(!moveMenuAllowed(nRowSrc, bCut))
			return false;

		TreeNode trSrc = GetTreeNode(nRowSrc);
		if(!trSrc)
			return false;
	
		bool 	bSrcMainPopup = MainPopup(trSrc);
		int 	nSrcType = GetNodeType(trSrc);

		int 	nMainPopup = GetMainPopupCount();
		
		///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
		int nPopups, nCmdItems, nSeparator;
		GetMenuItemsCount(trSrc, &nPopups, &nCmdItems, &nSeparator);
		///End CHECK_NUMBERS_OF_EACH_MENU_TYPE

		if(nRowSrc == nRowDest)	// a special case, the same items
		{
			if(bCut || nMoveToOption == CM_MOVE_TO_INSIDE)
				return false;
			if(bSrcMainPopup && nMainPopup >= CUSTOM_MENU_MAX_MAIN_POPUP)
				return false;

			///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE, only need to check the numbers, the depth won't be larger than that of the current
			if(bSrcMainPopup)
				nPopups--;
			if(	m_nNumSubPopups + nPopups > CUSTOM_MENU_MAX_SUB_POPUP ||
				m_nNumCmdItems + nCmdItems > CUSTOM_MENU_MAX_COMMAND_ITEMS ||
				m_nNumSeparator + nSeparator > CUSTOM_MENU_MAX_SEPARATOR)
				return false;
			///End CHECK_NUMBERS_OF_EACH_MENU_TYPE
			
			return true;
		}

		int nSrcCount = 1 + GetSubItemCount(trSrc);
		if(nRowDest > nRowSrc && nRowDest < nRowSrc + nSrcCount)			// dest is part of src
			return false;

		TreeNode trDest = GetTreeNode(nRowDest);
		if(!trDest)
			return false;
		bool bDestMainPopup = MainPopup(trDest);
		int nDestType = GetNodeType(trDest);
		int nDestCount = 1 + GetSubItemCount(trDest);

		///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
		//if(nMoveToOption == CM_MOVE_TO_INSIDE)			// simple case, move inside one item is allowed if and only if the item is popup
		//	return nDestType == MENU_NODE_TAG_POPUP;
		if(nMoveToOption == CM_MOVE_TO_INSIDE && nDestType != MENU_NODE_TAG_POPUP)			// simple case, move inside one item is allowed if and only if the item is popup
			return false;
		
		if(bDestMainPopup && nMoveToOption != CM_MOVE_TO_INSIDE)
			nPopups--;
		if(	m_nNumSubPopups + nPopups > CUSTOM_MENU_MAX_SUB_POPUP ||
			m_nNumCmdItems + nCmdItems > CUSTOM_MENU_MAX_COMMAND_ITEMS ||
			m_nNumSeparator + nSeparator > CUSTOM_MENU_MAX_SEPARATOR)
			return false;

		// check the depth
		int nLevelDest = m_MenuTreeCtrl.GetLevel(nRowDest);
		int nMovedDepth = GetDepth(trSrc, true);
		int nNewDepth = nLevelDest + nMovedDepth;
		if(nMoveToOption != CM_MOVE_TO_INSIDE)
			nNewDepth--;
		if(nNewDepth > CUSTOM_MENU_MAX_POPUP_DEPTH)
			return false;
			
		if(nMoveToOption == CM_MOVE_TO_INSIDE)
			return true;
		///End CHECK_NUMBERS_OF_EACH_MENU_TYPE

		if(bDestMainPopup)
		{
			if(bSrcMainPopup)
				return (bCut || nMainPopup < CUSTOM_MENU_MAX_MAIN_POPUP);
			return (nSrcType == MENU_NODE_TAG_POPUP && nMainPopup < CUSTOM_MENU_MAX_MAIN_POPUP);
		}
		else
		{
			return true;
		}
		return true;
	}

	//
	bool setCustomMenuClipboard(int nRow, bool bCut)
	{
		clearCustomMenuClipboard();

		TreeNode tr = GetTreeNode(nRow);
		if(tr)
		{
			tr.SetAttribute(STR_BEING_CUT_ATTRIB, "");
			m_customMenuClipboard.bUse = true;
			m_customMenuClipboard.bCut = bCut;
			return true;
		}
		return false;
	}
	
	int findClipboardRow(int nRowStart = -1)
	{
		int nRows;
		TreeNode trStart = GetTreeNode(nRowStart);
		if(trStart)
		{
			nRows = 1 + GetSubItemCount(trStart);
		}
		else
		{
			nRows = m_MenuTreeCtrl.GetNumRows();
			nRowStart = 0;
		}
		int nRowEnd = nRowStart + nRows;
		
		string strAttribVal;
		for(int nRow = nRowStart; nRow < nRowEnd; nRow++)
		{
			TreeNode tr = GetTreeNode(nRow);
			if(tr.GetAttribute(STR_BEING_CUT_ATTRIB, strAttribVal))
				return nRow;
		}
		return -1;
	}
	
	void clearCustomMenuClipboard()
	{
		TreeNode tr = GetTreeNode( findClipboardRow() );
		if(tr)
			tr.RemoveAttribute(STR_BEING_CUT_ATTRIB);
		m_customMenuClipboard.bUse = false;
	}
	
	bool customMenuClipboardUsable()
	{
		if(!m_customMenuClipboard.bUse)
			return false;

		if(findClipboardRow() < 0)
			m_customMenuClipboard.bUse = false;

		return m_customMenuClipboard.bUse;
	}
	
	bool getCustomMenuClipboard(int& nRow, bool& bCut)
	{
		if(!m_customMenuClipboard.bUse)
			return false;
		nRow = findClipboardRow();
		TreeNode tr = GetTreeNode(nRow);
		if(!tr)
		{
			m_customMenuClipboard.bUse = false;
			return false;
		}
		bCut = m_customMenuClipboard.bCut;
		return true;
	}

	bool onPasteMenu(int nCmd)
	{
		int nRowSrc, nRowDest, nMoveToOption;
		bool bCut;
		if(!getCustomMenuClipboard(nRowSrc, bCut))
			return false;
		nRowDest = GetSelectedRow();
		switch(nCmd)
		{
		case CUSTOM_MENU_PASTE_BEFORE:
			nMoveToOption = CM_MOVE_TO_BEFORE;
			break;
		case CUSTOM_MENU_PASTE_AFTER:
			nMoveToOption = CM_MOVE_TO_AFTER;
			break;
		case CUSTOM_MENU_PASTE_INSIDE:
			nMoveToOption = CM_MOVE_TO_INSIDE;
			break;
		default:
			return false;
		}
		return pasteMenu(nRowSrc, nRowDest, nMoveToOption, bCut);
	}
	
	bool pasteMenu(int nRowSrc, int nRowDest, int nMoveToOption, bool bCut)
	{
		if(!pasteMenuAllowed(nRowSrc, nRowDest, nMoveToOption, bCut))		// not allowed, nothing to do
			return false;

		TreeNode trSrc = GetTreeNode(nRowSrc);
		if(!trSrc)
			return false;
		TreeNode trDest = GetTreeNode(nRowDest);
		if(!trDest)
			return false;
		int nLevelDest = m_MenuTreeCtrl.GetLevel(nRowDest);

		///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
		//int nItemSrc = 1 + GetSubItemCount(trSrc);
		int nSubPopupSrc, nCmdItemsSrc, nSeparatorsSrc;
		GetMenuItemsCount(trSrc, &nSubPopupSrc, &nCmdItemsSrc, &nSeparatorsSrc);
		int nItemSrc = nSubPopupSrc + nCmdItemsSrc + nSeparatorsSrc;
		if(MainPopup(trSrc))
			nSubPopupSrc--;
		///End CHECK_NUMBERS_OF_EACH_MENU_TYPE

		int nItemDest = 1 + GetSubItemCount(trDest);
		if(nRowDest > nRowSrc && nRowDest < nRowSrc + nItemSrc)
			return false;

		// since need to rename the pasted item, so when bCut is true, firstly duplicate the source tree node the remove it from the menu tree, and then add it back on paste
		Tree trSrcDup;
		if(bCut)
		{
			trSrcDup = trSrc;
			trSrc.Remove();
		}

		int nNewStartRow, nNewLevel;
		TreeNode trNew;
		switch(nMoveToOption)
		{
		case CM_MOVE_TO_BEFORE:
			TreeNode trParent = trDest.Parent();
			if(trParent)
				trNew = trParent.InsertNode(trDest, "Empty");
			nNewStartRow = nRowDest;
			nNewLevel = nLevelDest;
			break;

		case CM_MOVE_TO_AFTER:
			TreeNode trParent = trDest.Parent();
			if(trDest.NextNode)
				trNew = trParent.InsertNode(trDest.NextNode, "Empty");
			else
				trNew = trParent.AddNode();
			nNewStartRow = nRowDest + nItemSrc;
			nNewLevel = nLevelDest;
			break;

		case CM_MOVE_TO_INSIDE:
			trNew = trDest.AddNode();
			nNewStartRow = nRowDest + nItemDest;
			nNewLevel = nLevelDest + 1;
			break;

		default:
			return false;
		}
		if(!trNew)
			return false;

		// get new name to rename the pasted item
		string strNewText;
		if(bCut)
		{
			MenuTreeNode mtnSrc(trSrcDup);
			strNewText = mtnSrc.GetText();
		}
		else
		{
			MenuTreeNode mtnSrc(trSrc);
			strNewText = mtnSrc.GetText();
		}
		GetMenuEnumLabelText(trDest, strNewText);

		if(bCut)
			trNew.Replace(trSrcDup);
		else
			trNew.Replace(trSrc);
		trNew.RemoveAttribute(STR_BEING_CUT_ATTRIB);			// should not copy the clipboard mark

		MenuTreeNode mtnNew(trNew);
		mtnNew.SetText(strNewText);

		///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
		//int nItemSrc = 1 + GetSubItemCount(trSrc);
		int nSubPopupNew, nCmdItemsNew, nSeparatorsNew;
		GetMenuItemsCount(trNew, &nSubPopupNew, &nCmdItemsNew, &nSeparatorsNew);
		if(MainPopup(trNew))
			nSubPopupNew--;

		m_nNumSubPopups += nSubPopupNew;
		m_nNumCmdItems +=nCmdItemsNew;
		m_nNumSeparator += nSeparatorsNew;
		if(bCut)
		{
			m_nNumSubPopups -= nSubPopupSrc;
			m_nNumCmdItems -= nCmdItemsSrc;
			m_nNumSeparator -= nSeparatorsSrc;
		}
		///End CHECK_NUMBERS_OF_EACH_MENU_TYPE


		int nStartRow = nNewStartRow;
		m_MenuTreeCtrl.AddTreeNodes(trNew, 0, STR_STOP_ATTRIB, nNewLevel, &nStartRow);
		
		if(bCut)
		{
			if(nRowSrc > nNewStartRow)
			{
				nRowSrc += nItemSrc;
			}
			else
			{
				nNewStartRow -= nItemSrc;
			}
			for(int nDelRow = nRowSrc + nItemSrc-1; nDelRow >= nRowSrc; nDelRow--)
				m_MenuTreeCtrl.DeleteRow(nDelRow);
		}

		SelectRow(nNewStartRow);
		Control ctrl;
		OnListRowChange(ctrl);
		
		if(bCut)			// only here need to clear the clipboard
			clearCustomMenuClipboard();

		return true;
	}

	///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
	/*
	bool duplicateAllowed(const TreeNode& trSel)
	{
		return insertItemAllowed(trSel);
	}
	
	bool deleteItemAllowed(const TreeNode& trSel)
	{
		return insertItemAllowed(trSel);
	}
	
	bool insertItemAllowed(const TreeNode& trSel)
	{
		string str;
		return octree_get_level(&str, &trSel, NULL, false) > 1;
	}
	*/
	///End SUPPORT_UP_TO_THREE_CUSTOM_MENUS
	
	bool needMergeTag(const TreeNode& trSel)
	{
		if(MENU_NODE_TAG_POPUP != GetNodeType(trSel))
			return false;
		string str;
		return octree_get_level(&str, &trSel, NULL, false) > 1;
	}
	
	///Kyle 05/07/2009 QA70-13423 SUPPORT_UP_TO_THREE_CUSTOM_MENUS
	bool checkGetCurrValidCmds(vector<int>& vnCmds, vector<string>& vsTexts, vector<bool>& vbEnables)
	{
		vnCmds.SetSize(0);
		vsTexts.SetSize(0);
		vbEnables.SetSize(0);

		//  get selection
		vector<uint> vnRows;
		m_MenuTreeCtrl.GetSelRows(vnRows);

		// no selection
		if(vnRows.GetSize() == 0)
		{
			vnCmds.Add(CUSTOM_MENU_NEW_MAIN_POPUP);
			vsTexts.Add(STR_CUSTOM_MENU_NEW_MAIN_POPUP);
			vbEnables.Add(GetMainPopupCount() < CUSTOM_MENU_MAX_MAIN_POPUP);
			return (vnCmds.GetSize()>0);
		}

		// with selection
		vector<int> vn = {	CUSTOM_MENU_ADD_POPUP,
							CUSTOM_MENU_ADD_ITEM,
							CUSTOM_MENU_ADD_SEPARATOR,
							CUSTOM_MENU_INVALID,

							CUSTOM_MENU_INSERT_POPUP,
							CUSTOM_MENU_INSERT_ITEM,
							CUSTOM_MENU_INSERT_SEPARATOR,
							CUSTOM_MENU_INVALID,
							
							CUSTOM_MENU_CUT,
							CUSTOM_MENU_COPY,
							CUSTOM_MENU_PASTE_BEFORE,
							CUSTOM_MENU_PASTE_AFTER,
							CUSTOM_MENU_PASTE_INSIDE,
							CUSTOM_MENU_INVALID,

							CUSTOM_MENU_DUPLICATE,
							CUSTOM_MENU_DELETE
						};
		vector<string> vs;
		vs.Add(STR_CUSTOM_MENU_ADD_POPUP);
		vs.Add(STR_CUSTOM_MENU_ADD_ITEM);
		vs.Add(STR_CUSTOM_MENU_ADD_SEPARATOR);
		vs.Add(STR_CUSTOM_MENU_INVALID);
		vs.Add(STR_CUSTOM_MENU_INSERT_POPUP);
		vs.Add(STR_CUSTOM_MENU_INSERT_ITEM);
		vs.Add(STR_CUSTOM_MENU_INSERT_SEPARATOR);
		vs.Add(STR_CUSTOM_MENU_INVALID);
		vs.Add(STR_CUSTOM_MENU_CUT);
		vs.Add(STR_CUSTOM_MENU_COPY);
		vs.Add(STR_CUSTOM_MENU_PASTE_BEFORE);
		vs.Add(STR_CUSTOM_MENU_PASTE_AFTER);
		vs.Add(STR_CUSTOM_MENU_PASTE_INSIDE);
		vs.Add(STR_CUSTOM_MENU_INVALID);
		vs.Add(STR_CUSTOM_MENU_DUPLICATE);
		vs.Add(STR_CUSTOM_MENU_DELETE);

		vnCmds = vn;
		vsTexts = vs;
		ASSERT(vn.GetSize() == vs.GetSize());
		vbEnables.SetSize(vnCmds.GetSize());
		vector<int> vnEnablesGroup;

		// multiple selection, only delete allowed
		if(vnRows.GetSize() > 1)
		{
			vnEnablesGroup.Add(CUSTOM_MENU_DELETE);
		}
		else								// sigle selection
		{
			TreeNode tnCurSel = GetTreeNode(vnRows[0]);
			int nCurrSelType = GetNodeType(tnCurSel);
			if( MENU_NODE_TAG_POPUP != nCurrSelType && MENU_NODE_TAG_ITEM != nCurrSelType && MENU_NODE_TAG_SEP != nCurrSelType )
				return false;
			
			int nCurrLevel = m_MenuTreeCtrl.GetLevel(vnRows[0]);			///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
	
			// enable add cmd
			if(nCurrSelType == MENU_NODE_TAG_POPUP)
			{
				///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
				//vnEnablesGroup.Add(CUSTOM_MENU_ADD_POPUP);
				//vnEnablesGroup.Add(CUSTOM_MENU_ADD_ITEM);
				//vnEnablesGroup.Add(CUSTOM_MENU_ADD_SEPARATOR);
				if(m_nNumSubPopups < CUSTOM_MENU_MAX_SUB_POPUP && nCurrLevel < CUSTOM_MENU_MAX_POPUP_DEPTH)
					vnEnablesGroup.Add(CUSTOM_MENU_ADD_POPUP);
				if(m_nNumCmdItems < CUSTOM_MENU_MAX_COMMAND_ITEMS)
					vnEnablesGroup.Add(CUSTOM_MENU_ADD_ITEM);
				if(m_nNumSeparator < CUSTOM_MENU_MAX_SEPARATOR)
					vnEnablesGroup.Add(CUSTOM_MENU_ADD_SEPARATOR);
				///End CHECK_NUMBERS_OF_EACH_MENU_TYPE
			}
	
			// enable insert cmd
			if(MainPopup(tnCurSel))
			{
				if(GetMainPopupCount() < CUSTOM_MENU_MAX_MAIN_POPUP)
					vnEnablesGroup.Add(CUSTOM_MENU_INSERT_POPUP)
			}
			else
			{
				///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
				//vnEnablesGroup.Add(CUSTOM_MENU_INSERT_POPUP);
				//vnEnablesGroup.Add(CUSTOM_MENU_INSERT_ITEM);
				//vnEnablesGroup.Add(CUSTOM_MENU_INSERT_SEPARATOR);
				if(m_nNumSubPopups < CUSTOM_MENU_MAX_SUB_POPUP && nCurrLevel-1 < CUSTOM_MENU_MAX_POPUP_DEPTH)
					vnEnablesGroup.Add(CUSTOM_MENU_INSERT_POPUP);
				if(m_nNumCmdItems < CUSTOM_MENU_MAX_COMMAND_ITEMS)
					vnEnablesGroup.Add(CUSTOM_MENU_INSERT_ITEM);
				if(m_nNumSeparator < CUSTOM_MENU_MAX_SEPARATOR)
					vnEnablesGroup.Add(CUSTOM_MENU_INSERT_SEPARATOR);
				///End CHECK_NUMBERS_OF_EACH_MENU_TYPE
			}
	
			// others, cut, copy, paste, duplicate, move to..., delete
			vnEnablesGroup.Add(CUSTOM_MENU_CUT);
			vnEnablesGroup.Add(CUSTOM_MENU_COPY);
			if(customMenuClipboardUsable())
			{
				vnEnablesGroup.Add(CUSTOM_MENU_PASTE_BEFORE);
				vnEnablesGroup.Add(CUSTOM_MENU_PASTE_AFTER);
				if(MENU_NODE_TAG_POPUP == nCurrSelType)				// special case, a simple checking
					vnEnablesGroup.Add(CUSTOM_MENU_PASTE_INSIDE);
			}

			///Kyle 06/10/2009 QA70-13423 CHECK_NUMBERS_OF_EACH_MENU_TYPE
			//if(!MainPopup(tnCurSel) || GetMainPopupCount() < CUSTOM_MENU_MAX_MAIN_POPUP)
			//	vnEnablesGroup.Add(CUSTOM_MENU_DUPLICATE);
			if(!MainPopup(tnCurSel) || GetMainPopupCount() < CUSTOM_MENU_MAX_MAIN_POPUP)
			{
				int nPopups, nCmdItems, nSeparators;
				GetMenuItemsCount(tnCurSel, &nPopups, &nCmdItems, &nSeparators);
				if(MainPopup(tnCurSel))
					nPopups--;
				if(	m_nNumSubPopups+nPopups < CUSTOM_MENU_MAX_SUB_POPUP &&
					m_nNumCmdItems+nCmdItems < CUSTOM_MENU_MAX_COMMAND_ITEMS &&
					m_nNumSeparator+nSeparators < CUSTOM_MENU_MAX_SEPARATOR		)
					vnEnablesGroup.Add(CUSTOM_MENU_DUPLICATE);
			}
			///End CHECK_NUMBERS_OF_EACH_MENU_TYPE
	
			//vnCmds.Add(CUSTOM_MENU_MOVE_TO);		//kyle, to do
	
			vnEnablesGroup.Add(CUSTOM_MENU_DELETE);
			
		}
		for(int ii=vnEnablesGroup.GetSize()-1; ii>=0; ii--)
		{
			vector<uint> vec;
			if(vnCmds.Find(vec, vnEnablesGroup[ii]) > 0)
				vbEnables[vec[0]] = true;
		}
		
		return (vnCmds.GetSize()>0);
	}
	///End SUPPORT_UP_TO_THREE_CUSTOM_MENUS
private:
	CustomMenuClipboard		m_customMenuClipboard;
	GridTreeControl			m_MenuTreeCtrl;
};


///////////////////////////////////////////////////////////////////////////////
/*
class LTCustomMenuMoveToDlg : public Dialog
{
public:
	LTCustomMenuMoveToDlg() : Dialog(IDD_LT_CUSTOM_MENU_MOVETO_DLG, "ODlg8")
	{
	}
	~LTCustomMenuMoveToDlg()
	{
	}

	int DoModalEx(int& nRowTo, int& nMoveType, const TreeNode& trMainMenu, const TreeNode& trCurSel, HWND hParent = NULL)
	{
		m_trMainMenu = trMainMenu;
		m_trCurSel = trCurSel;

		InitMsgMap();
		int nRet = Dialog::DoModal(hParent, 0, "Move To");
		if(nRet == IDOK)
		{
			//m_MSplitter.GetDestMenu(trDest, nMoveType);
		}
		return nRet;
	}
	
protected:
	
EVENTS_BEGIN
	ON_INIT(OnInitDialog) 
	//ON_READY(OnReady)
	//ON_SIZE(OnDlgResize)
	//ON_DESTROY(OnDestroy)
	//ON_HELPINFO(OnHelp)
	//ON_OK(OnOK)
	//ON_CANCEL(OnClose)

EVENTS_END

	BOOL OnInitDialog()
	{
		//string strDlgName = "Move To";
		//Dialog::OnInitDialog(0, strDlgName);
		//m_MSplitter.Init(IDC_MENU_TREE_DYNA, *this, 0, strDlgName);
		//return m_MSplitter.SetMenu(m_trMainMenu);
		m_comboOption = GetItem(IDC_COMBO_MOVETO_OPTION);
		m_comboOption.ResetContent();
		vector<string> vs = {STR_CM_MOVE_TO_BEFORE, STR_CM_MOVE_TO_AFTER, STR_CM_MOVE_TO_INSIDE};
		for( int nItem = 0; nItem < vs.GetSize(); nItem++ )
			m_comboOption.AddString(vs[nItem]);
		m_comboOption.SetCurSel(0);

		//initGrid();
		return true;
	}
	BOOL OnReady()
	{
		return true;
	}
	BOOL OnDestroy()
	{
		//SetInitReady();
		//m_MSplitter.SetTreeEditPaneSize(80, true);
		return TRUE;
	}

	BOOL OnOK()
	{
		return true;
	}
	BOOL OnClose()
	{
		return true;
	}
private:
	void initGrid()
	{
		//void Init(int nID, WndContainer& dlg, WndContainer* pParentDlg = NULL)
		//m_MSplitter.Init(IDC_MOVETO_MENU_GRID, *this);
		m_MSplitter.Init(IDC_MOVETO_MENU_GRID, false, true, NULL, *this);
		m_MSplitter.SetReady(false);
		m_MSplitter.SetAllowSelection(true);
		m_MSplitter.SetSelection(flexSelectionListBox);
		m_MSplitter.SetEditable(flexEDKbdMouse);
		m_MSplitter.SetExtendLastCol(true);	
		//m_MSplitter.SetListTree(m_trMainMenu);
			//bool AddTreeNodes(TreeNode& tr, DWORD dwCntrl=0, LPCSTR lpcszAttribute=NULL, 
						//int nLevel = -1, int *pnFromRow = NULL, 
						//bool bCollapseAll = true, int nCols = 0)
		m_MSplitter.UpdateGrid(m_trMainMenu);

		m_MSplitter.SetupRowsCols(0, 0,  -1, 1);
		//m_MSplitter.SetTreeNodeMoveRowsAttrib(tr);
		m_MSplitter.SetReady(true);
	}
private:
	TreeNode 			m_trMainMenu;
	TreeNode 			m_trCurSel;
	TreeEditControl		m_MSplitter;
	ComboBox			m_comboOption;
};


bool OpenMenuMoveToDlg(int& nRowTo, int& nMoveType, const TreeNode& trMainMenu, const TreeNode& trCurSel, HWND hParent = NULL)
{
	// TO DO
	ASSERT(FALSE);
	return false;

	LTCustomMenuMoveToDlg myDlg;
	return IDOK == myDlg.DoModalEx(nRowTo, nMoveType, trMainMenu, trCurSel, hParent);

}
*/
///////////////////////////////////////////////////////////////////////////////

//#define STR_CUSTOM_HIDE_BUILT_IN_MENU_INI						okutil_get_origin_path(ORIGIN_PATH_USER) + "Origin.ini"
//#define STR_CUSTOM_HIDE_BUILT_IN_MENU_SECTION					"Custom Hide Built-in Menus Hide List"
#define STR_CUSTOM_HIDE_BUILT_IN_MENU_ATTRIB_WKS					"MenuHideListWks"
#define STR_CUSTOM_HIDE_BUILT_IN_MENU_ATTRIB_GRAPH					"MenuHideListGraph"
#define STR_CUSTOM_HIDE_BUILT_IN_MENU_ATTRIB_MATRIX				"MenuHideListMatrix"

///Kyle 06/08/2009 QA70-13423 SUPORT_GET_MENU_TEXT_FROM_OC
//#define RESOURCE_MENU_TEXT_WKS  		"File|Edit|View|Plot|Column|Worksheet|Analysis|Statistics|Image|Tools|Format|Window|Help"
//#define RESOURCE_MENU_TEXT_GRAPH  		"File|Edit|View|Graph|Data|Analysis|Tools|Format|Window|Help"
//#define RESOURCE_MENU_TEXT_MATRIX  		"File|Edit|View|Plot|Matrix|Image|Analysis|Tools|Format|Window|Help"
///End SUPORT_GET_MENU_TEXT_FROM_OC


class BuiltInMenuMngrWnd
{
public:
	BuiltInMenuMngrWnd(int nWndType)
	{
		m_nWndType = nWndType;
		//LoadSetting();
		///Kyle 02/26/2010 QA80-15138 KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC
		Project.GetBuiltInMenuTags(m_vsMenuTags, m_nWndType);
		///End KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC
		loadDefaultConfig();
	}
	
	BOOL	SetHideList(LPCSTR lpcszHideList)
	{
		string strHideList(lpcszHideList);
		///Kyle 02/26/2010 QA80-15138 KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC
		//int nHideList = strHideList.GetTokens(m_vsHideList, '|');
		//if(nHideList != m_vsMenuText.GetSize())
			//m_vsHideList.SetSize(m_vsMenuText.GetSize());
		m_vsHideList.SetSize(m_vsMenuText.GetSize());
		for(int ii = m_vsHideList.GetSize()-1; ii >= 0; ii--)
			m_vsHideList[ii].Empty();

		vector<string> vsHideListWithMenuTag;
		int nHideList = strHideList.GetTokens(vsHideListWithMenuTag, '|');
		for(ii = 0; ii < vsHideListWithMenuTag.GetSize(); ii++)
		{
			string strMenuTagAndIndex = vsHideListWithMenuTag[ii];
			strMenuTagAndIndex.TrimLeft();
			strMenuTagAndIndex.TrimRight();
			
			if( strMenuTagAndIndex.IsEmpty() )
				continue;
			
			int nPosSep = strMenuTagAndIndex.Find(':');
			if( nPosSep <= 0 )
				continue;
			
			string strTag = strMenuTagAndIndex.Left(nPosSep);
			strTag.TrimRight();
			
			string strIndex = strMenuTagAndIndex.Mid(nPosSep + 1);
			strIndex.TrimLeft();
			
			if( strTag.IsEmpty() || strIndex.IsEmpty() )
				continue;
			
			int nPosMenu = findMenuTagPosition(strTag);
			if( nPosMenu >= 0 && nPosMenu < m_vsHideList.GetSize() && m_vsHideList[nPosMenu].IsEmpty() )
				m_vsHideList[nPosMenu] = strIndex;
		}
		///End KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC
		return true;
	}
	
	string	GetHideList()
	{
		string strHideList;
		///Kyle 02/26/2010 QA80-15138 KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC
		//strHideList.SetTokens(m_vsHideList, '|');
		for(int ii = 0; ii < m_vsHideList.GetSize(); ii++)
		{
			if( m_vsHideList[ii].IsEmpty() )
				continue;

			if( !strHideList.IsEmpty() )
				strHideList += "|";

			string strTag = m_vsMenuTags[ii];
			strHideList += strTag + ":" + m_vsHideList[ii];
		}
		///End KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC
		return strHideList;
	}

	//~BuiltInMenuMngrWnd()
	//{
		//SaveSettings();
		//return;
	//}

	//void LoadSetting()
	//{
		////Project.UpdateMainMenus();		///Kyle 06/08/2009 QA70-13423 SUPORT_GET_MENU_TEXT_FROM_OC
		//loadDefaultConfig();
		//loadHideList();
	//}
	
	
	//void SaveSetting()
	//{
		//string strHideList;
		//strHideList.SetTokens(m_vsHideList, '|');
//
		//string strKey;
		//switch(m_nWndType)
		//{
		//case EXIST_WKS:
			//strKey = STR_CUSTOM_HIDE_BUILT_IN_MENU_KEY_WKS;
			//break;
		//case EXIST_GRAPH:
			//strKey = STR_CUSTOM_HIDE_BUILT_IN_MENU_KEY_GRAPH;
			//break;
		//case EXIST_MATRIX:
			//strKey = STR_CUSTOM_HIDE_BUILT_IN_MENU_KEY_MATRIX;
			//break;
		//default:
			//return;
		//}
		//INIFile	iniFile(STR_CUSTOM_HIDE_BUILT_IN_MENU_INI);
		//update_ini_line(iniFile, STR_CUSTOM_HIDE_BUILT_IN_MENU_SECTION, strKey, strHideList);
	//}
	
	void Reset()
	{
		// clean hide list
		m_vsHideList.SetSize(0);
		m_vsHideList.SetSize(m_vsMenuText.GetSize());
	}
	
	void GetMenuText(vector<string>& vsMenuText)
	{
		vsMenuText = m_vsMenuText;
	}
	
	void GetMenuHidden(vector<int>& vnMenuHidden)
	{
		vector<int> vn;
		convert_string_vector_to_int_vector(m_vsHideList, vn, 0);
		
		vnMenuHidden.SetSize(m_vsMenuText.GetSize());
		for(int ii=vn.GetSize()-1; ii>=0; ii--)
			vnMenuHidden[ii] = vn[ii]==-1;
	}
	
	bool GetSubMenuText(int nIndex, vector<string>& vsMenuText)
	{
		if(nIndex < 0 || nIndex >= m_vsSubMenuText.GetSize())
			return false;
		
		string strSubMenuText = m_vsSubMenuText[nIndex];
		strSubMenuText.GetTokens(vsMenuText, '|');

		return true;
	}
	
	bool GetSubMenuHidden(int nIndex, vector<int>& vnHidden)
	{
		if(nIndex < 0 || nIndex >= m_vsSubMenuText.GetSize())
			return false;

		// size
		string strSubMenuText = m_vsSubMenuText[nIndex];
		vector<string> vsSubMenuText;
		int nSubMenus = strSubMenuText.GetTokens(vsSubMenuText, '|');
		vnHidden.SetSize(nSubMenus);

		vector<string> vsHiddenList;
		vector<int> vnHiddenList;
		string strHideList = m_vsHideList[nIndex];
		strHideList.GetTokens(vsHiddenList, ' ');
		convert_string_vector_to_int_vector(vsHiddenList, vnHiddenList);
		if(vnHiddenList.GetSize()==0)
		{
			vnHidden = 0;
		}
		else if(vnHiddenList.GetSize()==1 && vnHiddenList[0]==-1)
		{
			vnHidden = 0;			// only the whole popup is hidden, but the sub items are shown(only because their parent popup is hidden so you can't see them)
		}
		else
		{
			vnHidden = 0;
			for(int ii=vnHiddenList.GetSize()-1; ii>=0; ii--)
			{
				if(vnHiddenList[ii]>=0 && vnHiddenList[ii]<nSubMenus)
					vnHidden[ vnHiddenList[ii] ] = 1;
			}
		}
		return true;
	}
	
	void SetMenuHidden(int nIndex, bool bMainHidden, const vector<bool>& vbSubHidden)
	{
		string strHideList;
		if(bMainHidden)
		{
			strHideList = "-1";
		}
		else
		{
			vector<uint> vecHideList;
			vector<string> vsHideList;
			vbSubHidden.Find(vecHideList, 1);
			vector<int> vnHideList;
			vnHideList = vecHideList;
			convert_int_vector_to_string_vector(vnHideList, vsHideList);
			
			strHideList.SetTokens(vsHideList, ' ');
		}
		SetHideList(nIndex, strHideList);
	}
	
	void SetMainMenuHidden(const vector<int>& vnIndices, const vector<bool>& vbHidden)
	{
		int nSize = vnIndices.GetSize() < vbHidden.GetSize() ? vnIndices.GetSize() : vbHidden.GetSize();
		for(int ii=nSize-1; ii>=0; ii--)
		{
			int nIndex = vnIndices[ii];
			if(nIndex<0 || nIndex>=m_vsHideList.GetSize())
				continue;
			
			if(vbHidden[ii])
			{
				m_vsHideList[nIndex] = "-1";
			}
			else
			{
				string strHideList = m_vsHideList[nIndex];
				if(strHideList.IsEmpty())
					continue;

				vector<string> vsHideList;
				strHideList.GetTokens(vsHideList, ' ');
				vector<int> vnHideList;
				convert_string_vector_to_int_vector(vsHideList, vnHideList);
				vector<uint> vecIndex;
				if(vnHideList.Find(vecIndex, -1) > 0)
				{
					m_vsHideList[nIndex] = "";
				}
			}
		}
	}
	
	void GetHideList(vector<string>& vsHideList)
	{
		vsHideList = m_vsHideList;
	}

	bool SetHideList(int nIndex, LPCSTR lpcszHideList)
	{
		if(nIndex < 0 || nIndex >= m_vsMenuText.GetSize())
			return false;
		m_vsHideList[nIndex] = lpcszHideList;
		return true;
	}

private:
	///Kyle 02/26/2010 QA80-15138 KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC
	int findMenuTagPosition(LPCSTR lpcszMenuTag)
	{
		for(int ii = m_vsMenuTags.GetSize()-1; ii >= 0; ii--)
		{
			if( 0 == m_vsMenuTags[ii].CompareNoCase(lpcszMenuTag) )
				return ii;
		}

		return -1;
	}
	///End KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC
	//void loadHideList()
	//{
		//string strKey;
		//switch(m_nWndType)
		//{
		//case EXIST_WKS:
			//strKey = STR_CUSTOM_HIDE_BUILT_IN_MENU_KEY_WKS;
			//break;
		//case EXIST_GRAPH:
			//strKey = STR_CUSTOM_HIDE_BUILT_IN_MENU_KEY_GRAPH;
			//break;
		//case EXIST_MATRIX:
			//strKey = STR_CUSTOM_HIDE_BUILT_IN_MENU_KEY_MATRIX;
			//break;
		//default:
			//return;
		//}
		//INIFile	iniFile(STR_CUSTOM_HIDE_BUILT_IN_MENU_INI);
		//string strHideList = iniFile.ReadString(STR_CUSTOM_HIDE_BUILT_IN_MENU_SECTION, strKey);
		//if(strHideList.IsEmpty())
			//return;
		//int nHideList = strHideList.GetTokens(m_vsHideList, '|');
		//if(nHideList != m_vsMenuText.GetSize())
			//m_vsHideList.SetSize(m_vsMenuText.GetSize());
	//}
//
	void loadDefaultConfig()
	{
		m_vsMenuText.SetSize(0);
		m_vsHideList.SetSize(0);
		
		///Kyle 06/08/2009 QA70-13423 SUPORT_GET_MENU_TEXT_FROM_OC
		/*
		string strText;
		switch(m_nWndType)
		{
		case EXIST_WKS:
			strText = RESOURCE_MENU_TEXT_WKS;
			break;
		case EXIST_GRAPH:
			strText = RESOURCE_MENU_TEXT_GRAPH;
			break;
		case EXIST_MATRIX:
			strText = RESOURCE_MENU_TEXT_MATRIX;
			break;
		}
		int nMainMenus = strText.GetTokens(m_vsMenuText, '|');
		m_vsHideList.SetSize(nMainMenus);

		// to do
		m_vsSubMenuText.SetSize(nMainMenus);

		
		// for testing
		vector<string> vs;
		for(int ii=0; ii<nMainMenus; ii++)
		{
			vs.SetSize(5);
			for(int jj=0; jj<5; jj++)
				vs[jj] = m_vsMenuText[ii] + " " + (jj > 0 ? (string)jj : "");
			string strSubMenuText;
			strSubMenuText.SetTokens(vs, '|');
			m_vsSubMenuText[ii] = strSubMenuText;
		}
		*/
		Project.GetMainMenuTexts(m_vsMenuText, m_nWndType);
		int nMainMenus = m_vsMenuText.GetSize();

		m_vsHideList.SetSize(nMainMenus);
		m_vsSubMenuText.SetSize(nMainMenus);

		for(int ii=0; ii < nMainMenus; ii++)
		{
			m_vsMenuText[ii].Remove('&');		// trim & to displey

			vector<string> vs;
			Project.GetMainMenuTexts(vs, m_nWndType, ii);
			
			// trim hot key and special char invisible
			for(int jj=vs.GetSize()-1; jj>=0; jj--)
			{
				if(!vs[jj].IsEmpty())
				{
					vs[jj].Remove('&');				// trim & to displey
					int nPos = -1;
					if(	(nPos = vs[jj].Find("\t")) > 0 )		// trim Ctrl+Char or Alt+Num, will begin with "\t"
					{
						vs[jj] = vs[jj].Left(nPos);
						vs[jj].TrimRight();
					}
				}
			}
			string strSubMenuText;
			strSubMenuText.SetTokens(vs, '|');
			m_vsSubMenuText[ii] = strSubMenuText;
		}

		///End SUPORT_GET_MENU_TEXT_FROM_OC
	}

private:
	int 				m_nWndType;
	vector<string> 		m_vsMenuText;
	vector<string>		m_vsSubMenuText;
	vector<string> 		m_vsHideList;
	
	vector<string>		m_vsMenuTags;		///Kyle 02/26/2010 QA80-15138 KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC
};


#define STR_BUILT_IN_MENU_GRID_COLS		_L("Menu|Hide List")

enum
{
	BUILT_IN_MENU_TEXT,
	BUILT_IN_MENU_HIDE,
	BUILT_IN_MENU_TOTAL,
};

class BuiltInMenuMngr
{
public:
	BuiltInMenuMngr()
	{
		m_arrMngrWnd.SetAsOwner(true);
	}
	
	BOOL SetSettings(const vector<string>& vsHideList, const vector<int>& vnWndTypes)
	{
		ASSERT(vsHideList.GetSize() == vnWndTypes.GetSize());
		m_vnWndTypes = vnWndTypes;
		m_arrMngrWnd.SetSize(0);
		for(int nWndIndex = 0; nWndIndex < vnWndTypes.GetSize(); nWndIndex++)
		{
			int nWndType = vnWndTypes[nWndIndex];
			BuiltInMenuMngrWnd* pMngrWnd = getMenuMngrWnd(nWndType, true);
			if(!pMngrWnd)
			{
				ASSERT(false);
				return error_report("new BuiltInMenuMngrWnd error!");
			}
			pMngrWnd->SetHideList(vsHideList[nWndIndex]);
		}
		return true;
	}

	void GetSettings(vector<string>& vsHideList, vector<int>& vnWndTypes)
	{
		vnWndTypes = m_vnWndTypes;
		vsHideList.SetSize(vnWndTypes.GetSize());
		for(int nWndIndex = 0; nWndIndex < vnWndTypes.GetSize(); nWndIndex++)
		{
			BuiltInMenuMngrWnd* pMngrWnd = getMenuMngrWnd(vnWndTypes[nWndIndex]);
			string strHideList;
			if(pMngrWnd)
				strHideList = pMngrWnd->GetHideList();
			vsHideList[nWndIndex] = strHideList;
		}
	}
	
	void Reset(int nWndType)
	{
		BuiltInMenuMngrWnd* pMngrWnd = getMenuMngrWnd(nWndType);
		if(!pMngrWnd)
			return;
		pMngrWnd->Reset();
	}

	bool GetMainMenuText(int nWndType, vector<string>& vsMenuText)
	{
		BuiltInMenuMngrWnd* pMngrWnd = getMenuMngrWnd(nWndType);
		if(!pMngrWnd)
			return false;

		pMngrWnd->GetMenuText(vsMenuText);
		return true;
	}
	
	bool GetMainMenuHidden(int nWndType, vector<int>& vnHidden)
	{
		BuiltInMenuMngrWnd* pMngrWnd = getMenuMngrWnd(nWndType);
		if(!pMngrWnd)
			return false;

		pMngrWnd->GetMenuHidden(vnHidden);
		return true;
	}

	bool GetSubMenuText(int nWndType, int nMainIndex, vector<string>& vsMenuText)
	{
		BuiltInMenuMngrWnd* pMngrWnd = getMenuMngrWnd(nWndType);
		if(!pMngrWnd)
			return false;

		return pMngrWnd->GetSubMenuText(nMainIndex, vsMenuText);
	}
	
	bool GetSubMenuHidden(int nWndType, int nMainIndex, vector<int>& vnHidden)
	{
		BuiltInMenuMngrWnd* pMngrWnd = getMenuMngrWnd(nWndType);
		if(!pMngrWnd)
			return false;

		return pMngrWnd->GetSubMenuHidden(nMainIndex, vnHidden);
	}
	
	void SetMenuHidden(int nWndType, int nMainIndex, bool bMainHidden, const vector<bool>& vbSubHidden)
	{
		BuiltInMenuMngrWnd* pMngrWnd = getMenuMngrWnd(nWndType);
		if(!pMngrWnd)
			return;
		pMngrWnd->SetMenuHidden(nMainIndex, bMainHidden, vbSubHidden);
	}
	
	void ApplyMainConfigToWndType(int nSrcWndType, int nDestWndType, const vector<int>& vnIndices, const vector<bool>& vbMainHidden)
	{
		BuiltInMenuMngrWnd* pSrcMngrWnd = getMenuMngrWnd(nSrcWndType);
		BuiltInMenuMngrWnd* pDestMngrWnd = getMenuMngrWnd(nDestWndType);
		if(!pSrcMngrWnd || !pDestMngrWnd)
			return;

		// match and get common menu indices
		vector<int> 	vnDestIndices;
		vector<bool> 	vbDestHidden;
		
		vector<string> vsSrcMenuText, vsDestMenuText;
		pSrcMngrWnd->GetMenuText(vsSrcMenuText);
		pDestMngrWnd->GetMenuText(vsDestMenuText);
		
		int nSize = vnIndices.GetSize() < vbMainHidden.GetSize() ? vnIndices.GetSize() : vbMainHidden.GetSize();
		for(int ii=nSize-1; ii>=0; ii--)
		{
			int nSrcIndex = vnIndices[ii];
			if(nSrcIndex<0 || nSrcIndex>=vsSrcMenuText.GetSize())
				continue;
			
			string strSrcMenuTest = vsSrcMenuText[nSrcIndex];
			int nDestIndex = vsDestMenuText.Find(strSrcMenuTest, 0, true);
			if(nDestIndex >= 0)
			{
				vnDestIndices.Add(nDestIndex);
				vbDestHidden.Add(vbMainHidden[ii]);
			}
		}
		pDestMngrWnd->SetMainMenuHidden(vnDestIndices, vbDestHidden);
	}

private:

	BuiltInMenuMngrWnd* getMenuMngrWnd(int nWndType, bool bCreate = false)
	{
		if(!checkWndType(nWndType))
			return NULL;
		BuiltInMenuMngrWnd* pMngrWnd = NULL;
		BuiltInMenuMngrWnd& menuMngrWnd = m_arrMngrWnd.GetAt(nWndType);

		if(menuMngrWnd)
		{
			pMngrWnd = &menuMngrWnd;
		}
		else if(bCreate)
		{
			pMngrWnd = new BuiltInMenuMngrWnd(nWndType);
			m_arrMngrWnd.SetAtGrow(nWndType, *pMngrWnd);
		}
		return pMngrWnd;
	}

	bool checkWndType(int nWndType)
	{
		return (nWndType==EXIST_WKS || nWndType==EXIST_GRAPH || nWndType==EXIST_MATRIX);
	}

private:
	Array<BuiltInMenuMngrWnd&>				m_arrMngrWnd;			// manager
	vector<int>								m_vnWndTypes;
};



enum
{
	BUILT_IN_CONTEXT_MENU_INVALUD = 0,
	BUILT_IN_CONTEXT_MENU_SHOW,
	BUILT_IN_CONTEXT_MENU_HIDE,
	BUILT_IN_CONTEXT_MENU_APPLY_TO_WKS,
	BUILT_IN_CONTEXT_MENU_APPLY_TO_GRAPH,
	BUILT_IN_CONTEXT_MENU_APPLY_TO_MATRIX,
};

#define STR_BUILT_IN_CONTEXT_MENU_SHOW					_L("Show")
#define STR_BUILT_IN_CONTEXT_MENU_SHOW_ALL				_L("Show All")
#define STR_BUILT_IN_CONTEXT_MENU_HIDE					_L("Hide")
#define STR_BUILT_IN_CONTEXT_MENU_HIDE_ALL				_L("Hide All")
#define STR_BUILT_IN_CONTEXT_MENU_APPLY_TO_WKS			_L("Apply to Worksheet Menus")
#define STR_BUILT_IN_CONTEXT_MENU_APPLY_TO_GRAPH		_L("Apply to Graph Menus")
#define STR_BUILT_IN_CONTEXT_MENU_APPLY_TO_MATRIX		_L("Apply to Matrix Menus")


#define STR_MAIN_INDEX_ATTRIB		"MainIndex"
#define STR_SUB_INDEX_ATTRIB		"SubIndex"

class BuiltInMenuGridControl : public TreeEditControl
{
public:
	BuiltInMenuGridControl()
	{
	}
	
	void Init(int nID, Dialog& dlg,LPCSTR lpcszDlgName)
	{
		SetDirty(false, false);
		TreeEditControl::Init(nID, false, true, NULL, dlg);
		
		SetAllowSelection(true);
		SetSelection(flexSelectionListBox);
	}
	
	void Reset()
	{
		// reset all wnd type
		vector<int> vnWndTypes = {EXIST_WKS, EXIST_GRAPH, EXIST_MATRIX};
		for(int ii=0; ii<vnWndTypes.GetSize(); ii++)
			m_builtInMenusMngr.Reset(vnWndTypes[ii]);

		// just check all in grid
		for(int nRow=GetRowOffset(); nRow<GetRowOffset()+GetNumRows(); nRow++)
		{
			SetCheck(nRow, BUILT_IN_MENU_HIDE, true);

			// Update the tree
			TreeNode trRow = GetTreeNode(nRow);
			if(GetLevel(nRow) == 0)
				trRow.Use = TRUE;
			else
				trRow.nVal = TRUE;
		}
		SetDirty();
	}
	
	bool IsDirty()
	{
		return m_bDirty;
	}
	
	void SetDirty(bool bDirty = true, bool bUpdateWndText = true)
	{
		if(m_bDirty != bDirty)
		{
			m_bDirty = bDirty;
			if(bUpdateWndText)
			{
				Window win(GetDlgSafeHwnd());
				if(win)
					win.PostMessage(WM_USER_CUSTOM_MENU_EDITOR_UPDATE_WINDOW_TEXT);
			}
		}
	}
	
	void Update(int nWndType = EXIST_NONE, bool bClearAll = false)
	{
		 // save the current gui
		if(m_nWndType != EXIST_NONE)
			saveGuiToManager();

		m_nWndType = nWndType;
		if ( bClearAll )
			ClearAll();

		Tree tr;
		TreeNode trRoot = tr.AddNode("root");
		constructMenuTree(trRoot);
		Update(trRoot, true, true);
	}

	void SetSettings(const vector<string>& vsHideList, const vector<int>& vnWndTypes)
	{
		SetDirty(false, false);
		m_builtInMenusMngr.SetSettings(vsHideList, vnWndTypes);
		m_nWndType = EXIST_NONE;			// make gui invalid
	}
	
	void GetSettings(vector<string>& vsHideList, vector<int>& vnWndTypes)
	{
		// save the current gui to manager
		if(m_nWndType != EXIST_NONE)
			saveGuiToManager();

		m_builtInMenusMngr.GetSettings(vsHideList, vnWndTypes);
	}
	
	void OnAfterEdit(Control flxControl, int nRow, int nCol)
	{
		if(nCol != BUILT_IN_MENU_HIDE)
			return;

		OnAfterEdit(nRow, nCol);
		SetDirty();
		//PostDlgMessage(WM_USER_RECONSTRUCT, GRID_CHANGE_ENABLE);
	}

	void OnBeforeEdit(Control flxControl, long nRow, long nCol, BOOL* pCancel)
	{
		if(pCancel && nCol == BUILT_IN_MENU_TEXT)
			*pCancel = true;
	}
	
	void OnBeforeCollapse(Control flxControl, long nRow, short nState, BOOL* pCancel)
	{
		if(nRow < GetRowOffset() || nRow >= GetRowOffset() + GetNumRows() )		// error
			return;
		if(0==GetLevel(nRow) && !GetCheck(nRow, BUILT_IN_MENU_HIDE) && flexOutlineExpanded==nState && pCancel)
			*pCancel = true;
	}

	BOOL OnEnter(Control ctrl)
	{
		int nRow = 0, nCol = 0;
		int nx = -1, ny = -1;
		GetSelCell(nx, ny, nRow, nCol);
		if(nRow >= GetRowOffset())
		{
			if(GetLevel(nRow) > 0 || flexOutlineExpanded == GetCollapsed(nRow))
			{
				nRow++;
			}
			else
			{
				nRow++;
				int nEnd = GetNumRows() + GetRowOffset();
				while(nRow < nEnd && GetLevel(nRow) > 0)
					nRow++;
			}
			SelCell(nRow, nCol);
		}
		return TRUE;
	}
	
	void OnBeforeMouseDown(short nButton, short nShift, float X, float Y, BOOL* pCancel)
	{
		int nRow = m_flx.MouseRow;
		int nCol = m_flx.MouseCol;
		if(nButton != MK_RBUTTON || nShift != 0)
			return;

		vector<uint> vnRows;
		GetSelRows(vnRows);
		if(nRow < 0 || nCol < 0)
		{
			RemoveSelection();
		}
		else
		{
			vector<uint> vec;
			if(vnRows.Find(vec, nRow) <= 0)
				SelRow(nRow);
		}
		GetSelRows(vnRows);
		bool bHasSelection = vnRows.GetSize()>0;

		vector<int> vnCmds;
		vector<string> vsText;
		vector<bool> vbEnable;
		if(!GetValidCtxCmds(vnCmds, vsText, vbEnable))
			return;
		CustomContextMenu MyMenu(vnCmds, vsText, vbEnable);
		
		
		int    nx = XTwipsToPixels(X);
		int    ny = YTwipsToPixels(Y);
        ClientToScreen(nx, ny);

		int nCmd = 0;
		MyMenu.TrackPopupMenu(0, nx, ny, GetDlgSafeHwnd(), &nCmd);
		switch(nCmd)
		{
		case BUILT_IN_CONTEXT_MENU_SHOW:
		case BUILT_IN_CONTEXT_MENU_HIDE:
			OnShowHideMenus( nCmd==BUILT_IN_CONTEXT_MENU_SHOW, bHasSelection );
			SetDirty();
			break;
			
		case BUILT_IN_CONTEXT_MENU_APPLY_TO_WKS:
		case BUILT_IN_CONTEXT_MENU_APPLY_TO_GRAPH:
		case BUILT_IN_CONTEXT_MENU_APPLY_TO_MATRIX:
			int nWndType = EXIST_NONE;
			switch(nCmd)
			{
			case BUILT_IN_CONTEXT_MENU_APPLY_TO_WKS:
				nWndType = EXIST_WKS;
				break;
			case BUILT_IN_CONTEXT_MENU_APPLY_TO_GRAPH:
				nWndType = EXIST_GRAPH;
				break;
			case BUILT_IN_CONTEXT_MENU_APPLY_TO_MATRIX:
				nWndType = EXIST_MATRIX;
				break;
			}
			OnApplyToOtherWndType(nWndType, bHasSelection);
			SetDirty();
			break;

		default:
			return;
		}
	}
protected:
	bool GetValidCtxCmds(vector<int>& vnCmds, vector<string>& vsText, vector<bool>& vbEnable)
	{
		vnCmds.SetSize(0);
		vsText.SetSize(0);
		vbEnable.SetSize(0);
		
		vector<uint> vnRows;
		GetSelRows(vnRows);
		if(vnRows.GetSize() > 0)
		{
			vnCmds.Add(BUILT_IN_CONTEXT_MENU_SHOW);
			vsText.Add(STR_BUILT_IN_CONTEXT_MENU_SHOW);
			vbEnable.Add(true);
	
			vnCmds.Add(BUILT_IN_CONTEXT_MENU_HIDE);
			vsText.Add(STR_BUILT_IN_CONTEXT_MENU_HIDE);
			vbEnable.Add(true);
		}
		else
		{
			vnCmds.Add(BUILT_IN_CONTEXT_MENU_SHOW);
			vsText.Add(STR_BUILT_IN_CONTEXT_MENU_SHOW_ALL);
			vbEnable.Add(true);
	
			vnCmds.Add(BUILT_IN_CONTEXT_MENU_HIDE);
			vsText.Add(STR_BUILT_IN_CONTEXT_MENU_HIDE_ALL);
			vbEnable.Add(true);
		}
		
		vnCmds.Add(BUILT_IN_CONTEXT_MENU_INVALUD);
		vsText.Add("");
		vbEnable.Add(false);

		bool bMainSelected = false;
		for(int ii=vnRows.GetSize()-1; ii>=0; ii--)
		{
			if(0 == GetLevel(vnRows[ii]))
			{
				bMainSelected = true;
				break;
			}
		}
		switch(m_nWndType)
		{
		case EXIST_WKS:
			vnCmds.Add(BUILT_IN_CONTEXT_MENU_APPLY_TO_GRAPH);
			vsText.Add(STR_BUILT_IN_CONTEXT_MENU_APPLY_TO_GRAPH);
			vnCmds.Add(BUILT_IN_CONTEXT_MENU_APPLY_TO_MATRIX);
			vsText.Add(STR_BUILT_IN_CONTEXT_MENU_APPLY_TO_MATRIX);
			break;
			
		case EXIST_GRAPH:
			vnCmds.Add(BUILT_IN_CONTEXT_MENU_APPLY_TO_WKS);
			vsText.Add(STR_BUILT_IN_CONTEXT_MENU_APPLY_TO_WKS);
			vnCmds.Add(BUILT_IN_CONTEXT_MENU_APPLY_TO_MATRIX);
			vsText.Add(STR_BUILT_IN_CONTEXT_MENU_APPLY_TO_MATRIX);
			break;

		case EXIST_MATRIX:
			vnCmds.Add(BUILT_IN_CONTEXT_MENU_APPLY_TO_WKS);
			vsText.Add(STR_BUILT_IN_CONTEXT_MENU_APPLY_TO_WKS);
			vnCmds.Add(BUILT_IN_CONTEXT_MENU_APPLY_TO_GRAPH);
			vsText.Add(STR_BUILT_IN_CONTEXT_MENU_APPLY_TO_GRAPH);
			break;
		}
		vbEnable.Add(bMainSelected);
		vbEnable.Add(bMainSelected);
		return true;
	}

	void OnShowHideMenus(bool bShow, bool bToSelection)
	{
		if(bToSelection)		// show/hide all except the not extanded rows
		{
			vector<uint> vnRows;
			GetSelRows(vnRows);
			int nRows = vnRows.GetSize();
			for(int ii = 0; ii < nRows; ii++)
			{
				int nRow = vnRows[ii];
				int nLevel = GetLevel(nRow);
				if( nLevel == 0 || GetCheck(GetParent(nRow), BUILT_IN_MENU_HIDE))
				{
					SetCheck(nRow, BUILT_IN_MENU_HIDE, bShow);
					
					TreeNode trRow = GetTreeNode(nRow);
					if(nLevel == 0)
						trRow.Use = bShow;
					else
						trRow.nVal = bShow;
				}
			}
		}
		else			// show/hide all(including the not extand rows)
		{
			
			for(int nRow = GetRowOffset(); nRow < GetRowOffset() + GetNumRows(); nRow++)
			{
				int nLevel = GetLevel(nRow);
				if(bShow || nLevel == 0)		// if show check all, else only uncheck the branch
				{
					SetCheck(nRow, BUILT_IN_MENU_HIDE, bShow);
					TreeNode trRow = GetTreeNode(nRow);
					if(nLevel == 0)		// branch
						trRow.Use = bShow;
					else
						trRow.nVal = bShow;
				}
			}
		}
			
		// update grid 
		refreshGrid();
	}
	
	void OnApplyToOtherWndType(int nWndType, bool bApplySelection)
	{
		vector<bool> 	vbMainHidden;
		vector<int> 	vnIndices;
		
		int nMainMenu = 0;
		vector<uint> vnRows;
		if(bApplySelection)
		{
			GetSelRows(vnRows);
		}
		else
		{
			vnRows.Data(GetRowOffset(), GetRowOffset()+GetNumRows()-1);
		}
			
		for(int ii=0; ii<vnRows.GetSize(); ii++)
		{
			if(0==GetLevel(vnRows[ii]))
			{
				int nMainIndex;
				TreeNode trRow = GetTreeNode(vnRows[ii]);
				trRow.GetAttribute(STR_MAIN_INDEX_ATTRIB, nMainIndex);
				vnIndices.Add(nMainIndex);
				vbMainHidden.Add(1-GetCheck(vnRows[ii], BUILT_IN_MENU_HIDE));
			}
		}
		m_builtInMenusMngr.ApplyMainConfigToWndType(m_nWndType, nWndType, vnIndices, vbMainHidden);
	}

private:
	void updateGridCollapsed()
	{
		for(int nRow=GetRowOffset(); nRow<GetRowOffset()+GetNumRows(); nRow++)
		{
			if(0 == GetLevel(nRow) && !GetCheck(nRow, BUILT_IN_MENU_HIDE))
				SetCollapsed(nRow, flexOutlineCollapsed);
		}
	}

	void refreshGrid()
	{
		vector<byte> vnCollapsed;
		GetCollapsed(vnCollapsed);

		ReInit();
		
		int nMainIndex = 0;
		for(int nRow=GetRowOffset(); nRow<GetRowOffset()+GetNumRows(); nRow++)
		{
			if(0 == GetLevel(nRow))
			{
				if(!GetCheck(nRow, BUILT_IN_MENU_HIDE))
					vnCollapsed[nMainIndex] = flexOutlineCollapsed;
				nMainIndex++;
			}
		}
		SetCollapsed(vnCollapsed);
	}

	void saveGuiToManager()
	{
		vector<bool> vbCheck;
		vector<int> vnMainIndices;
		
		int nTotal 		= GetNumRows(),
			nRowOffset 	= GetRowOffset();

		vbCheck.SetSize(nTotal);
		for(int ii=0; ii<nTotal; ii++)
		{
			int nRow = ii+nRowOffset;
			vbCheck[ii] = GetCheck(nRow, BUILT_IN_MENU_HIDE);
			if(0==GetLevel(nRow))
				vnMainIndices.Add(ii);
		}
		
		int nMainMenus = vnMainIndices.GetSize();
		for(ii=0; ii<vnMainIndices.GetSize(); ii++)
		{
			bool bMainHidden;
			vector<bool> vnSubHidden;
			
			bMainHidden = 1-vbCheck[vnMainIndices[ii]];
			vbCheck.GetSubVector(vnSubHidden, vnMainIndices[ii]+1, ii+1 < nMainMenus ? vnMainIndices[ii+1] -1 : -1);
			if(vnSubHidden.GetSize())
				vnSubHidden = 1-vnSubHidden;
			
			///Kyle 06/08/2009 QA70-13423 SUPORT_GET_MENU_TEXT_FROM_OC, add back the skiped sub menus
			if(m_vnSubGroupFirstIndices[ii] >= 0)
			{
				int nn = m_vnSubGroupFirstIndices[ii];
				while(nn < m_vnSkipedSubMenuIndices.GetSize() && m_vnSkipedSubMenuIndices[nn] >= 0)
				{
					vnSubHidden.InsertAt(m_vnSkipedSubMenuIndices[nn], false);			// all separator will be shown
					nn++;
				}
			}
			///End SUPORT_GET_MENU_TEXT_FROM_OC
			
			m_builtInMenusMngr.SetMenuHidden(m_nWndType, ii, bMainHidden, vnSubHidden);
		}
	}
	
	void constructMenuTree(TreeNode& trRoot)
	{
		if(!trRoot)
			return;
		
		vector<string> 	vsMenuText;
		vector<int>		vnMenuHidden;
		m_builtInMenusMngr.GetMainMenuText(m_nWndType, vsMenuText);
		m_builtInMenusMngr.GetMainMenuHidden(m_nWndType, vnMenuHidden);
		ASSERT(vsMenuText.GetSize() == vnMenuHidden.GetSize());

		int nMainMenus = vsMenuText.GetSize();

		///Kyle 06/08/2009 QA70-13423 SUPORT_GET_MENU_TEXT_FROM_OC
		m_vnSubGroupFirstIndices.SetSize(nMainMenus);				// index of the first sub menu indices in m_vnSkipedSubMenuIndices
		m_vnSubGroupFirstIndices = -1;
		m_vnSkipedSubMenuIndices.SetSize(0);				// each sub group will end with -1
		///End SUPORT_GET_MENU_TEXT_FROM_OC

		GETN_USE(trRoot)
		for(int ii=0; ii<nMainMenus; ii++)
		{
			GETN_BEGIN_BRANCH(MainPopup, vsMenuText[ii])		GETN_CHECKBOX_BRANCH(!vnMenuHidden[ii])		GETN_CURRENT_SUBNODE.SetAttribute(STR_MAIN_INDEX_ATTRIB, ii);

			vector<string> 	vsSubMenuText;
			vector<int> 	vnSubMenuHidden;
			m_builtInMenusMngr.GetSubMenuText(m_nWndType, ii, vsSubMenuText);
			m_builtInMenusMngr.GetSubMenuHidden(m_nWndType, ii, vnSubMenuHidden);
			ASSERT(vsSubMenuText.GetSize() == vnSubMenuHidden.GetSize());
			
			int nSubMenus = vsSubMenuText.GetSize();
			bool bSkiped = false;					///Kyle 06/08/2009 QA70-13423 SUPORT_GET_MENU_TEXT_FROM_OC
			for(int jj=0; jj<nSubMenus; jj++)
			{
				///Kyle 06/08/2009 QA70-13423 SUPORT_GET_MENU_TEXT_FROM_OC
				//GETN_CHECK(SubItem, vsSubMenuText[jj], !vnSubMenuHidden[jj])		GETN_CURRENT_SUBNODE.SetAttribute(STR_SUB_INDEX_ATTRIB, jj);
				if(vsSubMenuText[jj].IsEmpty())		// separator
				{
					if(!bSkiped)
					{
						m_vnSubGroupFirstIndices[ii] = m_vnSkipedSubMenuIndices.GetSize();
						bSkiped = true;
					}
					m_vnSkipedSubMenuIndices.Add(jj);
				}
				else
				{
					GETN_CHECK(SubItem, vsSubMenuText[jj], !vnSubMenuHidden[jj])		GETN_CURRENT_SUBNODE.SetAttribute(STR_SUB_INDEX_ATTRIB, jj);
				}
				///End SUPORT_GET_MENU_TEXT_FROM_OC
			}
			///Kyle 06/08/2009 QA70-13423 SUPORT_GET_MENU_TEXT_FROM_OC
			if(bSkiped)
				m_vnSkipedSubMenuIndices.Add(-1);
			///End SUPORT_GET_MENU_TEXT_FROM_OC
			GETN_END_BRANCH(MainPopup)
		}
	}

private:
	bool					m_bDirty;
	int 					m_nWndType;
	BuiltInMenuMngr			m_builtInMenusMngr;
	
	///Kyle 06/08/2009 QA70-13423 SUPORT_GET_MENU_TEXT_FROM_OC
	vector<int>				m_vnSubGroupFirstIndices;				//
	vector<int>				m_vnSkipedSubMenuIndices;
	///End SUPORT_GET_MENU_TEXT_FROM_OC
};

#define					STR_ORIGIN_INI			"origin.ini"
#define					STR_SECTION_CONFIG		"Config"
#define					STR_SECTION_OPTIONS		"Options"
#define					STR_MENU_LEVEL_BY_OMC	"MenuLevelByOMC"
#define					STR_NUM_OMC_LEVELS		"NumOMCLevels"
#define					STR_OMC_FILE_NAME		"OMCFile"
#define					STR_OMC_MENU_LEVEL		"OMCLevel"

#define STR_OMC_UNTITLED		"UNTITLED"
class OMCFileManager
{
public:
	OMCFileManager()
	{
		m_nEditingLevel = -1;
		m_trEditingOMC.Reset();
		scanOMCFiles();
	}
	
	BOOL	Editable()
	{
		if(m_nEditingLevel < 0 || m_nEditingLevel >= m_vnPathTypes.GetSize())
			return true;

		if(m_vnPathTypes[m_nEditingLevel] == ORIGIN_PATH_GROUP || m_vnPathTypes[m_nEditingLevel]==ORIGIN_PATH_SYSTEM)
			return false;
		return true;
	}
	
	BOOL	Enable()
	{
		ASSERT(m_trEditingOMC);
		int nEnable;
		return (!m_trEditingOMC.GetAttribute(STR_FILE_ENABLE_ATTRIB, nEnable) || nEnable);
	}
	
	void	SetEnable(BOOL bEnable)
	{
		ASSERT(m_trEditingOMC);
		m_trEditingOMC.SetAttribute(STR_FILE_ENABLE_ATTRIB, bEnable);
	}
	
	///---Sim 01-22-2010 QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	/// ML 2/15/2010 QA70-15113 81SR1_OMC_FILES_SHOULD_ALWAYS_APPEND_BUT_NEW_SHOULD_INSERT_BEFORE_WINDOW
	//int		GetPosition()
	int		GetPosition(BOOL *pbDefault = NULL)
	/// end 81SR1_OMC_FILES_SHOULD_ALWAYS_APPEND_BUT_NEW_SHOULD_INSERT_BEFORE_WINDOW
	{
		ASSERT(m_trEditingOMC);
		int nPos;
		if ( !m_trEditingOMC.GetAttribute(STR_OMC_POS_ATTRIB, nPos) )
		{
			/// ML 2/15/2010 QA70-15113 81SR1_OMC_FILES_SHOULD_ALWAYS_APPEND_BUT_NEW_SHOULD_INSERT_BEFORE_WINDOW
			//nPos = OMC_POS_INSERT_BEFORE_WINDOW;//OMC_POS_APPEND_END; CPY 2012-02-12 CHANGE_CUSTOM_MENU_DEFAULT_TO_INSERT
			nPos = OMC_POS_DEFAUL_IF_POS_ABSENT;
			if ( pbDefault )
				*pbDefault = TRUE;
			/// end 81SR1_OMC_FILES_SHOULD_ALWAYS_APPEND_BUT_NEW_SHOULD_INSERT_BEFORE_WINDOW
		}
		/// ML 2/15/2010 QA70-15113 81SR1_OMC_FILES_SHOULD_ALWAYS_APPEND_BUT_NEW_SHOULD_INSERT_BEFORE_WINDOW
		else if ( pbDefault )
			*pbDefault = FALSE;
		/// end 81SR1_OMC_FILES_SHOULD_ALWAYS_APPEND_BUT_NEW_SHOULD_INSERT_BEFORE_WINDOW
		
		return nPos;
	}
	
	void	SetPosition(int nPos)//=OMC_POS_APPEND_END) CPY 2012-02-12 CHANGE_CUSTOM_MENU_DEFAULT_TO_INSERT, better have no default for a Set method
	{
		ASSERT(m_trEditingOMC);
		m_trEditingOMC.SetAttribute(STR_OMC_POS_ATTRIB, nPos);
	}
	///---END QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	
	BOOL OpenFile(LPCSTR lpcszFullPathFileName)
	{
		string strFullPathFile(lpcszFullPathFileName);
		strFullPathFile.TrimLeft();
		strFullPathFile.TrimRight();
		string strPath = GetFilePath(strFullPathFile);
		string strName = GetFileName(strFullPathFile, true);
		string strExt = strFullPathFile.Right(3);
		if(!strFullPathFile.IsFile() || strPath.IsEmpty() || strName.IsEmpty() || strExt.CompareNoCase(MENU_CUSTOMIZATION_FILE_EXT))
			return false;
		int nPathType = getPathType(strPath);
		
		int nIndex = 0;
		while(true)
		{
			nIndex = m_vsOMCFileNames.Find(strName, nIndex);
			if(nIndex < 0)
				break;
			if(strPath.CompareNoCase(m_vsFilePaths[nIndex]) == 0)
				break;
			nIndex++;
		}
		if(nIndex < 0)
		{
			m_vsOMCFileNames.Add(strName);
			m_vsFilePaths.Add(strPath);
			m_vnPathTypes.Add(nPathType);
			nIndex = m_vnPathTypes.GetSize()-1;
			m_nEditingLevel = nIndex;
			sortFiles();
		}
		else if(m_nEditingLevel == nIndex)		// do nothing
			return true;
		else
			m_nEditingLevel = nIndex;

		return SetEditingLevel(m_nEditingLevel);
	}
	
	//int FindDefaultLevel()		// 0 offset
	//{
		//INIFileEx iniFile(STR_ORIGIN_INI);
		//string strDef = iniFile.ReadString(STR_SECTION_OPTIONS, STR_OMC_MENU_LEVEL);
		//if(strDef.IsEmpty())
			//return -1;
		//return m_vsOMCFileNames.Find(strDef);
	//}

	void	GetOMCFileNames(vector<string>& vsFileNames)
	{
		vsFileNames = m_vsOMCFileNames;
	}
	
	void	GetOMCPathTypes(vector<string>& vsPathTypes)
	{
		vsPathTypes.SetSize(m_vnPathTypes.GetSize());
		for(int ii=m_vnPathTypes.GetSize()-1; ii>=0; ii--)
		{
			switch(m_vnPathTypes[ii])
			{
			case ORIGIN_PATH_USER:
				vsPathTypes[ii] = _L("User");
				break;
				
			case ORIGIN_PATH_GROUP:
				vsPathTypes[ii] = _L("Group");
				break;
				
			case ORIGIN_PATH_SYSTEM:
				vsPathTypes[ii] = _L("System");
				break;
			//case ORIGIN_PATH_UNDEF:
			default:
				vsPathTypes[ii] = _L("UnKnown");
			}
		}
	}
	
	int		GetNumOMCFiles()
	{
		return m_vsOMCFileNames.GetSize();
	}
	
	bool	GetEditingFileName(string& strFileName)
	{
		if(m_nEditingLevel < 0 || m_nEditingLevel >= m_vsOMCFileNames.GetSize())
			return false;
		strFileName = m_vsOMCFileNames[m_nEditingLevel];
		return true;
	}
	
	bool	GetEditingFilePathType(string& strPathType)
	{
		strPathType.Empty();
		if(m_nEditingLevel < 0 || m_nEditingLevel >= m_vsOMCFileNames.GetSize())
			return false;
		switch(m_vnPathTypes[m_nEditingLevel])
		{
		case ORIGIN_PATH_USER:
			strPathType = _L("User");
			break;
			
		case ORIGIN_PATH_GROUP:
			strPathType = _L("Group");
			break;
			
		case ORIGIN_PATH_SYSTEM:
			strPathType = _L("System");
			break;
		
		//case ORIGIN_PATH_UNDEF:
		default:
			strPathType = _L("UnKnown");
		}
		return true;
	}

	bool	SetEditingLevel(int nLevel)
	{
		if(nLevel < 0 || nLevel >= m_vsOMCFileNames.GetSize())
			nLevel = -1;
		m_nEditingLevel = nLevel;
		
		bool bRet = true;
		if(m_nEditingLevel < 0 || !(bRet = m_trEditingOMC.Load(m_vsFilePaths[m_nEditingLevel] + m_vsOMCFileNames[m_nEditingLevel] + ".omc")) )
			m_trEditingOMC.Reset();

		checkConvertOMCVersion();		///Kyle 02/26/2010 QA80-15138 KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC

		return bRet;
	}

	int		GetEditingLevel()
	{
		return m_nEditingLevel;
	}
	
	TreeNode GetEditingTreeNode()
	{
		return m_trEditingOMC;
	}
	
	bool	SetEditingTreeNode(TreeNode& trConfig)
	{
		ASSERT(m_trEditingOMC);
		m_trEditingOMC.Replace(trConfig, true, true);
		return true;
	}
	
	bool	SaveEditingOMC()
	{
		if(m_nEditingLevel < 0 || m_nEditingLevel >= m_vsOMCFileNames.GetSize())
			return false;
		if(!Editable())
			return false;

		if(m_trEditingOMC.Save(m_vsFilePaths[m_nEditingLevel] + m_vsOMCFileNames[m_nEditingLevel] + ".omc"))
		{
			//m_bDirty = false;
			return true;
		}
		return false;
	}
	
	BOOL SaveEditingOMCAs(LPCSTR lpcszFile)
	{
		if(m_trEditingOMC.Save(lpcszFile))
		{
			string 	strFile(lpcszFile),
					strFileName = GetFileName(strFile, true),
					strFilePath = GetFilePath(strFile);
			int nPathType = getPathType(strFilePath);
			
			int nIndex = 0;
			while(true)
			{
				nIndex = m_vsOMCFileNames.Find(strFileName, nIndex);
				if(nIndex < 0)
					break;
				if(strFilePath.CompareNoCase(m_vsFilePaths[nIndex]) == 0)
					break;
				nIndex++;
			}
			if(nIndex < 0)
			{
				m_vsOMCFileNames.Add(strFileName);
				m_vsFilePaths.Add(strFilePath);
				m_vnPathTypes.Add(nPathType);
				nIndex = m_vnPathTypes.GetSize()-1;
			}
			m_nEditingLevel = nIndex;
			sortFiles();
			
			//m_bDirty = false;
			return true;
		}

		return false;
	}
	
	BOOL DeleteEditingOMC()
	{
		if(m_nEditingLevel < 0 || m_nEditingLevel >= m_vsOMCFileNames.GetSize())
			return false;

		string strFullPathFile = m_vsFilePaths[m_nEditingLevel] + m_vsOMCFileNames[m_nEditingLevel] + ".omc";
		DeleteFile(strFullPathFile);

		m_vsOMCFileNames.RemoveAt(m_nEditingLevel);
		m_vsFilePaths.RemoveAt(m_nEditingLevel);
		m_vnPathTypes.RemoveAt(m_nEditingLevel);
		m_nEditingLevel = -1;
		m_trEditingOMC.Reset();

		return true;
	}

	bool	NewEditingOMC()
	{
		//m_bDirty = false;
		m_nEditingLevel = -1;
		m_trEditingOMC.Reset();
		return true;
	}
	
	bool	IsNewFile()
	{
		return m_nEditingLevel < 0;
	}

	// for hide built-in menus settings
	BOOL	GetEditingHideList(vector<string>& vsHideList, vector<int>& vnWndTypes)
	{
		getValidWndTypes(vnWndTypes);
		vsHideList.SetSize(vnWndTypes.GetSize());
		TreeNode trConfig = GetEditingTreeNode();
		if(!trConfig)
			return false;

		for(int ii=vnWndTypes.GetSize()-1; ii>=0; ii--)
		{
			string strAttrib = getHideListAttrib(vnWndTypes[ii]);
			string strHideList;
			if(!strAttrib.IsEmpty())
				trConfig.GetAttribute(strAttrib, strHideList);
			vsHideList[ii] = strHideList;
		}
		return true;
	}

	BOOL	SetEditingHideList(const vector<string>& vsHideList, const vector<int>& vnWndTypes)
	{
		ASSERT(vsHideList.GetSize() == vnWndTypes.GetSize());
		TreeNode trConfig = GetEditingTreeNode();
		if(!trConfig)
			return false;
		for(int ii=0; ii<vnWndTypes.GetSize(); ii++)
		{
			string strAttrib = getHideListAttrib(vnWndTypes[ii]);
			trConfig.SetAttribute(strAttrib, vsHideList[ii]);
		}
		return true;
	}

private:
	///Kyle 02/26/2010 QA80-15138 KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC
	void checkConvertOMCVersion()
	{
		if( !m_trEditingOMC )
		{
			ASSERT(false);
			return;
		}

		int nOMCVersion = 0;
		if( !m_trEditingOMC.GetAttribute(STR_OMC_VERSION_ATTRIB, nOMCVersion) || nOMCVersion < OMC_VERSION_HIDE_BUILT_IN_MENU_LIST_KEEP_MENU_TAG )
		{
			vector<int> vnWndTypes;
			getValidWndTypes(vnWndTypes);
			for(int ii=vnWndTypes.GetSize()-1; ii>=0; ii--)
			{
				string strAttrib = getHideListAttrib(vnWndTypes[ii]);
				string strHideList;
				if(!strAttrib.IsEmpty())
				{
					m_trEditingOMC.GetAttribute(strAttrib, strHideList);
					if( !strHideList.IsEmpty() )
					{
						okutil_omc_convert_hide_list_from_81_sr1(vnWndTypes[ii], strHideList, strHideList);
						m_trEditingOMC.SetAttribute(strAttrib, strHideList);
					}
				}
			}
		}

		int nCurVersion = okutil_omc_get_current_version();
		m_trEditingOMC.SetAttribute(STR_OMC_VERSION_ATTRIB, nCurVersion);
	}
	///End KEEP_MENU_TAG_FOR_HIDE_BUILT_IN_MENU_LIST_TO_INDICATE_THE_POPUP_INDICES_IN_OMC

	void sortFiles()
	{
		vector<uint> vnOrders;
		m_vsOMCFileNames.Sort(SORT_ASCENDING, TRUE, vnOrders);
		m_vsFilePaths.Reorder(vnOrders);
		m_vnPathTypes.Reorder(vnOrders);
		if(m_nEditingLevel >= 0 && m_nEditingLevel<m_vsOMCFileNames.GetSize())
		{
			///Kyle 12/16/2009 QA80-14794-P3 WRONG_SELECTED_LEVEL_AFTER_REORDER
			//m_nEditingLevel = vnOrders[m_nEditingLevel];
			vector<uint> vnIndex;
			if( vnOrders.Find(vnIndex, m_nEditingLevel) > 0 )
			{
				ASSERT(1 == vnIndex.GetSize());
				m_nEditingLevel = vnIndex[0];
			}
			else
			{
				ASSERT(false);
				m_nEditingLevel = 0;
			}
			///End WRONG_SELECTED_LEVEL_AFTER_REORDER
		}
	}

	int		getPathType(LPCSTR lpcszPath)
	{
		string strPath(lpcszPath);
		strPath.TrimRight("\\");
		
		vector<int> vnPathTypes = {ORIGIN_PATH_USER, ORIGIN_PATH_GROUP, ORIGIN_PATH_SYSTEM};
		for(int ii=vnPathTypes.GetSize()-1; ii>=0; ii--)
		{
			string strPathTmp = okutil_get_origin_path(vnPathTypes[ii]);
			strPathTmp.TrimRight("\\");
			if(strPathTmp.CompareNoCase(strPath) == 0)
				return vnPathTypes[ii];
		}
		return ORIGIN_PATH_UNDEF;
	}
	
	void	getValidWndTypes(vector<int>& vnWndTypes)
	{
		vector<int> vn = {EXIST_WKS, EXIST_GRAPH, EXIST_MATRIX};
		vnWndTypes = vn;
	}
	bool checkFileName(LPCSTR lpcszFile)
	{
		string strFile(lpcszFile);
		strFile.TrimLeft();
		strFile.TrimRight();
		if(strFile.IsEmpty())
			return false;
		
		return is_good_C_identifier(strFile);
	}

	int scanOMCFiles()
	{
		m_vsOMCFileNames.SetSize(0);
		m_vsFilePaths.SetSize(0);
		m_vnPathTypes.SetSize(0);
		vector<int> vnPathTypes = {ORIGIN_PATH_USER, ORIGIN_PATH_GROUP, ORIGIN_PATH_SYSTEM};
		for(int ii=0; ii<vnPathTypes.GetSize(); ii++)
		{
			string strPath = okutil_get_origin_path(vnPathTypes[ii]);
			if(strPath.IsEmpty())
				continue;
			vector<string> vsFiles;
			FindFiles(vsFiles, strPath, MENU_CUSTOMIZATION_FILE_EXT);
			for(int nFile = vsFiles.GetSize()-1; nFile>=0; nFile--)
			{
				m_vsOMCFileNames.Add(GetFileName(vsFiles[nFile], true));
				m_vsFilePaths.Add(strPath);
				m_vnPathTypes.Add(vnPathTypes[ii]);
			}
		}
		sortFiles();
		bool bHasFile = m_vsOMCFileNames.GetSize()>0;
		if(bHasFile)
		{
			///Kyle 12/07/2009 QA80-14794-P2 SELECT_THE_ACTIVE_OMC_CONFIG_IN_MAIN_MENU
			//SetEditingLevel(0);
			int nLevel = 0;
			string strDefFullPathFile;
			if( _find_current_omc_level(strDefFullPathFile) > 0 && !strDefFullPathFile.IsEmpty() )
			{
				string strDefPath = GetFilePath(strDefFullPathFile);
				string strDefFile = GetFileName(strDefFullPathFile, true);
				int nPosPath = m_vsFilePaths.Find(strDefPath),
					nPosFile = m_vsOMCFileNames.Find(strDefFile);
				while( nPosPath >= 0 && nPosFile >= 0 && nPosPath != nPosFile )
				{
					if( nPosPath > nPosFile )
						nPosFile = m_vsOMCFileNames.Find(strDefFile, nPosFile + 1);
					else	// nPosFile > nPosPath
						nPosPath = m_vsFilePaths.Find(strDefPath, nPosPath + 1);
				}
				if( nPosPath >= 0 && nPosPath == nPosFile )
					nLevel = nPosPath;
			}
			SetEditingLevel(nLevel);
			///End SELECT_THE_ACTIVE_OMC_CONFIG_IN_MAIN_MENU
		}
		
		return bHasFile;
	}

	string		getHideListAttrib(int nWndType)
	{
		string strHideListAttrib;
		switch(nWndType)
		{
		case EXIST_WKS:
			strHideListAttrib = STR_CUSTOM_HIDE_BUILT_IN_MENU_ATTRIB_WKS;
			break;
		case EXIST_GRAPH:
			strHideListAttrib = STR_CUSTOM_HIDE_BUILT_IN_MENU_ATTRIB_GRAPH;
			break;
		case EXIST_MATRIX:
			strHideListAttrib = STR_CUSTOM_HIDE_BUILT_IN_MENU_ATTRIB_MATRIX;
			break;
		}

		return strHideListAttrib;
	}

private:
	// custom menus structure
	//bool				m_bDirty;
	Tree				m_trEditingOMC;
	int					m_nEditingLevel;

	//string				m_strUserPath;
	vector<string>		m_vsOMCFileNames;
	vector<string>		m_vsFilePaths;
	vector<int>			m_vnPathTypes;
};

class OMCEditingMenu : public Menu
{
public:
	OMCEditingMenu(HMENU &hMenu) : Menu(hMenu)
	{
		m_nCheckedLevel = -1;
		m_nSize = 0;
	}
	~OMCEditingMenu()
	{
	}
	
	void		EnableSave(bool bEnable)
	{
		int nFlags = MF_STRING;
		if(!bEnable)
			nFlags |= MF_DISABLED | MF_GRAYED;
		modifyMenu(IDC_CUSTOM_MENU_SAVE, nFlags);
	}
	
	void		EnableDelete(bool bEnable)
	{
		int nFlags = MF_STRING;
		if(!bEnable)
			nFlags |= MF_DISABLED | MF_GRAYED;
		modifyMenu(IDC_CUSTOM_MENU_DELETE, nFlags);
	}

	void		UpdateFileList(const vector<string>& vsFileNames, const vector<string>& vsPathTypes, int nCheckedLevel = -1)
	{
		m_nCheckedLevel = nCheckedLevel;
		if(m_nSize > 0)
		{
			RemoveMenu(IDC_XFM_SEPARATOR, MF_SEPARATOR);
			for(int ii = 0; ii < m_nSize; ii++)
				RemoveMenu(IDC_SET_VALUE_COL_LIST_BEGIN + ii, MF_STRING);
		}
		m_nSize = vsFileNames.GetSize() < vsPathTypes.GetSize() ? vsFileNames.GetSize() : vsPathTypes.GetSize();
		if(m_nSize > IDC_SET_VALUE_COL_LIST_END-IDC_SET_VALUE_COL_LIST_BEGIN + 1)
			m_nSize = IDC_SET_VALUE_COL_LIST_END-IDC_SET_VALUE_COL_LIST_BEGIN + 1;
		if(m_nSize)
		{
			InsertMenu(IDC_CUSTOM_MENU_EXIT, MF_SEPARATOR, IDC_XFM_SEPARATOR);
			for(int ii=0; ii<m_nSize; ii++)
			{
				int nFlag = MF_STRING;
				if(nCheckedLevel == ii)
					nFlag |= MF_CHECKED;
				InsertMenu(IDC_XFM_SEPARATOR, nFlag, IDC_SET_VALUE_COL_LIST_BEGIN + ii, vsFileNames[ii] + " (" + vsPathTypes[ii] + ")");
			}
		}
	}

	int GetLevelFromID(int nID)
	{
		if( nID >= IDC_SET_VALUE_COL_LIST_BEGIN && nID <= IDC_SET_VALUE_COL_LIST_END )
			return nID - IDC_SET_VALUE_COL_LIST_BEGIN;
		return -1;
	}

	BOOL SetCheckedLevel(int nLevel)
	{
		if(m_nCheckedLevel == nLevel)
			return true;
		if(m_nCheckedLevel >= 0 && m_nCheckedLevel < m_nSize)
		{
			modifyMenu(m_nCheckedLevel+IDC_SET_VALUE_COL_LIST_BEGIN, MF_STRING);
		}
		m_nCheckedLevel = nLevel;
		if(m_nCheckedLevel >= 0 && m_nCheckedLevel < m_nSize)
		{
			modifyMenu(m_nCheckedLevel+IDC_SET_VALUE_COL_LIST_BEGIN, MF_STRING | MF_CHECKED);
		}
		return true;
	}
	
private:
	void	modifyMenu(int nID, int nFlags)
	{
		string str;
		if( GetMenuString(nID, str, MF_STRING) )
			ModifyMenu(nID, nFlags, nID, str);
	}
	
private:
	int m_nCheckedLevel;
	int m_nSize;
};

/*----------------------------------------------------------------------------*/
/* Declaration of LTCustomMenuEditorDlg
/*----------------------------------------------------------------------------*/

class LTCustomMenuEditorDlg : public ResizeDialog
{	
public:
	LTCustomMenuEditorDlg();
	~LTCustomMenuEditorDlg();

	int DoModalEx(HWND hParent = NULL) 
	{
		InitMsgMap();
		int nRet = ResizeDialog::DoModal(hParent);
		return nRet;
	}
	
protected:
	
EVENTS_BEGIN
	ON_INIT(OnInitDialog) 
	ON_READY(OnReady)
	ON_SIZE(OnDlgResize)
	ON_RESTORESIZE(OnRestoreSize)
	ON_DESTROY(OnDestroy)
	ON_HELPINFO(OnHelp)
	ON_OK(OnOK)
	ON_CANCEL(OnClose)
	ON_TAB_SEL_CHANGE(IDC_CUSTOM_MENU_TAB, OnTabChange)
	ON_GRID_BEFORE_EDIT(IDC_CUSTOM_MENU_BUILT_IN_GRID, OnBeforeEditBuiltInControl)
	ON_GRID_BEFORE_COLLAPSE(IDC_CUSTOM_MENU_BUILT_IN_GRID, OnBeforeCollapseBuiltInControl)
	ON_GRID_AFTER_EDIT(IDC_CUSTOM_MENU_BUILT_IN_GRID, OnAfterEditBuiltInControl)
	ON_CBN_SELCHANGE(IDC_CUSTOM_MENU_COMBO_WNDTYPE, OnWndTypeChange)
	ON_KEY(IDC_CUSTOM_MENU_BUILT_IN_GRID, OnKey)
	
	ON_BN_CLICKED(IDC_CUSTOM_MENU_RESET_BUILT_IN, OnResetBuiltInMenu)
	ON_GRID_BEFORE_MOUSE_DOWN(IDC_CUSTOM_MENU_BUILT_IN_GRID, OnBeforeMouseDownBuiltInMenusControl)
	ON_USER_MSG(WM_USER_RECONSTRUCT, OnReconstructGrid)
	
	ON_BN_CLICKED(IDC_CUSTOM_MENU_CHECK_ENABLE, OnCheckEnable)
	///---Sim 01-22-2010 QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	ON_CBN_SELCHANGE(IDC_CUSTOM_MENU_POS_COMBO, OnPositionChange)
	///---END QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	//ON_CBN_SELCHANGE(IDC_CUSTOM_MENU_COMBO_OMC, OnEditingOMCChange)
	ON_MENU_CMD_RANGE(IDC_SET_VALUE_COL_LIST_BEGIN, IDC_SET_VALUE_COL_LIST_END, OnSelOMCFile)
	
	ON_MENU_CMD(IDC_CUSTOM_MENU_NEW, OnNew)
	ON_MENU_CMD(IDC_CUSTOM_MENU_OPEN, OnOpenFile)
	ON_MENU_CMD(IDC_CUSTOM_MENU_DELETE, OnDelete)
	ON_MENU_CMD(IDC_CUSTOM_MENU_SAVE, OnSave)
	ON_MENU_CMD(IDC_CUSTOM_MENU_SAVEAS, OnSaveAs)
	ON_MENU_CMD(IDC_CUSTOM_MENU_EXIT, OnExit)
	
	ON_USER_MSG(WM_USER_CUSTOM_MENU_EDITOR_UPDATE_WINDOW_TEXT , OnUpdateWndText)
	
EVENTS_END

	BOOL OnInitDialog();
	BOOL OnReady();
	BOOL OnDlgResize(int nType, int cx, int cy);
	BOOL OnRestoreSize(DWORD dwSizeInfo);
	BOOL OnDestroy();
	BOOL OnHelp(int &nHelpID, int nIdCtrlFocus);
	BOOL OnOK();
	BOOL OnClose();
	BOOL OnTabChange(Control ctrl);
	void OnAfterEditBuiltInControl(Control flxControl, int nRow, int nCol);
	void OnBeforeEditBuiltInControl(Control flxControl, long nRow, long nCol, BOOL* pCancel);
	void OnBeforeCollapseBuiltInControl(Control flxControl, long nRow, short nState, BOOL* pCancel);
	BOOL OnWndTypeChange(Control ctrl);
	
	BOOL	OnCheckEnable(Control ctrl);
	///---Sim 01-22-2010 QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	BOOL	OnPositionChange(Control ctrl);
	///---END QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	//BOOL	OnEditingOMCChange(Control ctrl);
	BOOL OnEditingOMCChange(int nLevel);
	//BOOL	SaveEditingOMCFile();
	//void	UpdateOMCListCombo();
	void	UpdateOMCFileList();
	
	BOOL OnNew();
	BOOL OnOpenFile();
	BOOL OnDelete();
	BOOL OnSave();
	BOOL OnSaveAs();
	BOOL OnExit();
	BOOL OnSelOMCFile(int nID);
	
	BOOL	OnUpdateWndText(uint wParam, uint lParam);
	
	BOOL	CheckSaveOMCFile(BOOL bCheckDirty, BOOL bSaveAs, BOOL bAskBeforeSaving, BOOL* pCancel = NULL);
	void	SetDirty(bool bDirty = true, bool bUpdateWndText = true);

	bool LoadSettings();
	bool SaveSettings();
	int GetHideBuiltInHintsHeight(int nMsgBoxWidth);
	BOOL OnKey(Control ctrl, UINT msg, UINT wParam, UINT lParam);
	
	BOOL OnResetBuiltInMenu(Control ctrl);
	BOOL OnBeforeMouseDownBuiltInMenusControl(Control cntrl, short nButton, short nShift, float X, float Y, BOOL* pCancel);

	int ArrangeControlsRightLeftNoCheckVisible(uint nButtonIDs[], int nx, int ny, int nGap);
	int ArrangeControlsLeftRightNoCheckVisible(uint nButtonIDs[], int nx, int ny, int nGap);
	
	BOOL OnReconstructGrid(UINT wParam, UINT lParam);

private:
	//ComboBox				m_comboOMC;
	int						m_nOMCListBeginID;
	OMCEditingMenu*			m_pOMCEditingMenu;
	Button 					m_btnEnable;
	///---Sim 01-22-2010 QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	ComboBox				m_cmbPosition;
	///---END QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	BOOL					m_bDirty;

	ComboBox 				m_comboWndType;
	TabControl 				m_tab;

	MenuEditorSplitter		m_MESplitter;
	BuiltInMenuGridControl	m_builtInGridCtrl;
	Control 				m_ctrlHideBuiltInHints;
	
	OMCFileManager	 		m_omcFileMngr;

};

/*----------------------------------------------------------------------------*/
/* Constructors/Destructors of LTCustomMenuEditorDlg
/*----------------------------------------------------------------------------*/

LTCustomMenuEditorDlg::LTCustomMenuEditorDlg() : ResizeDialog(IDD_LT_CUSTOM_MENU_EDITOR_DLG, "ODlg8")
{
	m_pOMCEditingMenu = NULL;
}

LTCustomMenuEditorDlg::~LTCustomMenuEditorDlg()
{

}

/*----------------------------------------------------------------------------*/
/* Event handlers of LTCustomMenuEditorDlg
/*----------------------------------------------------------------------------*/

BOOL LTCustomMenuEditorDlg::OnInitDialog()
{
	ResizeDialog::OnInitDialog(0, STR_DLG_NAME_E);
	GetWindow().Text = STR_DLG_NAME;

	m_tab = GetItem(IDC_CUSTOM_MENU_TAB);
	
	m_tab.InsertItem(ADD_CUSTOM_MENUS_TAB, STR_ADD_CUSTOM_MENUS_TAB);
	m_tab.InsertItem(HIDE_BUILT_IN_MENUS_TAB, STR_HIDE_BUILT_IN_MENUS_TAB);

	//m_comboOMC = GetItem(IDC_CUSTOM_MENU_COMBO_OMC);
	Control ctrlComboOMC = GetItem(IDC_CUSTOM_MENU_COMBO_OMC);
	if(ctrlComboOMC)
		ctrlComboOMC.Visible = false;
	Control ctrlStaticOMC = GetItem(IDC_STATIC_OMC_LIST);
	if(ctrlStaticOMC)
		ctrlStaticOMC.Visible = false;
	m_btnEnable = GetItem(IDC_CUSTOM_MENU_CHECK_ENABLE);
	///---Sim 01-22-2010 QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	m_cmbPosition = GetItem(IDC_CUSTOM_MENU_POS_COMBO);
	///---END QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU

	m_MESplitter.Init(IDC_MENU_TREE_DYNA, *this, 0, STR_DLG_NAME_E);
	//m_MESplitter.SetCustomMenuConfig();

	m_builtInGridCtrl.Init(IDC_CUSTOM_MENU_BUILT_IN_GRID, *this, STR_DLG_NAME_E);
	//m_builtInGridCtrl.Update();

	m_ctrlHideBuiltInHints = GetItem(IDC_CUSTOM_MENU_HINT_BOX);
	m_ctrlHideBuiltInHints.Text = STR_HIDE_BUILT_IN_HINTS;
	
	m_comboWndType = GetItem(IDC_CUSTOM_MENU_COMBO_WNDTYPE);
	m_comboWndType.ResetContent();
	vector<string> vsWndTypes;// = { STR_GUI_LABEL_WORKBOOK_TYPE, STR_GUI_LABEL_GRAPH_TYPE, STR_GUI_LABEL_MATRIX_TYPE };
	vsWndTypes.Add(STR_GUI_LABEL_WORKBOOK_TYPE);
	vsWndTypes.Add(STR_GUI_LABEL_GRAPH_TYPE);
	vsWndTypes.Add(STR_GUI_LABEL_MATRIX_TYPE);
	for( int nItem = 0; nItem < vsWndTypes.GetSize(); nItem++ )
		m_comboWndType.AddString(vsWndTypes[nItem]);
	
	//UpdateOMCListCombo();				// should update the controls before loading settings
	HMENU 	hMenu = GetMenu(GetSafeHwnd());
	m_pOMCEditingMenu = new OMCEditingMenu(hMenu);
	UpdateOMCFileList();

	LoadSettings();
	//OnEditingOMCChange(m_comboOMC);
	int nLevel = m_omcFileMngr.GetEditingLevel();
	m_omcFileMngr.SetEditingLevel(-1);			// if nLevel == m_omcFileMngr.GetEditingLevel(), won't update gui
	OnEditingOMCChange(nLevel);

	OnTabChange(m_tab);

	return true;
}

BOOL LTCustomMenuEditorDlg::OnReady()
{			
	SetInitReady();
	m_MESplitter.SetTreeEditPaneSize(70, true);
	return TRUE;
}

BOOL	LTCustomMenuEditorDlg::OnRestoreSize(DWORD dwSizeInfo)
{
	void * p = (void*)dwSizeInfo;
	DLGSIZEINFO *pSz = (DLGSIZEINFO*)p;
	
	lstrcpyn(pSz->szDialogName, STR_DLG_NAME_E, MAXLINE);
	pSz->top = -1;
	pSz->left =-1;
	pSz->width = 800;
	pSz->height = 500;
	return TRUE;
}

BOOL LTCustomMenuEditorDlg::OnDlgResize(int nType, int cx, int cy)
{
	if(!IsInitReady())
		return FALSE;

	MoveControlsHelper	_temp(this);

	RECT rr;
	int nEdge = GetControlGap();
	Button btnClose;
	GetControlClientRect(IDCANCEL, rr, &btnClose);
	int nBtnHeight = RECT_HEIGHT(rr);

	cy -= (nBtnHeight + nEdge);
	uint nRightBottomButtonIDs[] = {IDCANCEL, IDC_CUSTOM_MENU_RESET_BUILT_IN, 0};
	ArrangeControlsRightLeftNoCheckVisible(nRightBottomButtonIDs, cx, cy, nEdge);
	
	uint nLeftBottomButtonIDs[] = {IDC_STATIC_WND_TYPE, IDC_CUSTOM_MENU_COMBO_WNDTYPE, 0};
	ArrangeControlsLeftRightNoCheckVisible(nLeftBottomButtonIDs, nEdge, cy, nEdge);

//	uint nLeftTopButtonIDs[] = {IDC_STATIC_OMC_LIST, IDC_CUSTOM_MENU_COMBO_OMC};
	///---Sim 01-22-2010 QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	//uint nLeftTopButtonIDs[] = {IDC_CUSTOM_MENU_CHECK_ENABLE, 0};
	uint nLeftTopButtonIDs[] = {IDC_CUSTOM_MENU_CHECK_ENABLE, IDC_STATIC_OMC_POS_LABEL, IDC_CUSTOM_MENU_POS_COMBO, 0};
	///---END QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	ArrangeControlsLeftRightNoCheckVisible(nLeftTopButtonIDs, nEdge, nEdge, nEdge);


	Control ctrTreeDyna;
	GetControlClientRect(IDC_CUSTOM_MENU_TAB, rr, &ctrTreeDyna);
	rr.left = nEdge;
	rr.top = nBtnHeight + 2 * nEdge;
	rr.right = cx-nEdge;
	rr.bottom = cy-nEdge;
	MoveControl(ctrTreeDyna, rr);

	RECT rTab;
	rTab = rr;
	m_tab.AdjustRect(FALSE, &rTab);

	// Add Custom Menus Tab
	Control ctrlTreeDyna = GetItem(IDC_MENU_TREE_DYNA);
	rr = rTab;
	if(ctrlTreeDyna)
		MoveControl(ctrlTreeDyna, rr);

	// Hide Built-in Menus Tab
	int nHintsHeight = GetHideBuiltInHintsHeight(RECT_WIDTH(rTab));
	Control ctrlHint = GetItem(IDC_CUSTOM_MENU_HINT_BOX);
	rr = rTab;
	rr.top = rr.bottom - nHintsHeight;
	MoveControl(ctrlHint, rr);

	Control ctrlGrid = GetItem(IDC_CUSTOM_MENU_BUILT_IN_GRID);
	rr = rTab;
	rr.bottom = rr.bottom - nHintsHeight - nEdge;
	MoveControl(ctrlGrid, rr);

	return TRUE;
}

BOOL LTCustomMenuEditorDlg::OnResetBuiltInMenu(Control ctrl)
{
	m_builtInGridCtrl.Reset();
	return true;
}

BOOL LTCustomMenuEditorDlg::OnReconstructGrid(UINT wParam, UINT lParam)
{
	return m_builtInGridCtrl.OnReconstructGrid(wParam, lParam);
}

BOOL LTCustomMenuEditorDlg::OnBeforeMouseDownBuiltInMenusControl(Control cntrl, short nButton, short nShift, float X, float Y, BOOL* pCancel)
{
	m_builtInGridCtrl.OnBeforeMouseDown(nButton, nShift, X, Y, pCancel);
	return true;
}

int LTCustomMenuEditorDlg::ArrangeControlsRightLeftNoCheckVisible(uint nButtonIDs[], int nx, int ny, int nGap)
{
	RECT rr, r1;
	rr.right = nx - nGap;
	rr.top = ny;
	int ii = 0;
	int nMaxHeight = 0;
	while(nButtonIDs[ii] > 0)
	{
		Control btn = GetItem(nButtonIDs[ii]);
		if(btn)
		{
			GetClientRect(btn, r1);
			rr.left = rr.right - RECT_WIDTH(r1);
			if(nMaxHeight < RECT_HEIGHT(r1))
				nMaxHeight = RECT_HEIGHT(r1);
			rr.bottom = rr.top + RECT_HEIGHT(r1);
			MoveControl(btn, rr);

			rr.right = rr.left - nGap;
		}
		ii++;
	}
	return ny + nMaxHeight;
}


int LTCustomMenuEditorDlg::ArrangeControlsLeftRightNoCheckVisible(uint nButtonIDs[], int nx, int ny, int nGap)
{
	RECT rr, r1;
	rr.left = nx;
	rr.top = ny;
	int ii = 0;
	int nMaxHeight = 0;
	while(nButtonIDs[ii] > 0)
	{
		Control btn = GetItem(nButtonIDs[ii]);
		if(btn)
		{
			GetClientRect(btn, r1);
			rr.right = rr.left + RECT_WIDTH(r1);
			if(nMaxHeight < RECT_HEIGHT(r1))
				nMaxHeight = RECT_HEIGHT(r1);
			rr.bottom = rr.top + RECT_HEIGHT(r1);
			MoveControl(btn, rr);

			rr.left = rr.right + nGap;
		}
		ii++;
	}
	return ny + nMaxHeight;
}

BOOL LTCustomMenuEditorDlg::OnKey(Control ctrl, UINT msg, UINT wParam, UINT lParam)
{
	if( msg == WM_KEYDOWN )
	{
		switch(wParam)
		{
		case VK_RETURN:
			m_builtInGridCtrl.OnEnter(ctrl);
			break;
			
		default:
			return FALSE;
		}
		return TRUE;
	}

	return FALSE; // return FALSE for not eating message for Enter key in Input window
}

int LTCustomMenuEditorDlg::GetHideBuiltInHintsHeight(int nMsgBoxWidth)
{
	string str = m_ctrlHideBuiltInHints.Text;
	int nW = nMsgBoxWidth;
	int nHeight = m_ctrlHideBuiltInHints.Measure(str, &nW);
	return nHeight;
}

BOOL LTCustomMenuEditorDlg::OnWndTypeChange(Control ctrl)
{
	int nCurSelWndType = m_comboWndType.GetCurSel();
	int nExist = EXIST_NONE;
	switch(nCurSelWndType)
	{
	case WND_TYPE_WKS:
		nExist = EXIST_WKS;
		break;
		
	case WND_TYPE_GRAPH:
		nExist = EXIST_GRAPH;
		break;

	case WND_TYPE_MATRIX:
		nExist = EXIST_MATRIX;
		break;

	default:
		return false;
	}
	m_builtInGridCtrl.Update(nExist, TRUE);

	return true;
}


BOOL LTCustomMenuEditorDlg::OnTabChange(Control cntrl)
{
	// update controls show/hide
	SetFocus(cntrl.GetSafeHwnd());

	bool bAddCustomMenusTab = (ADD_CUSTOM_MENUS_TAB == m_tab.GetCurSel());
	GetItem(IDC_MENU_TREE_DYNA).Visible = bAddCustomMenusTab;

	bool bHideBuiltInMenusTab = (HIDE_BUILT_IN_MENUS_TAB == m_tab.GetCurSel());
	GetItem(IDC_CUSTOM_MENU_BUILT_IN_GRID).Visible = bHideBuiltInMenusTab;
	GetItem(IDC_CUSTOM_MENU_HINT_BOX).Visible = bHideBuiltInMenusTab;
	GetItem(IDC_STATIC_WND_TYPE).Visible = bHideBuiltInMenusTab;
	GetItem(IDC_CUSTOM_MENU_COMBO_WNDTYPE).Visible = bHideBuiltInMenusTab;
	GetItem(IDC_CUSTOM_MENU_RESET_BUILT_IN).Visible = bHideBuiltInMenusTab;

	return TRUE;
}

void 	LTCustomMenuEditorDlg::OnAfterEditBuiltInControl(Control flxControl, int nRow, int nCol)
{
	m_builtInGridCtrl.OnAfterEdit(flxControl, nRow, nCol);
}

void 	LTCustomMenuEditorDlg::OnBeforeEditBuiltInControl(Control flxControl, long nRow, long nCol, BOOL* pCancel)
{
	m_builtInGridCtrl.OnBeforeEdit(flxControl, nRow, nCol, pCancel);
}

void LTCustomMenuEditorDlg::OnBeforeCollapseBuiltInControl(Control flxControl, long nRow, short nState, BOOL* pCancel)
{
	m_builtInGridCtrl.OnBeforeCollapse(flxControl, nRow, nState, pCancel);
}

bool LTCustomMenuEditorDlg::LoadSettings()
{
	//int nLevel = LoadSetting("CurrentSelOMC", 0, STR_DLG_NAME_E);
	//if(nLevel < 0 || nLevel >= m_omcFileMngr.GetNumOMCFiles())
	//{
		//nLevel = m_omcFileMngr.GetNumOMCFiles()>0 ? 0 : -1;
	//}
	//m_comboOMC.SetCurSel(nLevel);

	m_MESplitter.LoadBranchSetting(STR_DLG_NAME_E);
	
	int nSelWndType = LoadSetting("CurrentSelWndType", 0, STR_DLG_NAME_E);
	m_comboWndType.SetCurSel(nSelWndType);

	// selected tab
	int nSelTab = LoadSetting("CurrentSelTab", 0, STR_DLG_NAME_E);
	m_tab.SetCurSel(nSelTab);

	return false;
}

bool LTCustomMenuEditorDlg::SaveSettings()
{
	//SaveSetting("CurrentSelOMC", m_comboOMC.GetCurSel(), STR_DLG_NAME_E);
	m_MESplitter.SaveBranchSetting(STR_DLG_NAME_E);
	SaveSetting("CurrentSelWndType", m_comboWndType.GetCurSel(), STR_DLG_NAME_E);

	// selected tab
	SaveSetting("CurrentSelTab", m_tab.GetCurSel(), STR_DLG_NAME_E);
	return false;
}

BOOL LTCustomMenuEditorDlg::OnDestroy()
{
	SaveSettings();
	m_builtInGridCtrl.OnDestroy();
	
	ResizeDialog::OnDestroy();
	return TRUE;
}

BOOL LTCustomMenuEditorDlg::OnHelp(int &nHelpID, int nIdCtrlFocus)
{
	int nSelTab = m_tab.GetCurSel();
	if(nSelTab == HIDE_BUILT_IN_MENUS_TAB)
		nHelpID = IDD_CUSTOM_MENU_HIDE_BUILT_IN_MENU;
	else
		nHelpID = IDD_CUSTOM_MENU_ADD_CUSTOM_MENU;
	return TRUE;
}

BOOL LTCustomMenuEditorDlg::OnOK()
{
	return FALSE;	// NOT TO CLOSE THE DIALOG
}

//void LTCustomMenuEditorDlg::UpdateOMCListCombo()
//{
	//vector<string> vsFileNames;
	//m_omcFileMngr.GetOMCFileNames(vsFileNames);
//
	//m_comboOMC.ResetContent();
	//if(vsFileNames.GetSize())
	//{
		//for( int nOMCLevel = 0; nOMCLevel < vsFileNames.GetSize(); nOMCLevel++ )
		//{
			//m_comboOMC.AddString(vsFileNames[nOMCLevel]);
		//}
	//}
	//else
	//{
		//m_comboOMC.AddString(_L("<Empty>"));
	//}
//}
void LTCustomMenuEditorDlg::UpdateOMCFileList()
{
	vector<string> vsFileNames, vsPathTypes;
	m_omcFileMngr.GetOMCFileNames(vsFileNames);
	m_omcFileMngr.GetOMCPathTypes(vsPathTypes);
	m_pOMCEditingMenu->UpdateFileList(vsFileNames, vsPathTypes, m_omcFileMngr.GetEditingLevel());
}

void	LTCustomMenuEditorDlg::SetDirty(bool bDirty, bool bUpdateWndText)
{
	if(m_bDirty != bDirty)
	{
		m_bDirty = bDirty;
		if(bUpdateWndText)
		{
			uint wParam, lParam;
			OnUpdateWndText(wParam, lParam);
		}
	}
}

BOOL	LTCustomMenuEditorDlg::CheckSaveOMCFile(BOOL bCheckDirty, BOOL bSaveAs, BOOL bAskBeforeSaving, BOOL* pCancel)
{
	if(pCancel)
		*pCancel = false;
	if(bCheckDirty)
	{
		bool bDirty = m_bDirty || m_MESplitter.IsDirty() || m_builtInGridCtrl.IsDirty();
		if(!bDirty)
			return true;
	}

	if(bAskBeforeSaving)
	{
		string strMsg, strFileName;
		if(!m_omcFileMngr.GetEditingFileName(strFileName))
			strFileName = STR_OMC_UNTITLED;
		strMsg.Format(_L("Save changes to file: %s?"), strFileName);
		int nRet = warning_msg_box(strMsg, true, 'W', MB_YESNOCANCEL);
		
		if(IDCANCEL == nRet)
		{
			if(pCancel)
				*pCancel = true;
			return FALSE;
		}
		else if(IDNO == nRet)
		{
			m_MESplitter.SetDirty(false, false);
			m_builtInGridCtrl.SetDirty(false, false);
			SetDirty(false, false);
			return false;
		}
	}
	string strFullPathFile;
	if(bSaveAs || m_omcFileMngr.IsNewFile() || !m_omcFileMngr.Editable())
	{
		string strFileName;
		if(!m_omcFileMngr.GetEditingFileName(strFileName))
			strFileName = STR_OMC_UNTITLED;

		string strDlgName = _L("Save As");

		strFullPathFile = GetSaveAsBox( "*.omc OMC Files", GetAppPath(FALSE), strFileName, strDlgName);
		if(strFullPathFile.IsEmpty())
		{
			if(pCancel)
				*pCancel = true;
			return false;
		}
		else	// check if exe or group path
		{
			string strPath = GetFilePath(strFullPathFile);
			string strSys = okutil_get_origin_path(ORIGIN_PATH_SYSTEM);
			string strGrp = okutil_get_origin_path(ORIGIN_PATH_GROUP);
			string strMsg;
			bool bCancel = false;
			if(strPath.CompareNoCase(strSys) == 0)
			{
				bCancel = true;
				strMsg = STR_MSG_SAVE_IN_SYSTEM_FOLGER;
			}
			if(strPath.CompareNoCase(strGrp) == 0)
			{
				bCancel = true;
				strMsg = STR_MSG_SAVE_IN_GROUP_FOLGER;
			}
			if(bCancel)
			{
				warning_msg_box(strMsg, true, 'W', MB_OK);
				if(pCancel)
					*pCancel = true;
				return false;
			}
			bSaveAs = true;
		}
	}

	if(m_MESplitter.IsDirty())
	{
		Tree trConfig;
		m_MESplitter.GetCustomMenuConfig(trConfig);
		m_omcFileMngr.SetEditingTreeNode(trConfig);
		
		m_MESplitter.SetDirty(false, false);
	}
	if(m_builtInGridCtrl.IsDirty())
	{
		vector<string> vsHideList;
		vector<int> vnWndTypes;
		m_builtInGridCtrl.GetSettings(vsHideList, vnWndTypes);
		m_omcFileMngr.SetEditingHideList(vsHideList, vnWndTypes);
		
		m_builtInGridCtrl.SetDirty(false, false);
	}
	if(m_bDirty)
	{
		BOOL bCheck = m_btnEnable.Check;
		m_omcFileMngr.SetEnable(bCheck);
		///---Sim 01-22-2010 QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
		int nPos = m_cmbPosition.GetCurSel();
		m_omcFileMngr.SetPosition(nPos);
		///---END QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
		SetDirty(false, false);
	}

	bool bRet = false;
	if(bSaveAs || m_omcFileMngr.IsNewFile())
	{
		ASSERT(!strFullPathFile.IsEmpty());
		bRet = m_omcFileMngr.SaveEditingOMCAs(strFullPathFile);
	}
	else
	{
		bRet = m_omcFileMngr.SaveEditingOMC();
	}
	return bRet;
}

BOOL	LTCustomMenuEditorDlg::OnCheckEnable(Control ctrl)
{
	SetDirty();
	return false;
}
///---Sim 01-22-2010 QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
BOOL	LTCustomMenuEditorDlg::OnPositionChange(Control ctrl)
{
	SetDirty();
	return false;
}
///---END QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU

//BOOL	LTCustomMenuEditorDlg::OnEditingOMCChange(Control ctrl)
//{
	//int nLevel = m_comboOMC.GetCurSel();
	//if(nLevel>= 0 && (m_omcFileMngr.GetEditingLevel() == nLevel || m_omcFileMngr.GetNumOMCFiles()==0))	// select the same omc or the no omc files shown
		//return false;
	//BOOL bCancel = false;
	//CheckSaveOMCFile(true, false, true, &bCancel);
	//if(bCancel)
	//{
		//m_comboOMC.SetCurSel(m_omcFileMngr.GetEditingLevel());
		//return false;
	//}
	//UpdateOMCListCombo();
	//m_comboOMC.SetCurSel(nLevel);	// should resel after updating the combo
//
	//m_omcFileMngr.SetEditingLevel(nLevel);
	//TreeNode trConfig = m_omcFileMngr.GetEditingTreeNode();
	//m_MESplitter.SetCustomMenuConfig(trConfig);
	//
	//vector<string> vsHideList;
	//vector<int> vnWndTypes;
	//m_omcFileMngr.GetEditingHideList(vsHideList, vnWndTypes);
	//m_builtInGridCtrl.SetSettings(vsHideList, vnWndTypes);
	//OnWndTypeChange(m_comboWndType);
//
	//// update the window text
	//uint wParam, lParam;
	//OnUpdateWndText(wParam, lParam);
	//return true;
//}
BOOL	LTCustomMenuEditorDlg::OnEditingOMCChange(int nLevel)
{
	if(nLevel>= 0 && (m_omcFileMngr.GetEditingLevel() == nLevel || m_omcFileMngr.GetNumOMCFiles()==0))	// select the same omc or the no omc files shown
		return false;
	BOOL bCancel = false;
	CheckSaveOMCFile(true, false, true, &bCancel);
	if(bCancel)
		return false;

	m_pOMCEditingMenu->SetCheckedLevel(nLevel);

	m_omcFileMngr.SetEditingLevel(nLevel);
	TreeNode trConfig = m_omcFileMngr.GetEditingTreeNode();
	m_MESplitter.SetCustomMenuConfig(trConfig);
	
	vector<string> vsHideList;
	vector<int> vnWndTypes;
	m_omcFileMngr.GetEditingHideList(vsHideList, vnWndTypes);
	m_builtInGridCtrl.SetSettings(vsHideList, vnWndTypes);
	OnWndTypeChange(m_comboWndType);
	
	m_btnEnable.Check = m_omcFileMngr.Enable();
	/// ML 2/15/2010 QA70-15113 81SR1_OMC_FILES_SHOULD_ALWAYS_APPEND_BUT_NEW_SHOULD_INSERT_BEFORE_WINDOW
	/////---Sim 01-22-2010 QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	//m_cmbPosition.SetCurSel(m_omcFileMngr.GetPosition());
	/////---END QA81-13423 SUPPORT_INSERT_CUSTOM_MAIN_MENU
	BOOL		bDefault;
	int			nPos = m_omcFileMngr.GetPosition(&bDefault);
	if (nLevel < 0 && bDefault)		// if new
		nPos = OMC_POS_INSERT_BEFORE_WINDOW;		// new .omcs by default Insert
	
	m_cmbPosition.SetCurSel(nPos);
	/// end SR1_OMC_FILES_SHOULD_ALWAYS_APPEND_BUT_NEW_SHOULD_INSERT_BEFORE_WINDOW

	m_pOMCEditingMenu->EnableSave(m_omcFileMngr.Editable());
	m_pOMCEditingMenu->EnableDelete(m_omcFileMngr.Editable());

	// update the window text
	uint wParam, lParam;
	OnUpdateWndText(wParam, lParam);
	return true;
}

BOOL LTCustomMenuEditorDlg::OnClose()
{
	BOOL	bCancel;
	CheckSaveOMCFile(true, false, true, &bCancel);
	if(!bCancel)
	{
		// update menus
		//int nLevel = m_omcFileMngr.FindDefaultLevel();
		//if(nLevel < 0)
			//nLevel = 1;
		//else
			//nLevel += 1;
		int nLevel = _find_current_omc_level();

		string strScript;
		strScript.Format("menu.level=%d", nLevel);
		LT_execute(strScript);
	}

	return !bCancel;
}

BOOL LTCustomMenuEditorDlg::OnNew()
{
	OnEditingOMCChange(-1);
	UpdateOMCFileList();
	return TRUE;
}

BOOL LTCustomMenuEditorDlg::OnOpenFile()
{
	string strFileName = GetOpenBox("*.omc OMC Files", NULL, NULL, _L("Open File..."));
	if(strFileName.IsEmpty())
		return FALSE;
	BOOL	bCancel;
	CheckSaveOMCFile(true, false, true, &bCancel);
	if(bCancel)
		return FALSE;

	if(m_omcFileMngr.OpenFile(strFileName))
	{
		UpdateOMCFileList();
		int nLevel = m_omcFileMngr.GetEditingLevel();
		m_omcFileMngr.SetEditingLevel(-1);
		OnEditingOMCChange(nLevel);
	}
	return false;
}

BOOL LTCustomMenuEditorDlg::OnDelete()
{
	m_MESplitter.SetDirty(false, false);
	m_builtInGridCtrl.SetDirty(false, false);
	SetDirty(false, false);

	int nLevel = m_omcFileMngr.GetEditingLevel();
	m_omcFileMngr.DeleteEditingOMC();		// the editing level will be -1
	UpdateOMCFileList();

	if(nLevel < 0)										// select the first one, if no omc files, select -1
		nLevel = m_omcFileMngr.GetNumOMCFiles() > 0 ? 0 : -1;
	else if(nLevel >= m_omcFileMngr.GetNumOMCFiles())	// select the last one
		nLevel = m_omcFileMngr.GetNumOMCFiles()-1;

	OnEditingOMCChange(nLevel);

	return TRUE;
}

BOOL LTCustomMenuEditorDlg::OnSave()
{
	BOOL bCheckDirty = !m_omcFileMngr.IsNewFile();	// no need to check dirty if it's a new file, will open Save As... Dialog
	BOOL bCancel;
	CheckSaveOMCFile(bCheckDirty, false, false, &bCancel);
	if(!bCancel)
	{
		UpdateOMCFileList();
		m_pOMCEditingMenu->SetCheckedLevel(m_omcFileMngr.GetEditingLevel());
		m_pOMCEditingMenu->EnableSave(m_omcFileMngr.Editable());
		m_pOMCEditingMenu->EnableDelete(m_omcFileMngr.Editable());

		uint wParam, lParam;
		OnUpdateWndText(wParam, lParam);
	}

	return TRUE;
}

BOOL LTCustomMenuEditorDlg::OnSaveAs()
{
	BOOL bCancel;
	CheckSaveOMCFile(false, true, false, &bCancel);
	if(!bCancel)
	{
		UpdateOMCFileList();
		m_pOMCEditingMenu->SetCheckedLevel(m_omcFileMngr.GetEditingLevel());
		m_pOMCEditingMenu->EnableSave(m_omcFileMngr.Editable());
		m_pOMCEditingMenu->EnableDelete(m_omcFileMngr.Editable());

		uint wParam, lParam;
		OnUpdateWndText(wParam, lParam);
	}

	return TRUE;
}
BOOL LTCustomMenuEditorDlg::OnExit()
{
	if(OnClose())
		PostMessage( WM_CLOSE );
	return true;
}

BOOL LTCustomMenuEditorDlg::OnSelOMCFile(int nID)
{
	int nLevel = m_pOMCEditingMenu->GetLevelFromID(nID);
	if(nLevel < 0)
		return false;
	return OnEditingOMCChange(nLevel);
}

BOOL	LTCustomMenuEditorDlg::OnUpdateWndText(uint wParam, uint lParam)
{
	string strWndText = STR_DLG_NAME;
	string strFileName, strPathType;
	if( ! m_omcFileMngr.GetEditingFileName(strFileName) )
		strFileName = STR_OMC_UNTITLED;
	m_omcFileMngr.GetEditingFilePathType(strPathType);
	if(!strFileName.IsEmpty())
	{
		strWndText += " - " + strFileName;// + (bDirty ? "*" : "") + ")";
		if(!strPathType.IsEmpty())
			strWndText += "(" + strPathType + ")";
		if(	m_bDirty || m_MESplitter.IsDirty() || m_builtInGridCtrl.IsDirty() )
			strWndText += "*";
	}
	GetWindow().Text = strWndText;

	return true;
}

// this should be the same with that show in Format: Menu
static void _construct_menu_levels(vector<string>& vsLevel, vector<string>& vsFiles)
{
	vsLevel.SetSize(0);
	vsFiles.SetSize(0);

	vector<int> vnPathTypes = {ORIGIN_PATH_USER, ORIGIN_PATH_GROUP, ORIGIN_PATH_SYSTEM};
	for(int ii=0; ii<vnPathTypes.GetSize(); ii++)
	{
		string strPath = okutil_get_origin_path(vnPathTypes[ii]);
		if(strPath.IsEmpty())
			continue;
		vector<string> vsTmpFiles;
		string strOmcIni = strPath + MENU_CUSTOMIZATION_CONFIGURATION_FILE;
		if(strOmcIni.IsFile())
		{
			INIFile iniOmc(strOmcIni);
			int nNumOMCMenuLevels = iniOmc.ReadInt(STR_SECTION_CONFIG, STR_NUM_OMC_LEVELS, 0);
			for(int nLevel = 1; nLevel <= nNumOMCMenuLevels; nLevel++)
			{
				string strFile = iniOmc.ReadString(STR_SECTION_CONFIG, STR_OMC_FILE_NAME + nLevel);
				strFile.TrimLeft();
				strFile.TrimRight();
				if(strFile.IsEmpty())
					continue;
				
				strFile += "." + MENU_CUSTOMIZATION_FILE_EXT;
				vsTmpFiles.Add(strFile);
			}
		}
		else
		{
			FindFiles(vsTmpFiles, strPath, MENU_CUSTOMIZATION_FILE_EXT);
			vsTmpFiles.Sort();			// sort by names, case insensitive
		}
		for(int nFile = 0; nFile < vsTmpFiles.GetSize(); nFile++)
		{
			string strName = GetFileName(vsTmpFiles[nFile], true);
			if(vsLevel.Find(strName) >= 0)
				continue;

			Tree tr;
			BOOL bEnable;
			if(!tr.Load(strPath+vsTmpFiles[nFile]) || (tr.GetAttribute(STR_FILE_ENABLE_ATTRIB, bEnable) && !bEnable) )
				continue;
			vsLevel.Add(strName);
			vsFiles.Add(strPath+vsTmpFiles[nFile]);
		}
	}
}

static int _find_current_omc_level(string& strDefLevelFullPathFile = NULL)
{
	if(strDefLevelFullPathFile)
		strDefLevelFullPathFile.Empty();

	vector<string> vsMenuLevels, vsFullPathFiles;
	_construct_menu_levels(vsMenuLevels, vsFullPathFiles);
	ASSERT( vsMenuLevels.GetSize() == vsFullPathFiles.GetSize() );

	vector<string> vsConfigFiles = {STR_ORIGIN_INI, MENU_CUSTOMIZATION_CONFIGURATION_FILE};
	vector<int> vnPathTypes = {ORIGIN_PATH_USER, ORIGIN_PATH_GROUP, ORIGIN_PATH_SYSTEM};
	for(int nCnf = 0; nCnf < vsConfigFiles.GetSize(); nCnf++)
	{
		for(int nPath=0; nPath < vnPathTypes.GetSize(); nPath++)
		{
			string strPath = okutil_get_origin_path(vnPathTypes[nPath]);
			if(strPath.IsEmpty())
				continue;
			INIFile iniFile(strPath + vsConfigFiles[nCnf]);
			string strDef = iniFile.ReadString(STR_SECTION_OPTIONS, STR_OMC_MENU_LEVEL);
			strDef.TrimLeft();
			strDef.TrimRight();
			if(strDef.IsEmpty())
				continue;		// default
			int nLevel = vsMenuLevels.Find(strDef);
			if(nLevel >= 0)
			{
				if(strDefLevelFullPathFile)
					strDefLevelFullPathFile = vsFullPathFiles[nLevel];
				return nLevel+1;		// 1 offset
			}
		}
	}
	if( strDefLevelFullPathFile && vsFullPathFiles.GetSize() > 0 )
		strDefLevelFullPathFile = vsFullPathFiles[0];

	return 1;
}

static bool _check_menu_level_by_omc()
{
	INIFileEx iniFile(STR_ORIGIN_INI);
	bool bMenuLevelByOMC = 0 != iniFile.ReadInt(STR_SECTION_CONFIG, STR_MENU_LEVEL_BY_OMC, 0);
	if(bMenuLevelByOMC)
		return true;
	
	if(Project.MenuModifiedFromLT())
	{
		if(IDYES != warning_msg_box(STR_WARNING_SWITCH_MENU_LEVEL_BY_OMC, true, 'W', MB_YESNO))
			return false;
	}

	// update ini and menus
	iniFile.WriteInt(STR_SECTION_CONFIG, STR_MENU_LEVEL_BY_OMC, 1);

	int nLevel = _find_current_omc_level();
	string strScript;
	strScript.Format("menu.level=%d", nLevel);
	LT_execute(strScript);

	return true;
}

void ShowLTCustomMenuEditorDlg()
{
	if(!_check_menu_level_by_omc())
		return;

	LTCustomMenuEditorDlg editorDlg;
	int nRet = editorDlg.DoModalEx( GetWindow() );
}


class CustomContextMenu : public Menu
{
public:
	CustomContextMenu(const vector<int>& vnCmds, const vector<string>& vsText, const vector<bool>& vbEnables)
	{
		int nCmdSize = vnCmds.GetSize() < vsText.GetSize() ? vnCmds.GetSize() : vsText.GetSize();
		if(nCmdSize > vbEnables.GetSize())
			nCmdSize = vbEnables.GetSize();
		for(int ii=0; ii<nCmdSize; ii++)
		{
			int nFlags;
			if(BUILT_IN_CONTEXT_MENU_INVALUD == vnCmds[ii])
				nFlags = MF_SEPARATOR;
			else
			{
				nFlags = MF_STRING;
				if(!vbEnables[ii])
					nFlags |= MF_GRAYED | MF_DISABLED;
			}
			Add(vsText[ii], OnMenuItem, nFlags, vnCmds[ii]);
		}
	}

	void OnMenuItem(UINT nPos)
	{
	}
};

