Take over from Github

This commit is contained in:
Mike Müller 2018-08-29 13:31:07 +02:00
commit 5812e7525e
28 changed files with 2789 additions and 0 deletions

30
Classes/MVPDFReport.h Normal file
View File

@ -0,0 +1,30 @@
//
// MVPDFReport.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReport.h"
/**
* MVPDFReport is concrete sublcass of MVReport that generates PDF reports.
*/
@interface MVPDFReport : MVReport
@end

83
Classes/MVPDFReport.m Normal file
View File

@ -0,0 +1,83 @@
//
// MVPDFReport.m
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVPDFReport.h"
#import "MVReportPageRenderer+Private.h"
#import "MVReportTextFormatter+Private.h"
@import CoreGraphics;
@interface MVPDFReport ()
@property (nonatomic, strong)NSMutableData *data;
@end
@implementation MVPDFReport
- (id)generateReport
{
self.data = [NSMutableData data];
if (self.pageRenderer)
{
UIGraphicsBeginPDFContextToData(self.data, self.pageInfo.pageRect, nil);
NSInteger pageCount = [self.pageRenderer numberOfPages];
[self.pageRenderer prepareForDrawing];
for (NSInteger page = 0; page < pageCount; page++)
{
UIGraphicsBeginPDFPage();
CGRect rect = self.pageInfo.printableRect;
[self.pageRenderer drawPageAtIndex:page inRect:rect];
}
UIGraphicsEndPDFContext();
return [self.data copy];
}
else if (self.pageElement)
{
UIGraphicsBeginPDFContextToData(self.data, self.pageInfo.pageRect, nil);
self.pageElement.contentRect = self.pageInfo.printableRect;
NSInteger pageCount = [self.pageElement pageCount];
[self.pageElement prepareForDrawing];
for (NSInteger page = 0; page < pageCount; page++)
{
UIGraphicsBeginPDFPage();
CGRect rect = [self.pageElement rectForPageAtIndex:page];
[self.pageElement drawInRect:rect forPageAtIndex:page];
}
UIGraphicsEndPDFContext();
return [self.data copy];
}
else
{
return nil;
}
}
@end

38
Classes/MVReport-iOS.h Normal file
View File

@ -0,0 +1,38 @@
//
// MVReport-iOS.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef MVReport_iOS_MVReport_iOS_h
#define MVReport_iOS_MVReport_iOS_h
#import "MVReport.h"
#import "MVPDFReport.h"
#import "MVReportPageInfo.h"
#import "MVReportPageElement.h"
#import "MVReportTextFormatter.h"
#import "MVReportSimpleTextFormatter.h"
#import "MVReportMarkupTextFormatter.h"
#import "MVReportSection.h"
#import "MVReportSectionElement.h"
#import "MVReportPageRenderer.h"
#endif

95
Classes/MVReport.h Normal file
View File

@ -0,0 +1,95 @@
//
// MVReport.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#import "MVReportPageInfo.h"
#import "MVReportPageRenderer.h"
#import "MVReportPageElement.h"
/**
Base abstract class for report generation. Do not instantiate this class, use more specialized ones for desired report type.
## Subclassing Notes
If you create subclass or MVReport you MUST override `-generateReport` and return a result. Default implementation will raise an exeption.
## Methods to Override
To generate report of type not already provided by the framework you should override method `-generateReport`. Once you did this, its your resposibility to initialize apropriate context, render to it and return generated data.
*/
@interface MVReport : NSObject
/**
@name Accessing Report Information
*/
/**
An object representing the paper size and printing area for the report. (read-only)
*/
@property (nonatomic,readonly, strong)MVReportPageInfo *pageInfo;
/**
@name Providing the Source of Report Content
*/
/**
An object that draws pages of printable content when requested.
The object assigned to this property must be an instance of a custom subclass of MVReportPageRenderer. The default value is nil.
If you set this property, MVReport sets the textFormatter property to nil. (Only one of these properties can be set for a print job.)
*/
@property (nonatomic, strong)MVReportPageRenderer *pageRenderer;
/**
An object that lays out the content of pages based on the kind of content.
Assign to this property an instance of one of the concrete subclasses of MVReportPageElement: MVReportSimpleTextFormatter, MVReportMarkupTextFormatter, and MVReportSection. The default value is nil.
If you set this property, MVReport sets the pageRenderer property to nil. (Only one of these properties can be set for a report generation.)
*/
@property (nonatomic, strong)MVReportPageElement *pageElement;
/**
@name Generating Report
*/
/**
Generates and returns a report.
@return generated report.
*/
- (id)generateReport;
/**
@name Creating MVReport Instance
*/
/**
Returns a newly initialized report with the page info assigned.
@param pageInfo decription of the page used in report.
@return A newly initialized MVReport object.
*/
- (instancetype)initWithPageInfo:(MVReportPageInfo *)pageInfo;
@end

69
Classes/MVReport.m Normal file
View File

@ -0,0 +1,69 @@
//
// MVReport.m
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReport.h"
#import "MVReportPageRenderer+Private.h"
#import "MVReportTextFormatter+Private.h"
@interface MVReport ()
@property (nonatomic,readwrite, strong)MVReportPageInfo *pageInfo;
@end
@implementation MVReport
- (instancetype)initWithPageInfo:(MVReportPageInfo *)pageInfo
{
if (!pageInfo)
{
return nil;
}
self = [super init];
if (self)
{
self.pageInfo = pageInfo;
}
return self;
}
- (id)generateReport
{
NSAssert(NO, @"Should be implemented by subclasses");
return nil;
}
- (void)setPageRenderer:(MVReportPageRenderer *)pageRenderer
{
if (_pageRenderer)
{
_pageRenderer.pageInfo = nil;
}
_pageRenderer = pageRenderer;
_pageRenderer.pageInfo = self.pageInfo;
}
@end

View File

@ -0,0 +1,60 @@
//
// MVReportMarkupTextFormatter.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportTextFormatter.h"
/**
Instances of the MVReportMarkupTextFormatter class lay out HTML markup text, possibly over multiple pages.
To use this report formatter for a report, create an instance of MVReportMarkupTextFormatter initialized with the HTML, set the inherited layout properties, and add the object to the report in one of two ways:
- If a single report formatter is being used for the report (with no additional drawing), assign it to the pageElement property of the MVReport instance. The inherited startPage property identifies the beginning page of content with which the formatter is associated.
- If you are using multiple elements along with a page renderer, associate each report formatter with a starting page of the printed content. You often take this approach when you want to add content such as headers and footers to what the formatters provide. You have two ways of associating a report formatter with a MVReportPageRenderer object:
- You can add report formatters to the pageElements property of the MVReportPageRenderer object; the startPage property of the report formatter specifies the starting page.
- You can add report formatters by calling `-addPageElement:startingAtPageAtIndex:` for each report formatter; the second parameter of this method specifies the starting page (and overrides any startPage value).
*/
@interface MVReportMarkupTextFormatter : MVReportTextFormatter
/**
@name Getting the Markup Text
*/
/**
The HTML markup text for the print formatter.
*/
@property(nonatomic,readonly, copy) NSString *markupText;
/**
@name Creating a Markup-Text Report Formatter
*/
/**
Returns a markup-text print formatter initialized with an HTML string.
@param markupText A string of HTML markup text.
@return An instance of MVReportMarkupTextFormatter or nil if the object could not be created.
*/
- (instancetype)initWithMarkupText:(NSString *)markupText;
@end

View File

@ -0,0 +1,64 @@
//
// MVReportMarkupTextFormatter.m
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportMarkupTextFormatter.h"
#import "MVReportTextFormatter+Private.h"
@interface MVReportMarkupTextFormatter ()
@property(nonatomic,readwrite, copy) NSString *markupText;
@end
@implementation MVReportMarkupTextFormatter
- (instancetype)initWithMarkupText:(NSString *)markupText
{
self = [super init];
if (self)
{
self.markupText = markupText;
}
return self;
}
- (void)setMarkupText:(NSString *)markupText
{
_markupText = markupText;
if ([_markupText length] > 0)
{
NSData *sData = [markupText dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:@(8)};
NSError *error;
NSAttributedString *aStr = [[NSAttributedString alloc] initWithData:sData options:options documentAttributes:nil error:&error];
self.attributedString = aStr;
}
else
{
self.attributedString = nil;
}
}
@end

View File

