#DEFINE xlTemplate 17 glNeed2BAdd = .F. *** Launch Excel *** oXL = CREATEOBJECT("Excel.Application") gnXLProcessWeStarted = PROCID("excel.exe") && not case sensitive - Retrieves pID oXL.DisplayAlerts = .f. oEvents = NEWOBJECT("myClass", "XLEvents.prg") EVENTHANDLER(oXL, oEvents) gcPivotFullPath = ALLTRIM(thisform.combo3.ListItem(thisform.combo3.ListIndex,2)) SELECT rv_PivPivot LOCATE FOR ALLTRIM(thisform.combo3.ListItem(thisform.combo3.ListIndex,1)) == ALLTRIM(cFriendlyName) oWB = oXL.Workbooks.Open(gcPivotFullPath) oWB.SaveAs(gcPivotFullPath, xlTemplate) oWB.ActiveSheet.name = JUSTFNAME(rv_PivPivot.cFriendlyName) oSheet = oWB.ActiveSheet oPiv = oSheet.PivotTables(1) *** ALTER SQL SELECT STATEMENT IF THE USER SELECTED A DATE OR DATE RANGE lcPageField = opiv.PageFields(1).visibleItems(1).name lcSql = opiv.PivotCache.Sql DO CASE CASE thisform.optiongroup1.Value = 2 lcFldList = LEFT(lcSQL, AT("FROM",lcSQL)-1) lcFldList = ALLTRIM(STRTRAN(lcFldList, "SELECT", ",")) FOR c = 1 TO OCCURS(",",lcFldList) lcField = SUBSTR(lcFldList, AT(",",lcFldList,c),AT(",",lcFldList,c+1)-AT(",",lcFldList,c)) lcField = ALLTRIM(STRTRAN(lcField,",","")) lcOriginalField = lcField DO CASE CASE "TRANSACTIONS" $ lcField lcField = STRTRAN(lcField,"TRANSACTIONS","RV_Transaction") OTHERWISE lcField = "RV_"+lcField ENDCASE lcField2 = "["+lcField+"]" IF TYPE(&lcField2) = "D" lcSql = opiv.PivotCache.Sql IF "WHERE" $ lcSQL lcSql = STRTRAN(lcSQL, "WHERE", "WHERE ("+lcOriginalField+">={ts '"+TRANSFORM(YEAR(thisform.txtBirth_date.Value))+"-"+PADL(TRANSFORM(MONTH(thisform.txtBirth_date.Value)),2,"0")+"-"+PADL(TRANSFORM(DAY(thisform.txtBirth_date.Value)),2,"0")+" 00:00:00'} AND "+lcOriginalField+"<= {ts '"+TRANSFORM(YEAR(thisform.text1.Value))+"-"+PADL(TRANSFORM(MONTH(thisform.text1.Value)),2,"0")+"-"+PADL(TRANSFORM(DAY(thisform.text1.Value)),2,"0")+" 00:00:00'}) AND ") ELSE lcSql = STRTRAN(lcSQL, "ORDER BY", " WHERE ("+lcOriginalField+">={ts '"+TRANSFORM(YEAR(thisform.txtBirth_date.Value))+"-"+PADL(TRANSFORM(MONTH(thisform.txtBirth_date.Value)),2,"0")+"-"+PADL(TRANSFORM(DAY(thisform.txtBirth_date.Value)),2,"0")+" 00:00:00'} AND "+lcOriginalField+"<= {ts '"+TRANSFORM(YEAR(thisform.text1.Value))+"-"+PADL(TRANSFORM(MONTH(thisform.text1.Value)),2,"0")+"-"+PADL(TRANSFORM(DAY(thisform.text1.Value)),2,"0")+" 00:00:00'})" +CHR(13)+CHR(10)+"ORDER BY ") ENDIF DIMENSION laRetArray(1) oPiv.PivotCache.sql = thisform.BuildArray(lcSQL) oPiv.PivotCache.Refresh ENDIF ENDFOR CASE thisform.optiongroup1.Value = 3 lcFldList = LEFT(lcSQL, AT("FROM",lcSQL)-1) lcFldList = ALLTRIM(STRTRAN(lcFldList, "SELECT", ",")) FOR c = 1 TO OCCURS(",",lcFldList) lcField = SUBSTR(lcFldList, AT(",",lcFldList,c),AT(",",lcFldList,c+1)-AT(",",lcFldList,c)) lcField = ALLTRIM(STRTRAN(lcField,",","")) lcOriginalField = lcField DO CASE CASE "TRANSACTIONS" $ lcField lcField = STRTRAN(lcField,"TRANSACTIONS","RV_Transaction") OTHERWISE lcField = "RV_"+lcField ENDCASE lcField2 = "["+lcField+"]" IF TYPE(&lcField2) = "D" lcSql = opiv.PivotCache.Sql IF "WHERE" $ lcSQL lcSql = STRTRAN(lcSQL, "WHERE", "WHERE ("+lcOriginalField+"= {ts '"+TRANSFORM(YEAR(thisform.text2.Value))+"-"+PADL(TRANSFORM(MONTH(thisform.text2.Value)),2,"0")+"-"+PADL(TRANSFORM(DAY(thisform.text2.Value)),2,"0")+" 00:00:00'}) AND ") ELSE lcSql = STRTRAN(lcSQL, "ORDER BY", " WHERE ("+lcOriginalField+"= {ts '"+TRANSFORM(YEAR(thisform.text2.Value))+"-"+PADL(TRANSFORM(MONTH(thisform.text2.Value)),2,"0")+"-"+PADL(TRANSFORM(DAY(thisform.text2.Value)),2,"0")+" 00:00:00'})" +CHR(13)+CHR(10)+"ORDER BY ") ENDIF DIMENSION laRetArray(1) oPiv.PivotCache.sql = thisform.BuildArray(lcSQL) oPiv.PivotCache.Refresh ENDIF ENDFOR ENDCASE oXL.visible = .T. *** Refresh Data to make sure the data shown is up to date *** WITH oPiv .RefreshTable() .Format(3) ENDWITH *** Check if SQL Query returns records... if so check and uncheck IF opiv.PivotCache.RecordCount > 0 IF ALLTRIM(lcPageField) # "(All)" lFound = .F. FOR c = 1 TO oPiv.PageFields(1).HiddenItems.Count IF oPiv.PageFields(1).HiddenItems(c).name = lcPageField lFound = .T. EXIT ENDIF ENDFOR IF lFound oPiv.PivotFields(oPiv.PageFields(1).name).CurrentPage = lcPageField ENDIF ENDIF ************************************************************************* * We need to make sure that the VisibleItems & hiddenItems * are checked/unchecked according to the treeviews ** Row Fields lnParentNodeCount = 0 FOR c = 1 TO thisform.olecontrol1.Nodes.Count IF "~" $ LEFT(thisform.olecontrol1.Nodes(c).tag,2) && the ~ at the second digit is as top level node lnParentNodeCount = lnParentNodeCount + 1 *** make em all checked FOR EACH oRow IN oPiv.RowFields(lnParentNodeCount).HiddenItems oRow.visible = .T. ENDFOR *** Now we have a full collection of the items... cycle thru it and deselect what the user haven't checked FOR k = 1 TO thisform.olecontrol1.Nodes(c).children IF thisform.olecontrol1.Nodes(c+k).Checked = .F. && We won't bother with the checked since we checked all in the pivot FOR EACH oRow IN oPiv.RowFields(lnParentNodeCount).VisibleItems IF ALLTRIM(oRow.name) = ALLTRIM(thisform.olecontrol1.Nodes(c+k).text) oRow.visible = .F. ENDIF ENDFOR ENDIF ENDFOR ENDIF ENDFOR ** Column Fields lnParentNodeCount = 0 FOR c = 1 TO thisform.olecontrol2.Nodes.Count IF "~" $ LEFT(thisform.olecontrol2.Nodes(c).tag,2) .AND. thisform.olecontrol2.Nodes(c).text # "Data" && the ~ at the second digit is as top level node lnParentNodeCount = lnParentNodeCount + 1 *** make em all checked FOR EACH oCol IN oPiv.ColumnFields(lnParentNodeCount).HiddenItems oCol.visible = .T. ENDFOR *** Now we have a full collection of the items... cycle thru it and deselect what the user haven't checked FOR k = 1 TO thisform.olecontrol2.Nodes(c).children IF thisform.olecontrol2.Nodes(c+k).Checked = .F. && We won't bother with the checked since we checked all in the pivot FOR EACH oCol IN oPiv.ColumnFields(lnParentNodeCount).VisibleItems IF ALLTRIM(oCol.name) = ALLTRIM(thisform.olecontrol2.Nodes(c+k).text) oCol.visible = .F. ENDIF ENDFOR ENDIF ENDFOR ENDIF ENDFOR ENDIF *********************************************************************** ************************************************************************* **** Wait until user comes back DO WHILE glBackFromXL = .F. ENDDO ** we are back *EVENTHANDLER(oXL, oEvents, .T.) IF glNeed2BAdd SELECT rv_PivPivot LOCATE FOR ALLTRIM(cFriendlyName ) = ALLTRIM(gcXLEventRetVal1) IF !FOUND() INSERT INTO rv_PivPivot(cFriendlyName, cTemplatePath) VALUES (gcXLEventRetVal1, gcXLEventRetVal2) =TABLEUPDATE(.T.) thisform.combo3.Requery ENDIF thisform.combo3.setfocus ENDIF Thisform.killprocess(gnXLProcessWeStarted) oXL = .NULL. oEvents = .NULL. glBackFromXL = .F. glNeed2BAdd = .F. gcXLEventRetVal1 = "" gcXLEventRetVal2 = "">You might want to try reposting this with some sample code that is hanging you up. Hector Correa gave an excellent presentation on VFP and Pivot Tables at GLGDW earlier this month, so, hopefully, he will jump in here. I am fairly certain he was using SP1 in his presentation with no problems.