SpreadsheetFormatRow abruptly stops working - coldfusion

I've seen this post, but there does look to be a resolution. Anyway, I'm using ColdFusion 10 to generate an Excel spreadsheet. However, when I use SpreadsheetFormatRow() and pass in the rows to be formatted, it only does about 3 and then abruptly stops. Here is an example...
ColdFusion Code
<cfscript>
rowCount = 1;
headingRows = 4;
// Create instance of new Spreadsheet
excelSheet = SpreadsheetNew("ReportName",false);
// HEADING (IMAGE) ROW FORMAT
formatHeadingRow = StructNew();
formatHeadingRow.fgcolor="blue";
// Add rows to fill the header area (must add as many as we are spanning with the above image)
for (x=0;x<headingRows;x++) {
SpreadsheetAddRow(excelSheet,"TEST,TEST,TEST,TEST,TEST,TEST,TEST,TEST,TEST,TEST,TEST,TEST");
SpreadsheetFormatRow(excelSheet,formatHeadingRow,rowCount);
rowCount++;
}
</cfscript>
<!--- stream it to the browser --->
<cfheader name="Content-Disposition" value="inline; filename=reportName.xls">
<cfcontent type="application/vnd.ms-excel" variable="#SpreadSheetReadBinary(excelSheet)#">
and here is a screenshot of the resulting Excel sheet
Why is the formatting stopping after X number of rows and cells?
If I switch to using XML format with
excelSheet = SpreadsheetNew("ReportName",true);
it works properly. However I'm using a custom palette for my colors so I don't think switching to XLSX format is going to work for me. When I try and then call
palette = excelSheet.getWorkbook().getCustomPalette();
I get an error stating that getCustomPalette() method is undefined.
coldfusion.runtime.java.MethodSelectionException: The getcustompalette method was not found
Can anyone help me figure this out? Thank you!!!
Or even better since it works with the XML format, can anyone show example of how to use a custom palette with the XLSX (xml format)

This is an issue I have seen often when dealing with xls files from CF; they seem to stop applying styles after a certain number of cells. I've been able to work around it by outputting to xlsx instead. (I was able to replicate and "fix" your issue by doing so.)
excelSheet = SpreadsheetNew("ReportName",true);
...
<cfheader name="Content-Disposition" value="inline; filename=reportName.xlsx">
<cfcontent type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
variable="#SpreadSheetReadBinary(excelSheet)#">

Since you are applying the exact same format to all rows, only do it once, not on each row. Using SpreadsheetFormatCellRange after the loop should resolve the issue:
SpreadsheetFormatCellRange(excelSheet
, formatHeadingRow
, startRow
, startCol
, endRow
, endCol );
I suspect the problem somehow relates back to Excel's maximum style limits. Since CF is a black box, it is difficult to know how many styles it actually creates or exactly how they are applied. However, in my experience it is very easy to exceed the style limits without even knowing it. Especially when using the older .xls file format, whose limits are much lower. That is why I suggested using the newer .xlsx format instead.
getCustomPalette() method is undefined.
Correct. It does not exist in XSSF. Is there some reason you need a custom palette instead of just defining your own colors, as mentioned in your other thread?

Related

CFSpreadsheet borders for Merged Cells

I searched around for this for awhile, so forgive me if there is an answer already. I am having trouble applying borders to merged cells using CFSpreadsheet. Below is some example code.
<cfscript>
newSS = SpreadsheetNew('Testing'); //Create Spreadsheet
SpreadsheetMergeCells(newSS,1,1,1,9);
SpreadsheetAddRow(newSS,'Underline this Header');
SpreadSheetFormatCell(newSS,{bold=true,alignment='center',bottomborder='thin'},1,1);
Spreadsheetwrite(newSS,expandpath('myTest.xls'),true); //Write File
</cfscript>
What I would expect is the top cell to be underlined all the way across. What I get is the top cell only underlined through column "A" and not underlined after. Is there anyway around this or is this just a limitation of CFSpreadsheet??
Thanks!
According to the POI FAQ's, ie underlying library CF uses to generate spreadsheets, this is currently not supported (emphasis mine):
12. How do I add a border around a merged cell?
Add blank cells around where the cells normally would have been and
set the borders individually for each cell. We will probably enhance
HSSF in the future to make this process easier.
Probably the best you can do for now is to use SpreadsheetFormatCellRange instead of SpreadSheetFormatCell:
SpreadsheetFormatCellRange ( newSS
, {bold=true,alignment='center',bottomborder='thin'}
, 1,1,1,9 );

