CFSpreadsheet loses SpreadSheetAddFreezePane when updating - coldfusion

I am trying to add spreadsheets to a workbook with a freeze pane. The freeze pane will work if the action is write but not if I add another sheet using update.
<cfscript>
theSheet = SpreadsheetNew(SheetName);
SpreadsheetAddRows(theSheet,TheQuery);
format2=StructNew();
format2.font="Arial";
format2.fontsize="10";
format2.color="Black;";
format2.italic="False";
format2.bold="true";
format2.alignment="left";
format2.textwrap="true";
format2.fgcolor="tan";
format2.bottomborder="thick";
format2.bottombordercolor="Black";
format2.leftborder="thick";
format2.leftbordercolor="Black";
format2.rightborder="thick";
format2.rightbordercolor="Black";
SpreadsheetFormatRows(theSheet,format2,"1-2");
SpreadsheetFormatColumns(theSheet,format2,"1-3");
SpreadSheetAddFreezePane(theSheet,3,1);
</cfscript>
<cfspreadsheet filename="#theFile#" name="theSheet" sheet="#SheetCount#" action="update" sheetname="#SheetName#">

Sounds like it could be a bug. Unless there is a specific reason for using action=update, I would just use action=write instead. Read in the workbook. Add a new sheet. Make it active. Then write it back to disk.
<cfscript>
theSheet = SpreadSheetRead( theFile );
SpreadsheetCreateSheet( theSheet, sheetName );
SpreadSheetSetActiveSheet( theSheet, sheetName );
// ... code to add data
SpreadSheetAddFreezePane( theSheet, 3, 1 );
SpreadSheetWrite( theSheet, theFile, true );
</cfscript>
As Adam mentioned in the comments, you may want to file a bug report (and post the bug number here so others can vote on it).

Related

Apache POI XSSF header not created

As I experiment with xlsx creation, I'm stuck on creating headers. I'm able to create a file with rows and merged cells, but headers never seem to work. Here's what I have:
var WorkBook = CreateObject(
"java",
"org.apache.poi.xssf.usermodel.XSSFWorkbook"
).Init();
var Sheet = WorkBook.CreateSheet(
JavaCast( "string", 'my sheetname' )
);
// create the default header if it doesn't exist
var header = sheet.getHeader(); // have also tried getEvenHeader() and getOddHeader()
header.setText('&LLeft Section');
// have also tried the following:
//header.setLeft('left header');
//header.setCenter('CENTER');
//header.setRight('right header');
// open the file stream
var FileOutputStream = CreateObject(
"java",
"java.io.FileOutputStream"
).Init(
JavaCast( "string", filename )
);
// Write the workbook data to the file stream.
WorkBook.Write(
FileOutputStream
);
// Close the file output stream.
FileOutputStream.Close();
When I run this code, no errors are thrown. The file is created and can be opened without throwing any errors, but no headers appear. And like I said, if I create rows/cells instead of a header, those are created correctly. What am I missing?
EDIT:
As Leigh points out below, headers/footers have a different meaning in Excel than how I was thinking of them (as in PDFs). I got thrown off by the way adding a header in Excel shows it above the first row, and thought that adding one through POI would do the same thing.
(Promoted from comments, in case the answer is helpful for the next guy)
Silly question, but how are you verifying the headers are not present? In Excel, headers and footers should only be visible when printing (or in print preview mode).
...Headers and footers are not displayed on the worksheet in Normal
view — they are displayed only in Page Layout view and on the printed
pages.
FWIW, the code works fine for me under CF10 and 11, after I populated at least one cell (so there was something to print).
Runnable Example on trycf.com
<cfscript>
workBook = CreateObject( "java", "org.apache.poi.xssf.usermodel.XSSFWorkbook").Init();
sheet = WorkBook.CreateSheet( JavaCast( "string", 'my sheetname' ) );
header = sheet.getHeader(); // have also tried getEvenHeader() and getOddHeader()
header.setText('&LLeft Section');
// add some data so there is something to print
sheet.createRow(0).createCell(0).setCellValue("sample value");
// Using binary stream because trycf.com does not support files for security reasons
baos = createObject("java", "java.io.ByteArrayOutputStream").init();
// Write the workbook data to the binary stream
workBook.write( baos );
baos.close();
</cfscript>
<!--- CF10 lacks support for script version of cfcontent --->
<cfcontent type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
variable="#baos.toByteArray()#">

