Skip to content

Commit

Permalink
#205: Optionally disable table cell splicing (#223)
Browse files Browse the repository at this point in the history
* Added support for omitting first sliced cells
* Added page breaking without table cell slicing
* Added macOS support to tests
* Fixed test cases per OS
  • Loading branch information
Philip Niedertscheider authored Dec 5, 2020
1 parent 1267ff4 commit 6114276
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 68 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ jobs:
- bundle exec pod install --project-directory="${ROOT_FOLDER}"
- cd "${ROOT_FOLDER}"
script:
- set -o pipefail
- set -o pipefail
- xcodebuild -workspace "$WORKSPACE"
-scheme "$EXAMPLE_SCHEME"
-sdk iphonesimulator
Expand Down Expand Up @@ -122,7 +122,7 @@ jobs:
-clonedSourcePackagesDirPath .
-derivedDataPath ${TRAVIS_BUILD_DIR}/derived_data
-configuration Debug | xcpretty
- set -o pipefail
- set -o pipefail
- xcodebuild -project ${PROJECT}
-scheme ${EXAMPLE_SCHEME}
-clonedSourcePackagesDirPath .
Expand All @@ -146,7 +146,7 @@ jobs:
-clonedSourcePackagesDirPath .
-derivedDataPath ${TRAVIS_BUILD_DIR}/derived_data
-configuration Debug | xcpretty
- set -o pipefail
- set -o pipefail
- xcodebuild -project ${PROJECT}
-scheme ${EXAMPLE_SCHEME}
-clonedSourcePackagesDirPath .
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,21 @@

**Implemented enhancements:**

- Added optional table cell splicing disabling

**Fixed bugs:**

**Closed issues:**

- Issue #205
- Issue #222
- Issue #243
- Issue #249

**Merged pull requests:**

- PR #223