@ -0,0 +1,35 @@
//
// MVReportPageElement+Private.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportPageElement.h"
@interface MVReportPageElement (Private)
@property(nonatomic, readwrite, assign) MVReportPageRenderer *reportPageRenderer;
@property(nonatomic, readonly) NSInteger lastPage;
@property(nonatomic)CGRect contentRect;
@property (nonatomic, weak)MVReportPageElement *priorPageElement;
- (void)prepareForDrawing;
@end

View File

@ -0,0 +1,129 @@
//
// MVReportPageElement.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
@import CoreGraphics;
@import UIKit;
@class MVReportPageRenderer;
/**
MVReportPageElement is an abstract base class for page elements: objects that lay out custom printable content that can cross page boundaries. Given a page element, the report system can automate the generation of the type of content associated with the page element.
Examples of such content could be a web view, a mix of images and text, or a long text document. The MVReport framework provides several concrete subclasses of MVReportPageElement: MVReportSimpleTextFormatter, MVReportMarkupTextFormatter, and MVReportSection (alongside with MVReportSectionElement).
You can assign a single page element for a report via the pageElement property of the MVReport instance; or you can specify one or more page elements that are associated with specific pages of a page renderer through the `-addPageElement:startingAtPageAtIndex:` method of MVReportPageRenderer. A page renderer is an instance of a custom subclass of MVReportPageRenderer that draws content for printing.
MVReportPageElement publishes an interface that allows you to specify the starting page for a print job and the margins around the printed content; given that information plus the content, a page element computes the number of pages for the report.
## Subclassing Notes
You rarely should subclass MVReportPageElement, but in case where you want to add new type of a element to report it will be your only option. Keep in mind that your subclass needs to override all methods metioned bellow.
## Methods to Override
When creating custom subclass from MVReportPageElement you should override following methods `-pageCount` to return proper number of pages needed to render the element, `-rectForPageAtIndex:` to return valid rect for rendering for each page requested, and `-drawInRect:forPageAtIndex:` to actually render your element in specified rect.
*/
@interface MVReportPageElement : NSObject
/**
@name Laying Out the Content
*/
/**
The distances the edges of content are inset from the printing rectangle.
This property adjusts the margins for content generated by the formatter. The printing rectangle defines the area the printer is capable of printing in; each inset is an inward distance, in points, from a side of the printing area. The top inset is used only on the first page that the element draws. The bottom inset is not used. You can use the UIEdgeInsetsMake macro to create a UIEdgeInsets structure.
*/
@property(nonatomic) UIEdgeInsets contentInsets;
/**
The maximum height of the content area.
*/
@property(nonatomic) CGFloat maximumContentHeight;
/**
The maximum width of the content area.
MVReportPageElement uses this value to determine the maximum width of the content rectangle. It compares the value of this property with the printing rectangles width minus the left and right inset values and uses the lower of the two. The default value of this property is the maximum float value.
*/
@property(nonatomic) CGFloat maximumContentWidth;
/**
@name Managing Pagination
*/
/**
The index of the first page that the page element lays out.
The value is a zero-based index. You can set the starting page of a page element by assigning an index to this property or by passing one as the second argument of the `-addPageElement:startingAtPageAtIndex:` method of MVReportPageRenderer.
*/
@property(nonatomic) NSInteger startPage;
/**
The number of pages to be generated by this element. (read-only)
MVReportPageElement calculates this value based on the layout metrics and content.
*/
@property(nonatomic, readonly) NSInteger pageCount;
/**
@name Communicating with the Page Renderer
*/
/**
Returns the page renderer with which the receiver is associated.
If the receiving page element was not added to a page rendererthat is, it was assigned to the pageElement property of the MVReport classthe value returned is nil.
*/
@property(nonatomic, readonly, assign) MVReportPageRenderer *reportPageRenderer;
/**
Removes the page element from the page renderer.
A page element is typically associated with a pages of a MVReportPageRenderer object through the `-addPageElement:startingAtPageAtIndex:` method.
*/
- (void)removeFromReportPageRenderer;
/**
@name Drawing the Content
*/
/**
Draws the portion of a page element's content that goes in the given area for the specified page
@param rect The area in which to draw the content.
@param pageIndex The number of the page of content to draw.
This method is called by the default implementation of `-drawPageElement:forPageAtIndex:` of the MVReportPageRenderer class for each page element associated with a page.
*/
- (void)drawInRect:(CGRect)rect forPageAtIndex:(NSInteger)pageIndex;
/**
Returns the area enclosing a specified page of content.
@param pageIndex The index number of a page.
@return A rectangle enclosing the content area for page pageIndex.
Returns CGRectZero if the page element draws no content on the specified page.
*/
- (CGRect)rectForPageAtIndex:(NSInteger)pageIndex;
@end

View File

@ -0,0 +1,120 @@
//
// MVReportPageElement.m
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportPageElement+Private.h"
#import "MVReportPageRenderer+Private.h"
@interface MVReportPageElement ()
{
CGRect _contentRect;
__weak MVReportPageElement *_priorPageElement;
}
@end
@implementation MVReportPageElement
- (void)initInstance
{
self.maximumContentHeight = CGFLOAT_MAX;
self.maximumContentWidth = CGFLOAT_MAX;
self.startPage = 0;
}
- (instancetype)init
{
self = [super init];
if (self)
{
[self initInstance];
}
return self;
}
- (NSInteger)lastPage
{
return self.startPage + ([self pageCount]-1);
}
- (MVReportPageElement *)priorPageElement
{
return _priorPageElement;
}
- (void)setPriorPageElement:(MVReportPageElement *)priorPageElement
{
_priorPageElement = priorPageElement;
}
- (CGRect)contentRect
{
return _contentRect;
}
- (void)setContentRect:(CGRect)contentRect
{
_contentRect = contentRect;
}
- (void)setReportPageRenderer:(MVReportPageRenderer *)reportPageRenderer
{
if (self.reportPageRenderer)
{
[self.reportPageRenderer removePageElement:self];
}
_reportPageRenderer = reportPageRenderer;
}
- (void)removeFromReportPageRenderer
{
self.reportPageRenderer = nil;
}
- (void)drawInRect:(CGRect)rect forPageAtIndex:(NSInteger)pageIndex
{
NSAssert(NO, @"should be implemented by subclass");
}
- (CGRect)rectForPageAtIndex:(NSInteger)pageIndex
{
NSAssert(NO, @"should be implemented by subclass");
return CGRectZero;
}
- (void)prepareForDrawing
{
NSAssert(NO, @"should be implemented by subclass");
}
- (NSInteger)pageCount
{
NSAssert(NO, @"should be implemented by subclass");
return 0;
}
@end

View File

@ -0,0 +1,50 @@
//
// MVReportPageInfo.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
@import CoreGraphics;
/**
An instance of the MVReportPageInfo class encapsulates the size of paper used for a report and the rectangle in which content can be generated.
If you want to print generated report, you can obtain UIPrintPaper instance for the print job and use its properties to create MVReportPageInfo.
*/
@interface MVReportPageInfo : NSObject
/**
@name Getting the Paper Size and the Printing Area
*/
/**
The size of the sheet to be used for report.
The paper size is often associated with a standard designation, such as Letter and A4. For example, the paper size for a Letter sheet of paper is 612 points wide and 792 points high.
*/
@property(nonatomic, assign) CGRect pageRect;
/**
The rectangle that represents the portion of the paper that can be imaged upon.
*/
@property(nonatomic, assign) CGRect printableRect;
@end

View File

@ -0,0 +1,40 @@
//
// MVReportPageInfo.m
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportPageInfo.h"
@implementation MVReportPageInfo
- (instancetype)init
{
self = [super init];
if (self)
{
self.pageRect = CGRectMake(0, 0, 612, 792);
self.printableRect = CGRectInset(self.pageRect, 10, 20);
}
return self;
}
@end

View File

@ -0,0 +1,33 @@
//
// MVReportPageRenderer+Private.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportPageRenderer.h"
#import "MVReportPageInfo.h"
@interface MVReportPageRenderer (Private)
@property (nonatomic, weak)MVReportPageInfo *pageInfo;
- (void)removePageElement:(MVReportPageElement *)element;
@end

View File