ColdFusion: Trying to query database in CFScript

My boss wants me to use cfscript instead of tags for database interaction. Does anybody know of any good tutorials? I bought the Adobe ColdFusion application development book, vol 2. But it does not have much on scripting. I did google and found this site, but it did not explain much.
Does any body know of any good tutorials on accessing the data base in CFScript?
Basically I have to convert the following to using CFScript:
<cfquery name="drafts" datasource="ICEchat">
SELECT * from Messages where IsTemp=1 and LinkA=#FORM.LinkA# and LinkB=#FORM.LinkA#
</cfquery>
<cfif drafts.recordcount GT '0'>
<cfquery name="Attachments" datasource="ICEchat">
SELECT * FROM Attachments where id=2
</cfquery>
{ Message:"<cfoutput query="drafts">#Message#</cfoutput>", Attachments:[<cfoutput query="attachments">
"#url#"<cfif attachments.currentRow LT attachments.recordcount>,</cfif>
</cfoutput>]}
<cfelse>
<cfquery name="addrecord" datasource="ICEchat">
INSERT INTO Messages
VALUES(1,1,' ',1)
</cfquery>
{ Message:"NA", Attachments:[]}
</cfif>
From the 4th link on google for "cfscript query tutorial":
<CFSCRIPT>
myQry = new Query(); // new query object
myQry.setSQL("select bookid, title, genre from app.books where bookid = :bookid"); //set query
myQry.addParam(name="bookid",value="5",CFSQLTYPE="CF_SQL_INTEGER"); // add query param
qryRes = myQry.execute(); // execute query
writedump(qryRes.getResult().recordcount, true); // get resultcount
writedump(qryRes.getResult(), false); // dump result
writeoutput('<BR>');
</CFSCRIPT>
That ought to tell you everything you need to know.
Also, you really should not be creating JSON manually, no matter how simple it is. Use serializeJson().
Didn't test this, but this should do it.
<cfscript>
local.drafts = new Query();
local.drafts.setDatasource("ICEchat");
local.drafts.addParam(name="linkA", value="#form.linkA#", cfsqltype="CF_SQL_VARCHAR");
local.drafts.addParam(name="linkB", value="#form.linkB#", cfsqltype="CF_SQL_VARCHAR");
local.drafts.setSQL("SELECT * from Messages where IsTemp=1 and LinkA = :linkA and LinkB = :linkA");
local.drafts.execute().getResult();
if (local.drafts.recordcount GT 0) {
local.attachments = new Query();
local.attachments.setDatasource("ICEchat");
local.attachments.setSQL("SELECT * FROM Attachments where id=2");
local.attachments.execute().getResult();
WriteOutput("{ Message: ");
for (i=1; i LTE local.drafts.recordcount; i=i+1) {
WriteOutput(local.drafts.message[i]);
}
WriteOutput(", Attachments: ");
for (i=1; i LTE local.attachments.recordcount; i=i+1) {
WriteOutput(local.drafts.url[i]);
if (i LT local.attachments.recordcount) {
WriteOutput(", ");
}
}
WriteOutput("}");
} else {
local.q = new Query();
local.q.setDatasource("ICEchat");
local.q.setSQL("INSERT INTO Messages VALUES(1,1,' ',1)");
local.q.execute();
WriteOutput("{ Message:"NA", Attachments:[]}");
}
</cfscript>
I have been searching for a solution for the same error. I get not defined errors or construct errors. Have been chatting with Ray Camden for the past day, but everything he has suggested is not doing what I need either. I have been working on a website conversion from the standard CF tags to cfscript.
Ray suggested that the .execute(); is what pulls the recordcount and suggested this is all was needed: x=queryExecute(); would fetch the recordcount, with (x) being the query. He suggested not to use getPrefix(); but I read that the .getPrefix(); is what pulls the recordcount. He is experienced I am sure you know Ray Camden, but I keep getting the same error no matter what I try doing inside of my code.

Adding appointments to your calendar through email notifications