Applying conditional formatting with CFSpreadsheet

In continuation of a previous thread, I've reached pretty close to where I want and have learned a lot. I'm under CF10 on a MSSQL Server 2008 environment. I have a report I'm generating using cfspreadsheet and then spitting out values based on whether a user has an app enabled it will be output as "Yes" and if not output as "No" in the excel spreadsheet.
Problem is, I need to make it a little easier on the eye and so I wanted to see if it was possible to apply conditional formatting to where if the 3 columns with 3 different apps is Y then it will be green and if N it will be red.
Any suggestions or examples would be great, thanks!
Like I mentioned in your other thread, if you return bit values (not strings), it is simple to apply a custom cell format. But you must use the spreadsheet functions, rather than cfspreadsheet (which does not support custom formatting).
Here is an expanded example to demonstrate how you could incorporate conditional color formatting:
<cfscript>
// build sample query
// note: values must be numeric and NOT text/varchar
qData = queryNew("");
queryAddColumn(qData, "AppNameAlpha", "bit", listToArray("0,0,1,0,1"));
queryAddColumn(qData, "AppNameBeta", "bit", listToArray("1,1,0,0,1"));
// create sample sheet
sheet = spreadsheetNew();
spreadsheetAddRows(sheet, qData);
// apply colorized yes/no format
spreadsheetFormatColumns(sheet, {dataformat='[Green]"Y";;[Red]"N"'}, "1-2");
spreadsheetWrite(sheet, "c:/path/to/sheet.xls", true);
</cfscript>
The "dataformat" uses the first three sections of Excel's custom number formatting: <positive><negative><zero>. Translated:
[Green]"Y"; // <positive values>: display "Y" in green
; // <negative values>: do nothing extra
[Red]"N" // <zero values>: display "N" in red
The function you are looking for is SpreadsheetFormatCell()

Openpyxl: Formulas getting removed when saving file

im using openpyxl to edit an excel file that contains some formulas in certain cells. Now when i populate the cells from a text file, im expecting the formula to work and give me my desired output. But what i observe is that the formulas get removed and the cells are left blank.
I had the same problem when saving the file with openpyxl: formulas removed.
But I pointed out that some intermediate formulas were still there.
After some tests, it appears that, in my case, all formulas which are displaying blank result (nothing) are cleaned when the save occured, unlike the formulas with an output in the cell, which are preserved.
ex :
=IF((SUM(P3:P5))=0;"";(SUM(Q3:Q5))/(SUM(P3:P5))) => can be removed when saving because of the blank result
ex :
=IF((SUM(P3:P5))=0;"?";(SUM(Q3:Q5))/(SUM(P3:P5))) => preserved when saving
for my example I'm using openpyxl-2.0.3 on Windows. Open and save function calls are :
self._book = load_workbook("myfile.xlsx", data_only=False)
self._book.save("myfile.xlsx")
openpyxl does currently not support reading of formulas. Ie. If you read your file and write it back, all formulas are removed. There is an active feature request in bitbucket tough.

CFDOCUMENT creates PDF with different MD5 hashes for same input