@ -0,0 +1,185 @@
//
// MVReportPageRenderer.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
@import CoreGraphics;
@class MVReportPageElement;
/**
A MVReportPageRenderer object draws pages of content in the report, with or without the assistance of page elements.
A page renderer is an instance of a custom subclass of MVReportPageRenderer. When you compose a report using the instance of MVReport, you assign the page renderer to the pageRenderer property of that instance. The subclass typically overrides one or more of the five draw... methods:
- The `-drawPageAtIndex:inRect:` by default calls each of the other draw methods, in the order listed below. Your application can override it if you want to have complete control over what is drawn in the report.
- Override `-drawHeaderForPageAtIndex:inRect:` to draw content in the header.
- Override `-drawContentForPageAtIndex:inRect:` to draw the main content of the report in the area between the header and the footer.
- Override `-drawPageElement:forPageAtIndex:` to intermix custom drawing with the drawing performed by an associated page element. This method is called for each page element associated with a given page.
- Override `-drawFooterForPageAtIndex:inRect:` to draw content in the footer.
MVReportPageRenderer usually requires you to specify the number of pages of the content by overriding numberOfPages. It also allows you to specify the heights of page headers and footers.
You may assign one or more page elementsthat is, MVReportPageElement objects that can lay out content of a certain kindto specific page ranges of the content. For example, if your content is partially HTML, you may assign an instance of the MVReportMarkupTextFormatter object to the starting page of HTML content. You assign a report formatter using the `-addPageElement:startingAtPageAtIndex:` method and you can get the report formatters for a given page by calling `-pageElementsForPageAtIndex:`.
*/
@interface MVReportPageRenderer : NSObject
/**
@name Accessing Information About the Report
*/
/**
The number of pages to render.
By default, returns the number of pages as calculated by MVReport if the receiver uses page elements. If the page renderer uses no page elements, the returned value is zero. If your page renderer is doing any custom drawing except for headers and footers, it must override this method.
This method is called at any point when MVReport needs the number of pages.
If page elements arent used to compute the page count, the page renderer can override this method to calculate and return the number of pages. The computation can take into account the current printableRect value for each page, any implicit margins, and the content to be drawn when laid out within these boundaries.
*/
- (NSInteger)numberOfPages;
/**
@name Specifying Header and Footer Heights
*/
/**
The height of the page header.
The header is measured in points from the top of printableRect and is above the content area. The default header height is 0.0.
*/
@property(nonatomic) CGFloat headerHeight;
/**
The height of the page footer.
The footer is measured in points from the bottom of printableRect and is below the content area. The default footer height is 0.0.
*/
@property(nonatomic) CGFloat footerHeight;
/**
@name Managing Page Elements
*/
/**
The page elements associated with the page renderer.
The elements of the array are MVReportPageElement objects. A page element can be an instance of MVReportSimpleTextFormatter, MVReportMarkupTextFormatter, or MVReportSection. Page elements added this way to a page renderer are associated with page ranges through each page element's startPage and pageCount properties.
*/
@property(nonatomic, copy) NSArray *pageElements;
/**
Adds a page element to the page renderer starting at the specified page.
@param element The MVReportPageElement object to add to the page renderer. A page element can be an instance of MVReportSimpleTextFormatter, MVReportMarkupTextFormatter, or MVReportSection.
@param pageIndex The index identifying the first page with which the page element should be associated with. This value overrides the startPage property of the page element.
*/
- (void)addPageElement:(MVReportPageElement *)element startingAtPageAtIndex:(NSInteger)pageIndex;
/**
Adds a page element to the page renderer starting after priorElement.
@param element The MVReportPageElement object to add to the page renderer. A page element can be an instance of MVReportSimpleTextFormatter, MVReportMarkupTextFormatter, or MVReportSection.
@param priorElement page element after which page element should be added.
When you add page element to page renderer this way, start page and top content insets of the element will be overriden. You should not try to change those after page element is assigned to the page renderer.
*/
- (void)addPageElement:(MVReportPageElement *)element afterPageElement:(MVReportPageElement *)priorElement;
/**
Returns the page elements associated with a specified page.
@param pageIndex The index of a page of the report.
@return An array of MVReportPageElement objects. A page element can be an instance of MVReportSimpleTextFormatter, MVReportMarkupTextFormatter, or MVReportSection.
A page element is associated with a starting page of report through the `-addPageElement:startingAtPageAtIndex:` method or the startPage property of MVReportPageElement. The number of pages from that page is determined by the pageCount property, which MVReportPageElement computes based on layout metrics and content.
*/
- (NSArray *)pageElementsForPageAtIndex:(NSInteger)pageIndex;
/**
@name Preparing for Drawing
*/
/**
Overridden by the page renderer to prepare for drawing.
MVReport calls this method before it requests drawing of the report. You can optionally override this method to perform setup tasks.
@warning If you are using page elements in page renderer you should call super before any other call.
*/
- (void)prepareForDrawing;
/**
@name Drawing a Page
*/
/**
Overridden to draw a given page of content for the report.
@param index The index of the page to draw.
@param pageRect The rectangle in which printable content can be drawn.
The default implementation of this method calls, in sequence, `-drawHeaderForPageAtIndex:inRect:`, `-drawContentForPageAtIndex:inRect:`, `-drawPageElement:forPageAtIndex:`, and `-drawFooterForPageAtIndex:inRect:`. The method is set up for drawing to the current graphics context (as returned by UIGraphicsGetCurrentContext).
*/
- (void)drawPageAtIndex:(NSInteger)index inRect:(CGRect)pageRect;
/**
Overridden to draw the header of the given page.
@param index The index of the page in which to draw the header.
@param headerRect The rectangle in which the header content should be drawn. It is specified in the coordinate system of the page rectangle (pageRect); that is, the origin of coordinates is at the top-left corner of the sheet.
The default implementation of this method does nothing. It is not called if headerHeight is not a positive value. The method is set up for drawing to the current graphics context (as returned by UIGraphicsGetCurrentContext).
*/
- (void)drawHeaderForPageAtIndex:(NSInteger)index inRect:(CGRect)headerRect;
/**
Overridden to draw the content of the given page.
@param index The index of the page in which to draw content.
@param contentRect The area in which content is to be drawn, specified in the coordinate system of the page rectangle (pageRect); that is, the origin of coordinates is at the top-left corner of the sheet.
The default implementation of this method does nothing. The method is set up for drawing to the current graphics context (as returned by UIGraphicsGetCurrentContext).
*/
- (void)drawContentForPageAtIndex:(NSInteger)index inRect:(CGRect)contentRect;
/**
Overridden to add custom drawing to the drawing provided by a given page element for a page.
@param element A MVReportPageElement object associated with page index.
@param index The index of the page in which element is to draw.
This method is invoked for each page element assigned to the specified page. The default implementation invokes the `-drawInRect:forPageAtIndex:` method of the MVReportPageElement object that is passed in. You can override this method to intermix custom drawing with the element drawingfor example, by adding an overlay or underlay graphic. Call `-drawInRect:forPageAtIndex:` to have the page element draw its portion of the page. The method is set up for drawing to the current graphics context (as returned by UIGraphicsGetCurrentContext).
*/
- (void)drawPageElement:(MVReportPageElement *)element forPageAtIndex:(NSInteger)index;
/**
Overridden to draw the footer of the given page.
@param index The index of the page in which to draw the footer content.
@param footerRect The rectangle in which the footer content should be drawn. It is specified in the coordinate system of the page rectangle (pageRect); that is, the origin of coordinates is at the top-left corner of the sheet.
The default implementation of this method does nothing. It is not called if footerHeight is not a positive value. The method is set up for drawing to the current graphics context (as returned by UIGraphicsGetCurrentContext).
*/
- (void)drawFooterForPageAtIndex:(NSInteger)index inRect:(CGRect)footerRect;
@end

View File

