// // PDFPageEditViewController.m // PDFReader // // Copyright © 2014-2022 PDF Technologies, Inc. All Rights Reserved. // // The PDF Reader Sample applications are licensed with a modified BSD license. // Please see License for details. This notice may not be removed from this file. // #import "PDFPageEditViewController.h" #import "PDFPageEditCell.h" #import #import "PDFPageEditAddViewController.h" @interface PDFPageEditViewController () @property (nonatomic,assign) IBOutlet UICollectionView *collectionView; @property (nonatomic,assign) IBOutlet UIToolbar *toolbar; @property (nonatomic,retain) NSMutableArray *pages; @end @implementation PDFPageEditViewController #pragma mark - Init Methods - (instancetype)init { if (self = [super init]) { } return self; } - (void)dealloc { [_pages release]; [super dealloc]; } #pragma mark - UIViewController Methods - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self setEditing:NO animated:NO]; self.pages = [NSMutableArray array]; NSURL *documentURL = [self.pdfViewController.pdfView.document documentURL]; CGPDFDocumentRef documentRef = CGPDFDocumentCreateWithURL((CFURLRef)documentURL); if ([self.pdfViewController.pdfView.document password]) { CGPDFDocumentUnlockWithPassword(documentRef, [[self.pdfViewController.pdfView.document password] UTF8String]); } NSInteger pagesCount = CGPDFDocumentGetNumberOfPages(documentRef); for (int i = 0; i < pagesCount; i++) { CGPDFPageRef pageRef = CGPDFDocumentGetPage(documentRef, i+1); PDFEditPage *page = [[PDFEditPage alloc] initWithPageRef:pageRef]; [self.pages addObject:page]; [page release]; } CGPDFDocumentRelease(documentRef); [self.collectionView registerClass:[PDFPageEditCell class] forCellWithReuseIdentifier:@"PDFPageEditCell"]; self.collectionView.alwaysBounceVertical = YES; UILongPressGestureRecognizer *longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlelongGesture:)]; [self.collectionView addGestureRecognizer:longGesture]; [longGesture release]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSInteger pageIndex = [self.pdfViewController.pdfView currentPageIndex]; NSIndexPath *indexPath = [NSIndexPath indexPathForItem:pageIndex inSection:0]; [self.collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionCenteredVertically]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSInteger pageIndex = [self.pdfViewController.pdfView currentPageIndex]; NSIndexPath *indexPath = [NSIndexPath indexPathForItem:pageIndex inSection:0]; [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES]; } - (void)updateTitle { if (self.isEditing) { NSInteger count = [self.collectionView indexPathsForSelectedItems].count; self.title = [NSString stringWithFormat:@"%@ %ld",NSLocalizedString(@"Selected:", nil), (long)count]; } else { self.title = nil; } } - (void)reloadDataVisibleCells { for (PDFPageEditCell *cell in [self.collectionView visibleCells]) { NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell]; cell.textLabel.text = [NSString stringWithFormat:@"%@",@(indexPath.item+1)]; } } #pragma mark - Button Actions - (void)setEditing:(BOOL)editing animated:(BOOL)animated { [super setEditing:editing animated:animated]; if (editing) { self.collectionView.allowsMultipleSelection = YES; UIBarButtonItem *selectAllItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"selectall.png"] style:UIBarButtonItemStylePlain target:self action:@selector(buttonItemClicked_SelectAll:)]; if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) { NSMutableArray *items = [NSMutableArray array]; [self.toolbar.items enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(UIBarButtonItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if (obj.target) { [items addObject:obj]; } }]; [items addObject:selectAllItem]; [self.navigationItem setRightBarButtonItems:items animated:animated]; } else { [UIView animateWithDuration:animated ? 0.3 : 0.0 animations:^{ self.toolbar.alpha = 1.0; }]; [self.navigationItem setLeftBarButtonItems:@[selectAllItem] animated:animated]; UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(buttonItemClicked_Done:)]; [self.navigationItem setRightBarButtonItems:@[doneItem] animated:animated]; [doneItem release]; } [selectAllItem release]; } else { self.collectionView.allowsMultipleSelection = NO; [UIView animateWithDuration:animated ? 0.3 : 0.0 animations:^{ self.toolbar.alpha = 0.0; }]; UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(buttonItemClicked_Done:)]; [self.navigationItem setLeftBarButtonItems:@[doneItem] animated:animated]; [doneItem release]; UIBarButtonItem *editItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(buttonItemClicked_Edit:)]; [self.navigationItem setRightBarButtonItems:@[editItem] animated:animated]; [editItem release]; } [self updateTitle]; } - (void)buttonItemClicked_Done:(id)sender { if (self.isEditing) { [self setEditing:NO animated:YES]; } else { [self dismissViewControllerAnimated:YES completion:^{ [self.pdfViewController.pdfView.document writeToURL:self.pdfViewController.pdfView.document.documentURL]; [self.pdfViewController loadDocumentWithFilePath:self.pdfViewController.filePath completion:nil]; }]; } } - (void)buttonItemClicked_Edit:(id)sender { [self setEditing:YES animated:YES]; } - (void)buttonItemClicked_SelectAll:(id)sender { BOOL isSelectAll = NO; if ([self.collectionView indexPathsForSelectedItems].count != [self.collectionView numberOfItemsInSection:0]) { isSelectAll = YES; } for (int i=0; i<[self.collectionView numberOfItemsInSection:0]; i++) { NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; if (isSelectAll) { [self.collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone]; } else { [self.collectionView deselectItemAtIndexPath:indexPath animated:YES]; } } [self updateTitle]; } - (IBAction)buttonItemClicked_Add:(id)sender { PDFPageEditAddViewController *vc = [[PDFPageEditAddViewController alloc] init]; vc.callback = ^(PDFEditPage *page) { NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.pdfViewController.pdfView.currentPageIndex+1 inSection:0]; [self.pages insertObject:page atIndex:indexPath.item]; [self.collectionView insertItemsAtIndexPaths:@[indexPath]]; if (page.imagePath) { [self.pdfViewController.pdfView.document insertPage:page.size withImage:page.imagePath atIndex:indexPath.item]; } else { [self.pdfViewController.pdfView.document insertPage:page.size atIndex:indexPath.item]; } [self reloadDataVisibleCells]; }; [vc showViewController:self inBarButtonItem:sender]; [vc release]; } - (IBAction)buttonItemClicked_Extract:(id)sender { NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; NSString *fileName = self.pdfViewController.pdfView.document.documentURL.lastPathComponent.stringByDeletingPathExtension; NSString *filePath = [NSString stringWithFormat:@"%@/%@_Pages.pdf",path,fileName]; NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet]; for (NSIndexPath *indexPath in [self.collectionView indexPathsForSelectedItems]) { [indexSet addIndex:indexPath.item]; } CPDFDocument *document = [[[CPDFDocument alloc] init] autorelease]; [document importPages:indexSet fromDocument:self.pdfViewController.pdfView.document atIndex:0]; [document writeToURL:[NSURL fileURLWithPath:filePath]]; NSString *message = [NSString stringWithFormat:NSLocalizedString(@"This file has been saved in:'Documents/'", nil)]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleCancel handler:nil]; UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Successfully!", nil) message:message preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:cancelAction]; [self presentViewController:alert animated:YES completion:nil]; } - (IBAction)buttonItemClicked_Rotate:(id)sender { NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet]; for (NSIndexPath *indexPath in [self.collectionView indexPathsForSelectedItems]) { PDFPageEditCell *cell = (PDFPageEditCell *)[self.collectionView cellForItemAtIndexPath:indexPath]; PDFEditPage *page = [self.pages objectAtIndex:indexPath.item]; page.rotation += 90; if (page.rotation == 360) { page.rotation = 0; } cell.page = page; [indexSet addIndex:indexPath.item]; CPDFPage *pPage = [self.pdfViewController.pdfView.document pageAtIndex:indexPath.item]; pPage.rotation += 90; } } - (IBAction)buttonItemClicked_Mail:(id)sender { NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; NSString *fileName = self.pdfViewController.pdfView.document.documentURL.lastPathComponent.stringByDeletingPathExtension; NSString *filePath = [NSString stringWithFormat:@"%@/%@_Pages.pdf",path,fileName]; NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet]; for (NSIndexPath *indexPath in [self.collectionView indexPathsForSelectedItems]) { [indexSet addIndex:indexPath.item]; } CPDFDocument *document = [[[CPDFDocument alloc] init] autorelease]; [document importPages:indexSet fromDocument:self.pdfViewController.pdfView.document atIndex:0]; [document writeToURL:[NSURL fileURLWithPath:filePath]]; MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init]; vc.mailComposeDelegate = (id)self; [vc addAttachmentData:[NSData dataWithContentsOfFile:filePath] mimeType:[NSString stringWithFormat:@"application/%@",[filePath pathExtension]] fileName:[filePath lastPathComponent]]; [self presentViewController:vc animated:YES completion:nil]; [vc release]; } - (IBAction)buttonItemClicked_Delete:(id)sender { NSInteger selectedCount = [self.collectionView indexPathsForSelectedItems].count; NSInteger totalCount = [self.collectionView numberOfItemsInSection:0]; if (selectedCount == totalCount) { UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleCancel handler:nil]; UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Warning", nil) message:NSLocalizedString(@"Can not delete all pages.", nil) preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:cancelAction]; [self presentViewController:alert animated:YES completion:nil]; return; } NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet]; for (NSIndexPath *indexPath in [self.collectionView indexPathsForSelectedItems]) { [indexSet addIndex:indexPath.item]; } [self.pages removeObjectsAtIndexes:indexSet]; [self.collectionView deleteItemsAtIndexPaths:[self.collectionView indexPathsForSelectedItems]]; [self.pdfViewController.pdfView.document removePageAtIndexSet:indexSet]; [self reloadDataVisibleCells]; } #pragma mark - UICollectionViewDelegateFlowLayout - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { NSInteger count = 4; UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)collectionViewLayout; CGFloat width = MIN(self.view.bounds.size.width, self.view.bounds.size.height); width -= (count-1)*flowLayout.minimumInteritemSpacing; width -= flowLayout.sectionInset.left; width -= flowLayout.sectionInset.right; width /= count; return CGSizeMake(width, width+18); } #pragma mark - UICollectionViewDataSource - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.pages.count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { PDFPageEditCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PDFPageEditCell" forIndexPath:indexPath]; cell.backgroundColor = [UIColor clearColor]; cell.page = self.pages[indexPath.item]; cell.textLabel.text = [NSString stringWithFormat:@"%@",@(indexPath.item+1)]; return cell; } #pragma mark - UICollectionViewDelegate - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { [self updateTitle]; if (!self.isEditing) { [self dismissViewControllerAnimated:YES completion:^{ [self.pdfViewController.pdfView.document writeToURL:self.pdfViewController.pdfView.document.documentURL]; [self.pdfViewController loadDocumentWithFilePath:self.pdfViewController.filePath completion:^(BOOL result) { if (result) { [self.pdfViewController.pdfView goToPageIndex:indexPath.item animated:NO]; } }]; }]; } } - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath { [self updateTitle]; } #pragma mark - UICollectionView Draggable - (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath { return YES; } - (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath { if (sourceIndexPath.item != destinationIndexPath.item) { CPDFPage *page = [[self.pages objectAtIndex:sourceIndexPath.item] retain]; [self.pages removeObject:page]; [self.pages insertObject:page atIndex:destinationIndexPath.item]; [page release]; [self.pdfViewController.pdfView.document movePageAtIndex:sourceIndexPath.item withPageAtIndex:destinationIndexPath.item]; [self reloadDataVisibleCells]; } } - (void)handlelongGesture:(UILongPressGestureRecognizer *)longGesture { switch (longGesture.state) { case UIGestureRecognizerStateBegan: { NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[longGesture locationInView:self.collectionView]]; if (indexPath == nil) { break; } [self.collectionView beginInteractiveMovementForItemAtIndexPath:indexPath]; [UIView animateWithDuration:0.2 animations:^{ [self.collectionView updateInteractiveMovementTargetPosition:[longGesture locationInView:self.collectionView]]; }]; } break; case UIGestureRecognizerStateChanged: { [self.collectionView updateInteractiveMovementTargetPosition:[longGesture locationInView:self.collectionView]]; } break; case UIGestureRecognizerStateEnded: { [self.collectionView endInteractiveMovement]; } break; default: { [self.collectionView cancelInteractiveMovement]; } break; } } #pragma mark - MFMailComposeViewControllerDelegate - (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(nullable NSError *)error { [controller dismissViewControllerAnimated:YES completion:nil]; } @end