I am using CFDOCUMENT to create a PDF in CF9.0.1. However with the same input each time I generate a new PDF using CFDOCUMENT the MD5 hash seems to be different.
Test code is simple:
<cfdocument name=FileData1 format="PDF" localurl="yes" pagetype="A4"><h3>I am happy!</h3></cfdocument>
<cfdocument name=FileData2 format="PDF" localurl="yes" pagetype="A4"><h3>I am happy!</h3></cfdocument>
<cffile ACTION="write" FILE="C:\happy1.pdf" OUTPUT=#FileData1# ADDNEWLINE=NO NAMECONFLICT="Override">
<cffile ACTION="write" FILE="C:\happy2.pdf" OUTPUT=#FileData2# ADDNEWLINE=NO NAMECONFLICT="Override">
Both files produced have different MD5 file-hash although both PDF looks exactly the same. I have a user requirement where if the file is the same to ignore regeneration of PDF, so does anyone know how to force CF9 to generate the same PDF with same MD5 hash (bit similarity) if given the same input?
I ran a HxD Hex File Compare and found that the file differs in three sections:
The font name e.g. 62176/FontName/OJSSWJ+TimesNewRomanPS (the OJSSWJ is random)
The timestamp /CreationDate(D:20110927152929+08'00')
Some sort of key at the end: <]/Info 12 0 R/Size 13>>
Thanks for your help in advance!
They will never be the same.
The timestamp /CreationDate(D:20110927152929+08'00')
The creationDate is a timestamp of when it was created, thus unless you create it at the same second every time, it wont be the same.
You might be able to modify the pdf and remove or modify this bit.
Or use a different method to determine if you should create the pdf, creating it to md5 compare the results seems like a waste of processing power.

How to iterate over all the page breaks in an Excel 2003 worksheet via COM

I've been trying to retrieve the locations of all the page breaks on a given Excel 2003 worksheet over COM. Here's an example of the kind of thing I'm trying to do:
Excel::HPageBreaksPtr pHPageBreaks = pSheet->GetHPageBreaks();
long count = pHPageBreaks->Count;
for (long i=0; i < count; ++i)
{
Excel::HPageBreakPtr pHPageBreak = pHPageBreaks->GetItem(i+1);
Excel::RangePtr pLocation = pHPageBreak->GetLocation();
printf("Page break at row %d\n", pLocation->Row);
pLocation.Release();
pHPageBreak.Release();
}
pHPageBreaks.Release();
I expect this to print out the row numbers of each of the horizontal page breaks in pSheet. The problem I'm having is that although count correctly indicates the number of page breaks in the worksheet, I can only ever seem to retrieve the first one. On the second run through the loop, calling pHPageBreaks->GetItem(i) throws an exception, with error number 0x8002000b, "invalid index".
Attempting to use pHPageBreaks->Get_NewEnum() to get an enumerator to iterate over the collection also fails with the same error, immediately on the call to Get_NewEnum().
I've looked around for a solution, and the closest thing I've found so far is http://support.microsoft.com/kb/210663/en-us. I have tried activating various cells beyond the page breaks, including the cells just beyond the range to be printed, as well as the lower-right cell (IV65536), but it didn't help.
If somebody can tell me how to get Excel to return the locations of all of the page breaks in a sheet, that would be awesome!
Thank you.
#Joel: Yes, I have tried displaying the user interface, and then setting ScreenUpdating to true - it produced the same results. Also, I have since tried combinations of setting pSheet->PrintArea to the entire worksheet and/or calling pSheet->ResetAllPageBreaks() before my call to get the HPageBreaks collection, which didn't help either.
#Joel: I've used pSheet->UsedRange to determine the row to scroll past, and Excel does scroll past all the horizontal breaks, but I'm still having the same issue when I try to access the second one. Unfortunately, switching to Excel 2007 did not help either.
Experimenting with Excel 2007 from Visual Basic, I discovered that the page break isn't known unless it has been displayed on the screen at least once.
The best workaround I could find was to page down, from the top of the sheet to the last row containing data. Then you can enumerate all the page breaks.
Here's the VBA code... let me know if you have any problem converting this to COM:
Range("A1").Select
numRows = Range("A1").End(xlDown).Row
While ActiveWindow.ScrollRow < numRows
ActiveWindow.LargeScroll Down:=1
Wend
For Each x In ActiveSheet.HPageBreaks
Debug.Print x.Location.Row
Next
This code made one simplifying assumption:
I used the .End(xlDown) method to figure out how far the data goes... this assumes that you have continuous data from A1 down to the bottom of the sheet. If you don't, you need to use some other method to figure out how far to keep scrolling.
Did you set ScreenUpdating to True, as mentioned in the KB article?
You may want to actually toggle it to True to force a screen repaint. It sounds like the calculation of page breaks is a side-effect of actually rendering the page, rather than something Excel does on demand, so you have to trigger a page rendering on the screen.