@ -0,0 +1,214 @@
//
// MVReportPageRenderer.m
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportPageRenderer+Private.h"
#import "MVReportPageElement+Private.h"
@interface MVReportPageRenderer ()
{
MVReportPageInfo *_pageInfo;
}
@property (nonatomic)CGRect headerRect;
@property (nonatomic)CGRect contentRect;
@property (nonatomic)CGRect footerRect;
@end
@implementation MVReportPageRenderer
- (void)setPageInfo:(MVReportPageInfo *)pageInfo
{
_pageInfo = pageInfo;
[self calculateRectsForPageRect:pageInfo.printableRect];
for (MVReportPageElement *element in self.pageElements)
{
element.contentRect = self.contentRect;
}
}
- (MVReportPageInfo *)pageInfo
{
return _pageInfo;
}
- (void)setPageElements:(NSArray *)pageElements
{
for (MVReportPageElement *element in pageElements)
{
element.reportPageRenderer = self;
}
}
- (NSInteger)numberOfPages
{
NSInteger result = 0;
for (MVReportPageElement *element in self.pageElements)
{
NSInteger tc = [element pageCount];
//start page can be modified by page count call in case of chained elements...
NSInteger sp = element.startPage;
result = MAX(result, sp+tc);
}
return result;
}
- (void)addPageElement:(MVReportPageElement *)element startingAtPageAtIndex:(NSInteger)pageIndex
{
element.startPage = pageIndex;
element.reportPageRenderer = self;
element.contentRect = self.contentRect;
NSMutableArray *mutableElements = [self.pageElements mutableCopy];
if (!mutableElements)
{
mutableElements = [NSMutableArray array];
}
[mutableElements addObject:element];
_pageElements = [mutableElements copy];
}
- (void)addPageElement:(MVReportPageElement *)element afterPageElement:(MVReportPageElement *)priorElement
{
element.reportPageRenderer = self;
element.contentRect = self.contentRect;
element.priorPageElement = priorElement;
NSMutableArray *mutableElements = [self.pageElements mutableCopy];
if (!mutableElements)
{
mutableElements = [NSMutableArray array];
}
[mutableElements addObject:element];
_pageElements = [mutableElements copy];
}
- (void)removePageElement:(MVReportPageElement *)element
{
if ([self.pageElements containsObject:element])
{
NSMutableArray *mutableElements = [self.pageElements mutableCopy];
[mutableElements removeObject:element];
_pageElements = [mutableElements copy];
}
}
- (NSArray *)pageElementsForPageAtIndex:(NSInteger)pageIndex
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(startPage <= %d) AND (lastPage >= %d)",pageIndex, pageIndex];
return [self.pageElements filteredArrayUsingPredicate:predicate];
}
- (void)prepareForDrawing
{
for (MVReportPageElement *element in self.pageElements)
{
[element prepareForDrawing];
}
}
- (void)calculateRectsForPageRect:(CGRect)pageRect
{
NSInteger contentHeight = pageRect.size.height;
NSInteger contentOffset = pageRect.origin.y;
if (self.headerHeight > 0)
{
CGRect rect = pageRect;
rect.size.height = self.headerHeight;
self.headerRect = rect;
contentHeight = contentHeight - self.headerHeight;
contentOffset = contentOffset + self.headerHeight;
}
else
{
self.headerRect = CGRectZero;
}
if (self.footerHeight)
{
CGRect rect = pageRect;
rect.size.height = self.footerHeight;
rect.origin.y = (pageRect.origin.y + pageRect.size.height) - self.footerHeight;
self.footerRect = rect;
contentHeight = contentHeight - self.footerHeight;
}
else
{
self.footerRect = CGRectZero;
}
CGRect cRect = pageRect;
cRect.origin.y = contentOffset;
cRect.size.height = contentHeight;
self.contentRect = cRect;
}
- (void)drawPageAtIndex:(NSInteger)index inRect:(CGRect)pageRect
{
if (self.headerHeight > 0)
{
[self drawHeaderForPageAtIndex:index inRect:self.headerRect];
}
[self drawContentForPageAtIndex:index inRect:self.contentRect];
NSArray *elements = [self pageElementsForPageAtIndex:index];
for (MVReportPageElement *element in elements)
{
[self drawPageElement:element forPageAtIndex:index];
}
if (self.footerHeight > 0)
{
[self drawFooterForPageAtIndex:index inRect:self.footerRect];
}
}
- (void)drawHeaderForPageAtIndex:(NSInteger)index inRect:(CGRect)headerRect
{
}
- (void)drawContentForPageAtIndex:(NSInteger)index inRect:(CGRect)contentRect
{
}
- (void)drawPageElement:(MVReportPageElement *)element forPageAtIndex:(NSInteger)index
{
CGRect rect = [element rectForPageAtIndex:index];
[element drawInRect:rect forPageAtIndex:index];
}
- (void)drawFooterForPageAtIndex:(NSInteger)index inRect:(CGRect)footerRect
{
}
@end

View File

@ -0,0 +1,30 @@
//
// MVReportSection+Private.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportSection.h"
@interface MVReportSection (Private)
- (void)removeSectionElement:(MVReportSectionElement *)element;
@end

139
Classes/MVReportSection.h Normal file
View File

@ -0,0 +1,139 @@
//
// MVReportSection.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportPageElement.h"
@class MVReportSectionElement;
/**
A MVReportSection object draws pages of content in the report, with or without the assistance of section elements. Report section is convinient way to add table-like contnet into the report, where each section can have its own header, footer, and arbitrary number of section elements inbetween.
A report section is an instance of a custom subclass of MVReportSection, and can be added to report as any other MVReportPageElement instance.
The subclass typically overrides one or more of the five `-draw`... methods:
- The `-drawInRect:forPageAtIndex:` by default calls each of the other draw methods, in the order listed below. Your application can override it if you want to have complete control over what is drawn in the section.
- Override `-drawSectionHeaderForPageAtIndex:inRect:` to draw content in the section header.
- Override `-drawSectionContentForPageAtIndex:inRect:` to draw the main content of the section in the area between the section header and the section footer.
- Override `-drawSectionElement:forPageAtIndex:` to intermix custom drawing with the drawing performed by an associated section element. This method is called for each section element associated with a given page.
- Override `-drawSectionFooterForPageAtIndex:inRect:` to draw content in the section footer.
*/
@interface MVReportSection : MVReportPageElement
/**
@name Specifying Header and Footer Heights
*/
/**
The height of the section header.
The header is measured in points from the top of content rect and is above the content area. The default header height is 0.0.
*/
@property(nonatomic) CGFloat headerHeight;
/**
The height of the section footer.
The footer is measured in points from the bottom of content rect and is below the content area. The default footer height is 0.0.
*/
@property(nonatomic) CGFloat footerHeight;
/**
@name Managing Section Elements
*/
/**
The page elements associated with the report section.
*/
@property(nonatomic, copy) NSArray *sectionElements;
/**
Adds a section element to the report section.
Section elements are drawn one after the other in order they are added to the section, so there is no need to specify page or position of the element.
@param element instance of the custom subclass of the MVReportSectionElement.
*/
- (void)addsectionElement:(MVReportSectionElement *)element;
/**
Returns the section elements associated with a specified page.
@param pageIndex The index of a page of the report.
@return An array of MVReportSectionElement objects. A section element is a instance of the custom subclass of the MVReportSectionElement.
*/
- (NSArray *)sectionElementsForPageAtIndex:(NSInteger)pageIndex;
/**
@name Drawing a Section
*/
/**
Overridden to draw the section header of the given page.
@param index The index of the page in which to draw the section header.
@param headerRect The rectangle in which the section header content should be drawn. It is specified in the coordinate system of the page rectangle (pageRect); that is, the origin of coordinates is at the top-left corner of the sheet.
The default implementation of this method does nothing. It is not called if headerHeight is not a positive value, and it is called only for first page if section spans across multiple pages. The method is set up for drawing to the current graphics context (as returned by UIGraphicsGetCurrentContext).
*/
- (void)drawSectionHeaderForPageAtIndex:(NSInteger)index inRect:(CGRect)headerRect;
/**
Overridden to draw the section content of the given page.
@param index The index of the page in which to draw section content.
@param contentRect The area in which section content is to be drawn, specified in the coordinate system of the page rectangle (pageRect); that is, the origin of coordinates is at the top-left corner of the sheet.
The default implementation of this method does nothing. The method is set up for drawing to the current graphics context (as returned by UIGraphicsGetCurrentContext).
*/
- (void)drawSectionContentForPageAtIndex:(NSInteger)index inRect:(CGRect)contentRect;
/**
Overridden to add custom drawing to the drawing provided by a given section element for a page.
@param element A MVReportSectionElement object associated with page index.
@param index The index of the page in which section element is to draw.
This method is invoked for each section element assigned to the specified page. The default implementation invokes the `-drawInRect:forPageAtIndex:` method of the MVReportSectionElement object that is passed in. You can override this method to intermix custom drawing with the element drawingfor example, by adding an overlay or underlay graphic. Call `-drawInRect:forPageAtIndex:` to have the section element draw its portion of the page. The method is set up for drawing to the current graphics context (as returned by UIGraphicsGetCurrentContext).
*/
- (void)drawSectionElement:(MVReportSectionElement *)element forPageAtIndex:(NSInteger)index;
/**
Overridden to draw the footer of the given page.
@param index The index of the page in which to draw the section footer content.
@param footerRect The rectangle in which the section footer content should be drawn. It is specified in the coordinate system of the page rectangle (pageRect); that is, the origin of coordinates is at the top-left corner of the sheet.
The default implementation of this method does nothing. It is not called if footerHeight is not a positive value, and it is called only for last page if report section spans across multiple pages. The method is set up for drawing to the current graphics context (as returned by UIGraphicsGetCurrentContext).
*/
- (void)drawSectionFooterForPageAtIndex:(NSInteger)index inRect:(CGRect)footerRect;
@end

