Simple Swift report application source code
This program is provided for use as input to the procedure Quick Start: Write a Swift report application.
It is a simple example; in a real world situation, the data would be read from another source,
an iterator would read the data into memory and stream that data one record at a time. For
information about the requirements of a Swift report application, see Provide the data source (GRW for Swift).
/*
* FOURJS_START_COPYRIGHT(U,2016)
* Property of Four Js*
* (c) Copyright Four Js 2016, 2022. All Rights Reserved.
* * Trademark of Four Js Development Tools Europe Ltd
* in the United States and elsewhere
*
* Four Js and its suppliers do not warrant or guarantee that these samples are
* accurate and suitable for your purposes.
* Their inclusion is purely for information purposes only.
* FOURJS_END_COPYRIGHT
*/
import Foundation
import libgre
import AppKit
func addElement(_ content_handler: UnsafeMutablePointer<ContentHandler>, _ name: String, _ content: String)
{
startElement(content_handler, name)
characters(content_handler, content)
endElement (content_handler, name)
}
func convertDateComponentsToString(_ dateComponents: DateComponents?, _ format: String? = "yyyy-MM-dd HH:mm:ss.SSSSS") -> String?
{
if dateComponents == nil { return nil }
if let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.ISO8601),
let date = calendar.date(from: dateComponents!) {
let dateFormatter = DateFormatter()
dateFormatter.calendar = Calendar(identifier: .iso8601)
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = format
return dateFormatter.string(from: date)
}
return ""
}
public class Sales
{
public var content_handler: UnsafeMutablePointer<ContentHandler>
var shopName: String
var zipCode: Int
var day: DateComponents
var items = [SalesItem]()
public init?(_ content_handler: UnsafeMutablePointer<ContentHandler>,
_ shopName: String,
_ zipCode: Int,
_ day: DateComponents)
{
self.content_handler = content_handler
self.shopName = shopName
self.zipCode = zipCode
self.day = day
self.items.append(SalesItem("Tablelamp", SalesItem.Category.Furniture, 23.00, nil));
self.items.append(SalesItem("Tablelamp", SalesItem.Category.Furniture, 267.00, self.items.last));
self.items.append(SalesItem("Officechair", SalesItem.Category.Furniture, 155.00, self.items.last));
self.items.append(SalesItem("Grandfather clock", SalesItem.Category.Furniture, 329.00, self.items.last));
self.items.append(SalesItem("Scissors", SalesItem.Category.Supplies, 19.00, self.items.last));
self.items.append(SalesItem("Measuring tape", SalesItem.Category.Supplies, 23.00, self.items.last));
self.items.append(SalesItem("Sunglasses", SalesItem.Category.Travelling, 15.95, self.items.last));
self.items.append(SalesItem("Penknife", SalesItem.Category.Travelling, 6.25, self.items.last));
self.items.append(SalesItem("Ornateangel", SalesItem.Category.Art, 1.95, self.items.last));
self.fetch()
}
public func fetch()
{
startElement(content_handler, "sales")
attribute(content_handler, "xmlns", "http://www.4js.com/2004/REPORT")
addElement(content_handler, "shopName", shopName)
addElement(content_handler, "zipCode", "\(zipCode)")
addElement(content_handler, "day", convertDateComponentsToString(day)!)
for item in items
{
item.serializeToXML(content_handler)
}
endElement(content_handler, "sales")
}
class SalesItem
{
enum Category: String {
case Furniture, Art, Supplies, Travelling
}
var articleName: String
var category: Category
var price: Double
var runningTotal: Double
// The previous item is passed to allow computing the running total.
init(_ articleName: String, _ category: Category, _ price: Double, _ previousItem: SalesItem?)
{
self.articleName = articleName
self.category = category
self.price = price
self.runningTotal = (previousItem == nil ? price : previousItem!.runningTotal + price)
}
func serializeToXML(_ content_handler: UnsafeMutablePointer<ContentHandler>)
{
startElement(content_handler, "items")
addElement(content_handler, "articleName", articleName)
addElement(content_handler, "category", category.rawValue)
addElement(content_handler, "price", "\(price)")
addElement(content_handler, "runningTotal", "\(runningTotal)")
endElement(content_handler, "items")
}
}
}
/**
* MAIN
*
* Runs the report using the design file specified in args[0] or "SalesList.4rp" otherwise.
* The program creates the file "SalesList.pdf" and opens it using
* NSWorkspace.shared().open() which will typically
* invoke the Preview application.
*/
var designFile: String
var outputFilename: String = "SalesList.pdf"
if CommandLine.argc == 1 {
designFile = "SalesList.4rp"
} else {
designFile = CommandLine.arguments[1]
}
let rcPtr = createRuntimeConfiguration(designFile)
setOutputFileName(rcPtr, outputFilename)
selectDevice (rcPtr, PDF)
configureDistributedProcessing(rcPtr, "127.0.0.1", 7000)
guard let content_handler = createContentHandler(rcPtr) else {
print("Info: Report Writer server may not be started. Launch it with the following command: greportwriter -l 7000")
exit(EXIT_FAILURE)
}
let currentDate = Date()
let userCurrentCalendar = Calendar.current
let currentDateComponents = userCurrentCalendar.dateComponents([.year, .month, .day], from: currentDate)
let reportLauncher = Sales(content_handler, "Columbus Arts", 75038, currentDateComponents)
// Open the file
let reportFileURL = URL(fileURLWithPath: "../" + outputFilename).absoluteURL
print(reportFileURL)
guard NSWorkspace.shared().open(reportFileURL) else {
print("Error opening \(outputFilename).")
exit(EXIT_FAILURE)
}
exit(EXIT_SUCCESS)