cordova-plugin-printer/src/ios/APPPrinter.m
2019-02-06 12:02:41 +01:00

425 lines
12 KiB
Objective-C
Executable File

/*
Copyright 2013 appPlant GmbH
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#include "APPPrinter.h"
#include "APPPrinterItem.h"
#include "APPPrinterPaper.h"
#include "APPPrinterRenderer.h"
#include "UIPrintInteractionController+APPPrinter.h"
@interface APPPrinter ()
@property (nonatomic) UIPrinter *previousPrinter;
@end
@implementation APPPrinter
#pragma mark -
#pragma mark Interface
/*
* Checks if the printing service is available.
*/
- (void) check:(CDVInvokedUrlCommand *)command
{
[self.commandDelegate runInBackground:^{
BOOL res = [APPPrinterItem canPrintURL:command.arguments[0]];
[self sendResultWithMessageAsBool:res
callbackId:command.callbackId];
}];
}
/*
* List all printable document types (utis).
*/
- (void) types:(CDVInvokedUrlCommand *)command
{
[self.commandDelegate runInBackground:^{
NSSet *utis = UIPrintInteractionController.printableUTIs;
CDVPluginResult* result =
[CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:utis.allObjects];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
}
/**
* Displays system interface for selecting a printer.
*/
- (void) pick:(CDVInvokedUrlCommand *)command
{
[self.commandDelegate runInBackground:^{
NSMutableDictionary* settings = command.arguments[0];
settings[@"callbackId"] = command.callbackId;
[self presentPickerWithSettings:settings];
}];
}
/**
* Sends the printing content to the printer controller and opens them.
*/
- (void) print:(CDVInvokedUrlCommand *)command
{
[self.commandDelegate runInBackground:^{
NSString* content = command.arguments[0];
NSMutableDictionary* settings = command.arguments[1];
settings[@"callbackId"] = command.callbackId;
[self printContent:content withSettings:settings];
}];
}
#pragma mark -
#pragma mark UIPrintInteractionControllerDelegate
/**
* Asks the delegate for an object encapsulating the paper size and printing
* area to use for the print job. If Paper-Size is given it selects the best
* fitting papersize
*/
- (UIPrintPaper *) printInteractionController:(UIPrintInteractionController *)ctrl
choosePaper:(NSArray *)paperList
{
APPPrinterPaper* paperSpec = [[APPPrinterPaper alloc]
initWithDictionary:ctrl.settings[@"paper"]];
return [paperSpec bestPaperFromArray:paperList];
}
/**
* Asks the delegate for a length to use when cutting the page. If using roll
* printers like Label-Printer (brother QL-710W) you can cut paper after given
* length.
*/
- (CGFloat) printInteractionController:(UIPrintInteractionController *)ctrl
cutLengthForPaper:(UIPrintPaper *)paper
{
APPPrinterPaper* paperSpec = [[APPPrinterPaper alloc]
initWithDictionary:ctrl.settings[@"paper"]];
return paperSpec.length || paper.paperSize.height;
}
#pragma mark -
#pragma mark Core
/**
* Displays system interface for selecting a printer.
*
* @param settings Describes additional settings like from where to present the
* picker for iPad.
*
* @return [ Void ]
*/
- (void) presentPickerWithSettings:(NSDictionary *)settings
{
UIPrinterPickerController* controller =
[UIPrinterPickerController printerPickerControllerWithInitiallySelectedPrinter:nil];
UIPrinterPickerCompletionHandler handler =
^(UIPrinterPickerController *ctrl, BOOL selected, NSError *e) {
[self returnPickerResultForController:ctrl
callbackId:settings[@"callbackId"]];
};
dispatch_async(dispatch_get_main_queue(), ^{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
NSArray* bounds = settings[@"ui"][@"bounds"];
CGRect rect = [self convertIntoRect:bounds];
[controller presentFromRect:rect
inView:self.webView
animated:YES
completionHandler:handler];
} else {
[controller presentAnimated:YES
completionHandler:handler];
}
});
}
/**
* Loads the content into the print controller.
*
* @param content The HTML content or remote web page URI to print.
* @param settings The print job specs.
*
* @return [ Void ]
*/
- (void) printContent:(NSString *)content
withSettings:(NSDictionary *)settings
{
__block id item;
UIPrintInteractionController* ctrl =
[UIPrintInteractionController sharedPrintControllerWithSettings:settings];
ctrl.delegate = self;
if ([self strIsNullOrEmpty:content])
{
dispatch_sync(dispatch_get_main_queue(), ^{
item = self.webView.viewPrintFormatter;
});
}
else if ([content characterAtIndex:0] == '<')
{
dispatch_sync(dispatch_get_main_queue(), ^{
item = [[UIMarkupTextPrintFormatter alloc]
initWithMarkupText:content];
});
}
else if ([NSURL URLWithString:content])
{
item = [APPPrinterItem ItemFromURL:content];
}
else
{
dispatch_sync(dispatch_get_main_queue(), ^{
item = [[UISimpleTextPrintFormatter alloc]
initWithText:content];
});
}
[self useController:ctrl toPrintItem:item withSettings:settings];
}
/**
* Print the rendered content of the given view.
*
* @param ctrl The interactive printer controller.
* @param item Either the item to print or the formatted content.
* @param settings The print job specs.
*
* @return [ Void ]
*/
- (void) useController:(UIPrintInteractionController *)ctrl
toPrintItem:(id)item
withSettings:(NSDictionary *)settings
{
NSString* printer = settings[@"printer"];
if ([item isKindOfClass:UIPrintFormatter.class])
{
ctrl.printPageRenderer =
[[APPPrinterRenderer alloc] initWithDictionary:settings formatter:item];
}
else
{
ctrl.printingItem = item;
}
if ([self strIsNullOrEmpty:printer])
{
[self presentController:ctrl withSettings:settings];
}
else
{
[self printToPrinter:ctrl withSettings:settings];
}
}
/**
* Sends the content directly to the specified or previously selected printer.
*
* @param ctrl The interactive printer controller.
* @param printerURL The printer specified by its URL.
* @param settings The print job specs.
*
* @return [ Void ]
*/
- (void) printToPrinter:(UIPrintInteractionController *)ctrl
withSettings:(NSDictionary *)settings
{
NSString* callbackId = settings[@"callbackId"];
NSString* printerURL = settings[@"printer"];
UIPrinter* printer = [self printerWithURL:printerURL];
dispatch_async(dispatch_get_main_queue(), ^{
[ctrl printToPrinter:printer completionHandler:
^(UIPrintInteractionController *ctrl, BOOL ok, NSError *e) {
[self rememberPrinter:(ok ? printer : NULL)];
[self sendResultWithMessageAsBool:ok callbackId:callbackId];
}];
});
}
/**
* Opens the print controller so that the user can choose between
* available iPrinters.
*
* @param ctrl The interactive printer controller.
* @param settings The print job specs.
*
* @return [ Void ]
*/
- (void) presentController:(UIPrintInteractionController *)ctrl
withSettings:(NSDictionary *)settings
{
NSString* callbackId = settings[@"callbackId"];
NSArray* bounds = settings[@"ui"][@"bounds"];
CGRect rect = [self convertIntoRect:bounds];
UIPrintInteractionCompletionHandler handler =
^(UIPrintInteractionController *ctrl, BOOL ok, NSError *e) {
[self sendResultWithMessageAsBool:ok callbackId:callbackId];
};
dispatch_async(dispatch_get_main_queue(), ^{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
[ctrl presentFromRect:rect
inView:self.webView
animated:YES
completionHandler:handler];
}
else
{
[ctrl presentAnimated:YES
completionHandler:handler];
}
});
}
#pragma mark -
#pragma mark Helper
/**
* Tells the system to pre-select the given printer next time.
*
* @param printer The printer to remeber.
*
* @return [ Void ]
*/
- (void) rememberPrinter:(UIPrinter*)printer
{
[UIPrinterPickerController
printerPickerControllerWithInitiallySelectedPrinter:(_previousPrinter = printer)];
}
/**
* Returns an object that can be used to connect to the network printer.
*
* @param url The network URL as a string.
*
* @return A printer even if the URL is not a valid printer.
*/
- (UIPrinter *)printerWithURL:(NSString *)urlAsString
{
NSURL* url = [NSURL URLWithString:urlAsString];
UIPrinter* printer;
if (_previousPrinter && [_previousPrinter.URL.absoluteString isEqualToString:urlAsString])
{
printer = _previousPrinter;
}
else
{
printer = [UIPrinter printerWithURL:url];
}
return printer;
}
/**
* Convert Array into Rect object.
*
* @param bounds The bounds
*
* @return A converted Rect object
*/
- (CGRect) convertIntoRect:(NSArray*)bounds
{
if (!bounds) {
bounds = @[@40, @30, @0, @0];
}
return CGRectMake([bounds[0] floatValue],
[bounds[1] floatValue],
[bounds[2] floatValue],
[bounds[3] floatValue]);
}
/**
* Test if the given string is null or empty.
*
* @param string The string to test.
*
* @return true or false
*/
- (BOOL) strIsNullOrEmpty:(NSString *)string
{
return [string isEqual:[NSNull null]] || string.length == 0;
}
/**
* Calls the callback funtion with the result of the selected printer.
*
* @param ctrl The controller used to display the printer selector interface.
* @param callbackId The ID of the callback that shall receive the info.
*
* @return [ Void ]
*/
- (void) returnPickerResultForController:(UIPrinterPickerController *)ctrl
callbackId:(NSString *)callbackId
{
UIPrinter* printer = ctrl.selectedPrinter;
CDVPluginResult* result;
[self rememberPrinter:printer];
if (printer) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsString:printer.URL.absoluteString];
} else {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_NO_RESULT];
}
[self.commandDelegate sendPluginResult:result
callbackId:callbackId];
}
/**
* Sends the plugin result by invoking the callback function with a boolean arg.
*
* @param msg The boolean message value.
*
* @return [ Void ]
*/
- (void) sendResultWithMessageAsBool:(BOOL)msg
callbackId:(NSString *)callbackId
{
CDVPluginResult* result =
[CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsBool:msg];
[self.commandDelegate sendPluginResult:result
callbackId:callbackId];
}
@end