398
Classes/MVReportSection.m Normal file
View File

@ -0,0 +1,398 @@
//
// MVReportSection.m
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportSection+Private.h"
#import "MVReportPageElement+Private.h"
#import "MVReportSectionElement+Private.h"
#import "MVReportPageRenderer+Private.h"
@interface MVReportSection ()
{
CGFloat _pageCount;
BOOL needsToRecalculatePageCount;
}
@property (nonatomic)CGRect headerRect;
@property (nonatomic)NSMutableArray *sectionContentRects;
@property (nonatomic)CGRect footerRect;
@end
@implementation MVReportSection
- (instancetype)init
{
self = [super init];
if (self)
{
self.sectionContentRects = [NSMutableArray array];
}
return self;
}
- (void)setPriorPageElement:(MVReportPageElement *)priorPageElement
{
[super setPriorPageElement:priorPageElement];
needsToRecalculatePageCount = YES;
}
- (void)setSectionElements:(NSArray *)sectionElements
{
NSArray *oldElements = [_sectionElements copy];
for (MVReportSectionElement *element in oldElements)
{
[element removeFromReportSection];
}
_sectionElements = sectionElements;
for (MVReportSectionElement *element in _sectionElements)
{
element.reportSection = self;
}
}
- (void)addsectionElement:(MVReportSectionElement *)element
{
element.reportSection = self;
NSMutableArray *mutableElements = [self.sectionElements mutableCopy];
if (!mutableElements)
{
mutableElements = [NSMutableArray array];
}
[mutableElements addObject:element];
_sectionElements = [mutableElements copy];
needsToRecalculatePageCount = YES;
}
- (void)removeSectionElement:(MVReportSectionElement *)element
{
if ([self.sectionElements containsObject:element])
{
NSMutableArray *mutableElements = [self.sectionElements mutableCopy];
[mutableElements removeObject:element];
_sectionElements = [mutableElements copy];
needsToRecalculatePageCount = YES;
}
}
- (void)setContentRect:(CGRect)contentRect
{
[super setContentRect:contentRect];
needsToRecalculatePageCount = YES;
}
- (NSInteger)pageCount
{
if (needsToRecalculatePageCount == NO)
{
return _pageCount;
}
[self.sectionContentRects removeAllObjects];
if (self.priorPageElement)
{
self.startPage = self.priorPageElement.lastPage;
CGRect peRect = [self.priorPageElement rectForPageAtIndex:self.startPage];
self.contentInsets = UIEdgeInsetsMake(peRect.origin.y + peRect.size.height - self.reportPageRenderer.headerHeight - self.reportPageRenderer.pageInfo.printableRect.origin.y, self.contentInsets.left, self.contentInsets.bottom, self.contentInsets.right);
}
CGFloat verticalOffset = self.contentRect.origin.y + self.contentInsets.top;
CGFloat horizontalOffset = self.contentRect.origin.x + self.contentInsets.left;
CGFloat width = self.contentRect.size.width - self.contentInsets.left - self.contentInsets.right;
CGFloat height = 0;
CGFloat maxH = self.contentRect.origin.y + self.contentRect.size.height;
CGRect pageContent = CGRectMake(horizontalOffset, verticalOffset, width, height);
if (self.headerHeight > 0)
{
height = height + self.headerHeight;
CGRect hRect = CGRectZero;
hRect.origin.x = horizontalOffset;
hRect.origin.y = verticalOffset;
hRect.size.width = width;
hRect.size.height = height;
self.headerRect = hRect;
verticalOffset = verticalOffset + height;
height = 0;
pageContent.origin.y = verticalOffset;
}
_pageCount = 1;
CGRect cRect = CGRectZero;
cRect.origin.x = horizontalOffset;
cRect.origin.y = verticalOffset;
cRect.size.width = width;
cRect.size.height = self.contentRect.size.height - self.headerHeight; // maximum per element
BOOL pb = NO;
for (MVReportSectionElement *element in self.sectionElements)
{
pb = NO;
CGRect er = CGRectMake(cRect.origin.x, cRect.origin.y, cRect.size.width, cRect.size.height);
if ([element isBreakable])
{
er.size.height = MAXFLOAT;
}
[element setContentRect:er];
CGRect aRect = element.contentRect;
if (![element isBreakable])
{
// constrain W & H
aRect.size.height = MIN(aRect.size.height, cRect.size.height);
aRect.size.width = MIN(aRect.size.width, width);
CGFloat bh = aRect.origin.y + aRect.size.height;
if (bh > maxH)
{
pageContent.size.height = height;
[self.sectionContentRects addObject:[NSValue valueWithCGRect:pageContent]];
pb = YES;
//page break
verticalOffset = self.contentRect.origin.y;
aRect.origin.y = verticalOffset;
cRect.origin.y = verticalOffset;
height = 0;
pageContent = CGRectMake(horizontalOffset, verticalOffset, width, height);
element.contentRect = aRect;
_pageCount ++;
}
cRect.origin.y = cRect.origin.y + aRect.size.height;
height = height + aRect.size.height;
cRect.size.height = maxH - height;
element.startPage = self.startPage + _pageCount - 1;
element.pageCount = 1;
}
else
{
element.startPage = self.startPage + _pageCount - 1;
aRect.size.width = MIN(aRect.size.width, width);
CGFloat bh = aRect.origin.y + aRect.size.height;
if (bh > maxH)
{
NSInteger pc = ceil(bh / self.contentRect.size.height)-1;
_pageCount = _pageCount + pc;
element.pageCount = pc+1;
pb = NO;
CGFloat fph = maxH - aRect.origin.y;
CGFloat lph = aRect.size.height - fph - ((pc-1)*self.contentRect.size.height);
for (int i=0; i<pc+1; i++)
{
CGFloat h = self.contentRect.size.height;
CGFloat y = self.contentRect.origin.y;
if (i==0)
{
h = fph;
y = aRect.origin.y;
}
else if (i == pc)
{
h = lph;
}
height = height + h;
if (i<pc)
{
pageContent.size.height = height;
[self.sectionContentRects addObject:[NSValue valueWithCGRect:pageContent]];
verticalOffset = self.contentRect.origin.y;
aRect.origin.y = verticalOffset;
cRect.origin.y = verticalOffset;
height = 0;
pageContent = CGRectMake(horizontalOffset, verticalOffset, width, height);
}
cRect.origin.y = cRect.origin.y + height;
cRect.size.height = maxH - height;
}
}
else
{
element.pageCount = 1;
cRect.origin.y = cRect.origin.y + aRect.size.height;
height = height + aRect.size.height;
cRect.size.height = maxH - height;
}
}
}
if (!pb)
{
pageContent.size.height = height;
[self.sectionContentRects addObject:[NSValue valueWithCGRect:pageContent]];
}
if (self.footerHeight > 0)
{
CGFloat fheight = height + self.footerHeight;
if (fheight > maxH)
{
//page break
_pageCount++;
cRect.origin.y = self.contentRect.origin.y;
}
cRect.size.height = self.footerHeight;
self.footerRect = cRect;
}
needsToRecalculatePageCount = NO;
return _pageCount;
}
- (NSArray *)sectionElementsForPageAtIndex:(NSInteger)pageIndex
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(startPage <= %d) AND (lastPage >= %d)",pageIndex, pageIndex];
return [self.sectionElements filteredArrayUsingPredicate:predicate];
}
- (void)drawInRect:(CGRect)rect forPageAtIndex:(NSInteger)pageIndex
{
if (pageIndex == self.startPage)
{
if (self.headerHeight > 0)
{
[self drawSectionHeaderForPageAtIndex:pageIndex inRect:self.headerRect];
}
}
NSInteger i = pageIndex - self.startPage;
if (i < self.sectionContentRects.count)
{
NSValue *v = self.sectionContentRects[i];
[self drawSectionContentForPageAtIndex:pageIndex inRect:[v CGRectValue]];
}
NSArray *elements = [self sectionElementsForPageAtIndex:pageIndex];
for (MVReportSectionElement *element in elements)
{
[self drawSectionElement:element forPageAtIndex:pageIndex];
}
if (pageIndex == self.lastPage)
{
if (self.footerHeight > 0)
{
[self drawSectionFooterForPageAtIndex:pageIndex inRect:self.footerRect];
}
}
}
- (CGRect)rectForPageAtIndex:(NSInteger)pageIndex
{
CGRect result = CGRectZero;
CGRect r = CGRectZero;
NSInteger i = pageIndex - self.startPage;
if (i < self.sectionContentRects.count)
{
NSValue *v = self.sectionContentRects[i];
r = [v CGRectValue];
}
if (pageIndex == self.startPage)
{
if (self.headerHeight > 0)
{
result = CGRectMake(self.headerRect.origin.x, self.headerRect.origin.y, self.headerRect.size.width, self.headerRect.size.height);
result.size.height = result.size.height + r.size.height;
}
}
if (pageIndex == self.startPage + self.pageCount - 1)
{
if (self.footerHeight > 0)
{
if (CGRectIsNull(result))
{
result = self.footerRect;
}
else
{
result = r;
result.size.height = result.size.height + self.footerHeight;
}
}
else
{
result = r;
}
}
else
{
result = r;
}
return result;
}
- (void)prepareForDrawing
{
for (MVReportSectionElement *element in self.sectionElements)
{
[element prepareForDrawing];
}
}
- (void)drawSectionHeaderForPageAtIndex:(NSInteger)index inRect:(CGRect)headerRect
{
}
- (void)drawSectionContentForPageAtIndex:(NSInteger)index inRect:(CGRect)contentRect
{
}
- (void)drawSectionFooterForPageAtIndex:(NSInteger)index inRect:(CGRect)footerRect
{
}
- (void)drawSectionElement:(MVReportSectionElement *)element forPageAtIndex:(NSInteger)index
{
CGRect rect = [element rectForPageAtIndex:index];
[element drawInRect:rect forPageAtIndex:index];
}
@end