I need an example for adding events to my calendars through emails. For example when I send an email to my clients regarding their appointment, i want them to have an option in the email that will allow them to add the event on their calendar by just clicking on a button or something.
Is there anything out there that someone can direct me to it?
I need this mainly to use it with coldfusion 9.
Thanks!
I'd recommend the iCalUs UDF from http://www.cflib.org/udf/icalus
WebDH provides a great example here.
Here's an example using CF9 that I quickly put together but haven't tested yet.
<cfscript>
eventStr = {};
eventStr.organizerName = "John Doe"; //Organizer Name
eventStr.organizerEmail = "john.doe#email.com"; //Organizer Email
eventStr.startTime = ParseDateTime("12/30/2011 11:00"); //format: m/d/yyyy HH:mm OR h:mm TT -- this is Eastern time
eventStr.subject = "Demo Example";
eventStr.location = "StackOverflow.com";
eventStr.description = "Example iCalendar using CF9";
// Display in browser
//pc = getpagecontext().getresponse();
//pc.getresponse().setcontenttype('text/calendar');
//pc.setHeader("Content-Disposition","inline;filename=newAppointment.ics");
//writeOutput(iCalUS(eventStr));
//Email
m = new mail();
m.setSubject( "Event" );
m.setTo( "user#email.com" );
m.setFrom( "me#email.com" );
m.setServer( "localhost" );
//m.addParam( file="#ACCOUNT_TXT_FILE#" );
m.addPart( type="text", charset="utf-8", wraptext="72", body="Attached is a calendar event..." );
m.addPart( type="text/calendar" body="#iCalUS(eventStr)#");
m.send();
</cfscript>
Here's another example reference that shows how to email the calendar event.
Here is a very basic implementation of the ICS format. This is designed to be accessed through a browser, but it'd be fairly academic to change to create a text file with ICS extension and send it via e-mail.
<cfheader name="Content-Disposition" value="attachment; filename=event.ics" />
<cfcontent reset="true" type="text/calendar" />
<cfscript>
// handle all-day events
if (NOT isDate(starttime) OR NOT isDate(endtime)) {
dtstart=';VALUE=DATE:#dateFormat(eventdate,"yyyymmdd")#';
dtend=';VALUE=DATE:#dateFormat(dateAdd("d",1,eventdate),"yyyymmdd")#';
} else {
dtstart=';TZID="Eastern Standard Time":#dateFormat(eventdate,"yyyymmdd")#T#timeFormat(starttime,"HHmmss")#';
dtend=';TZID="Eastern Standard Time":#dateFormat(eventdate,"yyyymmdd")#T#timeFormat(endtime,"HHmmss")#';
}
</cfscript>
<cfoutput>
BEGIN:VCALENDAR
PRODID:-//Company//Source//EN
VERSION:2.0
METHOD:PUBLISH
BEGIN:VTIMEZONE
TZID:Eastern Standard Time
BEGIN:STANDARD
DTSTART:16011104T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:16010311T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
CLASS:PUBLIC
CREATED:#dateFormat(dateAdded,"yyyymmdd")#T#timeFormat(dateAdded,"HHmmss")#Z
DESCRIPTION:#desc#
DTEND#dtend#
DTSTAMP:#dateFormat(dateAdded,"yyyymmdd")#T#timeFormat(dateAdded,"HHmmss")#Z
DTSTART#dtstart#
LAST-MODIFIED:#dateFormat(dateApproved,"yyyymmdd")#T#timeFormat(dateApproved,"HHmmss")#Z
LOCATION:#location#
PRIORITY:5
SEQUENCE:0
SUMMARY;LANGUAGE=en-us:#title#
TRANSP:OPAQUE
UID:#dateFormat(now(),"yyyymmdd")#T#timeFormat(now(),"HHmmss")#Z##uniqueID#
BEGIN:VALARM
TRIGGER:-PT15M
ACTION:DISPLAY
DESCRIPTION:Reminder
END:VALARM
END:VEVENT
END:VCALENDAR
</cfoutput>

Converting Files to PDF and attaching to another PDF in Coldfusion