## [2.3.1](https://github.com/techprimate/TPPDF/tree/2.3.1) (2020-09-23)
[Full Changelog](https://github.com/techprimate/TPPDF/compare/2.3.0...2.3.1)

Expand Down
27 changes: 6 additions & 21 deletions Shared/Examples/ExperimentFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class ExperimentFactory: ExampleFactory {
table.margin = 10
table.padding = 10
table.showHeadersOnEveryPage = false
table.shouldSplitCellsOnPageBreak = false
table.style.columnHeaderCount = 3

for row in 0..<table.size.rows {
Expand All @@ -28,29 +29,13 @@ class ExperimentFactory: ExampleFactory {
}
}

for i in stride(from: 3, to: 48, by: 3) {
table[rows: i...(i + 2), column: 1].merge(with: PDFTableCell(content: Array(repeating: "\(i),1", count: 3).joined(separator: "\n").asTableContent,
alignment: .center))
}
for i in stride(from: 4, to: 47, by: 3) {
table[rows: i...(i + 2), column: 2].merge(with: PDFTableCell(content: Array(repeating: "\(i),2", count: 3).joined(separator: "\n").asTableContent,
alignment: .center))
}
for i in stride(from: 5, to: 48, by: 3) {
table[rows: i...(i + 2), column: 3].merge(with: PDFTableCell(content: Array(repeating: "\(i),3", count: 3).joined(separator: "\n").asTableContent,
alignment: .center))
}

table[rows: 0..<2, column: 2].merge()
table[rows: 1..<3, column: 3].merge()

document.add(table: table)

let singleCellTable = PDFTable(rows: 1, columns: 1)
singleCellTable[0,0].content = (0...100).map(String.init)
.joined(separator: "\n")
.asTableContent
document.add(table: singleCellTable)
// let singleCellTable = PDFTable(rows: 1, columns: 1)
// singleCellTable[0,0].content = (0...100).map(String.init)
// .joined(separator: "\n")
// .asTableContent
// document.add(table: singleCellTable)

return [document]
}
Expand Down
2 changes: 1 addition & 1 deletion Source/API/Table/PDFTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class PDFTable: PDFDocumentObject {
/**
Cells should split when overlapping page
*/
public var shouldSplitCellsOnPageBeak = false
public var shouldSplitCellsOnPageBreak = false

/**
Count of rows and columns in this table
Expand Down
15 changes: 15 additions & 0 deletions Source/Internal/Table/PDFTableCalculatedCell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// PDFTableCalculatedCell.swift
// TPPDF
//
// Created by Philip Niedertscheider on 19.07.20.
//

import CoreGraphics

internal struct PDFTableCalculatedCell {
var cell: PDFTableCell
var type: PDFTableObject.CellType
var style: PDFTableCellStyle
var frames: (cell: CGRect, content: CGRect)
}
117 changes: 74 additions & 43 deletions Source/Internal/Table/PDFTableObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@ import AppKit

// swiftlint:disable function_parameter_count

internal typealias PDFTableCalculatedCell = (cell: PDFTableCell,
type: PDFTableObject.CellType,
style: PDFTableCellStyle,
frames: (cell: CGRect, content: CGRect))

/**
Internal object, used for calculating a `PDFTable`
*/
Expand Down Expand Up @@ -144,7 +139,7 @@ internal class PDFTableObject: PDFRenderObject {
type: CellType,
origin: CGPoint,
width: CGFloat) -> PDFTableCalculatedCell {
var frame: PDFTableCalculatedCell = (
var frame = PDFTableCalculatedCell(
cell: cell,
type: type,
style: style,
Expand Down Expand Up @@ -335,8 +330,18 @@ internal class PDFTableObject: PDFRenderObject {
minOffset += headerHeight
}

var onPageCells: [PDFTableCalculatedCell]
(onPageCells, nextPageCells) = filterCellsOnPage(for: generator, items: nextPageCells, minOffset: minOffset, maxOffset: maxOffset)
let filterResult = filterCellsOnPage(for: generator,
items: nextPageCells,
minOffset: minOffset,
maxOffset: maxOffset,
shouldSplitCellsOnPageBeak: table.shouldSplitCellsOnPageBreak)
let onPageCells = filterResult.cells
nextPageCells = filterResult.remainder
// If none of the cells fit on the current page, the algorithm will try again on the next page and if it occurs again, an error should be thrown
if onPageCells.isEmpty && !firstPage, let firstInvalidCell = nextPageCells.first {
throw PDFError.tableCellTooBig(cell: firstInvalidCell.cell)
}


for (idx, item) in onPageCells.enumerated() {
let cellFrame = item.frames.cell
Expand Down Expand Up @@ -392,29 +397,60 @@ internal class PDFTableObject: PDFRenderObject {
return (objects: result, offset: pageEnd.y)
}

internal typealias FilteredCells = (cells: [PDFTableCalculatedCell], rest: [PDFTableCalculatedCell])
/// Holds two lists of cells, used during table calculations
internal struct FilteredCells {
/// List of calculated cells on the active page
var cells: [PDFTableCalculatedCell]
/// List of remaining cells on further pages
var remainder: [PDFTableCalculatedCell]
}


internal func filterCellsOnPage(for generator: PDFGenerator, items: [PDFTableCalculatedCell], minOffset: CGFloat, maxOffset: CGFloat) -> FilteredCells {
/// Filters the given list of cells into the ones that fit on the current page, and all remainding cells, repositioned for the next page.
///
/// - Parameters:
/// - generator: Active instance of `PDFGenerator`
/// - items: List of cells to filter
/// - minOffset: Minimum `y`-position on the page
/// - maxOffset: Maximum `y`-position on the page
/// - shouldSplitCellsOnPageBreak: If `true`, cells won't be sliced and shown on both pages, instead moved entirely to the next page
/// - Returns: Two lists of cells, see `FilteredCells`
internal func filterCellsOnPage(for generator: PDFGenerator, items: [PDFTableCalculatedCell], minOffset: CGFloat, maxOffset: CGFloat, shouldSplitCellsOnPageBeak: Bool) -> FilteredCells {
// Maximum height available
let contentHeight = maxOffset - minOffset
var result = FilteredCells(cells: [], remainder: [])

var cells: [PDFTableCalculatedCell] = []
var rest: [PDFTableCalculatedCell] = []
var offsetFix: CGFloat!

for item in items {
// Iterate each cell and decide if it fits on current page or if it needs to be moved to the further pages
for item in items {
let cellFrame = item.frames.cell
if cellFrame.maxY < maxOffset {
cells.append(item)

// Cells needs to fit the current available space entirely
if cellFrame.maxY < maxOffset { // TODO: is the row padding relevant here?
result.cells.append(item)
} else {
if cellFrame.minY < maxOffset {
cells.append(item)
// If cells should be split and cell is partially on current page, add it to the cells, the cell will be sliced afterwards
if shouldSplitCellsOnPageBeak && cellFrame.minY < maxOffset {
result.cells.append(item)
}
// In any case, if the cell does not fit on the active page entirely, it must be repositioned for further pages
var nextPageCell = item
nextPageCell.frames.cell.origin.y -= contentHeight
nextPageCell.frames.content.origin.y -= contentHeight
rest.append(nextPageCell)
if shouldSplitCellsOnPageBeak {
nextPageCell.frames.cell.origin.y -= contentHeight
nextPageCell.frames.content.origin.y -= contentHeight
} else {
let cellContentOffset = nextPageCell.frames.content.minY - nextPageCell.frames.cell.minY
if offsetFix == nil {
offsetFix = nextPageCell.frames.cell.minY - minOffset
}
nextPageCell.frames.cell.origin.y -= offsetFix
nextPageCell.frames.content.origin.y = nextPageCell.frames.cell.minY + cellContentOffset
}
result.remainder.append(nextPageCell)
}
}
return (cells: cells, rest: rest)
return result
}

internal func createSliceObject(frame: CGRect, elements: [PDFRenderObject], minOffset: CGFloat, maxOffset: CGFloat) -> PDFSlicedObject {
Expand All @@ -430,9 +466,12 @@ internal class PDFTableObject: PDFRenderObject {
return sliceObject
}

/**
Creates a render object for the cell background
*/
/// Creates a render object for the cell background
///
/// - Parameters:
/// - style: Style of table cell
/// - frame: Frame of cell
/// - Returns: Calculated `PDFRectangleObject`
internal func createCellBackgroundObject(style: PDFTableCellStyle, frame: CGRect) -> PDFRenderObject {
let object = PDFRectangleObject(lineStyle: .none, size: frame.size, fillColor: style.colors.fill)
object.frame = frame
Expand Down Expand Up @@ -500,14 +539,11 @@ internal class PDFTableObject: PDFRenderObject {
return .content
}

/**
Returns the style of a given cell, depending on the type.
- parameters tableStyle: Style configuration of table
- parameters type: Type of cell
- returns: Style of cell
*/
/// Returns the style of a given cell, depending on the type.
/// - Parameters:
/// - tableStyle: Style configuration of table
/// - type: Type of cell
/// - Returns: Style of cell
internal func getStyle(tableStyle: PDFTableStyle, type: CellType) -> PDFTableCellStyle {
switch type {
case .header:
Expand All @@ -525,14 +561,11 @@ internal class PDFTableObject: PDFRenderObject {
}
}

/**
Creates four outline line objects around a given frame using the given style.
- parameter borders: Style of each border direction
- parameter frame: Frame of rectangle
- returns: Array of `PDFLineObject`
*/
/// Creates four outline line objects around a given frame using the given style.
/// - Parameters:
/// - borders: Style of each border edge
/// - frame: Frame of rectangle
/// - Returns: Array of `PDFLineObject`
internal func createCellOutlineObjects(borders: PDFTableCellBorders, frame: CGRect) -> [PDFLineObject] {
[
PDFLineObject(style: borders.top,
Expand All @@ -550,9 +583,7 @@ internal class PDFTableObject: PDFRenderObject {
]
}

/**
Creates a new `PDFTableObject` with the same properties
*/
/// Creates a new `PDFTableObject` with the same properties
override internal var copy: PDFRenderObject {
PDFTableObject(table: table.copy)
}
Expand Down
4 changes: 4 additions & 0 deletions TPPDF.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@
D4803D3A24703E5300DDA039 /* PDFAttributedText.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4803C9F24703E5300DDA039 /* PDFAttributedText.swift */; };
D4803D3B24703E5300DDA039 /* PDFText.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4803CA024703E5300DDA039 /* PDFText.swift */; };
D4803D3C24703E5300DDA039 /* PDFTextStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4803CA124703E5300DDA039 /* PDFTextStyle.swift */; };
D4839C39253706950005BB87 /* PDFTableCalculatedCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4839C38253706950005BB87 /* PDFTableCalculatedCell.swift */; };
D4EE2F9724A34C990004E3B9 /* PDFContextGraphics.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EE2F9624A34C990004E3B9 /* PDFContextGraphics.swift */; };
D4EE2F9924A34CBF0004E3B9 /* CrossPlattformGraphics.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EE2F9824A34CBF0004E3B9 /* CrossPlattformGraphics.swift */; };
OBJ_419 /* AdapterProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_331 /* AdapterProtocols.swift */; };
Expand Down Expand Up @@ -621,6 +622,7 @@
D4803C9F24703E5300DDA039 /* PDFAttributedText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFAttributedText.swift; sourceTree = "<group>"; };
D4803CA024703E5300DDA039 /* PDFText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFText.swift; sourceTree = "<group>"; };
D4803CA124703E5300DDA039 /* PDFTextStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFTextStyle.swift; sourceTree = "<group>"; };
D4839C38253706950005BB87 /* PDFTableCalculatedCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFTableCalculatedCell.swift; sourceTree = "<group>"; };
D4EE2F9624A34C990004E3B9 /* PDFContextGraphics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PDFContextGraphics.swift; sourceTree = "<group>"; };
D4EE2F9824A34CBF0004E3B9 /* CrossPlattformGraphics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrossPlattformGraphics.swift; sourceTree = "<group>"; };
"Nimble::Nimble::Product" /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -1054,6 +1056,7 @@
D4803C3724703E5300DDA039 /* Table */ = {
isa = PBXGroup;
children = (
D4839C38253706950005BB87 /* PDFTableCalculatedCell.swift */,
D4803C3824703E5300DDA039 /* PDFTableMergeUtil.swift */,
D4803C3924703E5300DDA039 /* PDFTableNode.swift */,
D4803C3A24703E5300DDA039 /* PDFTableObject.swift */,
Expand Down Expand Up @@ -2265,6 +2268,7 @@
D4803D1124703E5300DDA039 /* PDFBezierPath.swift in Sources */,
D4803D3A24703E5300DDA039 /* PDFAttributedText.swift in Sources */,
D4803D2224703E5300DDA039 /* PDFTable+RowSubscripts.swift in Sources */,
D4839C39253706950005BB87 /* PDFTableCalculatedCell.swift in Sources */,
D4803CF924703E5300DDA039 /* PDFSection.swift in Sources */,
D4803CB924703E5300DDA039 /* PDFPaginationStyle+Equatable.swift in Sources */,
D4803CD124703E5300DDA039 /* PDFRectangleObject.swift in Sources */,
Expand Down
Loading

0 comments on commit 6114276

Please sign in to comment.