View File

@ -0,0 +1,36 @@
//
// MVReportSectionElement+Private.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportSectionElement.h"
@interface MVReportSectionElement (Private)
@property(nonatomic,readwrite, assign) NSInteger startPage;
@property(nonatomic, readwrite, assign) NSInteger pageCount;
@property(nonatomic, readwrite, assign) MVReportSection *reportSection;
@property(nonatomic, readonly) NSInteger lastPage;
@property(nonatomic)CGRect contentRect;
- (void)prepareForDrawing;
@end

View File

@ -0,0 +1,121 @@
//
// MVReportSectionElement.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
@import CoreGraphics;
@class MVReportSection;
/**
MVReportSectionElement is an abstract base class for section elements: objects that lay out custom printable content inside report section. You create your own subclass of MVReportSectionElement in application.
## Methods to Override
Override `-rectForContentRect:` to return desired rect for drawing, and `-drawInRect:forPageAtIndex:` to actually perform drawing in given rect.
*/
@interface MVReportSectionElement : NSObject
/**
@name Accessing Information About the Report
*/
/**
The index of the first page that the section element lays out. (read-only)
MVReportSection calculates this value based on the layout metrics and content of other section elements.
*/
@property(nonatomic,readonly, assign) NSInteger startPage;
/**
The number of pages to be generated by section element. (read-only)
MVReportSection calculates this value based on the layout metrics and content.
*/
@property(nonatomic, readonly, assign) NSInteger pageCount;
/**
@name Element Behavior
*/
/**
Set to define can this element span across multiple pages of report or not.
Default value of this property is NO. In your subclass you should take into account value of this property when returning rect from `-rectForContentRect:`. If value of this property is NO, height of bounding rect will be constrained to size of one page.
*/
@property(nonatomic, assign,getter=isBreakable)BOOL breakable;
/**
@name Communicating with the Report Section
*/
/**
Returns the report section with which the receiver is associated.
*/
@property(nonatomic, readonly, assign) MVReportSection *reportSection;
/**
Removes the section element from the report section.
*/
- (void)removeFromReportSection;
/**
@name Drawing the Content
*/
/**
Override to return desired rect in which your content can fit.
@param contentRect Proposed content rect in which content of the element should fit. If section element is breakable, height of the bounding rect is usauly max float.
@return Rect in which element can draw its content.
*/
- (CGRect)rectForContentRect:(CGRect)contentRect;
/**
Returns the area enclosing a specified page of section content.
@param pageIndex The index number of a page.
@return A rectangle enclosing the content area in section for page pageIndex.
*/
- (CGRect)rectForPageAtIndex:(NSInteger)pageIndex;
/**
Draws the portion of a section element's content that goes in the given area for the specified page
@param rect The area in which to draw the content.
@param pageIndex The number of the page of content to draw.
This method is called by the default implementation of `-drawSectionElement:forPageAtIndex:` of the MVReportSection class for each section element associated with a page.
*/
- (void)drawInRect:(CGRect)rect forPageAtIndex:(NSInteger)pageIndex;
/**
Returns actual content rect of the section element in coordinate space of page index
@param pageIndex The index number of a page.
@return A content rectangle as seen from the page requested
*/
- (CGRect)contentRectRelativeToPageAtIndex:(NSInteger)pageIndex;
@end

View File

@ -0,0 +1,192 @@
//
// MVReportSectionElement.m
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportSectionElement+Private.h"
#import "MVReportSection+Private.h"
#import "MVReportPageElement+Private.h"
@interface MVReportSectionElement ()
{
CGRect _contentRect;
NSInteger _pageCount;
NSInteger _startPage;
}
@property (nonatomic)NSMutableArray *elementContentRects;
@end
@implementation MVReportSectionElement
- (void)initInstance
{
self.startPage = 0;
self.elementContentRects = [NSMutableArray array];
}
- (instancetype)init
{
self = [super init];
if (self)
{
[self initInstance];
}
return self;
}
- (NSInteger)startPage
{
return _startPage;
}
- (void)setStartPage:(NSInteger)startPage
{
_startPage = startPage;
}
- (NSInteger)lastPage
{
return self.startPage + ([self pageCount]-1);
}
- (void)setContentRect:(CGRect)contentRect
{
_contentRect = [self rectForContentRect:contentRect];
if ([self isBreakable])
{
if ((_contentRect.origin.y + _contentRect.size.height) > contentRect.origin.y + contentRect.size.height)
{
_contentRect.size.height = (contentRect.origin.y + contentRect.size.height) - _contentRect.origin.y;
}
}
}
- (CGRect)contentRect
{
return _contentRect;
}
- (NSInteger)pageCount
{
return _pageCount;
}
- (void)setPageCount:(NSInteger)pageCount
{
_pageCount = pageCount;
}
- (CGRect)rectForPageAtIndex:(NSInteger)pageIndex
{
CGRect pageRect = self.reportSection.contentRect;
CGFloat maxHeight = self.contentRect.size.height;
CGFloat pY = pageRect.origin.y + pageRect.size.height;
if (pageIndex == self.startPage)
{
if (self.contentRect.origin.y + maxHeight < pY)
{
return self.contentRect;
}
else
{
CGRect r = CGRectMake(self.contentRect.origin.x, self.contentRect.origin.y, self.contentRect.size.width, self.contentRect.size.height);
r.size.height = pY - self.contentRect.origin.y;
return r;
}
}
else
{
NSInteger pc = pageIndex - self.startPage;
CGFloat priorHeight = pc * pageRect.size.height;
priorHeight = (priorHeight + pageRect.origin.y) - self.contentRect.origin.y;
CGFloat h = priorHeight + pageRect.size.height;
CGRect result = CGRectMake(self.contentRect.origin.x, self.contentRect.origin.y, self.contentRect.size.width, self.contentRect.size.height);
result.origin.y = pageRect.origin.y;
result.size.height = pageRect.size.height;
if (h > maxHeight)
{
result.size.height = maxHeight - priorHeight;
}
return result;
}
}
- (CGRect)contentRectRelativeToPageAtIndex:(NSInteger)pageIndex
{
CGRect pageRect = self.reportSection.contentRect;
if (pageIndex == self.startPage)
{
return self.contentRect;
}
else
{
NSInteger pc = pageIndex - self.startPage;
CGFloat priorHeight = pc * pageRect.size.height;
priorHeight = (priorHeight + pageRect.origin.y) - self.contentRect.origin.y;
CGRect result = CGRectMake(self.contentRect.origin.x, self.contentRect.origin.y, self.contentRect.size.width, self.contentRect.size.height);
result.origin.y = pageRect.origin.y-priorHeight;
return result;
}
}
- (void)setReportSection:(MVReportSection *)reportSection
{
if (self.reportSection)
{
[self.reportSection removeSectionElement:self];
}
_reportSection = reportSection;
}
- (void)removeFromReportSection
{
self.reportSection = nil;
}
- (void)drawInRect:(CGRect)rect forPageAtIndex:(NSInteger)pageIndex
{
//draw nothing
}
- (CGRect)rectForContentRect:(CGRect)contentRect
{
NSAssert(NO, @"should be implemented by subclass");
return CGRectZero;
}
- (void)prepareForDrawing
{
}
@end

