// // Document.swift // Graphic Analysis 2 // // Created by Kilian Hofmann on 15.06.17. // Copyright © 2017 Kilian Hofmann. All rights reserved. // import Cocoa class Document: NSDocument { var year: FileWrapper? var months: [FileWrapper?] = [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil] var days: [[FileWrapper?]] = [] var yearDatasource: CollectionViewYear = CollectionViewYear() var monthDatasource: CollectionViewMonth = CollectionViewMonth() var windowController: NSWindowController = NSWindowController() var pdfWindows: [Data] = [Data(), Data(), Data(), Data(), Data(), Data(), Data(), Data(), Data(), Data(), Data(), Data()] var pdfBegin: Bool = false var name: String = "" @IBOutlet var collectionViewYear: NSCollectionView! @IBOutlet var collectionViewMonth: NSCollectionView! @IBOutlet var progress: NSProgressIndicator! @IBOutlet var exportProgress: NSProgressIndicator! override class var autosavesInPlace: Bool { return false; } override init() { super.init() for _ in 0..<12 { var temp: [FileWrapper?] = [] for _ in 0..<31 { temp.append(nil) } days.append(temp) } } override var windowNibName: NSNib.Name? { return NSNib.Name(rawValue: "Document") } override func read(from fileWrapper: FileWrapper, ofType typeName: String) throws { name = (fileWrapper.filename! as NSString).deletingPathExtension year = fileWrapper for entry in fileWrapper.fileWrappers! { guard let month = Int(entry.key) else { continue } months[month-1] = entry.value for entry2 in entry.value.fileWrappers! { guard let day = Int(entry2.key) else { continue } days[month-1][day-1] = entry2.value } } //throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil) } override func windowControllerDidLoadNib(_ windowController: NSWindowController) { // Setup collection layout let flowLayout = NSCollectionViewFlowLayout() flowLayout.itemSize = NSSize(width: 228, height: 211) flowLayout.sectionInset = NSEdgeInsets(top: 10, left: 0, bottom: 10, right: 0) flowLayout.minimumInteritemSpacing = 10 flowLayout.minimumLineSpacing = 10 collectionViewYear.collectionViewLayout = flowLayout let flowLayout2 = NSCollectionViewFlowLayout() flowLayout2.itemSize = NSSize(width: 135, height: 132) flowLayout2.sectionInset = NSEdgeInsets(top: 2, left: 2, bottom: 2, right: 2) flowLayout2.minimumInteritemSpacing = 2 flowLayout2.minimumLineSpacing = 2 collectionViewMonth.collectionViewLayout = flowLayout2 // Performance windowController.window?.contentView?.wantsLayer = true self.windowController = windowController // Data sources and delegate monthDatasource = CollectionViewMonth(days: days, document: self) yearDatasource = CollectionViewYear(months: months, dataSourceMonth: monthDatasource, collectionViewMonth: collectionViewMonth, document: self) collectionViewYear.dataSource = yearDatasource collectionViewYear.delegate = yearDatasource collectionViewMonth.dataSource = monthDatasource collectionViewMonth.delegate = monthDatasource } override func shouldCloseWindowController(_ windowController: NSWindowController, delegate: Any?, shouldClose shouldCloseSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) { pthread_mutex_lock(&(NSApp.delegate as! AppDelegate).lock) if !pdfBegin { super.shouldCloseWindowController(windowController, delegate: delegate, shouldClose: shouldCloseSelector, contextInfo: contextInfo) } else { let alert = NSAlert() alert.messageText = "Warning" alert.informativeText = "PDF export active. Please wait until completed." alert.alertStyle = NSAlert.Style.warning alert.addButton(withTitle: "OK") alert.runModal() } pthread_mutex_unlock(&(NSApp.delegate as! AppDelegate).lock) } override func printOperation(withSettings printSettings: [NSPrintInfo.AttributeKey : Any]) throws -> NSPrintOperation { let printOperation: NSPrintOperation = NSPrintOperation(view: collectionViewMonth) printOperation.printInfo.orientation = .landscape printOperation.printInfo.horizontalPagination = .fitPagination printOperation.printInfo.verticalPagination = .fitPagination printOperation.printInfo.topMargin = 1 printOperation.printInfo.rightMargin = 1 printOperation.printInfo.bottomMargin = 1 printOperation.printInfo.leftMargin = 1 return printOperation } @IBAction func exportPDF(sender: Any) { (sender as! NSMenuItem).isEnabled = false let savePanel: NSSavePanel = NSSavePanel() savePanel.allowedFileTypes = ["pdf"] savePanel.nameFieldStringValue = name savePanel.canCreateDirectories = true savePanel.beginSheetModal(for: windowController.window!) { result in if result.rawValue == NSFileHandlingPanelOKButton { self.exportProgress.doubleValue = 0 self.exportProgress.isHidden = false let operationQueue: OperationQueue = OperationQueue() let d_group: DispatchGroup = DispatchGroup() let bg_queue: DispatchQueue = DispatchQueue.global() operationQueue.addOperation { pthread_mutex_lock(&(NSApp.delegate as! AppDelegate).lock) self.pdfBegin = true pthread_mutex_unlock(&(NSApp.delegate as! AppDelegate).lock) var bounds: NSRect = NSMakeRect(0, 0, 964, 675) let data: NSMutableData = NSMutableData() let dataConsumer: CGDataConsumer = CGDataConsumer(data: data)! let context: CGContext = CGContext(consumer: dataConsumer, mediaBox: &bounds, nil)! context.beginPDFPage(nil) let window: PDFTitle = PDFTitle(title: "Monthly loss overview of year \(self.name)") let providerTitle: CGDataProvider = CGDataProvider(data: (window.window?.contentView?.dataWithPDF(inside: (window.window?.contentView?.bounds)!))! as CFData)! let titlePDF: CGPDFDocument = CGPDFDocument(providerTitle)! let titlePage: CGPDFPage = titlePDF.page(at: 1)! context.drawPDFPage(titlePage) context.endPDFPage() for i in 0..<12 { bg_queue.async(group: d_group, qos: DispatchQoS(qosClass: .background, relativePriority: 0), flags: .barrier) { let window: PDFDraw = PDFDraw(month: i) window.days = self.days[i] self.pdfWindows[i] = (window.window?.contentView?.dataWithPDF(inside: (window.window?.contentView?.bounds)!))! DispatchQueue.main.async { self.exportProgress.increment(by: 100/13) } } } let _: DispatchTimeoutResult = d_group.wait(timeout: .distantFuture) for i in 0..<12 { context.beginPDFPage(nil) let montDataProvider: CGDataProvider = CGDataProvider(data: self.pdfWindows[i] as CFData)! let monthPDF: CGPDFDocument = CGPDFDocument(montDataProvider)! let page: CGPDFPage = monthPDF.page(at: 1)! context.drawPDFPage(page) context.endPDFPage() } context.closePDF() data.write(to: savePanel.url!, atomically: true) DispatchQueue.main.async { self.exportProgress.increment(by: 100/13) } pthread_mutex_lock(&(NSApp.delegate as! AppDelegate).lock) self.pdfBegin = false pthread_mutex_unlock(&(NSApp.delegate as! AppDelegate).lock) self.exportProgress.isHidden = true (sender as! NSMenuItem).isEnabled = true } } } } }