/*------------------------------------------------------------------------------*
 * File Name: Page_Utils.cpp													*
 * Creation: July 25, 2003														*
 * Purpose: Define page utility functions										*
 * Copyright (c) OriginLab Corp. 2003											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	RVD 9/3/2003 QA70-5078 v7.0682 PLOT_RANGE_APPLY								*
 *	ML 12/9/2003 QA70-5657 UTILITY_ORIGINC_FUNCTIONS_FOR_PLOT_CREATION			*
 *	AW 01/30/04 QA70-5657 v7.0811 TEMP_FIXING_MAKE_PLOTS_TREE					*	
 *	Frank 05/07/04 QA70-6331 v8.0867 GET_THUMBNAIL_FROM_PAGE					*
 *	Frank 05/08/04 QA70-6331 v8.0869 PAGE_IMAGE_ADD_INFO						*
 *  SY 08/24/2004 QA70-6780 v8.0116 LLOC_FOR_IMPORT								*
 *  SY 09/01/2004 QA70-6472 v8.0128 IMPORT_INFO_STORAGE_CLEANUP					*
 *	CPY 10/1/04 ADD_DATE_DISPLAY_INFO_FOR_WKBOOK_ORGANIZER						*
 *	CPY 10/11/04 MOVE_GRAPH_GET_INFO_TREE_TO_PAGE_UTILS							*
 *  SY 10/13/2004 v8.0147 IMPORT_WIZARD_CLEANUP									*
 *  SY 12/15/2004 QA70-7258 v8.0175 IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID	*
 * EJP 2005-01-21 v8.0185 QA70-7210 PCLAMP_IMPORT_DIALOG						*
 *	ML 3/3/2005 XFUNCTION_OUTPUT_VARIABLES_DATA_ASSOC							*
 *	ML 3/21/2005 OPERATIONTREE_UPDATING_BACK_AND_FORTH							*
 *  Iris 3/23/05 QA70-7493 BUILD_XVAR_DATA_BRANCH								*
 *  Iris 3/23/05 QA70-7478 MAKE_EXISTING_WORK_FOR_VAR_DATA						*
 *  Frank 4/12/05 MAKE_EXISTING_WORK_FOR_VAR_DATA_IN_XYRANGE					*
 *	ML 4/13/2005 ALLOW_EXCLAMATION_AFTER_SHEETNAME								*
 *	ML 4/15/2005 NO_NEED_FOR_CREATION_IF_NOT_OUPUT								*
 *	CPY 4/16/05 ACTIVE_BOOK_SHEET_AS_DEFAULT_FOR_XF								*
 *	Frank 5/27/05	PAGE_LIST_SUPPORT_SUBFOLDER_AND_NOTE_PAGE					*
 *	CPY 6/27/05 XF_LT_ACTIVE_NEW_FIX											*
 *	Frank 6/28/05 NEW_WINDOW_FOLDER_IN_SPECIAL									*
 *  Iris 7/7/05 GET_SOURCE_PAGE_NAME_FOR_MATRIX_DATA							*
 *  Iris 7/26/05 NO_NEED_GET_MATRIX_NAME										*
 *	 YuI 08/05/05 BOOK_MODE_SHOULD_RETURN_NEW_IF_UNABLE_TO_RESOLVE				*
 *	Sandy 9/18/05 CENTRALIZED_IMAGE_XF_COMMON_CODES								*
 *	CPY 10/5/05 QA70-8154 XF_AUTO_CREATE_DATA									*
 *	EJP 2005-11-02 v8.0328 QA70-8186 LEAD_BITMAP_GR_OBJ							*
 *	Frank 11/14/05 ADD_NEW_LAYER_ON_PAGE										*
 *	Kevin 11/14/05 SUPPORT_ADD_STRING_ARRAY_IN_ROW								*
 *  Iris 11/18/05 NO_Y_FOR_MATRIX_DATA											*
 *  Iris 12/12/05 SUPPORT_ADDING_MORE_ONE_ROW_COL_HEADER						*
 *	ML 1/13/2006 XVARIABLEBASE_TO_VC											*
 *	ML 2/17/2006 INTERACTIVE_CONTROL_MENUS										*
 *  Jim 2/22/06 ADD_RESIDUAL_LAG_PLOT_TO_RESIDUALS_PLOTS_BRANCH					*
 *	EJP 2006-03-14 v8.0375 SUPPORT_ROI_IN_IMAGE_PROCESSING						*
 *	EJP 2006-04-04 v8.0386 QA70-8187 GET_DATA_VALUES_DIRECT_FROM_IMAGE			*
 *	Deanna 4/17/2006 SET_SHOW_AXIS												*
 *	EJP 2006-05-22 v8.0414 BASIC_OPERATIONS_FOR_MATOBJ							*
 *	Jasmine 06/02/06 MOVE_TO_PAGE_UTILS											*
 *	Cheney 06/22/06 ADD_FUNCTIONS_ABOUT_CHECK_COLS_IN_RANGE_WITH_SAME_DATATYPE	*
 *	Cheney 06/23/06 SET_COLS_IN_RANGE_TO_SAME_DATATYPE							*
 *	Cheney 06/23/06 CHECK_EACH_SUBRANGE_SAME_ROW_NUM							*
 *	Jasmine 07/12/06 GET_FOLDER_PAGES_NAME										*
 *	Jasmine 07/11/06 MODIFICATION_ABOUT_MERGE_GRAPH								*
 *	CPY 7/14/06 LEGEND_SET_SHOW_CENTRAL_FUNC									*
 *	Jasmine 07/31/06 CHECK_INVALID_GRAPH_NAME									*
 *	Jasmine 08/16/06 ADD_SOME_TEMPLATE_FUNC										*
 *	Jasmine 08/24/06 CONSTRUCT_TEMP_ORG_TREE									*
 *	Sim 08-25-2006 COMMON_FUNC_WKS_EMPTY										*
 *	Arvin 9/25/06 CHECK_HAS_IMAGE												*
 *	Jasmine 10/09/06 SET_STFORMAT_DEFAULT										*
 *	Jasmine 10/12/06 ADD_WORKBOOK_TEMPLATE_INTO_TEMPLATE_INI					*
 *	Joseph  10/12/06 STRING_EMPTY_CORRECT_WHEN_MODE_CHOOSE						*
 *	Jasmine 10/17/06 BUILT_IN_TEMPLATE_INI_SYSTEM_FOLDER						*
 *	Jasmine 10/24/06 REARRANGE_TREE_STRUCTURE									*
 *	Cheney 2006-10-24 FIX_BUG_OF_MULTI_INDEP_AND_DEP_WHEN_PREVIEW				*
 *	CPY TD 11/2/06 CENTRALIZED_CODE_FOR_GET_PICTURE_TO_VC						*
 *	Jasmine 11/03/06 SHOULD_SHOW_SHORT_NAME										*
 *  SY 2006-11-06 v8.0505 ADD_SCALER_OBJECT										*
 *	AW 11/07/06 MORE_WORK_ON_SHOW_TIME_COL										*
 *	Jasmine 11/10/06 QA70-9112 GET_EMBEDDED_GRAPHS								*
 *	Jasmine 11/17/06 SHOW_LNAME_AND_CELL										*
 *	Jasmine 11/17/06 GET_ALL_EMBEDDED_GRAPHS_IN_FOLDER							*
 *	Jasmine 11/22/06 REMOVE_TEMPLATE_NODE_IF_FILE_INVALID						*
 *	Jasmine 12/06/06 KEEP_EACH_LAYER_UNIT_AFTER_MERGE							*
 *	Jasmine 12/07/06 GET_SET_USER_INFO											*
 *	Hong 12/07//06 FIX_SPARK_LINE_DISAPPEAR										*
 *  Iris 12/18/2006 v8.0527 COMBO_TO_SEL_ALL_PAGES_IN_FOLDER_FOR_EXPORT_PAGE	*
 *	CPY 12/18/06 COL_VARS_USING_EXTENDED_LABELS									*
 *	Max 12/21/06 WORKSHEET_COPY													*
 *	Jasmine 01/08/07 MODIFICATION_GET_SET_USER_INFO								*
 *	Jasmine 01/11/07 OPEN_REPORT_TREE_BROWSER									*
 *	Jasmine 01/18/07 ADD_REPORT_TREE_FILTER_STRING								*
 *	Jasmine 01/18/07 ADD_COL_LEVEL												*
 *	Jasmine 01/19/07 ADD_OPTION_TO_ALLOW_EMPTY_PARAM_VALUE						*
 *	Jasmine 02/06/07 SHOW_IMPORT_FILE_AND_USER_TREE								*
 *	Jasmine 02/24/07 BY_DEFAULT_NOT_RESIZE										*
 *	CPY 3/7/2007 SYSTEM_FILE_CANNOT_COMPILE_IN_PAGE_UTILS						*
 *	Jasmine 03/08/07 USE_NEW_FUNC_UNITSCONVERT									*
 *	Jasmine 03/15/07 ADD_UNDO_BUTTON											*
 *	Sim 03-15-2007 QA80-9325-P4 REFIX_NOT_SHOW_LABEL							*
 *	Sim 03-15-2007 FIX_MOSTLY_ACCORDING_ORDER_OF_VECTOR_OF_LABEL				*
 *	Jasmine 03/21/07 ONLY_SKIP_LINK_LAYER_WITH_M_LINK_UNIT						*
 *	Jasmine 03/22/07 MODIFICATION_ON_GET_PROJECT_TREE							*
 *	Jasmine 03/24/07 GET_GRAPH_IN_WKBOOK										*
 *	Jasmine 04/06/07 KEEP_SAME_RESOLUTION_AND_SHOULD_NOT_CHANGE_TEMPLATE		*
 *	Jake 04/06/07 ADD_CHECKBOX_FOR_SHOW_LONG_AND_SHORT_NAME						*
 *	Cheney 2007-4-13 FIX_BUG_OF_CUSTOM_TABLE_DISAPPEAR_WHEN_CONCATENATE			*
 *	Sim 04-25-2007 QA80-9325-P7 FIX_MISS_DATA									*
 *	Cheney 2007-4-30 ADD_TEMLATE_FOR_PREVIEW_WHEN_MULTI_LAYER					*	
 *	Jasmine 05/11/07 ARRANGE_FROM_BOTTOM_TO_TOP_FOR_ONE_COL						*
 *	Jasmine 05/16/07 QA80-9182 ARRANGE_SELECTION_ONLY							*
 *	Jasmine 05/17/07 MOVE_OUT_PORTRAIT_OPTION									*
 *	Sim 05-21-2007 SET_XF_BAR_NAME_ONLY_WITHOUT_SHOW_DIALOG						*
 *	Sim 05-25-2007 IMPROVE_GET_AND_SET_XF_BAR_NAME								*
 *	Folger 05/29/07 ADD_BOOL_ENABLE_EMBED_IN_PAGE_PREVIEW_LIST_DLG				*
 *	Folger 06/05/07 COMMENT_STR_EXCLUDE_PAGE									*
 *	Folger 06/06/07 FIX_BUGS_IN_SPECIFIED_WKS									*
 *	Folger 06/20/07 SHEET_BROWSER_BUTTON_INGETN									*
 *	Jasmine 06/25/07 UPDATE_ORGANIZER											*
 *	Sim 06-25-2007 UPDATE_ORGANIZER												*
 *	Folger 06/26/07 CHANGE_UPDATE_TO_NOTIFY										*
 *	Folger 07/18/07 MAKE_GET_PROJECT_TREE_SHOW_TWO_PAGE_TYPES					*
 *	Folger 07/18/07 CLEAN_UP_CONTROL_BITS_INTO_DWORD_FOR_GRAPH_BROWSER			*
 *	Folger 07/19/07 CONTROL_BROWSE_PAGE_TYPE									*
 *  Iris 07/23/2007 SHOULD_FIND_LEGEND_BY_L										*
 *	Hong 07/24/07 v8.0666 SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND						*
 *	Jasmine 07/30/07 MAX_UPDATE_ALL_BUILT_IN_TEMPLATE_IN_TEMPLATE_INI			*
 *	Jasmine 07/30/07 #8854 SHOW_TEMPLATE_UNDER_GROUP_FOLDER						*
 *	Jasmine 07/31/07 USE_FILE_TYPE_STRING_FOR_BRANCH_LABEL						*
 *	Hong QA80-10064 v8.0672 LEGEND_ADD_ORDER_OPTION_WHEN_RECONSTRUCT			*
 *	Folger 08/06/07 CHECK_WHETHER_DATARANGE_HAS_PLOTTED_IN_SPECIFIC_GRAPH_LAYER	*
 *	Jasmine 08/07/07 APPEND_NEW_AFTER_DELETE_OLD								*
 *	Folger 08/08/07 AUTO_ENUMERATION_WHEN_NAME_ALREADY_EXIST					*
 *	Hong 08/08/07 QA80-10064 FIX_LEGEND_COMBINE_FAIL_KEEP_ORIGIN_ORDER			*
 *	Jasmine 08/08/07 QA80-10193 APPLY_SYSTEM_THEME								*
 *	Folger 08/13/07 CHECK_IF_DATAPLOT_IN_DATARANGE								*
 *	Folger 08/14/07 SUPPORT_GET_DATASHEET_DATAOBJECT_FROM_DATASET				*
 *	Jasmine 08/15/07 QA80-10155 NO_MODIFICATION_TO_GROUP_FOLDER_FILE			*
 *	Arvin 08/15/07 QA70-10212-P3 ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
 *	Hong 08/17/07 v8.0684 MORE_RELIABLE_CODE									*
 *	Hong 08/21/07 v8.0685 SKIP_ERR_BAR_WHEN_LEGEND_APPEND_PLOT					*
 *	Folger 08/22/07 LOAD_SYSTEM_USER_GROUP_TEMPLATE_SEPERATELY					*
 *	Folger 08/23/07 GET_GRAPH_TEMPLATE_PREVIEW_IMAGE_FILES_FULL_NAME			*
 *	Arvin 08/28/07 QA70-10073-P2 KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
 *	Folger 08/29/07 SAVE_PARTITIAL_GROUP_PATH_FOR_PUBLISH						*
 *	Folger 09/04/07 USE_FILE_LAST_MODIFIED_COMPARE_OF_VC_LEVEL					*
 *	Folger 09/24/07 CLEAN_UP_TEMPLATE_PUBLISH_FOR_CORRECT_LOGIC					*
 *	Folger 09/25/07 TREAT_SERVER_GROUP_AND_LOCAL_GROUP_SEPARATELY				*
 *	Folger 09/29/07 NEW_DISIGN_FOR_SAVING_TEMPLATE_XML							*
 *	CPY 10/11/07 QA70-10520 BAD_CODE_WITH_INFO_NOT_CENTRALIZED_LEAD_TO_FAILED_OK_ENABLED
 *	Sim 10-12-2007 QA70-10520 CENTRALIZE_MAKE_PAGE_SHORT_LONG_NAME				*
 *	CPY 10/15/07 QA70-10536 SR0_725_OUTPUT_LOCATION_NOT_WORKING_FOR_STATS		*
 *	Hong 10/16/07 v8.0726 FIX_OTHER_SEPARATE_NOT_WORK							*
 *	Hong 10/24/07 v8.0732 IMPROVE_ORGANIZER_REFRESH_BY_ONIDLE					*
 *	Hong 11/02/07 QA80-10622 IMPORT_EXCEL_SUPPORT_MULTILINES_COMMENTS			*
 *	Folger 11/05/07 IMPROVE_XF_DYNADLG_SHOW_CONTROL								*
 *	Folger 11/08/07 NO_NEED_LOCALIZE											*
 *	Folger 11/07/07 LOCALIZE_DELETE_SYSTEM_FILE_BRANCH							*
 *	Arvin 11/16/07 QA70-10676 UPDATE_MEANS_COMPARISION_PLOT_LEGENT_WITH_SIG_INFO*
 *	YuI 12/03/07 QA70-10766 JAPANESE_SAVE_TEMPLATE_AS_FAILS						*
 *	Folger 12/05/07 SHOULD_NOT_COPY_UNKNOWN_TEMPLATE_FILE_TO_UFF				*
 *	Sim 12-07-2007 SAVE_REDRAW_STATUS_WHEN_SET_REDRAW							*
 *	CPY 12/17/07 QA80-10805 WKS_CREATE_COPY_NOW_ALLOWS_DESTINATION				*
 *	Sim 12-18-2007 SPECIFY_ACTIVE_PAGE_AFTER_XF_WIZ_FINISH						*
 *	Folger 12/25/07 NO_NEED_TO_SPECIFY_SHOW_AND_REDRAW_STATUS					*
 *	Sim 01-02-2007 FIX_DETECT_EMPTY_BOOK										*
 *	Sim 01-17-2007 QA80-10952 MULTI_SHEET_RANGE									*
 *	Folger 01/22/08 INDICATE_WHETHER_XF_EVENT_HANDLE_NEEDED						*
 *	Folger 02/02/08 QA80-11046 REMOVE_MAIN_HEADER_LINE_IN_IMPORT_EXCEL			*
 *	Hong 02/04/08 QA80-10987 FIX_EXPWKS_FAIL_WITH_WITH_SPECIAL_SHEET_NAME		*
 *	Folger 02/14/08 QA80-10946 SUPPORT_GET_SUB_RANGE_PER_SHEET					*
 *	CPY 3/1/08 QA70-11205 OC_SET_LINES_PROBLEMS									*
 *	CPY 3/7/08 WAUTOSIZE_ALLOW_SEL_ROW_COL										*
 *	Sim 03-14-2008 ALLOW_DESTROY_ATTACHED_PAGE									*
 *	CPY 4/1/08 ARVIN_FOUND_SURFACE_FIT_PREVIEW_NOT_SHOWING_SRC_CONTOUR			*
 *	Hong 07/07/08 QA80-11811 FIX_PLOT_TYPE_FAIL_UPDATE_IN_PREVIEW_AND_FIT_RESULT_PLOT
 *	Folger 07/24/08 BETTER_XF_OPERATION_OUTPUT_COMMENTS							*
 *	RVD 7/30/2008 qa70-11914 SAMPLE_INTERVAL_UNDO								*
 *	Hong 08/08/08 v8.0918b FIX_HIDDEN_UDL_SHOWN_AFTER_ADD_NEW_ONE				*
 *	Hong 08/19/08 v8.0925 IMP_WIZ_VARIABLE_SHOULD_KEEP_AS_STRING_TYPE			*
 *	Kyle 08/29/08 ADD_UTIL_FUNCTION_FOR_XF_BEFORE_EXECUTE						*
 *	Folger 10/22/08 CHECK_AND_PLOT_MATRIX_OBJECT_IN_GRAPH						*
 *	Folger 10/23/08 CENTRALIZE_CODE_ABOUT_CHECKING_ORIGIN_OBJECT_HAS_PLOTTED_IN_GRAPH
 *	Sophy 10/24/2008 SUPPORT_MUILTI_INDEP_AND_DEP_PREVIEW_FOR_NLFIT_81			*
 *	Sim 10-27-2008 v8.961 QA80-12463-P1-P2 SHOW_REOPEN_REMINDER_MESSAGE_ONLY_WHEN_USER_FORCELY_CLOSE_IT
 *	Sophy 10/29/2008 FIX_FAIL_TO_GET_ALL_SHEETS_WHEN_BOOK_CONTAINS_ONLY_REPORT_SHEET
 *	Hong QA80-12551 v8.0967 FIX_FAIL_REPLOT_SCR_PLOT_WHEN_RESET_TO_FULL_RANGE	*
 *	Jasmine 11/24/08 v978d QA80-12652 DATASHEET_SCROLL_RANGE_INTO_VIEW			*
 *	Kyle 12/10/2008 ADD_SKIP_AUTO_UPDATE_OPTION_TO_FUNCTION_IS_XF_STARTUP		*
 *	Folger 12/11/08 QA80-12764 v8.0985 MODIFY_PEAKS_IN_PA_DURING_CHANGE_PARAMETER_MAKE_ORIGIN_LOCK
 *	Kyle 12/17/2008 NEED_CHECK_RESCALE_WHEN_RANGE_HAS_PLOTTED_IN_GRAPH			*
 *	Jasmine 12/17/08 v8.0987d QA80-12271 CP_MAKE_ADDLAYERS_KEEP_NAME			*
 *	CPY 12/23/08 SMOOTH_ETC_XF_WITH_PREVIEW_SHOULD_NOT_RESCALE_GRAPH_UPON_CHANGE*
 *	Folger 01/14/09 PAGE_SET_ACTIVE_LAYER_SUPPORT_ACTIVE_LAYER_ONLY				*
 *  Iris 01/15/2009 LINK_TO_FIRST_LAYER_WHEN_ARRANGE							*
 *	Jasmine 01/22/09 REARRANGE_OUTER_CHILD_LAYER								*
 *	Jasmine 01/23/09 PLOT_SETUP_NEED_IMPORTED_FILE_INFO_FROM_SHEET				*
 *	Kyle 01/23/2009 HIDE_SHOW_TICK_MARKS_SAME_AS_TICK_LABELS					*
 *	YuI 01/26/09 QA70-13023 MATRIX_FIT_IN_IMAGE_FORM_PROBLEMS					*
 *	Sophy 2/11/2009 QA80-13020-S1 v8.0976c HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST	*
 *	Jasmine 02/11/09 SHARE_ERR_MSG_WITH_MERGE_GRAPH								*
 *	Jasmine 02/12/09 MUST_CHECK_PAGE_TYPE_WHEN_CONSTRUCT_FROM_NAME				*
 *	Sophy 2/16/2009 QA80-13020-S1 v8.0976c HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
 *	Sophy 2/16/2009 v8.0979b QA80-13121 CUSTOM_LEGEND_NEED_SIMPLER_LINE_SUPPORT	*
 *  Iris 2/19/2009 ACCORDING_TO_COLORMAP_FORMAT_TREE_STRUCT_CHANGE				*
 *	Kyle 03/13/2009 QA80-13260-S1 ADD_OPTION_TO_COPY_FORMAT_FROM_SOURCE_LAYER	*
 *	YuI 03/13/09 QA70-13281 TAGGING_AVECURVES_RESULTS_TO_EXCLUDE_THEM_FROM_FUTURE_AVERAGING*
 *	Folger 03/16/09 QA80-13260-P1 MULTIPLE_SOURCE_XYRANGES_PLOTTING_IN_XF_PREVIEW_DIALOG
 *	Jasmine 03/19/09 QA80-13295-P1 ADD_VARIABLE_FOR_NEW_POS_AFTER_SCOLL			*	
 *	Kyle 03/20/2009 SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH	*
 *  Kyle 03/20/2009 ADD_OPTION_TO_SPECIFY_FORMAT_OF_DATA_PLOT					*
 *  Iris 3/20/2009 QA80-13295-P1B CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES			* 
 *	Hong 03/25/09 QA80-12551 RESET_PLOT_ROW_RANGE_IF_USER_UPDATE_INPUT_DATARANGE_WHEN_CHANGE_PARAMETER
 *	Kyle 03/26/2009 ADD_UTIL_FUNCTION_TO_GET_DESCRIPTION_FROM_XYRANGE			*
 *	Jasmine 03/31/09 SHOULD_NOT_SAVE_TEMPLATE_XML_IN_EXE_FOLDER					*
 *	Kyle 04/10/2009 QA80-13260-P3 COPY_RELATIVE_SETTING_WHILE_COPYING_SCALE_TYPE*
 *	Fisher 4/28/2009 PLOT_SETUP_FIXING_FOR_TENERY_CONTOUR						*
 *  Iris 5/04/2009 QA80-13552 SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
 *	CPY 5/5/09 QA70-8941 AUTOSIZE_CODE_CENTRALIZING								*
 *	Folger 05/18/09 QA80-13552-P1 GRAPH_BROWSER_FAILS_TO_FILTER_EMBEDED_3D_GRAPHS
 *  Iris 5/18/2009 QA80-13552-P2 IMPROVE_CHECK_3D_LAYER_FUNCITON				*
 *	Sim 05-20-2009 QA80-13612 MOVE_TEMPLATE_UTILS_FROM_OC_TO_VC					*
 *	Sophy 3/2/2009 ADD_SIMPLER_GRAPHLAYER_ARRANGE_METHOD_FOR_CUSTOMER_USE		*
 *	Folger 07/09/09 QA80-13904 MREPLACE_FAILS_TO_COPY_MATRIX_XY_RANGE_TO_OUTPUT	*
 *	Sim 07-13-2009 QA81-13923 FIX_EXP_GRAPH_FAILED_WHEN_LONG_NAME_CONTAIN_ONLY_ONE_DOUBLE_QUOTATION_MARK
 *	Sim 07-14-2009 QA81-13935-P1 SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER		*
 *  Iris 7/14/2009 QA80-13941 SUPPORT_MORE_OPTIONS_FOR_WREPLACE_AND_MREPLACE_XF	*
 *	Kyle 07/17/2009 QA80-13970 COLOR_LIST_SHOULD_BE_CONSISTENT_WITH__DEFAULT_TEMPLETE
 *	Kenny 07/27/2009 IMPROVE_AND_FIX_BUG_IN_GL_SMART_SHOW_OBJECT				*
 *	Sophy 7/30/2009 QA80-14050 CHECK_BOOK_AND_SHEET_NAME_ON_COMPARE_WORKSHEET_OBJS
 *	Folger 07/31/09 QA80-11867-P1 ANALYSIS_OUTPUT_COMMENTS_FAIL_FOR_LOOSE_DATASET_INPUT
 *	Jasmine 07/31/09 QA80-14022 ADD_FAVORITES_TO_AVAILABLE_DROPDOWN				*
 *	Folger 08/10/09 GENERAL_COLUMN_COPY_UTILS_NEEDED_IN_OC						*
 *	Kyle 08/14/2009 QA80-14136 FIX_COL_STATS_CAN_NOT_GIVE_RESULT_WHEN_SELECTING_WHOLE_ROWS
 *	CPY 8/14/09 QA70-14151-P1 SLIDE_SHOW_SORT_NAME_SHOULD_CHK_END_NUMBERS		*
 *	Kenny 08/25/2009 QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC				*
 *	Sophy 9/3/2009 QA80-14241 CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
 *	Jasmine 09/14/09 NO_TOP_RIGHT_LABEL_OR_TICK									*
 *	Kyle 10/10/2009 QA80-14437-P2 USE_CENTRALIZED_CODE_TO_COPY_COLUMN_DESIGNATION_AND_FORMAT
 *	Folger 10/28/09 INSERT_USER_VAR_RUNTIME_ERROR_WHEN_OPEN_IN_TEXTOBJ_WHICH_SAVED_IN_OGG
 *	YuI 10/30/09 QA70-14567 INPUT_NEW_RANGE_CHANGE_NOT_WORKING					*
 *	Folger 11/02/09 QA81-14522 SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS			*
 *	Jasmine 11/06/09 QA80-14559 JAPANESE_TEXT_IS_TOO_LONG_TO_SHOW				*
 *	Folger 11/12/09 QA81-14636 PLOT_STACK_AND_MYAXES_REARRANGE_DATAPLOTS_IN_MULTIPLE_LAYERS
 *	Jasmine 11/12/09 QA80-14619 USER_WANT_ARRANGE_STACK_HORIZONTAL				*
 *	Folger 11/17/09 QA81-11105 COPY_COL_SUPPORT_UDLS							*
 *	Hong 11/25/09 QA80-14559 IMPROVE_CODE_TO_CENTER_TEXT						*
 *	Folger 12/23/09 QA81-14881 COLCOPY_LOSE_NUMERIC_PRECISION					*
 *	Sim 12-28-2009 QA81-14895 SPEED_UP_81_IMP_WIZ_ASC							*
 *	Sim 12-29-2009 QA81-14148 REDO_AUTOSIZE_BETTER_HEIGHT_FOR_LABEL				*
 *	Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
 *	Sophy 1/25/2010 QA80-14087-S4 CNORMALIZE_CHANGE_SROUCE_PLOT_COLOR_WHEN_RECALCULATE		*
 *	Hong 01/28/10 QA80-14995-P2 FIX_OUTPUT_TO_WKS_FAIL_ALL_PUT_TO_ONE_SHEET_IF_NOT_VALID_SHORT_NAME
 *	Sophy 1/29/2010 QA80-14995-P2 CHECK_UPDATE_REPORT_WORKSHEET_NAME_FOR_ROI_TOOLS
 *	Sim 02-02-2010 QA81-15063 ADD_CUSTOM_PROPERTIES_INTO_WKS_INFO_TREE			*
 *  Iris 2/04/2010 FIX_QUICK_FIT_OUTPUT_PLOT_NOT_UPDATE_COLOR_IF_HAS_PLOTTED	*
 *	Folger 02/21/10 QA81-14995-P4 QUICKFIT_FINDXY_FAILS_TO_FIND_BOOK_BY_LONGNAME*
 *	Kyle 03/16/2010 QA80-15208 SLIDESHOW_AND_PPTSLIDE_SUPPORT_EMBEDDED_GRAPHS	*
 *	Folger 04/15/10 QA81-15315 NLFIT_SHOULD_CHANGE_OUTPUT_GRAPH_AXIS_SCALE_IF_MANUAL
 *	EJP 2010-06-15 ORG-259 CONTEXT_MENU_FOR_MATRIX_THUMBNAILS					*
 *	Kyle 08/05/2010 ORG-723-P1 COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O				*
 *	Folger 08/06/10 ORG-502-P5 CONTEXT_MENU_OF_ADD_DELETE_COL_SHOULD_ONLY_SHOW_IN_GRID_TABLE
 *	Kyle 08/10/2010 ORG-172-S1 OC_DISABLE_ZOOM_FOR_PREVIEW						*
 *	Jasmine 08/13/2010 ORG-172-S2 CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL	*
 *	Folger 08/20/10 ORG-865-P1 INSERT_VARIABLE_LINKING_FAILED_FOR_VIRTUAL_MATRIX_PLOT
 *	Kyle 09/03/2010 ORG-969-P1 CLEANUP_OC_ACCESS_TO_DATAPLOT_COLORMAP			*
 *	Kyle 09/19/2010 ORG-1007-P1 WDELDUP_IMPROVE_SPEED							*
 *	Folger 09/27/2010 ORG-1151-P1 SAVE_AS_ANALYSIS_TEMPLATE_FAILED_TO_CLEAN_GRAPHS_EMEBEDED_IN_WKS
 *	Folger 10/13/2010 ORG-1210-S2 CREATE_NEW_TABLE_OBJ_FOR_FITTER_OPERATION_IF_WKS_WITHIN_HAS_NO_LINK
 *	Folger 10/28/2010 ORG-1311-S2 COLMOVE_SUPPORT_MOVE_COLUMNS_TO_SPECIFIED_INDEX
*-------------------------------------------------------------------------------*/

////////////////////////////////////////////////////////////////////////////////////
// Including the system header file Origin.h should be sufficient for most Origin
// applications and is recommended. Origin.h includes many of the most common system
// header files and is automatically pre-compiled when Origin runs the first time.
// Programs including Origin.h subsequently compile much more quickly as long as
// the size and number of other included header files is minimized. All NAG header
// files are now included in Origin.h and no longer need be separately included.
//
// Right-click on the line below and select 'Open "Origin.h"' to open the Origin.h
// system header file.
#include <Origin.h>
#pragma labtalk(0) //--- CPY 7/26/05 hide all functions in this file from LT access, as XF should be used instead

////////////////////////////////////////////////////////////////////////////////////
#ifndef _RANGE_EX_H
#pragma message("including rangeEx.h separately")
#include RangeEx.h
#endif //_RANGE_EX_H

#include <ocGDI.h>
/// YuI 11/09/05 QA70-8279 REPORT_TREE_AND_REPORT_DATA_XVARIABLES
#include "theme_utils.h"
/// end REPORT_TREE_AND_REPORT_DATA_XVARIABLES

/// YuI 03/30/06 COMPLEX_VECTOR_AND_RANGE_DATA_TYPES
#include <OCTreeUtils.h>
/// end COMPLEX_VECTOR_AND_RANGE_DATA_TYPES

/// YuI 05/17/06 DATA_RESOLUTION_IN_XF_EVENT_HANDLERS
#include <xfutils.h>
/// end DATA_RESOLUTION_IN_XF_EVENT_HANDLERS

#include <okocUtils.h> //---- CPY 8/6/2007 REWRITE_CODE_TO_FIND_DATAPLOT_FROM_XYRANGE

#include <MsgMap.h> ///---Sim 12-18-2007 SPECIFY_ACTIVE_PAGE_AFTER_XF_WIZ_FINISH

#include "graph_utils.h" /// Iris 01/22/2009 ADDED_TWO_OPTIONS_LINK_TO_AND_SMART_OBJECTS_WHEN_ARRANGE_IN_MERGE_GRAPH

#include <OC_Res.h>

#define PAGEIMAGESECTION				"PageImage"
////////////////////////////////////////////////////////////////////////////////////
// Include your own header files here.


////////////////////////////////////////////////////////////////////////////////////
// Start your functions here.
bool get_storage_and_section_names(string& strStorage, string& strSection, LPCSTR lpcszStorageSection)
{
	if( lpcszStorageSection )
	{
		string strStorageSection(lpcszStorageSection);
		if( 2 == strStorageSection.GetNumTokens('.') )
		{		
			strStorage = strStorageSection.GetToken(0, '.');
			strSection = strStorageSection.GetToken(1, '.');
			return true;
		}
	}
	return false;
}

bool info_get_section(OriginObject& obj, TreeNode& trSection, LPCSTR lpcszStorageSection)
{
	if( obj )
	{
		string strStorage, strSection;
		if( get_storage_and_section_names(strStorage, strSection, lpcszStorageSection) )
		{
			storage st;
			st = obj.GetStorage(strStorage);
			if( st )
				return st.GetSection(strSection, trSection);
		}
	}
	return false;
}

bool info_set_section(OriginObject& obj, TreeNode& trSection, LPCSTR lpcszStorageSection)
{
	if( obj )
	{
		string strStorage, strSection;
		if( get_storage_and_section_names(strStorage, strSection, lpcszStorageSection) )
		{
			storage st;
			st = obj.GetStorage(strStorage, true); // true = add if does not exist
			if( st )
				return st.SetSection(strSection, trSection);
		}
	}
	return false;
}

bool page_get_info_var_value(Page& pg, LPCSTR lpcszVarName, string& strVarVal, LPCSTR lpcszStorageSection)
{
	string strStorageSection("User.Variables");
	if( lpcszStorageSection )
		strStorageSection = lpcszStorageSection;

	Tree trSection;
	if( info_get_section(pg, trSection, strStorageSection) )
	{
		string strVarName(lpcszVarName);
		strVarName.MakeUpper();

		TreeNode trnVar;
		trnVar = trSection.GetNode(strVarName);
		if( trnVar )
		{
			strVarVal = trnVar.strVal;
			return true;
		}
	}
	return false;
}

/// Hong 08/19/08 v8.0925 IMP_WIZ_VARIABLE_SHOULD_KEEP_AS_STRING_TYPE
//bool page_set_info_var_value(Page& pg, LPCSTR lpcszVarName, LPCSTR lpcszVarVal, LPCSTR lpcszStorageSection)
bool page_set_info_var_value(Page& pg, LPCSTR lpcszVarName, LPCSTR lpcszVarVal, LPCSTR lpcszStorageSection/*=NULL*/, int* pnPreferNodeType/* = NULL*/)
/// end IMP_WIZ_VARIABLE_SHOULD_KEEP_AS_STRING_TYPE
{
	string strStorageSection("User.Variables");
	if( lpcszStorageSection )
		strStorageSection = lpcszStorageSection;

	Tree trSection;
	/// Hong 06/26/08 v.80891e CENTRALIZE_CODE
	//if( info_get_section(pg, trSection, strStorageSection) )
	if( !info_get_section(pg, trSection, strStorageSection) )
	{
		if ( !info_set_section(pg, trSection, strStorageSection) )
			return false;
	}
	/// end CENTRALIZE_CODE
	{
		string strVarName(lpcszVarName);
		strVarName.MakeUpper();

		TreeNode trnVar;
		trnVar = trSection.GetNode(strVarName);
		if( !trnVar )		
			trnVar = trSection.AddNode(lpcszVarName);
		if( trnVar )
		{
			trnVar.strVal = lpcszVarVal;
			/// Hong 08/19/08 v8.0925 IMP_WIZ_VARIABLE_SHOULD_KEEP_AS_STRING_TYPE
			if ( pnPreferNodeType )
			{				
				trnVar.SetAttribute(STR_ID_ATTRIB, *pnPreferNodeType);
			}
			/// end IMP_WIZ_VARIABLE_SHOULD_KEEP_AS_STRING_TYPE
			return info_set_section(pg, trSection, strStorageSection);
		}
	}
	return false;
}

bool page_get_info_var_value(Page& pg, LPCSTR lpcszVarName, double& dVarVal, LPCSTR lpcszStorageSection)
{
	string strVarVal;
	if( page_get_info_var_value(pg, lpcszVarName, strVarVal, lpcszStorageSection) )
	{
		dVarVal = atof(strVarVal);
		return true;
	}
	return false;
}

bool page_set_info_var_value(Page& pg, LPCSTR lpcszVarName, double dVarVal, LPCSTR lpcszStorageSection)
{
	string strVarVal;
	strVarVal.Format("%f", dVarVal);
	return page_set_info_var_value(pg, lpcszVarName, strVarVal, lpcszStorageSection);
}

bool page_get_storage_str(Page& pg, LPCSTR lpcszName, string &strValue)
{
	if( pg && lpcszName )
	{
		vector<byte> vb;
		if( pg.GetMemory(lpcszName, vb) )
			return strValue.SetBytes(vb);
	}
	return false;
}

bool page_set_storage_str(Page& pg, LPCSTR lpcszName, LPCSTR lpcstrValue)
{
	if( pg && lpcszName && lpcstrValue )
	{
		string strValue(lpcstrValue);
		vector<byte> vb;
		if( strValue.GetBytes(vb) )
			return pg.SetMemory(lpcszName, vb);
	}
	return false;
}

int	gpage_get_plots(const GraphPage &pg, TreeNode &tr)
{
	if(pg == NULL)
		return 0;
	
	int				nCount = 0;
	
	tr.RemoveChild("DataPlots");
	TreeNode		trRoot = tr.AddNode("DataPlots");
	if (!trRoot.IsValid())
		return false;
	int nActiveLayerIndex = -1;
	int nRet = 0;
	foreach (GraphLayer lay in pg.Layers)
	{
		if (lay)
		{
			Tree		trLayer;
			int nn;

			/// RVD 9/3/2003 QA70-5078 v7.0682 PLOT_RANGE_APPLY
			//if (nn = lay.GetLayerContents(trLayer, GETLC_DATAPLOTS | GETLC_STYLE_HOLDERS))
			//----- CPY 6/17/08 QA70-11637 DATA_DISPLAY_SHOWING_CORRECT_RANGE_INFO_BETTER_USE_PAGE_SHORT_NAME
			//DWORD dwCntrl = GETLC_DATAPLOTS | GETLC_STYLE_HOLDERS;
			DWORD dwCntrl = (use_short_name_in_GUI(0,-1)? GETLC_PAGE_SHORT_NAME : 0);
			dwCntrl |= GETLC_DATAPLOTS | GETLC_STYLE_HOLDERS;
			//-----

			DWORD dwPlotView;

			if( dlg_load_registry(STR_PLOT_SETUP_DLG, STR_PLOT_VIEW, dwPlotView) )
			{
				if( dwPlotView & DPEDTVIEW_HIDE_LIMITS )
					dwCntrl |= GETLC_NO_LIMITS;
			}

			if( nn = lay.GetLayerContents(trLayer, dwCntrl) )
			/// end PLOT_RANGE_APPLY
			{
				//TreeNode	trDP = trLayer.DataPlots.Clone();
				TreeNode	trL = trLayer.FirstNode;
				TreeNode	trDP = trL.Clone();
				DWORD		dwLayerBits = lay.GetSystemParam(GLI_PCD_BITS);
				string strTemp = dwLayerBits;
				trDP.SetAttribute(STR_LAYER_TYPE_BITS, strTemp);
				//TreeNode	trLayer = trRoot.AddNode("Layer");					
				trRoot.AddNode(trDP);
				//trLayer = trDP;
				if(0==nRet)
					nRet = nn;
			}
			else
				ASSERT(FALSE);
		}
		else
			ASSERT(FALSE);
	}
	///Jasmine 02/02/10 QA81-14470-P5 PCD_PLOT_TYPE_FILL_AREA_+_IDM_PLOT_HILOCLOSE_=_IDM_PLOT_FILL_COLOR_BAND
	if(IDM_PLOT_HILOCLOSE == nRet)
	{
		DWORD dw = 0;
		TreeNode trStyleHolder = tree_get_node_by_tagname(trRoot, "StyleHolder1", true);
		if(trStyleHolder)
			dw = trStyleHolder.PlotDesigs.AuxPlotInfo.nVal;
		if(dw & PCD_PLOT_TYPE_FILL_AREA)
			nRet = IDM_PLOT_FILL_COLOR_BAND;
	}
	///End PCD_PLOT_TYPE_FILL_AREA_+_IDM_PLOT_HILOCLOSE_=_IDM_PLOT_FILL_COLOR_BAND
	if(nRet)
	{
		nActiveLayerIndex = page_active_layer_index(pg);
		if(nActiveLayerIndex >= 0)
		{
			string strTemp = nActiveLayerIndex;
			trRoot.SetAttribute(STR_ACTIVE_LAYER, strTemp);
		}
		///Jasmine 07/21/08 QA80-8716-S17 SEL_ACTIVE_PLOT_IF_PLOT_SETUP_OPEN_FROM_GRAPH
		DataPlot dp = pg.Layers().DataPlots();
		if(dp)
			trRoot.SetAttribute( "ActivePlot", (string)dp.GetIndex() );
		///End SEL_ACTIVE_PLOT_IF_PLOT_SETUP_OPEN_FROM_GRAPH
	}
	return nRet;
}

//----- CPY 7/17/04
bool page_is_active(const Page& pg)
{
	Page activePg = Project.Pages();
	/// TD 6-5-07 PAGE_ACTIVE_TEST_WHEN_HIDDEN_WITH_EXCEL_ACTIVE
	if(NULL == activePg)
		return false;
	/// end PAGE_ACTIVE_TEST_WHEN_HIDDEN_WITH_EXCEL_ACTIVE
	if(activePg.GetName() != pg.GetName())
		return false;
	
	return true;
}

///------ Folger 01/14/09 PAGE_SET_ACTIVE_LAYER_SUPPORT_ACTIVE_LAYER_ONLY
/*
bool page_set_active_layer(Page& pg, int nLayer, bool bActivePageOnly)
{
	if(!pg)
		return false;
	if(bActivePageOnly && !page_is_active(pg))
		return false;
	if(nLayer >= pg.Layers.Count())
		return false;
	
	/// Iris 01/12/2009 ACTIVATE_LAYER_BY_OC
	//string strLT = "page.active=" + (nLayer+1);
	//pg.LT_execute(strLT);
	//return true;
	if(bActivePageOnly)
		return pg.CheckShowActivate();
	
	Layer gl = pg.Layers(nLayer);
	if(!gl)
		return false;
	return gl.CheckShowActivate();
	///end ACTIVATE_LAYER_BY_OC
}
*/
bool page_set_active_layer(Page& pg, int nLayer, bool bActiveLayerOnly/* = true*/)
{
	if ( !pg || nLayer >= pg.Layers.Count() )
		return false;
	
	if ( bActiveLayerOnly )
	{
		string	strLT = pg.GetName() + "!page.active=" + (nLayer + 1);
		LT_execute(strLT);
		return true;
	}
	
	Layer gl = pg.Layers(nLayer);
	if ( !gl )
		return false;
	return gl.CheckShowActivate();
}
///------ End PAGE_SET_ACTIVE_LAYER_SUPPORT_ACTIVE_LAYER_ONLY

#define STR_SHORT_LONG_NAME_SEPARATOR " - "

///-----Frank 5/27/05	PAGE_LIST_SUPPORT_SUBFOLDER_AND_NOTE_PAGE	
// use long name if available
//string page_get_display_name(const Page& pg, bool bShortAndLongName) // = false
string page_get_display_name(const PageBase& pg, bool bShortAndLongName) // = false
///-----End	PAGE_LIST_SUPPORT_SUBFOLDER_AND_NOTE_PAGE	
{
	string str;
	if(pg)
	{
		string strLongName = pg.GetLongName();
		string strShortName = pg.GetName();
		if(bShortAndLongName)
		{	
			/// Iris 7/26/05 NO_NEED_GET_MATRIX_NAME
			/////Iris 7/7/05 GET_SOURCE_PAGE_NAME_FOR_MATRIX_DATA
			//int index = strLongName.Find(STR_M2W_WKS_LONGNAME_PRE);
			//if( -1 != index)  // if the format of long name like "Converted from Matrix1", will get Matrix1 as page name
			//{
				//strLongName.Delete(index, strlen(STR_M2W_WKS_LONGNAME_PRE));
				//strLongName.TrimLeft();
				//MatrixPage mp(strLongName);
				//if(mp.IsValid())
					//str = strLongName;
			//}
			/////end GET_SOURCE_PAGE_NAME_FOR_MATRIX_DATA
			//else
			//{
			///END NO_NEED_GET_MATRIX_NAME
				///---Sim 10-12-2007 QA70-10520 CENTRALIZE_MAKE_PAGE_SHORT_LONG_NAME
				/*
				if(strLongName.IsEmpty() || strLongName.CompareNoCase(strShortName) == 0)
					str = strLongName.IsEmpty()? strShortName : strLongName;
				else
					str = strShortName + STR_SHORT_LONG_NAME_SEPARATOR + strLongName;
				*/
				str = get_page_short_long_name(pg);
				///---END QA70-10520 CENTRALIZE_MAKE_PAGE_SHORT_LONG_NAME
			//}
		}
		else
		{
			str = strLongName;
			if(str.IsEmpty())
				str = strShortName;
		}
	}
	return str;
}
// lpcszSpecialPrefix = book1 -> return book1
// lpcszSpecialPrefix = <new> -> return <new>
// lpcszSpecialPrefix = <new> book1 -> return <new> and str2ndPart = book1
// lpcszSpecialPrefix = <source> book1-longname -> return <source> and str2ndPart = book1-longname
static string _get_str_2nd_part(LPCSTR lpcszSpecialPrefix, string& str2ndPart)
{
	str2ndPart.Empty();
	string str1 = lpcszSpecialPrefix;
	if(str1.GetLength() < 5 || str1[0] != '<')
		return str1;
	int nSeperator = str1.Find(">", 2);// has to be at least <a>, cannot be <>
	if(nSeperator < 0)
		return str1;
	str2ndPart = str1.Mid(nSeperator+1); 
	str2ndPart.TrimLeft(); str2ndPart.TrimRight();
	string str1stPart = str1.Left(nSeperator + 1);
	return str1stPart;
}

//string page_short_name_from_display_name(LPCSTR lpcszDisplayName, bool& bSourceBook)  ///Iris 11/16/04 QA70-7139 UPDATE_2ND_ARGUMENT_FOR_PAGE_SHORT_NAME_FROM_DISPLAY_NAME
string page_short_name_from_display_name(LPCSTR lpcszDisplayName, int& nType)
{
	string str2ndPart;
	string str = _get_str_2nd_part(lpcszDisplayName, str2ndPart);
	int nPos = -1;
	/*
	if(str == STR_SOURCE_BOOK)
	{
		bSourceBook = true;
		str = str2ndPart;
		//CPY 11/3/04, only if in the form of <Source> ShortName - Long Name will we
		// reutrn only the ShortName
		nPos = str.Find(STR_SHORT_LONG_NAME_SEPARATOR);
	}
	else
		bSourceBook = false;
	*/

	nType = cvt_str_to_predefined_type(str);

	switch(nType)
	{
	case PDS_SOURCE:
		//str = str2ndPart; /// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
		//CPY 11/3/04, only if in the form of <Source> ShortName - Long Name will we
		// reutrn only the ShortName
		nPos = str.Find(STR_SHORT_LONG_NAME_SEPARATOR);
		break;
	case PDS_CUSTOM:
	/// ML 3/3/2005 XFUNCTION_OUTPUT_VARIABLES_DATA_ASSOC
	case PDS_NEW:
	/// end XFUNCTION_OUTPUT_VARIABLES_DATA_ASSOC
		//str = str2ndPart; /// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
		break;
	default:
		break;		
	}
	
	/// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
	// "<Auto>" case will return the ist part, but should always return str as 2nd part for all cases
	str = str2ndPart; 
	///end ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
	
	if(nPos > 0)
		return str.Left(nPos);
	
	return str;
}
//----- end CPY 7/17/04

int page_active_layer_index(Page& pg)
{
	if(!page_is_active(pg))
		return -1;
	
	Layer lay = pg.Layers();
	
	return lay.GetIndex();
}


/// ML 12/9/2003 QA70-5657 UTILITY_ORIGINC_FUNCTIONS_FOR_PLOT_CREATION


// this function is needed in several classes, we should not call GetPlotTypeInfo directly, need all these additional fix up
int	get_plot_type_info(int nPlotID, int nPageType, DWORD dwTargetLayer, DWORD& dwAuxTypeInfo, DWORD& dwAuxPlotInfo, string& strColPattern)
{
	int nPlotType = 0;
	
	if(nPlotID)
		nPlotType = Project.GetPlotTypeInfo(nPlotID, dwAuxTypeInfo, dwAuxPlotInfo, strColPattern);
	if(nPageType)
	{
		if(EXIST_DATA == nPageType || EXIST_FUNC_PLOT == nPageType)
			dwAuxTypeInfo &= ~PCD_CAN_ADD_E_H_L;
		if(EXIST_FUNC_PLOT == nPageType)
			dwAuxTypeInfo |= PCD_NO_X;
	}
	
	if (PCD_LAYER_TRI == dwTargetLayer)
	{
		DWORD dwSaveModifiers = dwAuxTypeInfo & ( PCD_MODIFIER_SIZE | PCD_MODIFIER_COLOR );
		dwAuxTypeInfo = PCD_LAYER_TRI | PCD_EXACT_YCOLS | PCD_Z_PREFER_Y | PCD_GROUP_MULTI_YS | PCD_PREFER_X | PCD_CAN_ADD_E_H_L | PCD_HIDE_ERR_BARS;
		dwAuxTypeInfo |= dwSaveModifiers;
		/// Fisher 4/28/2009 PLOT_SETUP_FIXING_FOR_TENERY_CONTOUR
		if( IS_ZINDEPENDENT_PLOT_ID(nPlotID) )
			dwAuxTypeInfo |= PCD_Z_INDEP_FOR_TERNARY | PCD_MODIFIER_TRICONT_BOUNDARY;
		/// End PLOT_SETUP_FIXING_FOR_TENERY_CONTOUR
	}
	else if (PCD_LAYER_SMITH == dwTargetLayer)
		dwAuxTypeInfo |= PCD_HIDE_ERR_BARS;
	return nPlotType;
}

static	int		make_plots_tree(TreeNode &tr, int nPlotType, vector<string>	&vsWksPages, vector<string>	&vsLayers, vector<string> &vsCols, vector<uint> &vpdesig, DWORD dwCntrl)
{
	DWORD			dwAuxTypeInfo, dwLTPlotInfo;
	string			strColPattern;
	uint			nExVal = 0;
	
	int				nn = get_plot_type_info(nPlotType, EXIST_WKS, 0, dwAuxTypeInfo, dwLTPlotInfo, strColPattern);
	/// AW 01/30/04 QA70-5657 v7.0811 TEMP_FIXING_MAKE_PLOTS_TREE
	// required by ML temp changing here
	//int				nRet = Project.MakeDataplotsTree(tr, nn, dwAuxTypeInfo, dwLTPlotInfo, strColPattern, nExVal, vpdesig, vsWksPages, vsLayers, vsCols, TRUE);
	int	nRet =  0 == Project.MakeDataplotsTree(tr, nn, dwAuxTypeInfo, dwLTPlotInfo, strColPattern, nExVal, vpdesig, vsWksPages, vsLayers, vsCols, dwCntrl);
	/// END TEMP_FIXING_MAKE_PLOTS_TREE
	
	return nRet;
}

/// AW 12/24/03 MORE_WORK_ON_ADD_PLOTS_TO_LAYER
// return: 
//		1) >0, the total number of plots added; 
//		2) =0 means "Failed to add dataplots.";
//      3) =-1 means "Cannot create plot tree.";
/// MORE_WORK_ON_ADD_PLOTS_TO_LAYER
int		add_plots_to_layer(GraphLayer &lay, int nPlotType, LPCSTR lpcszWksName, vector<string> &vsCols, vector<uint> &vpdesig, DWORD dwCntrl)
{
	Tree			tr;
	vector<string>	vsWksPages;
	vector<string>	vsLayers;
	
	vsWksPages.Add(lpcszWksName);
	vsLayers.SetSize(1);
	
	
	int				nRet = make_plots_tree(tr, nPlotType, vsWksPages, vsLayers, vsCols, vpdesig, dwCntrl);
	/// AW 12/24/03 MORE_WORK_ON_ADD_PLOTS_TO_LAYER
	/*
	if (!nRet)
	{
		out_str("Cannot create plot tree.");
		return -1;
	}
	*/
	if (0 != nRet)
		return -1;  // error, Cannot create plot tree 
	/// END MORE_WORK_ON_ADD_PLOTS_TO_LAYER
	TreeNode		trLayer = tr.FirstNode;
	int				nNumPlotsAdded = lay.AddPlots(trLayer, ADDPLOTSFROMTREE_NEW);
	if (nNumPlotsAdded <= 0)
	{
		/// AW 12/24/03 MORE_WORK_ON_ADD_PLOTS_TO_LAYER
		//out_str("Failed to add dataplots");
		return 0; //  error, Failed to add dataplots
		/// END MORE_WORK_ON_ADD_PLOTS_TO_LAYER
	}
	
	return nNumPlotsAdded;
}

/// end UTILITY_ORIGINC_FUNCTIONS_FOR_PLOT_CREATION

///Jasmine 12/16/09 QA81-14845-P4 SHOW_SELECTED_PLOT_INFO_TO_AVOID_DUPLICATED_SOURCE_BOOK
bool dataplot_get_info_tree(const DataPlot& dp, TreeNode& trNode)
{
	DataRange dr;
	Datasheet ds;
	if(dp && dp.GetDataRange(dr) && dr )
		dr.GetParent(ds);
		
	Page pg;
	if(ds)
		pg = ds.GetPage();
	if(!pg)	
		return false;
	
	string strSourceBook = pg.GetName();
	string strLabel = strSourceBook;
	if( !pg.Label.IsEmpty() )
		strLabel += " - " + pg.Label;
	
	tree_add_info(trNode, pg, strSourceBook, strLabel, dp.GetIndex()+1);//for labtalk
		
	TreeNode tr = tree_get_node_by_tagname(trNode, strSourceBook, true);
	if(!tr.IsValid())
		tr = trNode;
	tree_add_import_file_info(tr, pg);
	tree_add_user_tree_info(tr, pg);
		
	string strDataValue;
	ASSERT( !tr.GetAttribute(STR_PLOT_INDEX_ATTRIB, strDataValue) );
	tr.SetAttribute(STR_PLOT_INDEX_ATTRIB, dp.GetIndex()+1);
		
	return true;
}
///End SHOW_SELECTED_PLOT_INFO_TO_AVOID_DUPLICATED_SOURCE_BOOK
	
//------ CPY 10/11/04 MOVE_GRAPH_GET_INFO_TREE_TO_PAGE_UTILS
bool page_graph_get_info_tree(GraphLayer gl, TreeNode& trNode)
{
	if(!gl)
		return false;
	
	vector<string> vsWksNames;
	vector<uint>	vsDataPlots;
	uint iPlot = 1;// LabTalk index
	foreach(DataPlot dp in gl.DataPlots)
	{
		// we are trying to get wks name from a data plot
		// currently there is no clean way to do this
		string strName = dp.GetDatasetName();
		int nPos = strName.Find('_');
		string strWksName;
		if(nPos > 0)
			strWksName = strName.Left(nPos);
		else // check for matrices
			strWksName = strName;
		
		if(!strWksName.IsEmpty() && !is_in_list(strWksName, vsWksNames))
		{
			vsWksNames.Add(strWksName);
			///Jasmine 12/15/09 QA81-14845-P4 WRONG_LOGIC_TO_COUNT_PLOT_INDEX
			//vsDataPlots.Add(iPlot++);
			vsDataPlots.Add(dp.GetIndex()+1);
			///End WRONG_LOGIC_TO_COUNT_PLOT_INDEX
		}
		
	}
	
	for(int ii = 0; ii < vsWksNames.GetSize(); ii++)
	{
		string str = vsWksNames[ii];
		Page pg(vsWksNames[ii]);
		///------ Folger 10/28/09 INSERT_USER_VAR_RUNTIME_ERROR_WHEN_OPEN_IN_TEXTOBJ_WHICH_SAVED_IN_OGG
		if ( !pg )
			continue;
		///------ End INSERT_USER_VAR_RUNTIME_ERROR_WHEN_OPEN_IN_TEXTOBJ_WHICH_SAVED_IN_OGG
		string strLabel = pg.Label;
		if(!strLabel.IsEmpty())
			str += " - " + pg.Label;
		tree_add_info(trNode, pg, vsWksNames[ii], str, vsDataPlots[ii]);
		///Jasmine 02/06/07 SHOW_IMPORT_FILE_AND_USER_TREE
		TreeNode tr = tree_get_node_by_tagname(trNode, vsWksNames[ii], true);
		if(!tr.IsValid())
			tr = trNode;
		tree_add_import_file_info(tr, pg);
		tree_add_user_tree_info(tr, pg);
		//End SHOW_IMPORT_FILE_AND_USER_TREE
		
		///Jasmine 12/14/09 QA81-14845-P3 ACCESS_FILE_INFO_WITH_PLOT_NOTATION
		string strDataValue;
		ASSERT( !tr.GetAttribute(STR_PLOT_INDEX_ATTRIB, strDataValue) );
		tr.SetAttribute(STR_PLOT_INDEX_ATTRIB, vsDataPlots[ii]);
		///End ACCESS_FILE_INFO_WITH_PLOT_NOTATION
	}
	
	return true;
}
//---- end MOVE_GRAPH_GET_INFO_TREE_TO_PAGE_UTILS

//Begin	Frank	05/07/04	QA70-6331 v8.0867	GET_THUMBNAIL_FROM_PAGE	
/**
		Export graph page to picture holder
	Parameters:
		pgSrc = source graph page
		phDst = picture holder as destination
		lpcszType = "BMP"
		nRes = resolution of the image
		bSaveInPage = if true, save the image and date & time back to graph page.
	Returns: 
		TRUE if succeed; FALSE otherwise
 */
bool page_get_picture(GraphPageBase& pgSrc, PictureHolder& phDst, LPCSTR lpcszType, int nRes, bool bSaveInPage)//=NULL, 36,true 
{
	//Check input
	if( !pgSrc.IsValid() )
		return false;
	
	if( NULL == lpcszType )
		lpcszType = "EMF";
	return pgSrc.GetPicture(phDst, lpcszType, nRes, -1, bSaveInPage ? EMBEDGRAPH_CACHE_IN_PAGE : 0);
}
//---- CPY TD 11/2/06 CENTRALIZED_CODE_FOR_GET_PICTURE_TO_VC
// change to just pgSrc.GetPicture above
// original code below
/*

	string strFromat = lpcszType;
	char 	cFormat =strFromat.GetAt(0) ;
	int nFormat;
	switch(cFormat)
	{
	case 'B': 
		nFormat = CF_BITMAP;
		break;
	case 'W':
		nFormat = CF_METAFILEPICT;
		break;
	case 'E':
		nFormat = CF_ENHMETAFILE;
		break;
	case 'D':
		nFormat = CF_DIB;
		break;
	default:
		return false;
	}
				
	if( 0 >= nRes )
		return false;
	
	bool bRet = true;


		
	Tree	tr;
	TreeNode trSection = tr.AddNode(PAGEIMAGESECTION);
	vector<byte>	vb;
	pgSrc.GetMemory(PAGEIMAGESECTION,vb);
	string strXML ;
	if(strXML.SetBytes(vb))
		trSection.XML = strXML;

	TreeNode 	trPageSectionImage ;
	string strImageTitle  = lpcszType ;
	strImageTitle = strImageTitle + nRes;
	trPageSectionImage = trSection.GetNode(strImageTitle);
	bool bGetLastPict = false;
	//Begin	Frank 05/08/04 QA70-6331 v8.0869 PAGE_IMAGE_ADD_INFO
	if( !trPageSectionImage.IsValid())
	{
		//export page to a temp file and load it
		if( !export_page_to_pictureholder(pgSrc, phDst, nFormat, nRes))
			return false;
		if(bSaveInPage)
			trPageSectionImage = trSection.AddNode(strImageTitle);
	}
	else
	{
		double dPhCreationTime ; 
		dPhCreationTime = trPageSectionImage.CreateDateTime.dVal;
		PageSystemInfo	PgInfo;
		pgSrc.GetPageSystemInfo(&PgInfo);

		double	dLastModifyTime = PgInfo.dModified;

		if( dPhCreationTime < dLastModifyTime)	
		{
			if( !export_page_to_pictureholder(pgSrc, phDst, nFormat, nRes))
				return false;
		}
		else
		{
			phDst = trPageSectionImage.Image.pict;
			bGetLastPict = true;
		}
	}
	//End PAGE_IMAGE_ADD_INFO
	
	//Save picture and date & time to GraphPage if needed.
	if( bSaveInPage &&!bGetLastPict )
	{		
		///Get current create pictureholder time and convert into local file time.
		double dCurrentTime ;
		SYSTEMTIME systime;
		//----- CPY 8/17/05
		//GetSystemTime( &systime );
		//FILETIME ft, ftLocal;
		//SystemTimeToFileTime(&systime, &ft);
		//FileTimeToLocalFileTime(&ft, &ftLocal);
		//FileTimeToSystemTime(&ftLocal, &systime);
		get_current_time(systime);
		//------
		SystemTimeToJulianDate(&dCurrentTime, &systime);
		trPageSectionImage.CreateDateTime.dVal = dCurrentTime;
		trPageSectionImage.Image.pict = phDst;

		//Save the export date and create time as binary data
		strXML = trSection.XML;
		if( strXML.GetBytes(vb) )
		{
			pgSrc.SetMemory(PAGEIMAGESECTION, vb);
		}
	}
	return bRet;
}

bool export_page_to_pictureholder(GraphPage& pgSrc, PictureHolder& phDst,int nCFformat , int nRes)//,Tree &trTemp ) test
{
	bool bRet;
	switch(nCFformat)
	{
		case CF_BITMAP: 
			HBITMAP hbp = pgSrc.CreateImage(CF_BITMAP, nRes,0);
			phDst.CreateFromBitmap(hbp,true);
			break;

		case CF_METAFILEPICT:
			//Can't support now/
			HMETAFILE hmf = pgSrc.CreateImage(CF_METAFILEPICT, nRes,0);
			RECT16 rec;
			phDst.CreateFromMetafile( hmf, rec.right - rec.left, rec.bottom - rec.top , true);
			break;

		case CF_ENHMETAFILE:
			HENHMETAFILE	hemf;
			hemf = pgSrc.CreateImage(CF_ENHMETAFILE,nRes,0);
			bRet = phDst.CreateFromEnhMetafile( hemf, true );
			break;
			
		case CF_DIB:
			//Can't use now
			HDIB	hemf;
			hemf  = pgSrc.CreateImage(CF_DIB,nRes,0);
			break;
		default:
			return false;
	}
	return true;
}
*/
//---- end CENTRALIZED_CODE_FOR_GET_PICTURE_TO_VC

//------- CPY 
// temp, will need to move to centralized place later
bool wkbook_find_import_file(LPCSTR lpcszBook, LPCSTR lpcszSheet, LPCSTR lpcszCol, string& strFileFullPath, double& dFileDate)
{
	/// SY 09/01/2004 QA70-6472 v8.0128 IMPORT_INFO_STORAGE_CLEANUP
	///WorksheetPage pg(lpcszBook);
	///string strStorageSection = "System.Import";
	///Tree tr;
	///if( info_get_section(pg, tr, strStorageSection) )
	Tree tr;
	if( wkbook_find_import_file_info(lpcszBook, lpcszSheet, lpcszCol, tr) > 0 )
	/// end IMPORT_INFO_STORAGE_CLEANUP
	{
		/// SY 10/06/2004 QA70-6472 v8.0145 IMPORT_INFO_STORAGE_CLEANUP
		///	if(tr.FileDate)
		///	{
		///		dFileDate = tr.FileDate.dVal;
		///		strFileFullPath = tr.FilePath.strVal;
		///	}
		if(tr.Info.FileDate)
		{
			dFileDate = tr.Info.FileDate.dVal;
			strFileFullPath = tr.Info.FilePath.strVal;
		}		
		/// end IMPORT_INFO_STORAGE_CLEANUP
		else
			dFileDate = get_missing_value();
			
		return true;
	}
	return false;
}

///	SY 08/24/2004 QA70-6780 v8.0116 LLOC_FOR_IMPORT
// put data from trImpResults into target page (pgTarget)
bool page_put_tree_data_branch(Page& pgTarget, TreeNode& trImpResults, bool bRemoveDataFromTree) // = false
{
	if( !pgTarget || !trImpResults )
		return false;

	switch( pgTarget.GetType() )
	{
	case EXIST_WKS:
		{
			TreeNode trData = trImpResults.GetNode(IMPTREE_NODE_DATA);
			if( !trData )
				break;
			
			Layer ly = pgTarget.Layers();
			if( !ly )
				break;
			
			Worksheet wks(ly);
			if( !wks )
				break;

			/// EJP 2005-01-21 v8.0185 QA70-7210 PCLAMP_IMPORT_DIALOG
			if( wks.GetNumCols() < trData.GetNodeCount() )
				wks.SetSize(-1, trData.GetNodeCount());
			/// end PCLAMP_IMPORT_DIALOG
			
			string strChName;
			int ich = 0; // the first column
			
			TreeNode trChNode;
			TreeNode trDataCh;

			/// EJP 2005-01-21 v8.0185 QA70-7210 PCLAMP_IMPORT_DIALOG
			/*
			do
			{
				strChName.Format("Ch%d", ich);
				trChNode = trData.GetNode(strChName);
				
				if( trChNode )
				{
					trDataCh = trChNode.GetNode(IMPTREE_NODE_DATA);
					Dataset ds(wks, ich);
					ds = trDataCh.sVals;
					ich++;
				}
				
			} while(trChNode);
			*/
			trChNode = trData.FirstNode;
			while( trChNode )
			{
				/// SY 04/11/2005 QA70-7210 v8.0219 MORE_WORK_PCLAMP_IMPORT_DIALOG
				wks.Columns(ich).SetName(trChNode.tagName);
				
				trDataCh = trChNode.GetNode("LongName");
				if( trDataCh )
					wks.Columns(ich).SetLongName(trDataCh.strVal);
				
				trDataCh = trChNode.GetNode("Unit");
				if( trDataCh )
					wks.Columns(ich).SetUnits(trDataCh.strVal);
				/// end MORE_WORK_PCLAMP_IMPORT_DIALOG
				
				trDataCh = trChNode.GetNode(IMPTREE_NODE_DATA);
				if( trDataCh )
				{
					int nDataType;
					if( trDataCh.GetAttribute(IMPTREE_NODE_DATATYPE, nDataType) )
					{
						Dataset ds(wks, ich);
						switch( nDataType )
						{
						case FSI_REAL:
							ds = trDataCh.fVals;
							break;
						case FSI_SHORT:
							ds = trDataCh.sVals;
							break;
						}
						ich++;
					}
				}
				trChNode = trChNode.NextNode;
			}
			/// end PCLAMP_IMPORT_DIALOG
			
			if( bRemoveDataFromTree )
				trData.Remove();	
		}
		
		return true;

	default:
		break;
	}
	
	return false;
}
/// end LLOC_FOR_IMPORT

/// SY 08/31/2004 QA70-6472 v8.0127 IMPORT_INFO_STORAGE_CLEANUP
int page_ifi_get_node_count(LPCSTR lpcszBook)
{
	WorksheetPage wp(lpcszBook);

	if( wp.IsValid() )
	{
		Tree trStorage;
		if( tree_get_binary_storage(trStorage, wp, IFI_BINARY_STORAGE_NAME) )
			return trStorage.GetNodeCount();
	}
	
	return 0;
}

bool page_ifi_get_file_node(LPCSTR lpcszBook, TreeNode& trn, int nIndex)
{
	WorksheetPage wp(lpcszBook);

	if( wp.IsValid() )
	{
		Tree trStorage;
		if( tree_get_binary_storage(trStorage, wp, IFI_BINARY_STORAGE_NAME) )
		{
			string str;
			str.Format(IFI_FILE_NODE_ENUM_NAME, nIndex);
			trn = trStorage.GetNode(str);
			
			return trn.IsValid();
		}
	}
	return FALSE;
}

/// SY 12/16/2004 QA70-7258 v8.0176 IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
///	static bool ifiGetDataRange(const TreeNode& tr, DataRange& dr)
///	{
///		TreeNode trnDataRange = tr.GetNode(IMPTREE_NODE_DATA_RANGE);
///		
///		if( !trnDataRange.IsValid() )
///			return FALSE;
///		
///		return dr.Create(trnDataRange);
///	}
/// end IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID

// return index into file storage, or -1 if not found
// fill trInfo with a Clone copy of the found info tree
int wkbook_find_import_file_info(LPCSTR lpcszBook, LPCSTR lpcszSheet, LPCSTR lpcszCol, TreeNode& trInfo)
{
	WorksheetPage wp(lpcszBook);
	if( !wp.IsValid() )
		return -1;
	
	Worksheet wks;
	wks = wp.Layers(lpcszSheet);
	if( !wks.IsValid() )
		return -1;

	Column col = wks.Columns(lpcszCol);
	if( !col.IsValid() )
		return -1;
		
	int iColIndex = col.GetIndex();
	if( iColIndex < 0 )
		return -1;
	
	int nCount = page_ifi_get_node_count(lpcszBook);
	if( nCount < 1 )
		return -1;

	TreeNode trn;
	/// SY 12/16/2004 QA70-7258 v8.0176 IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
	///DataRange dr;
	///Worksheet wkstmp;
	///int c1, c2, r1, r2;
	//DataRangeEx dr;
	int c1, c2;
	/// end IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
	int nNode;
	
	for( nNode = 1; nNode <= nCount; nNode++ )
	{
		if( page_ifi_get_file_node(lpcszBook, trn, nNode) )
		{
			/// SY 12/16/2004 QA70-7258 v8.0176 IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
			///	if( ifiGetDataRange(trn, dr) )
			///	{
			///		// Check if the DataRange is for lpcszSheet and lpcszCol
			///		dr.GetRange(0, r1, c1, r2, c2, wkstmp);
			TreeNode trnDataRange = trn.GetNode(IMPTREE_NODE_DATA_RANGE);
			
			if( trnDataRange.IsValid() )
			{
				DataRangeEx dr(trnDataRange, true); // constructor with true will update trn with corrected UID and excelRange from saved GUID
				if( dr.GetRange(c1,c2) )
				{
				/// end IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
					if( iColIndex >= c1 && iColIndex <= c2 )
					{
						trInfo = trn.Clone();
						break;
					}
				}
			}
		}
	}
	/// SY 12/16/2004 QA70-7258 v8.0176 IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
	///dr.Destroy();
	/// end IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
	
	return (nNode <= nCount ? nNode : -1);
}

/// EJP 09-15-2004 v8.0135 QA70-6472 IMPORT_INFO_STORAGE_CLEANUP
// Get Import File Info tree from active page
static bool page_get_import_file_info_tree(Page& pg, TreeNode& trFiles)
{
	///Page pg = Project.Pages();
	if( pg )
	{
		if( !tree_get_binary_storage(trFiles, pg, IFI_BINARY_STORAGE_NAME) )
			trFiles.Reset();
		return true;
	}
	return false;
}

// Set Import File Info tree into active page
static bool page_set_import_file_info_tree(Page& pg, TreeNode& trFiles)
{
	///Page pg = Project.Pages();
	if( pg )
	{
		return tree_put_binary_storage(trFiles, pg, IFI_BINARY_STORAGE_NAME);
	}
	return false;
}

static bool tree_rename(TreeNode& tr, LPCSTR lpcszNewName)
{
	Tree trTmp;
	TreeNode trnTmp;
	trnTmp = trTmp.AddNode(lpcszNewName);
	if( !trnTmp )
		return false;

	TreeNode trn;
	trn = tr.FirstNode;
	while( trn )
	{
		trnTmp.AddNode(trn);
		trn = trn.NextNode;
	}

	return tr.Replace(trnTmp);
}

// Delete File nodes from an Import File Info tree.
// If a book name is not specified then the active book is used.
// If a sheet name is not specified then the active sheet in the specified book is used.
static bool tree_del_import_file_info_nodes(TreeNode& trFiles, LPCSTR lpcszSheet = NULL, LPCSTR lpcszBook = NULL)
{
	// Get book by name, if name is NULL then get active
	string strBook;
	if( lpcszBook )
		strBook = lpcszBook;
	else // if no book name then use active
	{
		Page pgActive = Project.Pages();
		strBook = pgActive.GetName();
	}
	WorksheetPage wp(strBook);
	if( !wp.IsValid() )
		return false;

	// Get sheet by name, if name is NULL then get active
	Worksheet wks;
	if( lpcszSheet )
		wks = wp.Layers(lpcszSheet);
	else // if no sheet name then use active
		wks = wp.Layers();
	if( !wks.IsValid() )
		return -1;
	string strSheet;
	wks.GetName(strSheet);

	int nNodeCountBeforeDel = trFiles.GetNodeCount();
	
	// The following are variables used for checking the data range.
	/// SY 12/16/2004 QA70-7258 v8.0176 IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
	///	DataRange dr;
	///	Worksheet wksTmp;
	///	int c1, c2, r1, r2;
	string strWksName;
	/// end IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID

	TreeNode trnNext;

	TreeNode trn(trFiles.FirstNode);
	while( trn )
	{
		trnNext = trn.NextNode;
		/// SY 12/16/2004 QA70-7258 v8.0176 IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
		///	if( ifiGetDataRange(trn, dr) )
		///	{
		///		dr.GetRange(0, r1, c1, r2, c2, wksTmp);
		///		if( wksTmp )
		///		{
		///			string strWksName;
		///			if( wksTmp.GetName(strWksName) && 0 == strWksName.CompareNoCase(strSheet) )
		///				trFiles.RemoveChild(trn);
		///		}
		///	}
		TreeNode trnDataRange = trn.GetNode(IMPTREE_NODE_DATA_RANGE);
		
		if( trnDataRange.IsValid() )
		{
			DataRangeEx dr(trnDataRange, true);
			Worksheet wksTmp;
			
			if( dr.GetRange(wksTmp) )
			{
				if( wksTmp && wksTmp.GetName(strWksName) && 0 == strWksName.CompareNoCase(strSheet) )
					trFiles.RemoveChild(trn);	
			}
		}
		/// end IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
		trn = trnNext;
	}

	// The following loop is to renumber the nodes.
	int nNodeCountAfterDel = trFiles.GetNodeCount();
	if( nNodeCountBeforeDel != nNodeCountAfterDel && nNodeCountAfterDel > 0 )
	{
		string str;
		int nNode = 1;
		trn = trFiles.FirstNode;
		while( trn )
		{
			str.Format(IFI_FILE_NODE_ENUM_NAME, nNode++);
			tree_rename(trn, str);
			trn = trn.NextNode;
		}
	}

	return true;	
}

// Setup the Import File Info tree and add a new node.
static bool tree_new_import_file_info_node(TreeNode& trFiles, int nImportMode)
{
	if( ASCIMP_MODE_REPLACE_DATA == nImportMode )
		tree_del_import_file_info_nodes(trFiles); // delete nodes for active book and sheet

	int nFile = trFiles.GetNodeCount() + 1;
	string str;
	str.Format(IFI_FILE_NODE_ENUM_NAME, nFile);
	trFiles.AddNode(str);
	
	return true;
}

int page_init_import_file_info(int nImportMode, LPCSTR lpcszFileName, LPCSTR lpcszPageName)
{
	Page pg(lpcszPageName);
	if( !pg )
		return 1;

	Tree trFiles;
	if( page_get_import_file_info_tree(pg, trFiles) )
	{
		if( tree_new_import_file_info_node(trFiles, nImportMode) )
		{
			TreeNode trnFile;
			trnFile = trFiles.LastNode; // last node is the new node
			
			//tree_set_import_file_info(trnFile, lpcszFileName);
			impinfo_FileInfoToFileNode(trnFile, lpcszFileName)
		}
		page_set_import_file_info_tree(pg, trFiles);
	}
	return 0;
}

int page_set_import_file_info_result(ASCIMPRESULT* pImportResult, LPCSTR lpcszPageName)
{
	Page pg(lpcszPageName);
	if( !pg )
		return 1;

	Tree trFiles;
	if( page_get_import_file_info_tree(pg, trFiles) )
	{
		TreeNode trnFile;
		trnFile = trFiles.LastNode; // last node is the new node
				
		Worksheet wks = Project.ActiveLayer();
		/// SY 12/15/2004 QA70-7258 v8.0175 IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
		///	DataRange dr;
		///	dr.Add("Import", wks, pImportResult->nR1, pImportResult->nC1, pImportResult->nR2, pImportResult->nC2);
		///
		///	Tree trRange;
		///	dr.GetTree(trRange);
		///	
		///	trnFile.DataRange.Range.strVal = trRange.Import.strVal;
		DataRangeEx dr;
		dr.Add(wks, pImportResult->nR1, pImportResult->nC1, pImportResult->nR2, pImportResult->nC2);
		dr.Save();
		trnFile.DataRange.ID = 1; // we may have a better ID for this later
		dr.PrepareTree(trnFile.DataRange);
		/// end IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID

		page_set_import_file_info_tree(pg, trFiles);
	}
	return 0;
}

int page_set_import_file_info_header(LPCSTR lpcszHeaderLines, LPCSTR lpcszPageName)
{
	Page pg(lpcszPageName);
	if( !pg )
		return 1;

	Tree trFiles;
	if( page_get_import_file_info_tree(pg, trFiles) )
	{
		TreeNode trnFile;
		trnFile = trFiles.LastNode; // last node is the new node

		trnFile.ASCII.HeaderLines.strVal = lpcszHeaderLines;
		
		page_set_import_file_info_tree(pg, trFiles);
	}
	return 0;
}
/// end IMPORT_INFO_STORAGE_CLEANUP

///Jasmine 01/23/09 PLOT_SETUP_NEED_IMPORTED_FILE_INFO_FROM_SHEET, move from fu_utils 
///---Sim 03-07-2007 QA80-9435 SUPPORT_RELATIVE_DATA_RANGE
DataRange get_and_check_range(TreeNode& trRangeInfo, string strPg) // = ""
{
	///---Sim 03-11-2007 QA80-9435 CENTRALIZE_RANGE_TREE_BOTH_ON_VC_AND_OC
	DataRange dr;
	if ( trRangeInfo )
	{
		///---Sim 11-01-2007 CLEAN_RANGE_ID_CODE
		/*
		TreeNode trRangeUID = trRangeInfo.GetNode(STR_RANGE_UID);
		if ( trRangeUID )
		{
			dr = (DataRange)Project.GetObject(trRangeUID.nVal);
			if( dr.IsValid() && dr.GetNumData() )
				return dr;
		}
		
		TreeNode trRangeStr = trRangeInfo.GetNode(STR_RANGE_STR);
		if ( trRangeStr )
		{
			string str = trRangeStr.strVal;
			if(str[0] != '[')
			{
				string strTemp;
				strTemp.Format("[%s]%s", strPg, str);
				str = strTemp;
			}
			dr.Add(STR_RANGE_STR, str);
			if ( dr.IsValid() && dr.GetNumData() )
			{
				// update UID
				uint UID = dr.GetUID(TRUE);
				Project.AddDataRange(dr);
				
				if ( !trRangeUID )
					trRangeUID = trRangeInfo.AddNode(STR_RANGE_UID);
				trRangeUID.nVal = UID;
				
				return dr;      
			}
		}
		*/
		///---END CLEAN_RANGE_ID_CODE
		
		trRangeInfo.GetDataRange(dr);
	}
	return dr;
	//return trRangeInfo.GetDataRange();
	///---END QA80-9435 CENTRALIZE_RANGE_TREE_BOTH_ON_VC_AND_OC
}
///---END QA80-9435 SUPPORT_RELATIVE_DATA_RANGE

///---Sim 01-29-2007 MORE_UTILS_FUNCTION
typedef struct
{
	int r1, c1, r2, c2;
} DataSheetRange ;

static bool _get_range_span(DataRange& dr, int Index, int& r1, int& c1, int& r2, int& c2, Datasheet& ds, Page& pg)
{
	dr.GetRange(Index, r1, c1, r2, c2, ds);
	
	if ( !ds )
		return false;
	
	ds.GetParent(pg);
	
	if(-1 == r2)
		r2 = ds.GetNumRows() - 1;
	
	if(-1 == c2)
		c2 = ds.GetNumCols() - 1;
	
	return true;
}

bool is_relative_range(const DataRange& dr1, const DataRange& dr2)
{
	if ( !dr1 || !dr2 )
		return false;
	
	DataSheetRange dsr1, dsr2;
	Datasheet ds1, ds2;
	Page pg1, pg2;
	
	for(int ii = 0; ii < dr1.GetNumRanges(); ii++ )
	{		
		if ( !_get_range_span(dr1, ii, dsr1.r1, dsr1.c1, dsr1.r2, dsr1.c2, ds1, pg1) )
			continue;
		
		for(int jj = 0; jj < dr2.GetNumRanges(); jj++ )
		{
			if ( !_get_range_span(dr2, jj, dsr2.r1, dsr2.c1, dsr2.r2, dsr2.c2, ds2, pg2) )
				continue;
			
			// same page and layer
			if ( pg1.GetName() == pg2.GetName() && ds1.GetName() == ds2.GetName() )
			{
				bool bRowRelated, bColRelated;
				
				bRowRelated = !(dsr1.r2 < dsr2.r1 || dsr2.r2 < dsr1.r1);
				bColRelated = !(dsr1.c2 < dsr2.c1 || dsr2.c2 < dsr1.c1);
				
				if ( bRowRelated && bColRelated )
					return true;
			}					
		}
	}
	
	return false;
}

static bool is_contain_range(const DataRange& drSub, const DataRange& dr)
{
	if ( !drSub || !dr )
		return false;
	
	DataSheetRange dsrSub, dsr;
	Datasheet dsSub, ds;
	Page pgSub, pg;
	
	if ( !_get_range_span(drSub, 0, dsrSub.r1, dsrSub.c1, dsrSub.r2, dsrSub.c2, dsSub, pgSub) )
		return false;
	
	if ( !_get_range_span(dr, 0, dsr.r1, dsr.c1, dsr.r2, dsr.c2, ds, pg) )
		return false;
	
	// same page and layer
	if ( pgSub.GetName() == pg.GetName() && dsSub.GetName() == ds.GetName() )
	{
		// dr contain drSub
		///---Sim 03-20-2007 FIX_BUG_OF_RANGE_FOR_REIMPORT
		//if (dsrSub.r1 >= dsr.r1 || dsrSub.r2 <= dsr.r2)
		if ( dsrSub.c1 >= dsr.c1 && dsrSub.c2 <= dsr.c2 )
		///---END FIX_BUG_OF_RANGE_FOR_REIMPORT
			return true;
	}		
	
	return false;
}
///---END MORE_UTILS_FUNCTION

int get_file_info_by_range(TreeNode& trFile, const DataRange& dr, int* pnErrCode) // = NULL
{
	//int nFNodeIndex = -1;
	//int nFNodeIndex = 0;
	Datasheet dsTemp;
	Page pgTarget;
	int c1 = 0, c2 = -1;
	//if( !dr.IsValid() && (0 == dr.GetNumData()) )
	if( !dr.IsValid() || (0 == dr.GetNumData()) ) /// Hong 01/09/08
	{
		/// Hong 05/30/07 OUTPUT_ERROR_CODE
		if ( pnErrCode )
			*pnErrCode = XFERR_REIMP_SELECT_NO_IMPORT_FILE;
		/// end OUTPUT_ERROR_CODE
		return 0;
	}
	
	dr.GetRange(dsTemp, c1, c2);
	dsTemp.GetParent(pgTarget);
	
	if( !pgTarget )
	{
		error_report(_L("The selected range is invalid!"));
		/// Hong 05/30/07 OUTPUT_ERROR_CODE
		if ( pnErrCode )
			*pnErrCode = XFERR_REIMP_SELECT_NO_IMPORT_FILE;
		/// end OUTPUT_ERROR_CODE
		return 0;
	}
	
	Tree trBinary;
	if( !tree_get_binary_storage(trBinary, pgTarget, IFI_BINARY_STORAGE_NAME) )
	{
		error_report(_L("No any file info in book organizer!"));
		/// Hong 05/30/07 OUTPUT_ERROR_CODE
		if ( pnErrCode )
			*pnErrCode = XFERR_REIMP_SELECT_NO_IMPORT_FILE;
		/// end OUTPUT_ERROR_CODE
		return 0;
	}
	
	//int nIndex = dsTemp.GetIndex();
	foreach(TreeNode tn in trBinary.Children)
	{
		//nFNodeIndex++;
		TreeNode trRange = tree_get_node_by_tagname(tn, "DataRange", true);
		if(!trRange.IsValid())
			continue;
		bool bValidRange = true;
		if( tn.Info.CoveredByAnotherImport ) // IW have no such node before we do clean 
			bValidRange = (0 == tn.Info.CoveredByAnotherImport.strVal.CompareNoCase("No"));
		
		if( !bValidRange )//|| !dr.IsValid() || (0 == dr.GetNumData()) )
			continue; // range isn't valid, go on next
		
		//Worksheet wksTemp;
		//int nStartCol, nEndCol;
		DataRange drExistent;
		drExistent = get_and_check_range(trRange, pgTarget.GetName());

		//dr.GetRange(wksTemp, nStartCol, nEndCol);
		
		//if( nIndex == wksTemp.GetIndex() && nStartCol <= c1 && tn.FilterInfo) // need more test for c2 later
		/// Hong 05/30/07 OUTPUT_ERROR_CODE
		//if ( is_contain_range(dr, drExistent) && tn.FilterInfo )		
		if ( is_contain_range(dr, drExistent) )
		{
			if ( tn.FilterInfo )
			{
		/// end OUTPUT_ERROR_CODE
				trFile = tn;
				/*
				// temporary code, hard code
				string str = trFile.tagName;
				if ( 0 == str.Find("File") )
					str.Delete(0, 4);
				nFNodeIndex = atoi(str);
				*/
				char szBuffer[MAXLINE];
				int nFNodeIndex = string_to_prefix_end_number(szBuffer, trFile.tagName);
				return nFNodeIndex;
			}
			/// Hong 05/30/07 OUTPUT_ERROR_CODE
			else
			{
				*pnErrCode = REIMP_NOT_SUPPORT_FORMAT;
				return 0;
			}
			/// end OUTPUT_ERROR_CODE
		}
	}	
	/// Hong 05/30/07 OUTPUT_ERROR_CODE
	if ( pnErrCode )
		*pnErrCode = XFERR_REIMP_SELECT_NO_IMPORT_FILE;
	/// end OUTPUT_ERROR_CODE
	error_report(_L("The selected range is invalid or cross over more than one file!"));
	error_report(_L("Please select again."));
	//return -1; // reach here mean not find, should return -1
	return 0; // reach here mean not find, should return 0
}

///End PLOT_SETUP_NEED_IMPORTED_FILE_INFO_FROM_SHEET


/// SY 10/13/2004 v8.0147 IMPORT_WIZARD_CLEANUP
// Move from App_Utils.c and change function name GetLayerNumbers to page_get_layer_numbers
/**
		Builds a list of the layer numbers in the active graph. The list is returned
		as a series of tokens separated by the | character. The active layer number
		is also returned.
	Example:
		string str;
		int iActive;
		iActive = page_get_layer_numbers(str);
	Return:
		Returns a list of the layer numbers in the active graph as a series of tokens
		separated by the | character. The layer number of the active layer is returned
		on success and -1 is returned on failure.
*/
int page_get_layer_numbers(string& strLayerNumbers)
{
	int iActive = -1;
	GraphPage gp;
	gp = (GraphPage) Project.Pages();
	if( gp.IsValid() )
	{
		for(int ii = 1; ii <= gp.Layers.Count(); ii++)
		{
			if( ii == 1 )
				strLayerNumbers.Format("%d", ii);
			else
				strLayerNumbers.Format("%s|%d", strLayerNumbers, ii);		
		}
		GraphLayer glLayer = gp.Layers();
		if( glLayer.IsValid() )
			iActive = glLayer.GetIndex();
	}

	return iActive;
}

// Move from Wks_Utils.c and change function name FindEmptyColumn to wks_find_empty_column
int wks_find_empty_column(Datasheet &dats, int nStartCol)
{
	/// Hong 06/28/07 v8.0651 ASCII_SUPPORT_IMPORT_TO_MATRIX_WITH_APPEND_COL
	/* move origin code to sheet_find_empty_dataobject
	///---Sim 09-01-2006 FIX_BUG_OF_RUNTIME_ERROR_WITH_INVALID_DATA_SHEET
	//if(dats)
	if ( dats && dats.IsValid() )
	///---END FIX_BUG_OF_RUNTIME_ERROR_WITH_INVALID_DATA_SHEET
		return dats.FindFirstEmpty(nStartCol);
	else
		///---Sim 11-29-2006 FIX_BUG_WHEN_DATASHEET_IS_INVALID		
		//return 0;
		return -1;
		///---END FIX_BUG_WHEN_DATASHEET_IS_INVALID		
	*/
	return sheet_find_empty_dataobject(dats, nStartCol);
	/// end ASCII_SUPPORT_IMPORT_TO_MATRIX_WITH_APPEND_COL
}
/// end IMPORT_WIZARD_CLEANUP
/// Hong 06/28/07 v8.0651 ASCII_SUPPORT_IMPORT_TO_MATRIX_WITH_APPEND_COL
int sheet_find_empty_dataobject(Datasheet& ds, int nStartObj) // = 0
{
	if ( ds && ds.IsValid() )
		return ds.FindFirstEmpty(nStartObj);
	else
		return -1;
}
/// end ASCII_SUPPORT_IMPORT_TO_MATRIX_WITH_APPEND_COL


//// AW 11/07/06 MORE_WORK_ON_SHOW_TIME_COL
bool wks_has_x(Worksheet& wks)
{
	if ( !wks )
		return false;
	if ( 0 == wks.FindFirstEmpty() )
		return false;
	int nCol = wks.GetNumCols();
	for (int ii = 0; ii < nCol; ii++ )
	{
		if ( wks.Columns(ii).GetType() == OKDATAOBJ_DESIGNATION_X )
			return true;
	}
	return false;
}
/// END MORE_WORK_ON_SHOW_TIME_COL

//----- CPY IMPORT_IMAGE_INTO_ACTIVE_SHOULD_USE_1ST_EMPTY_SHEET
/*
/// Sim 08-25-2006 COMMON_FUNC_WKS_EMPTY
int _is_sheet_empty(Layer &ly)
{
	Page pg;
	ly.GetParent(pg);
	if( !pg )
		return -1;
	int nPageType = pg.GetType();
	switch( nPageType )
	{
	case EXIST_WKS:
		Worksheet wks = ly;//pg.Layers();
		if( !wks )
			return -1;
		//----CPY 4/5/06 WKS_CAN_BE_CREATED_WITH_NO_COLS
		if(wks.GetNumCols() == 0)
			return 1;
		//----
		int nR1, nR2;
		if( !wks.GetBounds(nR1, 0, nR2, -1) )
			return -1;
		if( 0 == nR1 && -1 == nR2 )
			return 1;
		return 0;
		
	case EXIST_MATRIX:
		MatrixLayer ml = ly;//pg.Layers();
		if( !ml )
			return -1;
		if( ml.HasData() || ml.HasImage() )
			return 0;
		return 1;
	}
	return -1;
}
/// END COMMON_FUNC_WKS_EMPTY
*/

//---- CPY 11/3/06 SHEET_IS_EMPTY_IF_NO_COL_MAT_OBJ
/*
int is_sheet_empty(Layer& ly)
{
	Datasheet dats = ly;
	if ( dats && dats.IsValid() )
	{
		// let FindFirstEmpty to decide is a col or MatrixObject is empty
		int nC1 = wks_find_empty_column(dats, 0);
		///---Sim 11-2-2006 FIX_FOR_NONE_COLUMN_ON_SHEET
		//return nC1 == 0? 1:0;
		//// AW 11/02/06 MORE_ON_FIX_FOR_NONE_COLUMN_ON_SHEET
		//return (nC1 == 0) || (0 == dats.GetNumCols())? 1:0; // nC1 isn't 0 if none column on sheet
		return (nC1 <= 0) || (0 == dats.GetNumCols())? 1:0; // ************ need check if there is a better way
		/// END MORE_ON_FIX_FOR_NONE_COLUMN_ON_SHEET
		///---Sim 11-2-2006 FIX_FOR_NONE_COLUMN_ON_SHEET
	}
	return -1;
}
*/
///------ Folger 10/28/2010 ORG-1311-S2 COLMOVE_SUPPORT_MOVE_COLUMNS_TO_SPECIFIED_INDEX
//static int _get_num_objects(Datasheet& dats)
int get_num_objects(Datasheet& dats)
///------ End COLMOVE_SUPPORT_MOVE_COLUMNS_TO_SPECIFIED_INDEX
{
	MatrixLayer ml = dats;
	if(ml)
		return ml.MatrixObjects.Count();
	
	Worksheet wks = dats;
	if(wks)
		return wks.Columns.Count();
	out_str("_get_num_objects: invalid datasheet found");
	return 0;
}

bool is_sheet_empty(Layer& ly)
{
	Datasheet dats = ly;
	if ( dats && dats.IsValid() )
	{
		///------ Folger 10/28/2010 ORG-1311-S2 COLMOVE_SUPPORT_MOVE_COLUMNS_TO_SPECIFIED_INDEX
		//int nCols = _get_num_objects(dats);
		int nCols = get_num_objects(dats);
		///------ End COLMOVE_SUPPORT_MOVE_COLUMNS_TO_SPECIFIED_INDEX
		if(0 == nCols)
		{
			//out_str("sheet has no col mat");
			return true;
		}
		// let FindFirstEmpty to decide is a col or MatrixObject is empty
		int nC1 = wks_find_empty_column(dats, 0);
		return nC1 == 0? true:false;
	}
	out_str("is_sheet_empty found invalid datasheet");
	return false; // an invalid sheet, just make it not empty
}
//----- end SHEET_IS_EMPTY_IF_NO_COL_MAT_OBJ

///---Sim 01-02-2007 FIX_DETECT_EMPTY_BOOK
bool is_book_empty(Page &pg)
{
	int nNumLayers = pg.Layers.Count();
	if ( nNumLayers <= 0 )
		return false;
	
	for (int ii = 0; ii < nNumLayers; ii++ )
	{
		if ( !is_sheet_empty(pg.Layers(ii)) )
			return false;
	}
	
	return true;
}
///---END FIX_DETECT_EMPTY_BOOK


//----- end IMPORT_IMAGE_INTO_ACTIVE_SHOULD_USE_1ST_EMPTY_SHEET

//--- CPY 12/25/2007 
/// Hong 12/27/07 QA80-10625 FIX_EXCEL_EMPTY_SHEET_REPLACE_BY_FOLLOWING_SHEET
//int page_find_empty_sheet(Page& pg)
int page_find_empty_sheet(Page& pg, int nStartIndex) // = 0
/// end FIX_EXCEL_EMPTY_SHEET_REPLACE_BY_FOLLOWING_SHEET
{
	int nn = 0;
	foreach(Layer lay in pg.Layers)
	{		
		/// Hong 12/27/07 QA80-10625 FIX_EXCEL_EMPTY_SHEET_REPLACE_BY_FOLLOWING_SHEET
		if ( nn < nStartIndex )
		{
			nn++; /// Hong 12/28/07 v8.0776 EXCEL_OPEN_MULTI_IMPMODE_SUPPORT
			continue;
		}
		/// end FIX_EXCEL_EMPTY_SHEET_REPLACE_BY_FOLLOWING_SHEET
		if(is_sheet_empty(lay))
			return nn;
		
		nn++;
	}
	return -1;
}
//---


///---Sim 10-23-2006 SAME_LAYER_FUNCTION
bool is_same_layer(Layer &ly1, Layer &ly2)
{
	if ( !ly1 || !ly2 )
		return false;
	
	Page pg1, pg2;
	ly1.GetParent(pg1);
	ly2.GetParent(pg2);
	if ( !pg1 || !pg2)
		return false; // invalid pages
	
	string str1, str2;
	pg1.GetName(str1);
	pg2.GetName(str2);
	if ( str1 != str2 )
		return false; // different pages of layers
	
	if ( ly1.GetIndex() != ly2.GetIndex() )
		return false; // different layers;
	
	return true;	
}
///---END SAME_LAYER_FUNCTION


/// SY 12/15/2004 QA70-7258 v8.0175 IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID
DataRangeEx::DataRangeEx(TreeNode& tr, bool bUpdateTree) // = false
{
	m_bCreated = m_bSaved = false;
	if(tr.RangeGUID)
	{
		string strGUID = tr.RangeGUID.strVal;
		uint uUid = atoi(tr.RangeUID.strVal);
		
		*this = Project.GetObject(uUid, strGUID);
	
		if( bUpdateTree && IsValid())
		{
			tr.RangeUID.strVal = getUID(strGUID);
			tr.Range.strVal = getExcelRange();		
		}
	}
}

DataRangeEx::DataRangeEx()
{
	m_bCreated = m_bSaved = false;
}

DataRangeEx::~DataRangeEx()
{
	if( m_bCreated && !m_bSaved )
		Destroy();
}

static string _getDefaultRangeTagName() { return "Range1";}

int	DataRangeEx::Add(LPCSTR lpcszRange, LPCSTR lpcszName) //=NULL
{
	string strTagName = lpcszName==NULL?  _getDefaultRangeTagName(): lpcszName;
	int nRet = DataRange::Add(strTagName, lpcszRange);
	
	if( nRet >0 )
		m_bCreated = true;
	
	return nRet;
}

int	DataRangeEx::Add(Worksheet& wks, int nR1, int nC1, int nR2, int nC2, LPCSTR lpcszName) //=NULL
{
	string strTagName = lpcszName==NULL? _getDefaultRangeTagName() : lpcszName;
	int nRet = DataRange::Add(strTagName, wks, nR1, nC1, nR2, nC2);
	
	if( nRet >0 )
		m_bCreated = true;
	
	return nRet;
}

// Create datarange
bool DataRangeEx::Create(TreeNode& tr, bool bOneData) // = TRUE
{
	bool bRet = DataRange::Create(tr, bOneData);
	
	if( bRet )
	{
		ASSERT(!m_bCreated);
		m_bCreated = true;
	}
	
	return bRet;
}

bool DataRangeEx::Save()
{
	if( IsValid() )
	{
		m_bSaved = true;
		return Project.AddDataRange(*this);
	}
	
	return false;
}

// Get c1 c2 of data range
bool DataRangeEx::GetRange(int& c1, int& c2, int nIndex) // = 0
{
	ASSERT( IsValid() );
	
	Worksheet wkstmp;
	int r1, r2;
	
	return GetRange(nIndex, r1, c1, r2, c2, wkstmp);
}
//----- CPY 8/9/06 WKS_DATASHEET_CLEAN_UP
/*
// Get worksheet of data range
bool DataRangeEx::GetRange(Worksheet& wks, int nIndex) // = 0
{
	ASSERT( IsValid() );
	
	int c1, c2, r1, r2;
	
	return GetRange(nIndex, r1, c1, r2, c2, wks);
}
*/
bool DataRangeEx::GetRange(Datasheet& ds, int nIndex) // = 0
{	
	int c1, c2;
	
	return GetRange(ds, c1, c2, nIndex);
}
//------

string DataRangeEx::getUID(string& strGUID) 
{
	uint uid = this->GetUID(true, &strGUID);
	return (string)uid;
}

string DataRangeEx::getExcelRange(LPCSTR lpcszName) // = NULL
{
	string strTagName = lpcszName==NULL? _getDefaultRangeTagName() : lpcszName;
	ASSERT( IsValid() );
	
	Tree trExcelRange;
	GetTree(trExcelRange);
	
	string strNamedExcelRange;
	trExcelRange.GetValue(strNamedExcelRange, strTagName);
	return strNamedExcelRange
}

void DataRangeEx::PrepareTree(TreeNode& tr)
{
	string strGUID;
	tr.RangeUID.strVal = getUID(strGUID);
	tr.RangeGUID.strVal = strGUID;
	tr.RangeUID.Show = false;
	tr.RangeGUID.Show = false;
	tr.Range.strVal = getExcelRange();
}

/// end IMPORT_INFO_RESET_AND_DATARANGE_SAVEAS_UID


BOOL	make_column_range_string(string &str, const Column& col, int r1, int r2)// = 1 = 0);
{
	Worksheet wks;
	col.GetParent(wks);
	if( !wks )
		return FALSE;
	
	Page pg;
	wks.GetParent(pg);
	if( !pg )
		return FALSE;
	
	string strBook;
	string strSheet;
	wks.GetName(strSheet);
	pg.GetName(strBook);
	string strColumn = col.GetName();
	okutil_create_complete_range_string_col_row(&str, strBook, strSheet, strColumn, r1, strColumn, r2);
	return TRUE;
}





// It retrieves only book and sheet.
BOOL	get_book_sheet_info(string &strBookName, string &strSheetName, LPCSTR lpcszString)
{
	/// ML 1/13/2006 XVARIABLEBASE_TO_VC
	/////-----Frank 4/12/05 MAKE_EXISTING_WORK_FOR_VAR_DATA_IN_XYRANGE
	/////Because there are two type of display name ...
	////return parse_one_excel_formatted_string(lpcszString, strBookName, strSheetName);
	//if(!parse_one_excel_formatted_string(lpcszString, strBookName, strSheetName))
	//		return parse_one_xyrange_formatted_string(lpcszString, strBookName, strSheetName);
	//
	/////-----End MAKE_EXISTING_WORK_FOR_VAR_DATA_IN_XYRANGE
	//return true;
	//
	return okutil_get_book_sheet_info(&strBookName, &strSheetName, lpcszString);
	/// end XVARIABLEBASE_TO_VC
}

BOOL	get_book_sheet_info(string &strBookName, string &strSheetName, const TreeNode &trvladata)
{
	TreeNode	tr = trvladata;
	TreeNode	trX = tr.X;
	if ( !trX.IsValid() )
		return error_report("Cannot get book sheet info!");
	
	string		str = trX.strVal;
	
	/// ML 1/13/2006 XVARIABLEBASE_TO_VC
	//return get_book_sheet_info(strBookName, strSheetName, str);
	return okutil_get_book_sheet_info(&strBookName, &strSheetName, str);
	/// end XVARIABLEBASE_TO_VC
}





//---------- CPY 4/16/05 ACTIVE_BOOK_SHEET_AS_DEFAULT_FOR_XF
//if (PDS_NEW != nSheetMode)
//	indexCol = wks.Columns.Count();		// if not new sheet, it should not reuse existing columns
//
// we should always make use of 1st empty col in wks
/// YuI 05/23/05 XVARIABLE_SAME_IMPLEMENTATION
//	int find_begin_of_empty_cols_from_right(Worksheet& wks)
int find_begin_of_empty_cols_from_right(Worksheet& wks, int nStartWith)
/// end XVARIABLE_SAME_IMPLEMENTATION
{
	vector<int> vnColSizes;
	foreach(Column cc in wks.Columns)
	{
		vnColSizes.Add(cc.i2);
	}
	if(vnColSizes.GetSize() < 1)
		/// YuI 05/23/05 XVARIABLE_SAME_IMPLEMENTATION
		//return 0;
		return nStartWith;
		/// end XVARIABLE_SAME_IMPLEMENTATION

	/// YuI 05/23/05 XVARIABLE_SAME_IMPLEMENTATION
	/*
	for(int ii = vnColSizes.GetSize() -1; ii >= 0; ii--)
	{
		if(vnColSizes[ii] >= 0)
			return ii+1;
	}
	return 0;
	*/
	for(int ii = vnColSizes.GetSize() - 1; ii >= nStartWith;  ii--)
	{
		if(vnColSizes[ii] >= 0)
			return ii+1;
	}
	
	return nStartWith;
	/// end XVARIABLE_SAME_IMPLEMENTATION
}
/// YuI 05/23/05 XVARIABLE_SAME_IMPLEMENTATION
//	static int _find_new_col_index(Worksheet& wks, int nPredefinedType)
static int _find_new_col_index(Worksheet& wks, int nPredefinedType, int nStartWith)
/// end XVARIABLE_SAME_IMPLEMENTATION
{
	if(PDS_NEW == nPredefinedType)
		return 0;// new sheet, no need to check, always use 1st col
	
	//return find_begin_of_empty_cols_from_right(wks);
	return find_begin_of_empty_cols_from_right(wks, nStartWith);
}
#define GWMP_RET_ACTIVE_GRAPH	(-100)

//----------


/// YuI 06/29/05 XVARIABLE_ACTIVE_CLEANUP
BOOL	copy_plot_uid_from_tree_to_tree(TreeNode& trDest, TreeNode& trSource)
{
	int nPlotUID;
	if( get_plot_uid_from_tree(trSource, nPlotUID) )
	{
		set_plot_uid_to_tree(trDest, nPlotUID);
		return TRUE;
	}
	
	return FALSE;
}

BOOL	get_plot_uid_from_tree(TreeNode& tr, int& nPlotUID)
{
	return tr.GetAttribute(STR_PLOTOBJ_UID_ATTRIB, nPlotUID);
}

void	set_plot_uid_to_tree(TreeNode& tr, int nPlotUID)
{
	tr.SetAttribute(STR_PLOTOBJ_UID_ATTRIB, nPlotUID);
}

BOOL	get_data_plot_from_range_tree(TreeNode& tr, DataPlot& dp)
{
	int nPlotUID;
	if( get_plot_uid_from_tree(tr, nPlotUID) )
	{
		dp = Project.GetObject(nPlotUID);
		return dp.IsValid();
	}
	///Sohy 4/25/08 ROW_STATS_PUT_RESULTS_COL_TO_BEGINNING_OF_SRC_SHEET
	//else if( tr.X && cvt_str_to_predefined_type(tr.X.strVal) == PDS_ACTIVE )
	else if( tr.X && str_to_predefined_type(tr.X.strVal) == PDS_ACTIVE )
	///end ROW_STATS_PUT_RESULTS_COL_TO_BEGINNING_OF_SRC_SHEET
	{
		GraphLayer gl = Project.ActiveLayer();
		if( !gl )
			return error_report("Non-graph window is active");

		dp = gl.DataPlots(-1);
		return dp.IsValid();
	}
	
	return FALSE;
}
/// end XVARIABLE_ACTIVE_CLEANUP


/// end GENERAL_X_STRING_CONVENTION_TO_ACCESS_OBJECTS
bool	init_data_range_from_data_object(DataRange& dr, DataObject& obj)
{
	Datasheet ds;
	obj.GetParent(ds);
	if( !ds )
		return FALSE;

	string 	strRange = make_range_string(ds, obj.GetName());
	return dr.AddInput(strRange);
}

//int dataplot_set_colormap(DataPlot& dp, double dMin, double dMax, const vector<double>& vzPercents, const vector<uint> vcz, uint ncAbove, uint ncBelow, bool bContourLines)
///Sandy 2007-1-30 MODIFY_SETTING_DEFAULT_TO_SUPPORT_NO_CHANGE
//int dataplot_set_colormap(DataPlot& dp, const vector<double>& vzLevels, const vector<uint>& vzColors, uint ncAbove, uint ncBelow, bool bContourLines, bool bLogScale)
/// Iris 02/28/2008 v8.0813 NEW_FUNC_TO_SET_CONTOUR_LINES
//int dataplot_set_colormap(DataPlot& dp, const vector<double>& vzLevels, const vector<uint>& vzColors, uint ncAbove, uint ncBelow, int nModifyContourLines, int nLogScale);
int dataplot_set_colormap(DataPlot& dp, const vector<double>& vZLevels, const vector<uint>& vnFillColors, uint ncAbove, uint ncBelow, int nModifyContourLines, int nLogScale, const vector<uint>& vnLineColors, const vector<uint>& vnLineStyles, const vector<double>& vLineThickness)
///end NEW_FUNC_TO_SET_CONTOUR_LINES
{
	if(!dp)
		return -1;
	
	if(vZLevels.GetSize() != vnFillColors.GetSize() + 1)
		return -2;
	
	//set z Levels
	/// Iris 02/28/2008 v8.0813 NEW_FUNC_TO_SET_CONTOUR_LINES, to fix set colormap twice when nLogScale >= 0
	/*	
	///Sandy 2007-1-30 MODIFY_SETTING_DEFAULT_TO_SUPPORT_NO_CHANGE	
	//if(!dp.SetColormap(vzLevels, bLogScale))
	//	return -3;	
	/// Iris 01/30/2007 FIX_RUNTIME_ERROR_AFTER_SANDY_CHANGE
	// import XYZ Regular.dat, and open Surface Fit with Chebyshev2D function ==> Got runtime error.
	if(!dp.SetColormap(vzLevels))
		return -3;		
	///end FIX_RUNTIME_ERROR_AFTER_SANDY_CHANGE
	if(nLogScale != -1)
	{
		bool bSet = (nLogScale == 1 ? true: false);
		if(!dp.SetColormap(vzLevels, bSet))
			return -3;		
	}
	*/
	///Kyle 09/03/2010 ORG-969-P1 CLEANUP_OC_ACCESS_TO_DATAPLOT_COLORMAP, nLogScale is not used now
	//bool 	bSetLog = nLogScale <= 0? false : true;
	//if(!dp.SetColormap(vZLevels, bSetLog))
	if( !dp.SetColormap(vZLevels) )
	///End CLEANUP_OC_ACCESS_TO_DATAPLOT_COLORMAP
		return -3;
	///end NEW_FUNC_TO_SET_CONTOUR_LINES	
		
	
	Tree tr;	
	///Sandy 2007-1-30 MODIFY_SETTING_DEFAULT_TO_SUPPORT_NO_CHANGE
	//turn on/off contour lines
	/*	vector<int> vecLines;
		vecLines.SetSize(vzColors.GetSize());
		vecLines = bContourLines? 1:0;
		tr.ColorMap.Details.ShowLines.nVals = vecLines;
		// in order to keep all the vectors the same size, the last line entry is pushed
		// into Above section, as separate items
		tr.ColorMap.Details.AboveLine.nVal = bContourLines;
	*/
	if(nModifyContourLines != -1)
	{

		vector<int> vecLines;
		vecLines.SetSize(vnFillColors.GetSize());
		vecLines = nModifyContourLines? 1:0;
		tr.ColorMap.Details.ShowLines.nVals = vecLines;
		// in order to keep all the vectors the same size, the last line entry is pushed
		// into Above section, as separate items
		tr.ColorMap.Details.AboveLine.nVal = nModifyContourLines;
	}
	///end MODIFY_SETTING_DEFAULT_TO_SUPPORT_NO_CHANGE
	
	//set Color
	tr.ColorMap.Details.BelowColor.nVal = ncBelow; 
	tr.ColorMap.Details.AboveColor.nVal = ncAbove; 
	tr.ColorMap.Details.Colors.nVals = vnFillColors;
	
	/// Iris 02/28/2008 v8.0813 NEW_FUNC_TO_SET_CONTOUR_LINES
	_update_colormap_tree_about_lines(tr, vnLineColors, vnLineStyles, vLineThickness);
	///end NEW_FUNC_TO_SET_CONTOUR_LINES
	
	/// Iris 2/19/2009 ACCORDING_TO_COLORMAP_FORMAT_TREE_STRUCT_CHANGE
	//tr.Colormap.ColorFillControl.nVal = 1; //--CPY 4/1/08 ARVIN_FOUND_SURFACE_FIT_PREVIEW_NOT_SHOWING_SRC_CONTOUR
	_change_enable_colormap_fill_color_treenode(dp, tr, true);
	///end ACCORDING_TO_COLORMAP_FORMAT_TREE_STRUCT_CHANGE
	
	if(!dp.SetColormap(tr))
		return -4;
	
	// update color scale object
	_update_color_scale_object(dp);
	
	return 0;	
}

/// Iris 2/19/2009 ACCORDING_TO_COLORMAP_FORMAT_TREE_STRUCT_CHANGE
// nType(1 or 2) only used for matrix contour and when bEnable is true. Please see #13143 for details
static bool _change_enable_colormap_fill_color_treenode(DataPlot& dp, TreeNode& tr, bool bEnable, int nType = 1)
{
	if(!dp || !tr)
		return false;
	
	DataPlotStrings  stDescStrs;
	dp.GetPlotType(&stDescStrs);
	string strBookName = stDescStrs.szWorkBook;
	Page pg(strBookName);
	if( !pg )
		return false;
	
	if(EXIST_MATRIX == pg.GetType() )
	{
		if(!bEnable)
			nType = 0;
		tr.Colormap.ColorFillControl.nVal = nType;
	}
	else if(EXIST_WKS == pg.GetType() )
	{
		tr.Colormap.ColorFillCheck.nVal = bEnable;
	}
	return true;	
}
///end ACCORDING_TO_COLORMAP_FORMAT_TREE_STRUCT_CHANGE

/// Iris 02/28/2008 v8.0813 NEW_FUNC_TO_SET_CONTOUR_LINES
static void _update_color_scale_object(DataPlot& dp)
{
	if(dp)
	{
		GraphLayer gl;
		dp.GetParent(gl);
		GraphObject grBand = gl.GraphObjects("Spectrum1");
		if(grBand)
			grBand.Invalidate();
	}
}
///Sophy 2/11/2009 QA80-13020-S1 v8.0976c HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST_AS_CP_SUGGEST
//static void _update_colormap_tree_about_lines(TreeNode& tr, const vector<uint>& vnColors = NULL, const vector<uint>& vnStyles = NULL, const vector<double>& vThickness = NULL)
static void _update_colormap_tree_about_lines(TreeNode& tr, const vector<uint>& vnColors = NULL, const vector<uint>& vnStyles = NULL, const vector<double>& vThickness = NULL, const vector<uint>& vnShowLines = NULL)
///end HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
{
	
	if(vnColors)
	{
		//---- CPY 3/1/08 QA70-11205 OC_SET_LINES_PROBLEMS
		vector<int> vLines; vLines.SetSize(vnColors.GetSize());
		///Sophy 2/11/2009 QA80-13020-S1 v8.0976c HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
		//vLines = 1;
		if ( vnShowLines )
			vLines = vnShowLines;
		else
			vLines = 1;
		///end HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
		tr.ColorMap.Details.ShowLines.nVals = vLines;
		//----
		tr.ColorMap.Details.LineColors.nVals = vnColors;
	}
	
	if(vnStyles)
		tr.ColorMap.Details.LineStyles.nVals = vnStyles;
	
	if(vThickness)
		tr.ColorMap.Details.LineWidths.dVals = vThickness;	
}

///Sophy 2/11/2009 QA80-13020-S1 v8.0976c HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
//int set_contour_lines(DataPlot& dp, const vector<double>& vLevels, const vector<uint>& vnColors, const vector<uint>& vnStyles, const vector<double>& vThickness, bool bRemoveFill)
int set_contour_lines(DataPlot& dp, const vector<double>& vLevels, const vector<uint>& vnColors, const vector<uint>& vnStyles, const vector<double>& vThickness, const vector<uint>& vnShowLines, bool bRemoveFill)
///end HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
{
	if(!dp)
		return -1;
	if(vLevels.GetSize() != vnColors.GetSize() + 1)
		return -2;
	
	if(vnStyles && vnStyles.GetSize() != vnColors.GetSize())
		return -3;
	
	if(vThickness && vThickness.GetSize() != vnColors.GetSize())
		return -4;
	
	///Sophy 2/11/2009 QA80-13020-S1 v8.0976c HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
	if( vnShowLines && vnShowLines.GetSize() != vnColors.GetSize() )
		return -5;
	///end HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
	// DataPlot::GetColormap(TreeNode& trColormap) and DataPlot::SetColormap(TreeNode& trColormap) fail to correct Z range level by "tr.ColorMap.Details.Levels.dVals"
	// So use DataPlot(const vector<double>& vz, BOOL bLogScale=FALSE) separately here
	if(!dp.SetColormap(vLevels))
		return -6;
		
	Tree tr;	
	///Sophy 2/11/2009 QA80-13020-S1 v8.0976c HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
	//_update_colormap_tree_about_lines(tr, vnColors, vnStyles, vThickness);
	_update_colormap_tree_about_lines(tr, vnColors, vnStyles, vThickness, vnShowLines);
	///end HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
	
	if(bRemoveFill)
	{
		/// Iris 2/19/2009 ACCORDING_TO_COLORMAP_FORMAT_TREE_STRUCT_CHANGE
		//tr.Colormap.ColorFillControl.nVal = 0;
		_change_enable_colormap_fill_color_treenode(dp, tr, false);
		///end ACCORDING_TO_COLORMAP_FORMAT_TREE_STRUCT_CHANGE
	}
	
	if(!dp.SetColormap(tr))
		return -7;
	
	// update color scale object
	_update_color_scale_object(dp);
	
	return 0;
}
///end NEW_FUNC_TO_SET_CONTOUR_LINES

//---------- CPY 3/39/08 SURFACE_FIT_USE_COLOR_CONTOUR_FOR_SRC_DATA
bool rescale_init_colormap(DataPlot& dp, vector* pz, int nSteps, bool bGrayScale)
{
	string strDatasetName = dp.GetDatasetName();
	/// YuI 01/26/09 QA70-13023 MATRIX_FIT_IN_IMAGE_FORM_PROBLEMS
	//	Dataset zz(strDatasetName); // assume double or mixed, otherwise will need new function for DatasetObject
	DatasetObject zz(strDatasetName);
	/// end MATRIX_FIT_IN_IMAGE_FORM_PROBLEMS
	if(!zz)
		return error_report("failed to get dataset from data plot, maybe not double or T&N type");
	
	double z1,z2, zInc = 0;
	/// YuI 01/26/09 QA70-13023 MATRIX_FIT_IN_IMAGE_FORM_PROBLEMS
	//	zz.GetMinMax(z1, z2);
	if( !zz.GetMinMax(z1, z2) )
	{
		return error_report("failed to get Z scale from dataset");
	}
	/// end MATRIX_FIT_IN_IMAGE_FORM_PROBLEMS
	RoundLimits(&z1, &z2, &zInc, nSteps);
	if(pz)
	{
		vector& zz = *pz;
		zz.SetSize(3);
		zz[0] = z1;
		zz[1] = z2;
		zz[2] = zInc;
	}
	// contour levels for the contour plot
	vector vLevels;vLevels.Data(z1, z2, zInc);
	vector<uint> vColors;
	int nLevels = vLevels.GetSize();
	if(nLevels < 2)
		return error_report("too few contour levels");
	
	vColors.SetSize(nLevels-1);
	if(bGrayScale)
	{
		for(int ii = 0; ii < vColors.GetSize(); ii++)
		{
			int gg = 255* ii / (nLevels-1);
			int nRGB = RGB(gg, gg, gg);
			vColors[ii] = RGB2OCOLOR(nRGB);
		}
	}
	else // color, Red->Blue with Green Mixed
		///Kyle 07/17/2009 QA80-13970 COLOR_LIST_SHOULD_BE_CONSISTENT_WITH__DEFAULT_TEMPLETE, Blue->Red
		//colormap_rgb_ramp(RGB(255,0,0), RGB(0,0,255), vColors.GetSize(), vColors, true);
		colormap_rgb_ramp(RGB(0,0,255), RGB(255,0,0), vColors.GetSize(), vColors, true);
		///End COLOR_LIST_SHOULD_BE_CONSISTENT_WITH__DEFAULT_TEMPLETE
	
	//nModifyContourLines = 0 to turn off contour lines
	int nErr = dataplot_set_colormap(dp, vLevels, vColors, SYSCOLOR_WHITE, SYSCOLOR_BLACK, 0);
	if(nErr != 0)
		return error_report("dataplot_set_colormap err = " + (string)nErr);
	
	return true;
}
// zz are obtained from rescale_init_colormap's pz output
bool setup_fit_contour(DataPlot& dp, vector& zz, int nColor) 
{
	double z1 = zz[0];
	double z2 = zz[1];
	double zInc = zz[2];
	vector vLevels;
	vector<uint> vColors;
	vLevels.Data(z1, z2, zInc);
	int nLevels = vLevels.GetSize();
	if(nLevels < 2)
	{
		string strErr;
		strErr.Format("bad z range, z1=%f,z2=%f,zInc=%f\n", z1, z2, zInc);
		return error_report(strErr);
	}
	
	double zmiddle = z1 + (z2-z1)/2;
	vColors.SetSize(nLevels-1); // number of lines = number of fill colors, line above last is separtely controlled
	vColors = nColor;
	int nErr = set_contour_lines(dp, vLevels, vColors);
	if(nErr != 0)
	{
		out_int("set_contour_lines err = ", nErr);
		return false;
	}
	return true;
}

///Sophy 2/16/2009 v8.0979b QA80-13121 CUSTOM_LEGEND_NEED_SIMPLER_LINE_SUPPORT
#define	STR_LEGEND_RESIDUAL_TITLE		_L("Residual Contour Lines\n")
#define STR_LEGEND_BLUE_LINE_FORMAT		"\l(L 4) %s"
#define STR_LEGEND_RED_LINE_FORMAT		"\l(L 2) %s"
#define STR_OUTER_LIMIT					_L("Outer limit")
#define STR_ABOVE						_L("Above")
#define	STR_BELOW						_L("Below")
///end CUSTOM_LEGEND_NEED_SIMPLER_LINE_SUPPORT
// irl = Inner Residual Limit
// orl = Outer Residual Limit
// both expressed in percent of source data's Z range which is in zz[1] and zz[0]
///Sophy 2/11/2009 QA80-13020-S1 v8.0976c HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
//bool setup_residual_contour(DataPlot& dp, vector& zz, double irl, double orl, int nInnersteps, int nOutSteps) 
bool setup_residual_contour(DataPlot& dp, vector& zz, double irl, double orl, int nInnersteps, int nOutSteps, bool bShowLines)  //true
///end HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
{
	if(irl >= orl)
		return error_report("inner residual limit must be smaller then the outer one");
	
	double dataScaleRange = fabs(zz[1] - zz[0]);
	double z1 = -dataScaleRange;
	double z2 = dataScaleRange;
	double zInc = 0;
	double f1 = irl * z2/100.; // residual limits, inner
	double f2 = orl * z2/100.; // residual limits, outer
	RoundLimits(&f1, &f2, &zInc, nOutSteps); 
	vector v3; v3.Data(f1, f2, zInc);
	vector v1; v1.Data(-f2, -f1, zInc);
	
	double zInnerInc = 2*f1/nInnersteps;// inner range inc
	vector v2; v2.Data(-f1+zInnerInc, f1-zInnerInc, zInnerInc);
	vector vLevels;
	vLevels = v1;
	vLevels.Append(v2);
	vLevels.Append(v3);
	int nLevels = vLevels.GetSize();
	vector<uint> vColors;
	vColors.SetSize(nLevels-1); // number of lines = number of fill colors, line above last is separtely controlled
	int c1 = SYSCOLOR_BLUE, c2 = SYSCOLOR_BLACK, c3 = SYSCOLOR_RED; 
	int nBlueLines = 0, nBlackLines = 0, nRedLines = 0;	///Sophy 2/16/2009 QA80-13020-S1 v8.0976c HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
	for(int ii = 0; ii < vColors.GetSize(); ii++)
	{
		if(vLevels[ii] < -f1)
		{
			vColors[ii] = c1;
			nBlueLines++;
		}
		else if(vLevels[ii] > f1)
		{
			vColors[ii] = c3;
			nRedLines++;
		}
		else
		{
			vColors[ii] = c2;
			nBlackLines++;
		}
	}
	///Sophy 2/11/2009 QA80-13020-S1 v8.0976c HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
	//int nErr = set_contour_lines(dp, vLevels, vColors);
	vector<uint> vShowLines;
	///Sophy 2/16/2009 QA80-13020-S1 v8.0976c HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
	//vShowLines.SetSize(vColors.GetSize());
	//vShowLines = 0;
	//int nErr = bShowLines ? set_contour_lines(dp, vLevels, vColors) : set_contour_lines(dp, vLevels, vColors, NULL, NULL, vShowLines);
	vector<int> vnShowHideColor;
	vnShowHideColor.SetSize(nBlueLines);
	vnShowHideColor = 1; //show all blue lines
	vShowLines.Append(vnShowHideColor);
	
	vnShowHideColor.SetSize(nBlackLines);
	vnShowHideColor = 0; //hide all black lines
	vShowLines.Append(vnShowHideColor);
	
	vnShowHideColor.SetSize(nRedLines); //skip last line's show hide setting.
	vnShowHideColor = 1;
	vShowLines.Append(vnShowHideColor);
	int nErr = set_contour_lines(dp, vLevels, vColors, NULL, NULL, vShowLines);
	//end HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
	///end HIDE_CONTOUR_LINES_FOR_3D_FITTING_RESIDUAL_PLOT_AS_CP_SUGGEST
	if(nErr != 0)
	{
		out_int("set_contour_lines err = ", nErr);
		return false;
	}
	///Sophy 2/16/2009 v8.0979b QA80-13121 CUSTOM_LEGEND_NEED_SIMPLER_LINE_SUPPORT
	GraphLayer gl;
	dp.GetParent(gl);
	if ( gl )
	{
		GraphObject goLegend = gl.GraphObjects("ContourL");
		if ( goLegend )
		{
			string strOneLine;
			string strLineInfo;
			string strLegend = STR_LEGEND_RESIDUAL_TITLE;
			
			strLineInfo.Format("%s %s(%.1lf%% %s)", STR_ABOVE, ftoa(f1, "*4*"), orl - irl, STR_OUTER_LIMIT);
			strOneLine.Format(STR_LEGEND_RED_LINE_FORMAT, strLineInfo);
			strLegend += strOneLine;
			strLegend += "\n";
			
			strLineInfo.Format("%s %s(-%.1lf%% %s)", STR_BELOW, ftoa(-f1, "*4*"), orl - irl, STR_OUTER_LIMIT);
			strOneLine.Format(STR_LEGEND_BLUE_LINE_FORMAT, strLineInfo);
			strLegend += strOneLine;
			
			goLegend.Text = strLegend;
		}
	}
	///end CUSTOM_LEGEND_NEED_SIMPLER_LINE_SUPPORT
	return true;
}
//-------- end SURFACE_FIT_USE_COLOR_CONTOUR_FOR_SRC_DATA

bool page_insert_label(Layer& layer, const string& strLabel, LPCSTR lpcszName, int x, int y) // =NULL = 10, =5
{
	/// Iris 12/19/05 QA70-7703 CHECK_IS_OBJECT_VALID
	if(!layer) 
		return false;
	if(strLabel.IsEmpty())
		return false;
	///End CHECK_IS_OBJECT_VALID

	string strLT;
	string strName;
	if(lpcszName)
	{
		strName = "-n ";
		strName += lpcszName;
	}
	strLT.Format("Label -p %d %d %s \"%s\"", x, y, strName, strLabel);
	
	return layer.LT_execute(strLT);
}


static string	_specifier_get_name(TreeNode& tr)
{
	if( tr.name )
		return tr.name.strVal;
	
	return "";
}

static string	_specifier_get_template(TreeNode& tr)
{
	if( tr.template )
		return tr.template.strVal;
	
	return "";
}

static int		_specifier_get_show(TreeNode& tr)
{
	if( tr.show )
		return tr.show.nVal;
	
	return 1; //default value for show
}



BOOL	data_plot_update_xy_data_range_tree(DataPlot& dp, TreeNode& tr)
{
	if( !dp )
		return FALSE;
	
	return dp.UpdateXYDataRangeTree(tr);
}


string	_get_column_description(int nColIndex)
{
	string strReturn;
	strReturn.Format("Col(%d)", nColIndex + 1);
	return strReturn;
}

string	_get_column_description(Column col)
{
	return _get_column_description(col.GetIndex());
}

// It returns true if the string in form "Col(name or number)".
//	#define		STR_DATA_COL_BEG		"Col("
#define		STR_DATA_COL_BEG		"COL("
bool	is_Col_str(const string &str)
{
	//string		str = lpcszStr;
	//	int			nPos = str.Find(STR_DATA_COL_BEG);
	string strTemp = str;
	strTemp.MakeUpper();
	int			nPos = strTemp.Find(STR_DATA_COL_BEG);
	if (nPos != 0)
		return false;
	
	return true;	// no checking for closing paranth. for now
}


///Iris 3/17/05 QA70-7493 BUILD_XVAR_DATA_BRANCH
string  page_get_layer_names(Page& pg, bool bIncHierarchy)
{
	string str = "|";
	string strNames;
	
	int ii=0;
	while(1)
	{
		Layer layer = pg.Layers(ii++);
		if(layer)
		{
			//---- Iris 04/19/2007 v8.0604 need to skip hierarchy sheet sometimes
			//strNames += layer.GetName() + str;
			if( layer.GetSystemParam(0) & WP_SHEET_HIERARCHY )
			{
				if(bIncHierarchy)
				{
					strNames += layer.GetName() + str;
				}
			}
			else
			{
				strNames += layer.GetName() + str;
			}
			//----
		}
		else
		{
			strNames.TrimRight(str);		
			break;
		}
	}
	return strNames;
}


//---- CPY 5/14/05
bool get_layer_rect_page_units(const GraphLayer& grl, int& nLeft, int& nTop, int& nRight, int& nBottom)
{
	if(!grl)
		return false;
	
	Scale		scX(grl.X);
	Scale		scY(grl.Y);
	double		rLeft = scX.From;
	double		rRight = scX.To;
	double		rTop = scY.To;
	double		rBottom = scY.From;

	grl.WorldToPage(nLeft, nTop, rLeft, rTop);
	grl.WorldToPage(nRight, nBottom, rRight, rBottom);
	int nn;
	if(nRight < nLeft)
	{
		SWAP(nLeft, nRight, nn);
	}
	if(nTop > nBottom)
	{
		SWAP(nTop, nBottom, nn);
	}
	return true;
}


GraphObject create_rect_object(GraphLayer gl, double left, double top, double dx, double dy)
{
	GraphObject	gr = gl.CreateGraphObject(GROT_RECT);
	//gr.SetName(strName);
	int			nLeft, nTop, nRight, nBottom;
	get_layer_rect_page_units(gl, nLeft, nTop, nRight, nBottom);
	int nWidth = dx * (nRight - nLeft);
	int nHeight = dy * (nBottom - nTop);
	//printf("width = %d, height = %d\n", nWidth, nHeight);
	// when newly created, somehow need to set Left/Top first, and then set width/height, then later to set Left/Top to
	// properly to set its Rect
	gr.Left = nLeft;
	gr.Top = nTop;
	gr.Width = nWidth;
	gr.Height = nHeight;
	gr.Top = nTop + (nBottom - nTop) * top;
	gr.Left = nLeft + (nRight - nLeft) * left;
	return gr;
}

//---- end CPY 5/14/05

//---- CPY QA70-7820 6/22/05
bool get_wks_col(LPCSTR lpcszDataset, Column& cc, Worksheet& wks)
{	
	cc = Project.GetDataObject(lpcszDataset);
	if(cc)
	{
		cc.GetParent(wks);
		return true;
	}
	return false;
}

//------ Folger 08/14/07 SUPPORT_GET_DATASHEET_DATAOBJECT_FROM_DATASET
bool get_datasheet_dataobj(LPCSTR lpcszDataset, DataObject &dataObj, Datasheet &ds)
{
	dataObj = Project.GetDataObject(lpcszDataset);
	if (dataObj)
	{
		dataObj.GetParent(ds);
		return true;
	}
	return false;
}
//------ End SUPPORT_GET_DATASHEET_DATAOBJECT_FROM_DATASET

///------ Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
static	BOOL	_check_get_sheet_by_index(Datasheet& ds, Page& pg, string& strSheet)
{
	if ( !is_str_numeric_integer(strSheet) )
	{
		okutil_check_remove_quotes(&strSheet);
		return FALSE;
	}

	int		nIndex = atoi(strSheet) - 1;
	int		nCount = pg.Layers.Count();
	while ( nIndex >= nCount++ )
		pg.AddLayer();
	
	ds = pg.Layers(nIndex);
	return TRUE;
}
///------ End GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION

//	attach a Worksheet object by [Book]Sheet specification. Create if not found
///------ Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
//bool attach_or_create_sheet(Datasheet& wks, LPCSTR lpcszBookSheetName, int nCreate, bool bMatrixSheet)
bool attach_or_create_sheet(Datasheet& wks, LPCSTR lpcszBookSheetName, int nCreate, bool bMatrixSheet, BOOL* pbIsNewCreated/* = NULL*/)
///------ End GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
{
	if(wks == NULL)
		return false;

	///------ Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
	if ( pbIsNewCreated )
		*pbIsNewCreated = FALSE;
	///------ End GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
	
	wks.Attach(lpcszBookSheetName);
	if(wks.IsValid())
		return true;

	// we need to create
	string strBooksheet = lpcszBookSheetName;
	///------ Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
	if ( strBooksheet.IsEmpty() )
		return false;
	///------ End GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
	string strBook, strSheet;
	///------ Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
	//if(!get_book_sheet_names(strBooksheet, strBook, strSheet))
		//return false;
	if ( !okutil_get_book_sheet_names(strBooksheet, &strBook, &strSheet, 0) )
	{
		strBook = strBooksheet;
		strSheet = "Sheet1";
	}
	///------ End GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
	
	///Jasmine 02/12/09 MUST_CHECK_PAGE_TYPE_WHEN_CONSTRUCT_FROM_NAME
	///------ Folger 02/21/10 QA81-14995-P4 QUICKFIT_FINDXY_FAILS_TO_FIND_BOOK_BY_LONGNAME
	//Page pp(strBook);
	Page	pp = Project.FindPage(strBook);
	///------ End QUICKFIT_FINDXY_FAILS_TO_FIND_BOOK_BY_LONGNAME
	if(pp) // if book already there, just add a new sheet
	{
		if(pp.GetType() == EXIST_WKS || pp.GetType() == EXIST_MATRIX)
		{
			///------ Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
			if ( !_check_get_sheet_by_index(wks, pp, strSheet) )
			///------ End GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
			{
				int nLayer = pp.AddLayer(strSheet);
				if(nLayer >= 0)
					wks = pp.Layers(nLayer);
			}
			
			if(wks)
			{
				///------ Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
				if ( pbIsNewCreated )
					*pbIsNewCreated = TRUE;
				///------ GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION

				return true;
			}
		}
	}
	///End MUST_CHECK_PAGE_TYPE_WHEN_CONSTRUCT_FROM_NAME
	if(bMatrixSheet)
	{
		MatrixPage wp;
		wp.Create("Origin", nCreate);
		wks = wp.Layers(0);
	}
	else
	{
		WorksheetPage wp;
		wp.Create("Origin", nCreate);
		wks = wp.Layers(0);
	}
	///------ Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
	if ( pbIsNewCreated )
		*pbIsNewCreated = TRUE;
	///------ End GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
	//wks.GetPage().Rename(strBook);
	/// Hong 01/28/10 QA80-14995-P2 FIX_OUTPUT_TO_WKS_FAIL_ALL_PUT_TO_ONE_SHEET_IF_NOT_VALID_SHORT_NAME
	//wks.GetPage().Rename(strBook, true);		///Folger 06/06/07 FIX_BUGS_IN_SPECIFIED_WKS
	wks.GetPage().Rename(strBook, false, PG_RENAME_LONGNAME_IF_NOT_GOOD_SHORT_NAME);
	/// end FIX_OUTPUT_TO_WKS_FAIL_ALL_PUT_TO_ONE_SHEET_IF_NOT_VALID_SHORT_NAME

	///------ Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
	if ( !_check_get_sheet_by_index(wks, wks.GetPage(), strSheet) )
	///------ End GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
		wks.SetName(strSheet);
	return true;
}

bool get_plot_info(int nColDesign, DataPlotStrings& dps, string& strBook, string& strSheet, string& strPlot, string& strLongName, string& strCol, int nRow, string& strVal, bool& bRealLongName)
{
	LPCSTR lpcsz = get_plot_dataset_ptr(&dps, nColDesign);
	if(NULL == lpcsz)
		return false;
	
	strLongName= lpcsz; // dataset name
	if(strLongName.IsEmpty())
		return false;
	char szTemp[NAME_SIZE];
	if(get_plot_designation_str(nColDesign, szTemp, NAME_SIZE))
		strPlot = szTemp;
	
	Column cc;
	Worksheet wks;
	if(get_wks_col(lpcsz, cc, wks))
	{
		string strTemp = cc.GetName();
		strLongName = cc.GetLongName();
		if(strLongName.IsEmpty())
			strLongName = strTemp;
	  	else bRealLongName = true;//Jake 04/06/07 ADD_CHECKBOX_FOR_SHOW_LONG_AND_SHORT_NAME	
		if(strCol)
			strCol = strTemp;
		
		if(nRow >=0)
		{
			int nCol = cc.GetIndex();
			wks.GetCell(nRow, nCol, strVal);
		}
		strBook = wks.GetPage().GetName();
		strSheet = wks.GetName();
	}	
	else // loose dataset, assume only possible to be numeric
	{
		Dataset ds(strPlot);
		/// Iris 03/28/2007 v8.0591 FIX_RUNTIME_ERRER_IN_OPENING_DATA_INFO_DLG_ON_FUNC_GRAPH, in this case ds is invalid
		//strVal = ftoa(ds[nRow]);
		if(ds && nRow < ds.GetSize())
			strVal = ftoa(ds[nRow]);
		///end FIX_RUNTIME_ERRER_IN_OPENING_DATA_INFO_DLG_ON_FUNC_GRAPH
	}
	return true;
}
//---- end CPY QA70-7820 6/22/05
///------Frank 6/28/05 NEW_WINDOW_FOLDER_IN_SPECIAL
string add_new_window(Folder &fld, int nWinType)
{
	PageBase pb;
	string strWindowName;
	string 	strTemplate = ""; 
	switch(nWinType)
	{
		case EXIST_WKS:
			strTemplate = "Origin.otw";
			Worksheet wks;
			if(!wks.Create(strTemplate))
				return "";
			
			pb = (PageBase)wks.GetPage();
			break;
		case EXIST_MATRIX:
			strTemplate = "Origin.otm";
			MatrixPage Mat;
			if(!Mat.Create(strTemplate))
				return "";
			
			pb = (PageBase)Mat;
			break;
		case EXIST_NOTES:
			Note nt;
			if(!nt.Create())
				return "";
			
			pb = nt;
			break;
		/*
		case EXIST_FOLDER:
			Folder fldParent = fld;
			
			if(!fldParent)
				fldParent = Application.ActiveFolder();
			Folder subFld = fldParent.AddSubfolder("New Folder");

			return subFld.GetName();
		*/
		case EXIST_GRAPH:
			strTemplate = "Origin.otp";
			break;
		case EXIST_EXTERN_WKS:
			strTemplate = "Origin.otw";
			break;
		case EXIST_LAYOUT:
			LayoutPage lp;
			strTemplate = "Layout.otp";
			if(!lp.Create(strTemplate))
				return "";
			pb = lp;
			break;
		case EXIST_FUNCTION:
			strTemplate = "Function.otp";
			break;
		default :
			return "";
	}
	GraphPage pg;
	
	if(!pb.IsValid())
	{
		/// Kenny 08/25/2009 QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
		//if(!pg.Create(strTemplate))
		if(!pg.Create(strTemplate, CREATE_DEFAULT_OPTIONS | CREATE_ENUM_EXIST_PAGE))
		/// End QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
			return "";
		
		pb = (Page)pg;
	};
	
	if(fld)	///If invalid, create in active folder.
	{
		Folder fldActive = Application.ActiveFolder();
		if(lstrcmp(fldActive.GetPath(),fld.GetPath()) != 0)
			if(!fldActive.Move(pb.GetName(),fld.GetPath()))
				out_str("Move to folder fail");
	}
	return pb.GetName();
}
string add_new_folder(Folder &fld )
{
	Folder fldParent = fld;
	
	if(!fldParent)
		fldParent = Application.ActiveFolder();
	
	Folder subFld = fldParent.AddSubfolder("New Folder");

	return subFld.GetName();
	
}
///------End NEW_WINDOW_FOLDER_IN_SPECIAL

//---- Sandy 9/18/05 CENTRALIZED_IMAGE_XF_COMMON_CODES
/// EJP 2006-03-14 v8.0375 SUPPORT_ROI_IN_IMAGE_PROCESSING
///bool matobj_copy(MatrixObject& moDest, const MatrixObject& moSrc)
typedef LPVOID (*PFNCOPYLBMPROI)(LPVOID, GraphObject &grROI);
typedef BOOL (*PFNSETLBMPROI)(LPVOID, vector<point> *pROI);
/// EJP 2006-05-22 v8.0414 BASIC_OPERATIONS_FOR_MATOBJ
///bool matobj_copy(MatrixObject& moDest, const MatrixObject& moSrc,
///	bool bUseROI, vector<point> *pROI) // = true, NULL
///Kyle 08/05/2010 ORG-723-P1 COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
//bool matobj_copy(MatrixObject& moDest, const MatrixObject& moSrc, bool bUseROI, vector<point> *pROI, bool bAllAttr) // = true, NULL, true
bool matobj_copy(MatrixObject& moDest, const MatrixObject& moSrc, bool bUseROI, vector<point> *pROI, bool bAllAttr, bool bCopyPal) // = true, NULL, true, false
///End COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
/// end BASIC_OPERATIONS_FOR_MATOBJ
/// end SUPPORT_ROI_IN_IMAGE_PROCESSING
{
	if( !moDest.IsValid() || !moSrc.IsValid() )
	{
		return false;
	}
	/// YuI 11/14/06 OC_METHOD_TO_CHECK_DATA_PROTECTION
	if( moDest.IsDataProtected() )
	{
		return FALSE;
	}
	/// end OC_METHOD_TO_CHECK_DATA_PROTECTION

	string strDest = moDest.GetDatasetName();
	if( strDest.Compare(moSrc.GetDatasetName()) == 0 )
		return true; // same matrix, nothing to do.

	bool bRet = false;

	/// EJP 2006-05-22 v8.0414 BASIC_OPERATIONS_FOR_MATOBJ
	///	/// EJP 2006-04-04 v8.0386 QA70-8187 GET_DATA_VALUES_DIRECT_FROM_IMAGE
	///	///if( moSrc.HasData() )
	///	if( moSrc.HasData(FALSE) ) // FALSE to not include gray scale image
	///	/// end GET_DATA_VALUES_DIRECT_FROM_IMAGE
	if( moSrc.HasData(FALSE) || false == bAllAttr )
	/// end BASIC_OPERATIONS_FOR_MATOBJ
	{
		/// EJP 2006-05-22 v8.0414 BASIC_OPERATIONS_FOR_MATOBJ
		if( bAllAttr )
		{
		/// end BASIC_OPERATIONS_FOR_MATOBJ
			int nRows = moSrc.GetNumRows();
			int nCols = moSrc.GetNumCols();
			moDest.SetNumRows(nRows);
			moDest.SetNumCols(nCols);
			int nInternalType = moSrc.GetInternalDataType();
		/// EJP 2006-05-22 v8.0414 BASIC_OPERATIONS_FOR_MATOBJ
			moDest.SetInternalData(nInternalType);
			///------ Folger 07/09/09 QA80-13904 MREPLACE_FAILS_TO_COPY_MATRIX_XY_RANGE_TO_OUTPUT
			double	rXMin, rYMin, rXMax, rYMax;
			moSrc.GetXY(rXMin, rYMin, rXMax, rYMax);
			moDest.SetXY(rXMin, rYMin, rXMax, rYMax);
			///------ End MREPLACE_FAILS_TO_COPY_MATRIX_XY_RANGE_TO_OUTPUT

			///Kyle 08/05/2010 ORG-723-P1 COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
			if( bCopyPal )
			{
				string strPal;
				DWORD dwCntrl;
				if( moSrc.GetPaletteInfo(strPal, dwCntrl) )
					moDest.ApplyPalette(strPal, dwCntrl);
			}
			///End COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
		}
		/// end BASIC_OPERATIONS_FOR_MATOBJ

		matrixbase& matSrc=moSrc.GetDataObject();
		matrixbase& matDst=moDest.GetDataObject();
		matDst=matSrc;

		/// EJP 2006-05-22 v8.0414 BASIC_OPERATIONS_FOR_MATOBJ
		///bRet=moDest.SetInternalData(nInternalType);
		bRet = true;
		/// end BASIC_OPERATIONS_FOR_MATOBJ
	}
	else
	{
		/// EJP 2006-03-14 v8.0375 SUPPORT_ROI_IN_IMAGE_PROCESSING
		///	/// EJP 2005-11-02 v8.0328 QA70-8186 LEAD_BITMAP_GR_OBJ
		///	///HDIB hDib = moSrc.GetDIB();
		///	///if( hDib )
		///	///{
		///	///	bRet = moDest.SetDIB(hDib);
		///	///}
		///	LPVOID pLBmp = moSrc.GetLeadBitmap();
		///	if( pLBmp )
		///		bRet = moDest.SetLeadBitmap(pLBmp); // Set will make copy by default
		///	/// end LEAD_BITMAP_GR_OBJ
		LPVOID pLBmp = moSrc.GetLeadBitmap();
		if( pLBmp )
		{
			if( bUseROI )
			{
				if( pROI )
				{
					bRet = moDest.SetLeadBitmap(pLBmp); // Set will make copy by default
					if( bRet )
					{
						pLBmp = moDest.GetLeadBitmap();
						if( pLBmp )
						{
							PFNSETLBMPROI pfn = (PFNSETLBMPROI)Project.FindFunction("set_ROI_in_LeadBitmap", "OriginLab\\image_utils.c", TRUE);
							bRet = pfn(pLBmp, pROI);
						}
					}
				}
				else
				{
					GraphObject grROI;
					MatrixLayer ml;
					moSrc.GetParent(ml);
					if( ml )
						grROI = ml.GraphObjects("ROI");

					if( grROI )
					{
						PFNCOPYLBMPROI pfn = (PFNCOPYLBMPROI)Project.FindFunction("copy_ROI_from_LeadBitmap", "OriginLab\\image_utils.c", TRUE);
						LPVOID pLBmpNew = pfn(pLBmp, grROI);
						if( pLBmpNew )
							bRet = moDest.SetLeadBitmap(pLBmpNew, false); // false = do not make copy
					}
					else // if no ROI found then use whole image
						bRet = moDest.SetLeadBitmap(pLBmp); // Set will make copy by default
				}
			}
			else		
				bRet = moDest.SetLeadBitmap(pLBmp); // Set will make copy by default
		}
		/// end SUPPORT_ROI_IN_IMAGE_PROCESSING
	}

	///Gareth 7/37/2010 ORG-631-S1 SAVE_THE_LONGNAME_COMMENT_UNIT
	MatrixLayer mlSrc, mlDes;
	moSrc.GetParent(mlSrc);
	moDest.GetParent(mlDes);
					
	string strLongName = moSrc.GetLongName();
	string strUnits = moSrc.GetUnits();
	string strComments = moSrc.GetComments();
	
	string strXLongName = mlSrc.GetAxesLongName(false);
	string strXUnits = mlSrc.GetAxesUnits(false);
	string strXComments = mlSrc.GetAxesComments(false);
	
	string strYLongName = mlSrc.GetAxesLongName(true);
	string strYUnits = mlSrc.GetAxesUnits(true);
	string strYComments = mlSrc.GetAxesComments(true);
	
	moDest.SetLongName(strLongName);
	moDest.SetUnits(strUnits);
	moDest.SetComments(strComments);
	
	mlDes.SetAxesLongName(strXLongName, false);
	mlDes.SetAxesUnits(strXUnits, false);
	mlDes.SetAxesComments(strXComments, false);
	
	mlDes.SetAxesLongName(strYLongName, true);
	mlDes.SetAxesUnits(strYUnits, true);
	mlDes.SetAxesComments(strYComments, true);
	///END SAVE_THE_LONGNAME_COMMENT_UNIT
	return bRet;
}
//------- end CENTRALIZED_IMAGE_XF_COMMON_CODES

/// EJP 2006-05-23 v8.0415 BASIC_OPERATIONS_FOR_MATOBJ
///Kyle 08/05/2010 ORG-723-P1 COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
//bool matobj_move(MatrixObject& moSrc, MatrixObject& moDest)
bool matobj_move(MatrixObject& moSrc, MatrixObject& moDest, bool bCopyPal)		// false
///End COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
{
	// Get source layer so we can delete source
	// object after copying to destination
	MatrixLayer mlSrc;
	moSrc.GetParent(mlSrc);
	if( !mlSrc )
		return false; // Need source layer for deleting source object

///Gareth 7/30/2010 ORG-631-P4 NO_NEED_TO_RENAME_THE_MATOBJ
	// Rename destination object
	//string strName = moSrc.GetName();
	////------ Folger 08/08/07 AUTO_ENUMERATION_WHEN_NAME_ALREADY_EXIST
	////moDest.SetName(strName);
	//moDest.SetName(strName, OCD_ENUM_NEXT);
	//------ Folger 08/08/07 AUTO_ENUMERATION_WHEN_NAME_ALREADY_EXIST
///END NO_NEED_TO_RENAME_THE_MATOBJ

	// Copy source object to destination object
	///Kyle 08/05/2010 ORG-723-P1 COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
	//if( !matobj_copy(moDest, moSrc, false, NULL) )
	if( !matobj_copy(moDest, moSrc, false, NULL, true, bCopyPal) )
	///End COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
		return false;

	// Delete source object from source layer
	return mlSrc.Delete(moSrc.GetIndex());	
}

///Kyle 08/05/2010 ORG-723-P1 COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
//bool matobj_move(MatrixObject& moSrc, MatrixLayer& mlDest)
bool matobj_move(MatrixObject& moSrc, MatrixLayer& mlDest, bool bCopyPal)	// false
///End COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
{
	// Check required arguments
	if( !moSrc || !mlDest )
		return false;

//	// Get source layer
//	MatrixLayer mlSrc;
//	moSrc.GetParent(mlSrc);
//	if( !mlSrc )
//		return false;

	// Create destination object in destination layer
	int nDestIndex = mlDest.Insert(1); // 1 == create one object
	if( nDestIndex < 0 )
		return false;

	// Get destination object created in destination layer
	MatrixObject moDest = mlDest.MatrixObjects(nDestIndex);
	if( !moDest )
		return false;

//	// Copy source MatrixObject to destination MatrixObject
//	if( !matobj_copy(moDest, moSrc, false, NULL) )
//		return false;

//	// Rename destination MatrixObject
//	string strName = moSrc.GetName();
//	moDest.SetName(strName);

//	// Delete the source MatrixObject
//	mlSrc.Delete(moSrc.GetIndex());	
	
//	return true;
	// Move source object to destination object
	///Kyle 08/05/2010 ORG-723-P1 COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
	//return matobj_move(moSrc, moDest);
	return matobj_move(moSrc, moDest, bCopyPal);
	///End COPY_PALETTE_INFO_FOR_MO2S_AND_MS2O
}
/// end BASIC_OPERATIONS_FOR_MATOBJ

//-------- CPY 10/31/05
//	Get active page that is not a Notes page
Page get_active_page(bool bAllowGraph)// = true);
{
	char szTemp[MAXLINE];
	LT_get_str("%H", szTemp, MAXLINE);
	
	Page pg;
	if(lstrlen(szTemp)==0)
		return pg;// invalid
	
	pg = Project.Pages(szTemp);
	if(bAllowGraph)
		return pg;
	
	if(pg)
	{
		if(pg.GetType() == EXIST_PLOT || pg.GetType() == EXIST_LAYOUT)
		{
			Page pgTemp;
			return pgTemp;
		}
	}
	return pg;
}
//-------- end CPY 10/31/05

/// YuI 11/09/05 QA70-8279 REPORT_TREE_AND_REPORT_DATA_XVARIABLES
string	get_fitter_results_curve_table_tagname(int nGraphIndex)
{
	string strTable;
	switch(nGraphIndex)
	{
	case GRAPH_RESIDUALS_SCATTER:
		strTable = STR_RESIDUALS_DATA_TABLE;
		break;
	case GRAPH_RESIDUALS_HISTOGRAM:
		strTable = STR_RESIDUALS_HISTOGRAM_TABLE;
		break;
	case GRAPH_RESIDUALS_VERSUS_FITS_PLOT:
		strTable = STR_RESIDUALS_FIT_GRAPH_TABLE;
		break;
	case GRAPH_RESIDUALS_VERSUS_ORDER_PLOT:
		strTable = STR_RESIDUALS_ORDER_GRAPH_TABLE;
		break;
	///Jim 2/22/06 v8.0368 ADD_RESIDUAL_LAG_PLOT_TO_RESIDUALS_PLOTS_BRANCH
	case GRAPH_RESIDUALS_LAG_PLOT:
		strTable = STR_RESIDUALS_LAG_GRAPH_TABLE;
		break;
	// END 	ADD_RESIDUAL_LAG_PLOT_TO_RESIDUALS_PLOTS_BRANCH
	
	default:
		strTable = STR_FIT_CURVES_TABLE;
		break;
	}
	return strTable;
}


///-----Frank 11/14/05 ADD_NEW_LAYER_ON_PAGE
string add_new_layer(Folder &fld, string &strPageName, int nLayerType)
{
	Page pb(strPageName);
	
	string 	strLayerName; 
	int	nLayerIndex;
	if(!pb.IsValid())
	{
		strPageName = add_new_window(fld, nLayerType);
		nLayerIndex = 0;
		Page pbTemp(strPageName);
		strLayerName = pbTemp.Layers(nLayerIndex).GetName();
	}
	else
		if(pb.GetType() == nLayerType)
		{
			nLayerIndex = pb.AddLayer();
			strLayerName = pb.Layers(nLayerIndex).GetName();
		}
	
	return strLayerName;
}
///-----End ADD_NEW_LAYER_ON_PAGE

///Jasmine 11/10/06 QA70-9112 GET_EMBEDDED_GRAPHS
///----Frank 11/22/05 GET_PROJECT_TREE
//nLevel , PTL_LAYER = sheet, PTL_OBJ = col for wks
//nPage1 = EXIST_WKS etc or 0 if allow all,
//nPage2 if ignore unless nPage1 is not zero 
/// Iris 5/04/2009 QA80-13552 SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
//bool get_project_tree(TreeNode& tr, int nLevel , int nPage1 , int nPage2, LPCSTR lpcszStartPEpath, bool bGetEmbeddedGraph)
bool get_project_tree(TreeNode& tr, int nLevel , int nPage1 , int nPage2, LPCSTR lpcszStartPEpath, const ProjectTreeOptions& stOptions)
///end SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
{
	Folder	rtFolder = Project.RootFolder;
	/// Iris 8/23/06 QA80-7729 GRAPH_BRWOSER_BUTTON_IN_GETN
	string 	strStartPath(lpcszStartPEpath);
	if(!strStartPath.IsEmpty())
	{
		Folder fld(strStartPath);
		if( !fld.IsValid() )
			return false;
		rtFolder.Attach(strStartPath);
	}
	///end GRAPH_BRWOSER_BUTTON_IN_GETN

	tr.project.ID = 0;// we may need a diff ID for project root later.
	tr.project.SetAttribute(STR_LABEL_ATTRIB, rtFolder.GetName());
	tr.project.SetAttribute(STR_PATH_ATTRIB, rtFolder.GetPath());
	tr.project.SetAttribute(STR_DISPLAY_ATTRIB, get_page_display_id(-1));
	tr.project.SetAttribute(STR_STOP_ATTRIB, PTL_FOLDER);//level	///Jasmine 11/17/06 SHOW_LNAME_AND_CELL
	
	/// Iris 5/04/2009 SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
	//return _get_objects(tr.project, rtFolder, nLevel , nPage1, nPage2, bGetEmbeddedGraph);
	return _get_objects(tr.project, rtFolder, nLevel , nPage1, nPage2, stOptions);
	///end SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
}

/// Iris 5/04/2009 SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
/// Iris 5/18/2009 QA80-13552-P2 IMPROVE_CHECK_3D_LAYER_FUNCITON
/*
static bool _is_3D_plot_page(PageBase& pg)
{
	if( EXIST_PLOT != pg.GetType() )
		return false;
	
	GraphPage gp(pg);
	GraphLayer gl = gp.Layers(-1); //acitve layer
	try
	{
		if(gl.ZAxis)
			return true;
		return false;
	}
	catch(int err)
	{
	}
	return false;	
}
*/
bool is_3D_graph(const GraphLayer& gl)
{
	if(!gl)
		return false;
	
	DWORD dw = gl.GetSystemParam(GLI_PCD_BITS);
	return IS_LAYER_BITS_ANY_3D(dw);	
}	
///end IMPROVE_CHECK_3D_LAYER_FUNCITON
///end SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE

/// Iris 5/04/2009 SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
//static bool _get_objects(TreeNode& tr, Folder& fldParent, int nLevel, int nPage1 , int nPage2, bool bGetEmbeddedGraph)
static bool _get_objects(TreeNode& tr, Folder& fldParent, int nLevel, int nPage1 , int nPage2, const ProjectTreeOptions& stOptions)
///end SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
{
	int	iNode = 0;
	int iFolder = 1;
	
	/// Iris 5/04/2009 QA80-13552 SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
	bool	bGetEmbeddedGraph = false;
	bool	bSortPages = false;
	bool	bFilter3DGraph = false;
	vector<string>* pvsExcludePages = NULL; /// Iris 6/17/2009 QA80-13771 FILTER_GRAPH_FUNCTION_SUPPORT
	DWORD	dwCtrl = PT_CTRL_SHOW_FULL_RANGE; ///Sophy 9/3/2009 QA80-14241 CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
	if( NULL != stOptions )
	{
		bGetEmbeddedGraph = stOptions.bGetEmbeddedGraph;
		bSortPages = stOptions.bSortPages;
		bFilter3DGraph = stOptions.bFilter3DGraph;
		pvsExcludePages = &(stOptions.vsExcludePages); /// Iris 6/17/2009 QA80-13771 FILTER_GRAPH_FUNCTION_SUPPORT
		dwCtrl = stOptions.dwCtrl; ///Sophy 9/3/2009 QA80-14241 CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
	}  
	///end SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
	
	///Jasmine 10/24/06 REARRANGE_TREE_STRUCTURE
	//add pages first, then subfolder
	int	iPage = 1;
	if(nLevel >= PTL_PAGE)
	{
		/// Iris 5/04/2009 QA80-13552 SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
		//foreach(PageBase pg in fldParent.Pages)		
		//{
		vector<string> vsPages;
		///Jasmine 04/26/10 QA81-14826-P5 BROWSER_HAS_INCLUDE_SHORTCUT_OPTION
		//foreach(PageBase pgTemp in fldParent.Pages)
		Collection<PageBase> cPages;
		if(dwCtrl & PT_CTRL_INCLUDE_SHORTCUT)
			cPages = fldParent.PagesAndShortcuts;
		else
			cPages = fldParent.Pages;
		///End BROWSER_HAS_INCLUDE_SHORTCUT_OPTION
		foreach(PageBase pgTemp in cPages)
		{
			/// Iris 6/17/2009 QA80-13771 FILTER_GRAPH_FUNCTION_SUPPORT
		    //vsPages.Add(pgTemp.GetName());
		    string strName = pgTemp.GetName();
		    if( NULL == pvsExcludePages || NULL != pvsExcludePages && 0 == pvsExcludePages->GetSize() 
		    	||  NULL != pvsExcludePages && pvsExcludePages->GetSize() && -1 == pvsExcludePages->Find(strName) )
		    	vsPages.Add(strName);	
		    ///end FILTER_GRAPH_FUNCTION_SUPPORT
		}
		
		if(bSortPages && vsPages.GetSize() >0)
			vsPages.Sort();
	 
		for(int ipage = 0; ipage < vsPages.GetSize(); ipage++)
		{
			PageBase pg = Project.Pages(vsPages[ipage]);
			if(!pg)//Note window will be invalid page object
				continue;
		///end SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
		
			bool bGetGraphInWks = (nPage1 == 0 || nPage1 == EXIST_PLOT) && bGetEmbeddedGraph && pg.GetType() == EXIST_WKS, bRemoveEmpty;
			//--------Folger 07/18/07 MAKE_GET_PROJECT_TREE_SHOW_TWO_PAGE_TYPES
			//if(nPage1 != 0 && pg.GetType() != nPage1 )
			if(nPage1 != 0 && pg.GetType() != nPage1 && pg.GetType() != nPage2)
			//--------End MAKE_GET_PROJECT_TREE_SHOW_TWO_PAGE_TYPES
			{
				if(!bGetGraphInWks)
					continue;
				bRemoveEmpty = true;
			}
			//--------Folger 07/18/07 MAKE_GET_PROJECT_TREE_SHOW_TWO_PAGE_TYPES
			//if(nPage1!= 0 && nPage2 != 0 && pg.GetType() != nPage2)
			if(nPage1!= 0 && nPage2 != 0 && pg.GetType() != nPage1 && pg.GetType() != nPage2 && !bGetGraphInWks)
			//--------End MAKE_GET_PROJECT_TREE_SHOW_TWO_PAGE_TYPES
				continue;
			
			/// Iris 5/04/2009 QA80-13552 SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
			/// Iris 5/18/2009 QA80-13552-P2 IMPROVE_CHECK_3D_LAYER_FUNCITON
			//if( bFilter3DGraph && _is_3D_plot_page(pg) )
			GraphPage graph(pg);
			if( bFilter3DGraph && graph && is_3D_graph(graph.Layers(-1)) )
				continue;
			///end IMPROVE_CHECK_3D_LAYER_FUNCITON
			///end SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
			
			/// Iris 6/17/2009 QA80-13771 FILTER_GRAPH_FUNCTION_SUPPORT
		    if( NULL != pvsExcludePages && pvsExcludePages->GetSize() && -1 != pvsExcludePages->Find(pg.GetName()) )
		    	continue;			
			///end FILTER_GRAPH_FUNCTION_SUPPORT
			
			DWORD dwStatus = pg.GetStatus(fldParent);///Jasmine 04/27/10 QA81-15312 SHOW_SHORTCUT_ICON_IN_PROJECT_TREE
			
			string strTagName = "Page" + iPage++;
			TreeNode tnp;
			bool bRet = _check_get_page_node(pg, 
											tr, tnp, 
											strTagName, fldParent.GetPath(), 
											dwCtrl,
											(dwStatus & PBFS_SHORTCUT) );///Jasmine 04/27/10 QA81-15312 SHOW_SHORTCUT_ICON_IN_PROJECT_TREE
			if(bRet)
				iNode++;
			else
				continue;
			
			int nPageType = pg.GetType();
			if(nLevel >= PTL_LAYER || (bGetGraphInWks && nPageType== EXIST_WKS))
				if( nPageType== EXIST_WKS || nPageType== EXIST_MATRIX ||nPageType== EXIST_GRAPH)
				{
					/// TD 8-3-06 QA70-8843 DOWNCAST_BUG
					Page page = pg;
					if(page)
						///------ Folger 05/18/09 QA80-13552-P1 GRAPH_BROWSER_FAILS_TO_FILTER_EMBEDED_3D_GRAPHS
						//_get_layers(tnp, page, nLevel, bGetGraphInWks, bRemoveEmpty);
						/// Iris 6/17/2009 QA80-13771 FILTER_GRAPH_FUNCTION_SUPPORT
						//_get_layers(tnp, page, nLevel, bGetGraphInWks, bRemoveEmpty, bFilter3DGraph);
						///Sophy 9/3/2009 QA80-14241 CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
						//_get_layers(tnp, page, nLevel, bGetGraphInWks, bRemoveEmpty, bSortPages, bFilter3DGraph, pvsExcludePages);
						_get_layers(tnp, page, nLevel, bGetGraphInWks, bRemoveEmpty, bSortPages, bFilter3DGraph, pvsExcludePages, dwCtrl);
						///end CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
						///end FILTER_GRAPH_FUNCTION_SUPPORT
						///------ End GRAPH_BROWSER_FAILS_TO_FILTER_EMBEDED_3D_GRAPHS
					/// end DOWNCAST_BUG
				}
			if(bRemoveEmpty && tnp.GetNodeCount() < 1)
				tnp.Remove();
		}
	}/// Iris 5/04/2009 QA80-13552 SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
		
	
	foreach(Folder fld in fldParent.Subfolders)
	{
		string strTagName = "Folder" + iFolder++;
		TreeNode	tn = tr.AddNode(strTagName, get_page_display_id(-1));
		iNode++;
		tn.SetAttribute(STR_DATA_ATTRIB, iFolder-1);///Jasmine 03/22/07 MODIFICATION_ON_GET_PROJECT_TREE
		tn.SetAttribute(STR_LABEL_ATTRIB, fld.GetName());
		tn.SetAttribute(STR_PATH_ATTRIB, fld.GetPath());
		tn.SetAttribute(STR_DISPLAY_ATTRIB, get_page_display_id(-1));
		tn.SetAttribute(STR_STOP_ATTRIB, PTL_FOLDER);///Jasmine 11/17/06 SHOW_LNAME_AND_CELL
		/// Iris 5/04/2009 QA80-13552 SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
		//_get_objects(tn, fld, nLevel, nPage1 , nPage2, bGetEmbeddedGraph);
		_get_objects(tn, fld, nLevel, nPage1 , nPage2, stOptions);
		///end SUPPORT_OPTION_TO_SORT_PAGE_LIST_AND_FILTER_3D_PAGE
		
	}
	///End REARRANGE_TREE_STRUCTURE
	return 0 == iNode ? false : true;
}
///------ Folger 05/18/09 QA80-13552-P1 GRAPH_BROWSER_FAILS_TO_FILTER_EMBEDED_3D_GRAPHS
//static bool	_get_layers(TreeNode &trProject,Page &pg, int nLevel, bool bGetGraphInWks, bool bRemoveEmpty)
/// Iris 6/17/2009 QA80-13771 FILTER_GRAPH_FUNCTION_SUPPORT
//static bool	_get_layers(TreeNode &trProject,Page &pg, int nLevel, bool bGetGraphInWks, bool bRemoveEmpty, bool bFilter3DGraph)
///Sophy 9/3/2009 QA80-14241 CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
//static bool	_get_layers(TreeNode &trProject,Page &pg, int nLevel, bool bGetGraphInWks, bool bRemoveEmpty, bool bSortPages, bool bFilter3DGraph, const vector<string>* pvsExcludePages)
static bool	_get_layers(TreeNode &trProject,Page &pg, int nLevel, bool bGetGraphInWks, bool bRemoveEmpty, bool bSortPages, bool bFilter3DGraph, const vector<string>* pvsExcludePages, DWORD dwCtrl = PT_CTRL_SHOW_FULL_RANGE)
///end CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
///end FILTER_GRAPH_FUNCTION_SUPPORT
///------ End GRAPH_BROWSER_FAILS_TO_FILTER_EMBEDED_3D_GRAPHS
{
	int nType = pg.GetType();
	
	string strFolder;
	Folder fld = pg.GetFolder();
	if(fld)
		strFolder = fld.GetPath();

	///------Frank 12/12/05 GET_LAYER_COUNT_FROM_PAGE
	Page* ppb;
	switch(nType)
	{
	case EXIST_WKS:
		ppb = new WorksheetPage(pg);
		break;
	case EXIST_PLOT:
		ppb = new GraphPage(pg);
		break;
	case EXIST_MATRIX:
		ppb = new MatrixPage(pg);
		break;
	default:
		return true;
	}
	
	//for(int ii = 0; ii < pg.Layers.Count(); ii++)
	for(int ii = 0; ii < _layer_num_of_page(pg); ii++)
	///------End GET_LAYER_COUNT_FROM_PAGE
	{
		Layer lay;
		lay = ppb->Layers(ii);
		
		///Sophy 9/3/2009 QA80-14241 CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
		if ( (dwCtrl & PT_CTRL_SKIP_HIERARCHY) && nType == EXIST_WKS )
		{
			Worksheet wks(lay);
			if ( wks && wks.GetSystemParam(GLI_PCD_BITS) & WP_SHEET_HIERARCHY )
				continue; //skip hierarchy worksheet in Set Columun Value dialog's Project tree from "Insert Info Variable..." as to Max's suggestion
		}
		///end CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
		
		TreeNode tnp;
		if( !_check_get_layer_node(lay, trProject, tnp, nType, strFolder, dwCtrl) )
			continue;
		
		if(bGetGraphInWks && nType == EXIST_WKS)
		{
			vector<string> vs;
			Worksheet wks(lay);
			//---- CPY 5/27/07 QA70-9837 GRAPHS_IN_WKS_SHOULD_EXCLUDE_SPARKLINES
			//int nCount = wks.GetEmbeddedGraphs(vs);
			int nCount = wks.GetEmbeddedGraphs(vs, GRAPH_IN_WKS_EXCLUDE_BITS);
			//---
			
			if( bSortPages )
				vs.Sort();
			
			string strLayerName;
			wks.GetRangeString(strLayerName);
			string strPath = strFolder + pg.GetName() +"/"+ strLayerName + "/";
			int		nSkip = 0;			///------ Folger 05/18/09 QA80-13552-P1 GRAPH_BROWSER_FAILS_TO_FILTER_EMBEDED_3D_GRAPHS
			for(int nn = 0; nn < nCount; nn++)
			{
				GraphPage gp(vs[nn]);
				///------ Folger 05/18/09 QA80-13552-P1 GRAPH_BROWSER_FAILS_TO_FILTER_EMBEDED_3D_GRAPHS
				/// Iris 5/18/2009 QA80-13552-P2 IMPROVE_CHECK_3D_LAYER_FUNCITON
				//if( bFilter3DGraph && _is_3D_plot_page(gp) )
				if( bFilter3DGraph && gp && is_3D_graph(gp.Layers(-1)) )
				///end IMPROVE_CHECK_3D_LAYER_FUNCITON
				{
					++nSkip;
					continue;
				}
				///------ End GRAPH_BROWSER_FAILS_TO_FILTER_EMBEDED_3D_GRAPHS
				
				/// Iris 6/17/2009 QA80-13771 FILTER_GRAPH_FUNCTION_SUPPORT
				// pvsExcludePages can be NULL or 0 size to specify no exclude page
			    if( gp && NULL != pvsExcludePages && pvsExcludePages->GetSize() && -1 != pvsExcludePages->Find(gp.GetName()) )
			    {
			    	++nSkip;
			    	continue;			
			    }
				///end FILTER_GRAPH_FUNCTION_SUPPORT

				string strNode = "EmbeddedGraph" + nn;
				TreeNode tnGraph;
				bool bRet = _check_get_page_node(gp, tnp, tnGraph, strNode, strPath, dwCtrl);
				ASSERT(bRet);
			}
			///------ Folger 05/18/09 QA80-13552-P1 GRAPH_BROWSER_FAILS_TO_FILTER_EMBEDED_3D_GRAPHS
			//if(nCount < 1 && bRemoveEmpty)
			if( bRemoveEmpty && (nCount - nSkip) < 1)
			///------ End GRAPH_BROWSER_FAILS_TO_FILTER_EMBEDED_3D_GRAPHS
				tnp.Remove();				
		}
		///Jasmine 01/18/07 ADD_COL_LEVEL
		if(nLevel == PTL_OBJ)
		{
			switch(nType)
			{
			case EXIST_WKS:
			///Sophy 9/3/2009 QA80-14241 CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
			//_get_columns(tnp, lay, nType, strFolder);
			_get_columns(tnp, lay, nType, strFolder, dwCtrl);
			///end CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
			break;
		///End ADD_COL_LEVEL
			case EXIST_PLOT:
				_get_plots(tnp, lay, nType, strFolder, dwCtrl);
				break;
			case EXIST_MATRIX:
				_get_matrices(tnp, lay, nType, strFolder, dwCtrl);
				break;
			}
		}
	}
	delete ppb;///------Frank 12/12/05 GET_LAYER_COUNT_FROM_PAGE
	return true;
}
///End GET_EMBEDDED_GRAPHS
///Jasmine 01/18/07 ADD_COL_LEVEL
///Sophy 9/3/2009 QA80-14241 CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
//static bool	_get_columns(TreeNode &trProject,Layer &layer, int nType, const string strFolder)
static bool	_get_columns(TreeNode &trProject,Layer &layer, int nType, const string strFolder, DWORD dwCtrl = PT_CTRL_SHOW_FULL_RANGE)
///end CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
{
	if(EXIST_WKS == nType)
	{
		Worksheet wks(layer);
		if(!wks.IsValid())
			return false;
		foreach(Column col in wks.Columns)
		{
			TreeNode tnp;
			bool bRet = _check_get_dataobj_node(col, trProject, tnp, nType, strFolder, dwCtrl);
			ASSERT(bRet);
		}
	}
	return true;
}
///End ADD_COL_LEVEL

static bool	_get_matrices(TreeNode &trProject, Layer &layer, int nType, const string strFolder, DWORD dwCtrl = PT_CTRL_SHOW_FULL_RANGE)
///end CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
{
	if(EXIST_MATRIX != nType)
		return false;
	
	MatrixLayer ml(layer);
	if( !ml.IsValid() )
		return false;
	
	foreach(MatrixObject mo in ml.MatrixObjects)
	{
		TreeNode tnp;
		bool bRet = _check_get_dataobj_node(mo, trProject, tnp, nType, strFolder, dwCtrl);
		ASSERT(bRet);
	}
	
	return true;
}

///Jasmine 12/16/09 QA81-14845-P4 SHOW_SELECTED_PLOT_INFO_TO_AVOID_DUPLICATED_SOURCE_BOOK
static bool	_get_plots(TreeNode &trProject, Layer &layer, int nType, const string strFolder, DWORD dwCtrl = PT_CTRL_SHOW_FULL_RANGE)
///end CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
{
	if(EXIST_PLOT != nType)
		return false;
	
	GraphLayer gl(layer);
	if( !gl.IsValid() )
		return false;
	
	foreach(DataPlot dp in gl.DataPlots)
	{
		TreeNode tnp;
		bool bRet = _check_get_dataobj_node(dp, trProject, tnp, nType, strFolder, dwCtrl);
		ASSERT(bRet);
	}
	
	return true;
}
///End SHOW_SELECTED_PLOT_INFO_TO_AVOID_DUPLICATED_SOURCE_BOOK
///----End GET_PROJECT_TREE

///Jasmine 12/24/09 QA81-14845-S1 SHOW_SOURCE_DATA_TREE_UNDER_PLOT_NODE
static bool _check_get_column_node(const Column& col, TreeNode& trParent, TreeNode& trDataObject, DWORD dwCtrl)
{
	if(!col || !trParent)
		return false;
	
	string strRange;
	col.GetRangeString(strRange);
	
	trDataObject = trParent.FindNodeByAttribute(STR_NAME_ATTRIB, strRange);
	if(trDataObject)
		return true;
	
	string 	strTagName = tree_get_enum_node_name(trParent, "Column");
	trDataObject = trParent.AddNode(strTagName);
	if(!trDataObject)
		return false;
	
	string strColLabel = dwCtrl & PT_CTRL_SHOW_FULL_RANGE? strRange : get_column_name(col, true, true);
	
	trDataObject.SetAttribute(STR_NAME_ATTRIB, strRange);
	trDataObject.SetAttribute(STR_LABEL_ATTRIB, strColLabel);
	trDataObject.SetAttribute(STR_DATA_ATTRIB, col.GetIndex());
	trDataObject.SetAttribute(STR_STOP_ATTRIB, PTL_OBJ);
	
	Layer lay;
	col.GetParent(lay);
	Page pg;
	if(lay)
	{
		Folder fld = lay.GetPage().GetFolder();
		if(fld)
			trDataObject.SetAttribute(STR_PATH_ATTRIB, fld.GetPath()+strRange);
	}
	return true;
}
static bool _check_get_dataobj_node(const OriginObject& orgobj, TreeNode& trParent, TreeNode& trDataObject, int nType, const string strFolder, DWORD dwCtrl)
{
	if(!orgobj || !trParent)
		return false;
	
	
	bool 	bRet = false;
	int 	index,
			nDisplay = 0;
	string 	strTagName,
			strRange,
			strObjLabel;	
			
	switch(nType)
	{		
	case EXIST_WKS:
		Column col;
		col = orgobj;
		if(!col)
			break;
		
		nDisplay = IDR_WKSCOLTYPE;
		
		index = col.GetIndex();
		strTagName.Format("Column%d", index);
		
		col.GetRangeString(strRange);
		///Sophy 9/3/2009 QA80-14241 CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
		strObjLabel = dwCtrl & PT_CTRL_SHOW_FULL_RANGE? strRange : get_column_name(col, true, true);
		///End CTRL_WHETHER_SHOW_FULL_SYNTAX_OF_RANGE_IN_PROJECT_TREE
		bRet = true;
		break;
		
	case EXIST_PLOT:
		DataPlot dp;
		dp = orgobj;
		if(!dp)
			break;
		
		index = dp.GetIndex();
		strTagName.Format("Plot%d", index);
		
		dp.GetRangeString(strRange, NTYPE_FOR_RANGE);
		
		if ( dwCtrl & PT_CTRL_SHOW_FULL_RANGE )
			dp.GetRangeString(strObjLabel, NTYPE_BOOKSHEET_XY_RANGE);
		else
			dp.GetLegend(strObjLabel);
		
		bRet = true;
		break;
		
	case EXIST_MATRIX:
		MatrixObject mo;
		mo = orgobj;
		if(!mo)
			break;
		
		nDisplay = IDR_MATRIXCOLTYPE;
		
		index = mo.GetIndex();
		strTagName.Format("Matrix%d", index);
		
		orgobj.GetRangeString(strRange);
		
		if ( dwCtrl & PT_CTRL_SHOW_FULL_RANGE )
			strObjLabel = strRange;
		else
		{
			strObjLabel = mo.GetLongName();
			if( strObjLabel.IsEmpty() )
				strObjLabel = mo.GetName();
		}
		
		bRet = true;
		break;
	default:
		ASSERT(0);
		return false;
	}
	if(!bRet)
		return false;
	
	trDataObject = trParent.GetNode(strTagName);
	if(!trDataObject)
		trDataObject = trParent.AddNode(strTagName);
	else
		ASSERT(0);//assum it won't add a same node twice
	if(!trDataObject)
		return false;
	
	trDataObject.SetAttribute(STR_STOP_ATTRIB, 	PTL_OBJ);
	trDataObject.SetAttribute(STR_DISPLAY_ATTRIB, nDisplay);
	trDataObject.SetAttribute(STR_DATA_ATTRIB, 	index);
	trDataObject.SetAttribute(STR_NAME_ATTRIB, 	strRange);
	trDataObject.SetAttribute(STR_LABEL_ATTRIB, strObjLabel);	
	trDataObject.SetAttribute(STR_PATH_ATTRIB, 	strFolder+strRange);
	return true;
}
static bool _check_get_layer_node(const Layer& lay, TreeNode& trParent, TreeNode& trLayer, int nType, const string strFolder, DWORD dwCtrl)
{
	if(!lay || !trParent)
		return false;
		
	int nDisplayID 	= get_layer_display_id(nType);
	int index 		= lay.GetIndex();
	
	string 	strTagName;
	strTagName.Format("Layer%d", index);
	
	trLayer = trParent.GetNode(strTagName);
	if(trLayer)
	{
		trLayer.ID = nDisplayID;
		ASSERT(0);//assum it won't add a same node twice
	}
	else
		trLayer = trParent.AddNode(strTagName, nDisplayID);
	if(!trLayer)
		return false;
	
	string strRange;
	lay.GetRangeString(strRange);
	
	string strLabel = dwCtrl & PT_CTRL_SHOW_FULL_RANGE? strRange : lay.GetName();
	
	trLayer.SetAttribute(STR_STOP_ATTRIB, 	PTL_LAYER);	
	trLayer.SetAttribute(STR_DISPLAY_ATTRIB, nDisplayID);
	trLayer.SetAttribute(STR_DATA_ATTRIB, 	index);
	trLayer.SetAttribute(STR_NAME_ATTRIB, 	strRange);
	trLayer.SetAttribute(STR_LABEL_ATTRIB, 	strLabel);
	trLayer.SetAttribute(STR_PATH_ATTRIB, 	strFolder+lay.GetPage().GetName());
	
	return true;
}
static bool _check_get_page_node(const PageBase& pg, 
								TreeNode& trParent, TreeNode& trPage, 
								const string strTagName, const string strPath, 
								DWORD dwCtrl,
								bool bShortcut = false)	///Jasmine 04/27/10 QA81-15312 SHOW_SHORTCUT_ICON_IN_PROJECT_TREE
{
	if(!pg || !trParent)
		return false;
		
	int 	nDisplayID = get_page_display_id( pg.GetType() );
	
	trPage = trParent.GetNode(strTagName);
	if(trPage)
	{
		trPage.ID = nDisplayID;
		ASSERT(0);//assum it won't add a same node twice
	}
	else
		trPage = trParent.AddNode(strTagName, nDisplayID);
	if(!trPage)
		return false;
	
	trPage.SetAttribute(STR_STOP_ATTRIB, PTL_PAGE);
	trPage.SetAttribute(STR_DISPLAY_ATTRIB, nDisplayID);
	trPage.SetAttribute(STR_DATA_ATTRIB, pg.GetIndex());
	trPage.SetAttribute(STR_NAME_ATTRIB, pg.Label);
	trPage.SetAttribute(STR_LABEL_ATTRIB, pg.GetName());
	trPage.SetAttribute(STR_PATH_ATTRIB, strPath+pg.GetName());
	///Jasmine 04/27/10 QA81-15312 SHOW_SHORTCUT_ICON_IN_PROJECT_TREE
	if(bShortcut)
		trPage.SetAttribute(STR_OVERLAY_ATTRIB, IDR_SHORTCUT_OVERLAY);
	///End SHOW_SHORTCUT_ICON_IN_PROJECT_TREE
	return true;
}
///Jasmine 01/04/10 QA81-14845-P7 DATA_FROM_MATRIX
///------ Folger 08/20/10 ORG-865-P1 INSERT_VARIABLE_LINKING_FAILED_FOR_VIRTUAL_MATRIX_PLOT
//bool get_main_dataobj_from_datarange(const DataRange& dr, Datasheet& ds, OriginObject& obj)
bool get_main_dataobj_from_datarange(const DataRange& dr, Datasheet& ds, OriginObject& obj, Array<OriginObject&>& mainObjs/* = NULL*/)
///------ End INSERT_VARIABLE_LINKING_FAILED_FOR_VIRTUAL_MATRIX_PLOT
{
	if(!dr)
		return false;
	
	///------ Folger 08/20/10 ORG-865-P1 INSERT_VARIABLE_LINKING_FAILED_FOR_VIRTUAL_MATRIX_PLOT
	if ( mainObjs )
		mainObjs.SetAsOwner(TRUE);
	///------ End INSERT_VARIABLE_LINKING_FAILED_FOR_VIRTUAL_MATRIX_PLOT
	
	vector<string> vsRanges = {"Z", "Y"};	
	for(int ii = 0; ii < vsRanges.GetSize(); ii++)
	{
		bool bRet = false;
		int r1, c1, r2, c2;
		dr.GetRange(vsRanges[ii], r1, c1, r2, c2, ds);
		
		MatrixLayer ml(ds);
		if(ml)
		{
			obj = ml.MatrixObjects(c1);
			bRet = true;
		}
		else
		{
			Worksheet wks(ds);
			if(wks)
			{
				obj = wks.Columns(c1);
				///------ Folger 08/20/10 ORG-865-P1 INSERT_VARIABLE_LINKING_FAILED_FOR_VIRTUAL_MATRIX_PLOT
				if ( mainObjs )
				{
					for ( int ii=c1; ii<=c2; ++ii )
					{
						OriginObject*	pObj = new OriginObject;
						*pObj = wks.Columns(ii);
						mainObjs.Add(*pObj);
					}
				}
				///------ End INSERT_VARIABLE_LINKING_FAILED_FOR_VIRTUAL_MATRIX_PLOT
				bRet = true;
			}
		}
		
		if(bRet)
			break;
	}
	
	return obj.IsValid();
}
///End DATA_FROM_MATRIX
///Jasmine 12/28/09 QA81-14845-S1 CP_ASK_ONLY_GET_Y_COLUMN, i.e. the main column 
bool get_plot_data_tree(const DataPlot& dp, TreeNode& trData, DWORD dwCtrl)
{
	if(!dp || !trData)
		return false;
		
	DataRange dr;
	if( !dp.GetDataRange(dr) )
		return false;
	
	Datasheet ds;
	OriginObject obj;
	///------ Folger 08/20/10 ORG-865-P1 INSERT_VARIABLE_LINKING_FAILED_FOR_VIRTUAL_MATRIX_PLOT
	//if( !get_main_dataobj_from_datarange(dr, ds, obj) )
	Array<OriginObject&>	mainObjs(TRUE);
	if( !get_main_dataobj_from_datarange(dr, ds, obj, mainObjs) )
	///------ End INSERT_VARIABLE_LINKING_FAILED_FOR_VIRTUAL_MATRIX_PLOT
		return false;
	
	Page pg = ds.GetPage();
	int nType = pg.GetType();
	string strFolder;
	Folder fld = pg.GetFolder();
	if(fld)
		strFolder = fld.GetPath();
	
	TreeNode trBook;
	string strTagName = "Page"+pg.GetIndex();
	if( !_check_get_page_node(pg, trData, trBook, strTagName, strFolder, dwCtrl) )
		return false;
		
	TreeNode trSheet;
	if( !_check_get_layer_node(ds, trBook, trSheet, nType, strFolder, dwCtrl) )
		return false;
		
	TreeNode trDataObject;
	///------ Folger 08/20/10 ORG-865-P1 INSERT_VARIABLE_LINKING_FAILED_FOR_VIRTUAL_MATRIX_PLOT
	//return _check_get_dataobj_node(obj, trSheet, trDataObject, nType, strFolder, dwCtrl)
	for ( int ii=0; ii<mainObjs.GetSize(); ++ii )
	{
		if ( !_check_get_dataobj_node(mainObjs.GetAt(ii), trSheet, trDataObject, nType, strFolder, dwCtrl) )
			return false;
	}
	return true;
	///------ End INSERT_VARIABLE_LINKING_FAILED_FOR_VIRTUAL_MATRIX_PLOT
}
///End CP_ASK_ONLY_GET_Y_COLUMN
///End SHOW_SOURCE_DATA_TREE_UNDER_PLOT_NODE

///-----Frank 11/14/05 NO_OPERATOR_CONTROL_IN_BROWSER
int get_page_display_id(int nItemID)
{
	switch(nItemID)
		{
		case EXIST_GRAPH:
			return IDR_GRAPHTYPE_V8;
		case EXIST_WKS:
			return IDR_WORKBOOKTYPE;//IDR_WORKSHEETTYPE_V8;///Jasmine 01/06/10 QA81-14909 WKS_AND_MATRIX_HAVE_NEW_BOOK_AND_COL_ICONS
		case EXIST_NOTES:
			return IDR_NOTESTYPE;
		case EXIST_EXTERN_WKS:
			return IDR_EXCELTYPE;
		case EXIST_MATRIX:
			return IDR_MATRIXBOOKTYPE;//IDR_MATRIXTYPE_V8;///Jasmine 01/06/10 QA81-14909 WKS_AND_MATRIX_HAVE_NEW_BOOK_AND_COL_ICONS
		case EXIST_LAYOUT:
			return IDR_LAYOUTTYPE;
		};
	return IDI_FOLDER_CLOSED;

}
///-----End NO_OPERATOR_CONTROL_IN_BROWSER

///Jasmine 01/06/10 QA81-14909 WKS_AND_MATRIX_HAVE_NEW_BOOK_AND_COL_ICONS
int get_layer_display_id(int nItemID)
{
	switch(nItemID)
	{
	case EXIST_GRAPH:
		return 0;
	case EXIST_WKS:
		return IDR_WORKSHEETTYPE_V8;
	case EXIST_MATRIX:
		return IDR_MATRIXTYPE_V8;
	};
	
	return 0;
}
int get_data_object_display_id(int nItemID)
{
	switch(nItemID)
	{
	case EXIST_GRAPH:
		return 0;
	case EXIST_WKS:
		return IDR_WKSCOLTYPE;
	case EXIST_MATRIX:
		return IDR_MATRIXCOLTYPE;
	};
	
	return 0;
}
///End WKS_AND_MATRIX_HAVE_NEW_BOOK_AND_COL_ICONS

///------Frank 12/12/05 GET_LAYER_COUNT_FROM_PAGE
static UINT _layer_num_of_page(PageBase &pb)
{
	if(!pb)
		return -1; //Change 0 to -1 mean not a valid page
	UINT nLayers;
	switch(pb.GetType())
	{
	case EXIST_NOTES:
	case EXIST_LAYOUT:
		return 0;	//Change 1 to 0 mean not just one layer, if use 1 will confuse with worksheetpage with one layer
	case EXIST_WKS:
	case EXIST_EXTERN_WKS:
		WorksheetPage wks(pb);
		nLayers = wks.Layers.Count();
		break;
	case EXIST_MATRIX:
		MatrixPage mat(pb);
		nLayers = mat.Layers.Count();
		break;
	case EXIST_GRAPH:
		GraphPage gp(pb);
		nLayers = gp.Layers.Count();
		break;
	default:
		break:
	};	
	return nLayers;
}
///------End GET_LAYER_COUNT_FROM_PAGE
//---- CPY 12/12/2005 GETNGRAPH_BOX_TEMPLATE_FROM_XF
bool page_load(GraphPage& page, LPCSTR lpcszTemplate, DWORD dwClicks, bool* pbLoadSystemTheme)// = NOCLICK_USE_DEFAULT, NULL	///Jasmine 08/08/07 QA80-10193 APPLY_SYSTEM_THEME, same logic with ApplySystemThemeToPage
{
	if(!page)
		return false;
	
	if(page.LoadTemplate(lpcszTemplate))
	{
		if(NOCLICK_USE_DEFAULT != dwClicks)
		{
			string strLT;
			strLT.Format("page.noClick=%d", dwClicks);
			page.LT_execute(strLT);
		}
		///Jasmine 08/08/07 QA80-10193 APPLY_SYSTEM_THEME	
		bool bLoadSystemTheme;
		if(pbLoadSystemTheme)
			bLoadSystemTheme = *pbLoadSystemTheme;
		else
		{
			DWORD dwCntrl = LabTalk.page.cntrl;	//temporary solution
			bLoadSystemTheme  = !(dwCntrl & PPDWCNTRL_IGNORE_SYSTEM_THEME);
		}
		if(bLoadSystemTheme)
		{
			int nThemeType = theme_get_type_from_page_type(page.GetType());
			string strTheme = okutil_theme_get_system_theme_file_name(nThemeType);
			if(!strTheme.IsEmpty())
				page.ApplyFormat(strTheme);
		}
		///End APPLY_SYSTEM_THEME
		return true;
	}
	return false;
}
//----

///Jasmine 08/13/2010 ORG-172-S2 CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
bool xf_load_nopreview(PageBase& pgTemp, DWORD dwClicks/* = OC_PREVIEW_NOCLICK_NOZOOMPAN*/, bool* pbLoadSystemTheme/* = NULL*/)
{
	GraphPage gp = pgTemp;
	if(gp)
	{
		if( page_load(gp, STR_NONE_PREVIEW_TEMPLATE, dwClicks, pbLoadSystemTheme) &&
			load_text_for_nonepreview_graphpage(gp, TEMPLATE_NONE_PREVIEW_CONTENT, TEMPLATE_NONE_PREVIEW_HINTS) )
			return true;
	}
	
	return false;
}
///End CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL

///Sandy add  2007-6-30 set noclick of page
DWORD get_gp_noclick(GraphPage& gp)
{
	if(!gp)
		return false;

	gp.LT_execute("page_noclick = page.noClick;");

	double noClicks;
	if(LT_get_var( "page_noclick", &noClicks))
		return (DWORD)noClicks;
	else return -1;
	
}

bool set_gp_noclick(GraphPage& gp, const DWORD noClicks)
{
	if(!gp)
		return false;

	string strLT;
	strLT.Format("page.noClick=%d", noClicks);
	gp.LT_execute(strLT);

	return true;
	
}
///end

BOOL	resolve_active_data_plot(TreeNode& tr)
{
	GraphLayer gl = Project.ActiveLayer();
	if( !gl )
		return error_report("Non-graph window is active");
	DataPlot dp = gl.DataPlots(-1);
	if( !data_plot_update_xy_data_range_tree(dp, tr) )
		return error_report("Unable to resolve active DataPlot");
	
	return TRUE;
}


//----- CPY 1/4/06 XF_GRAPH_PREVIEW

bool xy_range_from_GetN_data_node(TreeNode& trGetNinputData, XYRange& xy)
{
	return okxf_resolve_tree_construct_range(&trGetNinputData, &xy);
}

/*
static void _add_data_range(XYRange& xy, LPCSTR lpcszType, Worksheet& wks, int nCol)
{
	if(nCol>=0)
	{
		//	xy.Add(lpcszType, make_range_string(wks, wks.Columns(nCol).GetName()));
		xy.Add(wks, nCol, lpcszType); 
	}
	else
		xy.Add(lpcszType, "");		
}
*/
bool xy_range_from_wks_cols(XYRange& xy, Worksheet& wks, int nX, int nY, int nYErr)
{
	/*
	_add_data_range(xy, "X", wks, nX);
	_add_data_range(xy, "Y", wks, nY);
	_add_data_range(xy, "ED", wks, nYErr);
	*/
	Tree tr;
	string strX;
	string strY;
	string strErr;
	if( nX >= 0 )
		strX = make_range_string(wks, wks.Columns(nX).GetName());
	if( nY >= 0 )
		strY = make_range_string(wks, wks.Columns(nY).GetName());
	if( nYErr >= 0 )
		strErr = make_range_string(wks, wks.Columns(nYErr).GetName());
	if( octree_set_composite_subrange_values(&tr, strX, strY, strErr) )
	{
		if( !xy )
			xy.Create();
		
		xy.SetTree(tr, DRTREE_ONE_DATA);
	}
	
	return true;
}

///Kyle 03/13/2009 QA80-13260-S1 ADD_OPTION_TO_COPY_FORMAT_FROM_SOURCE_LAYER
///Kyle 04/10/2009 QA80-13260-P3 COPY_RELATIVE_SETTING_WHILE_COPYING_SCALE_TYPE
//typedef bool (*FUNC_LAYER_GET_SCALE_TYPE) (GraphLayer& gl, int* pnXScale = NULL, int* pnYScale = NULL);
//typedef bool (*FUNC_LAYER_SET_SCALE_TYPE) (GraphLayer& gl, string strAxis, int nType, bool bUndo = false);
///End COPY_RELATIVE_SETTING_WHILE_COPYING_SCALE_TYPE

static void _preview_copy_layer_format(GraphLayer& glDest, const GraphLayer& glSrc, DWORD dwCopyLayerFormat)
{
	if(!glDest || !glSrc || !dwCopyLayerFormat)
		return;
	
	if(dwCopyLayerFormat & PREVIEW_LAYER_FORMAT_SCALE_TYPE)
	{
		///-----------Kyle 04/10/2009 QA80-13260-P3 COPY_RELATIVE_SETTING_WHILE_COPYING_SCALE_TYPE
		//string strPath = "Originlab\\graph_utils.c";
		//FUNC_LAYER_GET_SCALE_TYPE pfnGet = Project.FindFunction("axis_get_scale_type", strPath, true);
		//FUNC_LAYER_SET_SCALE_TYPE pfnSet = Project.FindFunction("axis_set_scale_type", strPath, true);
		//if( !pfnGet || !pfnSet )
		//{
		//	ASSERT(0);
		//}
		//int nXScale, nYScale;
		//pfnGet( glSrc, &nXScale, &nYScale);
		//pfnSet(glDest, "X", nXScale);
		//pfnSet(glDest, "Y", nYScale);
		Tree 		trSrc;
		trSrc = glSrc.GetFormat(FPB_SCALE, FOB_SCALE, true, true);
		TreeNode	trSrcAxes = trSrc.Root.Axes;
		if( !trSrcAxes )
			return;

		Tree 		trDest;
		trDest = glDest.GetFormat(FPB_SCALE, FOB_SCALE, true, true);
		TreeNode	trDestAxes = trDest.Root.Axes;
		if( !trDestAxes )
			return;
		trDestAxes.Replace(trSrcAxes);

		glDest.UpdateThemeIDs(trDest.Root);
		glDest.ApplyFormat(trDest, true, true);
		///-----------End COPY_RELATIVE_SETTING_WHILE_COPYING_SCALE_TYPE
	}
}
///End ADD_OPTION_TO_COPY_FORMAT_FROM_SOURCE_LAYER

// clear of graph and add original plot and preview plot
///Kyle 03/13/2009 QA80-13260-S1 ADD_OPTION_TO_COPY_FORMAT_FROM_SOURCE_LAYER
//bool init_preview_graph(TreeNode& trGetNinputData, PageBase& pgPreview, Worksheet& wksPreview, LPCSTR lpcszGraphTemplate, 
//XYRange* pxyIn, XYRange* pxyPreviwe, int nLayer, int nColor, int nResultColor)// = NULL = NULL
bool init_preview_graph(TreeNode& trGetNinputData, PageBase& pgPreview, Worksheet& wksPreview, LPCSTR lpcszGraphTemplate, 
///------ Folger 03/16/09 QA80-13260-P1 MULTIPLE_SOURCE_XYRANGES_PLOTTING_IN_XF_PREVIEW_DIALOG
//XYRange* pxyIn, XYRange* pxyPreviwe, int nLayer, int nColor, int nResultColor, DWORD dwCopyLayerFormat)// = NULL = NULL
XYRange* pxyIn, XYRange* pxyPreviwe, int nLayer, int nColor, int nResultColor, DWORD dwCopyLayerFormat, bool bPlotFirstSourceRangeOnly/* = false*/)// = NULL = NULL
///------ End MULTIPLE_SOURCE_XYRANGES_PLOTTING_IN_XF_PREVIEW_DIALOG
///End ADD_OPTION_TO_COPY_FORMAT_FROM_SOURCE_LAYER
{
	GraphPage pg = pgPreview;
	string strTemplate = lpcszGraphTemplate;
	if(!strTemplate.IsEmpty())
		///Kyle 08/10/2010 ORG-172-S1 OC_DISABLE_ZOOM_FOR_PREVIEW
		//page_load(pg, strTemplate, NOCLICK_DATA_PLOT | NOCLICK_TICKLABEL | NOCLICK_LAYER | NOCLICK_LAYERICON | NOCLICK_AXES);
		///Jasmine 08/13/2010 ORG-172-S2 CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
		//page_load(pg, strTemplate, NOCLICK_DATA_PLOT | NOCLICK_TICKLABEL | NOCLICK_LAYER | NOCLICK_LAYERICON | NOCLICK_AXES | NOCLICK_ZOOMPAN);
		page_load(pg, strTemplate, OC_PREVIEW_NOCLICK_NOZOOMPAN);
		///End CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
		///End OC_DISABLE_ZOOM_FOR_PREVIEW

	GraphLayer gl = pg.Layers(nLayer);
	if(!gl)
		return error_report("init_preview_graph failed for layer index = " + nLayer);
	
	//remove all graph dataplot
	int nPlots = gl.DataPlots.Count();
	for(int ii = 0; ii < nPlots; ii++)
		gl.RemovePlot(0);
	
	XYRange xy;
	if(pxyIn == NULL)
		pxyIn = &xy;
		
	xy_range_from_GetN_data_node(trGetNinputData, *pxyIn);
	
	///Kyle 03/13/2009 QA80-13260-S1 ADD_OPTION_TO_COPY_FORMAT_FROM_SOURCE_LAYER
	if(pxyIn->IsValid() && dwCopyLayerFormat)
	{
		DataPlot dpSrc;
		///Kyle 03/20/2009 SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
		//if( pxyIn->GetPlot(dpSrc) && dpSrc.IsValid())
		vector<uint> vUID;
		pxyIn->GetPlots(vUID);
		if(vUID.GetSize() > 0)
			dpSrc = (DataPlot)Project.GetObject(vUID[0]);
		if( dpSrc.IsValid())
		///End SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
		{
			GraphLayer glSrc;
			dpSrc.GetParent(glSrc);
			if(glSrc)
				_preview_copy_layer_format(gl, glSrc, dwCopyLayerFormat);
		}
	}
	///End ADD_OPTION_TO_COPY_FORMAT_FROM_SOURCE_LAYER

	///------ Folger 03/16/09 QA80-13260-P1 MULTIPLE_SOURCE_XYRANGES_PLOTTING_IN_XF_PREVIEW_DIALOG
	///// YuI 12/19/05 XFUNCTION_OC_TO_VC_CONVERSION
	////	DataPlot dpData = pxyIn->MakePlot(gl, IDM_PLOT_LINE);
//#ifndef SELF_CREATING_RANGE_VC_BASED
	//DataPlot dpData = pxyIn->MakePlot(gl, IDM_PLOT_LINE);
//#else// SELF_CREATING_RANGE_VC_BASED
	//DataPlot dpData = pxyIn->MakePlot(gl);
//#endif //SELF_CREATING_RANGE_VC_BASED
	///// end XFUNCTION_OC_TO_VC_CONVERSION
	//if(!dpData)
	//{
		//return error_report("init_preview_graph failed to create plot, most likely XYRange invalid");
	//}
	//if(nColor >= 0)
	//{
		//dpData.SetColor(nColor);
	//}
	///Kyle 03/20/2009 SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
	// apply grayscale.pal to the dataplots if there are multiple dataplots and all are shown,
	// in case that the nearby dataplots are almost with the same color, the dataplots are equably distributed in the full range of grayscale.pal
	int nPlotType = IDM_PLOT_LINE;
	int nColorIndex = 0, nColorSize = 0, nColorStep = 1;		// step to the next color
	vector<int> rgb;
	int nNumSrcData = pxyIn->GetNumData(DRR_NO_FACTORS | DRR_GET_DEPENDENT);
	if(nNumSrcData > 1)
	{
		string strGrayPal = okutil_get_origin_path(ORIGIN_PATH_SYSTEM) + "Palettes\\grayscale.pal";
		okutil_palette_load(strGrayPal, &rgb);
		if(rgb.GetSize() <= 0 && nColor >= 0)
			rgb.Add(color_index_to_rgb(nColor));
		nColorSize = rgb.GetSize();
		nColorStep = nColorSize / nNumSrcData;
	}
	///End SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
	DataPlot dpData;
	for ( int nIndex=0; nIndex<nNumSrcData; ++nIndex )
	{
		/// seems SELF_CREATING_RANGE_VC_BASED is some old logic not used now ...
		//#ifndef SELF_CREATING_RANGE_VC_BASED
		//dpData = pxyIn->MakePlot(gl, IDM_PLOT_LINE);
		//#else// SELF_CREATING_RANGE_VC_BASED
		dpData = pxyIn->MakePlot(gl, NULL, nIndex);
		//#endif //SELF_CREATING_RANGE_VC_BASED
		
		if(!dpData)
		{
			return error_report("init_preview_graph failed to create plot, most likely XYRange invalid");
		}
		
		///Kyle 03/20/2009 SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
		//if(nColor >= 0)
		//{
			//dpData.SetColor(nColor + nIndex);
		//}
		if(nNumSrcData > 1 && !bPlotFirstSourceRangeOnly)
		{
			if(nColorSize)
			{
				if(nColorIndex >= nColorSize )
					nColorIndex = 0;
				dpData.SetColor(RGB2OCOLOR(rgb[nColorIndex]));
				nColorIndex += nColorStep;
			}
		}
		else if(nColor >= 0)
			dpData.SetColor(nColor);
		///End SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
		
		///Kyle 03/20/2009 SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH, get source plottype for result plot
		if(nIndex == 0)
		{
			nPlotType = dpData.GetPlotType();
		}
		///End SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
		if ( bPlotFirstSourceRangeOnly )
			break;
	}
	///Kyle 03/20/2009 SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
	//if ( nColor + nIndex > nResultColor )
		//nResultColor = nColor + nIndex;
	///End SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
	///------ End MULTIPLE_SOURCE_XYRANGES_PLOTTING_IN_XF_PREVIEW_DIALOG
	
	// for now, assume XY for preview data
	if(wksPreview.GetNumCols() < 2)
		return error_report("init_preview_graph found preview wks not properly setup");
	int nX = 0, nY = 1;
	//----- temp code, need to call centralized function later
	if(pxyPreviwe)
	{
		xy_range_from_wks_cols(*pxyPreviwe, wksPreview, nX, nY);
	}
	//-----	
	Curve cuvPrev(wksPreview, nX, nY);
	///Kyle 03/20/2009 SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
	//int nn = gl.AddPlot(cuvPrev, IDM_PLOT_LINE);
	int nn = gl.AddPlot(cuvPrev, nPlotType);
	///End SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
	DataPlot dp = gl.DataPlots(nn);
	if(dp)
	{
		if(nResultColor >= 0)
			dp.SetColor(nResultColor);

		///Kyle 03/20/2009 SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH
		if(pxyIn->GetNumData(DRR_NO_FACTORS | DRR_GET_DEPENDENT) > 1 && !bPlotFirstSourceRangeOnly)		// multiple input, preview result should be thicker
		{
			Tree trFormat;
			trFormat.Root.Line.Width.dVal = 3;
			dp.UpdateThemeIDs(trFormat.Root);
			dp.ApplyFormat(trFormat, true, true);
		}
		///End SAME_COLOR_FOR_SOURCE_AND_RED_FOR_RESULT_IN_PREVIEW_GRAPH

		if(!strTemplate.IsEmpty()) //----CPY 12/23/08 SMOOTH_ETC_XF_WITH_PREVIEW_SHOULD_NOT_RESCALE_GRAPH_UPON_CHANGE
			gl.Rescale(ANL_RUN_LT_SIZEMOVE);
		//--- CPY 7/20/06 FFT_FILTERS_ZOOM_RECT_FOR_BETTER_PREVIEW
		if(nLayer == pg.Layers.Count()-2) // preview in second last layer, which mean that there is another layer after this, so most likely it is for zoom in view of preview layer
		{
			GraphLayer glZoom = pg.Layers(nLayer+1);
			glZoom.AddPlot(dpData);
			glZoom.AddPlot(dp);
			//glZoom.Rescale();
		}
		//---
		
		legend_update(gl);			///------ Folger 03/16/09 QA80-13260-P1 MULTIPLE_SOURCE_XYRANGES_PLOTTING_IN_XF_PREVIEW_DIALOG
		return true;
	}
	return error_report("init_preview_graph failed to add preview plot");
}
//----- end CPY 1/4/06 XF_GRAPH_PREVIEW

//--- CPY QA70-8615-5 7/12/06 REMOVE_COMMENTS_COL_FROM_REPORT
bool wks_set_show_labels(Worksheet& wks, 
int nLine1, int nLine2, int nLine3, int nLine4, int nLine5)
{
	/// ML 8/7/2006 GET_SET_SHOW_LABELS_BY_ARRAY_OF_TYPES
	/*
	Tree tr;
	if(_wks_get_labels_show_theme(wks, tr))
	{
		TreeNode trLabel = tr.Root.Dimensions.Horizontal.Labels;
		if(trLabel)
		{
			int nLines = 0;
			if(nLine1 >= 0)
			{
				nLines++;
				trLabel.Label1.Type.nVal = nLine1;
				if(nLine2 >= 0)
				{
					nLines++;
					trLabel.Label2.Type.nVal = nLine2;
					if(nLine3 >= 0)
					{
						nLines++;
						trLabel.Label3.Type.nVal = nLine3;
						if(nLine4 >= 0)
						{
							nLines++;
							trLabel.Label4.Type.nVal = nLine4;
							if(nLine5 >= 0)
							{
								nLines++;
								trLabel.Label5.Type.nVal = nLine5;
							}
						}
					}
				}
			}
			// we need to del those labels not specified
			int nLabels;// should be safe to assume Lable1,2,3,4
			while((nLabels = trLabel.GetNodeCount()) > nLines)
			{
				string strTag = "Label" + nLabels;
				trLabel.RemoveChild(strTag);
			}
			Grid grid;
			grid.Attach(wks);
			grid.UpdateThemeIDs(tr.Root);
			grid.ApplyFormat(tr, TRUE, TRUE);
			return true;
		}
	}
	return false;
	*/
	Grid		grid;
	grid.Attach(wks);
	if(grid.SetShowLabels(FALSE, nLine1, nLine2, nLine3, nLine4, nLine5))
	{
		wks.Invalidate();
		return true;
	}
	return false;
	/// end GET_SET_SHOW_LABELS_BY_ARRAY_OF_TYPES
}

bool wks_get_show_labels(const Worksheet& wks, vector<int>& vnIDs)
{
	Tree tr;
	if(wks_get_labels_show_theme(wks, tr))
	{
		vnIDs.SetSize(0); ///---Sim 03-15-2007 QA80-9325-P4 REFIX_NOT_SHOW_LABEL
		TreeNode trLabels = tr.Root.Dimensions.Horizontal.Labels;
		if(trLabels)
		{
			TreeNodeCollection tnc(trLabels, "Label");
			//vnIDs.SetSize(0); ///---Sim 03-15-2007 QA80-9325-P4 REFIX_NOT_SHOW_LABEL remove
			foreach(TreeNode tn in tnc)
				vnIDs.Add(tn.Type.nVal);
			//return true; ///---Sim 03-15-2007 QA80-9325-P4 REFIX_NOT_SHOW_LABEL remove
		}
		return true; ///---Sim 03-15-2007 QA80-9325-P4 REFIX_NOT_SHOW_LABEL
	}
	return false;
}

//----


//----- Deanna 4/17/2006 SET_SHOW_AXIS
static void _set_show_axis_obj(AxisObject& ao, bool bSetShow)
{
	Tree tr;
	bool bRelative = TRUE;
	tr = ao.GetFormat(FPB_ALL, FOB_ALL, true, bRelative);
	//out_tree(tr);
	TreeNode trShow = tr.Root.GetNode("Show");
	trShow.nVal = bSetShow;
	ao.ApplyFormat(tr, true, bRelative);	
}
static void _set_show_axis_and_ticklabels(GraphLayer gl, int nAxis, int nAObjIndex, bool bShow)
{
	int nLabelObjIndex = AXISOBJPOS_AXIS_SECOND==nAObjIndex? AXISOBJPOS_LABEL_SECOND : AXISOBJPOS_LABEL_FIRST; 
	AxisObject aoA, aoL;
	if(YAXIS == nAxis)
	{
		aoA = gl.YAxis.AxisObjects(nAObjIndex);
		aoL = gl.YAxis.AxisObjects(nLabelObjIndex);
	}
	else
	{
		aoA = gl.XAxis.AxisObjects(nAObjIndex);
		aoL = gl.XAxis.AxisObjects(nLabelObjIndex);
	}
	_set_show_axis_obj(aoA, bShow);
	_set_show_axis_obj(aoL, bShow);
}

/// Hong 08/08/07 QA80-10064 FIX_LEGEND_COMBINE_FAIL_KEEP_ORIGIN_ORDER
static bool _is_one_legend_for_one_layer(LPCSTR lpszLegend)
{
	string		strText = lpszLegend;

	strText.MakeLower();
	int nStart = strText.Find("\l(");
	if(nStart >= 0)
	{
		int nEnd = strText.Find(')', nStart);
		if( nEnd >= 0 )
		{
			int nPos = strText.Find('.', nStart);
			return (nPos >=0 && nPos < nEnd)? false : true; 
		}
	}
	
	return false;
}
/// end FIX_LEGEND_COMBINE_FAIL_KEEP_ORIGIN_ORDER

/// Iris 07/20/2007 IMPROVE_LEGEND_UPDATE
static bool _is_one_legend_for_one_layer(const GraphObject& goLegend)
{
	string		strText = goLegend.Text;
	/// Hong 08/08/07 QA80-10064 FIX_LEGEND_COMBINE_FAIL_KEEP_ORIGIN_ORDER
	/*
	/// Iris 07/20/2007 IMPROVE_LEGEND_UPDATE
	////  "." may be used as separator to separate each legend, so should find from "%(" and end with ")" for this "." here
	//return strText.Find('.') < 0 ? true : false;		
	int nStart = strText.Find("%(");
	if(nStart >= 0)
	{
		int nEnd = strText.Find(')', nStart);
		if( nEnd >= 0 )
		{
			// "%(LayerIndex.PlotIndex)" means one legend of all layers; 
			// "%(PlotIndex)", not dot, means one legend for one layer
			int nPos = strText.Find('.', nStart);
			return (nPos >=0 && nPos < nEnd)? false : true; 
		}
	}
	return false;
	///end IMPROVE_LEGEND_UPDATE
	*/
	return _is_one_legend_for_one_layer(strText);
	/// end FIX_LEGEND_COMBINE_FAIL_KEEP_ORIGIN_ORDER
}

/// Hong 07/24/07 v8.0666 SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
bool is_page_one_legend_for_all(GraphPage& gp, int& nLayerIndex)
{	
	int nNum = 0;
	int nIndex = -1;
	foreach(GraphLayer gl in gp.Layers)
	{
		nIndex++;
		
		GraphObject 	go = gl.GraphObjects(GO_LEGEND_NAME);
		
		if ( !go )
			continue;
		
		if ( !_is_one_legend_for_one_layer(go) )
		{			
			nNum++;	
			if ( nNum > 1 )
				break;
			
			if ( &nLayerIndex != NULL )
				nLayerIndex = nIndex;
		}
	}
	
	if ( 1 == nNum )
		return true;	
	
	if ( &nLayerIndex != NULL )
			nLayerIndex = -1;	
			
	return false;
}

static string _construct_one_legend_LT_pre_text(const GraphObject& goLegend, const GraphLayer& gl, int nPlot)
{
	string	str;
	if( _is_one_legend_for_one_layer(goLegend) )
	{
		str = "(%d";		
		str.Format(str, nPlot + 1);
	}
	else
	{
		str = "(%d.%d";
		str.Format(str, gl.GetIndex() + 1, nPlot + 1);
	}
	
	return str;
}
/// end SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND


//------Iris 07/31/2007 v8.0671 moved from graph_utils
///Arvin 06/07/07 CHANGE_LEGEND_TO_USE_LONG_NAME_AND_UNIT as max's suggestion
///Arvin 07/19/07 USE_STRING_TYPE_LEGEND_DIRECTLY as CP said
//bool legend_append_plot(GraphLayer& gl, int nPlot, int nLegendType)
bool legend_append_plot(GraphLayer& gl, int nPlot, LPCSTR lpcszExtraFormat, LPCSTR lpcszSep) //The seperator string may not be "\r\n" as Iris said
///end USE_STRING_TYPE_LEGEND_DIRECTLY
{	
	//if(!gl)
	if(!gl || _is_plot_not_to_add_legend(gl, nPlot)) /// Hong 08/21/07 v8.0685 SKIP_ERR_BAR_WHEN_LEGEND_APPEND_PLOT
		return false;
	
	GraphObject	goLegend = gl.GraphObjects(GO_LEGEND_NAME);
	if(!goLegend)
	{
		return false;
	}
	
	string		strText = goLegend.Text;
	///Arvin 06/07/07 CHANGE_LEGEND_TO_USE_LONG_NAME_AND_UNIT as max's suggestion
	//strText = strText + "\r\n" + construct_one_legend_LT_text(goLegend, gl, nPlot);
	/// Iris 06/14/2007 v8.0640 AVOILD_DUP_PLOT_LEGEND_TEXT
	//strText = strText + "\r\n" + construct_one_legend_LT_text(goLegend, gl, nPlot, nLegendType);
	string		strNewLegend = construct_one_legend_LT_text(goLegend, gl, nPlot, lpcszExtraFormat);
	string strNew = strNewLegend.GetToken(0, '%');
	int nStart = strText.Find(strNew);
	//Append new legend
	string strSep(lpcszSep);
	if(strSep.IsEmpty())
		strSep = "\r\n";
	
	if(  nStart < 0)
		strText = strText + strSep + strNewLegend;
	///Jasmine 08/07/07 APPEND_NEW_AFTER_DELETE_OLD
	///*
	//Replace old legend by new type legend
	else
	{
		//int nEnd = strText.Find("\r\n", nStart);		
		int	nEnd = strText.Find("\l", nStart + 1);
		if(nEnd < 0)
			nEnd = strText.Find("\L", nStart + 1);
		if(nEnd < 0) // is the last legned
			nEnd = strText.GetLength();//-1;	///Jasmine 08/07/07 APPEND_NEW_AFTER_DELETE_OLD
		else
			strNewLegend += strSep;
		strText.Delete(nStart, nEnd-nStart);//+1);	///Jasmine 08/07/07 APPEND_NEW_AFTER_DELETE_OLD
		strText.Insert(nStart, strNewLegend);
	}
	//*/
	///End APPEND_NEW_AFTER_DELETE_OLD
	///end AVOILD_DUP_PLOT_LEGEND_TEXT
	///end CHANGE_LEGEND_TO_USE_LONG_NAME_AND_UNIT
	
	///Jake 07/18/07 TRIM_LEGEND_TEXT_WHEN_GOLEGENDTEXT_IS_EMPTY_AT_FIRST
	strText.TrimLeft(strSep);
	strText.TrimRight(strSep);
	///end TRIM_LEGEND_TEXT_WHEN_GOLEGENDTEXT_IS_EMPTY_AT_FIRST
	
	goLegend.Text = strText;
	//----- CPY 8/7/2007 QA70-10175 SET_LEGEND_TEXT_ALSO_MIGHT_NEED_TO_TURN_OFF_AUTO_UPDATE
	// should not be needed, if not working, better fix properly
	//gl.GetPage().Refresh(true); //legend will not be auto updated if not do refresh...
	//-----
	
	return true;	
}


bool legend_delete_plot(GraphLayer& gl, int nPlot)
{
	if(!gl)
		return false;
	
	GraphObject	goLegend = gl.GraphObjects(GO_LEGEND_NAME);
	if(!goLegend)
	{
		return false;
	}
	
	string		strText = goLegend.Text;
	string		strFind = construct_one_legend_LT_text(goLegend, gl, nPlot);
	
	vector<string>	vsText;
	///Arvin 07/20/07 SUPPORT_OTHER_SEPERATOR_STRINGS
	//The seperator string may not be "\r\n" as Iris said
	//string			strSep = "\r\n";
	//str_separate(strText, strSep, vsText);
	///END SUPPORT_OTHER_SEPERATOR_STRINGS
	///Jake 07/19/07 FIX_FAIDED_TO_FIND_FORMAT
	/*
	int		nFind = vsText.Find(strFind);
	if(nFind < 0 || nFind >= vsText.GetSize())
		return false;
	
	vsText.RemoveAt(nFind);
	*/
	string		strFirstPart = strFind.GetToken(0, '%');
	///Arvin 07/20/07 SUPPORT_OTHER_SEPERATOR_STRINGS
	/*
	for(int ii = 0; ii < vsText.GetSize(); ii++)
	{
		int nRet = vsText[ii].Find(strFirstPart);
		if(nRet > -1)
		{
			vsText.RemoveAt(ii);
			break;
		}
	}
	*/
	int nStart = strText.Find(strFirstPart);
	if(nStart < 0)
		return false;
	int nEnd = strText.Find("\l(", nStart+1);//The start of next legend
	if(nEnd < 0) //is the last legend
		nEnd = strText.GetLength();
	
	strText.Delete(nStart, nEnd-nStart);
	strText.TrimLeft("\r\n");
	strText.TrimRight("\r\n");
	///end SUPPORT_OTHER_SEPERATOR_STRINGS
	///end FIX_FAIDED_TO_FIND_FORMAT
	
	//strText = str_combine(vsText, strSep); ///Arvin 07/20/07 SUPPORT_OTHER_SEPERATOR_STRINGS
	
	goLegend.Text = strText;
	return true;
}
//------


// moved from graph_utils
///Arvin 11/16/07 QA70-10676 UPDATE_MEANS_COMPARISION_PLOT_LEGENT_WITH_SIG_INFO
//string construct_one_legend_LT_text(const GraphObject& goLegend, const GraphLayer& gl, int nPlot, LPCSTR lpcszExtraFormat)
string construct_one_legend_LT_text(const GraphObject& goLegend, const GraphLayer& gl, int nPlot, LPCSTR lpcszExtraFormat, int nUnit)
///end UPDATE_MEANS_COMPARISION_PLOT_LEGENT_WITH_SIG_INFO
{
	string	str;
	/// Hong 07/24/07 v8.0666 SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
	/*
	if( _is_one_legend_for_one_layer(goLegend) )
	{
		str = _L("(%d");		
		str.Format(str, nPlot + 1);
	}
	else
	{
		str = _L("(%d.%d");
		str.Format(str, gl.GetIndex() + 1, nPlot + 1);
	}
	*/
	str = _construct_one_legend_LT_pre_text(goLegend, gl, nPlot);
	/// end SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
	string	str2ndPart = str;
	///Arvin 11/16/07 QA70-10676 UPDATE_MEANS_COMPARISION_PLOT_LEGENT_WITH_SIG_INFO
	if(nUnit >= 0)
		str = str + "," + ftoa(nUnit+1);
	///end UPDATE_MEANS_COMPARISION_PLOT_LEGENT_WITH_SIG_INFO
	string 	strLegendType = lpcszExtraFormat;
	if( !strLegendType.IsEmpty() )
		str2ndPart += "," + strLegendType;
	
	
	string	strText;
	strText = "\l" + str + ")";
	strText += " ";
	strText += "%" + str2ndPart + ")";
	return strText;
}

//---- CPY 7/27/2007 SKIP_ERR_BARS_WHEN_UPDATE_ADD_LEGEND
static bool _is_plot_not_to_add_legend(GraphLayer& gl, int nPlot)
{
	DataPlot dp = gl.DataPlots(nPlot);
	if(dp)
	{
		int nPlotType = dp.GetPlotType();
		if(IS_TXT_ERR_BAR_PLOT_ID(nPlotType))
			return true;
		
		return false;
	}
	return true;
}
//----

bool	legend_check_remove_invalid_plot(GraphObject& go, vector<uint> &vnExistedPlots)
{
	if(!go.IsValid())
		return false;
	
	GraphLayer gl;
	go.GetParent(gl);
	
	int 		nLgLyIndex = gl.GetIndex();	
	GraphPage 	gp = gl.GetPage();
	int 		nLyNum = gp.Layers.Count();
	
	string	strLegend = go.Text;
	
	vector<uint> vnExistedPlotsTemp;
	int nStart = 0, nEnd = 0;
	while(true)
	{
		/// Iris 07/23/2007 SHOULD_FIND_LEGEND_BY_L
		//int		nPrecentPos = strLegend.Find("%", nStart);
		//if(nPrecentPos < 0) //cannot find next %
		//	break;
		int		nLPos = strLegend.Find("\l", nStart);
		if(nLPos < 0)
			nLPos = strLegend.Find("\L", nStart);
		if(nLPos < 0) //cannot find next "\l"
			break;
		///end SHOULD_FIND_LEGEND_BY_L
		
		int		nPlotStart = strLegend.Find("(",  nLPos) + 1; // the position of ( + 1
		nEnd = strLegend.Find(")",  nPlotStart); //the positon of )
		int		nPlotEnd = nEnd - 1; 
		/// Hong 07/24/07 v8.0666 SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND		
		//int nLTPlot = atoi( strLegend.Mid(nPlotStart, nPlotEnd - nPlotStart + 1) );
		//if( nLTPlot <= 0 || nLTPlot > nNumPlots) // for invalid plot index, should delete the relative lengend
		int nLyIndex = nLgLyIndex;
		/// Iris 07/25/2007 v8.0667 LEGEND_UPDATE_FAIL_TO_DEL_INVALID_PLOT
		/*
		//int nPos = strLegend.Find(".", nPlotStart) + 1; // the position of . + 1
		//if ( nPos > nPlotStart && nPos <= nPlotEnd )
			nLyIndex = atoi( strLegend.Mid(nPlotStart, nPos - nPlotStart - 1) ) - 1;
		else if ( nPos < 0 )
			nPos = nPlotStart;
		
		int nLTPlot = atoi( strLegend.Mid(nPos, nPlotEnd - nPos + 1) );
		*/
		int nDotPos = strLegend.Find(".", nPlotStart); // the position of .
		if ( nDotPos > nPlotStart && nDotPos < nPlotEnd )
		{
			nLyIndex = atoi( strLegend.Mid(nPlotStart, nDotPos - nPlotStart) ) - 1;
			nPlotStart = nDotPos + 1;
		}
		int nLTPlot = atoi( strLegend.Mid(nPlotStart, nPlotEnd - nPlotStart + 1) );
		///end LEGEND_UPDATE_FAIL_TO_DEL_INVALID_PLOT
		
		
		bool bInvalidLayer = false, bInvalidPlot = false;
		if ( nLyIndex < 0 || nLyIndex > nLyNum - 1)
			bInvalidLayer = true;
		
		if ( !bInvalidLayer )
		{
			GraphLayer glTemp = gp.Layers(nLyIndex);
			int nTempNumPlots = glTemp.DataPlots.Count();
			
			if ( nLTPlot <= 0 || nLTPlot > nTempNumPlots)
				bInvalidPlot = true;
		}
		
		if ( bInvalidLayer || bInvalidPlot )
		/// end SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND				
		{
			/// Hong 07/24/07 v8.0666 FIX_FAIL_DELETE_INVALID_LEGEND			
			//strLegend.Delete(nStart, nEnd - nStart + 1);
			int nNextLPos = strLegend.Find("\l", nPlotEnd);
			if ( -1 == nNextLPos )
				nNextLPos = strLegend.GetLength();
			
			strLegend.Delete(nLPos, nNextLPos - nLPos);
			nEnd = nStart;
			/// end FIX_FAIL_DELETE_INVALID_LEGEND
		}
		else if ( nLyIndex == nLgLyIndex ) /// Hong 07/24/07 v8.0666 SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
			vnExistedPlotsTemp.Add(nLTPlot);
		
		nStart = nEnd + 1;
		
		if(nEnd >= strLegend.GetLength() - 1)
			break;		
	}
	
	strLegend.TrimRight();
	go.Text = strLegend;
	
	if(vnExistedPlots)
		vnExistedPlots = vnExistedPlotsTemp;
	
	return true;
	
}
	
/// Hong 07/24/07 v8.0666 SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND	
//static bool _legend_update(GraphObject& go)
static bool _legend_update(GraphObject& go, bool bOneforAll = false)
/// end SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
{
	if(!go.IsValid())
		return false;
	
	GraphLayer gl;
	go.GetParent(gl);
	/// Hong 07/24/07 v8.0666 SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
	int nLgLyIndex = gl.GetIndex();	
	GraphPage gp = gl.GetPage();
	int nLyNum = gp.Layers.Count();
	///// end SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
	//string		strLegend = go.Text; /// Hong 08/23/07 v8.0688 FIX_INVALID_PLOT_FAIL_REMOVED
	int 		nNumPlots = gl.DataPlots.Count();
	
	//------ delete invalid legend
	vector<uint> 	vnExistedPlots;
	legend_check_remove_invalid_plot(go, vnExistedPlots);
	
	string		strLegend = go.Text; /// Hong 08/23/07 v8.0688 FIX_INVALID_PLOT_FAIL_REMOVED
	//------  add new legends
	string	strSep = "\r\n";
	for(int nn = 0; nn < nNumPlots; nn++)
	{
		vector<uint> 	vecIndex;
		if( vnExistedPlots.Find(vecIndex, nn+1) <= 0 )// not existed, need add
		{
			if(_is_plot_not_to_add_legend(gl, nn)) //---- CPY 7/27/2007 SKIP_ERR_BARS_WHEN_UPDATE_ADD_LEGEND
				continue;
			string strNew = construct_one_legend_LT_text(go, gl, nn);
			strLegend += strSep + strNew;
		}
	}
	/// Hong 07/24/07 v8.0666 SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
	if ( bOneforAll )
	{
		for (int nn = 0; nn < gp.Layers.Count(); nn++)
		{
			if ( nLgLyIndex == nn )
				continue;
			
			GraphLayer gl2 = gp.Layers(nn);
			
			string strKey;
			for (int ii = 0; ii < gl2.DataPlots.Count(); ii++)
			{
				if(_is_plot_not_to_add_legend(gl2, ii)) //---- CPY 7/27/2007 SKIP_ERR_BARS_WHEN_UPDATE_ADD_LEGEND
					continue;
				
				strKey = _construct_one_legend_LT_pre_text(go, gl2, ii);
				int nPos = strLegend.Find("\l" + strKey);
				if ( nPos < 0 )
					nPos = strLegend.Find("\L" + strKey);
				if ( nPos < 0 )
				{
					string strNew = construct_one_legend_LT_text(go, gl2, ii);
					strLegend += strSep + strNew;
				}
			}
		}
	}
	/// end SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
	strLegend.TrimLeft(strSep);
	strLegend.TrimRight(strSep);	
	go.Text = strLegend;
	
	
	return true;
}
////end IMPROVE_LEGEND_UPDATE

//--- CPY 7/14/06 LEGEND_SET_SHOW_CENTRAL_FUNC
//enum {ALM_COMMENT, ALM_RANGE, ALM_LONGNAME_UNITS, ALM_PARAM1};
/// Iris 07/20/2007 IMPROVE_LEGEND_UPDATE
//bool legend_update(GraphLayer& gl, int nLegendMode, bool bCreate, LPCSTR lpcszCustomFormat)
/// Hong 07/24/07 v8.0666 SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
//bool legend_update(GraphLayer& gl, int nLegendMode, bool bCreate, bool bReconstruct, LPCSTR lpcszCustomFormat)
/// Hong QA80-10064 v8.0672 LEGEND_ADD_ORDER_OPTION_WHEN_RECONSTRUCT
//bool legend_update(GraphLayer& gl, int nLegendMode, bool bCreate, bool bReconstruct, LPCSTR lpcszCustomFormat, bool bOneforAll) // false
bool legend_update(GraphLayer& gl, int nLegendMode, bool bCreate, bool bReconstruct, LPCSTR lpcszCustomFormat, bool bOneforAll, bool bAscending) // = false, =  true
/// end LEGEND_ADD_ORDER_OPTION_WHEN_RECONSTRUCT
/// end SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
///end IMPROVE_LEGEND_UPDATE
{
	if(!gl)
		return false;
	GraphPage gp = gl.GetPage();
	if(!gp)
		return false;

	if(nLegendMode >= 0) //---- CPY 10/29/2007 QA70-10599 NLFIT_PREVIEW_UPDATE_CLEANUP, found code pretty messy here so did rewrite and remove old codes
	{
		string strCustomFmt;
		int nCurentMode = get_page_legend_mode(gp, &strCustomFmt);
		bool bSameMode = true;
		if ( nCurentMode != nLegendMode || ( ALM_CUSTOM == nCurentMode && 0 != strCustomFmt.CompareNoCase(lpcszCustomFormat) ) )
			bSameMode = false;
		
		if( !bSameMode && nLegendMode <= ALM_CUSTOM )
		{
			set_page_legend_mode(gp, nLegendMode, lpcszCustomFormat);
		}
	}
	
	/// Iris 01/25/2007 CONTROL_HOW_PLOT_FIT_CURVE_ON_SOURCE_GRAPH
	//"legend -s" to Creates a legend or updates the current legend if one exists. 
	//gl.LT_execute("legend -s");
	GraphObject 	go = gl.GraphObjects(GO_LEGEND_NAME);
	/// Iris 07/20/2007 IMPROVE_LEGEND_UPDATE
	//if( go.IsValid() || bCreate)
	if( (!go.IsValid() && bCreate) || bReconstruct)
	///end IMPROVE_LEGEND_UPDATE
	{
		gl.LT_execute("legend -s");
		/// Hong QA80-10064 v8.0672 LEGEND_ADD_ORDER_OPTION_WHEN_RECONSTRUCT
		if ( bReconstruct && !bAscending )
		{
			go = gl.GraphObjects(GO_LEGEND_NAME);
			if ( go.IsValid() ) /// Hong 08/06/07 v8.0675 FIX_RUNTIME_ERROR_IF_NO_LEGEND		
			{
				string		strLegend = go.Text;
				string 		strSep = "\r\n";
				vector<string> vsLegends;
				str_separate(strLegend, strSep, vsLegends);
				strLegend.Empty();
				for (int ii = vsLegends.GetSize() - 1; ii >= 0; ii--)
				{
					strLegend += vsLegends[ii] + strSep;
				}
				strLegend.TrimRight(strSep);
				go.Text = strLegend;
			}
		}
		/// end LEGEND_ADD_ORDER_OPTION_WHEN_RECONSTRUCT
	}
	///end CONTROL_HOW_PLOT_FIT_CURVE_ON_SOURCE_GRAPH
	
	/// Iris 07/20/2007 IMPROVE_LEGEND_UPDATE
	go = gl.GraphObjects(GO_LEGEND_NAME);
	if( go.IsValid() && !bReconstruct )
	{
		/// Hong 07/24/07 v8.0666 SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
		//return _legend_update(go);
		return _legend_update(go, bOneforAll);
		/// end SUPPORT_UPDATE_ONE_FOR_ALL_LEGEND
	}
	///end IMPROVE_LEGEND_UPDATE
	
	return true;
}
//--- end LEGEND_SET_SHOW_CENTRAL_FUNC

/// Hong 08/17/07 v8.0684 MORE_RELIABLE_CODE
static int _find_legend_first_key_pos(const string& strLegend, int nStart = 0)
{
//	strLegend.MakeLower();
	return strLegend.Find("\l(", nStart);
}
/// end MORE_RELIABLE_CODE

/// Hong 08/08/07 QA80-10064 FIX_LEGEND_COMBINE_FAIL_KEEP_ORIGIN_ORDER
static string _get_one_for_all_legend_text(const GraphObject& goLegend)
{
	if (!goLegend)
		return "";
	
	GraphLayer gl;
	goLegend.GetParent(gl);
	int nIndex = gl.GetIndex();
	string strInsert;
	strInsert.Format("%d.", nIndex + 1);
	
	string strText = goLegend.Text;	
	int nStart = 0, nEnd = 0;
	while(true)
	{
		/// Hong 08/17/07 v8.0684 MORE_RELIABLE_CODE
		/*
		nStart = strText.Find("\l(", nStart);
		if ( nStart < 0 )
		{
			nStart = strText.Find("\L(", nStart);
			if ( nStart < 0 )
				break;
		}		
		*/
		nStart = _find_legend_first_key_pos(strText, nStart);
		if ( nStart < 0 )		
			break;
		/// end MORE_RELIABLE_CODE		
		string strTemp = strText.Right(strText.GetLength() - nStart);
		nStart += lstrlen("\l(");
		if ( _is_one_legend_for_one_layer(strTemp) )
		{
			strText.Insert(nStart, strInsert);
			
			int nPlot;
			nPlot = strText.Find("%(", nStart);
			//nPlot += lstrlen("%("); /// Hong 08/17/07 v8.0684 MORE_RELIABLE_CODE
			if ( -1 != nPlot )
			{
				/// Hong 08/17/07 v8.0684 MORE_RELIABLE_CODE
				nEnd = _find_legend_first_key_pos(strText, nStart + 1);			
				if ( -1 == nEnd || nPlot < nEnd )
				{
					nPlot += lstrlen("%(");
				/// end MORE_RELIABLE_CODE
				strText.Insert(nPlot, strInsert);
			}	
		}						
	}
	}
	
	return strText;
}

bool legend_combine(GraphPage& gp, int nLayerHasLegend, bool bAscending) // = 0, = true
{
	string strLegendText = "";
	string strSep = "\r\n";
	
	GraphObject goLegend;
	vector<string> vsLegendsText;
	foreach(GraphLayer gl in gp.Layers)
	{
		///------ Folger 11/12/09 QA81-14636 PLOT_STACK_AND_MYAXES_REARRANGE_DATAPLOTS_IN_MULTIPLE_LAYERS
		legend_update(gl);
		///------ End PLOT_STACK_AND_MYAXES_REARRANGE_DATAPLOTS_IN_MULTIPLE_LAYERS
		GraphObject goTemp;
		goTemp = gl.GraphObjects(GO_LEGEND_NAME);	
		
		if( nLayerHasLegend == gl.GetIndex() )				
		{			
			if(!goTemp)
			{
				legend_update(gl);
				goTemp = gl.GraphObjects(GO_LEGEND_NAME);
			}		
			goLegend = goTemp;
			vsLegendsText.Add( _get_one_for_all_legend_text(goLegend) );
		}
		else
		{
			vsLegendsText.Add( _get_one_for_all_legend_text(goTemp) );
			gl.RemoveGraphObject(GO_LEGEND_NAME);
		}						
	}
		
	if ( bAscending )
	{
		strLegendText = str_combine(vsLegendsText, strSep);
	}
	else
	{
		for (int ii = vsLegendsText.GetSize() - 1; ii >= 0; ii--)
		{
			strLegendText += vsLegendsText[ii] + strSep;			
		}
	}
	
	strLegendText.TrimLeft(strSep);
	strLegendText.TrimRight(strSep);	
	goLegend.Text = strLegendText;
	
	return true;
}
/// end FIX_LEGEND_COMBINE_FAIL_KEEP_ORIGIN_ORDER
	
/// Iris 07/31/2007 v8.0671 ADDED_UTILITY_FUNC_TO_GET_SET_LEGEND_MODE	
int get_page_legend_mode(GraphPage& gp, string* pstrCustomFormat)
{
	Tree tr;
	tr = gp.GetFormat(FPB_OTHER, FOB_OTHER, true, true);
	
	int	nMode = -1;
	if( tr.Root.Legends.Type )
		nMode = tr.Root.Legends.Type.nVal;
	else
		return nMode;
		
	if(ALM_CUSTOM == nMode && tr.Root.Legends.CustomFormat && pstrCustomFormat)
		*pstrCustomFormat = tr.Root.Legends.CustomFormat.strVal;
	
	return nMode;
	
}

bool set_page_legend_mode(GraphPage& gp, int nMode, LPCSTR lpcszCustomFormat)
{
	if(!gp)
		return false;
	
	Tree tr;
	
	tr.Root.Legends.Type.nVal = nMode;
	
	if(ALM_CUSTOM == nMode && lpcszCustomFormat)
		tr.Root.Legends.CustomFormat.strVal = lpcszCustomFormat;
	
	if(gp.UpdateThemeIDs(tr.Root) == 0 && gp.ApplyFormat(tr, true, true))
		return true;
	
	return error_report("set_page_legend_mode failed"); 
}
///end ADDED_UTILITY_FUNC_TO_GET_SET_LEGEND_MODE

//----- CPY 8/7/2007 QA70-10175 SET_LEGEND_TEXT_ALSO_MIGHT_NEED_TO_TURN_OFF_AUTO_UPDATE
bool set_page_legend_auto_update(GraphPage& gp, bool bSet)
{
	if(!gp)
		return false;
	Tree tr;
	tr.Root.Legends.AutoUpdate.nVal = bSet?1:0;
	if(gp.UpdateThemeIDs(tr.Root)==0 && gp.ApplyFormat(tr, true, true))
		return true;
	
	return error_report("set_page_legend_auto_update failed"); 
}
//-----

bool set_show_axis(GraphLayer gl, int nAxis, bool bShow1st, bool bShow2nd)//=true=false
{
	if (!gl) return error_report("Invalid Graph Layer");
	_set_show_axis_and_ticklabels(gl, nAxis, AXISOBJPOS_AXIS_FIRST, bShow1st);
	_set_show_axis_and_ticklabels(gl, nAxis, AXISOBJPOS_AXIS_SECOND, bShow2nd);
	return true;
	/*
	Tree tr;
	tr=gl.GetFormat(FPB_SHOW);
	tr.Root.Page.RemoveChild("Display");
	tr.Root.Page.Layers.All.RemoveChild("Histogram");
	tr.Root.Page.Layers.All.RemoveChild("Legend");	
	tr.Root.Page.Layers.All.RemoveChild("Display");		
		
	string strShow1st = (bShow1st)? "1":"0";
	string strShow2nd = (bShow2nd)? "1":"0";
	
	TreeNode tnTicks;
	tnTicks=tr.Root.Page.Layers.All.Axes;
	
	if (tnTicks.GetNode("All").IsValid()) 
	{
		if (tnTicks.All.GetNode("Ticks").IsValid())
		{
			if (tnTicks.All.Ticks.GetNode("All").IsValid())
			{
				if (tnTicks.All.Ticks.All.GetNode("Show").IsValid()) 
				{
					string strShowAll;
					tnTicks.All.Ticks.All.GetValue(strShowAll, "Show");					
					
					tnTicks.Y.AddNode("Ticks", 0x40000036);
					tnTicks.X.AddNode("Ticks", 0x40000036);
					
					tnTicks.X.Ticks.AddNode("BottomTicks", 0x21110037);
					tnTicks.X.Ticks.AddNode("TopTicks",    0x21120037);
					tnTicks.Y.Ticks.AddNode("LeftTicks",   0x21210037);
					tnTicks.Y.Ticks.AddNode("RightTicks",  0x21220037);
					
					tnTicks.Y.Ticks.LeftTicks.AddNode("Show",   0x00000038);
					tnTicks.Y.Ticks.RightTicks.AddNode("Show",  0x00000038);
					tnTicks.X.Ticks.BottomTicks.AddNode("Show", 0x00000038);
					tnTicks.X.Ticks.TopTicks.AddNode("Show",    0x00000038);
					
					tnTicks.X.Ticks.TopTicks.SetValue(strShowAll, "Show");
					tnTicks.X.Ticks.BottomTicks.SetValue(strShowAll, "Show");
					tnTicks.Y.Ticks.LeftTicks.SetValue(strShowAll, "Show");
					tnTicks.Y.Ticks.RightTicks.SetValue(strShowAll, "Show");			
				}	
			}
		}
	}
	
	if (nAxis == OKAXISTYPE_Y)
	{
		tnTicks=tr.Root.Page.Layers.All.Axes.Y.Ticks;	
		
		if (tnTicks.GetNode("All").IsValid()) 
		{		
			tnTicks.AddNode("LeftTicks",  0x21210037);
			tnTicks.AddNode("RightTicks", 0x21220037);
				
			tnTicks.LeftTicks.AddNode("Show",  0x00000038);
			tnTicks.RightTicks.AddNode("Show", 0x00000038);
		}
		
		tnTicks.LeftTicks.SetValue(strShow1st, "Show");
		tnTicks.RightTicks.SetValue(strShow2nd, "Show");
	}
	else if (nAxis == OKAXISTYPE_X)
	{
		tnTicks=tr.Root.Page.Layers.All.Axes.X.Ticks;
		
		if (tnTicks.GetNode("All").IsValid()) 
		{		
			tnTicks.AddNode("BottomTicks", 0x21110037);
			tnTicks.AddNode("TopTicks",    0x21120037);
			
			tnTicks.BottomTicks.AddNode("Show", 0x00000038);
			tnTicks.TopTicks.AddNode("Show",    0x00000038);

		}
		
		tnTicks.BottomTicks.SetValue(strShow1st, "Show");
		tnTicks.TopTicks.SetValue(strShow2nd, "Show");
	}
	else
	{		
		return error_report("Invalid Axis Type");
	}		

	bool bRet=gl.ApplyFormat(tr);
	
	GraphPage gp=gl.GetPage();
	gp.Refresh(true);
	return bRet;
	*/	
}
//----- end Deanna 4/17/2006 SET_SHOW_AXIS

/// Iris 5/30/06 EXPORT_PAGE_XF
int		page_get_image_type_from_type_str(LPCSTR lpcszType)//not finished...
{
	string strType(lpcszType);
	if(0 == strType.CompareNoCase("EPS"))
		return IL_FORMAT_EPS;
	if(0 == strType.CompareNoCase("JPG"))
		return IL_FORMAT_JPG;
	
	return -1;
}
///End EXPORT_PAGE_XF

///Jasmine 06/02/06 MOVE_TO_PAGE_UTILS
int page_get_layer_count(Page& pg, bool bExcludeLinked)// = true)
{
	int nCount = 0;
	if( !pg )
		return nCount;
	
	nCount = pg.Layers.Count();
	
	if(bExcludeLinked)//if exclude linked layers
	{
		double 	dLinks;
		string	strLT;
		strLT.Format("%s!page.nLinks", pg.GetName());
		LT_get_var(strLT, &dLinks);
		nCount -= (int)dLinks;
	}
	
	return nCount;
}

int page_get_layer_count(vector<string>& vsPages, bool bExcludeLinked)// = true)
{
	int nCount = 0;
	for(int ii=0; ii<vsPages.GetSize(); ii++)
	{
		Page pg(vsPages[ii]);
		if( !pg )
			continue;
		
		nCount += page_get_layer_count(pg, bExcludeLinked);
	}
	
	return nCount;
}
///Jasmine 07/11/06 MODIFICATION_ABOUT_MERGE_GRAPH
bool page_add_to_one_graph(GraphPage& gp, const vector<string> vsPages, bool bKeepOld)// = true)
{
	//gp.Create("origin");
	if( !gp )
		return false;	
	
	int nNumToAdd = page_get_layer_count(vsPages), nLayerNum;	
	///Jasmine 07/31/06 CHECK_INVALID_GRAPH_NAME
	// move layer to new page and remove old layers if no need keep old
	//clean old layers
	//gp.AppendLayers("origin");	///Jasmine 04/06/07 KEEP_SAME_RESOLUTION_AND_SHOULD_NOT_CHANGE_TEMPLATE
	for( ; 0 < gp.Layers.Count() - 1; )
	{
		GraphLayer gl = gp.Layers(0);
		if(gl)
			gl.Destroy();
	}	
	int nSize = vsPages.GetSize();
	if(nSize < 1)
		return false;
	for(int nPage=0; nPage<nSize; nPage++)
	{
		GraphPage 	gpSource(vsPages[nPage]);
		///Jasmine 01/25/07 RETURN_FALSE_TO_SHOW_PAGE_INVALID
		if(!gpSource.IsValid())
			return false;		
		gp.AddLayers(gpSource);
		if(!bKeepOld && !gpSource.GetEmbeddingInfo())///Jasmine 11/10/06 QA70-9112 GET_EMBEDDED_GRAPHS
			gpSource.Destroy();
		///End RETURN_FALSE_TO_SHOW_PAGE_INVALID
	}	
	if(1 < page_get_layer_count(gp))
		gp.Layers(0).Destroy(); // remove the first existed layer
	
	///Jasmine 12/17/08 v8.0987d QA80-12271 CP_MAKE_ADDLAYERS_KEEP_NAME
	/*int ii = 1;
	foreach(GraphLayer gl in gp.Layers)
	{
		gl.SetName("Layer" + (string)(ii));
		ii++;
	}*/
	///End CP_MAKE_ADDLAYERS_KEEP_NAME
	nLayerNum = page_get_layer_count(gp);
	return nLayerNum == nNumToAdd;
}	///End CHECK_INVALID_GRAPH_NAME

/// Iris 01/15/2009 LINK_TO_FIRST_LAYER_WHEN_ARRANGE
int get_linked_parent_layer(GraphLayer &gl)
{
	double 		dLink;
	string		strLT;
	strLT.Format("%s!layer%d.link", gl.GetPage().GetName(), gl.GetIndex()+1);
	LT_get_var(strLT, &dLink); // get 0 if not linked
	
	return (int)dLink-1; // changed to 0 offset	
}
///end LINK_TO_FIRST_LAYER_WHEN_ARRANGE

bool	is_linked_layer(GraphLayer &gl)
{
	if(!gl)
		return false;
	
	/// Iris 01/15/2009 LINK_TO_FIRST_LAYER_WHEN_ARRANGE
	/*
	double 		dLink;
	string		strLT;
	strLT.Format("%s!layer%d.link", gl.GetPage().GetName(), gl.GetIndex()+1);
	LT_get_var(strLT, &dLink);
	if(dLink > 0) // >0 means linked layer
		return true;
	*/
	if(get_linked_parent_layer(gl) >= 0)
		return true;
	////end LINK_TO_FIRST_LAYER_WHEN_ARRANGE
	
	return false;
}
static int _is_child_layer_outside_parent(GraphLayer &gl)
{
	if(!gl)
		return -1;
	
	int nParent = get_linked_parent_layer(gl);
	if(nParent < 0)
		return -1;
	
	GraphLayer glParent = gl.GetPage().Layers(nParent);
	if(!glParent)
		return -1;
	
	return !_is_layer_intersect(glParent, gl);
}
	
static bool _is_layer_intersect(GraphLayer& glParent, GraphLayer& glChild)
{
	int nCompareUnit = M_PERCENT;
	double dParentPos[TOTAL_POS];
	if( nCompareUnit != glParent.GetPosition(dParentPos) )
		glParent.UnitsConvert(nCompareUnit, dParentPos);
	
	double dChildPos[TOTAL_POS];
	if( nCompareUnit != glChild.GetPosition(dChildPos) )
		glChild.UnitsConvert(nCompareUnit, dChildPos);

	RECT rRet, rParent, rChild;
	rParent.left 	= dParentPos[LEFT_POS];
	rParent.top 	= dParentPos[TOP_POS];
	rParent.right 	= dParentPos[LEFT_POS] + dParentPos[WIDTH_POS];
	rParent.bottom 	= dParentPos[TOP_POS] + dParentPos[HEIGHT_POS];
	
	rChild.left 	= dChildPos[LEFT_POS];
	rChild.top 		= dChildPos[TOP_POS];
	rChild.right 	= dChildPos[LEFT_POS] + dChildPos[WIDTH_POS];
	rChild.bottom	= dChildPos[TOP_POS] + dChildPos[HEIGHT_POS];
			
	return IntersectRect(&rRet, &rParent, &rChild);
}

typedef AxisObject (*PFN_GET_AXIS_OBJECT)(const GraphLayer& gl, const int nAxisType);	/// Kenny 07/27/2009 IMPROVE_AND_FIX_BUG_IN_GL_SMART_SHOW_OBJECT

///Kyle 01/08/2009 v8.0994d QA80-12812 SMART_SHOW_HIDE_AXIS_TICK_LABELS_AND_TITLE
//	0: 	hide
//	1: 	show
//	-1:	not change
///Kyle 01/12/2009 v8.0995c QA80-12812 ADD_TICK_DIRECTIONS_IN_AXES_TAB_OF_LAYER_MANAGEMENT
///static void _gl_smart_show_object(GraphLayer& gl, const vector<int>& vnTicks, const vector<int>& vnLabels, const vector<int>& vnTitles, bool bRepaint = false)
void gl_smart_show_object(GraphLayer& gl, const vector<int>& vnAxes, const vector<int>& vnLabels, const vector<int>& vnTitles, const vector<int>& vnMajorTicks, const vector<int>& vnMinorTicks, bool bRepaint)
///End ADD_TICK_DIRECTIONS_IN_AXES_TAB_OF_LAYER_MANAGEMENT
{
	ASSERT(4 == vnAxes.GetSize() && 4 == vnLabels.GetSize() && 4 == vnTitles.GetSize());
	///Kyle 01/12/2009 v8.0995c QA80-12812 ADD_TICK_DIRECTIONS_IN_AXES_TAB_OF_LAYER_MANAGEMENT
	ASSERT(!vnMajorTicks || 4 == vnMajorTicks.GetSize());
	ASSERT(!vnMinorTicks || 4 == vnMinorTicks.GetSize());
	///End ADD_TICK_DIRECTIONS_IN_AXES_TAB_OF_LAYER_MANAGEMENT
	if(!gl)
		return;

	Tree tr;
	tr = gl.GetFormat(FPB_ALL, FOB_AXIS_TICKS | FOB_AXIS_LABELS | FOB_LABELS, true, true);
	TreeNode trAxes = tr.Root.Axes;
	if(!trAxes)
	{
		ASSERT(false);
		return;
	}
	TreeNode trX, trY;
	trX = trAxes.X ? trAxes.X : trAxes.AddNode("X");
	trY = trAxes.Y ? trAxes.Y : trAxes.AddNode("Y");

	TreeNode trTicks, trLabels, trTitle, trShow, trColor;
	for(int ii=0; ii<4; ii++)
	{
		string strDefaultTitle;
		switch(ii)
		{
		case AXIS_BOTTOM:
			trTicks = tree_get_node_by_tagname(trX, "BottomTicks", true);
			if(!trTicks)
				trTicks = trX.Ticks.AddNode("BottomTicks");
			trLabels = tree_get_node_by_tagname(trX, "BottomLabels", true);
			if(!trLabels)
				trLabels = trX.Labels.AddNode("BottomLabels");
			trTitle = tree_get_node_by_tagname(trX, "BottomTitle", true);
			if(!trTitle)
				trTitle = trX.Titles.AddNode("BottomTitle");
			strDefaultTitle = STR_X_DEFAULT_TITLE;		///Kyle 01/22/2009 SHOW_DEFAULT_TITLE_IF_TITLE_IS_EMPTY
			break;
		
		case AXIS_LEFT:
			trTicks = tree_get_node_by_tagname(trY, "LeftTicks", true);
			if(!trTicks)
				trTicks = trY.Ticks.AddNode("LeftTicks");
			trLabels = tree_get_node_by_tagname(trY, "LeftLabels", true);
			if(!trLabels)
				trLabels = trY.Labels.AddNode("LeftLabels");
			trTitle = tree_get_node_by_tagname(trY, "LeftTitle", true);
			if(!trTitle)
				trTitle = trY.Titles.AddNode("LeftTitle");
			strDefaultTitle = STR_Y_DEFAULT_TITLE;		///Kyle 01/22/2009 SHOW_DEFAULT_TITLE_IF_TITLE_IS_EMPTY
			break;
			
		case AXIS_TOP:
			trTicks = tree_get_node_by_tagname(trX, "TopTicks", true);
			if(!trTicks)
				trTicks = trX.Ticks.AddNode("TopTicks");
			trLabels = tree_get_node_by_tagname(trX, "TopLabels", true);
			if(!trLabels)
				trLabels = trX.Labels.AddNode("TopLabels");
			trTitle = tree_get_node_by_tagname(trX, "TopTitle", true);
			if(!trTitle)
				trTitle = trX.Titles.AddNode("TopTitle");
			strDefaultTitle = STR_X_DEFAULT_TITLE;		///Kyle 01/22/2009 SHOW_DEFAULT_TITLE_IF_TITLE_IS_EMPTY
			break;
			
		case AXIS_RIGHT:
			trTicks = tree_get_node_by_tagname(trY, "RightTicks", true);
			if(!trTicks)
				trTicks = trY.Ticks.AddNode("RightTicks");
			trLabels = tree_get_node_by_tagname(trY, "RightLabels", true);
			if(!trLabels)
				trLabels = trY.Labels.AddNode("RightLabels");
			trTitle = tree_get_node_by_tagname(trY, "RightTitle", true);
			if(!trTitle)
				trTitle = trY.Titles.AddNode("RightTitle");
			strDefaultTitle = STR_Y_DEFAULT_TITLE;		///Kyle 01/22/2009 SHOW_DEFAULT_TITLE_IF_TITLE_IS_EMPTY
			break;
		default:
			ASSERT(false);
			return;
		}
		ASSERT(trTicks);
		ASSERT(trLabels);
		ASSERT(trTitle);

		if(vnAxes[ii]>=0)
		{
			trShow = trTicks.GetNode("Show");
			if(!trShow)
				/// Kenny 07/27/2009 IMPROVE_AND_FIX_BUG_IN_GL_SMART_SHOW_OBJECT
				//trTicks.AddNode("Show");
				trShow = trTicks.AddNode("Show");
				/// End IMPROVE_AND_FIX_BUG_IN_GL_SMART_SHOW_OBJECT
			trShow.nVal = vnAxes[ii];
		}
		///Kyle 01/12/2009 v8.0995c QA80-12812 ADD_TICK_DIRECTIONS_IN_AXES_TAB_OF_LAYER_MANAGEMENT
		if(vnMajorTicks && vnMajorTicks[ii]>=0)
		{
			TreeNode trMajorTick = trTicks.GetNode("Major");
			if(!trMajorTick)
				trMajorTick = trTicks.AddNode("Major");
			trMajorTick.nVal = vnMajorTicks[ii];
		}
		if(vnMinorTicks && vnMinorTicks[ii]>=0)
		{
			TreeNode trMinorTick = trTicks.GetNode("Minor");
			if(!trMinorTick)
				trMinorTick = trTicks.AddNode("Minor");
			trMinorTick.nVal = vnMinorTicks[ii];
		}
		///End ADD_TICK_DIRECTIONS_IN_AXES_TAB_OF_LAYER_MANAGEMENT

		if(vnLabels[ii]>=0)
		{
			trShow = trLabels.GetNode("Show");
			if(!trShow)
				trShow = trLabels.AddNode("Show");
			trShow.nVal = vnLabels[ii];
			trLabels.Color.nVal = 0;
		}

		if(vnTitles[ii]>=0)
		{
			trShow = trTitle.GetNode("Show");
			if(!trShow)
				trShow = trTitle.AddNode("Show");
			trShow.nVal = vnTitles[ii];
			///Kyle 01/22/2009 SHOW_DEFAULT_TITLE_IF_TITLE_IS_EMPTY
			if(vnTitles[ii] > 0)
			{
				/// Kenny 07/27/2009 IMPROVE_AND_FIX_BUG_IN_GL_SMART_SHOW_OBJECT
#ifdef __SUPPORT_ACCESS_AXIS_TITLE_OBJECT_IN_OC
				string strPath = "Originlab\\graph_utils.c";
				PFN_GET_AXIS_OBJECT pfn_get_axis_object = Project.FindFunction("get_axis_object", strPath, true);
				if (pfn_get_axis_object)
				{
					AxisObject ao = pfn_get_axis_object(gl, ii);
					GraphObject goTitle = ao.GetTitleObject(strDefaultTitle);
					ASSERT( goTitle.IsValid() );
				}
#endif // __SUPPORT_ACCESS_AXIS_TITLE_OBJECT_IN_OC
				/// End IMPROVE_AND_FIX_BUG_IN_GL_SMART_SHOW_OBJECT
				trTitle.Color.nVal = 0;
				TreeNode trTitleText = trTitle.GetNode("Text");
				if(!trTitleText)
					trTitleText = trTitle.AddNode("Text");
				string strTitle = trTitleText.strVal;
				strTitle.TrimLeft();
				strTitle.TrimRight();
				if(strTitle.IsEmpty())
				{
					trTitleText.strVal = strDefaultTitle;
					trTitle.LinkToVars.nVal = 1;
				}
			}
			///End SHOW_DEFAULT_TITLE_IF_TITLE_IS_EMPTY
		}
	}
	gl.UpdateThemeIDs(tr.Root);
	gl.ApplyFormat(tr, bRepaint, true, true);
}

///Jasmine 11/12/09 QA80-14619 USER_WANT_ARRANGE_STACK_HORIZONTAL
static int _switch_axes_type_with_xy_exchange(int nType, bool bXYexchange)
{
	if(!bXYexchange)
		return nType;
	
	switch(nType)
	{
	case AXIS_BOTTOM:
		return AXIS_LEFT;
	case AXIS_LEFT:
		return AXIS_BOTTOM;
	case AXIS_TOP:
		return AXIS_RIGHT;
	case AXIS_RIGHT:
		return AXIS_TOP;
	}
	
	return -1;
}
///End USER_WANT_ARRANGE_STACK_HORIZONTAL

static void _gp_smart_show_object(GraphPage& gp, int nNumRow, int nNumCol, const vector<int>& vnSel, int nXGap, int nYGap, DWORD dwOptions = 0, bool bRefresh = false)
{
	if(!gp || nNumRow <= 0 || nNumCol <= 0)
		return;
	
	// remove duplicated, linked layers
	vector<int> vnSelected;
	if(NULL != vnSel)
	{
		vnSelected = vnSel;
		vnSelected.Sort();
	}
	if(vnSelected.GetSize() <= 0)
		vnSelected.Data(0, gp.Layers.Count()-1);		// select all

	GraphLayer gl;
	double xx[TOTAL_POS];
	for(int ii = vnSelected.GetSize()-1; ii >= 0; ii--)
	{
		if(ii>0 && vnSelected[ii] == vnSelected[ii-1])
			vnSelected.RemoveAt(ii);
		else
		{
			gl = gp.Layers(vnSelected[ii]);
			if(!gl || (is_linked_layer(gl) && M_LINK == gl.GetPosition(xx)))
				vnSelected.RemoveAt(ii);
		}
	}

	int nNumLayerLastRow = nNumCol,
		nLaySelected = vnSelected.GetSize();
	if(vnSelected.GetSize() < nNumRow * nNumCol)		// not full, correct nNumRow & nNumLayerLastRow
	{
		nNumRow = nLaySelected / nNumCol;
		nNumLayerLastRow = nLaySelected -  nNumRow * nNumCol;
		if(nNumLayerLastRow == 0)
			nNumLayerLastRow = nNumCol;
		else
			nNumRow++;
	}
	bool 	bXBigGap		= nXGap >= SA_MIN_GAP,
			bYBigGap		= nYGap >= SA_MIN_GAP,
			bOuterTitle		= !(SA_HIDE_OUTER_TITLE & dwOptions),
			bInnerAxis		= SA_SHOW_INNER_AXIS & dwOptions,
			bInnerLabel		= SA_SHOW_INNER_TICK_LABEL & dwOptions;
	int nGrid = nNumCol * nNumRow;
	
	bool 	bTop, bBottom, bLeft, bRight;
	vector<int> vnAxes(4), vnLabels(4), vnTitles(4);
	vector<int> vnTicks(4);			///Kyle 01/23/2009 HIDE_SHOW_TICK_MARKS_SAME_AS_TICK_LABELS

	for(int nPosIndex = 0; nPosIndex < nLaySelected; nPosIndex++)
	{
		gl = gp.Layers(vnSelected[nPosIndex]);
		ASSERT(gl);
		
		///Jasmine 11/12/09 QA80-14619 USER_WANT_ARRANGE_STACK_HORIZONTAL
		string strLTVar = "_exchangexy", strLT;
		strLT.Format("%s = %s!layer%d.exchangexy", strLTVar, gp.GetName(), gl.GetIndex()+1);
		LT_execute(strLT);
		double exchangexy = 0;
		LT_get_var(strLTVar, &exchangexy);
		///End USER_WANT_ARRANGE_STACK_HORIZONTAL
		
		if(nPosIndex < nGrid)
		{
			int nColIndex = nPosIndex % nNumCol;	// [0, nNumCol)
			int nRowIndex = nPosIndex / nNumCol;	// [0, nNumRow)
			bTop = nRowIndex == 0;
			bBottom = (nRowIndex == nNumRow - 1) || (nRowIndex == nNumRow - 2 && nColIndex >= nNumLayerLastRow);
			bLeft = nColIndex == 0;
			bRight = (nColIndex == nNumCol - 1) || (nPosIndex == vnSelected.GetSize()-1);
			
			///Jasmine 11/12/09 QA80-14619 USER_WANT_ARRANGE_STACK_HORIZONTAL
			// left
			int nSwichType = _switch_axes_type_with_xy_exchange(AXIS_LEFT, exchangexy);
			vnAxes[ nSwichType] = bLeft || nXGap > 0 || bInnerAxis;
			vnTitles[nSwichType] = bLeft && bOuterTitle;
			vnLabels[nSwichType] = (bLeft || bXBigGap || bInnerLabel) && vnAxes[nSwichType];
			vnTicks[nSwichType] = vnLabels[nSwichType] >= 0 ? (vnLabels[nSwichType] > 0? TICK_OUT : TICK_NONE) : -1;		///Kyle 01/23/2009 HIDE_SHOW_TICK_MARKS_SAME_AS_TICK_LABELS

			// bottom
			nSwichType = _switch_axes_type_with_xy_exchange(AXIS_BOTTOM, exchangexy);
			vnAxes[nSwichType] = bBottom || nYGap > 0 || bInnerAxis;
			vnTitles[nSwichType] = bBottom && bOuterTitle;
			vnLabels[nSwichType] = (bBottom || bYBigGap || bInnerLabel) && vnAxes[nSwichType];
			vnTicks[nSwichType] = vnLabels[nSwichType] >= 0 ? (vnLabels[nSwichType] > 0? TICK_OUT : TICK_NONE) : -1;		///Kyle 01/23/2009 HIDE_SHOW_TICK_MARKS_SAME_AS_TICK_LABELS
	
			// top
			nSwichType = _switch_axes_type_with_xy_exchange(AXIS_TOP, exchangexy);
			vnAxes[nSwichType] = bTop || nYGap > 0;
			vnTitles[nSwichType] = false;
			///Jasmine 09/14/09 NO_TOP_RIGHT_LABEL_OR_TICK
			//if not change label state(-1), it will lead different results: top axis has/has no ticks.
			//vnLabels[AXIS_TOP] = (!vnLabels[AXIS_BOTTOM] && bTop)? -1:0;
			vnLabels[nSwichType] = 0;
			///End NO_TOP_RIGHT_LABEL_OR_TICK
			vnTicks[nSwichType] = vnLabels[nSwichType] >= 0 ? (vnLabels[nSwichType] > 0? TICK_IN : TICK_NONE) : -1;		///Kyle 01/23/2009 HIDE_SHOW_TICK_MARKS_SAME_AS_TICK_LABELS
	
			// right
			nSwichType = _switch_axes_type_with_xy_exchange(AXIS_RIGHT, exchangexy);
			vnAxes[nSwichType] = bRight || nXGap > 0;
			vnTitles[nSwichType] = false;
			///Jasmine 09/14/09 NO_TOP_RIGHT_LABEL_OR_TICK
			//vnLabels[AXIS_RIGHT] = (!vnLabels[AXIS_LEFT] && bRight)?-1:0;
			vnLabels[nSwichType] = 0;
			///End NO_TOP_RIGHT_LABEL_OR_TICK
			vnTicks[nSwichType] = vnLabels[nSwichType] >= 0 ? (vnLabels[nSwichType] > 0? TICK_IN : TICK_NONE) : -1;		///Kyle 01/23/2009 HIDE_SHOW_TICK_MARKS_SAME_AS_TICK_LABELS
			///End USER_WANT_ARRANGE_STACK_HORIZONTAL
		}
		else
		{
			vector<int> vn = {0, 0, 0, 0};
			vnAxes = vnLabels = vnTitles = vn;
		}
		///Kyle 01/23/2009 HIDE_SHOW_TICK_MARKS_SAME_AS_TICK_LABELS
		//gl_smart_show_object(gl, vnAxes, vnLabels, vnTitles);
		gl_smart_show_object(gl, vnAxes, vnLabels, vnTitles, vnTicks, vnTicks);
		///End HIDE_SHOW_TICK_MARKS_SAME_AS_TICK_LABELS
	}
	if(bRefresh)
		gp.Refresh();
}

///Jasmine 02/11/09 SHARE_ERR_MSG_WITH_MERGE_GRAPH
bool arrange_layer_check_spacing(int nRow, int nCol, stLayersGridFormat stFormat, int& nErr)
{
	if(1 > nRow || 1 > nCol)
		nErr = XFERR_TOO_FEW_COLS_OR_ROWS;
	if(nErr == CER_NO_ERROR && (0 > stFormat.nXGap || 0 > stFormat.nYGap || 0 > stFormat.nLeftMg || 0 > stFormat.nRightMg || 0 > stFormat.nTopMg || 0 > stFormat.nBottomMg))
		nErr = CER_INPUT_ARGUMENT_LESS_THAN_SPECIFIED_VALUE;
	if(nErr == CER_NO_ERROR)
	{
		int nX = 100 - stFormat.nLeftMg - stFormat.nRightMg - (nCol-1)*stFormat.nXGap;
		nX /= nCol;
		int nY = 100 - stFormat.nTopMg - stFormat.nBottomMg - (nRow-1)*stFormat.nYGap;
		nY /= nRow;
		if(nX < 5 || nY < 5) 
			nErr = CER_LAYER_TOO_SMALL;
	}
	return nErr == CER_NO_ERROR;
}
///End SHARE_ERR_MSG_WITH_MERGE_GRAPH

///Jasmine 05/17/07 MOVE_OUT_PORTRAIT_OPTION
///Jasmine 05/11/07 ARRANGE_FROM_BOTTOM_TO_TOP_FOR_ONE_COL
/// Iris 01/22/2007 v8.0544 MERGE_GRAPH_NEED_SETUP_PAGE_TO_PORTRAIT
///// Iris 01/16/2007 v8.0542 REMOVE_AXIS_SCROLLER_BEFORE_MERGE
///////Jasmine 10/09/06 SET_STFORMAT_DEFAULT
//////bool page_arrange_layers(GraphPage& gp, int nRow, int nCol, stLayersGridFormat stFormat)
////bool page_arrange_layers(GraphPage& gp, int nRow, int nCol, stLayersGridFormat* pstFormat)//= NULL
//bool page_arrange_layers(GraphPage& gp, int nRow, int nCol, stLayersGridFormat* pstFormat, bool bDelAxisScroll)//= NULL, =true
//bool page_arrange_layers(GraphPage& gp, int nRow, int nCol, stLayersGridFormat* pstFormat, bool* pbPortrait, bool bDelAxisScroll)//= NULL, =NULL, =false
//bool page_arrange_layers(GraphPage& gp, int nRow, int nCol, stLayersGridFormat* pstFormat, bool* pbPortrait, bool bBottomTop, bool bDelAxisScroll, const vector<int>& vnSel)//= NULL, =NULL, =false, true, NULL	///Jasmine 05/16/07 QA80-9182 ARRANGE_SELECTION_ONLY	
//bool page_arrange_layers(GraphPage& gp, int nRow, int nCol, stLayersGridFormat* pstFormat, bool bBottomTop, bool bDelAxisScroll, const vector<int>& vnSel)//= NULL, =NULL, =false, true, NULL	///Jasmine 05/16/07 QA80-9182 ARRANGE_SELECTION_ONLY	
/// Iris 01/22/2009 ADDED_TWO_OPTIONS_LINK_TO_AND_SMART_OBJECTS_WHEN_ARRANGE_IN_MERGE_GRAPH
//bool page_arrange_layers(GraphPage& gp, int nRow, int nCol, stLayersGridFormat* pstFormat, bool bBottomTop, bool bDelAxisScroll, const vector<int>& vnSel, bool bUndo)//= NULL, =NULL, =false, true, NULL, false	///Jasmine 10/31/07 ADD_UNDO_OPTION	
bool page_arrange_layers(GraphPage& gp, int nRow, int nCol, 
						stLayersGridFormat* pstFormat,					//NULL
						bool bReverse, bool bDelAxisScroll, 			//false, true
						const vector<int>& vnSel,						//NULL
						bool bLinkToFirstLayer, bool bArrangeChild, 	//true, false	//Jasmine 01/22/09 REARRANGE_OUTER_CHILD_LAYER
						bool bSmartShowObject, int nSmartShowObjectType,//false, SA_SHOW_INNER_AXIS
						bool bUndo)//false
///end ADDED_TWO_OPTIONS_LINK_TO_AND_SMART_OBJECTS_WHEN_ARRANGE_IN_MERGE_GRAPH
{		
	if(!gp.IsValid() || nRow < 1 || nCol < 1)//nRow and nCol can't be less than 1
		return false;
	stLayersGridFormat stFormat;
	if(pstFormat)
		stFormat = *pstFormat;
	else
	{
		stFormat.nXGap = 5;		
		stFormat.nYGap = 5;			
		stFormat.nLeftMg = 15;			
		stFormat.nRightMg = 15;			
		stFormat.nTopMg = 15;			
		stFormat.nBottomMg = 15;
	}
	///End SET_STFORMAT_DEFAULT
	
	/// Iris 01/16/2007 v8.0542 REMOVE_AXIS_SCROLLER_BEFORE_MERGE
	if(bDelAxisScroll)
	{
		foreach(GraphLayer gl in gp.Layers)
		{
			gl.LT_execute("label -r *scroll*");
		}
	}
	///end REMOVE_AXIS_SCROLLER_BEFORE_MERGE
	///Jasmine 05/16/07 QA80-9182 ARRANGE_SELECTION_ONLY
	bool bCheckIndex;
	if(vnSel && vnSel.GetSize())
		bCheckIndex = true;
	///End ARRANGE_SELECTION_ONLY
	/// Iris 01/22/2007 v8.0544 MERGE_GRAPH_NEED_SETUP_PAGE_TO_PORTRAIT
	///-----Jasmine 02/09/07 it seems ApplyFormat will make the legend move left, so use LT instead
	/*
	Tree 	tr;
	tr = gp.GetFormat(FPB_DIMENSION);
	double 	dWidth = tr.Root.Page.Dimension.Width.dVal;
	double 	dHeight = tr.Root.Page.Dimension.Height.dVal;
	if(bPortrait)
	{
		tr.Root.Page.Dimension.Width.dVal = min(dWidth, dHeight);
		tr.Root.Page.Dimension.Height.dVal = max(dWidth, dHeight);
	}
	else
	{		
		tr.Root.Page.Dimension.Width.dVal = max(dWidth, dHeight);
		tr.Root.Page.Dimension.Height.dVal = min(dWidth, dHeight);		
	}
	gp.ApplyFormat(tr);
	*/
	///Jasmine 02/24/07 BY_DEFAULT_NOT_RESIZE
	string 	strLT;
	///Jasmine 05/17/07 MOVE_OUT_PORTRAIT_OPTION
	/*
	if(pbPortrait)
	{
		bool bPortrait = *pbPortrait;
		strLT.Format("page -o %s",bPortrait?"p":"l");
		gp.LT_execute(strLT);	
	}
	*/
	///End MOVE_OUT_PORTRAIT_OPTION
	///End BY_DEFAULT_NOT_RESIZE
	///-----
	///end MERGE_GRAPH_NEED_SETUP_PAGE_TO_PORTRAIT	
	
	// get layer total number
	int 	nLayerNum = gp.Layers.Count();
		
	string 	strPageName = gp.GetName();
	int nX = 100 - stFormat.nLeftMg - stFormat.nRightMg - (nCol-1)*stFormat.nXGap;
	nX /= nCol;
	int nY = 100 - stFormat.nTopMg - stFormat.nBottomMg - (nRow-1)*stFormat.nYGap;
	nY /= nRow;
	if(nX < 5 || nY < 5) 
		return false; //Error! Resulting layers are too small.
	
	///Jasmine 11/12/09 QA80-14619 USER_WANT_ARRANGE_STACK_HORIZONTAL
	bool bVerticalReverse = (bReverse && 1 == nCol);	///Jasmine 05/11/07 ARRANGE_FROM_BOTTOM_TO_TOP_FOR_ONE_COL
	bool bHorizontalReverse = (bReverse && 1 == nRow);
	///End USER_WANT_ARRANGE_STACK_HORIZONTAL
	int 	cc=1, rr=1, nGrid = 1;	
	for(int ii=0; ii<nLayerNum; ii++)
	{
		///Jasmine 05/16/07 QA80-9182 ARRANGE_SELECTION_ONLY
		vector<uint> vecIndex;
		if(bCheckIndex)
		{
			if(1 > vnSel.Find(vecIndex, ii))
				continue;
		}
		///End ARRANGE_SELECTION_ONLY
		
		//set the current layer to active
		/// Iris 01/12/2009 ACTIVATE_LAYER_BY_OC, not use LT command below any more, no need active layer here
		//strLT.Format("%s!page.active=%d", strPageName, ii);
		//gp.LT_execute(strLT);			
		///end ACTIVATE_LAYER_BY_OC

		//------ Iris 02/15/2007 moved this part codes as global function
		/*
		double dLink;
		strLT.Format("%s!layer%d.link", strPageName, ii);
		LT_get_var(strLT, &dLink);
		if(dLink > 0) // >0 means linked layer
		*/
		GraphLayer 	gl = gp.Layers(ii);///Jasmine 02/16/07 0-offset
		///Jasmine 03/21/07 ONLY_SKIP_LINK_LAYER_WITH_M_LINK_UNIT
		//if(is_linked_layer(gl))
		////------
			//continue;
		///end FIX_LINK_LAYER_PROBLEM
		
		//the type of units of page to % of page
		///Jasmine 12/06/06 KEEP_EACH_LAYER_UNIT_AFTER_MERGE
		///--------------Jasmine 03/07/07 it seems LT will get a wrong layer's unit
		/*double dUnit;
		LT_get_var("layer.unit", &dUnit);
		///End KEEP_EACH_LAYER_UNIT_AFTER_MERGE
		strLT = "layer -u 1";
		gp.LT_execute(strLT);*/
		//---- CPY 3/7/2007 SYSTEM_FILE_CANNOT_COMPILE_IN_PAGE_UTILS
		// should not use functions from graph_utils.c in system folder
		//int nUnit = layer_get_unit(gl);
		//layer_set_unit(gl, M_PERCENT);
		///Jasmine 03/08/07 USE_NEW_FUNC_UNITSCONVERT	
		double xx[TOTAL_POS];
		int nUnit = gl.GetPosition(xx);
		if(is_linked_layer(gl) && M_LINK == nUnit)
		{
			bool bSkip = true;
			///Jasmine 01/22/09 REARRANGE_OUTER_CHILD_LAYER
			if(bArrangeChild)
			{
				int nRet = _is_child_layer_outside_parent(gl);
				if(nRet > 0)
					bSkip = false;
			}
			
			if(bSkip)
				continue;
			///End REARRANGE_OUTER_CHILD_LAYER
		}
		///End ONLY_SKIP_LINK_LAYER_WITH_M_LINK_UNIT
		gl.UnitsConvert(M_PERCENT, xx);
		DWORD dw = bUndo? OCD_UNDO : OCD_ASK;//OCD_ASK is default setting in SetPosition
		gl.SetPosition(xx, M_PERCENT, dw);	///Jasmine 03/15/07 ADD_UNDO_BUTTON
		//----
		///--------------end
		//set layer's location
		//int nRight = stFormat.nTopMg + (rr-1) *(nY + stFormat.nYGap);
		///Jasmine 05/11/07 ARRANGE_FROM_BOTTOM_TO_TOP_FOR_ONE_COL
		//int nTop = stFormat.nTopMg + (rr-1) *(nY + stFormat.nYGap);
		int nTop = stFormat.nTopMg + (bVerticalReverse?(nRow-rr):(rr-1)) *(nY + stFormat.nYGap);	
		///End ARRANGE_FROM_BOTTOM_TO_TOP_FOR_ONE_COL
		
		///Jasmine 11/12/09 QA80-14619 USER_WANT_ARRANGE_STACK_HORIZONTAL
		//int nLeft = stFormat.nLeftMg + (cc-1))*(nX + stFormat.nXGap);
		int nLeft = stFormat.nLeftMg + (bHorizontalReverse?(nCol-cc):(cc-1))*(nX + stFormat.nXGap);
		///End USER_WANT_ARRANGE_STACK_HORIZONTAL
		
		//strLT.Format("layer x y %d %d", nLeft, nRight);
		//gp.LT_execute(strLT);
		
		cc = mod((nGrid++)+1, nCol);//mod((ii++)+1, nCol) ///Jasmine 08/25/06,	no ii but nGrid, should ignore linked layers
		if(cc==0)
			cc = nCol;
		if(cc==1)
			rr = rr + 1;
		rr = rr>nRow? 1 : rr;		
		//---- CPY 3/7/2007 SYSTEM_FILE_CANNOT_COMPILE_IN_PAGE_UTILS
		/*
		//set layer's wdith and height
		strLT.Format("layer.width=%d", nX);
		gp.LT_execute(strLT);		
		strLT.Format("layer.height=%d", nY);
		gp.LT_execute(strLT);
		///Jasmine 12/06/06 KEEP_EACH_LAYER_UNIT_AFTER_MERGE
		///--------------Jasmine 03/07/07 it seems LT will get a wrong layer's unit
		//strLT = "layer -u "+ dUnit;
		//gp.LT_execute(strLT);
		layer_set_unit(gl, nUnit);
		///--------------end
		///End KEEP_EACH_LAYER_UNIT_AFTER_MERGE
		*/
		//gl.GetPosition(xx);
		xx[WIDTH_POS] = nX;
		xx[HEIGHT_POS] = nY;
		xx[LEFT_POS] = nLeft;
		xx[TOP_POS] = nTop;
		gl.UnitsConvert(nUnit, xx);
		gl.SetPosition(xx, nUnit, dw);	///Jasmine 03/15/07 ADD_UNDO_BUTTON
		//----
		///End USE_NEW_FUNC_UNITSCONVERT
	}
		
	/// Iris 01/22/2009 ADDED_TWO_OPTIONS_LINK_TO_AND_SMART_OBJECTS_WHEN_ARRANGE_IN_MERGE_GRAPH
	if(bSmartShowObject)
	{
		_gp_smart_show_object(gp, nRow, nCol, vnSel, stFormat.nXGap, stFormat.nYGap, nSmartShowObjectType);
	}

	foreach(GraphLayer gl in gp.Layers)
	{
		vector<uint> vecIndex;
		if(bCheckIndex)
		{
			ii = gl.GetIndex();
			if(1 > vnSel.Find(vecIndex, ii))
				continue;
		}
		
		if(bLinkToFirstLayer)
		{
			int nParentLayer = get_linked_parent_layer(gl);
			int nLinkTo = bCheckIndex ? vnSel[0] : 0;
			
			vector<uint> vn;
			if( nParentLayer < 0 // no link to 
				//---Jasmine 01/15/09 MAX_ASK_NOT_CHANGE_OLD_LINK_RELATIONSHIP_EVEN_UNIT_NOT_PECENT_OF_LINK_LAYER
				//|| nParentLayer >= 0 && M_LINK != gl.GetPosition() // linked but uint is not M_LINK
				//|| nParentLayer >= 0 && bArrangeSelection && vnSel.Find(MATREPL_TEST_EQUAL, nParentLayer, vn) <= 0 // linked but link to layer not in selected layer list
				//---
				)
			{
				if( nLinkTo != gl.GetIndex() ) 
				{
					int nLinkUint = M_LINK;
					
					string strPath = "Originlab\\graph_utils.c";
					FUNC_LAYER_SET_LINK pfn = Project.FindFunction("layer_set_link", strPath, true);
					if( !pfn )
					{
						ASSERT(0);
					}
					else
					{
						//pfn(gl, nLinkTo, 0, 0, &nLinkUint, "", "", "", "");
						pfn(gl, nLinkTo, 0, 0, &nLinkUint);
					}
				}
			}
		}
	}
	///end ADDED_TWO_OPTIONS_LINK_TO_AND_SMART_OBJECTS_WHEN_ARRANGE_IN_MERGE_GRAPH
	
	return true;
}
///End MOVE_TO_PAGE_UTILS
///End MODIFICATION_ABOUT_MERGE_GRAPH
///Sophy 3/2/2009 ADD_SIMPLER_GRAPHLAYER_ARRANGE_METHOD_FOR_CUSTOMER_USE
bool graph_arrange_layers(GraphPage& gp, int nRows, int nCols)
{
	return page_arrange_layers(gp, nRows, nCols);
}
///end ADD_SIMPLER_GRAPHLAYER_ARRANGE_METHOD_FOR_CUSTOMER_USE

///Jasmine 09/15/09 QA81-14321 SAVE_SPACING_SETTING_FOR_ARRANGEMENT
#define STR_SPACING_STORAGE		"Spacing"

bool load_arrange_spacing_settings(	const GraphPage& gp, int& nCol, int& nRow, 
									int& nXGap, int& nYGap, 
									int& nLeftMargin, int& nRightMargin, int& nTopMargin, int& nBottomMargin)
{	
	if(!gp)
		return false;
	
	Tree trSpacing;
	if( !gp.GetBinaryStorage(STR_SPACING_STORAGE, trSpacing) )
		return false;
		
	nCol = trSpacing.Col.nVal;
	nRow = trSpacing.Row.nVal;
	nXGap= trSpacing.XGap.nVal;
	nYGap= trSpacing.YGap.nVal;
	nLeftMargin		= trSpacing.LeftMargin.nVal;
	nRightMargin	= trSpacing.RightMargin.nVal;
	nTopMargin		= trSpacing.TopMargin.nVal;
	nBottomMargin	= trSpacing.BottomMargin.nVal;
	
	return true;
}
	
bool save_arrange_spacing_settings(	GraphPage& gp, int nCol, int nRow, 
									int nXGap, int nYGap, 
									int nLeftMargin, int nRightMargin, int nTopMargin, int nBottomMargin)
{
	if(!gp)
		return false;
	
	Tree trSpacing;
	trSpacing.Col.nVal = nCol;
	trSpacing.Row.nVal = nRow;
	trSpacing.XGap.nVal= nXGap;
	trSpacing.YGap.nVal= nYGap;
	trSpacing.LeftMargin.nVal 	= nLeftMargin;
	trSpacing.RightMargin.nVal 	= nRightMargin;
	trSpacing.TopMargin.nVal 	= nTopMargin;
	trSpacing.BottomMargin.nVal	= nBottomMargin;
		
	return gp.PutBinaryStorage(STR_SPACING_STORAGE, trSpacing);
}
///End SAVE_SPACING_SETTING_FOR_ARRANGEMENT

//----- CPY 6/21/06 MUST_CHECK_WKS_BEFORE_TRYING_TO_SCROLL
// return new 1st visible col index
// nCol is 0 offset
bool	wks_scroll_into_view(Worksheet& wks, int nCol, int nOffset, bool bCol, bool bCheckInView)
{
	if(NULL == wks || !wks.IsValid())
		return false;
	
	// first get current col scroll pos
	if(bCol)
		wks.LT_execute("v1=x1;v2=x2");
	else
		wks.LT_execute("v1=y1;v2=y2");
		
	double v1,v2;
	LT_get_var("v1", &v1);
	LT_get_var("v2", &v2);v2-=1;// x2 is the col index of right of scroll range
	if(bCheckInView && nCol >= v1 && nCol <= v2)
		return true;// no need to scroll if already in view
	if(nOffset > v2-v1-1)
		nOffset = v2-v1-1;
	if(nOffset < 0) nOffset = 0;
	v1 = nCol - nOffset;
	if(v1 < 0) v1 = 0;
	LT_set_var("v1", v1);
	if(bCol)
		wks.LT_execute("x1=v1");
	else
		wks.LT_execute("y1=v1");
		
	return true;
}
//-----

///Jasmine 11/24/08 v978d QA80-12652 DATASHEET_SCROLL_RANGE_INTO_VIEW
//r1 and r2 are row index. c1 and c2 are column index. 0-offset

///Jasmine 03/19/09 QA80-13295-P1 ADD_VARIABLE_FOR_NEW_POS_AFTER_SCOLL
//void ds_scroll_into_view(Datasheet& ds, int r1, int r2, int c1, int c2, bool bCheckInView)//all int = -1, true
/// Iris 3/20/2009 QA80-13295-P1B CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES
/*
void ds_scroll_into_view(Datasheet& ds, int r1/*=-1/, int r2/*=-1/, int c1/*=-1/, int c2/*=-1/, int nNewPos/*=SCROLL_TO_MIDDLE/, bool bCheckInView/*=true/)
{
	if(-1 < c1)
		_scroll_into_view(ds, true, c1, c2, nNewPos, bCheckInView);
	
	if(-1 < r1)
		_scroll_into_view(ds, false, r1, r2, nNewPos, bCheckInView);
	
}
*/
int ds_scroll_into_view(Datasheet& ds, int r1/*=-1*/, int r2/*=-1*/, int c1/*=-1*/, int c2/*=-1*/, int nNewPos/*=SCROLL_TO_MIDDLE*/, bool bCheckInView/*=true*/)
{
	int nRet1, nRet2;
	
	if(-1 < c1)
		nRet1 = _scroll_into_view(ds, true, c1, c2, nNewPos, bCheckInView);
	
	if(-1 < r1)
		nRet2 = _scroll_into_view(ds, false, r1, r2, nNewPos, bCheckInView);
	
	if( SCROLL_CHECK_IN_VIEW == nRet1 && SCROLL_CHECK_IN_VIEW == nRet2)
		return SCROLL_CHECK_IN_VIEW;
	
	if( SCROLL_FAILED == nRet1 || SCROLL_FAILED == nRet2 )
		return SCROLL_FAILED;

	return SCROLL_DONE;
}
///end CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES

///Jasmine 03/19/09 QA80-13295-P1 ADD_VARIABLE_FOR_NEW_POS_AFTER_SCOLL
//static void _scroll_into_view(Datasheet& ds, bool bCol, int n1, int n2, bool bCheckInView = true)
/// Iris 3/20/2009 QA80-13295-P1B CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES
//static void _scroll_into_view(Datasheet& ds, bool bCol, int n1, int n2, int nNewPos, bool bCheckInView = true)
static int _scroll_into_view(Datasheet& ds, bool bCol, int n1, int n2, int nNewPos, bool bCheckInView = true)
//end CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES
{	
	if(bCol)
		ds.LT_execute("v1=x1;v2=x2");
	else
		ds.LT_execute("v1=y1;v2=y2");
	//out_str("before");
	//ds.LT_execute("x1=;x2=;y1=;y2=");
	
	double v1, v2;
	LT_get_var("v1", &v1);
	LT_get_var("v2", &v2);
	v2 -= 1;//x2 & y2 are 1-offset while x1 & y1 are 0-offset
	ASSERT(v2 > v1);
		
	if(n2 < 0)
		n2 = bCol? ds.GetNumCols()-1 : ds.GetNumRows()-1;
	if(n1 > n2)
	{
		int nTemp = n1;
		n1 = n2;
		n2 = nTemp;
	}
	
	/// Iris 3/20/2009 QA80-13295-P1B CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES
	if(bCheckInView && n1 >= v1 && n2 <= v2)
	{
		return SCROLL_CHECK_IN_VIEW;		
	}
	///end CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES
	
	int nNew;
	switch(nNewPos)
	{
	case SCROLL_TO_TOP:
		nNew = n1;
		break;
		
	case SCROLL_TO_MIDDLE:
		/// Iris 3/20/2009 QA80-13295-P1B CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES
		//if(bCheckInView && n1 >= v1 && n2 <= v2)
			//return;
		///end CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES
		
		if(n2 - n1 < v2 - v1)
			nNew = (n1 + n2 + v1 - v2)/2;
		else//if the [n1:n2] range is longer than [v1:v2] range, scroll n1 top/left
			nNew = n1;
			
		break;
		
	case SCROLL_TO_BOTTOM:
		nNew = n2 + v1 - v2;
		break;			
		
	default:
		ASSERT(0);
		/// Iris 3/20/2009 QA80-13295-P1B CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES
		//return;
		return SCROLL_FAILED;
		///end CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES
	}	
	v1 = nNew < 0? 0 : nNew;
	LT_set_var("v1", v1);			
	
	
	/// Iris 3/20/2009 QA80-13295-P1B CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES
	/*
	if(bCol)
		ds.LT_execute("x1=v1");
	else
		ds.LT_execute("y1=v1");
	*/
	bool bExeRet = false; 
	if(bCol)
		bExeRet = ds.LT_execute("x1=v1");
	else
		bExeRet = ds.LT_execute("y1=v1");
	
	if( !bExeRet )
		return SCROLL_FAILED;
	
	return SCROLL_DONE;
	///end CHANGE_SCROLL_VIEW_FUNC_RETURN_VALUES
	
	//out_str("after");
	//ds.LT_execute("x1=;x2=;y1=;y2=");
	
}
///End ADD_VARIABLE_FOR_NEW_POS_AFTER_SCOLL
///End DATASHEET_SCROLL_RANGE_INTO_VIEW


///Cheney 06/27/06 CHK_SET_VAL
#define CHK_SET_VAL(_nn, _val) if (_nn) *(_nn) = _val;
///end CHK_SET_II_VAL

/// Cheney 06/22/06 ADD_FUNCTIONS_ABOUT_CHECK_COLS_IN_RANGE_WITH_SAME_DATATYPE
bool check_cols_in_range_with_same_datatype(DataRange& dr, int* pType)
{
	Worksheet wksSource;
	int r1, c1, r2, c2;

	get_range_span(dr, 0, r1, c1, r2, c2);
	if(!get_source_worksheet(dr, wksSource))
		return false;
	
	int nFormat1st = wksSource.Columns(c1).GetInternalDataType();
	int nRange = dr.GetNumRanges();
	
	for(int rr = 0; rr < nRange; rr++)
	{
		get_range_span(dr, rr, r1, c1, r2, c2);
		
		for(int cc = c1; cc <= c2; cc++)
		{
			int nFormatTemp = wksSource.Columns(cc).GetInternalDataType();
			if(nFormat1st != nFormatTemp)
			{
				if(nFormatTemp == FSI_MIXED || nFormatTemp == FSI_REAL || nFormatTemp == FSI_DOUBLE || nFormatTemp == FSI_COMPLEX)
					CHK_SET_VAL(pType, FSI_DOUBLE)
				else
					CHK_SET_VAL(pType, FSI_LONG);
				
				return false;
			}
		}		
	}
	
	CHK_SET_VAL(pType, nFormat1st);
	return true;
}
/// end ADD_FUNCTIONS_ABOUT_CHECK_COLS_IN_RANGE_WITH_SAME_DATATYPE

///Cheney 06/23/06 SET_COLS_IN_RANGE_TO_SAME_DATATYPE
int set_cols_in_range_to_same_datatype(DataRange& dr, int* pType)
{
	Worksheet wksSource;
	int r1, c1, r2, c2;

	get_range_span(dr, 0, r1, c1, r2, c2);
	if(!get_source_worksheet(dr, wksSource))
		return -1;
	
	if(pType)
		if(*pType < FSI_DOUBLE || *pType > FSI_COMPLEX)
			return -1;
	
	int nRange = dr.GetNumRanges();
	
	//scan cloumns's data type
	int nType = (!pType) ? FSI_LONG : *pType;
	if(!pType)
	{
		for(int rr = 0; rr < nRange; rr++)
		{
			get_range_span(dr, rr, r1, c1, r2, c2);
			
			for(int cc = c1; cc <= c2; cc++)
			{
				int nFormat = wksSource.Columns(cc).GetInternalDataType();
				if(nFormat == FSI_MIXED || nFormat == FSI_REAL || nFormat == FSI_DOUBLE || nFormat == FSI_COMPLEX)
				{
					nType = FSI_DOUBLE;
					break;
				}
			}
			
			if(nType == FSI_DOUBLE)
				break;
		}
	}
	
	//set cloumns's data type
	for(int rr = 0; rr < nRange; rr++)
	{
		get_range_span(dr, rr, r1, c1, r2, c2);
		
		for(int cc = c1; cc <= c2; cc++)
		{
			bool bRet =  wksSource.Columns(cc).SetInternalDataType(nType) ;
			if(!bRet)
				return -1;
		}
	}
		
	return nType;
}
///end SET_COLS_IN_RANGE_TO_SAME_DATATYPE

///Cheney 06/23/06 CHECK_EACH_SUBRANGE_SAME_ROW_NUM
bool check_each_subrange_same_row_num(DataRange& dr)
{
	Worksheet wksSource;
	int r1, c1, r2, c2;

	get_range_span(dr, 0, r1, c1, r2, c2);
	if(!get_source_worksheet(dr, wksSource))
		return false;
	
	int nRow1 = r1, nRow2 = r2;	
	int nRange = dr.GetNumRanges();
	
	for(int rr = 0; rr < nRange; rr++)
	{
		get_range_span(dr, rr, r1, c1, r2, c2);
		if(nRow1 != r1 || nRow2 != r2)
			return false;
	}
	
	return true;
}
///end CHECK_EACH_SUBRANGE_SAME_ROW_NUM

//---- CPY 8/13/09 QA80-14093-P2 GET_PAGE_DISPLAY_INDEX_IN_PE
static void _reoder_pages(vector<string>& vsPages, int nOrder)
{
	if(nOrder <= GGN_ORDER_BY_CURRENT_PE)
	{
		out_str("_reoder_pages found bad nOrder passed in.");
		return;
	}
	vector<uint> vn;vn.SetSize(vsPages.GetSize());
	vector vv;vv.SetSize(vsPages.GetSize());
	vector<string> vsNames; vsNames.SetSize(vsPages.GetSize());
	int nTypeStr = 0;//0 for vv, 1 = vsNames
	int wOption = 0;
	for(int ii = 0; ii< vsPages.GetSize(); ii++)
	{
		PageSystemInfo st;
		Page pg(vsPages[ii]);pg.GetPageSystemInfo(&st);
		switch(nOrder)
		{
		case GGN_ASCENDING_BY_MODIFIED:
			wOption |= SORT_ASCENDING;
		case GGN_DESENDING_BY_MODIFIED:
			vv[ii] = st.dModified;
			break;
		case GGN_ASCENDING_BY_CREATION:
			wOption |= SORT_ASCENDING;
		case GGN_DESENDING_BY_CREATION:
			vv[ii] = st.dCreated;
			break;
		case GGN_ASCENDING_BY_LN:
		case GGN_ASCENDING_BY_SN:
			nTypeStr = 1;
			wOption |= SORT_ASCENDING | SORT_NUMERIC_SUFFIX; //CPY 8/14/09 QA70-14151-P1 SLIDE_SHOW_SORT_NAME_SHOULD_CHK_END_NUMBERS, add SORT_NUMERIC_SUFFIX
			vsNames[ii] = GGN_ASCENDING_BY_SN==nOrder? pg.GetName():pg.GetLongName();
			break;
		}
	}
	if(nTypeStr)
		vsNames.Sort(wOption, true, vn);
	else
		vv.Sort(wOption, true, vn);
	vsPages.Reorder(vn);
}

static void _reorder_pages_in_folder(vector<string>& vsNames, Folder fld)
{
	int nn;
	vector<uint> vn;vn.SetSize(vsNames.GetSize());
	vector<int> vn1;vn1.Data(0, vsNames.GetSize()-1); 
	for(int ii = 0; ii< vsNames.GetSize(); ii++)
	{
		Page pg(vsNames[ii]);
		pg.GetStatus(fld, &nn);
		vn1[ii] = nn; 
	}
	vn1.Sort(SORT_ASCENDING, true, vn);
	vsNames.Reorder(vn);
}
//----
//------ CPY 7/14/09 QA70-13947 SLIDE_SHOW_GET_GRAPHS_GENERAL_OC_FUNC
//i write a separate function from get_folder_pages_name as we need one specifically for graphs
///Kyle 03/16/2010 QA80-15208 SLIDESHOW_AND_PPTSLIDE_SUPPORT_EMBEDDED_GRAPHS
//int get_graph_names(Folder& fld, vector<string>& vsNames, bool bRecursive, int nSkip, int nOrder)
int get_graph_names(Folder& fld, vector<string>& vsNames, bool bRecursive, int nSkip, int nOrder, bool bIncludeEmbedded)
///End SLIDESHOW_AND_PPTSLIDE_SUPPORT_EMBEDDED_GRAPHS
{
	string strName;
	foreach(PageBase page in fld.PagesAndShortcuts) 
	{
		int nPageType = page.GetType();
		if(nPageType != EXIST_GRAPH && nPageType != EXIST_LAYOUT)
			continue;
		DWORD dw = page.GetStatus(fld);
		switch(nSkip)
		{
		case GGNSKIP_HIDDEN_NON_SHORTBUT:
			if(!(dw & PBFS_SHORTCUT) && (dw & PBFS_HIDDEN))
				continue;
			break;
		case GGNSKIP_HIDDEN_SLIDE:
			if(dw & PBFS_SLIDE_HIDDEN)
				continue;
			break;
		}
		vsNames.Add(page.GetName());
	}
	if(GGN_ORDER_BY_CURRENT_PE == nOrder)
		_reorder_pages_in_folder(vsNames, fld);
	
	///Kyle 03/16/2010 QA80-15208 SLIDESHOW_AND_PPTSLIDE_SUPPORT_EMBEDDED_GRAPHS, append at the end if order by slide indices or use current folder order, so add there after sorting if needed
	if( bIncludeEmbedded )
	{
		vector<string> vsEmbeddedNames;
		if( get_folder_embedded_graphs(fld, vsEmbeddedNames, false) > 0 )		// take care of bRecursive later
		{
			vsNames.Append(vsEmbeddedNames);
		}
	}
	///End SLIDESHOW_AND_PPTSLIDE_SUPPORT_EMBEDDED_GRAPHS

	if(bRecursive)
	{
		int nOrderSub = nOrder> GGN_ORDER_BY_CURRENT_PE? GGN_ORDER_BY_SLIDE : nOrder;// only if sort by page properties,will order later
		foreach(Folder sub in fld.Subfolders)
		{
			vector<string> vsSubNames;
			//if(get_graph_names(sub, vsSubNames, bRecursive, nSkip, nOrderSub) > 0)
			if(get_graph_names(sub, vsSubNames, bRecursive, nSkip, nOrderSub, bIncludeEmbedded) > 0)
				vsNames.Append(vsSubNames);
		}
	}
	if(nOrder > GGN_ORDER_BY_CURRENT_PE)// by page properties, then sort globally for all subfolders
		_reoder_pages(vsNames, nOrder);
	
    return vsNames.GetSize();
}

int get_sel_page_names(vector<string>& vsNames, int nType, int nOrder)
{
	Folder 	fld = Project.ActiveFolder();
	string strName;
	foreach(PageBase page in fld.PagesAndShortcuts) 
	{
		int nPageType = page.GetType();if(nPageType == EXIST_LAYOUT) nPageType = EXIST_GRAPH;
		if(nType >= 0 && nPageType != nType)
			continue;

		if(PBFS_SELECTED & page.GetStatus(fld))
		{
			vsNames.Add(page.GetName());
		}
	}
    return vsNames.GetSize();
}
//------ end SLIDE_SHOW_GET_GRAPHS_GENERAL_OC_FUNC

///Jasmine 07/12/06 GET_FOLDER_PAGES_NAME
///---Sim 07-14-2009 QA81-13935-P1 SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER
//int get_folder_pages_name(Folder fld, vector<string>& vsGraphs, int nPageType, bool bRecursive, int nPageShowState)// = -1, = false, = -1
int get_folder_pages_name(Folder fld, vector<string>& vsGraphs, int nPageType, bool bRecursive, int nPageShowState, bool bIncludeShortcut)// = -1, = false, = -1, = false
///---END QA81-13935-P1 SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER
{
	bool bOK = false;
	Collection<PageBase> cPages;
	///---Sim 07-14-2009 QA81-13935-P1 SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER
#ifdef __SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER__
	if ( bIncludeShortcut )
		cPages = fld.PagesAndShortcuts;
	else
#endif //__SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER__
	///---END QA81-13935-P1 SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER
		cPages = fld.Pages;
		
	foreach(PageBase gp in cPages)
	{
		if(-1 != nPageType && gp.GetType() != nPageType)
			continue;
		switch(nPageShowState)
		{
		case PAGE_OPEN:
			bOK = ( gp.GetShow() != PAGE_MINIMIZED && gp.GetShow() != PAGE_HIDDEN );
			break;
		case -1:
			bOK = true;
			break;
		default:
			bOK = gp.GetShow() == nPageShowState;
			break;
		}
		if(bOK)
			vsGraphs.Add(gp.GetName());		
	}
	
	if(bRecursive)
	{
		foreach(Folder subfld in fld.Subfolders)
		{
			///---Sim 07-14-2009 QA81-13935-P1 SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER
			//get_folder_pages_name(subfld, vsGraphs, nPageType, bRecursive, nPageShowState);
			get_folder_pages_name(subfld, vsGraphs, nPageType, bRecursive, nPageShowState, bIncludeShortcut);
			///---END QA81-13935-P1 SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER
		}
	}
	return vsGraphs.GetSize();
}
///End GET_FOLDER_PAGES_NAME


///Jasmine 11/17/06 GET_ALL_EMBEDDED_GRAPHS_IN_FOLDER
int get_folder_embedded_graphs(Folder fld, vector<string>& vsGraphs, bool bRecursive)//= false
{
	Collection<PageBase> cPages;
	cPages = fld.Pages;
	foreach(PageBase pg in cPages)
	{
		WorksheetPage wp(pg);
		if(!wp)
			continue;
		foreach(Layer lay in wp.Layers)
		{
			Worksheet wks(lay);
			vector<string> vs;
			if(wks && wks.GetEmbeddedGraphs(vs, GRAPH_IN_WKS_EXCLUDE_BITS))
				vsGraphs.Append(vs);
		}
	}
	if(bRecursive)
	{
		foreach(Folder subfld in fld.Subfolders)
		{
			get_folder_embedded_graphs(subfld, vsGraphs, bRecursive)
		}
	}
	return vsGraphs.GetSize();
}
///End GET_ALL_EMBEDDED_GRAPHS_IN_FOLDER

///Jasmine 07/31/09 QA80-14022 ADD_FAVORITES_TO_AVAILABLE_DROPDOWN
#define E_STR_FAVOR_FOLDER		_LE("Favorites")
bool get_favorites_folder(Folder& fldFavor)
{
	string strFavor = GetLocalized(E_STR_FAVOR_FOLDER);
	
	fldFavor = Project.RootFolder.Subfolders(strFavor);
	if(!fldFavor)
		fldFavor = Project.RootFolder.Subfolders(E_STR_FAVOR_FOLDER);
	
	return fldFavor.IsValid();
}
///End ADD_FAVORITES_TO_AVAILABLE_DROPDOWN

///---Sim 10-12-2007 QA70-10520 CENTRALIZE_MAKE_PAGE_SHORT_LONG_NAME
string get_page_short_long_name(const PageBase& pg)
{
	if ( !pg )
	{
		ASSERT(FALSE);
		return "";
	}
	
	string strName = pg.GetName();
	string strLongname = pg.GetLongName();
	if(!strLongname.IsEmpty() && strName.Compare(strLongname))
		strName += STR_PAGE_SHORT_LONG_NAME_SEPARATOR + strLongname;
	
	return strName;
}
///---END QA70-10520 CENTRALIZE_MAKE_PAGE_SHORT_LONG_NAME

/// Iris 12/18/2006 v8.0527 COMBO_TO_SEL_ALL_PAGES_IN_FOLDER_FOR_EXPORT_PAGE
//---- Iris 01/04/2007 v8.0536 ADD_ACTIVE_PAGE_INTO_PAGE_OPTION
//int get_folder_pages_name(vector<string>& vsGraphs, int nOption, LPCSTR lpcszGraphs, LPCSTR lpcszRemove, int nPageType, bool bIncLongName)
///---Sim 07-14-2009 QA81-13935-P1 SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER
//int get_folder_pages_name(vector<string>& vsPages, int nOption, int nPageOptionOffset, LPCSTR lpcszGraphs, LPCSTR lpcszRemove, int nPageType, bool bIncLongName)
int get_folder_pages_name(vector<string>& vsPages, int nOption, int nPageOptionOffset, LPCSTR lpcszGraphs, LPCSTR lpcszRemove, int nPageType, bool bIncLongName, bool bIncludeShortcut)
///---END QA81-13935-P1 SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER
//----
{
	Folder 	fld = Project.ActiveFolder();
	int 	nPageShowState = PAGE_OPEN;
	bool 	bRecursive = false, bSpecified = false;
	//---- Iris 01/04/2007 v8.0536 ADD_ACTIVE_PAGE_INTO_PAGE_OPTION
	// Just want show Active Page in Export Page dialog and not want show it in Merge Graph dialg, so introduced nPageOptionOffset
	nOption += nPageOptionOffset;
	//----
	
	vsPages.RemoveAll();
	switch(nOption)
	{
	//---- Iris 01/04/2007 v8.0536 ADD_ACTIVE_PAGE_INTO_PAGE_OPTION
	case OPTION_ACTIVE_PAGE:
		Layer	lay = Project.ActiveLayer();
		if(lay.IsValid())
		{
			Page 	pg = lay.GetPage();	
			if(nPageType == pg.GetType())
				vsPages.Add(pg.GetName());
			///Jasmine 03/24/07 GET_GRAPH_IN_WKBOOK
			else if(EXIST_PLOT == nPageType && EXIST_WKS == pg.GetType())
			{
				foreach(Layer layer in pg.Layers)
				{
					vector<string> vs;
					Worksheet wks(layer);
					if(wks.IsValid())
						wks.GetEmbeddedGraphs(vs, GRAPH_IN_WKS_EXCLUDE_BITS);
					vsPages.Append(vs);
				}
			}
			///End GET_GRAPH_IN_WKBOOK
		}
		break;
	//----
	
	case OPTION_ALL_EMBEDDED_IN_ACTIVE_FOLDER:
		get_folder_embedded_graphs(fld, vsPages);
		
	case OPTION_ALL_IN_ACTIVE_FOLDER:
		nPageShowState = -1;
		break;
		
	case OPTION_ALL_IN_OPJ:
		fld = Project.RootFolder;
		
	case OPTION_ALL_RECURSIVE_IN_ACTIVE_FOLDER:
		nPageShowState = -1;
		bRecursive = true;
		break;	
		
	case OPTION_ALL_OPEN_IN_ACTIVE_FOLDER:
		break;
		
	case OPTION_SPECIFIED:
		bSpecified = true;
		string strNames(lpcszGraphs);
		if(strNames.Find("|")>0)
			strNames.GetTokens(vsPages, '|');
		else
			strNames.GetTokens(vsPages, '\n');
		///Jasmine 01/27/07 remove sapce
		for(int ii = vsPages.GetSize() - 1; ii > -1; ii--)
		{
			string strTemp = vsPages[ii];
			strTemp.TrimLeft();
			strTemp.TrimRight();
			Page pg(strTemp);
			if(pg)
				vsPages[ii] = strTemp;
			else
				vsPages.RemoveAt(ii);
		}
		break;
		
	default:
		return 0;
	}
	
	if(!bSpecified && OPTION_ACTIVE_PAGE != nOption)
	///---Sim 07-14-2009 QA81-13935-P1 SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER
		//get_folder_pages_name(fld, vsPages, nPageType, bRecursive, nPageShowState);
		get_folder_pages_name(fld, vsPages, nPageType, bRecursive, nPageShowState, bIncludeShortcut);
	///---END QA81-13935-P1 SUPPORT_EXPORT_ALL_SHORTCUT_PAGE_IN_FOLDER
	
	//remove the pages that want to exclude from page list
	string 		strExclude(lpcszRemove);	
	vector<string> 	vsExcludes;
	strExclude.GetTokens(vsExcludes, '|');
	for(int nn=0; nn<vsExcludes.GetSize(); nn++)
	{
		int 	index = vsPages.Find(vsExcludes[nn]);
		if(index > -1)
			vsPages.RemoveAt(index);
	}
	
	/// Iris 12/18/2006 v8.0527 COMBO_TO_SEL_ALL_PAGES_IN_FOLDER_FOR_EXPORT_PAGE
	//convert list to ShortName - LongName format
	if( bIncLongName )
	{
		for(int nn=0; nn<vsPages.GetSize(); nn++)
		{
			string 	str = vsPages[nn];
			Page 	pg(str);
			///---Sim 10-12-2007 QA70-10520 CENTRALIZE_MAKE_PAGE_SHORT_LONG_NAME
			/*
			string strLongname = pg.GetLongName();
			if(str.Compare(strLongname))
				str += " - " + strLongname;
			*/
			str = get_page_short_long_name(pg);
			///---END QA70-10520 CENTRALIZE_MAKE_PAGE_SHORT_LONG_NAME
			vsPages[nn] = str;
		}
	}
	///end COMBO_TO_SEL_ALL_PAGES_IN_FOLDER_FOR_EXPORT_PAGE
	
	return vsPages.GetSize();
}
///end COMBO_TO_SEL_ALL_PAGES_IN_FOLDER_FOR_EXPORT_PAGE



///Jasmine 08/16/06 ADD_SOME_TEMPLATE_FUNC
///Jasmine 11/22/06 REMOVE_TEMPLATE_NODE_IF_FILE_INVALID

//------ Folger 08/22/07 LOAD_SYSTEM_USER_GROUP_TEMPLATE_SEPERATELY
//bool load_template_tree(Tree& trXML)
bool load_template_tree(Tree& trXML, int nLocation)
//------ End LOAD_SYSTEM_USER_GROUP_TEMPLATE_SEPERATELY
{
	//------ Folger 08/22/07 LOAD_SYSTEM_USER_GROUP_TEMPLATE_SEPERATELY
	//string strFile(STR_TEMPLATE_XML);
	//if(!strFile.IsFile())
		//construct_template_organizer_tree();
	//if(!trXML.IsValid() || !trXML.Load(STR_TEMPLATE_XML))
		//return false;
	//_check_add_shared_templates(trXML);	///Jasmine 07/30/07 #8854 SHOW_TEMPLATE_UNDER_GROUP_FOLDER
	
	string strFile;
	string strPath;		//------ Folger 09/29/07 NEW_DISIGN_FOR_SAVING_TEMPLATE_XML
	switch (nLocation)
	{
	case TEMPLATE_LOCATION_SYSTEM_FOLDER:
		strFile = STR_SYSTEM_TEMPLATE_XML;
		strPath = okutil_get_origin_path(ORIGIN_PATH_SYSTEM);	//------ Folger 09/29/07 NEW_DISIGN_FOR_SAVING_TEMPLATE_XML
		break;
	case TEMPLATE_LOCATION_USER_FOLDER:
		strFile = STR_TEMPLATE_XML;
		strPath = okutil_get_origin_path(ORIGIN_PATH_USER);		//------ Folger 09/29/07 NEW_DISIGN_FOR_SAVING_TEMPLATE_XML
		break;
	case TEMPLATE_LOCATION_GROUP_FOLDER:
		strFile = STR_GROUP_TEMPLATE_XML;
		strPath = okutil_get_origin_path(ORIGIN_PATH_GROUP);	//------ Folger 09/29/07 NEW_DISIGN_FOR_SAVING_TEMPLATE_XML
		break;
	//------ Folger 09/25/07 TREAT_SERVER_GROUP_AND_LOCAL_GROUP_SEPARATELY
	case TEMPLATE_LOCATION_SERVER_GROUP_FOLDER:
		strFile = STR_SERVER_GROUP_TEMPLATE_XML;
		strPath = okutil_get_origin_path(ORIGIN_PATH_SERVER_GROUP_FOLDER);	//------ Folger 09/29/07 NEW_DISIGN_FOR_SAVING_TEMPLATE_XML
		break;
	//------ End TREAT_SERVER_GROUP_AND_LOCAL_GROUP_SEPARATELY
	default:
		break;
	}
	
	if (strFile.CompareNoCase(STR_SYSTEM_TEMPLATE_XML) == 0 && !strFile.IsFile())
	{
		///Jasmine 03/31/09 SHOULD_NOT_SAVE_TEMPLATE_XML_IN_EXE_FOLDER
		//construct_template_organizer_tree();
		error_report(strFile + " is missing!", true);
		///End SHOULD_NOT_SAVE_TEMPLATE_XML_IN_EXE_FOLDER
	}
	
	if (strPath.IsEmpty() || !trXML.IsValid() || !trXML.Load(strFile))
		return false;
	
	//------ End LOAD_SYSTEM_USER_GROUP_TEMPLATE_SEPERATELY
	
	foreach(TreeNode trBranch in trXML.Children)
	{
		foreach(TreeNode trCategory in trBranch.Children)
		{
			foreach(TreeNode trTemplate in trCategory.Children)	
			{
				//------ Folger 09/29/07 NEW_DISIGN_FOR_SAVING_TEMPLATE_XML
				string strFilePath;
				//trTemplate.GetAttribute(STR_FILENAME_ATTRIB, strFilePath);
				////------ Folger 08/29/07 SAVE_PARTITIAL_GROUP_PATH_FOR_PUBLISH
				////------ Folger 09/25/07 TREAT_SERVER_GROUP_AND_LOCAL_GROUP_SEPARATELY
				////if (nLocation == TEMPLATE_LOCATION_GROUP_FOLDER)
				//if (nLocation == TEMPLATE_LOCATION_GROUP_FOLDER || nLocation == TEMPLATE_LOCATION_SERVER_GROUP_FOLDER)
				////------ End TREAT_SERVER_GROUP_AND_LOCAL_GROUP_SEPARATELY
				////------ CPY 9/22/2007 QA70-10384 CODE_CLEANUP_SEPARATE_UNC_AND_LOCAL_PATH
				//// this type of code should be totally rewritten properly, but I don't really know what was the original logic, 
				//// will need to wait for Folger to clean this up
				////	strFilePath = GetAppPath(true) + strFilePath;
				//{
					//if(!strFilePath.IsEmpty() && !is_str_has_path(strFilePath))
						////------ Folger 09/24/07 CLEAN_UP_TEMPLATE_PUBLISH_FOR_CORRECT_LOGIC
						////strFilePath = GetAppPath(true) + strFilePath; // why adding EXE path?				
						//strFilePath = okutil_get_origin_path(nLocation == TEMPLATE_LOCATION_GROUP_FOLDER ? ORIGIN_PATH_GROUP : ORIGIN_PATH_SERVER_GROUP_FOLDER) + strFilePath;
						////------ End CLEAN_UP_TEMPLATE_PUBLISH_FOR_CORRECT_LOGIC
				//}
				////------
				////------ End SAVE_PARTITIAL_GROUP_PATH_FOR_PUBLISH
				trTemplate.GetAttribute(STR_NAME_ATTRIB, strFilePath);
				if (GetFilePath(strFilePath).IsEmpty())
					strFilePath = strPath + strFilePath;
				//------ End NEW_DISIGN_FOR_SAVING_TEMPLATE_XML
				if(!strFilePath.IsFile())
					trTemplate.Remove();
				//------ Folger 09/29/07 NEW_DISIGN_FOR_SAVING_TEMPLATE_XML
				else
				{
					trTemplate.SetAttribute(STR_FILENAME_ATTRIB, strFilePath);
					trTemplate.SetAttribute(STR_LABEL_ATTRIB, template_composite_name_from_file_path(strFilePath, "Templates"));
				}
				//------ End NEW_DISIGN_FOR_SAVING_TEMPLATE_XML
				
			}
		}
	}
	//trXML.Save(STR_TEMPLATE_XML);		//------ Folger 08/22/07 LOAD_SYSTEM_USER_GROUP_TEMPLATE_SEPERATELY
	//trXML.Save(STR_GROUP_TEMPLATE_XML);	///Jasmine 07/30/07 #8854 SHOW_TEMPLATE_UNDER_GROUP_FOLDER	///Jasmine 08/15/07 QA80-10155 NO_MODIFICATION_TO_GROUP_FOLDER_FILE
	return true;
}
///End REMOVE_TEMPLATE_NODE_IF_FILE_INVALID
///Jasmine 07/30/07 #8854 SHOW_TEMPLATE_UNDER_GROUP_FOLDER
			
//------ Folger 08/22/07 LOAD_SYSTEM_USER_GROUP_TEMPLATE_SEPERATELY
//bool _check_add_shared_templates(TreeNode& tr)
//{
	//Tree trXML;
	//if(!tr || !trXML.Load(STR_GROUP_TEMPLATE_XML))
		//return false;
	//string strGroupPath = okutil_get_origin_path(ORIGIN_PATH_GROUP, NULL, TRUE);
	//vector<int>  vnType = { EXIST_GRAPH, EXIST_WKS, EXIST_MATRIX};
	//for(int ii = 0; ii < vnType.GetSize(); ii++)
	//{
		//StringArray saFiles;
		//FindFiles(saFiles, strGroupPath, page_get_template_ext(vnType[ii]));
		//int nSize = saFiles.GetSize();
		//for(int nn = 0; nn < nSize; nn++)
		//{
			//string strCategory;
			//string strFile = strGroupPath + saFiles[nn];
			//string strTemplate = GetFileName(saFiles[nn], TRUE);
			//string strUser = okutil_xft_GetFunctionNameStr(strTemplate, ORIGIN_PATH_USER);
			//strTemplate = okutil_xft_GetFunctionNameStr(strTemplate, ORIGIN_PATH_GROUP);
			//
			//TreeNode trBH = tree_get_node_by_id(tr, vnType[ii]);
			//TreeNode trBranch = tree_get_node_by_id(trXML, vnType[ii]);
			//TreeNode trTemp = trBH.FindNodeByAttribute(STR_LABEL_ATTRIB, strTemplate);
			//if(trTemp)
				//continue;
			//TreeNode trTemplate = trBranch.FindNodeByAttribute(STR_LABEL_ATTRIB, strUser);
			//if(!trTemplate)
				//continue;
			//
			//trTemplate.Parent().GetAttribute(STR_LABEL_ATTRIB, strCategory);				
			//TreeNode trCategory = trBH.FindNodeByAttribute(STR_LABEL_ATTRIB, strCategory);
			//if(!trCategory)
				//trCategory = _add_category_node(trBH, strCategory);
			//_add_template_node(trCategory, strTemplate, strFile);
		//}
	//}
	//return true;
//}
//------ End LOAD_SYSTEM_USER_GROUP_TEMPLATE_SEPERATELY

///End SHOW_TEMPLATE_UNDER_GROUP_FOLDER
//Jasmine 08/24/06 CONSTRUCT_TEMP_ORG_TREE, should move to UtilSdk.cpp

//if there's no template.xml in system folder, 
//this function can construct a tree and save in template.xml under system folder
bool construct_template_organizer_tree()
{
	Tree trXML;
	//------ Folger 08/22/07 LOAD_SYSTEM_USER_GROUP_TEMPLATE_SEPERATELY
	//string strXML = STR_TEMPLATE_XML;
	string strXML = STR_SYSTEM_TEMPLATE_XML;
	//------ End LOAD_SYSTEM_USER_GROUP_TEMPLATE_SEPERATELY
	
	///Jasmine 03/31/09 SHOULD_NOT_SAVE_TEMPLATE_XML_IN_EXE_FOLDER
	//if(strXML.IsFile() && trXML.Load(strXML))
		//return true;
	///End SHOULD_NOT_SAVE_TEMPLATE_XML_IN_EXE_FOLDER
	
	int nRet = 0;
	
	///Jasmine 07/31/07 USE_FILE_TYPE_STRING_FOR_BRANCH_LABEL
	//vector<string>  vsType = {"Graph", "Workbook", "Matrix"};
	vector<int>  vnType = { EXIST_GRAPH, EXIST_WKS, EXIST_MATRIX};
	int nCount = vnType.GetSize(), ii;
	for(ii = 0; ii < nCount; ii++)
	{
		//TreeNode trBranch = tree_check_get_node(trXML, _L("branch" + vsType[ii]), vnType[ii], STR_LABEL_ATTRIB, vsType[ii]);
		string strType, strLabel;
		string strExt = page_get_template_ext(vnType[ii], strType);
		strLabel.Format(_L("%s Template (*%s)"), strType, strExt);
		/// AW 10/25/07 WRONG_LOCALIZE_MACRO
		//TreeNode trBranch = tree_check_get_node(trXML, _L("branch" + strType), vnType[ii], STR_LABEL_ATTRIB, strLabel);
		/// YuI 12/03/07 QA70-10766 JAPANESE_SAVE_TEMPLATE_AS_FAILS
		// tag names are never localized
		//	TreeNode trBranch = tree_check_get_node(trXML, _L("branch") + strType, vnType[ii], STR_LABEL_ATTRIB, strLabel);
		TreeNode trBranch = tree_check_get_node(trXML, "branch" + strType, vnType[ii], STR_LABEL_ATTRIB, strLabel);
		/// end JAPANESE_SAVE_TEMPLATE_AS_FAILS
		/// END  WRONG_LOCALIZE_MACRO
	///End USE_FILE_TYPE_STRING_FOR_BRANCH_LABEL
		trBranch.DataID = vnType[ii];
		///Jasmine 10/12/06 ADD_WORKBOOK_TEMPLATE_INTO_TEMPLATE_INI
		/*
		if(EXIST_GRAPH == vnType[ii])
			_construct_graph_branch(trBranch);
		else
			_construct_wks_matrix_branch(trBranch);  
		*/
		switch(vnType[ii])	
		{
		case EXIST_GRAPH:
			nRet += _construct_graph_branch(trBranch);
			break;
		case EXIST_WKS:
			nRet += _construct_workbook_branch(trBranch);
			break;
		case EXIST_MATRIX:
			nRet += _construct_matrix_branch(trBranch);
			break;
		}
		///End ADD_WORKBOOK_TEMPLATE_INTO_TEMPLATE_INI
	}
	//---- CPY 11/7/07 COMPILE_ERR_AND_REMOVE_FOLGER_LOCALIZE_DELETE_SYSTEM_FILE_BRANCH_CODE
	// should not localize strings that are not even sparated by space, indicating that there is possibility to be localized
	//tree_check_get_node(trXML, "branchDelete", 0, STR_LABEL_ATTRIB, "DeletedSystemFile");
	//tree_check_get_node(trXML, STR_DELETE_SECTION_TAGNAME, 0, STR_LABEL_ATTRIB, GetLocalized(STR_DELETED_SYSTEM_FILE));
	//------ Folger 11/07/07 LOCALIZE_DELETE_SYSTEM_FILE_BRANCH
	//tree_check_get_node(trXML, STR_DELETE_SECTION_TAGNAME, 0, STR_LABEL_ATTRIB, "DeletedSystemFile");
	tree_check_get_node(trXML, STR_DELETE_SECTION_TAGNAME, 0, STR_LABEL_ATTRIB, STR_DELETE_SECTION);
	//------ End LOCALIZE_DELETE_SYSTEM_FILE_BRANCH
	//----
	return trXML.Save(strXML) && nRet == nCount;
} 
static bool _construct_graph_branch(TreeNode& trGraph)
{
	if(!trGraph.IsValid())
		return error_report("Error! Input tree is invalid!");
	//read ini file
	///Jasmine 03/31/09 SHOULD_NOT_SAVE_TEMPLATE_XML_IN_EXE_FOLDER
	//string strINIFilePath = okutil_get_origin_path(ORIGIN_PATH_USER, NULL, TRUE) + "Template.ini";
	//if(!strINIFilePath.IsFile())
	//	strINIFilePath = STR_SYSTEM_PATH + "Template.ini";
	string strINIFilePath = STR_SYSTEM_PATH + "Template.ini";
	///End SHOULD_NOT_SAVE_TEMPLATE_XML_IN_EXE_FOLDER
	if(!strINIFilePath.IsFile())
		return error_report(strINIFilePath + " is missing!");
	INIFile iniTemplate(strINIFilePath);
	
	//construct graph tree
	string strSection = "Categories";
	StringArray saSections;
	iniTemplate.GetKeyNames(saSections, strSection);
	int nCount = saSections.GetSize();
	for( int iSection = 1; iSection < nCount; iSection++ )
	{
		string strCategory = iniTemplate.ReadString(strSection, saSections[iSection]);
		TreeNode trCate = _add_category_node(trGraph, strCategory);
		
		StringArray saKeys;
		iniTemplate.GetKeyNames(saKeys, strCategory);
		int nSize = saKeys.GetSize();
		for( int iKey = 0; iKey < nSize; iKey++ )
		{
			string strPath, strFile = saKeys[iKey] + page_get_template_ext(trGraph.DataID);
			char szTemp[MAXFULLPATH];
			lstrcpy(szTemp, STR_SYSTEM_PATH);
			if(FindFile(strFile, szTemp))
				strPath = szTemp;
			TreeNode trTemplate = _add_template_node(trCate, saKeys[iKey], strPath + strFile);
		}  
	}
	return true;
}
///Jasmine 10/12/06 ADD_WORKBOOK_TEMPLATE_INTO_TEMPLATE_INI
/*
static bool _construct_wks_matrix_branch(TreeNode& trBranch)
{
	if(!trBranch.IsValid())
		return error_report("Error! Input tree is invalid!");
	TreeNode trCate = _add_category_node(trBranch, _L("Category"));
	//get file from system folder only
	StringArray saSystemFile;//filename with extension  
	FindFiles(saSystemFile, STR_SYSTEM_PATH, page_get_template_ext(trBranch.DataID));
	saSystemFile.Sort();
	int nCount = saSystemFile.GetSize();
	for(int ii = 0; ii < nCount; ii++ )
	{
		string strTemplate = saSystemFile[ii].GetToken(0,'.');
		_add_template_node(trCate, strTemplate, STR_SYSTEM_PATH + saSystemFile[ii]);
	}
	return true;
} 
*/
///Jasmine 07/30/07 MAX_UPDATE_ALL_BUILT_IN_TEMPLATE_IN_TEMPLATE_INI
static bool _construct_workbook_branch(TreeNode& trBranch, int nType = EXIST_WKS)
{
	if(!trBranch.IsValid())
		return error_report("Error! Input tree is invalid!");
	//------ Folger 11/08/07 NO_NEED_LOCALIZE
	//TreeNode trCate = _add_category_node(trBranch, _L("Built-in"));
	///Jasmine 02/04/09 QA80-13028 SHOW_USER_DEFIND_CATEGORY_INSTEAD_OF_BUILT_IN_CATEGORY_WHEN_SAVING
	//TreeNode trCate = _add_category_node(trBranch, (string)"Built-in");
	string strCategory = STR_BUILT_IN_CATEGORY;
	TreeNode trCate = _add_category_node(trBranch, strCategory);
	///End SHOW_USER_DEFIND_CATEGORY_INSTEAD_OF_BUILT_IN_CATEGORY_WHEN_SAVING
	//------ End NO_NEED_LOCALIZE
	//read ini file
	///Jasmine 03/31/09 SHOULD_NOT_SAVE_TEMPLATE_XML_IN_EXE_FOLDER
	//string strINIFilePath = okutil_get_origin_path(ORIGIN_PATH_USER, NULL, TRUE) + "Template.ini";
	//if(!strINIFilePath.IsFile())
		//strINIFilePath = STR_SYSTEM_PATH + "Template.ini";
	string strINIFilePath = STR_SYSTEM_PATH + "Template.ini";
	///End SHOULD_NOT_SAVE_TEMPLATE_XML_IN_EXE_FOLDER
	if(!strINIFilePath.IsFile())
		return error_report(strINIFilePath + " is missing!");
	INIFile iniTemplate(strINIFilePath);	
	StringArray saKeys;
	//iniTemplate.GetKeyNames(saKeys, "Workbook");
	string strPageType;
	page_get_template_ext(nType, strPageType);
	iniTemplate.GetKeyNames(saKeys, strPageType);
	int nSize = saKeys.GetSize();
	for( int iKey = 0; iKey < nSize; iKey++ )
	{
		string strPath, strFile = saKeys[iKey] + page_get_template_ext(trBranch.DataID);
		char szTemp[MAXFULLPATH];
		lstrcpy(szTemp, STR_SYSTEM_PATH);
		if(FindFile(strFile, szTemp))
			strPath = szTemp;
		TreeNode trTemplate = _add_template_node(trCate, saKeys[iKey], strPath + strFile);
	}  
	return true;
}
static bool _construct_matrix_branch(TreeNode& trBranch)
{
	/*
	if(!trBranch.IsValid())
		return error_report("Error! Input tree is invalid!");
	TreeNode trCate = _add_category_node(trBranch, _L("Built-in"));
	//now there's only one Built-in ORIGIN.OTM
	_add_template_node(trCate, "ORIGIN", STR_SYSTEM_PATH + "ORIGIN.OTM");
	return true;	
	*/
	return _construct_workbook_branch(trBranch, EXIST_MATRIX);
}
///End MAX_UPDATE_ALL_BUILT_IN_TEMPLATE_IN_TEMPLATE_INI
///End ADD_WORKBOOK_TEMPLATE_INTO_TEMPLATE_INI
static TreeNode _add_category_node(TreeNode& trBranch, string& strCategory)
{
	string strNode = tree_get_enum_node_name(trBranch, STR_CATEGORY_NODE);
	if(strCategory.IsEmpty())
		strCategory = tree_get_enum_attribute_value(trBranch, STR_LABEL_ATTRIB, STR_NEW_CATEGORY_PREFIX);
	return tree_check_get_node(trBranch, strNode, TRGP_BRANCH, STR_LABEL_ATTRIB, strCategory);
}
static TreeNode _add_template_node(TreeNode& trCategory, string strTemplate, string strFile)
{
	string strNode = tree_get_enum_node_name(trCategory, STR_TEMPLATE_NODE);
	//------ Folger 09/29/07 NEW_DISIGN_FOR_SAVING_TEMPLATE_XML
	//TreeNode trTemplate = tree_check_get_node(trCategory, strNode, ONODETYPE_TREE_NODE, STR_LABEL_ATTRIB, strTemplate); 
	//bool flag = trTemplate.SetAttribute(STR_FILENAME_ATTRIB, strFile);
	TreeNode trTemplate = tree_check_get_node(trCategory, strNode, ONODETYPE_TREE_NODE, STR_NAME_ATTRIB, GetFileName(strFile)); 
	//------ End NEW_DISIGN_FOR_SAVING_TEMPLATE_XML
	return trTemplate; 
}
///End CONSTRUCT_TEMP_ORG_TREE
//check if the template name exist or not
string page_get_template_category(LPCSTR lpcszTemplateOrganizerTreeFile, LPCSTR lpcszTemplate, int nType)
{
	Tree trXML;
	TreeNode trBranch;
	string strCate;
	trXML.Load(lpcszTemplateOrganizerTreeFile);
	if(trXML.IsValid())
		trBranch = tree_get_node_by_id(trXML, nType);
	if(trBranch.IsValid())
		strCate = page_get_template_category(lpcszTemplate, trBranch);
	return strCate;
}

string page_get_template_category(LPCSTR lpcszTemplate, TreeNode& trBranch)
{
	string strCate;
	TreeNode tr;
	if(trBranch.IsValid())
		tr = trBranch.FindNodeByAttribute(STR_LABEL_ATTRIB, lpcszTemplate);//, true, true); ///Jasmine 09/04/06 USE_DEFAULT_SETTING
	if(tr.IsValid() && tr.Parent().IsValid())
	{
		tr = tr.Parent();
		tr.GetAttribute(STR_LABEL_ATTRIB, strCate);
		if(!lstrlen(strCate))
			strCate = tr.tagName;
	}
	return strCate;
}

bool page_delete_template(LPCSTR lpcszTemplateOrganizerTreeFile, LPCSTR lpcszCategory, LPCSTR lpcszTemplate, int nWinType)
{
	Tree trXML;
	TreeNode trBranch, trCategory, trTemplate;
	trXML.Load(lpcszTemplateOrganizerTreeFile);
	if(!trXML.IsValid())
		return error_report("Error! Can't load TemplateOrganizer Tree file!");
	trBranch = tree_get_node_by_dataid(trXML, nWinType);
	if(!trBranch.IsValid())
		return true;
	trCategory = trBranch.FindNodeByAttribute(STR_LABEL_ATTRIB, lpcszCategory);
	if(!trCategory.IsValid())
		trCategory = trBranch.GetNode(lpcszCategory);
	if(trCategory.IsValid())
	{
		trTemplate = trCategory.FindNodeByAttribute(STR_LABEL_ATTRIB, lpcszTemplate);
		if(trTemplate.IsValid() && trTemplate.Remove())
			return trXML.Save(lpcszTemplateOrganizerTreeFile);
	}
	return error_report("Error! Can't find specified category or template!");
}
//----- CPY 11/13/06, added bAddExt
string page_get_template_name(Page pg, bool bAddExt)
{	
	//get current Template Name from Page
	if(!pg.IsValid())
		return "";
	pg.LT_execute("win -G");
	char szTemp[ MAXFULLPATH ];
	LT_get_str( "%A", szTemp, MAXFULLPATH );
	string strTemplate(szTemp);
	if(bAddExt)
		strTemplate += page_get_template_ext(pg.GetType());
	//strTemplate = GetFileName(szTemp, true);
	return strTemplate;
}
string page_get_template_ext(int nType, string& strType)// = "")
{
	string strExt;
	switch(nType)
	{
	case EXIST_WKS:
		strExt = ".otw";
		strType = "Workbook";
		break;
	case EXIST_PLOT:
		strExt = ".otp";
		strType = "Graph";
		break;
	case EXIST_MATRIX:
		strExt = ".otm";
		strType = "Matrix";
		break;
	default:
		break;
	}
	return strExt;
}
///Jasmine 10/17/06 BUILT_IN_TEMPLATE_INI_SYSTEM_FOLDER
bool is_built_in_template(int nType, LPCSTR lpcszTemplate, LPCSTR lpcszFile)
{	//built-in: system path and name in Template.ini 
	if( lstrcmpi(GetFilePath(lpcszFile), STR_SYSTEM_PATH) )
		return false;
	//if(EXIST_MATRIX == nType)
		//return !lstrcmpi(lpcszTemplate, "ORIGIN");
	//read ini file
	string strINIFilePath = okutil_get_origin_path(ORIGIN_PATH_USER, NULL, TRUE) + "Template.ini";
	if(!strINIFilePath.IsFile())
		strINIFilePath = STR_SYSTEM_PATH + "Template.ini";
	if(!strINIFilePath.IsFile())
		return error_report("Error! Template.ini is missing!");
	INIFile iniTemplate(strINIFilePath);	
	///Jasmine 07/30/07 MAX_UPDATE_ALL_BUILT_IN_TEMPLATE_IN_TEMPLATE_INI
	if(EXIST_WKS == nType || EXIST_MATRIX == nType)
	{
		StringArray saKeys;
		//iniTemplate.GetKeyNames(saKeys, "Workbook");
		string strPageType;
		page_get_template_ext(nType, strPageType);
		iniTemplate.GetKeyNames(saKeys, strPageType);
		return -1 != saKeys.Find(lpcszTemplate);
	}
	///End MAX_UPDATE_ALL_BUILT_IN_TEMPLATE_IN_TEMPLATE_INI
	if(EXIST_PLOT != nType)
		return false;
	string strSection = "Categories";
	StringArray saSections;
	iniTemplate.GetKeyNames(saSections, strSection);
	int nCount = saSections.GetSize();
	for( int iSection = 1; iSection < nCount; iSection++ )
	{
		string strCategory = iniTemplate.ReadString(strSection, saSections[iSection]);
		StringArray saKeys;
		iniTemplate.GetKeyNames(saKeys, strCategory);
		if(-1 != saKeys.Find(lpcszTemplate))
			return true;
	}
	return false;
}
///BUILT_IN_TEMPLATE_INI_SYSTEM_FOLDER
///End ADD_SOME_TEMPLATE_FUNC

/// Hong 05/05/07 QA80-9716 ADD_PLOT_CONTROL_XF_FOR_GRAPH_WINDOW
bool remove_axis_scrollbar(GraphLayer& gl, bool bHorizontal) // = true
{
	if( !gl )
       	return false;
	
	string strRect, strThumb;
	if( bHorizontal )
	{
		strRect = X_SCROLL_BAR_NAME;
		strThumb = X_SCROLL_THUMB_NAME;
	}
	else
	{
		strRect = Y_SCROLL_BAR_NAME;
		strThumb = Y_SCROLL_THUMB_NAME;
	}
	
	gl.RemoveGraphObject(strRect);
	gl.RemoveGraphObject(strThumb);
	
	return true;	
}
/// end ADD_PLOT_CONTROL_XF_FOR_GRAPH_WINDOW
/// Hong 11/05/07 v8.0740 FIX_EXP_GRAPH_FAIL_WITH_AXIS_SCROLLBAR
bool remove_axis_scrollbar(const GraphPageBase& gp)
{
	GraphPage gpTemp(gp);
	if ( !gpTemp )
		return false;
	
	string strLTBar, strLTThumb;
	strLTBar.Format("label -r %s;", ASTERISK_SCROLL_BAR_NAME);		
	strLTThumb.Format("label -r %s;", ASTERISK_SCROLL_THUMB_NAME);	
	
	foreach ( GraphLayer gl in gpTemp.Layers )
	{
		gl.LT_execute(strLTBar);
		gl.LT_execute(strLTThumb);
	}
	
	return true;
}
/// end FIX_EXP_GRAPH_FAIL_WITH_AXIS_SCROLLBAR

//----- CPY 10/27/2007 QA70-10605 OC_ACCESS_TO_PAGE_NOTSAVED_BITS
bool page_clone(const GraphPageBase& pgSource, GraphPageBase& pgNew, bool bRemoveScalerObj, bool bSetNoClick, bool bDisableLTEvetns)
{
	if(pgSource && pgNew)
	{
		ASSERT(pgSource.GetName() != pgNew.GetName());
		
		pgSource.CreateCopy(pgNew);
		if(bSetNoClick)
		{
			string str;
			str.Format("page.noClick=%d", 0xffff); // 0xffff to disable all options
			pgNew.LT_execute(str);
		}
		if(bDisableLTEvetns)
			pgNew.SetFlag(PGDWNS_DISABLE_LT_EVENTS);
		
		//--------- CPY 5/6/08 QA70-11514 LAYOUT_PAGE_EXPORT_NOT_USING_WRONG_TEMP_PAGE_TYPE
		if(bRemoveScalerObj)
			remove_axis_scrollbar(pgNew);
		
		if(pgSource.GetType() == EXIST_LAYOUT && pgNew.GetType() == EXIST_PLOT)
		{
			GraphPage gpTemp = pgNew;
			gpTemp.ForceNoLayerBoundsAxesForTightRect = true;
#ifdef _DEBUG
			out_str("Clone from a layout into a normal graph, set ForceNoLayerBoundsAxesForTightRect");
#endif
		}
		
#ifdef _DEBUG
		printf("clone %s(%d) to %s(%d)\n", pgSource.GetName(), pgSource.GetType(), pgNew.GetName(), pgNew.GetType());
#endif
		//---------
		pgNew.Refresh(true);
		return true;
	}
	return false;
}

//--------- CPY 5/6/08 QA70-11514 LAYOUT_PAGE_EXPORT_NOT_USING_WRONG_TEMP_PAGE_TYPE
GraphPageBase clone_graph(LPCSTR lpcszGraphSortName, bool bUseGraphForLayout, bool bHideNoPE, bool bRemoveScalerObj, bool bSetNoClick, bool bDisableLTEvetns)
{
	GraphPage gpTemp;
	GraphPageBase gp(lpcszGraphSortName);
	if(!gp)
	{
		if(NULL == lpcszGraphSortName) // clone active
			gp = Project.Pages();
		else
			return gpTemp;
	}
	DWORD dwCreateBits = bHideNoPE? CREATE_SET_MISSING_IN_MANAGER : CREATE_VISIBLE_SAME;
	if(gp.GetType() == EXIST_LAYOUT)
	{
		if(!bUseGraphForLayout)
		{
			LayoutPage gply;
			gply.Create(NULL, dwCreateBits);
			page_clone(gp, gply);
			return gply;
		}
		// creating graph to clone layout, then we need to set a bit to indicate that is what we are doing
	}
	/// Kenny 08/25/2009 QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
	//gpTemp.Create("origin", dwCreateBits);	
	gpTemp.Create("origin", dwCreateBits | CREATE_ENUM_EXIST_PAGE);
	/// End QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
	page_clone(gp, gpTemp);
	return gpTemp;		
}
//--------- end LAYOUT_PAGE_EXPORT_NOT_USING_WRONG_TEMP_PAGE_TYPE

//----- end OC_ACCESS_TO_PAGE_NOTSAVED_BITS

///Folger 06/05/07 COMMENT_STR_EXCLUDE_PAGE
///Folger 05/29/07 ADD_BOOL_ENABLE_EMBED_IN_PAGE_PREVIEW_LIST_DLG
//bool open_page_preview_list_dlg(HWND hWndParent, string& strPages, bool bMultiplePages, LPCSTR lpcszStartPEpath, bool bShowFolders, LPCSTR lpcszExcludePage = NULL, bool bEnableEmbed)
//------Folger 07/18/07 CLEAN_UP_CONTROL_BITS_INTO_DWORD_FOR_GRAPH_BROWSER
//bool open_page_preview_list_dlg(HWND hWndParent, string& strPages, bool bMultiplePages, LPCSTR lpcszStartPEpath, bool bShowFolders, bool bEnableEmbed)
//-------Folger 07/19/07 CONTROL_BROWSE_PAGE_TYPE
//bool open_page_preview_list_dlg(HWND hWndParent, string& strPages, LPCSTR lpcszStartPEpath, DWORD dwCtrl)
/// Iris 6/17/2009 QA80-13771 FILTER_GRAPH_FUNCTION_SUPPORT
//bool open_page_preview_list_dlg(HWND hWndParent, string& strPages, LPCSTR lpcszStartPEpath, DWORD dwCtrl, int nPageType)
bool open_page_preview_list_dlg(HWND hWndParent, string& strPages, LPCSTR lpcszStartPEpath, DWORD dwCtrl, int nPageType, LPCSTR lpcszFilterFuncName)
///end FILTER_GRAPH_FUNCTION_SUPPORT
//-------End CONTROL_BROWSE_PAGE_TYPE
//------End CLEAN_UP_CONTROL_BITS_INTO_DWORD_FOR_GRAPH_BROWSER
{		
	string strPath = "Originlab\\PagePreviewList.c";
//	FUNC_HWND_STR_BOOL_LPSTR_BOOL_LPSTR_BOOL pfn = Project.FindFunction("PagePreviewListGraph", strPath);
	//------Folger 07/18/07 CLEAN_UP_CONTROL_BITS_INTO_DWORD_FOR_GRAPH_BROWSER
	//FUNC_HWND_STR_BOOL_LPSTR_BOOL_BOOL pfn = Project.FindFunction("PagePreviewListGraph", strPath);
//	if(!pfn || !pfn(hWndParent, strPages, bMultiplePages, lpcszStartPEpath, bShowFolders, lpcszExcludePage, bEnableEmbed))
	//if(!pfn || !pfn(hWndParent, strPages, bMultiplePages, lpcszStartPEpath, bShowFolders, bEnableEmbed))
	//-------Folger 07/19/07 CONTROL_BROWSE_PAGE_TYPE
	//FUNC_HWND_STR_LPSTR_DWORD pfn = Project.FindFunction("PagePreviewListGraph", strPath);
	//if(!pfn || !pfn(hWndParent, strPages, lpcszStartPEpath, dwCtrl))
	FUNC_HWND_STR_LPSTR_DWORD_INT pfn = Project.FindFunction("PagePreviewListGraph", strPath);
	/// Iris 6/17/2009 QA80-13771 FILTER_GRAPH_FUNCTION_SUPPORT
	//if(!pfn || !pfn(hWndParent, strPages, lpcszStartPEpath, dwCtrl, nPageType))
	if(!pfn || !pfn(hWndParent, strPages, lpcszStartPEpath, dwCtrl, nPageType, lpcszFilterFuncName))
	///end FILTER_GRAPH_FUNCTION_SUPPORT
	//-------End CONTROL_BROWSE_PAGE_TYPE
	//------End CLEAN_UP_CONTROL_BITS_INTO_DWORD_FOR_GRAPH_BROWSER
		return false;	

	return true;
}
///End ADD_BOOL_ENABLE_EMBED_IN_PAGE_PREVIEW_LIST_DLG
///End COMMENT_STR_EXCLUDE_PAGE
///Jasmine 01/11/07 OPEN_REPORT_TREE_BROWSER
///Jasmine 01/18/07 ADD_REPORT_TREE_FILTER_STRING
typedef BOOL (*FUNC_STR_VECTOR_UINT_INT_STR_HWND) (string& strResults, vector<uint>& vuIDs, int nSelMode, LPCSTR lpcszFilter, HWND hParent);
bool open_report_tree_browser(string& strResults, vector<uint>& vuIDs, int nSelMode, LPCSTR lpcszFilter, HWND hWndParent)
{	
	FUNC_STR_VECTOR_UINT_INT_STR_HWND pfn = Project.FindFunction("ReportTreeBrowser");
	if(!pfn || !pfn(strResults, vuIDs, nSelMode, lpcszFilter, hWndParent))
		return false;	
	return true;
}
///End ADD_REPORT_TREE_FILTER_STRING
///End OPEN_REPORT_TREE_BROWSER
bool update_plot_type(DataPlot& dp, int nType)
{
	if(!dp)
		return false;
	
	GraphLayer gl;
	dp.GetParent(gl);
	if(!gl)
		return false;

	string str;
	str.Format("layer -i%d %s", nType, dp.GetDatasetName());
	return gl.LT_execute(str);
}

//create a new data range with range name "X", "Y", "Err" and so on according to col type
bool	convert_result_curve_range_to_one_plotted_range(const DataRange& dr, DataRange& drSubRange, int nPlotType, int index, int* pDelCol)
{
	//--- Iris 3/16/2009 QA80-13285-P1 FIX_DUPLICATE_RESIDUAL_DATA_REPORT_FOR_DIFF_RESIDUAL_REPORT_AND_PLOT
	XYRange xy(dr);
	if(xy && xy.GetNumRanges() > 0) // if alreay one xy range then no need convert
	{
		drSubRange = dr;
		return true; 		
	}
	//---FIX_DUPLICATE_RESIDUAL_DATA_REPORT_FOR_DIFF_RESIDUAL_REPORT_AND_PLOT
	
	int c1, c2, r1, r2;
	Worksheet wksTemp;
	dr.GetRange(index, r1, c1, r2, c2, wksTemp);
	
	///Cheney 2007-4-13 FIX_BUG_OF_CUSTOM_TABLE_DISAPPEAR_WHEN_CONCATENATE
	if(pDelCol)
	{
		if(*pDelCol >= c2 - c1)
			return false;
		
		c1 += *pDelCol;
	}
	///end FIX_BUG_OF_CUSTOM_TABLE_DISAPPEAR_WHEN_CONCATENATE

	///-----Arvin 11/10/06 RESIDUALS_HISTOGRAM_PLOT 
	//Histogram plot only need one column data 
	//AddPlot only support "X" range when data range only has one column data.
	if((nPlotType == IDM_PLOT_HISTOGRAM_TYPE || nPlotType == IDM_PLOT_BOX) && c1 >= 0 && c1 == c2)
	{
		drSubRange.Add(wksTemp, c1, "X");
	}
	else
	{
	///-----
		for( int nCol = c1; nCol <= c2; nCol++ )
		{
			Column col(wksTemp, nCol);
			if( col )
			{
				string strRange;
				switch( col.GetType() )
				{
				case OKDATAOBJ_DESIGNATION_X:
					strRange = "X";
					break;
					
				case OKDATAOBJ_DESIGNATION_Y:				
					strRange = "Y";
					break;
					
				case OKDATAOBJ_DESIGNATION_ERROR:				
					strRange = "ED";				
					break;
					
				case OKDATAOBJ_DESIGNATION_Z:
					strRange = "Z";
					break;
					
				default:
					break;
				}
			
				if( !strRange.IsEmpty() )
				{
					if("X" == strRange && drSubRange.IsValid())
						drSubRange.Add(); //add separator
					
					drSubRange.Add(wksTemp, nCol, strRange);
				}
			}
		}
	///-----Arvin 11/10/06 RESIDUALS_HISTOGRAM_PLOT
	}
	///----end RESIDUALS_HISTOGRAM_PLOT 
	return true;
}

/// Iris 9/12/06 SURFACE_FIT_REPORT_MAT_FIT_DATA
///Cheney 2007-4-13 FIX_BUG_OF_CUSTOM_TABLE_DISAPPEAR_WHEN_CONCATENATE
//static int _plot_wks_data_range(DataRange& dr, GraphLayer& gl, int nPlotType, uint nCntrl)
/// Iris 08/06/2007 v8.0674 NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_GRAPH
//static int _plot_wks_data_range(DataRange& dr, GraphLayer& gl, int nPlotType, uint nCntrl, int* pDelCol)
///Arvin 08/15/07 QA70-10212-P3 ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
//static int _plot_wks_data_range(DataRange& dr, GraphLayer& gl, int nPlotType, uint nCntrl, int* pDelCol, bool bCheckIfPlot, DWORD *pdwDataRules)
static int _plot_wks_data_range(DataRange& dr, GraphLayer& gl, int nPlotType, uint nCntrl, int* pDelCol, bool bCheckIfPlot, DWORD *pdwDataRules, int* pStartPlotIndex)
///end ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
///end NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_GRAPH
///end FIX_BUG_OF_CUSTOM_TABLE_DISAPPEAR_WHEN_CONCATENATE
{
	int nStartPlot = -1;
	if(!gl || !dr)
		return nStartPlot;	
	
	for(int nRange=0; nRange < dr.GetNumRanges(); nRange++)
	{
		DataRange       drSubRange;
		/// Iris 7/10/2008 v8.0899 QA80-11831 MR_PARTIAL_LEVERAGE_PLOTS_ONE_RESULT_CURVE_RANGE_NEED_TWO_DIFF_PLOTTYPE
		/*
		int c1, c2, r1, r2;
		Worksheet wksTemp;
		dr.GetRange(nRange, r1, c1, r2, c2, wksTemp);
		
		///Cheney 2007-4-13 FIX_BUG_OF_CUSTOM_TABLE_DISAPPEAR_WHEN_CONCATENATE
		if(pDelCol)
		{
			if(*pDelCol >= c2 - c1)
				return -1;
			
			c1 += *pDelCol;
		}
		///end FIX_BUG_OF_CUSTOM_TABLE_DISAPPEAR_WHEN_CONCATENATE
	
		///-----Arvin 11/10/06 RESIDUALS_HISTOGRAM_PLOT 
		//Histogram plot only need one column data 
		//AddPlot only support "X" range when data range only has one column data.
		if((nPlotType == IDM_PLOT_HISTOGRAM_TYPE || nPlotType == IDM_PLOT_BOX) && c1 >= 0 && c1 == c2)
		{
			drSubRange.Add(wksTemp, c1, "X");
		}
		else
		{
		///-----
			for( int nCol = c1; nCol <= c2; nCol++ )
			{
				Column col(wksTemp, nCol);
				if( col )
				{
					string strRange;
					switch( col.GetType() )
					{
					case OKDATAOBJ_DESIGNATION_X:
						strRange = "X";
						break;
						
					case OKDATAOBJ_DESIGNATION_Y:				
						strRange = "Y";
						break;
						
					case OKDATAOBJ_DESIGNATION_ERROR:				
						strRange = "ED";				
						break;
						
					case OKDATAOBJ_DESIGNATION_Z:
						strRange = "Z";
						break;
						
					default:
						break;
					}
				
					if( !strRange.IsEmpty() )
					{
						if("X" == strRange && drSubRange)
							drSubRange.Add(); //add separator
						
						drSubRange.Add(wksTemp, nCol, strRange);
					}
				}
			}
		///-----Arvin 11/10/06 RESIDUALS_HISTOGRAM_PLOT
		}
		///----end RESIDUALS_HISTOGRAM_PLOT 		
		*/
		if( !convert_result_curve_range_to_one_plotted_range(dr, drSubRange, nPlotType, nRange, pDelCol) )
			return nStartPlot;
		///end MR_PARTIAL_LEVERAGE_PLOTS_ONE_RESULT_CURVE_RANGE_NEED_TWO_DIFF_PLOTTYPE
		
		/// Iris 08/06/2007 v8.0674 NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_GRAPH
		//int nPlot = gl.AddPlot(drSubRange, nPlotType, nCntrl);
		int 		nPlot = -1;
		vector<int> vnPlotIndex;
		if(bCheckIfPlot)
		{		
			DWORD 	dwRules = NULL != pdwDataRules? *pdwDataRules : DRR_GET_DEPENDENT|DRR_NO_FACTORS;
			int 	nNumRanges = drSubRange.GetNumData(dwRules);
			vector<int>	vnNeededPlotIndex;///Arvin 08/15/07 QA70-10212-P3 ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
			for(int nRange = 0; nRange < nNumRanges; nRange++)
			{
				DataRange 	drOneRange;
				drSubRange.GetSubRange(drOneRange, dwRules, nRange);
				if(check_has_plotted_in_graph(drOneRange, gl, vnPlotIndex) > 0 && vnPlotIndex.GetSize() > 0)
				{
					/// Iris 08/13/2007 v8.0680 FIX_NEW_ADDED_PLOT_ARE_RED_AFTER_CHANGE_PARAM
					//if(nPlot < 0)
						//nPlot = vnPlotIndex[0];
					///end FIX_NEW_ADDED_PLOT_ARE_RED_AFTER_CHANGE_PARAM
					vnNeededPlotIndex.Append(vnPlotIndex);///Arvin 08/15/07 QA70-10212-P3 ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
					///Sophy 1/25/2010 QA80-14087-S4 CNORMALIZE_CHANGE_SROUCE_PLOT_COLOR_WHEN_RECALCULATE
					//I think when check plot exist, we should return the plot's index, other than just return -1, which means active plot
					if ( 0 == nRange )
						nPlot = vnPlotIndex[0];
					///end CNORMALIZE_CHANGE_SROUCE_PLOT_COLOR_WHEN_RECALCULATE
				}
				else
				{
					/// Hong 07/07/08 QA80-11811 FIX_PLOT_TYPE_FAIL_UPDATE_IN_PREVIEW_AND_FIT_RESULT_PLOT
					//int nNewPlot = gl.AddPlot(drOneRange, nPlotType, nCntrl);
					//vnNeededPlotIndex.Add(nNewPlot);///Arvin 08/15/07 QA70-10212-P3 ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
					const	int		nMaxAdditionalAddedPlots = 10;
					const	int		nInvalidPlotIndex = -1;
					vector<int>		vnAdditionalAddedPlots(nMaxAdditionalAddedPlots);
					vnAdditionalAddedPlots = nInvalidPlotIndex;
					int nNewPlot = gl.AddPlot(drOneRange, nPlotType, nCntrl, vnAdditionalAddedPlots, nMaxAdditionalAddedPlots);
					vnNeededPlotIndex.Add(nNewPlot);///Arvin 08/15/07 QA70-10212-P3 ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
					for ( int ii = 0 ; ii < vnAdditionalAddedPlots.GetSize(); ii++ )
					{
						if ( nInvalidPlotIndex == vnAdditionalAddedPlots[ii] )
							break;
						
						vnNeededPlotIndex.Add(vnAdditionalAddedPlots[ii]);
					}
					
				#ifdef	_DEBUG
					int				nNumAdditionalAddedPlot = 0;
					for ( int iDebug = 0; iDebug < vnAdditionalAddedPlots.GetSize(); iDebug++ )
					{
						if ( nInvalidPlotIndex != vnAdditionalAddedPlots[iDebug] )
							nNumAdditionalAddedPlot++;
					}
					ASSERT(nNumAdditionalAddedPlot < nMaxAdditionalAddedPlots - 1); // when assert fired, then we need to enlarge out buffer
				#endif	//_DEBUG
				
					/// end FIX_PLOT_TYPE_FAIL_UPDATE_IN_PREVIEW_AND_FIT_RESULT_PLOT 					
					if(nPlot < 0)
						nPlot = nNewPlot;
				}
			}
			///Arvin 08/15/07 QA70-10212-P3 ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
			int nTotalPlot = gl.DataPlots.Count();
			int nSize = vnNeededPlotIndex.GetSize();
			/// Iris 7/02/2008 FIX_ARVIN_INCORRECT_CODES
			//if(nSize > 1 && nSize < nTotalPlot)
			if( pStartPlotIndex && nSize > 1 && nSize < nTotalPlot )
			///end FIX_ARVIN_INCORRECT_CODES	
			{
				int nStartPlotIndex = *pStartPlotIndex;
				vnNeededPlotIndex.Sort();
				bool bRemovedPlot = false;
				for(int iPlot = vnNeededPlotIndex[nSize-1]-1; iPlot > vnNeededPlotIndex[0]; iPlot--)
				{
					vector<uint> vInd;
					vnNeededPlotIndex.Find(vInd, iPlot, iPlot);
					if(vInd.GetSize() <= 0)
					{
						gl.RemovePlot(iPlot);
						bRemovedPlot = true;
						if(pStartPlotIndex && nStartPlotIndex >= iPlot)
							nStartPlotIndex--;
						
						if(nPlot >= iPlot)
							nPlot--;
					}				
				}
				*pStartPlotIndex = nStartPlotIndex;
				if(bRemovedPlot)
					legend_check_remove_invalid_plot(gl.GraphObjects(GO_LEGEND_NAME));
			}
			///end ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
		}
		else
		{
			nPlot = gl.AddPlot(drSubRange, nPlotType, nCntrl);
		}
		///end NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_GRAPH
		
		if(0 == nRange)
			nStartPlot = nPlot;
	}
	
	return nStartPlot;
}
///Arvin 08/28/07 QA70-10073-P2 KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
//static int _plot_mat_data_range(DataRange& dr, GraphLayer& gl, int nPlotType)
static int _plot_mat_data_range(DataRange& dr, GraphLayer& gl, int nPlotType, bool bCheckIfPlot)
///end KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
{
	if(!gl || !dr)
		return -1;
	
	int nStartPlot = -1;
	int nPlot = -1;	///Arvin 08/28/07 QA70-10073-P2 KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
	for(int nRange=0; nRange < dr.GetNumRanges(); nRange++)
	{
		int c1, c2, r1, r2;
		MatrixLayer mlTemp;
		//---- Iris 9/1/2008 
		//dr.GetRange(nRange, r1, c1, r2, c2, mlTemp);
		if( !dr.GetRange(nRange, r1, c1, r2, c2, mlTemp) || !mlTemp.IsValid() )
			return nPlot;
		//----
		
		if(c2 < 0)
			c2 = c1;
		
		for( int nMatrixObject = c1; nMatrixObject <= c2; nMatrixObject++ )
		{
			///Arvin 08/28/07 QA70-10073-P2 KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
			//MatrixObject mo = mlTemp.MatrixObjects(nMatrixObject);
			//int nPlot = gl.AddPlot(mo, nPlotType);
			if(bCheckIfPlot)
			{
				string strRange;
				string strPage = mlTemp.GetPage().GetName();
				string strSheet = mlTemp.GetName();
				strRange.Format("[%s]%s!%d", strPage, strSheet, nMatrixObject+1);
				DataRange drOneMatrixRange;
				drOneMatrixRange.Create(strRange, XVT_MATRIX);
				vector<int> vnPlotIndices;
				if(check_has_plotted_in_graph(drOneMatrixRange, gl, vnPlotIndices) <= 0)
				{
					MatrixObject mo = mlTemp.MatrixObjects(nMatrixObject);
					nPlot = gl.AddPlot(mo, nPlotType);
				}
			}
			else
			{
				MatrixObject mo = mlTemp.MatrixObjects(nMatrixObject);
				nPlot = gl.AddPlot(mo, nPlotType);
			}
			///end KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
			
			if(0 == nRange)
				nStartPlot = nPlot;
		}		
	}
	return nStartPlot;
	
}

//return the plot index of first plot
///Cheney 2007-4-13 FIX_BUG_OF_CUSTOM_TABLE_DISAPPEAR_WHEN_CONCATENATE
//int	plot_data_range(DataRange& dr, GraphLayer& gl, int nPlotType, uint nCntrl)
/// Iris 08/06/2007 v8.0674 NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_GRAPH
//int	plot_data_range(DataRange& dr, GraphLayer& gl, int nPlotType, uint nCntrl, int* pDelCol)
///Arvin 08/15/07 QA70-10212-P3 ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
//int	plot_data_range(DataRange& dr, GraphLayer& gl, int nPlotType, uint nCntrl, int* pDelCol, bool bCheckIfPlot, DWORD *pdwDataRules)
int	plot_data_range(DataRange& dr, GraphLayer& gl, int nPlotType, uint nCntrl, int* pDelCol, bool bCheckIfPlot, DWORD *pdwDataRules, int* pStartPlotIndex)
///end ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
///end NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_GRAPH
///end FIX_BUG_OF_CUSTOM_TABLE_DISAPPEAR_WHEN_CONCATENATE
{
	int c1, c2, r1, r2;
	Datasheet dsTemp;
	dr.GetRange(0, r1, c1, r2, c2, dsTemp);
		
	int 	nType = dsTemp.GetPage().GetType();	
	switch(nType)
	{
	case EXIST_WKS:
		///Cheney 2007-4-13 FIX_BUG_OF_CUSTOM_TABLE_DISAPPEAR_WHEN_CONCATENATE
		//return _plot_wks_data_range(dr, gl, nPlotType, nCntrl);
		/// Iris 08/06/2007 v8.0674 NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_GRAPH
		//return _plot_wks_data_range(dr, gl, nPlotType, nCntrl, pDelCol);
		///Arvin 08/15/07 QA70-10212-P3 ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
		//return _plot_wks_data_range(dr, gl, nPlotType, nCntrl, pDelCol, bCheckIfPlot, pdwDataRules);
		return _plot_wks_data_range(dr, gl, nPlotType, nCntrl, pDelCol, bCheckIfPlot, pdwDataRules, pStartPlotIndex);
		///end ADD_NEW_PLOT_FOR_COLUMN_TYPE_CHANGED_AND_REMOVE_REDUNDANT_PLOTS
		///end NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_GRAPH
		///end FIX_BUG_OF_CUSTOM_TABLE_DISAPPEAR_WHEN_CONCATENATE
		break;
	case EXIST_MATRIX:
		/// Iris 08/06/2007 v8.0674 NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_GRAPH
		///Arvin 08/28/07 QA70-10073 KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
		//return _plot_mat_data_range(dr, gl, nPlotType);	
		return _plot_mat_data_range(dr, gl, nPlotType, bCheckIfPlot);
		///end KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
		///end NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_GRAPH
		break;
	default:
		return -1;
		break;
	}
	
	return -1;
}
///end SURFACE_FIT_REPORT_MAT_FIT_DATA
int plot_wks_one_xy_from_data_range(DataRange& dr, GraphLayer& gl, int nPlotType, int nXIndex, int nYIndex, bool bCheckIfHasPlot)
{
	int 	nNumRange = dr.GetNumRanges();
	if(nNumRange <= 0)
		return -1;
	
	int 	c1, c2, r1, r2;
	Worksheet wks;
	
	if(1 == nNumRange)
		dr.GetRange(0, r1, c1, r2, c2, wks);
	else
	{
		for(int nRange=0; nRange<nNumRange; nRange++)
		{
			int 		c1Temp, c2Temp;
			Worksheet 	wksTemp;
			dr.GetRange(nRange, r1, c1Temp, r2, c2Temp, wksTemp);
			if(c1Temp < c1 && c1Temp>= 0)
				c1 = c1Temp;
			if(c2Temp > c2 && c2Temp>= 0)
				c2 = c2Temp;
			if(wksTemp)
				wks = wksTemp;
		}		
	}
	
	int nNumCols = c2 - c1 + 1;
	if(nXIndex >= nNumCols || nYIndex >= nNumCols)
		return -1;
	
	int nNunXCol = 0, nNumYCol = 0;
	int nXCol = -1, nYCol = -1;
	for(int ncol=c1; ncol<=c2; ncol++)
	{
		Column col(wks, ncol);
		
		if(OKDATAOBJ_DESIGNATION_X == col.GetType())
			nNunXCol++;
		if(nXIndex == nNunXCol - 1 && nXCol < 0)
			nXCol = ncol;	
		
		if(OKDATAOBJ_DESIGNATION_Y == col.GetType())
			nNumYCol++;			
		if(nYIndex == nNumYCol - 1 && nYCol < 0)
			nYCol = ncol;		
	}
	
	if( nXCol < 0 || nYCol < 0)
		return -1;
	
	/// Iris 08/07/2007 v8.0674 NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_AND_SOURCE_GRAPH
	//Curve cv(wks, nXCol, nYCol);
	//return gl.AddPlot(cv, nPlotType);
	DataRange drOneXY;
	drOneXY.Add(wks, nXCol, "X");
	drOneXY.Add(wks, nYCol, "Y");
	
	vector<int> vnPlotIndex;
	if(bCheckIfHasPlot && check_has_plotted_in_graph(drOneXY, gl, vnPlotIndex) > 0 && vnPlotIndex.GetSize() > 0)
		return vnPlotIndex[0];
	else
		return gl.AddPlot(drOneXY, nPlotType);
	///end NOT_PLOT_AGAIN_IF_PLOTTED_FOR_REPORT_AND_SOURCE_GRAPH

}

//---- CPY 9/21/06 SPARKLINE_IN_WKS_SUPPORT
bool add_end_points(DataPlot& dp, int nColorFirst, int nColorLast, int nSize)// = SYSCOLOR_BLUE = SYSCOLOR_RED = 12; //CPY 11/5/06
{
	if(!dp)
		return false;
	
	Tree tr;
	tr.Root.Points.Point1.Index.nVal= -2; // 1st pt
	tr.Root.Points.Point1.Symbol.Size.dVal=nSize;        // pts
	tr.Root.Points.Point1.Symbol.Type.nVal=0;        // geometric
	tr.Root.Points.Point1.Symbol.Shape.nVal=1;        // square
	tr.Root.Points.Point1.Symbol.Interior.nVal=0;    // solid
	tr.Root.Points.Point1.Symbol.EdgeColor.nVal=nColorFirst;

	tr.Root.Points.Point2.Index.nVal=-1; // last pt
	tr.Root.Points.Point2.Symbol.Size.dVal=nSize;        // pts
	tr.Root.Points.Point2.Symbol.Type.nVal=0;        // geometric
	tr.Root.Points.Point2.Symbol.Shape.nVal=1;        // square
	tr.Root.Points.Point2.Symbol.Interior.nVal=0;    // solid
	tr.Root.Points.Point2.Symbol.EdgeColor.nVal=nColorLast;

	int iRet = dp.UpdateThemeIDs(tr.Root);
	dp.ApplyFormat(tr, true, true);
	return true;
}

DataPlot plot_col(Worksheet& wks, int nCol, GraphPage& gp, int nPlotType, bool bRescaleNoRoundAxis, LPCSTR lpcszTemplate, bool bCreateAsHidden, bool bUseX)
{
	DataPlot dp;
	string strTemplate = lpcszTemplate;
	if(NULL == lpcszTemplate)
		strTemplate = "sparkline_label";	
	/// Kenny 08/25/2009 QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
	//gp.Create(strTemplate, bCreateAsHidden?CREATE_HIDDEN : CREATE_VISIBLE);
	gp.Create(strTemplate, (bCreateAsHidden?CREATE_HIDDEN : CREATE_VISIBLE) | CREATE_ENUM_EXIST_PAGE );
	/// End QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
	gp.Rename("sparkline"); // Hong 02/12/07 ADD_INFO_TO_INDICATE_SPARKLINE
	GraphLayer gl = gp.Layers();
	if(!gl)
	{
		out_str("failed to load graph");
		return dp;
	}
	DataRange dr;
	dr.Add(wks, nCol, "Y");
	int nPlot = gl.AddPlot(dr, nPlotType, bUseX?GAP_USE_X_FROM_SY : 0);
	gl.Rescale(bRescaleNoRoundAxis? ANL_NO_ROUNDING : 0);
	dp = gl.DataPlots(nPlot);
	return dp;
}
//----

///Arvin 9/25/06 CHECK_HAS_IMAGE
bool has_image(const MatrixLayer& ml)
{
	if(!ml)
		return false;
	
	foreach(MatrixObject mo in ml.MatrixObjects)
	{
		///Sandy 2006-9-27 CHECK_WITH_MATRIXOBJECT_HAS_DATA
		//LPVOID pLBmp = mo.GetLeadBitmap(); 
		//if( pLBmp )
			//return true;
		if(!mo.HasData(false))
			return true;
		//end CHECK_WITH_MATRIXOBJECT_HAS_DATA
	}
	
	return false;
}
///end CHECK_HAS_IMAGE

//--------------------------------------- CPY 10/10/06 QA70-9039 XF_WIZARD_BAR
//typedef int (*FUNC_STR_INT)(string strXF, int nMode); ///---Sim 05-25-2007 IMPROVE_GET_AND_SET_XF_BAR_NAME remove

///---Sim 05-21-2007 SET_XF_BAR_NAME_ONLY_WITHOUT_SHOW_DIALOG
//bool show_xf_bar(Page& pg, int nShow, LPCSTR lpcszXFname)
bool show_xf_bar(Page& pg, int nShow, LPCSTR lpcszXFname, bool bSetNameOnly)// = NULL, false
///---END SET_XF_BAR_NAME_ONLY_WITHOUT_SHOW_DIALOG
{
	if(SXFB_CLOSE == nShow)
	{
		OptionalMessage(STR_REMINDER_REOPEN_XFBAR, MB_OK); ///---Sim 10-27-2008 v8.961 QA80-12463-P1-P2 SHOW_REOPEN_REMINDER_MESSAGE_ONLY_WHEN_USER_FORCELY_CLOSE_IT
		pg.SetSplitters(NULL);
	}
	else
	{
		bool bOK = false;
		///Joseph  10/12/06 STRING_EMPTY_CORRECT_WHEN_MODE_CHOOSE
		//It should show the xf_bar when the string is empty, but the SXFB_CHOOSER == nShow.
		if(lpcszXFname || SXFB_OPEN_CHOOSER == nShow)
		//if(lpcszXFname)
		///End STRING_EMPTY_CORRECT_WHEN_MODE_CHOOSE
		{
			pg.SetSplitters(NULL); // better close it first if XF is specified
			///---Sim 05-25-2007 IMPROVE_GET_AND_SET_XF_BAR_NAME
			/*
			Function fn = Project.FindFunction("XFBarSet", "OriginLab\\PageXFBar");
			FUNC_STR_INT pfn = fn;
			if(pfn)
			{
				string strXFname = lpcszXFname;
				if(pfn(strXFname, nShow)< 0)
					return error_report("set XFBar xf failed");
				else
					bOK = true;
			}
			*/
			bOK = set_page_xf_bar(pg, lpcszXFname, nShow);
			///---END IMPROVE_GET_AND_SET_XF_BAR_NAME
		}
		///---Sim 05-21-2007 IT_SEEMS_MAKE_NO_SENSE
		/*
		else
			bOK = true;
		*/
		///---END IT_SEEMS_MAKE_NO_SENSE
		
		if(!bOK)
			return error_report("set XFBar failed");

		///---Sim 05-21-2007 SET_XF_BAR_NAME_ONLY_WITHOUT_SHOW_DIALOG
		if ( !bSetNameOnly )
		{
			///Joseph 04/13/07 QA70-9507 XFBAR_WIDTH_SHOULD_USE_PERCENT
			/*
			///Joseph 03/19/07 XFBAR_WIDTH_IS_NOT_ENOUGH
			//string	strConfig = "c[" + STR_XF_BAR + "]{210}c";
			string	strConfig = "c[" + STR_XF_BAR + "]{340}c";
			///End XFBAR_WIDTH_IS_NOT_ENOUGH
			*/
			string	strConfig = "c[" + STR_XF_BAR + "]{30%}c";
			///End XFBAR_WIDTH_SHOULD_USE_PERCENT
			pg.SetSplitters(strConfig);
		}
		///---END SET_XF_BAR_NAME_ONLY_WITHOUT_SHOW_DIALOG
			
	}
	return true;
}
//--------------------------------------- end XF_WIZARD_BAR

///Kyle 08/29/08 ADD_UTIL_FUNCTION_FOR_XF_BEFORE_EXECUTE
///Kyle 12/10/2008 ADD_SKIP_AUTO_UPDATE_OPTION_TO_FUNCTION_IS_XF_STARTUP
//bool is_xf_startup(int nGetNDialog, int dwCntrl)
bool is_xf_startup(int nGetNDialog, int dwCntrl, bool bSkipAutoUpdate) // = false
///End ADD_SKIP_AUTO_UPDATE_OPTION_TO_FUNCTION_IS_XF_STARTUP
{
	///Kyle 12/10/2008 ADD_SKIP_AUTO_UPDATE_OPTION_TO_FUNCTION_IS_XF_STARTUP
	if(bSkipAutoUpdate && (dwCntrl & (LTXF_FROM_AUTO_UPDATE | LTXF_CHANGE_PARAM)) )		// from Auto Update or Change Param
		return false;
	///End ADD_SKIP_AUTO_UPDATE_OPTION_TO_FUNCTION_IS_XF_STARTUP
	return nGetNDialog > 0 || nGetNDialog == 0 && !(dwCntrl & LTXF_SHOW_DIALOG);
}
///End ADD_UTIL_FUNCTION_FOR_XF_BEFORE_EXECUTE

///------ Folger 10/29/2010 ORG-1311-S2 COLMOVE_SUPPORT_MOVE_COLUMNS_TO_SPECIFIED_INDEX
bool is_xf_really_before_execute(int nGetNDialog, int dwCntrl)
{
	return (0 == nGetNDialog || -1 == nGetNDialog) && O_QUERY_BOOL(dwCntrl, LTXF_EXECUTE);
}
///------ End COLMOVE_SUPPORT_MOVE_COLUMNS_TO_SPECIFIED_INDEX

//--- CPY 9/25/06, taken from ColumnList.h
//return name of col.
//return short name if bLongname = false, and long name if true.
//When bLongname = true, if col has no long name,
//return short name if bUseSName = true, else return an empty string.
string get_column_name(const Column& col, bool bLongname, bool bUseSName) // = true = true
{
	if(!col.IsValid())
		return "";
	
	string strName;
	if(bLongname)
	{
		strName = col.GetLongName();
		if(!strName.IsEmpty() || !bUseSName)
			return strName;
	}
	col.GetName(strName);
	return strName;
}
//----

/// Iris 9/26/09 SUPPORT_PREVIEW_FOR_MULT_DEPS_MULTI_INDEPS
///Cheney 2007-4-30 ADD_TEMLATE_FOR_PREVIEW_WHEN_MULTI_LAYER	
//int plot_combinated_xy(Worksheet& wks, GraphPage& gp, int nPlotID, int nColor, bool bRescale, bool bArrange, int nColFrom, int nColTo)
int plot_combinated_xy(Worksheet& wks, GraphPage& gp, int nPlotID, int nColor, bool bRescale, bool bArrange, LPCSTR lpcszTemplate, int nColFrom, int nColTo)
///end ADD_TEMLATE_FOR_PREVIEW_WHEN_MULTI_LAYER
{
	int nNumPlots = 0;
	
	if(!wks || !gp)
		return nNumPlots;
	
	if(nColTo < 0)
		nColTo = wks.GetNumCols() - 1; //the last one
	if(nColFrom > nColTo)
		return nNumPlots;
	
	///Cheney 2006-10-24 FIX_BUG_OF_MULTI_INDEP_AND_DEP_WHEN_PREVIEW, multidataset,
	//wks will be xx..xyy..yyxx..xyy..yyxx..xyy..yy.....
	//so find begin and end of x and begin and end of y of 1st dataset, then loop
	//int nStartPlot = gl.DataPlots.Count();
	//vector<uint> vnXs, vnYs; //the column index array for X and Y columns
	//for(int ncol = nColFrom; ncol <= nColTo; ncol++)
	//{
		//Column 	col(wks, ncol);
		//if( col )
		//{
			//int nType = col.GetType(); 
			//if( OKDATAOBJ_DESIGNATION_X == nType)
			//{
				//vnXs.Add(ncol);
			//}
			//if( OKDATAOBJ_DESIGNATION_Y == nType )
			//{
				//vnYs.Add(ncol);
			//}
		//}
	//}
	//
	//for(int nx=0; nx < vnXs.GetSize(); nx++)
	//{
		//for(int ny=0; ny < vnYs.GetSize(); ny++)
		//{
			//GraphLayer gl = gp.Layers(nNumPlots);
			//if(!gl)
			//{
				//int nn = gp.AddLayer();
				//gl = gp.Layers(nn);
			//}
			//
			//Curve 	cv(wks, vnXs[nx], vnYs[ny]);			
			//uint 	dwCntrl = GAP_USE_TEMPLATE | GAP_ALLOW_DUPLICATE_COL;
			//int nPlot = gl.AddPlot(cv, nPlotID, dwCntrl);
			//if(nPlot >= 0)
			//{
				//DataPlot dp = gl.DataPlots(nPlot);
				//dp.SetColor(nColor);
			//}
			//
			//if( bRescale )
				//gl.Rescale();
			//
			//nNumPlots++;
		//}
	//}
	int nXBegin = nColFrom, nXEnd = nColFrom - 1, nYBegin, nYEnd;
	int nFormerColType;
	for(int ncol = nColFrom; ncol <= nColTo; ncol++)
	{			
		Column 	col(wks, ncol);
		if( col )
		{
			int nType = col.GetType();
			
			if(ncol == 0)
				nFormerColType = nType;
			
			if(nType != nFormerColType)
			{
				if(nFormerColType == OKDATAOBJ_DESIGNATION_Y)
					break;
				else
				{
					nYBegin = nXEnd + 1;
					nYEnd = nYBegin - 1;
					nFormerColType = nType;
				}	
			}
				
			if( OKDATAOBJ_DESIGNATION_X == nType)
				nXEnd++;
			
			if( OKDATAOBJ_DESIGNATION_Y == nType )
				nYEnd++;
		}
	}
	
	int nDatasetCols = nYEnd + 1 - nXBegin;
	int nDataSets = (nColTo - nColFrom + 1) / nDatasetCols;
	
	for(int ii=0; ii < nDataSets; ii++)
	{
		int nXBeginTemp = ii*nDatasetCols + nXBegin;
		int nXEndTemp 	= ii*nDatasetCols + nXEnd;
		int nYBeginTemp = ii*nDatasetCols + nYBegin;
		int nYEndTemp 	= ii*nDatasetCols + nYEnd;
		
		for(int ny = nYBeginTemp; ny <= nYEndTemp; ny++)
		{
			for(int nx = nXBeginTemp; nx <= nXEndTemp; nx++)
			{
				GraphLayer gl = gp.Layers(nNumPlots);
				if(!gl)
				{
					///Cheney 2007-4-30 ADD_TEMLATE_FOR_PREVIEW_WHEN_MULTI_LAYER
					//int nn = gp.AddLayer();
					int nn = gp.AddLayer(NULL, GAP_USE_TEMPLATE, lpcszTemplate);
					///end ADD_TEMLATE_FOR_PREVIEW_WHEN_MULTI_LAYER
					gl = gp.Layers(nn);
				}
				
				DataRange drTemp;
				drTemp.Add(wks, nx, "X");
				drTemp.Add(wks, ny, "Y");			
				///Sophy 10/24/2008 SUPPORT_MUILTI_INDEP_AND_DEP_PREVIEW_FOR_NLFIT_81
				//uint 	dwCntrl = GAP_USE_TEMPLATE | GAP_ALLOW_DUPLICATE_COL;
				uint 	dwCntrl = GAP_USE_TEMPLATE; //if allow duplicate plot, update preview graph will add redundant plots
				///end SUPPORT_MUILTI_INDEP_AND_DEP_PREVIEW_FOR_NLFIT_81
				int nPlot = gl.AddPlot(drTemp, nPlotID, dwCntrl);
				if(nPlot >= 0)
				{
					DataPlot dp = gl.DataPlots(nPlot);
					dp.SetColor(nColor);
				}
				
				if( bRescale )
					gl.Rescale();
				
				nNumPlots++;
			}
		}
	}
	///end FIX_BUG_OF_MULTI_INDEP_AND_DEP_WHEN_PREVIEW	
	
	
	if(bArrange)
	{
		///Jasmine 10/09/06 SET_STFORMAT_DEFAULT
		/*
		stLayersGridFormat stFormat;
		stFormat.nXGap = 5;		
		stFormat.nYGap = 5;			
		stFormat.nLeftMg = 15;			
		stFormat.nRightMg = 15;			
		stFormat.nTopMg = 15;			
		stFormat.nBottomMg = 15;
		page_arrange_layers(gp, vnYs.GetSize(), vnXs.GetSize(), stFormat);
		*/
		///Cheney 2006-10-24 FIX_BUG_OF_MULTI_INDEP_AND_DEP_WHEN_PREVIEW
		//page_arrange_layers(gp, vnYs.GetSize(), vnXs.GetSize());		
		page_arrange_layers(gp, nDataSets*(nYEnd-nYBegin+1), nXEnd-nXBegin+1);
		///end FIX_BUG_OF_MULTI_INDEP_AND_DEP_WHEN_PREVIEW
		///End SET_STFORMAT_DEFAULT
	}
	return nNumPlots;
		
}
///end SUPPORT_PREVIEW_FOR_MULT_DEPS_MULTI_INDEPS



///justin 11/17/2006 RESET_GRAPHLAYER
/*  temp solution, should be repalced by GraphLayer::Reset() 
*/
bool graphlayer_reset(GraphLayer& gl)
{
	if(gl.IsValid())
	{
		for(int ii = gl.DataPlots.Count(); ii > 0; ii--)
		{
			gl.RemovePlot(0);
		}
		return true;
	}
	return false;
}
//end RESET_GRAPHLAYER
///Jasmine 01/08/07 MODIFICATION_GET_SET_USER_INFO
///Jasmine 12/07/06 GET_SET_USER_INFO	
#define STR_USER_INFO	"TREE"	///Jasmine 01/15/07 CHANGE_USER_INFO_TO_TREE, "user_info"->"tree"
//bool get_user_info(OriginObject& obj, TreeNode& trUserInfo, bool bCreate)// = true
bool get_user_info(OriginObject& obj, LPCSTR lpcszName, TreeNode& trUserInfo)
{
	if(!obj.IsValid())
		return error_report("obj is invalid");
	vector<string> vsNames;
	if(!obj.GetStorageNames(vsNames) || 0 > vsNames.Find(STR_USER_INFO))
	//{
		//if(!bCreate)
			//return false;
		//Tree trNew;
		//trNew.SetAttribute(STR_LABEL_ATTRIB, STR_USER_INFO);
		//bool bRet = obj.PutBinaryStorage(STR_USER_INFO, trNew);
	//}
		return false;
	Tree tr;
	obj.GetBinaryStorage(STR_USER_INFO, tr);
	//trUserInfo.Replace(tr, true, true);
	if(lpcszName)
	{
		TreeNode trTemp;
		trTemp =  tree_get_node_by_tagname(tr, lpcszName, true);
		return trUserInfo.Replace(trTemp, true, true);
	}
	return false;
}
//bool set_user_info(OriginObject& obj, TreeNode& trUserInfo)
bool set_user_info(OriginObject& obj, string& strName, const TreeNode& trUserInfo)
{
	string strTagname = cvt_str_to_tag_name(strName);
	if(strTagname.IsEmpty())
		return error_report("strName is invalid");		
	if(!obj.IsValid())
		return error_report("obj is invalid");	
	//return obj.PutBinaryStorage(STR_USER_INFO, trUserInfo);vector<string> vsNames;
	Tree tr;
	vector<string> vsNames;
	if(obj.GetStorageNames(vsNames) && vsNames.Find(STR_USER_INFO) > -1)
		obj.GetBinaryStorage(STR_USER_INFO, tr);
	strName = strTagname;
	TreeNode trName =  tree_get_node_by_tagname(tr, strName, true);
	if(!trName.IsValid())
		trName = tr.AddNode(strName);
	trName.Replace(trUserInfo, TRUE, TRUE);
	return obj.PutBinaryStorage(STR_USER_INFO, tr);
}
///End MODIFICATION_GET_SET_USER_INFO
//---------- CPY 12/18/06 COL_VARS_USING_EXTENDED_LABELS
///Jasmine 01/19/07 ADD_OPTION_TO_ALLOW_EMPTY_PARAM_VALUE
/// Hong 05/17/10 ORG-131 MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
//int get_user_parameters(Column& col, vector<string>& vsNames, vector<string>& vsValues, bool bGetEmpty)//=false
int get_user_parameters(DataObject& obj, vector<string>& vsNames, vector<string>& vsValues, bool bGetEmpty)//=false
/// end MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
{
	/// Hong 05/17/10 ORG-131 MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
	/*
	Worksheet wks;
	col.GetParent(wks);
	if(!wks)
		return -1;
	Grid grid;   
	if( !grid.Attach(wks) )
		return -2;
	*/
	Datasheet	ds;
	obj.GetParent(ds);
	if ( !ds )
		return -1;
	Grid 		grid;   
	if ( !grid.Attach(ds) )
		return -2;
	/// end MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
	vector<string> vsLabelNames;
	grid.GetUserDefinedLabelNames(vsLabelNames);
	int nSize = vsLabelNames.GetSize();
	vsNames.SetSize(0);
	vsValues.SetSize(0);
	if(nSize == 0)
		return 0;
	/// Hong 05/17/10 ORG-131 MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
	Column			col(obj);
	MatrixObject	mo(obj);
	ASSERT( col || mo );
	BOOL			bRet;
	/// end MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
	for(int ii = 0; ii < nSize; ii++)
	{
		string strTemp;
		/// /// Hong 05/17/10 ORG-131 MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
		//if((col.GetExtendedLabel(strTemp, RCLT_UDL + ii) && !strTemp.IsEmpty()) || bGetEmpty)///Jasmine 01/19/07 ADD_OPTION_TO_ALLOW_EMPTY_PARAM_VALUE
		if ( col )
			bRet = col.GetExtendedLabel(strTemp, RCLT_UDL + ii);
		else if ( mo )
			bRet = mo.GetExtendedLabel(strTemp, RCLT_UDL + ii);
		if ( bRet && !strTemp.IsEmpty() || bGetEmpty )
		/// end MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
		{
			vsNames.Add(vsLabelNames[ii]);
			vsValues.Add(strTemp);
		}
	}
	return vsValues.GetSize();
}
/// Hong 05/17/10 ORG-131 MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
//bool set_user_parameters(Column& col, const vector<string>& vsNames, const vector<string>& vsValues)
bool set_user_parameters(DataObject& obj, const vector<string>& vsNames, const vector<string>& vsValues, bool bShowLabel/* = true*/)
/// end MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
{
	/// Hong 05/17/10 ORG-131 MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
	/*
	Worksheet wks;
	col.GetParent(wks);
	if(!wks)
		return false;
	Grid grid;   
	if( !grid.Attach(wks) )
		return false;
	*/
	ASSERT( obj );
	Datasheet	ds;
	obj.GetParent(ds);
	if ( !ds )
		return false;
	Grid		grid;   
	if( !grid.Attach(ds) )
		return false;
	/// end MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
	vector<string> vsLabelNames;
	grid.GetUserDefinedLabelNames(vsLabelNames);
	int nAdded = 0;
	for(int ii = 0; ii < vsNames.GetSize(); ii++)
	{
		if(vsLabelNames.Find(vsNames[ii]) < 0) // not in list
		{
			nAdded++;
			vsLabelNames.Add(vsNames[ii]);
		}
	}
	if(nAdded > 0)
	{
		grid.SetUserDefinedLabelNames(vsLabelNames);
		/// Hong 08/08/08 v8.0918b FIX_HIDDEN_UDL_SHOWN_AFTER_ADD_NEW_ONE
		//for(int ii = 0; ii < vsLabelNames.GetSize(); ii++)
		//	grid.ShowLabels(RCLT_UDL+ii, TRUE);
		/// end FIX_HIDDEN_UDL_SHOWN_AFTER_ADD_NEW_ONE
	}
	// next we can put the values into col
	/// Hong 05/17/10 ORG-131 MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
	Column			col = obj;
	MatrixObject	mo = obj;
	ASSERT( col || mo );
	/// end MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
	for(ii = 0; ii < vsNames.GetSize(); ii++)
	{
		int nRow = vsLabelNames.Find(vsNames[ii]);
		/// Hong 05/17/10 ORG-131 MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
		//if(nRow < 0)
		//	return false; // this should never happen
		//col.SetExtendedLabel(vsValues[ii], RCLT_UDL + nRow);
		ASSERT( nRow >= 0 );
		if ( nRow > UDL_MAX_NUM )
			return false;
		if ( col )
			col.SetExtendedLabel(vsValues[ii], RCLT_UDL + nRow);
		else if ( mo )
			mo.SetExtendedLabel(vsValues[ii], RCLT_UDL + nRow);
		if ( bShowLabel )
		/// end MATRIX_ADD_GENERAL_LABEL_SUPPORT_AS_WKSHEET
			grid.ShowLabels(RCLT_UDL + nRow, TRUE); /// Hong 08/08/08 v8.0918b FIX_HIDDEN_UDL_SHOWN_AFTER_ADD_NEW_ONE
	}
	return true;
}
//---------- end COL_VARS_USING_EXTENDED_LABELS

///End GET_SET_USER_INFO

/// Hong 12/07/06 FIX_SPARK_LINE_DISAPPEAR
/// RVD 7/30/2008 qa70-11914 SAMPLE_INTERVAL_UNDO
//bool wks_add_show_labels(Worksheet& wks, const vector<int>& vnType, bool bReplace)
bool wks_add_show_labels(Worksheet& wks, const vector<int>& vnType, bool bReplace, bool bUndo)
/// end SAMPLE_INTERVAL_UNDO
{
	vector<int> vnOriType;
	if( !wks_get_show_labels(wks, vnOriType) )
		return false;
	
	if(bReplace)
	{
		vnOriType = vnType;
	}
	else
	{
		int nSize = vnType.GetSize();
		int nLastIndex = -1;
		for(int ii=0; ii < nSize; ii++)
		{
			int nVal = vnType[ii];
			/// Hong 01026/07 FIX_HAVE_DUPLICATE_SPARKLINE
			//int nIndex = find_in_list(nVal, vnOriType, true);
			int nIndex = -1;
			for(int ii = 0; ii < vnOriType.GetSize(); ii++)
			{
				if(vnOriType[ii] == nVal)
				{
					nIndex = ii;
					break;
				}
			}
			/// end FIX_HAVE_DUPLICATE_SPARKLINE
			if( nIndex >= 0)
			{
				///---Sim 03-15-2007 FIX_MOSTLY_ACCORDING_ORDER_OF_VECTOR_OF_LABEL
				if ( nIndex > nLastIndex )
					nLastIndex = nIndex;
				///---END FIX_MOSTLY_ACCORDING_ORDER_OF_VECTOR_OF_LABEL
			}
			else
			{
				///---Sim 03-15-2007 FIX_MOSTLY_ACCORDING_ORDER_OF_VECTOR_OF_LABEL
				if(-1 == nLastIndex )
				{
					//vnOriType.Add(nVal);
					nLastIndex = vnOriType.GetSize() - 1;
				}
				//else
				vnOriType.InsertAt(nLastIndex + 1, nVal);
				nLastIndex++;
				///---END FIX_MOSTLY_ACCORDING_ORDER_OF_VECTOR_OF_LABEL
			}
		}
	}
		
	Grid		grid;
	grid.Attach(wks);
	/// RVD 7/30/2008 qa70-11914 SAMPLE_INTERVAL_UNDO
	//if(grid.SetShowLabels(vnOriType, FALSE))
	if(grid.SetShowLabels(vnOriType, bUndo))
	/// end SAMPLE_INTERVAL_UNDO
	{
		wks.Invalidate();
		return true;
	}
	return false;
}
/// end FIX_SPARK_LINE_DISAPPEAR

//index: -1 means all pages
string get_page_short_name_from_page_list(LPCSTR lpcszPages, char chSep, int index)
{
	string 	strPage(lpcszPages);
	//int		num = strPage.GetNumTokens(STR_PAGE_LIST_SEPARATOR);
	///---Sim 07-13-2009 QA81-13923 FIX_EXP_GRAPH_FAILED_WHEN_LONG_NAME_CONTAIN_ONLY_ONE_DOUBLE_QUOTATION_MARK
#ifdef __FIX_EXP_GRAPH_FAILED_WHEN_LONG_NAME_CONTAIN_ONLY_ONE_DOUBLE_QUOTATION_MARK__
	StringArray vsPages;
	int		num = okutil_get_tokens(strPage, &vsPages, chSep, NULL);
#else
	///---END QA81-13923 FIX_EXP_GRAPH_FAILED_WHEN_LONG_NAME_CONTAIN_ONLY_ONE_DOUBLE_QUOTATION_MARK
	int		num = strPage.GetNumTokens(chSep); /// Hong 10/16/07 v8.0726 FIX_OTHER_SEPARATE_NOT_WORK
#endif ///---Sim 07-13-2009 QA81-13923 FIX_EXP_GRAPH_FAILED_WHEN_LONG_NAME_CONTAIN_ONLY_ONE_DOUBLE_QUOTATION_MARK
	
	vector<string> vsShortNames;
	for(int nn=0; nn<num; nn++)
	{
		//string 	str = strPage.GetToken(nn, STR_PAGE_LIST_SEPARATOR);
		///---Sim 07-13-2009 QA81-13923 FIX_EXP_GRAPH_FAILED_WHEN_LONG_NAME_CONTAIN_ONLY_ONE_DOUBLE_QUOTATION_MARK
#ifdef __FIX_EXP_GRAPH_FAILED_WHEN_LONG_NAME_CONTAIN_ONLY_ONE_DOUBLE_QUOTATION_MARK__
		string 	str = vsPages[nn];
#else
		///---END QA81-13923 FIX_EXP_GRAPH_FAILED_WHEN_LONG_NAME_CONTAIN_ONLY_ONE_DOUBLE_QUOTATION_MARK
		string 	str = strPage.GetToken(nn, chSep); /// Hong 10/16/07 v8.0726 FIX_OTHER_SEPARATE_NOT_WORK
#endif ///---Sim 07-13-2009 QA81-13923 FIX_EXP_GRAPH_FAILED_WHEN_LONG_NAME_CONTAIN_ONLY_ONE_DOUBLE_QUOTATION_MARK
		//------- CPY 10/11/07 QA70-10520 BAD_CODE_WITH_INFO_NOT_CENTRALIZED_LEAD_TO_FAILED_OK_ENABLED
		//str = str.GetToken(0, '-'); // cannot assume things and have basic logic/info in two places
		int nPosSLNSeparator = str.Find(STR_PAGE_SHORT_LONG_NAME_SEPARATOR);
		if(nPosSLNSeparator > 0)
		{
			/// Hong 02/04/08 QA80-10987 FIX_EXPWKS_FAIL_WITH_WITH_SPECIAL_SHEET_NAME
			// this code will fail when resolve worksheet range which sheet name contain key string STR_PAGE_SHORT_LONG_NAME_SEPARATOR
			// so i add check of quotation to skip this case, not sure if have another better way or utility function
			bool bInQuote = false;
			int nQuotePos = str.Find("\"");
			if ( nQuotePos > 0 && nQuotePos < nPosSLNSeparator )
			{
				nQuotePos = str.Find("\"", nQuotePos+1);
				if ( nQuotePos > nPosSLNSeparator )
				{
					bInQuote = true;
				}
			}
			if ( !bInQuote )
			/// end FIX_EXPWKS_FAIL_WITH_WITH_SPECIAL_SHEET_NAME
				str = str.Left(nPosSLNSeparator);
		}
		//-------
		str.TrimLeft();
		str.TrimRight();		
		
		if(index >= 0 && nn == index)
			return str;
		
		vsShortNames.Add(str);
	}
			
	//strPage.SetTokens(vsShortNames, STR_PAGE_LIST_SEPARATOR);
	strPage.SetTokens(vsShortNames, chSep); /// Hong 10/16/07 v8.0726 FIX_OTHER_SEPARATE_NOT_WORK
	return strPage;
}

/// Max 12/21/06 WORKSHEET_COPY
bool wks_copy(Worksheet& wksDesc, const Worksheet& wksSrc, int nOption, DWORD dwCtrl) // = CREATE_VISIBLE, DCTRL_COPY_DEFAULT
{
	if( !wksDesc.IsValid() || !wksSrc.IsValid() )
		return false;

	bool bRet;
	string strSrc, strDest;
	wksSrc.GetName(strSrc);
	wksDesc.GetName(strDest);

	///Sophy 7/30/2009 QA80-14050 CHECK_BOOK_AND_SHEET_NAME_ON_COMPARE_WORKSHEET_OBJS
	//if ( strSrc == strDest )
	//{
		//wksDesc = wksSrc;
		//return true;
	//}
	string strSrcPage = wksSrc.GetPage().GetName();
	string strDstPage = wksDesc.GetPage().GetName();
	if ( strSrcPage.CompareNoCase(strDstPage) == 0 && strSrc.CompareNoCase(strDest) == 0 )
		return true; //same worksheet, no need to do anything
	///end CHECK_BOOK_AND_SHEET_NAME_ON_COMPARE_WORKSHEET_OBJS
	else
	{
		//----- CPY 12/17/07 QA80-10805 WKS_CREATE_COPY_NOW_ALLOWS_DESTINATION
		//wksDesc.Destroy(); // if create new book
		if(wksDesc) 
			dwCtrl |= DCTRL_COPY_USE_EXIST_OKPTR | DCTRL_COPY_MAKE_ACTIVATE | DCTRL_COPY_KEEP_SHEET_NAME;
		//-----
		bRet = wksDesc.CreateCopy(wksSrc, nOption, dwCtrl);
		wksDesc.GetPage().SetShow();
		return bRet;
	}
}
/// END WORKSHEET_COPY

///---Sim 01-22-2006 SET_LABEL_VALUE
/// Hong 11/02/07 QA80-10622 IMPORT_EXCEL_SUPPORT_MULTILINES_COMMENTS
static void setLabelAndUpdateRowsList(Worksheet& wks, int nType, int nRowFrom, int nRowTo, vector<int>& vLabels, vector<int>& vRemovedRows)
{
	bool bLabelShow = wks.IsLabelTypeShown(nType);

	/// Hong 11/02/07 v8.0739 SHOW_NOT_HAVE_HIGH_LIGHT_FEATURE
	if ( nRowFrom < 0 )
		return ;
	/// end SHOW_NOT_HAVE_HIGH_LIGHT_FEATURE
	if ( nRowTo < nRowFrom )
		nRowTo = nRowFrom;
	
	bool bAppend;
	for ( int ii = nRowFrom; ii <= nRowTo; ii++ )
	{
		bAppend = (ii == nRowFrom) ? false : true;		
		if ( wks.SetAsLabel(nType, ii, FALSE, FALSE, bAppend) )
		{
			///---Sim 04-25-2007 QA80-9325-P7 FIX_MISS_DATA			
			if ( -1 == find_in_list(ii, vRemovedRows, false) ) // not exist in list
				vRemovedRows.Add(ii);
			///---END QA80-9325-P7 FIX_MISS_DATA
		}		
	}
	
	vLabels.Add(nType);
	if( !bLabelShow )
		wks.HideLabelByType(nType);
}
static void setLabelAndUpdateRowList(Worksheet& wks, int nType, int nRow, vector<int>& vLabels, vector<int>& vRemovedRows)
{
	setLabelAndUpdateRowsList(wks, nType, nRow, nRow, vLabels, vRemovedRows);
}
	
/// Hong 11/02/07 QA80-10622 IMPORT_EXCEL_SUPPORT_MULTILINES_COMMENTS
//bool setLabelValueFromRows(Worksheet& wks, int nShortName, int nLongName, int nUnit, int nComment, bool bRemoveRows, bool bShowLabel) // = -1, -1, -1, -1, true, true
//------ Folger 02/02/08 QA80-11046 REMOVE_MAIN_HEADER_LINE_IN_IMPORT_EXCEL
//bool setLabelValueFromRows(Worksheet& wks, int nShortName, int nLongName, int nUnit, int nCommentFrom, bool bRemoveRows, bool bShowLabel, int nCommentTo) // = -1, -1, -1, -1, true, true, -1
bool setLabelValueFromRows(Worksheet& wks, int nShortName, int nLongName, int nUnit, int nCommentFrom, bool bRemoveRows, bool bShowLabel, int nCommentTo, int nMainHeaderLines) // = -1, -1, -1, -1, true, true, -1, 0
///// end IMPORT_EXCEL_SUPPORT_MULTILINES_COMMENTS
{
	for ( int ii=0; ii<nMainHeaderLines; ++ii )
		wks.DeleteRow(0);
//------
	
	vector<int> vLabels;
	vector<int> vRemovedRows;
	int nRows = wks.GetNumRows();
	int nCols = wks.GetNumCols();

	// set short name 
	if ( nShortName >= 0 && nShortName <= nRows )
	{
		string strValue;
		for (int ii = 0; ii < nCols; ii++ )
		{
			wks.GetCell(nShortName, ii, strValue);
			wks.Columns(ii).SetName(strValue);
		}
		
		vRemovedRows.Add(nShortName);
	}
	
	/// Hong 11/02/07 QA80-10622 IMPORT_EXCEL_SUPPORT_MULTILINES_COMMENTS
	//setLabelAndUpdateRowsList(wks, RCLT_LONG_NAME, nLongName, vLabels, vRemovedRows);
	//setLabelAndUpdateRowsList(wks, RCLT_UNIT, nUnit, vLabels, vRemovedRows);	
	//setLabelAndUpdateRowsList(wks, RCLT_COMMENT, nComment, vLabels, vRemovedRows);
	setLabelAndUpdateRowList(wks, RCLT_LONG_NAME, nLongName, vLabels, vRemovedRows);
	setLabelAndUpdateRowList(wks, RCLT_UNIT, nUnit, vLabels, vRemovedRows);	
	setLabelAndUpdateRowsList(wks, RCLT_COMMENT, nCommentFrom, nCommentTo, vLabels, vRemovedRows);
	/// end IMPORT_EXCEL_SUPPORT_MULTILINES_COMMENTS

	if ( bShowLabel )
		wks_add_show_labels(wks, vLabels, false);
				
	if ( bRemoveRows )
	{
		if( vRemovedRows.GetSize() > 0 ) /// YuI 02/26/07 added size testing
			vRemovedRows.Sort(SORT_DESCENDING);
		
		for ( int ii = 0; ii < vRemovedRows.GetSize(); ii++ )
		{
			int nRow = vRemovedRows[ii];
			wks.DeleteRow(nRow);
		}
	}
	
	return true;
}
///---END SET_LABEL_VALUE



bool page_add_result_sheet(Page& pg, Datasheet& wksMatLayer, LPCSTR lpcszSheetName, bool bHierachySheet, bool bRemoveExisting)
{
	DWORD dwCntrl = 0;
	DWORD dwOptions = 0;
	if(bHierachySheet)
	{
		dwCntrl |= WP_SHEET_HIERARCHY | CREATE_NO_DEFAULT_TEMPLATE | WP_SHEET_THIN_COL_HEADERS | WP_SHEET_MAIN_NAN_AS_BLANK;
		dwOptions |= GETNBRANCH_HIDE_COL_LABELS | GETNBRANCH_FIT_COL_WIDTH | GETNBRANCH_FIT_ROW_HEIGHT;
	}
		
	int nn = pg.AddLayer(lpcszSheetName, dwCntrl, NULL, dwOptions );
	wksMatLayer = pg.Layers(nn);
		
	if( bRemoveExisting && nn > 0) // there was already another sheet, 
	{
		for(int ii = 0; ii < nn; ii++)
		{
			Layer layJunk = pg.Layers(0);
			layJunk.Destroy();
		}
		//out_int("num cols = ", wksMatLayer.GetNumCols());
	}
	return true;
}

///---Sim 05-09-2007 CHANGE_LABEL_TEXT_STYLE
bool wks_set_label_text_control(Worksheet& wks, int nLabel, int nStyle)
{
	if ( !wks )
		return false;
	
	string strName;
	switch ( nLabel )
	{
	case RCLT_LONG_NAME:	strName = "ogLongName"; break;
	case RCLT_UNIT: 		strName = "ogUnit"; 	break;
	case RCLT_COMMENT:		strName = "ogComment"; 	break;
	default:
		return error_report("Unknown label ID for change text style");
	}
	
	string strControl;
	switch ( nStyle )
	{
	case WKS_LABEL_TEXT_CONTROL_ORIGIN_TEXT:	strControl = "Origin Text Edit"; break;
	case WKS_LABEL_TEXT_CONTROL_EDIT:			strControl = "Edit"; 		break;
	default:
		return error_report("Unknown control for change text style");
	}
	
	Grid grid;
	grid.Attach(wks);
	Tree tr;
	tr.Root.NameStyles.NameStyle1.Name.strVal = strName;
	tr.Root.NameStyles.NameStyle1.Style.Control.strVal = strControl;
	int iRet = grid.UpdateThemeIDs(tr.Root);
	if(0 != iRet)
		return error_report("UpdateThemeIDs Err = " + iRet);
	
	grid.ApplyFormat(tr, true, true);
	
	return true;
}
///---END CHANGE_LABEL_TEXT_STYLE

///---Sim 05-25-2007 IMPROVE_GET_AND_SET_XF_BAR_NAME
typedef int (*FUNC_PAGE_STR_INT)(Page& page, string strXF, int nMode);
typedef int (*FUNC_PAGE_RSTR_RINT)(Page& page, string& strXF, int& nMode);

bool set_page_xf_bar(Page& page, LPCSTR lpcszName, int nMode)// = NULL, 0
{
	Function fn = Project.FindFunction("XFBarSet", "OriginLab\\PageXFBar");
	FUNC_PAGE_STR_INT pfn = fn;
	if(!pfn)
		return error_report(_L("Load XFBarSet Function failed"));
		
	string strName = lpcszName;
	if(pfn(page, strName, nMode)< 0)
		return error_report("set XFBar xf failed");
	
	return true;
}

bool get_page_xf_bar(Page& page, string& strName, int* pnMode)// = NULL
{
	Function fn = Project.FindFunction("XFBarGet", "OriginLab\\PageXFBar");
	FUNC_PAGE_RSTR_RINT pfn = fn;
	if(!pfn)
		return error_report(_L("Load XFBarGet Function failed"));
		
	int nMode;
	if(pfn(page, strName, nMode)< 0)
		return error_report("get XFBar xf failed");
	
	if ( NULL != pnMode )
		*pnMode = nMode;
	
	return true;
}
///---END IMPROVE_GET_AND_SET_XF_BAR_NAME

///Folger 06/20/07 SHEET_BROWSER_BUTTON_INGETN
BOOL open_sheet_list_dlg(HWND hWndParent, vector<string> &vsResult, bool bMutiSelect)
{
	string strPath = "Originlab\\ProjectBrowser.c";
	FUNC_VECTORSTR_DWORD_HWND_BOOL pfn = Project.FindFunction("ProjectBrowseSheets", strPath);
	if(!pfn || !pfn(vsResult, 0, hWndParent, bMutiSelect))
		return false;	
	return true;
}
///End SHEET_BROWSER_BUTTON_INGETN

///Jasmine 06/25/07 UPDATE_ORGANIZER
bool set_organizer_handle(Page& page, HWND hwnd)
{
	if(!page)
		return false;
	
	Tree trOrg;
	tree_get_binary_storage(trOrg, page, ORGANIZER);
	
	TreeNode trHWND = trOrg.GetNode(ORGHWND);
	if ( !trHWND )
		trHWND = trOrg.AddNode(ORGHWND);
	
	trHWND.nVal = (DWORD)hwnd;
	return tree_put_binary_storage(trOrg, page, ORGANIZER);
}

HWND get_organizer_handle(const Page& page)
{
	if ( !page )
		return NULL;
	
	Tree trOrg;
	if( tree_get_binary_storage(trOrg, page, ORGANIZER) )
	{
		TreeNode trHWND = trOrg.GetNode(ORGHWND);
		if(trHWND)
			return (HWND)trHWND.nVal;
	}
	return NULL;
}
///End UPDATE_ORGANIZER

///---Sim 06-25-2007 UPDATE_ORGANIZER
/// Hong 10/24/07 v8.0732 IMPROVE_ORGANIZER_REFRESH_BY_ONIDLE
/* only notify_organizer_gui should be enough as it should cause refresh event if UPDATE_FROM_IMPORT
bool refresh_organizer_gui(const Page& page)
{
	HWND hwnd = get_organizer_handle(page);
	
	Window win(hwnd);
	if ( win )
	{
		win.PostMessage(WM_USER_ON_REFRESH_ORGANIZER);
		return true;
	}
		
	return false;
}
*/
/// end IMPROVE_ORGANIZER_REFRESH_BY_ONIDLE

///Folger 06/26/07 CHANGE_UPDATE_TO_NOTIFY
//bool update_organizer_gui(const Page& page, int wParam, int lParam)
bool notify_organizer_gui(const Page& page, int wParam, int lParam)
///End CHANGE_UPDATE_TO_NOTIFY
{
	HWND hwnd = get_organizer_handle(page);
	
	Window win(hwnd);
	if ( win )
	{
		///Folger 06/26/07 CHANGE_UPDATE_TO_NOTIFY
		//win.PostMessage(WM_USER_ON_UPDATE_ORGANIZER, wParam, lParam);
		win.PostMessage(WM_USER_ON_NOTIFY_ORGANIZER, wParam, lParam);
		///End CHANGE_UPDATE_TO_NOTIFY
		return true;
	}
		
	return false;
}
///---END UPDATE_ORGANIZER

//------ Folger 08/06/07 CHECK_WHETHER_DATARANGE_HAS_PLOTTED_IN_SPECIFIC_GRAPH_LAYER
#ifdef _WRONG_CODE_FOR_FINDING_XY_RANGE_IN_PLOT
int check_has_plotted_in_graph(const DataRange &dr, const GraphLayer &gl, vector<int> &vnPlotIndices)
{
	vector<uint> vnUID;
	dr.GetPlots(vnUID);
	int nSize = vnUID.GetSize();
	
	vector<int> vnPlotIndicesTemp(nSize);
	vnPlotIndicesTemp = -1;
	
	vector<string> vsPlotted;
	foreach (DataPlot dp in gl.DataPlots)
	{
		string strRange;
		dp.GetRangeString(strRange, NTYPE_FOR_RANGE);
		vsPlotted.Add(strRange);
	}
	
	int nPlotted = 0;
	for (int ii=0; ii<nSize; ii++)
	{
		DataPlot dp;
		dp = Project.GetObject(vnUID[ii]);
		if (dp)
		{
			string strRange;
			dp.GetRangeString(strRange, NTYPE_FOR_RANGE);
			if (vsPlotted.Find(strRange) >= 0)
			{
				vnPlotIndicesTemp[ii] = dp.GetIndex();
				nPlotted++;
			}
		}
	}
	
	if(NULL != vnPlotIndices)
		vnPlotIndices = vnPlotIndicesTemp;
	
	/*
	vector<string> vsRanges;
	int nRangeSize = dr.GetNumRanges();
	for(int nRange=0; nRange < nRangeSize; nRange++)
	{
		Worksheet wks;
		int r1, r2, c1, c2;
		dr.GetRange(nRange, r1, c1, r2, c2, wks);
		for (; c1<=c2; c1++)
		{
			Column col(wks, c1);
			if (col.GetType() == OKDATAOBJ_DESIGNATION_Y)	//"Y"
			{
				string strRange;
				string strWks;
				wks.GetRangeString(strWks);
				okoc_get_range_str(strWks, c1, &strRange, DRR_GET_DEPENDENT);
				vsRanges.Add(strRange);
			}
		}
	}
	
	vector<string> vsPlots;
	foreach (DataPlot dp in gl.DataPlots)
	{
		string strRange;
		dp.GetRangeString(strRange, NTYPE_BOOKSHEET_XY_RANGE);
		vsPlots.Add(strRange);
	}
	
	int nXYRangeSize = vsRanges.GetSize();
	int nPlotSize = vsPlots.GetSize();
	
	vector<int> vnPlotIndicesTemp(nXYRangeSize);
	vnPlotIndicesTemp = -1;
	
	int nPlotted = 0;
	for (int ii=0; ii<nXYRangeSize; ii++)
	{
		for (int jj=0; jj<nPlotSize; jj++)
		{
			int nRet;
			if ((nRet = okoc_compare_obj_ranges(vsRanges[ii], vsPlots[jj])) == 0)
			{
				vnPlotIndicesTemp[ii] = jj;
				nPlotted++;
				break;
			}
		}
	}
	
	if (vnPlotIndices != NULL)
		vnPlotIndices = vnPlotIndicesTemp;
	*/
	return nPlotted;
}
#endif
//------ End CHECK_WHETHER_DATARANGE_HAS_PLOTTED_IN_SPECIFIC_GRAPH_LAYER

//---- CPY 8/6/2007 REWRITE_CODE_TO_FIND_DATAPLOT_FROM_XYRANGE

///Arvin 08/28/07 QA70-10073-P2 KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
//int check_has_plotted_in_graph(const DataRange &dr, const GraphLayer &gl, vector<int> &vnPlotIndices)
/// Hong 03/25/09 QA80-12551 RESET_PLOT_ROW_RANGE_IF_USER_UPDATE_INPUT_DATARANGE_WHEN_CHANGE_PARAMETER
//int check_has_plotted_in_graph(const DataRange &dr, const GraphLayer &gl, vector<int> &vnPlotIndices, DWORD dwNTypeCntrl)
int check_has_plotted_in_graph(const DataRange &dr, const GraphLayer &gl, vector<int> &vnPlotIndices, DWORD dwNTypeCntrl, bool bResetPlotRowRangeIfDiffButNotChecked)
/// end RESET_PLOT_ROW_RANGE_IF_USER_UPDATE_INPUT_DATARANGE_WHEN_CHANGE_PARAMETER
///end KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
{
	//------ Folger 10/23/08 CENTRALIZE_CODE_ABOUT_CHECKING_ORIGIN_OBJECT_HAS_PLOTTED_IN_GRAPH
	/*
	if(!gl)
		return -1;
	if(!dr)
		return -2;
	string strRange;
	///Arvin 08/28/07 QA70-10073-P2 KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
	//dr.GetRangeString(strRange, NTYPE_BOOKSHEET_XY_RANGE);
	dr.GetRangeString(strRange, dwNTypeCntrl);
	///end KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
	if(strRange.IsEmpty())
		return -3;
	
	vector<int> vnPlots;
	int ii = 0;
	foreach (DataPlot dp in gl.DataPlots)
	{
		string strRange1;
		///Arvin 08/28/07 QA70-10073 KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
		//dp.GetRangeString(strRange1, NTYPE_BOOKSHEET_XY_RANGE);
		dp.GetRangeString(strRange1, dwNTypeCntrl);
		///end KEEP_CUSTOMIZATION_AFTER_CHANGE_PARAMETER_OR_RECALCULATE_SURFACE_FIT
		if(okoc_compare_obj_ranges(strRange, strRange1) == 0)
			vnPlots.Add(ii);
		
		ii++;
	}
	if(vnPlotIndices)
		vnPlotIndices = vnPlots;
	return vnPlots.GetSize();
	*/
	/// Hong 03/25/09 QA80-12551 RESET_PLOT_ROW_RANGE_IF_USER_UPDATE_INPUT_DATARANGE_WHEN_CHANGE_PARAMETER
	//return check_origin_object_has_plotted_in_graph(dr, gl, vnPlotIndices, dwNTypeCntrl);
	return check_origin_object_has_plotted_in_graph(dr, gl, vnPlotIndices, dwNTypeCntrl, bResetPlotRowRangeIfDiffButNotChecked);
	/// end RESET_PLOT_ROW_RANGE_IF_USER_UPDATE_INPUT_DATARANGE_WHEN_CHANGE_PARAMETER
	//------ End CENTRALIZE_CODE_ABOUT_CHECKING_ORIGIN_OBJECT_HAS_PLOTTED_IN_GRAPH
}
//----

//------ Folger 08/13/07 CHECK_IF_DATAPLOT_IN_DATARANGE
/// Hong QA80-12551 v8.0967 FIX_FAIL_REPLOT_SCR_PLOT_WHEN_RESET_TO_FULL_RANGE
//bool check_plot_in_range(const DataRange &dr, const DataPlot &dp, DWORD dwRules)
bool check_plot_in_range(const DataRange &dr, const DataPlot &dp, DWORD dwRules, DWORD dwNTypeCtrl/* = NTYPE_BOOKSHEET_XY_RANGE | NTYPE_ADD_ROW_RANGE*/)
/// end FIX_FAIL_REPLOT_SCR_PLOT_WHEN_RESET_TO_FULL_RANGE
{
	int nNumRanges = dr.GetNumData(dwRules);
	string strPlot;
	/// Hong QA80-12551 v8.0967 FIX_FAIL_REPLOT_SCR_PLOT_WHEN_RESET_TO_FULL_RANGE
	//dp.GetRangeString(strPlot, NTYPE_BOOKSHEET_XY_RANGE);
	dp.GetRangeString(strPlot, dwNTypeCtrl);	
	/// end FIX_FAIL_REPLOT_SCR_PLOT_WHEN_RESET_TO_FULL_RANGE
	for(int nRange = 0; nRange < nNumRanges; nRange++)
	{
		DataRange drOneRange;
		dr.GetSubRange(drOneRange, dwRules, nRange);
		string strOneRange;
		/// Hong QA80-12551 v8.0967 FIX_FAIL_REPLOT_SCR_PLOT_WHEN_RESET_TO_FULL_RANGE
		//drOneRange.GetRangeString(strOneRange);
		//if (okoc_compare_obj_ranges(strPlot, strOneRange) == 0)
		drOneRange.GetRangeString(strOneRange, dwNTypeCtrl);		
		if ( okoc_compare_obj_ranges(strPlot, strOneRange, !(dwNTypeCtrl & NTYPE_ADD_ROW_RANGE)) == 0 )
		/// end FIX_FAIL_REPLOT_SCR_PLOT_WHEN_RESET_TO_FULL_RANGE
			return true;
	}
	return false;
}
//------ End CHECK_IF_DATAPLOT_IN_DATARANGE

/// YuI 10/30/09 QA70-14567 INPUT_NEW_RANGE_CHANGE_NOT_WORKING
static BOOL	_update_plot_range_from_datarange(DataPlot& dp, const DataRange& dr)
{
	int r1 = 0;
	int r2 = -1;
	int c1 = 0;
	int c2 = -1;
	Datasheet ds;
	if( dr.GetRange("Y", r1, c1, r2, c2, ds) )
	{
		if( r1 == 0 && r2 == -1 )
			dp.SetRange();
		else
			dp.SetRange(r1, r2);
		
		return TRUE;
	}
	
	return FALSE;
}
/// end INPUT_NEW_RANGE_CHANGE_NOT_WORKING

///Arvin 08/16/07 QA70-10073 KEEP_OUTPUT_CURVE_CUSTOMIZATION_AFTER_RECALCULATE_FOR_XF
/// YuI 03/13/09 QA70-13281 TAGGING_AVECURVES_RESULTS_TO_EXCLUDE_THEM_FROM_FUTURE_AVERAGING
//	static bool _check_plot_rng_in_graph(const DataRange &dr, GraphLayer& gl, DataPlot* pdpOut, int nPlotType, int nPlotColor, uint nCntrl, bool bNeedRescale = false)
///Kyle 03/20/2009 ADD_OPTION_TO_SPECIFY_FORMAT_OF_DATA_PLOT
//static bool _check_plot_rng_in_graph(const DataRange &dr, GraphLayer& gl, DataPlot* pdpOut, int nPlotType, int nPlotColor, uint nCntrl, bool bNeedRescale = false, LPCSTR lpcszTag = NULL)
static bool _check_plot_rng_in_graph(const DataRange &dr, GraphLayer& gl, DataPlot* pdpOut, int nPlotType, int nPlotColor, uint nCntrl, bool bNeedRescale = false, LPCSTR lpcszTag = NULL, DWORD dwPlotFormat = 0)
///End ADD_OPTION_TO_SPECIFY_FORMAT_OF_DATA_PLOT
/// end TAGGING_AVECURVES_RESULTS_TO_EXCLUDE_THEM_FROM_FUTURE_AVERAGING
{
	if(!gl.IsValid())
		return false;
	
	vector<int> vnPlotIndices;
	if(check_has_plotted_in_graph(dr, gl, vnPlotIndices) > 0)
	{
		///Kyle 12/17/2008 NEED_CHECK_RESCALE_WHEN_RANGE_HAS_PLOTTED_IN_GRAPH
		if(bNeedRescale)
			gl.Rescale();
		///End NEED_CHECK_RESCALE_WHEN_RANGE_HAS_PLOTTED_IN_GRAPH
		
		/// YuI 10/30/09 QA70-14567 INPUT_NEW_RANGE_CHANGE_NOT_WORKING
		// data plot may get "desynchronized" with its range in terms of i1 i2. Need to update plot range
		for( int ii = 0; ii < vnPlotIndices.GetSize(); ii++ )
		{
			DataPlot dp = gl.DataPlots(vnPlotIndices[ii]);
			if( dp )
			{
				_update_plot_range_from_datarange(dp, dr);
				/// Iris 2/04/2010 FIX_QUICK_FIT_OUTPUT_PLOT_NOT_UPDATE_COLOR_IF_HAS_PLOTTED
				if(0 == ii && pdpOut)
					*pdpOut = dp;
				///End FIX_QUICK_FIT_OUTPUT_PLOT_NOT_UPDATE_COLOR_IF_HAS_PLOTTED
			}
		}
		/// end INPUT_NEW_RANGE_CHANGE_NOT_WORKING
		
		return true;
	}
			
	int nPlot = gl.AddPlot(dr, nPlotType, nCntrl);
	if(nPlot >= 0)
	{
		/// YuI 03/13/09 QA70-13281 TAGGING_AVECURVES_RESULTS_TO_EXCLUDE_THEM_FROM_FUTURE_AVERAGING
		if( NULL != lpcszTag )
		{
			tag_columns_in_data_range(dr, lpcszTag);
		}
		/// end TAGGING_AVECURVES_RESULTS_TO_EXCLUDE_THEM_FROM_FUTURE_AVERAGING
		legend_append_plot(gl, nPlot);
		DataPlot dpOut = gl.DataPlots(nPlot);
		if(dpOut)
		{
			//gl.UngroupPlots(nPlot);
			dpOut.SetColor(nPlotColor);
			
			///Kyle 03/20/2009 ADD_OPTION_TO_SPECIFY_FORMAT_OF_DATA_PLOT
			// specified dataplot format, for now only PLOT_OUTPUT_FORMAT_THICKNESS is defined
			if(dwPlotFormat & PLOT_OUTPUT_FORMAT_THICKNESS)
			{
				Tree trFmt;
				trFmt.Root.Line.Width.dVal = 3;
				dpOut.UpdateThemeIDs(trFmt.Root);
				dpOut.ApplyFormat(trFmt, true, true);
			}
			///End ADD_OPTION_TO_SPECIFY_FORMAT_OF_DATA_PLOT
			if(pdpOut)
				*pdpOut = dpOut;
			if(bNeedRescale)
				gl.Rescale();
		}
	}
	
	return true;
}


/// YuI 03/13/09 QA70-13281 TAGGING_AVECURVES_RESULTS_TO_EXCLUDE_THEM_FROM_FUTURE_AVERAGING
//	bool xf_check_plot_output_rng_in_source_rng_graph(const DataRange& drSource, const DataRange& drOutput, DataPlot* pdpOut, int nPlotType, int nPlotColor, uint nCntrl, bool bNeedRescale)
///Kyle 03/20/2009 ADD_OPTION_TO_SPECIFY_FORMAT_OF_DATA_PLOT
//bool xf_check_plot_output_rng_in_source_rng_graph(const DataRange& drSource, const DataRange& drOutput, DataPlot* pdpOut, int nPlotType, int nPlotColor, uint nCntrl, bool bNeedRescale, LPCSTR lpcszTag)
bool xf_check_plot_output_rng_in_source_rng_graph(const DataRange& drSource, const DataRange& drOutput, DataPlot* pdpOut, int nPlotType, int nPlotColor, uint nCntrl, bool bNeedRescale, LPCSTR lpcszTag, DWORD dwPlotFormat)
///End ADD_OPTION_TO_SPECIFY_FORMAT_OF_DATA_PLOT
/// end TAGGING_AVECURVES_RESULTS_TO_EXCLUDE_THEM_FROM_FUTURE_AVERAGING
{
	vector<uint> vnUID;
	drSource.GetPlots(vnUID);
	int nPlotNum = vnUID.GetSize();
	
	if(nPlotNum > 0)
	{
		DataPlot dp;
		dp = Project.GetObject(vnUID[0]);
		if(!dp.IsValid())
			return false;
		
		GraphLayer gl;
		dp.GetParent(gl);
		/*
		if(gl)
		{
			vector<int> vnPlotIndices;
			if(check_has_plotted_in_graph(drOutput, gl, vnPlotIndices) > 0)
				return true;
			
			int nPlot = gl.AddPlot(drOutput, nPlotType, nCntrl);
			if(nPlot >= 0)
			{
				legend_append_plot(gl, nPlot);
				DataPlot dpOut = gl.DataPlots(nPlot);
				if(dpOut)
				{
					//gl.UngroupPlots(nPlot);
					dpOut.SetColor(nPlotColor);
					if(pdpOut)
						*pdpOut = dpOut;
				}
			}
			return true;
		}
		*/
		///Kyle 03/20/2009 ADD_OPTION_TO_SPECIFY_FORMAT_OF_DATA_PLOT
		//return _check_plot_rng_in_graph(drOutput, gl, pdpOut, nPlotType, nPlotColor, nCntrl, bNeedRescale);
		return _check_plot_rng_in_graph(drOutput, gl, pdpOut, nPlotType, nPlotColor, nCntrl, bNeedRescale, NULL, dwPlotFormat);
		///End ADD_OPTION_TO_SPECIFY_FORMAT_OF_DATA_PLOT
	}
	
	return false;
}

bool xf_check_plot_output_rng_in_graph(const DataRange& drOutput, int nXFGraphPageID, DataPlot* pdpOut, int nPlotType, int nPlotColor, uint nCntrl)
{
	XFExeContext* pxfexectxt = Project.GetCurrentXFExeCtxt();
	if(!pxfexectxt)
		return false;
	
	GraphPage gp;
	gp = pxfexectxt->GetGraph(nXFGraphPageID);
	
	bool bIsNewCreated = false;
	if ( !gp )
	{
		/// Kenny 08/25/2009 QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
		//gp.Create("origin");
		gp.Create("origin", CREATE_DEFAULT_OPTIONS | CREATE_ENUM_EXIST_PAGE);
		/// End QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
		bIsNewCreated = true;
	}
	
	GraphLayer	gl = gp.Layers(0);
	if(!_check_plot_rng_in_graph(drOutput, gl, pdpOut, nPlotType, nPlotColor, nCntrl))
		return false;
	
	if(bIsNewCreated)
		gl.Rescale();
	
	pxfexectxt->SetGraph(gp, nXFGraphPageID);
	
	return true;	
}
///end KEEP_OUTPUT_CURVE_CUSTOMIZATION_AFTER_RECALCULATE_FOR_XF

//------ Folger 10/22/08 CHECK_AND_PLOT_MATRIX_OBJECT_IN_GRAPH
/// Hong 03/25/09 QA80-12551 RESET_PLOT_ROW_RANGE_IF_USER_UPDATE_INPUT_DATARANGE_WHEN_CHANGE_PARAMETER
//int	check_origin_object_has_plotted_in_graph(const OriginObject& obj, const GraphLayer &gl, vector<int> &vnPlotIndices/* = NULL*/, DWORD dwNTypeCntrl/* = NTYPE_BOOKSHEET_XY_RANGE*/)
int		check_origin_object_has_plotted_in_graph(const OriginObject& obj, const GraphLayer &gl, vector<int> &vnPlotIndices/* = NULL*/, DWORD dwNTypeCntrl/* = NTYPE_BOOKSHEET_XY_RANGE*/, bool bResetPlotRowRangeIfDiffButNotChecked/* = false*/)
/// end RESET_PLOT_ROW_RANGE_IF_USER_UPDATE_INPUT_DATARANGE_WHEN_CHANGE_PARAMETER
{
	if(!gl)
		return -1;
	if(!obj)
		return -2;
	
	string strRange;
	obj.GetRangeString(strRange, dwNTypeCntrl);
	if(strRange.IsEmpty())
		return -3;
	/// Hong 03/25/09 QA80-12551 RESET_PLOT_ROW_RANGE_IF_USER_UPDATE_INPUT_DATARANGE_WHEN_CHANGE_PARAMETER
	int			r1, r2;
	string 		strRowRange;
	if ( bResetPlotRowRangeIfDiffButNotChecked )
	{
		DataRange		dr;
		dr = (DataRange)obj;
		if ( !dr || (NTYPE_ADD_ROW_RANGE & dwNTypeCntrl) )
			bResetPlotRowRangeIfDiffButNotChecked = false;
		else
		{
			int			c1, c2;
			Datasheet	ds;
			dr.GetRange(0, r1, c1, r2, c2, ds);
			obj.GetRangeString(strRowRange, dwNTypeCntrl | NTYPE_ADD_ROW_RANGE);
			ASSERT(!strRowRange.IsEmpty());
		}
	}
	/// end RESET_PLOT_ROW_RANGE_IF_USER_UPDATE_INPUT_DATARANGE_WHEN_CHANGE_PARAMETER
	
	vector<int> vnPlots;
	int ii = 0;
	foreach (DataPlot dp in gl.DataPlots)
	{
		string strRange1;
		dp.GetRangeString(strRange1, dwNTypeCntrl);
		if(okoc_compare_obj_ranges(strRange, strRange1) == 0)
		{
			/// Hong 03/25/09 QA80-12551 RESET_PLOT_ROW_RANGE_IF_USER_UPDATE_INPUT_DATARANGE_WHEN_CHANGE_PARAMETER
			if ( bResetPlotRowRangeIfDiffButNotChecked )
			{
				string 		strRowRange1;
				dp.GetRangeString(strRowRange1, dwNTypeCntrl | NTYPE_ADD_ROW_RANGE);
				if ( okoc_compare_obj_ranges(strRange, strRange1, false) > 0 )
					dp.SetRange(r1, r2, false);
			}
			/// end RESET_PLOT_ROW_RANGE_IF_USER_UPDATE_INPUT_DATARANGE_WHEN_CHANGE_PARAMETER
			vnPlots.Add(ii);
		}
		
		ii++;
	}
	if(vnPlotIndices)
		vnPlotIndices = vnPlots;
	
	return vnPlots.GetSize();
}

static bool _check_plot_matrix_in_graph(const MatrixObject& mo, GraphLayer& gl, DataPlot* pdpOut, int nPlotType, bool bNeedRescale = false)
{
	if(!gl.IsValid())
		return false;
	
	vector<int> vnPlotIndices;
	if(check_origin_object_has_plotted_in_graph(mo, gl, vnPlotIndices) > 0)
		return true;
			
	int nPlot = gl.AddPlot(mo, nPlotType);
	if(nPlot >= 0)
	{
		legend_append_plot(gl, nPlot);
		DataPlot dpOut = gl.DataPlots(nPlot);
		if(dpOut)
		{
			if(pdpOut)
				*pdpOut = dpOut;
			if(bNeedRescale)
				gl.Rescale();
		}
	}
	
	return true;
}

bool	xf_check_plot_output_matrix_in_graph(const MatrixObject& mo, GraphLayer& gl, int nXFGraphPageID/* = 0*/, DataPlot* pdpOut/* = NULL*/, int nPlotType/* =  IDM_PLOT_MATRIX_IMAGE*/, LPCSTR lpcszTemplate/* = "Origin"*/)
{
	if ( gl == NULL )
		return false;
	
	XFExeContext* pxfexectxt = Project.GetCurrentXFExeCtxt();
	if(!pxfexectxt)
		return false;
	
	GraphPage gp;
	gp = pxfexectxt->GetGraph(nXFGraphPageID);
	
	bool bIsNewCreated = false;
	if ( !gp )
	{
		/// Kenny 08/25/2009 QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
		//gp.Create(lpcszTemplate);
		gp.Create(lpcszTemplate, CREATE_DEFAULT_OPTIONS | CREATE_ENUM_EXIST_PAGE);
		/// End QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
		bIsNewCreated = true;
	}
	
	gl = gp.Layers(0);	
	if(!_check_plot_matrix_in_graph(mo, gl, pdpOut, nPlotType, bIsNewCreated ? true : false))
		return false;
	
	pxfexectxt->SetGraph(gp, nXFGraphPageID);
	
	return true;
}
//------ End CHECK_AND_PLOT_MATRIX_OBJECT_IN_GRAPH

///Arvin 08/13/07 v8.0680 FIND_PRED_AND_CONF_BAND_AND_ELLIPSE_PLOT_INDEX
static bool string_range_has_key(const string& strPlotRange, LPCSTR lpcszKey, bool bCaseSensitive)
{
	bool bFind = false;
	string strKey(lpcszKey);
	bFind = strPlotRange.Find(strKey) >= 0;
	if(!bCaseSensitive)
	{
		strKey.MakeLower();
		bFind |= strPlotRange.Find(strKey) >= 0;
		strKey.MakeUpper();
		bFind |= strPlotRange.Find(strKey) >= 0;
	}
	return bFind;
}

int find_plot_index_by_key(const GraphLayer& gl, LPCSTR lpcszKey1, LPCSTR lpcszKey2, int nPlotFrom, bool bCaseSensitive, DWORD dwCntrl)
{
	if(lpcszKey1 == NULL)
		return -1;
	
	int index = 0;
	bool bFind = false;
	foreach(DataPlot dp in gl.DataPlots)
	{
		if(nPlotFrom >=0 && nPlotFrom > index)
		{
			//do nothing
		}
		else
		{
			string strPlotRange;
			BOOL bRet = dp.GetRangeString(strPlotRange, dwCntrl);
			if(lpcszKey1)
			{
				bFind = string_range_has_key(strPlotRange, lpcszKey1, bCaseSensitive);
				if(bFind && lpcszKey2)
					bFind = string_range_has_key(strPlotRange, lpcszKey2, bCaseSensitive);
			}
			if(bFind)
				return index;
		}
		
		index++;
	}
	
	return -1;
}
///end FIND_PRED_AND_CONF_BAND_AND_ELLIPSE_PLOT_INDEX

//------ Folger 08/23/07 GET_GRAPH_TEMPLATE_PREVIEW_IMAGE_FILES_FULL_NAME
string get_graph_template_preview_file(LPCSTR lpcszTemplate)
{
	string strSystem = "Templates\\Previews\\";
	string strPath 		= GetFilePath(lpcszTemplate);
	string strNameOnly 	= GetFileName(lpcszTemplate, true);
	string strEMF 		= strPath + strNameOnly + ".emf";
	string strBMP 		= strPath + strNameOnly + ".bmp";
	string strPicture;
	//look for existing file first
	if(strEMF.IsFile() || strBMP.IsFile())
		//------ Folger 09/04/07 USE_FILE_LAST_MODIFIED_COMPARE_OF_VC_LEVEL
		//strPicture = file_modified_time_compare(strEMF, strBMP)? strEMF : strBMP;
		strPicture = file_last_modified_time_compare(strBMP, strEMF) > 0 ? strBMP : strEMF;
		//------ End USE_FILE_LAST_MODIFIED_COMPARE_OF_VC_LEVEL
	else
	{
		strEMF = strPath + strSystem + strNameOnly + ".emf";
		strBMP = strPath + strSystem + strNameOnly + ".bmp";
		if(strEMF.IsFile() || strBMP.IsFile())
			//------ Folger 09/04/07 USE_FILE_LAST_MODIFIED_COMPARE_OF_VC_LEVEL
			//strPicture = file_last_modified_time_compare(strEMF, strBMP)? strEMF : strBMP;
			strPicture = file_last_modified_time_compare(strBMP, strEMF) > 0 ? strBMP : strEMF;
			//------ End USE_FILE_LAST_MODIFIED_COMPARE_OF_VC_LEVEL
	}
	return strPicture;
}
//------ End GET_GRAPH_TEMPLATE_PREVIEW_IMAGE_FILES_FULL_NAME

///Cheney 2007-8-27 ADD_HINTS_AND_LOCALIZE_NONEPREVIEW_TEMPLATE
bool load_text_for_nonepreview_graphpage(GraphPage& gp, int nContentID, int nHintsID)
{
	if(!gp)
		return false;
	
	int nLayers = gp.Layers.Count();
	for(int ii = 0; ii < nLayers; ii++)
	{
		GraphLayer gl = gp.Layers(ii);
		if(!load_text_for_nonepreview_graphlayer(gl, nContentID, nHintsID))
			return false;
	}
	return true;
}

///Jasmine 11/06/09 QA80-14559 JAPANESE_TEXT_IS_TOO_LONG_TO_SHOW
//this function only check if the text is out of the left side of the page
static void _check_set_text_position(GraphLayer& gl, GraphObject& goContent)
{
	int nXPage, nYPage;
	gl.WorldToPage(nXPage, nYPage, goContent.X, goContent.Y);
	
	int nWidthPage, nHeightPage;
	gl.WorldToPage(nWidthPage, nHeightPage, goContent.DX, goContent.DY);
	
	double dPos[TOTAL_POS];
	dPos[WIDTH_POS] = nWidthPage;
	dPos[HEIGHT_POS] = nHeightPage;
	dPos[LEFT_POS] = nXPage;
	dPos[TOP_POS] = nYPage;
	gl.UnitsConvert(M_PERCENT, dPos, M_PIXEL);
		
	if(dPos[LEFT_POS] + dPos[WIDTH_POS]*0.5 < 100)
		return;
	//if page is still not big enough to show the whole text
	bool bSetFont = dPos[WIDTH_POS] > 100;
	
	double dOffset = 5;//5% of page
	//dPos[WIDTH_POS] = 100 - dOffset*2;
	double left = dPos[LEFT_POS] - dPos[WIDTH_POS] * 0.5;
	dPos[WIDTH_POS] = 100 - dOffset*2 - left;
	dPos[LEFT_POS] = 50;	
	gl.UnitsConvert(M_PIXEL, dPos, M_PERCENT);
	
	//---
	//I don't know why the following code does not work for graph in picture control, 
	//so now I can only always set a smaller font to show all the text
	//if(bSetFont)
	{
		Tree trFmt;
		trFmt = goContent.GetFormat(FPB_ALL, FOB_ALL, TRUE, TRUE);
		double dOldSize = trFmt.Root.Font.Size.dVal;
		double dFontSize = dOldSize * dPos[WIDTH_POS] / goContent.Width;
		trFmt.Root.Font.Size.dVal = dFontSize;
		goContent.ApplyFormat(trFmt, TRUE, TRUE, TRUE);
		/// Hong 11/25/09 QA80-14559 IMPROVE_CODE_TO_CENTER_TEXT
		// Hong, goContent.X fail to work fine due to Unit conversion when page is put in custom control, so use Left to avoid Unit conversion
		goContent.Left = dPos[LEFT_POS] - dPos[WIDTH_POS] / 2;
		/// end IMPROVE_CODE_TO_CENTER_TEXT
	}
	
	//move goContent to middle of page
	//double dXScale, dYScale;
	//gl.PageToWorld(dXScale, dYScale, dPos[LEFT_POS], dPos[TOP_POS]);
	//goContent.X = dXScale;
	//---
}
///End JAPANESE_TEXT_IS_TOO_LONG_TO_SHOW

bool load_text_for_nonepreview_graphlayer(GraphLayer& gl, int nContentID, int nHintsID)
{
	if(!gl)
		return false;
	
	string strContent, strHints;
	if(!ocu_load_msg_str(nContentID, &strContent) || !ocu_load_msg_str(nHintsID, &strHints))
		return false;
	/// Hong 11/07/07 v.80743 ROLLBACK_CORRECT_CODE
	/////Cheney 2007-10-24 USE_NEW_NONE_PREVIEW_TEMPLATE_FOR_NLFIT
	GraphObject goContent = gl.GraphObjects("TextContent");
	/////end USE_NEW_NONE_PREVIEW_TEMPLATE_FOR_NLFIT
	GraphObject goHints = gl.GraphObjects("TextHints");
	/////Cheney 2007-10-24 USE_NEW_NONE_PREVIEW_TEMPLATE_FOR_NLFIT
	if(!goContent || !goHints)
	//if(!goHints)	
	/////end USE_NEW_NONE_PREVIEW_TEMPLATE_FOR_NLFIT
		return false;
	
	goContent.Text = strContent; 	///Cheney 2007-10-24 USE_NEW_NONE_PREVIEW_TEMPLATE_FOR_NLFIT
	/// end ROLLBACK_CORRECT_CODE
	goHints.Text = strHints;
	
	///Jasmine 11/06/09 QA80-14559 JAPANESE_TEXT_IS_TOO_LONG_TO_SHOW
	_check_set_text_position(gl, goContent);
	_check_set_text_position(gl, goHints);
	///End JAPANESE_TEXT_IS_TOO_LONG_TO_SHOW
	
	return true;
}

bool is_nonepreview_template(GraphPage& gp, bool bNLFit)
{
	if(!gp)
		return false;
	
	string strTemplate = page_get_template_name(gp);
	string strTemplateName = GetFileName(strTemplate, true);
	
	if(!bNLFit)
		return strTemplateName.CompareNoCase(STR_NONE_PREVIEW_TEMPLATE) == 0;
	return strTemplateName.CompareNoCase(NLSF_NO_PREVIEW_TEMPLATE) == 0;
}
///end ADD_HINTS_AND_LOCALIZE_NONEPREVIEW_TEMPLATE




//----- CPY 10/12/07 10522-P3 CLEANUP_IF_LOOSE_DATASET_SHOULD_NOT_PUT_REPORT_SHEET_TO_SOURCE
///Cheney 2007-10-15 QA70-10522-P4 CLEAN_CODE_AND_ADD_AUTO_FOR_OUTPUT_SETTING 
//bool is_range_from_normal_book(const TreeNode& trInput, string* pstrBookName)
/// Sophy 5/08/2008 FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
//bool is_range_from_normal_book(const TreeNode& trInput, string* pstrBookName, string* pstrSheetName)
bool is_range_from_normal_book(const TreeNode& trInput, string* pstrBookName, string* pstrSheetName, bool bNotAllowEmptyInput) //bNotAllowEmptyInput default false,means allowed
/// End FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
///end CLEAN_CODE_AND_ADD_AUTO_FOR_OUTPUT_SETTING
{
	if(pstrBookName)
		pstrBookName->Empty();
	
	DataRange		rngInput;
	if(!trInput)
		return error_report("is_range_from_normal_book found invalid trInput");
	
	rngInput.Create(trInput, FALSE);
	if(!rngInput)
		return error_report("is_range_from_normal_book failed to construct input range"); 

	///Cheney 2007-10-15 QA70-10522-P4 CLEAN_CODE_AND_ADD_AUTO_FOR_OUTPUT_SETTING 
	//Datasheet		dsInput; 
	//WorksheetPage	pgInput;
	//rngInput.GetParent(dsInput); 
	//if (dsInput)
	//{
		/////Cheney 2007-10-15 QA70-10522-P4 CLEAN_CODE_AND_ADD_AUTO_FOR_OUTPUT_SETTING 
		//if(pstrSheetName)
			//pstrSheetName = dsInput.GetName();
		/////end CLEAN_CODE_AND_ADD_AUTO_FOR_OUTPUT_SETTING
		//dsInput.GetParent(pgInput);
		//if(pgInput && !pgInput.m_bIsExcel)
		//{
			//if(pstrBookName)
				//*pstrBookName = pgInput.GetName();
			//return true;
		//}
	//}
	//return false;
	/// Sophy 5/08/2008 FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
	//return is_range_from_normal_book(rngInput, pstrBookName, pstrSheetName);
	return is_range_from_normal_book(rngInput, pstrBookName, pstrSheetName, bNotAllowEmptyInput);	
	/// End FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
	///end CLEAN_CODE_AND_ADD_AUTO_FOR_OUTPUT_SETTING
}
//----- end CLEANUP_IF_LOOSE_DATASET_SHOULD_NOT_PUT_REPORT_SHEET_TO_SOURCE

//---- CPY 10/15/07 QA70-10536 SR0_725_OUTPUT_LOCATION_NOT_WORKING_FOR_STATS
static bool _is_range_empty(DataRange& rgInput)
{
	if(!rgInput)
		return true;
	if(rgInput.IsReal())
		return false;
	/*
	DataRange 	drOneRange;
	DWORD dwRulesTemp = DRR_NO_FACTORS;
	if(!rgInput.GetSubRange(drOneRange, dwRulesTemp, 0))
		return true;
	*/
	return true;
}
//----

///Cheney 2007-10-15 QA70-10522-P4 CLEAN_CODE_AND_ADD_AUTO_FOR_OUTPUT_SETTING 
/// Sophy 5/08/2008 FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
//bool is_range_from_normal_book(const DataRange& rgInput, string* pstrBookName, string* pstrSheetName)
bool is_range_from_normal_book(const DataRange& rgInput, string* pstrBookName, string* pstrSheetName, bool bNotAllowEmptyInput) //bNotAllowEmpty default false
/// End FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
{
	if(!rgInput)
		return error_report("invalid input range is_range_from_normal_book"); 

	Datasheet		dsInput; 
	WorksheetPage	pgInput;
	MatrixPage		mpInput;	///Cheney 2007-10-16 QA70-10536 CLEAN_CODE_AND_FIX_BUG_OF_ADD_AUTO_FOR_OUTPUT_SETTING
	rgInput.GetParent(dsInput); 
	if (dsInput)
	{
		if(pstrSheetName)
			*pstrSheetName = dsInput.GetName();
		dsInput.GetParent(pgInput);
		if(pgInput && !pgInput.m_bIsExcel)
		{
			if(pstrBookName)
				*pstrBookName = pgInput.GetName();
			return true;
		}
		///Cheney 2007-10-16 QA70-10536 CLEAN_CODE_AND_FIX_BUG_OF_ADD_AUTO_FOR_OUTPUT_SETTING
		dsInput.GetParent(mpInput);
		if(mpInput)
		{
			if(pstrBookName)
				*pstrBookName = mpInput.GetName();
			return true;
		}
		///end CLEAN_CODE_AND_FIX_BUG_OF_ADD_AUTO_FOR_OUTPUT_SETTING
	}
	//---- CPY 10/15/07 QA70-10536 SR0_725_OUTPUT_LOCATION_NOT_WORKING_FOR_STATS
	// temp solution, test if range is really empty
	else if(_is_range_empty(rgInput))
	{
		/// Sophy 5/08/2008 FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
		if( bNotAllowEmptyInput )  //On statistic on column/row.etc. empty input range is not allowed to set output to source book
			return false;
		/// End FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
		Page pgActive = Project.Pages();
		if(pgActive && pgActive.GetType()==EXIST_WKS)
			return true;
	}
	//----
	return false;
}
///end CLEAN_CODE_AND_ADD_AUTO_FOR_OUTPUT_SETTING
///Jasmine 10/15/07 MOVE_TO_PAGE_UTILS

///Cheney 2007-10-15 QA70-10522-P4 CLEAN_CODE_AND_ADD_AUTO_FOR_OUTPUT_SETTING 
//string get_source_page_name(const DataRange& drInput, string *pstrLayerName)
string get_range_source_page_name(const DataRange& drInput, string *pstrLayerName)
{	
	string strName;
	is_range_from_normal_book(drInput, &strName, pstrLayerName);
	return strName;	
}
///end CLEAN_CODE_AND_ADD_AUTO_FOR_OUTPUT_SETTING
///End MOVE_TO_PAGE_UTILS
//------ Folger 11/05/07 IMPROVE_XF_DYNADLG_SHOW_CONTROL
typedef bool (*FUNC_PAGE_REF_INT_REF_BOOL)(Page &pg, int &n, bool bGet = true);
//------ Folger 12/11/08 QA80-12764 v8.0985 MODIFY_PEAKS_IN_PA_DURING_CHANGE_PARAMETER_MAKE_ORIGIN_LOCK
typedef bool (*FUNC_PAGE_REF_INT_REF_BOOL_BOOL)(Page &pg, int &n, bool bGet = true, bool b2nd= false);
//------

//------ Folger 12/25/07 NO_NEED_TO_SPECIFY_SHOW_AND_REDRAW_STATUS
//bool page_set_xf_dynadlg_storage(Page &pg, int nHwnd, int nShow, int nRedraw)
bool page_set_xf_dynadlg_storage(Page &pg, int nHwnd)
//------
{
	FUNC_PAGE_REF_INT_REF_BOOL pfnHwnd = Project.FindFunction("xf_dynadlg_hwnd_control", "OriginLab\\xfdynadlg_utils.c");
	//------ Folger 12/11/08 QA80-12764 v8.0985 MODIFY_PEAKS_IN_PA_DURING_CHANGE_PARAMETER_MAKE_ORIGIN_LOCK
	//FUNC_PAGE_REF_INT_REF_BOOL pfnShow = Project.FindFunction("xf_dynadlg_shown_control", "OriginLab\\xfdynadlg_utils.c");
	FUNC_PAGE_REF_INT_REF_BOOL_BOOL pfnShow = Project.FindFunction("xf_dynadlg_shown_control", "OriginLab\\xfdynadlg_utils.c");
	//------ End MODIFY_PEAKS_IN_PA_DURING_CHANGE_PARAMETER_MAKE_ORIGIN_LOCK
	FUNC_PAGE_REF_INT_REF_BOOL pfnRedraw = Project.FindFunction("xf_dynadlg_redraw_control", "OriginLab\\xfdynadlg_utils.c");
	//------ Folger 12/25/07 NO_NEED_TO_SPECIFY_SHOW_AND_REDRAW_STATUS
	int nShow = 0, nRedraw = 1;
	if ( nHwnd < 0 )
	{
		nShow = nRedraw = -1;
	}
	else
	{
		HWND hwnd = (HWND) nHwnd;
		Window wnd(hwnd);
		if ( wnd )
			nShow = wnd.Visible;
	}
	//------
	bool bRetHwnd = false, bRetShow = false, bRetRedraw = false;
	if (pfnHwnd && pfnShow && pfnRedraw)
	{
		bRetHwnd = pfnHwnd(pg, nHwnd, false);
		bRetShow = pfnShow(pg, nShow, false);
		bRetRedraw = pfnRedraw(pg, nRedraw, false);
	}
	return bRetHwnd && bRetShow && bRetRedraw;
}
//------ Folger 12/11/08 QA80-12764 v8.0985 MODIFY_PEAKS_IN_PA_DURING_CHANGE_PARAMETER_MAKE_ORIGIN_LOCK
/*
bool page_xf_dynadlg_shown_control(Page &pg, int &nShow, bool bGet)		//bGet = true
{
	FUNC_PAGE_REF_INT_REF_BOOL pfn = Project.FindFunction("xf_dynadlg_shown_control", "OriginLab\\xfdynadlg_utils.c");
	if (pfn)
		return pfn(pg, nShow, bGet);		
	return false;
}
*/
bool page_xf_dynadlg_shown_control(Page &pg, int &nShow, bool bGet, bool bMinimizedBeforeHidden/* = false*/)		//bGet = true
{
	FUNC_PAGE_REF_INT_REF_BOOL_BOOL pfn = Project.FindFunction("xf_dynadlg_shown_control", "OriginLab\\xfdynadlg_utils.c");
	if (pfn)
		return pfn(pg, nShow, bGet, bMinimizedBeforeHidden);
		
	return false;
}
//------ End MODIFY_PEAKS_IN_PA_DURING_CHANGE_PARAMETER_MAKE_ORIGIN_LOCK
//------ End IMPROVE_XF_DYNADLG_SHOW_CONTROL
///---Sim 12-07-2007 SAVE_REDRAW_STATUS_WHEN_SET_REDRAW
bool page_xf_dynadlg_redraw_flag_control(Page &pg, int &nRedraw, bool bGet) // = true
{
	FUNC_PAGE_REF_INT_REF_BOOL pfn = Project.FindFunction("xf_dynadlg_redraw_control", "OriginLab\\xfdynadlg_utils.c");
	if (pfn)
		return pfn(pg, nRedraw, bGet);
	return false;
}
///---END SAVE_REDRAW_STATUS_WHEN_SET_REDRAW
///---Sim 12-18-2007 SPECIFY_ACTIVE_PAGE_AFTER_XF_WIZ_FINISH
typedef bool (*FUNC_PAGE_REF_UINT_DWORD_DWORD)(Page &pg, uint msg, DWORD wParam = 0, DWORD lParam = 0);

static bool _page_xf_dynadlg_send_msg(Page &pg, uint msg, DWORD wParam, DWORD lParam) // = 0, 0
{
	FUNC_PAGE_REF_UINT_DWORD_DWORD pfn = Project.FindFunction("xf_dynadlg_send_msg", "OriginLab\\xfdynadlg_utils.c");
	if (pfn)
		return pfn(pg, msg, wParam, lParam);
	return false;
}

bool page_xf_dynadlg_set_active_sheet_after_finish(Page &pg, Layer &layActive)
{
	Datasheet ds = layActive;
	if ( !ds )
		return false;
	
	DataRange dr;
	dr.Add(ds, 0, "Range1", -1);
	
	string str = dr.GetDescription();
	
	return _page_xf_dynadlg_send_msg(pg, WM_USER_NOTIFY_ACTIVE_PAGE, (DWORD)(const void*)(LPCSTR)str, 0);
}
///---END SPECIFY_ACTIVE_PAGE_AFTER_XF_WIZ_FINISH
///---Sim 03-14-2008 ALLOW_DESTROY_ATTACHED_PAGE
bool page_xf_dynadlg_destroy_created_page(Page &pg, bool bDestroy)// = true
{
	return _page_xf_dynadlg_send_msg(pg, WM_USER_DESTROY_CREATED_PAGE, (DWORD)(const void*)bDestroy, 0);
}
///---END ALLOW_DESTROY_ATTACHED_PAGE

//------ Folger 01/22/08 INDICATE_WHETHER_XF_EVENT_HANDLE_NEEDED
bool	page_xf_trivial_event_handle_needed(const Page &pg)
{
	return _page_xf_dynadlg_send_msg(pg, WM_USER_WIZ_DLG_XF_EVENT_HANDLE_NEEDED, 0, 0);
}
//------

//------ Folger 11/17/07 IS_USE_ORIGIN_CHM
bool is_use_origin_chm()
{
	/// according to Echo, Japanese Origin.chm is ready and should be able to access
	//return (get_current_language() == ORESLANG_ENGLISH);
	/// Shirley told me that now Origin.chm of all versions are ready to be used for XFs
	//return (get_current_language() == ORESLANG_ENGLISH || get_current_language() == ORESLANG_JAPANESE);
	return TRUE;
}
//------ End IS_USE_ORIGIN_CHM

///Arvin 11/30/07 WRONG_CURVES_COLOR_FOR_REPLICA_IN_SOURCE_GRAPH
bool set_color_by_group_plots(GraphLayer& gl, int nStartPlot, int nEndPlot, int nStartColor)
{
	if(!gl || nStartColor<0)
		return false;
	
	if(nStartPlot > nEndPlot)
	{
		int nn;
		SWAP(nStartPlot, nEndPlot, nn);
	}
	
	/// Hong 04/18/08 v8.0846 FIX_RUNTIME_ERROR_BY_WEAKNESS_CODE
	//gl.GroupPlots(nStartPlot,nEndPlot); 
	if ( !gl.GroupPlots(nStartPlot,nEndPlot) )
		return false;
	/// end FIX_RUNTIME_ERROR_BY_WEAKNESS_CODE
	GroupPlot gPlot = gl.Groups(0); 
	if(gPlot)
	{
		// first we want to make sure that line color is incremented
		vector<int> vv;
		vv = gPlot.Increment.Nester.nVals;
		vector<uint> vRemp;
		vv.Find(vRemp, 0); // look if line color (0) is already there
		if( vRemp.GetSize() == 0 ) //line color is not incremented
		{
			vv.Add(0); // add line color
			gPlot.Increment.Nester.nVals = vv; // assign back to nester
		}       
		// now modify incrementor such that colors are nice
		vector<int> vColors;
		int nEndColor = nStartColor + (nEndPlot - nStartPlot);
		vColors.Data(nStartColor, nEndColor);
		gPlot.Increment.LineColor.nVals = vColors;
		return true;
	}
	
	return false;
}
///end WRONG_CURVES_COLOR_FOR_REPLICA_IN_SOURCE_GRAPH

//------ Folger 12/05/07 SHOULD_NOT_COPY_UNKNOWN_TEMPLATE_FILE_TO_UFF
//we treat subfolder of UFF as "(Unknown)", not "(User)"

string	template_composite_name_from_file_path(LPCSTR lpcszFullFilePath, LPCSTR lpcszSubPath)
{
	int nPathType = template_get_origin_path_type( lpcszFullFilePath );
	return okutil_composite_name_from_components( nPathType, NULL, GetFileName(lpcszFullFilePath, true) );
}

int 	template_get_origin_path_type(LPCSTR lpcszFilePath, BOOL bPreferUser)
{
	///---Sim 05-20-2009 QA80-13612 MOVE_TEMPLATE_UTILS_FROM_OC_TO_VC
	/*
	string strTmp = GetFilePath(lpcszFilePath);
	strTmp.MakeUpper();
	string strUser = okutil_get_origin_path(ORIGIN_PATH_USER);
	strUser.MakeUpper();
	if ( strTmp.CompareNoCase( okutil_get_origin_path(ORIGIN_PATH_GROUP) ) != 0 &&
		strTmp.Replace(strUser, "" ) > 0 && !strTmp.IsEmpty() )
		return ORIGIN_PATH_UNDEF;
	return okutil_get_origin_path_type( lpcszFilePath, bPreferUser );
	*/
	return okutil_template_get_origin_path_type(lpcszFilePath, bPreferUser);
	///---END QA80-13612 MOVE_TEMPLATE_UTILS_FROM_OC_TO_VC
}

//------

//---- CPY 5/5/09 QA70-8941 AUTOSIZE_CODE_CENTRALIZING
/*
//---- CPY 12/16/2007 moved from wksOperation CPY RVD 8/9/05 LIMIT_AUTOSIZ_ROWCOL
static int _cvt_double_to_percent_check_sign(double dd)
{
	if(dd < 0)
		return -1;
	
	return dd * 100. + 0.5;
}
void autosize_rowcol(OriginObject& obj, double dminCol, double dmaxCol, double dminRow, double dmaxRow, DWORD dwCntrl, int nMarginH, int nMarginW)
{
	OGRIDLIMITS limits;
	limits.col.nMin = _cvt_double_to_percent_check_sign(dminCol);
	limits.col.nMax = _cvt_double_to_percent_check_sign(dmaxCol);
	limits.row.nMin = _cvt_double_to_percent_check_sign(dminRow);
	limits.row.nMax = _cvt_double_to_percent_check_sign(dmaxRow);
	//---- CPY 12/17/2007 QA70-8941 v8.0771 AUTOSIZE_OPTIONS
//---- CPY 3/7/08 WAUTOSIZE_ALLOW_SEL_ROW_COL
//	limits.col.nCount=limits.col.nMargin=limits.col.dwCntrl=0;
//	limits.row.nCount=limits.row.nMargin=limits.row.dwCntrl=0;
	limits.col.nCount=limits.col.dwCntrl=0;
	limits.row.nCount=limits.row.dwCntrl=0;
	limits.col.nMargin = nMarginW;
	limits.row.nMargin = nMarginH;
//--- end WAUTOSIZE_ALLOW_SEL_ROW_COL
	//----
	obj.AutoSize(dwCntrl, 0, &limits);
}
*/
///---Sim 12-28-2009 QA81-14895 SPEED_UP_81_IMP_WIZ_ASC
//void autosize_rowcol(OriginObject& obj, double dminCol, double dmaxCol, double dminRow, double dmaxRow, DWORD dwCntrl, int nMarginH, int nMarginW, int nColCounts)
void autosize_rowcol(OriginObject& obj, double dminCol, double dmaxCol, double dminRow, double dmaxRow, DWORD dwCntrl, int nMarginH, int nMarginW, int nColCounts,
					///---Sim 12-29-2009 QA81-14148 REDO_AUTOSIZE_BETTER_HEIGHT_FOR_LABEL
					//DWORD dwCntrlCol, DWORD dwCntrlRow, const vector<int> &vnLabelTypesToSkip)
					DWORD dwCntrlCol, DWORD dwCntrlRow,
					const vector<int> &vnSpecificLabelTypes, bool bSkipSpecificLabel, bool bLabelOnly)
					///---END QA81-14148 REDO_AUTOSIZE_BETTER_HEIGHT_FOR_LABEL
///---END QA81-14895 SPEED_UP_81_IMP_WIZ_ASC
{
	OGRIDLIMITS limits;
	init_autosize_limits(&limits, dminCol, dmaxCol, dminRow, dmaxRow);
	limits.col.nMargin = nMarginW;
	limits.row.nMargin = nMarginH;
	limits.col.nCount = nColCounts;
	///---Sim 12-28-2009 QA81-14895 SPEED_UP_81_IMP_WIZ_ASC
	limits.col.dwCntrl = dwCntrlCol;
	limits.row.dwCntrl = dwCntrlRow;
	///---Sim 12-29-2009 QA81-14148 REDO_AUTOSIZE_BETTER_HEIGHT_FOR_LABEL
	//if ( vnLabelTypesToSkip )
	//{
		//limits.labelsToSkip.pnTypes = vnLabelTypesToSkip;
		//limits.labelsToSkip.nCount = vnLabelTypesToSkip.GetSize();
	//}	
	limits.bLabelOnly = bLabelOnly;
	if ( vnSpecificLabelTypes )
	{
		limits.speclabels.labels.pnTypes = vnSpecificLabelTypes;
		limits.speclabels.labels.nCount = vnSpecificLabelTypes.GetSize();
		limits.speclabels.bSkip = bSkipSpecificLabel;
	}	
	///---END QA81-14148 REDO_AUTOSIZE_BETTER_HEIGHT_FOR_LABEL
	///---END QA81-14895 SPEED_UP_81_IMP_WIZ_ASC
	obj.AutoSize(dwCntrl, 0, &limits);
}
//---- end AUTOSIZE_CODE_CENTRALIZING

/// Hong 01/04/08 QA80-10901 ADD_MANIPUTATE_IN_BOOK_LEVEL
/* //CPY 1/5/08, I moved code directly to Workbook.h
bool page_reorder_sheets_by_name(WorksheetPage& wp, BOOL wOrder, int nFromSheet, int nToSheet) // = SORT_ASCENDING, = 0,  = -1
{
	if ( !wp )
		return false;
	
	vector<string> vsSheetNames;
	int nIndex = -1;
	foreach (Layer ly in wp.Layers)
	{
		Datasheet ds(ly);
		nIndex++;
		if ( nIndex < nFromSheet )
			continue;
		if ( -1 != nToSheet && nIndex >= nToSheet )
			break;
		
		vsSheetNames.Add(ds.m_strBookSheet);		
	}
	vsSheetNames.Sort(wOrder);
	
	for (int ii = 0; ii < vsSheetNames.GetSize(); ii++)
	{
		Worksheet wks(vsSheetNames[ii]);
		wks.SetIndex(ii); //CPY 1/5/08. should add nFromSheet here
	}
	
	return true;
}

bool page_insert_layer(WorksheetPage& wp, int& nBefore, LPCSTR lpcszLayerName, DWORD dwOptions, LPCSTR lpcszTemplate) // = NULL,  = 0, = NULL
{
	if ( !wp )
		return false;
	
	int nIndex = wp.AddLayer(lpcszLayerName, dwOptions, lpcszTemplate);	
	if ( nBefore < 0 || nBefore >= wp.Layers.Count() )
		nBefore = nIndex;			
	Worksheet wks = wp.Layers(nIndex);	
	wks.SetIndex(nBefore);
	// SetIndex will NOT active worksheet if index not changed
	page_set_active_layer(wp, nBefore, false);
	
	return true;
}*/
/// end ADD_MANIPUTATE_IN_BOOK_LEVEL

///---Sim 01-17-2007 QA80-10952 MULTI_SHEET_RANGE
SheetRangesList::SheetRangesList(const DataRange &dr)
{
	dr.Clone(m_dr);

	int ii;
	Datasheet ds;
	int r1, c1, r2, c2; // temp variable, only for function prototype, not used
	for ( ii = 0; ii < m_dr.GetNumRanges(); ii++ )
	{
		if( m_dr.GetRange(ii, r1, c1, r2, c2, ds)) // only Sheet used
		{
			if ( ds )
			{
				m_vnIDs.Add(ds.GetUID());
				continue;
			}
		}	
		m_vnIDs.Add(0); // invalid uid
	}
	
	// m_vnIDs will be sorted, but dr will not. vnIndeces is such index vector for get unsorted sub ranges info.
	if ( m_vnIDs.GetSize() > 1 )
	{
		if(!m_vnIDs.Sort(SORT_ASCENDING, true, m_vnIndeces))
		{
			//return false;
			error_report("Should not come here, vector uint array sort failed!")
		}
	}
	else
	{
		// size is 1, will failed to sort.
		m_vnIndeces.Add(0);
	}

	m_nNumSheets = 0;
	// invalid uid (0) all are in the front of UID array,
	// so they will be skipped before find first valid datasheet uid.
	uint uID = 0; // invalid uid
	for ( ii = 0; ii < m_vnIDs.GetSize(); ii++ )
	{
		if ( m_vnIDs[ii] != uID )
		{
			m_nNumSheets++;
			m_vnOffsetSheets.Add(ii);
			uID = m_vnIDs[ii];
		}
	}
	// for last datasheet get ending bound
	m_vnOffsetSheets.Add(m_vnIDs.GetSize());
	
}
int SheetRangesList::GetNumSheets()
{
	return m_nNumSheets;
}
int SheetRangesList::GetNumSubRange(int nSheetIndex)
{
	if ( nSheetIndex < 0 || nSheetIndex >= m_nNumSheets )
		return -1;
	return m_vnOffsetSheets[nSheetIndex+1] - m_vnOffsetSheets[nSheetIndex];
}
int SheetRangesList::GetSubRangeIndex(int nSheetIndex, int nSheetSubRangeIndex)
{
	if ( nSheetIndex < 0 || nSheetIndex >= m_nNumSheets )
		return -1;

	if ( nSheetSubRangeIndex < 0 || nSheetSubRangeIndex >= GetNumSubRange(nSheetIndex) )
		return -1;
	
	return m_vnIndeces[m_vnOffsetSheets[nSheetIndex] + nSheetSubRangeIndex];
}
bool SheetRangesList::GetRange(int nSheetIndex, Datasheet& ds, int nSheetSubRangeIndex, ORANGE* pRange) // = 0, NULL
{
	int nRangeIndex = GetSubRangeIndex(nSheetIndex, nSheetSubRangeIndex);
	if ( nRangeIndex < 0 )
		return false;
	
	int nR1, nC1, nR2, nC2;
	if ( !m_dr.GetRange(nRangeIndex, nR1, nC1, nR2, nC2, ds) )
		return false;
	///Kyle 08/14/2009 QA80-14136 FIX_COL_STATS_CAN_NOT_GIVE_RESULT_WHEN_SELECTING_WHOLE_ROWS
	if(nC2 == -1)
		nC2 = ds.GetNumCols() - 1;
	if(nR2 == -1)
		nR2 = ds.GetNumRows() -1;
	///End FIX_COL_STATS_CAN_NOT_GIVE_RESULT_WHEN_SELECTING_WHOLE_ROWS
	
	if ( NULL != pRange )
	{
		pRange->r1 = nR1;
		pRange->c1 = nC1;
		pRange->r2 = nR2;
		pRange->c2 = nC2;
	}
	
	return true;
}
///---END QA80-10952 MULTI_SHEET_RANGE

//------ Folger 02/14/08 QA80-10946 SUPPORT_GET_SUB_RANGE_PER_SHEET
bool	SheetRangesList::GetWksSubRange(int nSheetIndex, DataRange &drSub, Datasheet *pds)
{
	if ( nSheetIndex >= m_nNumSheets )
		return false;
	
	if ( !drSub )
		drSub.Create();
	
	/// EJP 2010-06-15 ORG-259 CONTEXT_MENU_FOR_MATRIX_THUMBNAILS
	///Worksheet wks;
	Datasheet wks;
	/// end CONTEXT_MENU_FOR_MATRIX_THUMBNAILS
	for ( int ii=m_vnOffsetSheets[nSheetIndex]; ii<m_vnOffsetSheets[nSheetIndex+1]; ++ii )
	{
		int nR1, nC1, nR2, nC2;
		if ( !m_dr.GetRange(m_vnIndeces[ii], nR1, nC1, nR2, nC2, wks) )
			return false;
		drSub.Add("X", wks, nR1, nC1, nR2, nC2);
	}
	
	if ( pds != NULL)
		*pds = wks;
	
	return true;
}
//------

void format_report_table(TreeNode& trTable, bool bTranspose, bool bHideHeader, bool bAutoFit)// = false,  = true,  = true
{
	int nTableFormat = GETNBRANCH_OPEN;
	
	if(bTranspose)
		nTableFormat |= GETNBRANCH_TRANSPOSE;
	
	if(bHideHeader)
		nTableFormat |= GETNBRANCH_HIDE_COL_HEADINGS| GETNBRANCH_HIDE_ROW_HEADINGS;
	
	if(bAutoFit)
		nTableFormat |= GETNBRANCH_FIT_COL_WIDTH | GETNBRANCH_FIT_ROW_HEIGHT;
	
	trTable.SetAttribute("TABLE", nTableFormat);
	
}


bool prepare_report_sheet(Worksheet& wks, LPCSTR lpcszSheetName) // = NULL
{
	WorksheetPage wksPage;
	wksPage.Create();
	
	DWORD dwOptions = WP_SHEET_HIERARCHY | CREATE_NO_DEFAULT_TEMPLATE;
		
	int nn = wksPage.AddLayer(lpcszSheetName, dwOptions); 
	
	if( nn >=0 )
	{
		wks = wksPage.Layers(nn);
		wksPage.Layers(0).Delete();
		return true;
	}
	
	return false;
}

/// Iris 3/26/2008 v8.0832 CLEANUP_OUTPUT_BOOK_SHEET_AREA_TO_CLASS
// moved from event_utils
string get_sheets_in_book(const Page& pg, int nSheetType )
{
	if(!pg)
		return "";
	string strNameList, strRpsheetList;
	if(WKS_REPORT_TABLE != nSheetType)
		///Sophy 10/29/2008 FIX_FAIL_TO_GET_ALL_SHEETS_WHEN_BOOK_CONTAINS_ONLY_REPORT_SHEET
		//strNameList = page_get_layer_names(pg, false);
		strNameList = page_get_layer_names(pg, true);
		///end FIX_FAIL_TO_GET_ALL_SHEETS_WHEN_BOOK_CONTAINS_ONLY_REPORT_SHEET
	if(WKS_ALL != nSheetType)
		strRpsheetList = get_report_sheets_in_book(pg, 0);
	switch(nSheetType)
	{
	case WKS_REPORT_TABLE:
		return strRpsheetList;
	case WKS_DATA_SHEET:
		if(lstrlen(strNameList) && lstrlen(strRpsheetList))
		{
			vector<string> vsLayers, vsRpsheets;
			strNameList.GetTokens(vsLayers, '|');
			strRpsheetList.GetTokens(vsRpsheets, '|');
			remove_if_in_list(vsLayers, vsRpsheets);
			strNameList.SetTokens(vsLayers, '|');
		}
	}
	return strNameList;	
}

string get_report_sheets_in_book(const Page& pg, int& iActiveSheet)
{
	string strName, strList, strActiveLayer;
	int ii = 0;
	iActiveSheet = -1;
	if( pg )
	{
		strActiveLayer = pg.Layers(-1).GetName();
		foreach( Layer ly in pg.Layers )
		{
			strName = ly.GetName();
			
			if(strName.IsEmpty() ) // cannot output to sheet with no name
				continue;

			if(!(ly.GetSystemParam(0) & WP_SHEET_HIERARCHY))
				continue;
			
			strList += strName;
			strList += STR_TOKEN_SEP;  
			if( strActiveLayer == strName )
				iActiveSheet = ii;
			ii++;
		}
	}
	return strList;
}

void get_project_pages_name(vector<string> &vsPagesName, uint nPageType)
{
	vsPagesName.RemoveAll();
	foreach(PageBase pg in Project.Pages)
	{
		if(pg.GetType() == nPageType)
			vsPagesName.Add(pg.GetName());

	}	
}

/// Iris 4/01/2008 v8.0834 MOVE_GET_SOURCE_PAGE_NAME_TO_PAGE_UTILS, _MOVE_FIT_OUTPUT_TO_OC_CLASS defined in Operation.h
//#ifndef _MOVE_FIT_OUTPUT_TO_OC_CLASS 	/// Iris 3/26/2008 v8.0832 CLEANUP_OUTPUT_BOOK_SHEET_AREA_TO_CLASS
//string get_source_page_name(TreeNode& trGUI, string *pstrLayerName, bool bIsNLFitOutputEvent)
//#else
///end MOVE_GET_SOURCE_PAGE_NAME_TO_PAGE_UTILS
string get_source_page_name(TreeNode& trGUI, string *pstrLayerName, TreeNode& trInput)
//#endif //_MOVE_FIT_OUTPUT_TO_OC_CLASS  	/// Iris 4/01/2008 v8.0834 MOVE_GET_SOURCE_PAGE_NAME_TO_PAGE_UTILS
{	
	string	strName;	
/// Iris 4/01/2008 v8.0834 MOVE_GET_SOURCE_PAGE_NAME_TO_PAGE_UTILS, _MOVE_FIT_OUTPUT_TO_OC_CLASS defined in Operation.h
//#ifndef _MOVE_FIT_OUTPUT_TO_OC_CLASS 
	//TreeNode trRootNode;
	//if(bIsNLFitOutputEvent)
		//trRootNode = trGUI.Parent();
	//else
		//trRootNode = trGUI;
	//TreeNode trInputData = tree_get_node_by_tagname(trRootNode, "InputData");
//#else
///end MOVE_GET_SOURCE_PAGE_NAME_TO_PAGE_UTILS
	TreeNode trInputData;
	if( trInput )
		trInputData = trInput;
//#endif //_MOVE_FIT_OUTPUT_TO_OC_CLASS  	/// Iris 4/01/2008 v8.0834 MOVE_GET_SOURCE_PAGE_NAME_TO_PAGE_UTILS
	if( !trInputData )
		trInputData = tree_get_node_by_tagname(trGUI, "InputData", true);	  
	if(trInputData)
	{
		is_range_from_normal_book(trInputData, &strName, pstrLayerName);
	}
	return strName;	
}
///end MOVE_GET_SOURCE_PAGE_NAME_TO_PAGE_UTILS

bool	get_graph_layer_by_plot_uid(GraphLayer& gl, DWORD dwPlotUID)
{
	DataPlot	dp;
	dp	= (DataPlot)Project.GetObject((int)dwPlotUID);
	if(dp)
	{
		dp.GetParent(gl);
		if(gl)
			return true;
	}
	return false;
}

//---- CPY 7/27/08 QA70-11868 CHANGE_BACK_TO_USE_CRLF_TO_SEP_LN_COMMENT
/*
//------ Folger 07/24/08 BETTER_XF_OPERATION_OUTPUT_COMMENTS
string	get_input_data_range_string(DataRange &inputRange)
{
	if ( !inputRange )
	{
		ASSERT(false);
		return "";
	}

	string strRange;
	inputRange.GetRangeString(strRange, NTYPE_BOOKSHEET_XY_RANGE);
	return _L("Input") + ": " + strRange;
}
//------ End BETTER_XF_OPERATION_OUTPUT_COMMENTS
*/
string	get_input_data_range_string(DataRange &inputRange)
{
	if ( !inputRange )
	{
		ASSERT(false);
		return "";
	}
	///------ Folger 07/31/09 QA80-11867-P1 ANALYSIS_OUTPUT_COMMENTS_FAIL_FOR_LOOSE_DATASET_INPUT
	//return inputRange.GetDescription(GETLC_COL_LN_ONLY);
	return inputRange.GetDescription(GETLC_COL_LN_ONLY | GETLC_INCLUDE_LOOSE_DATA);
	///------ End ANALYSIS_OUTPUT_COMMENTS_FAIL_FOR_LOOSE_DATASET_INPUT
}
//------ end CHANGE_BACK_TO_USE_CRLF_TO_SEP_LN_COMMENT

///Kyle 03/26/2009 ADD_UTIL_FUNCTION_TO_GET_DESCRIPTION_FROM_XYRANGE
string get_xy_range_string(const XYRange& irng, string strDesignations, int nIndex)
{
	if(!irng)
	{
		ASSERT(false);
		return "";
	}

	Column col;
	if(strDesignations.FindOneOf("Yy") == 0)
		irng.GetYColumn(col, nIndex);
	else if(strDesignations.FindOneOf("Xx") >= 0)
		irng.GetXColumn(col, nIndex);
	else if(strDesignations.FindOneOf("Ee") == 0 || strDesignations.FindOneOf("Ww"))
		irng.GetErrColumn(col, nIndex);

	string strDescription;
	if(col)
	{
		int nColIndex = col.GetIndex();
		Datasheet ds;
		col.GetParent(ds);
		DataRange dr;
		dr.Add(ds, nColIndex, "Y", nColIndex);
		strDescription = get_input_data_range_string(dr);
	}
	return strDescription;
}
///End ADD_UTIL_FUNCTION_TO_GET_DESCRIPTION_FROM_XYRANGE

///Sophy 11/21/2008 v8.976 QA80-12591-P3 ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT
int get_source_data_sheet_type(TreeNode& trInput)
{
	if(trInput)
	{
		DataRange rngInput;
		rngInput.Create(trInput, FALSE);	
		if(rngInput)
		{
			Datasheet dsInput;
			rngInput.GetParent(dsInput);
			if(dsInput)
			{
				Page pg = dsInput.GetPage();
				if(pg)
					return pg.GetType();
			}
		}		
	}
	return -1;
}
///end ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT


typedef int (*PAGE_ADD_LAYER_FUNC)(GraphPage&, bool, bool, bool, bool, int, bool, int, int, int, int*, int*, int*, int*, int*, int, LPCSTR);
int	graph_add_layer(GraphPage& gp, bool bBottom/* = true*/, bool bLeft/* = true*/, bool bTop/* = false*/, bool bRight/* = false*/, 
					bool bAutoOffset/* = true*/,
					int nLinkTo/* = -1*/)
{
	PAGE_ADD_LAYER_FUNC pfun = Project.FindFunction("page_add_layer", "Originlab\graph_utils.c", true);
	if(pfun)
	{
		int 	nAutoInitSizePosition = bAutoOffset? ADD_LAYER_INIT_SIZE_POS_MOVE_OFFSET : ADD_LAYER_INIT_SIZE_POS_SAME_AS_PREVIOUS;
		bool 	bActivateNewLayer = true;
		return pfun(gp, bBottom, bLeft, bTop, bRight, nAutoInitSizePosition, bActivateNewLayer, nLinkTo, LINK_NONE, LINK_NONE, NULL, NULL, NULL, NULL, NULL, -1, NULL);
	}
	return -1;
}

/// Iris 7/14/2009 QA80-13941 SUPPORT_MORE_OPTIONS_FOR_WREPLACE_AND_MREPLACE_XF
///------ Folger 11/02/09 QA81-14522 SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
//bool get_sheet_selection(Datasheet& ds, DataRange& dr)
bool get_sheet_selection(Datasheet& ds, DataRange& dr, BOOL bCheckLabelRows/* = FALSE*/)
///------ End SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
{
	bool bRet = ds.IsValid();
	if ( bRet )
	{
		vector<int> vr1, vc1, vr2, vc2;
		Grid gg;
		int nTotalRange = 0;
		if ( gg.Attach(ds) )
		{
			///------ Folger 11/02/09 QA81-14522 SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
			//int nRegions = gg.GetSelection(vr1, vc1, vr2, vc2);
			int nRegions = gg.GetSelection(vr1, vc1, vr2, vc2, bCheckLabelRows);
			///------ End SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
			for (int ii = 0; ii < nRegions; ++ii)
			{
				int nNumRanges = dr.Add("Range" + ii, ds, vr1[ii], vc1[ii], vr2[ii], vc2[ii]);
				if ( nNumRanges > 0 )
					nTotalRange += nNumRanges;
			}
		}
		bRet &= (nTotalRange > 0);
	}
	return bRet;
}

bool	is_matrix_sheet(Datasheet& ds)
{
	if ( ds.IsValid() )
	{
		const bool bIsMatrixType = ( EXIST_MATRIX == ds.GetPage().GetType() );
		return bIsMatrixType;
	}
	return false;
}

int get_matrix_active_object_index(Datasheet& ds)
{
	int nIndex = -1;
	if ( is_matrix_sheet(ds) )
	{
		MatrixLayer ml(ds);
		MatrixObject mo = ml.MatrixObjects();
		nIndex = mo.GetIndex();
	}
	return nIndex;
}

///------ Folger 11/02/09 QA81-14522 SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
//bool get_active_sheet_range(Datasheet& ds, int* pnMatrixObjectIndex/* = NULL*/, DataRange* pDataRange/* = NULL*/)
bool get_active_sheet_range(Datasheet& ds, int* pnMatrixObjectIndex/* = NULL*/, DataRange* pDataRange/* = NULL*/, BOOL bCheckLabelRows/* = FALSE*/)
///------ End SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
{
	bool bRet = true;
	ds = Project.ActiveLayer();
	bRet = ds.IsValid();
	if ( pnMatrixObjectIndex )
	{
		*pnMatrixObjectIndex = get_matrix_active_object_index(ds);
	}
	if ( pDataRange )
	{
		///------ Folger 11/02/09 QA81-14522 SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
		//bRet &= get_sheet_selection(ds, *pDataRange);
		bRet &= get_sheet_selection(ds, *pDataRange, bCheckLabelRows);
		///------ End SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
	}
	return bRet;
}

///------ Folger 11/02/09 QA81-14522 SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
//bool	get_active_sheet_range_ex(DataRange& dr, bool bPerformInSelectedRange/* = false*/, Datasheet* pDatasheet/* = NULL*/, bool bGetActiveMatrixObjectOnly/* = true*/)
bool	get_active_sheet_range_ex(DataRange& dr, bool bPerformInSelectedRange/* = false*/, Datasheet* pDatasheet/* = NULL*/, bool bGetActiveMatrixObjectOnly/* = true*/, BOOL bCheckLabelRows/* = FALSE*/)
///------ End SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
{
	Datasheet ds;
	int nMatrixObjectIndex = -1;
	bool bRet = get_active_sheet_range(ds, &nMatrixObjectIndex);
	if ( pDatasheet )
	{
		*pDatasheet = ds;
	}
	if ( !bRet )
	{
		ASSERT(FALSE);
		return false;
	}
	
	if ( bPerformInSelectedRange )
	{
		///------ Folger 11/02/09 QA81-14522 SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
		//bRet = get_sheet_selection(ds, dr);
		bRet = get_sheet_selection(ds, dr, bCheckLabelRows);
		///------ End SUPPORT_FIND_REPLACE_STR_IN_LABEL_ROWS
	}
	else
	{
		int nR1 = 0;
		int nR2 = -1;
		int nC1, nC2;
		if ( is_matrix_sheet(ds) && bGetActiveMatrixObjectOnly )
		{
			nC1 = nC2 = nMatrixObjectIndex;
		}
		else
		{
			nC1 = 0;
			nC2 = -1;
		}
		int nNumRanges = dr.Add("Range1", ds, nR1, nC1, nR2, nC2);
		bRet = (nNumRanges > 0);
	}
	return bRet && dr.IsValid();
}
///end SUPPORT_MORE_OPTIONS_FOR_WREPLACE_AND_MREPLACE_XF

///------ Folger 08/10/09 GENERAL_COLUMN_COPY_UTILS_NEEDED_IN_OC
/// move from colcopy.oxf
static void _col_copy_parameter_label(const Column &ccSrc, Column &ccDes, int nTypeSrc, int nTypeDes, const vector<int>& vnTypesSrc, vector<int>& vnTypesDes)
{
	string strLabel;
	ccSrc.GetExtendedLabel(strLabel, nTypeSrc);
	ccDes.SetExtendedLabel(strLabel, nTypeDes);

	vector<uint>	vnIndices;
	if ( vnTypesSrc.Find(vnIndices, nTypeSrc) > 0 )
	{
		if ( vnTypesDes.Find(vnIndices, nTypeDes) <= 0 )
			vnTypesDes.Add(nTypeDes);
	}
}

///------ Folger 11/17/09 QA81-11105 COPY_COL_SUPPORT_UDLS
class UDLMergeHelper
{
public:
	UDLMergeHelper(Worksheet& wksDes, Worksheet& wksSrc)
	{
		MergeUDLs(wksDes, wksSrc);
	}

	vector<int>&	GetLabelTypes()
	{
		return m_vnTypes;
	}

private:

	void	GetUDLs(vector<string>& vs, Worksheet& wks)
	{
		Grid	grid;
		if ( grid.Attach(wks) && grid )
		{
			grid.GetUserDefinedLabelNames(vs);
		}
	}
	
	void	SetUDLs(const vector<string>& vs, Worksheet& wks)
	{
		Grid	grid;
		if ( grid.Attach(wks) && grid )
		{
			grid.SetUserDefinedLabelNames(vs);
		}
	}

	void	MergeUDLs(Worksheet& wksDes, Worksheet& wksSrc)
	{
		vector<string>	vsUDLDes;
		vector<string>	vsUDLSrc;
		GetUDLs(vsUDLDes, wksDes);
		GetUDLs(vsUDLSrc, wksSrc);

		for ( int ii=0; ii<vsUDLSrc.GetSize(); ++ii )
		{
			int		nIndex = -1;
			if ( (nIndex = vsUDLDes.Find(vsUDLSrc[ii])) < 0 )
			{
				nIndex = vsUDLDes.Add(vsUDLSrc[ii]);
			}
			m_vnTypes.Add(nIndex);
		}

		SetUDLs(vsUDLDes, wksDes);
		if ( m_vnTypes.GetSize() > 0 )
			m_vnTypes += RCLT_UDL;
	}

private:
	vector<int>		m_vnTypes;
};
///------ End COPY_COL_SUPPORT_UDLS

bool	copy_col(Column ccSc, Column ccTg, DWORD dwOptions/* = 0*/)
{
	Worksheet	wksSc, wksTg;
	ccSc.GetParent(wksSc);
	ccTg.GetParent(wksTg);	
	
	if( O_QUERY_BOOL(dwOptions, COPY_COL_FORMAT) )
	{
		///Kyle 10/10/2009 QA80-14437-P2 USE_CENTRALIZED_CODE_TO_COPY_COLUMN_DESIGNATION_AND_FORMAT
		/*
		Tree trFmt, trTgFmt;
		trFmt = ccSc.GetFormat(FPB_ALL, FOB_ALL, true, true);		
		trTgFmt = ccTg.GetFormat(FPB_ALL, FOB_ALL, true, true);
		TreeNode trProp = trFmt.Root;
		TreeNode trTgProp = trTgFmt.Root;
		octree_copy_values_by_id(&trProp, &trTgProp, true, STR_ID_ATTRIB, STR_ID_ATTRIB);
		octree_delete_nodes_by_missing_attribute(&trTgProp, STR_CHANGED_ATTRIB);				
		if(trTgProp.Format.IsValid() && trTgProp.InternalData.IsValid())
		{
			if(trTgProp.Format.nVal != OKCOLTYPE_NUMERIC)
			{
				trTgProp.InternalData.Remove(); // this is later in the theme tree, so we must remove otherwise it will set col back to Numeric
			}
		}
		//TreeNode trRoot = trFmt.Root;
		if(trTgProp.ShortName)
			trTgProp.ShortName.Remove();
		if(trTgProp.LongName)
			trTgProp.LongName.Remove();
		if(trTgProp.Comment)
			trTgProp.Comment.Remove();
		if(trTgProp.Unit)
			trTgProp.Unit.Remove();
		//------ Folger 10/06/08 QA80-12240 SHOULD_SET_FORMAT_AND_DISPLAY_SEPARATELY_FROM_OTHER_SETTINGS
		if ( trTgProp.NumericDisplay && (trTgProp.Format && OKCOLTYPE_NUMERIC != trTgProp.Format.nVal && OKCOLTYPE_TEXT_NUMERIC != trTgProp.Format.nVal) )
			trTgProp.NumericDisplay.Remove();
		UndoBlock ub;
		if ( trTgProp.Format )
		{
			if ( trTgProp.CustomFormat )
			{
				ccTg.SetCustomDisplay(trTgProp.CustomFormat.strVal);
			}
			ccTg.SetFormat(trTgProp.Format.nVal, trTgProp.Display ? trTgProp.Display.nVal : 0, true);
			trTgProp.Format.Remove();
			if ( trTgProp.Display )
				trTgProp.Display.Remove();
		}
		//------ End SHOULD_SET_FORMAT_AND_DISPLAY_SEPARATELY_FROM_OTHER_SETTINGS
		ccTg.ApplyFormat(trTgFmt, true, true);
		*/
		ccTg.SetType(ccSc.GetType());
		ccTg.CopyDataFormat(ccSc);
		///End USE_CENTRALIZED_CODE_TO_COPY_COLUMN_DESIGNATION_AND_FORMAT
	}
	if( O_QUERY_BOOL(dwOptions, COPY_COL_DATA) )
	{
		///------ Folger 12/23/09 QA81-14881 COLCOPY_LOSE_NUMERIC_PRECISION
		/////Sophy 04/30/2008 v8.0853 FIX_COPY_NUMERIC_FORMAT_COLUMN_FAILURE
		///*
		//Dataset dsS(wksSc, nScCol);
		//vector<string> vs;
		//if(!dsS.GetStringArray(vs))
		//{
			//DataRange deTemp;
			//deTemp.Create();
			//deTemp.Add("X", wksSc, 0, nScCol, -1, nScCol);
			//deTemp.GetData(vs, 0);
		//}
		///// ML 2/6/2007 QA70-9350 PROPER_SETTING_UPPER_INDEX_DEST_COLUMN
		////for(int nRow = 0; nRow < vs.GetSize(); nRow++)
		////	wksTg.SetCell(nRow, nTgCol, vs[nRow]);
		//int		nSize = vs.GetSize();
		//ccTg.SetUpperIndex(nSize - 1);
		//ccTg.PutStringArray(vs, 0, true);
		///// end PROPER_SETTING_UPPER_INDEX_DEST_COLUMN
		//*/
		////------ Folger 09/23/08 QA80-12240 SHOULD_COPY_NUMERIC_VALUES_FOR_COLUMN_DATE_FORMAT
		////if( OKCOLTYPE_NUMERIC == ccSc.GetFormat() ) //copy column with numeric format
		//if( OKCOLTYPE_NUMERIC == ccSc.GetFormat() || OKCOLTYPE_DATE == ccSc.GetFormat() || OKCOLTYPE_TIME == ccSc.GetFormat() ) 
		////------
		//{
			//vectorbase& vbColSc = ccSc.GetDataObject();
			//vectorbase& vbColTg = ccTg.GetDataObject();
			//vbColTg = vbColSc;
		//}
		//else
		//{
			//Dataset dsS(ccSc);
			//vector<string> vs;
			//if(!dsS.GetStringArray(vs))
			//{
				//int		nScCol = ccSc.GetIndex();
				//DataRange deTemp;
				//deTemp.Create();
				//deTemp.Add("X", wksSc, 0, nScCol, -1, nScCol);
				//deTemp.GetData(vs, 0);
			//}
			///// ML 2/6/2007 QA70-9350 PROPER_SETTING_UPPER_INDEX_DEST_COLUMN
			////for(int nRow = 0; nRow < vs.GetSize(); nRow++)
			////	wksTg.SetCell(nRow, nTgCol, vs[nRow]);
			//int		nSize = vs.GetSize();
			//ccTg.SetUpperIndex(nSize - 1);
			//ccTg.PutStringArray(vs, 0, true);
			///// end PROPER_SETTING_UPPER_INDEX_DEST_COLUMN
		//}
		/////end FIX_COPY_NUMERIC_FORMAT_COLUMN_FAILURE
		int		nColIndex = ccSc.GetIndex();
		wksSc.CopyTo(wksTg, nColIndex, nColIndex, 0, -1, ccTg.GetIndex(), -1, CPYT_EXTERN_UPDATE_ORIGIN | CPYT_ALLOW_SAME_LAYER_IF_NOT_INTERSECT);
		///------ End COLCOPY_LOSE_NUMERIC_PRECISION
	}
	//set labels
	vector<int> vnLabelType;
	vnLabelType.Add(O_QUERY_BOOL(dwOptions, COPY_COL_LONGNAME));
	vnLabelType.Add(O_QUERY_BOOL(dwOptions, COPY_COL_UNITS));
	vnLabelType.Add(O_QUERY_BOOL(dwOptions, COPY_COL_COMMENTS));
	//------ Folger 02/18/08 QA80-11105 COPY_COLUMN_NEED_TO_DO_WITH_ADDITIONAL_PARAMETERS
	//vnLabelType.Add(para);
	//for(int nType = RCLT_LONG_NAME; nType <= RCLT_PARAM; nType++)
	//{
		//if(!vnLabelType[nType])
			//continue;
		//string strLabel;
		//ccSc.GetExtendedLabel(strLabel, nType);
		//ccTg.SetExtendedLabel(strLabel, nType);
	//}
	
	Grid gridSc, gridTg;   
	if( !gridSc.Attach(wksSc) || !gridTg.Attach(wksTg) )
		return false;
	
	vector<int> vnTypesSrc;
	vector<int>	vnTypesDes;
	gridSc.GetShowLabels(vnTypesSrc);
	gridTg.GetShowLabels(vnTypesDes);
	
	for ( int nType = RCLT_LONG_NAME; nType <= RCLT_COMMENT; ++nType )
	{
		if ( !vnLabelType[nType] )
			continue;
		_col_copy_parameter_label(ccSc, ccTg, nType, nType, vnTypesSrc, vnTypesDes);
		
	}
	
	if ( O_QUERY_BOOL(dwOptions, COPY_COL_PARAMETERS) )
	{
		for ( int nType = RCLT_PARAM; nType < RCLT_PARAM + PARAMS_MAX_NUM; ++nType )
			_col_copy_parameter_label(ccSc, ccTg, nType, nType, vnTypesSrc, vnTypesDes);
	}

	///------ Folger 11/17/09 QA81-11105 COPY_COL_SUPPORT_UDLS
	if ( O_QUERY_BOOL(dwOptions, COPY_COL_UDL) )
	{
		UDLMergeHelper		clHelper(wksTg, wksSc);
		vector<int>&		vnLabelTypes = clHelper.GetLabelTypes();
		for ( int ii=0; ii<vnLabelTypes.GetSize(); ++ii )
		{
			_col_copy_parameter_label(ccSc, ccTg, ii + RCLT_UDL, vnLabelTypes[ii], vnTypesSrc, vnTypesDes);
		}
	}
	///------ End COPY_COL_SUPPORT_UDLS
	gridTg.SetShowLabels(vnTypesDes);

	/*
	if ( usrdef )
	{
		Grid grid;   
		if(!grid.Attach(wksSc))
			return false;
		
		vector<string> vsUserDefined;
		grid.GetUserDefinedLabelNames(vsUserDefined);
		for ( int ii=0; ii<vsUserDefined.GetSize(); ++ii )
			_col_copy_parameter_label(ccSc, ccTg, RCLT_UDL + ii);
	}
	*/
	//------ End COPY_COLUMN_NEED_TO_DO_WITH_ADDITIONAL_PARAMETERS
	return true;
}
///------ End GENERAL_COLUMN_COPY_UTILS_NEEDED_IN_OC


///Sophy 1/29/2010 QA80-14995-P2 CHECK_UPDATE_REPORT_WORKSHEET_NAME_FOR_ROI_TOOLS
bool	check_update_worksheet_name(string& strBooksheetName)
{
	Worksheet wks(strBooksheetName);
	if ( wks )
		return true;
	
	/// Iris 2/04/2010 IMPROVE_ROI_TOOL_BOOKSHEET_NAME_CHECK
	// If not contain [] in name string, means this string not book sheet name, just book name,
	// For book name, discussed and found very hard to check, so always return true here, if this name
	// is invalid for short name, will auto convert and set original string as long name
	if( strBooksheetName.Find('[') >= 0 && strBooksheetName.Find(']') >= 0 )
	{
	///End IMPROVE_ROI_TOOL_BOOKSHEET_NAME_CHECK	
		string strBook, strSheet;
		if ( !get_book_sheet_names(strBooksheetName, strBook, strSheet) )
			return false;
		
		bool bChanged = okutil_make_valid_wksheet_name(&strSheet);
		strBooksheetName = make_book_sheet_name(strBook, strSheet);
		return !bChanged;
	}
	return true;	
}
///end CHECK_UPDATE_REPORT_WORKSHEET_NAME_FOR_ROI_TOOLS

///---Sim 02-02-2010 QA81-15063 ADD_CUSTOM_PROPERTIES_INTO_WKS_INFO_TREE
//#define SIFI_BINARY_STORAGE_NAME "File"				///Kyle 02/04/2010 READ_COLUMN_INPORT_FILE_INFO, moved to oc_sys.h

bool get_import_file_info(const OriginObject& obj, TreeNode& trInfo, LPCSTR lpcszName)// = NULL
{
	if(!obj.IsValid())
		return error_report("obj is invalid");
	
	Tree tree;
	if ( !obj.GetBinaryStorage(SIFI_BINARY_STORAGE_NAME, tree) )
		return false;
	
	TreeNode tr = tree;
	if ( lpcszName )
	{
		tr =  tree_get_node_by_tagname(tree, lpcszName, true);
	}
	if ( !tr )
		return false;
	
	return trInfo.Replace(tr, true, true);
}
bool set_import_file_info(OriginObject& obj, const TreeNode& trInfo, LPCSTR lpcszName)// = NULL
{
	if(!obj.IsValid())
		return error_report("obj is invalid");
	
	Tree tree;
	obj.GetBinaryStorage(SIFI_BINARY_STORAGE_NAME, tree);
	
	TreeNode tr = tree;
	if ( lpcszName )
	{
		string strTagname = cvt_str_to_tag_name(lpcszName);
		if( strTagname.IsEmpty() )
			return error_report("strName is invalid");		
		tr =  tree_get_node_by_tagname(tree, strTagname, true);
		if(!tr.IsValid())
			tr = tree.AddNode(strTagname);
	}
	tr.Replace(trInfo, TRUE, TRUE);
	
	return obj.PutBinaryStorage(SIFI_BINARY_STORAGE_NAME, tree);
}
///---END QA81-15063 ADD_CUSTOM_PROPERTIES_INTO_WKS_INFO_TREE

int get_selected_data_plot()
{
	GraphLayer gl = Project.ActiveLayer();
	if( !gl )
		return -2; // error
	
	DataPlot dpActive = gl.DataPlots(-1);
	if( dpActive && Selection.IsSelected(dpActive) )
		return dpActive.GetIndex();
		
	foreach(DataPlot dp in gl.DataPlots)
	{
		if( Selection.IsSelected(dp) )
			return dp.GetIndex();
	}	
	return -1; // if not selected data plot, then return active data plot
}

///------ Folger 04/15/10 QA81-15315 NLFIT_SHOULD_CHANGE_OUTPUT_GRAPH_AXIS_SCALE_IF_MANUAL
#define		SET_SCALE_PROPERTY(_property) \
			if ( pr##_property ) \
				scale._property = *pr##_property

void	set_axis_scale_properties(Scale& scale, LPDOUBLE prFrom, LPDOUBLE prTo, LPDOUBLE prInc)
{
	switch ( scale.Rescale )
	{
	case AXIS_RESCALE_NORMAL:
	case AXIS_RESCALE_AUTO:
		SET_SCALE_PROPERTY(From);
		SET_SCALE_PROPERTY(To);
		SET_SCALE_PROPERTY(Inc);
		break;

	case AXIS_RESCALE_FIXED_BEG:
		SET_SCALE_PROPERTY(To);
		SET_SCALE_PROPERTY(Inc);
		break;

	case AXIS_RESCALE_FIXED_END:
		SET_SCALE_PROPERTY(From);
		SET_SCALE_PROPERTY(Inc);
		break;

	case AXIS_RESCALE_MANUAL:
	default:
		break;
	}
}
///------ End NLFIT_SHOULD_CHANGE_OUTPUT_GRAPH_AXIS_SCALE_IF_MANUAL

///------ Folger 08/06/10 ORG-502-P5 CONTEXT_MENU_OF_ADD_DELETE_COL_SHOULD_ONLY_SHOW_IN_GRID_TABLE
BOOL	pt_in_rect(RECT& rect, POINT pt)
{
	return pt.x >= rect.left && pt.x <= rect.right && pt.y >= rect.top && pt.y <= rect.bottom;
}
///------ End CONTEXT_MENU_OF_ADD_DELETE_COL_SHOULD_ONLY_SHOW_IN_GRID_TABLE


///Kyle 09/19/2010 ORG-1007-P1 WDELDUP_IMPROVE_SPEED
BOOL	worksheet_delete_rows(Worksheet& wks, const vector<uint>& vnRows, bool bUndo)
{
	if( !wks )
		return false;

	if( vnRows.GetSize() > 0)
	{
		vector<uint> vnOrder;
		
		int nRowsTotal = wks.GetNumRows();
		vnOrder.Data(0, nRowsTotal-1, 1);
		
		vector<int> vnRowsToDel;			// vector::RemoveAt() accept vector<int>
		vnRowsToDel = vnRows;
		vnOrder.RemoveAt(vnRowsToDel);
		
		int nRowsKeep = vnOrder.GetSize();
		
		vnOrder.Append(vnRowsToDel);
		
		return wks.Reorder(vnOrder, 0, -1, bUndo) && wks.SetNumRows(nRowsKeep, bUndo);
	}

	return true;
}
///End WDELDUP_IMPROVE_SPEED

///------ Folger 09/27/2010 ORG-1151-P1 SAVE_AS_ANALYSIS_TEMPLATE_FAILED_TO_CLEAN_GRAPHS_EMEBEDED_IN_WKS
BOOL	check_make_full_row_range(DataRange& dr)
{
	#ifdef	__SAVE_AS_ANALYSIS_TEMPLATE_FAILED_TO_CLEAN_GRAPHS_EMEBEDED_IN_WKS__
	for ( int ii=0; ii<dr.GetNumRanges(); ++ii )
	{
		Worksheet	wks;
		int			r1, c1, r2, c2;
		dr.GetRange(ii, r1, c1, r2, c2, wks);

		if ( wks && c1 == c2 )
		{
			Column	col(wks, c1);
			if ( col && col.GetUpperBound() <= r2 )
			{
				r2 = -1;
				dr.SetRange(ii, wks, r1, c1, r2, c2);
			}
		}
	}
	#endif	/// __SAVE_AS_ANALYSIS_TEMPLATE_FAILED_TO_CLEAN_GRAPHS_EMEBEDED_IN_WKS__
	return TRUE;
}
///------ End SAVE_AS_ANALYSIS_TEMPLATE_FAILED_TO_CLEAN_GRAPHS_EMEBEDED_IN_WKS

///------ Folger 10/13/2010 ORG-1210-S2 CREATE_NEW_TABLE_OBJ_FOR_FITTER_OPERATION_IF_WKS_WITHIN_HAS_NO_LINK
BOOL	wks_has_cell_linkes(Worksheet& wks)
{
	int		nCols = wks.GetNumCols();
	for ( int ii=0; ii<nCols; ++ii )
	{
		Column	col(wks, ii);
		if ( col.HasCellLinks() )
			return TRUE;
	}

	return FALSE;
}
///------ End CREATE_NEW_TABLE_OBJ_FOR_FITTER_OPERATION_IF_WKS_WITHIN_HAS_NO_LINK

/// Iris 10/21/2010 ORG-1291 ADD_FUNC_TO_FIND_WKS_LABLE_BY_NAME
int 	find_user_defined_label(Worksheet& wks, LPCSTR lpcszLabelName)
{ 
	if( !wks )
		return -1;

	Grid gg;
	gg.Attach(wks);
	 
	vector<string> vsLabelNames;
	if( gg.GetUserDefinedLabelNames(vsLabelNames) )
	{	    
	    int nn = vsLabelNames.Find(lpcszLabelName);
	    if( nn >= 0 )
	        return RCLT_UDL + nn;	    
	}	
	return -1;
}
///End ADD_FUNC_TO_FIND_WKS_LABLE_BY_NAME