View File

@ -0,0 +1,85 @@
//
// MVReportSimpleTextFormatter.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportTextFormatter.h"
/**
Instances of the MVReportSimpleTextFormatter class lay out plain text, possibly over multiple pages. The class allows you to specify global font, color, and text alignment properties for the text in report.
To use this report formatter for a report, create an instance of MVReportSimpleTextFormatter initialized with the text, set the text properties and the inherited layout properties, and add the object to the report in one of two ways:
- If a single report formatter is being used for the report (with no additional drawing), assign it to the pageElement property of the MVReport instance. The inherited startPage property identifies the beginning page of content with which the formatter is associated.
- If you are using multiple elements along with a page renderer, associate each report formatter with a starting page of the printed content. You often take this approach when you want to add content such as headers and footers to what the formatters provide. You have two ways of associating a report formatter with a MVReportPageRenderer object:
- You can add report formatters to the pageElements property of the MVReportPageRenderer object; the startPage property of the report formatter specifies the starting page.
- You can add report formatters by calling `-addPageElement:startingAtPageAtIndex:` for each report formatter; the second parameter of this method specifies the starting page (and overrides any startPage value).
*/
@interface MVReportSimpleTextFormatter : MVReportTextFormatter
/**
@name Getting and Setting the Text
*/
/**
A string of plain text.
*/
@property(nonatomic, copy) NSString *text;
/**
@name Text Attributes for Content
*/
/**
The font of the text.
If the value of this property is nil (the default), MVReport uses the standard system font.
*/
@property(nonatomic, retain) UIFont *font;
/**
The color of the text.
If the value of this property is nil (the default), MVReport uses a black color when printing.
*/
@property(nonatomic, retain) UIColor *color;
/**
The alignment of the text.
The default text alignment is UITextAlignmentLeft.
*/
@property(nonatomic) NSTextAlignment textAlignment;
/**
@name Creating a Simple-Text Report Formatter
*/
/**
Returns a simple-text report formatter initialized with plain text.
@param text A string of plain text.
@return An initialized instance of MVReportSimpleTextFormatter or nil if the object could not be created.
*/
- (instancetype)initWithText:(NSString *)text;
@end

View File

@ -0,0 +1,98 @@
//
// MVReportSimpleTextFormatter.m
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportSimpleTextFormatter.h"
#import "MVReportTextFormatter+Private.h"
@implementation MVReportSimpleTextFormatter
- (instancetype)initWithText:(NSString *)text
{
self = [super init];
if (self)
{
self.font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
self.color = [UIColor blackColor];
self.textAlignment = NSTextAlignmentLeft;
self.text = text;
}
return self;
}
- (void)generateAttributedString
{
if ([self.text length] <= 0)
{
self.attributedString = nil;
return;
}
if (!self.font)
{
self.attributedString = nil;
return;
}
if (!self.color)
{
self.attributedString = nil;
return;
}
NSMutableAttributedString *mst = [[NSMutableAttributedString alloc] initWithString:self.text];
NSRange range = NSMakeRange(0, [self.text length]);
[mst addAttribute:NSFontAttributeName value:self.font range:range];
[mst addAttribute:NSForegroundColorAttributeName value:self.color range:range];
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
style.alignment = self.textAlignment;
[mst addAttribute:NSParagraphStyleAttributeName value:style range:range];
NSAttributedString *s = [mst copy];
self.attributedString = s;
}
- (void)setText:(NSString *)text
{
_text = [text copy];
[self generateAttributedString];
}
- (void)setFont:(UIFont *)font
{
_font = font;
[self generateAttributedString];
}
- (void)setColor:(UIColor *)color
{
_color = color;
[self generateAttributedString];
}
- (void)setTextAlignment:(NSTextAlignment)textAlignment
{
_textAlignment = textAlignment;
[self generateAttributedString];
}
@end

View File

@ -0,0 +1,31 @@
//
// MVReportTextFormatter+Private.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportTextFormatter.h"
#import "MVReportPageElement+Private.h"
@interface MVReportTextFormatter (Private)
@property(nonatomic, strong)NSAttributedString *attributedString;
@end

View File

@ -0,0 +1,33 @@
//
// MVReportTextFormatter.h
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#import "MVReportPageElement.h"
/**
This is abstract class for all text formatters. Use one of concrete classes: MVReportSimpleTextFormatter, or MVReportMarkupTextFormatter.
*/
@interface MVReportTextFormatter : MVReportPageElement
@end

View File

