It's always bugged me that there's no decent report writer in VisualWorks. The Document class can certainly do a bit, but it can't do complex layout, add page numbers, or display color text. I've seen report writers that extend the Document class and others that interface to Crystal Reports, but they are proprietary and even then they lack some of the features I'm looking for.
For a recent contract proposal I made, one of the requirements was a report writer. In order to prove the feasibility of creating reports in VisualWorks, I decided to just write one up. Here's a page of a sample report I created with this tool.
The layout uses vertical and horizontal stacks. Each stack lays out each of its children vertically or horizontally. The children can declare their height or width as fixed (a certain number of pixels), proportional (a fraction of the remaining space) or preferred (whatever size it calculates that it needs). Each element can have borders along any edge, margins and pads, and background colors. The layout of the report is defined separately from the content. Headers and footers are automatically repeated on each page and page numbers are calculated for you to use if you want. The final report can be rendered onto Images for viewing in Smalltalk, or sent to the printer.
Just to show you what it took to create this report, here's some of the code.
report
self newPage.
(self allClassesFrom: Collection) do: [:each |
self startHorizontalStack.
each withAllSuperclasses size timesRepeat: [self spacer].
self
text: each name;
style: #arial12;
endText.
self endHorizontalStack].
self finishPage
The report method created the content. It belongs to a class which subclasses from Report so it has the ability to add stacks and other elements.
Headers and footers are defined in their own methods.
header
self
startHeader;
borders: #(#bottom);
startHorizontalStack;
image: self class simberonLogo;
proportionalWidth: 0.25;
endImage;
text: 'Smalltalk Class Hierarchy';
proportionalWidth: 0.5;
color: ColorValue blue;
style: #times30;
centered;
endText;
endHorizontalStack;
endHeader
footer
self
startFooter;
borders: #(#top);
margins: (2@2 corner: 2@2);
text: 'Printed: ' asText allBold, ((PrintConverter for: #timestamp withFormatString: 'm/dd/yyyy h:mm:ss am/pm') formatStringFor: Timestamp now);
proportionalWidth: 0.5;
style: #times16;
pad: (10 @ 10 corner: 10 @ 10);
leftFlush;
endText;
text: ('Page <1p> of <2s>' expandMacrosWith: self pageNumber with: self totalPages);
proportionalWidth: 0.5;
style: #times16;
pad: (10 @ 10 corner: 10 @ 10);
rightFlush;
endText;
endFooter
I still haven't decided what I'll do this this package. I'll likely release it as freeware and let other people use it. Any comments or suggestions are welcome.