So I'm doing a project that generates a PDF of information that was previously filled out in a form. Along with this information, documents were attached to support the information in the form.
I generate the PDF with the normal info from my DB, but I also want to convert their uploaded files (if .doc or .docx) to PDF format and stick in the same PDF. (So it is all in one place.)
I know how to convert to PDF, problem is how do you attach those newly generated PDFs to the current one with the other information on it?
you have 2 options:
merge all PDFs into one using <cfpdf action="merge"...>
really attach files in your main pdf but as CFPDF does not support it (yet?) you have to use iText:
<cfscript>
try {
// Source of THE main PDF and destination file
inputFile = ExpandPath("myDoc.pdf");
outputFile = ExpandPath("myDocPlusAttachments.pdf");
// the file to attach (can be of any type)
attach1 = ExpandPath("myAttachment.doc");
// prepare everything
reader = createObject("java", "com.lowagie.text.pdf.PdfReader").init( inputFile );
outStream = createObject("java", "java.io.FileOutputStream").init( outputFile );
stamper = createObject("java", "com.lowagie.text.pdf.PdfStamper").init( reader, outStream );
// attachment the file
stamper.addFileAttachment("My Attached File", javacast("null", ""), attach1, "myAttachment.doc");
// display the attachment pane when the pdf opens (Since 1.6)
writer = stamper.getWriter();
writer.setPdfVersion( writer.VERSION_1_6 );
}
finally {
// always cleanup objects
if (IsDefined("stamper")) {
stamper.close();
}
if (IsDefined("outStream")) {
outStream.close();
}
}
</cfscript>
Just found where I got that piece of code: ColdFusion 9: Adding Document Level Attachments to a PDF with iText
You need to use the CFPDF tag, and use the merge action.

Best practice for Datasource use in a CFC

I have an application which uses context sensitive datasources. Currently I keep the datasource information stored a such
reqeust.DB.Datasource = "DatasourceName";
request.DB.Username = "DatasourceUsername"
request.DB.Password = "DatasourcePassword"
I then overwrite the variables depending on the context, so each cfquery tag has the attributes datasource="#request.DB.Datesource#" ... etc ...
I want to start moving to more CFC centric frameworks like Coldbox, but I just don't see how this would work.
Do I need to pass in a datasource object into the init statement of the CFC? This seems like it would be a super PITA.
With CF9, you can this.datasource in Application.cfc as the default datasource. Unfortunately, it doesn't seem to have a way to set username/password
Either
A.) use an Dependency Injection framework such as ColdSpring (only suitable for singleton Services), Lightwire or Coldbox's own DI solution (Wirebox). and inject the datasource/username/password through the init constructor or setters.
B.) set <Datasources> in Coldbox.xml.cfm, see: http://wiki.coldbox.org/wiki/ConfigurationFile.cfm
<!--Datasource Setup, you can then retreive a datasourceBean
via the getDatasource("name") method: -->
<Datasources>
<Datasource alias="MyDSNAlias"
name="real_dsn_name"
dbtype="mysql"
username=""
password="" />
</Datasources>
Even if your objects only get initialized at request level, it seems like it should be less of a pain to work with in this fashion.
<cfscript>
request.DB.Datasource = "DatasourceName";
request.DB.Username = "DatasourceUsername";
request.DB.Password = "DatasourcePassword";
request.randomDAO = createObject('component','DAOStuff.randomDAO');
request.randomDAO.init(DBObject = request.DB);
request.someQuery = request.randomDAO.someGetter();
request.someOtherQuery = request.randomDAO.someOtherGetter();
request.aThirdQuery = request.randomDAO.aThirdGetter();
</cfscript>
As opposed to:
<cfscript>
request.DB.Datasource = "DatasourceName";
request.DB.Username = "DatasourceUsername";
request.DB.Password = "DatasourcePassword";
</cfscript>
<cfquery name="request.someQuery"
datasource=request.DB.Datasource
username=request.DB.Username
password=request.DB.Password>
--SOME SQL HERE
</cfquery>
<cfquery name="request.someOtherQuery"
datasource=request.DB.Datasource
username=request.DB.Username
password=request.DB.Password>
--SOME SQL HERE
</cfquery>
<cfquery name="request.aThirdQuery"
datasource=request.DB.Datasource
username=request.DB.Username
password=request.DB.Password>
--SOME SQL HERE
</cfquery>
If it is safe for your data objects to exist at an application level (assuming here that the data source for the object will not change at run-time and that you have written thread-safe CFCs) You can store and initialize DAOs at application level and then each request has wonderfully simple code like:
<cfscript>
request.someQuery = application.randomDAO.someGetter();
request.someOtherQuery = application.randomDAO.someOtherGetter();
request.aThirdQuery = application.randomDAO.aThirdGetter();
</cfscript>