@ -0,0 +1,251 @@
//
// MVReportTextFormatter.m
//
// Copyright (c) 2014 Moroverse
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "MVReportTextFormatter+Private.h"
#import "MVReportPageRenderer+Private.h"
@import CoreText;
@interface MVReportTextFormatter ()
{
CTFramesetterRef framesetter;
NSAttributedString *_attributedString;
CFRange localRange;
CGFloat _maxHeight;
CGFloat _pageCount;
}
@end
@implementation MVReportTextFormatter
- (void)dealloc
{
if (framesetter)
{
CFRelease(framesetter);
framesetter = nil;
}
}
- (instancetype)init
{
self = [super init];
if (self)
{
localRange = CFRangeMake(0, 0);
}
return self;
}
- (void)prepareForDrawing
{
localRange = CFRangeMake(0, self.attributedString.length);
}
- (NSAttributedString *)attributedString
{
return _attributedString;
}
- (void)setAttributedString:(NSAttributedString *)attributedString
{
if (_attributedString)
{
if (framesetter)
{
CFRelease(framesetter);
}
}
_attributedString = attributedString;
if ([_attributedString length] > 0)
{
framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)_attributedString);
}
}
- (CGFloat)evaluateRectsForTextInRange:(CFRange)range usingRect:(CGRect)rect andPageCount:(NSInteger)pCount
{
CFRange myRange = CFRangeMake(range.location, range.length);
for (NSInteger i = self.startPage; i < (self.startPage + pCount); i++)
{
CGMutablePathRef path = CGPathCreateMutable();
CGRect rect = [self rectForPageAtIndex:i];
CGPathAddRect(path, NULL, rect);
CTFrameRef sFrame = CTFramesetterCreateFrame(framesetter, myRange, path, NULL);
CFRange visibleRange = CTFrameGetVisibleStringRange(sFrame);
myRange.location += visibleRange.length;
myRange.length -= visibleRange.length;
CFRelease(sFrame);
CFRelease(path);
}
if (myRange.length > 0)
{
CGSize evalSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter,myRange,NULL,rect.size,NULL);
return evalSize.height;
}
else
{
return 0;
}
}
- (NSInteger)pageCountForMaxHeight:(CGFloat)mHeight
{
// ignoring per page insets for now
mHeight = mHeight + self.contentInsets.top;
CGFloat numP = mHeight / self.contentRect.size.height;
numP = ceilf(numP);
NSInteger pages = numP;
return pages;
}
- (NSInteger)pageCount
{
if (_pageCount)
{
return _pageCount;
}
if ([self.attributedString length] <= 0)
{
return 0;
}
if (self.priorPageElement)
{
self.startPage = self.priorPageElement.lastPage;
CGRect peRect = [self.priorPageElement rectForPageAtIndex:self.startPage];
self.contentInsets = UIEdgeInsetsMake(peRect.origin.y + peRect.size.height - self.reportPageRenderer.headerHeight - self.reportPageRenderer.pageInfo.printableRect.origin.y, self.contentInsets.left, self.contentInsets.bottom, self.contentInsets.right);
}
CGRect effectiveRect = self.contentRect;
if (CGRectIsNull(effectiveRect))
{
effectiveRect = CGRectMake(0, 0, 612, 792);
}
effectiveRect.size.width = effectiveRect.size.width - self.contentInsets.left - self.contentInsets.right;
effectiveRect.size.height = self.maximumContentHeight;
effectiveRect.size.width = MIN(effectiveRect.size.width, self.maximumContentWidth);
CFRange effectiveRange;
CGSize textSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter,CFRangeMake(0, 0),NULL,effectiveRect.size,&effectiveRange);
_maxHeight = textSize.height;
_pageCount = [self pageCountForMaxHeight:_maxHeight];
//recalculate max height
CGFloat evalSize = 0;
do
{
evalSize = [self evaluateRectsForTextInRange:effectiveRange usingRect:effectiveRect andPageCount:_pageCount];
if (evalSize > 0)
{
_maxHeight = _maxHeight + evalSize;
_pageCount = [self pageCountForMaxHeight:_maxHeight];
}
}
while (evalSize != 0);
return _pageCount;
}
- (void)drawInRect:(CGRect)rect forPageAtIndex:(NSInteger)pageIndex
{
if (localRange.location < self.attributedString.length)
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(currentContext);
CGContextTranslateCTM(currentContext, 0.0, rect.size.height+2*rect.origin.y);
CGContextScaleCTM(currentContext, 1.0, -1.0);
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, rect);
CTFrameRef sFrame = CTFramesetterCreateFrame(framesetter, localRange, path, NULL);
CTFrameDraw(sFrame, currentContext);
CFRange visibleRange = CTFrameGetVisibleStringRange(sFrame);
CGContextRestoreGState(currentContext);
localRange.location += visibleRange.length;
localRange.length -= visibleRange.length;
CFRelease(sFrame);
CFRelease(path);
}
}
- (CGRect)rectForPageAtIndex:(NSInteger)pageIndex
{
CGRect effectiveRect = self.contentRect;
if (CGRectIsNull(effectiveRect))
{
effectiveRect = CGRectMake(0, 0, 612, 792);
}
effectiveRect.size.width = effectiveRect.size.width - self.contentInsets.left - self.contentInsets.right;
effectiveRect.size.width = MIN(effectiveRect.size.width, self.maximumContentWidth);
effectiveRect.origin.x = effectiveRect.origin.x + self.contentInsets.left;
if (pageIndex == self.startPage)
{
effectiveRect.size.height = effectiveRect.size.height - self.contentInsets.top;
effectiveRect.origin.y = effectiveRect.origin.y + self.contentInsets.top;
if (_maxHeight < effectiveRect.size.height)
{
effectiveRect.size.height = _maxHeight;
}
}
else
{
NSInteger pc = pageIndex - self.startPage;
CGFloat priorHeight = pc * self.contentRect.size.height;
priorHeight = priorHeight - self.contentInsets.top;
CGFloat newHeight = priorHeight + effectiveRect.size.height;
if (newHeight > _maxHeight)
{
effectiveRect.size.height = _maxHeight - priorHeight;
}
}
return effectiveRect;
}
@end

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2014 Daniel Moro <daniel.moro@me.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

111
README.md Normal file
View File

@ -0,0 +1,111 @@
# MVReport
[![CI Status](http://img.shields.io/travis/Daniel Moro/MVReport.svg?style=flat)](https://travis-ci.org/Daniel Moro/MVReport)
[![Version](https://img.shields.io/cocoapods/v/MVReport.svg?style=flat)](http://cocoadocs.org/docsets/MVReport)
[![License](https://img.shields.io/cocoapods/l/MVReport.svg?style=flat)](http://cocoadocs.org/docsets/MVReport)
[![Platform](https://img.shields.io/cocoapods/p/MVReport.svg?style=flat)](http://cocoadocs.org/docsets/MVReport)
## Introduction
In 2011 Apple introduced iOS Printing API, a set of classes intended to simplify printing from iOS devices. Those classes will allow user to compose document for printing and send it to a printer.
However, that didn't resolve a reporting problem completely. If user wants to print a document he can use those new classes, but if one wants to generate document and send it via mail, or share it on some other way
he will need to abandon this approach and use c frameworks to generate PDF report. MVReport aims to solve this problem by introducing set of classes similar to Apple's printing classes but not only for printing.
It uses the same paradigm, formatter and page renderer objects, and same methods where it make sense. But, It also extends functionality by adding some new objects that allow generation of repeatable content, and positioning of text sections relative to other sections.
I marked this release as 0.1 because it requires more testing for some edge cases, and there are some parts of code I'm not satisfied how it looks now. I can imagine fairly complex cases resolved with existing classes and methods, but I didn't tried enough of them to call release 1.0.
## How To Get Started
- [Download MVReport](https://github.com/Moroverse/MVReport/archive/master.zip) and try out the included iPhone & iPad example app
- Check out the [documentation](http://cocoadocs.org/docsets/MVReport/0.1.3/) for a comprehensive look at all of the APIs available in MVReport
## Installation
MVReport is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile:
pod "MVReport"
## Usage
To run the example project, clone the repo, and run `pod install` from the Example directory first.
### Simple Page Elements
If you wish only to generate document with portion of text, or simple repeatable content you can use this approach.
Create concrete instance of `MVReport` depending on report type you wish to generate (currently there is only `MVPDFReport` available), and initialize it with your `MVReportPageInfo` object. Create concrete instance of `MVReportPageElement` and initialize it with your plain text or HTML text. Attach `MVReportPageElement` instance to pageElement property of `MVReport` instance and generate report.
```objective-c
MVReport *report = [[MVPDFReport alloc] initWithPageInfo:myPageInfo];
MVReportPageElement *pageElement = [[MVReportSimpleTextFormatter alloc] initWithText:mySimpleText];
report.pageElement = pageElement;
NSData *data = [report generateReport];
```
Result is a PDF document that can be written to file, send via email, or send to printer...
#### Report Section
If you need to put repeatable content in report you may use `MVReportSection` class. You don't have to subclass `MVReportSection` if there is no need for section heder, footer or some custom drawing not related to repeatable content.
You will need, however to create custom subclass of `MVReportSectionElement`, object that will draw one row in a section. You can think of it as a table row cell. In your subclass you will override method that returns content rect (height of the row in other words), and method that actually draws something:
```objective-c
@interface MyAcmeElement : MVReportSectionElement
@property (nonatomic, copy)NSString *text;
@end
@implementation MyAcmeElement
- (CGRect)rectForContentRect:(CGRect)contentRect
{
if (contentRect.size.height > 44)
{
contentRect.size.height = 44;
}
return contentRect;
}
- (void)drawInRect:(CGRect)rect forPageAtIndex:(NSInteger)pageIndex
{
CGRect myRect = CGRectInset(rect, 3, 3);
[self.text drawInRect:myRect withAttributes:textAttributes];
}
@end
```
Having `MyAcmeElement` class, its easy to compose report:
```objective-c
NSMutableArray *textElements = [NSMutableArray array];
for (NSString *text in myTextArray)
{
MyAcmeElement *element = [[MyAcmeElement alloc] init];
element.text = text;
[textElements addObject:element];
}
MVReportSection *section = [[MVReportSection alloc] init];
section.sectionElements = textElements;
MVReport *report = [[MVPDFReport alloc] initWithPageInfo:myPageInfo];
report.pageElement = section;
NSData *data = [report generateReport];
```
### Page Renderer
TBD
#### Combining Page Elements in Page Renderer
TBD
## Requirements
MVReport 0.1 and higher requires Xcode 5, targeting either iOS 7.0 and above. MVReport uses ARC.
## Author
Daniel Moro, Moroverse - moroverse@gmail.com
## License
MVReport is available under the MIT license. See the LICENSE file for more info.