// // PDFOutlineViewController.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 "PDFOutlineViewController.h" #define kPDFOutlineItemMaxDeep 10 @interface PDFOutlineModel : NSObject @property (nonatomic,assign) NSInteger level; @property (nonatomic,assign) NSInteger hide; @property (nonatomic,assign) NSInteger count; @property (nonatomic,assign) NSInteger number; @property (nonatomic,retain) NSString *title; @property (nonatomic,assign) BOOL isShow; @end @implementation PDFOutlineModel - (void)dealloc { [_title release]; [super dealloc]; } @end @interface PDFOutlineViewCell : UITableViewCell @property (nonatomic,assign) IBOutlet UILabel *nameLabel; @property (nonatomic,assign) IBOutlet UILabel *countLabel; @property (nonatomic,assign) IBOutlet UIButton *arrowButton; @property (nonatomic,assign) IBOutlet NSLayoutConstraint *offsetX; @property (nonatomic,retain) PDFOutlineModel *outline; @property (nonatomic,assign) BOOL isShow; @property (nonatomic,assign) id delegate; @end @implementation PDFOutlineViewCell - (void)dealloc { [_outline release]; [super dealloc]; } - (void)setOutline:(PDFOutlineModel *)outline { if (_outline != outline) { [_outline release]; _outline = [outline retain]; } self.nameLabel.text = outline.title; self.countLabel.text = [NSString stringWithFormat:@"%ld",outline.number+1]; self.offsetX.constant = 10*outline.level; if (outline.count>0) { [self.arrowButton setHidden:NO]; if (outline.isShow) { self.arrowButton.selected = YES; } else { self.arrowButton.selected = NO; } } else{ [self.arrowButton setHidden:YES]; } } - (void)setIsShow:(BOOL)isShow { _isShow = isShow; self.outline.isShow = self.isShow; if (self.outline.count>0) { if (self.outline.isShow) { self.arrowButton.selected = YES; } else { self.arrowButton.selected = NO; } } } - (IBAction)buttonItemClicked_Arrow:(id)sender { if ([self.delegate respondsToSelector:@selector(buttonItemClicked_Arrow:)]) { [self.delegate performSelector:@selector(buttonItemClicked_Arrow:) withObject:self]; } } @end @interface PDFOutlineViewController () @property (nonatomic,retain) UITableView *tableView; @property (nonatomic,retain) NSArray *outlines; @property (nonatomic,retain) UILabel *noDataLabel; @end @implementation PDFOutlineViewController #pragma mark - Init Methods - (void)dealloc { [_noDataLabel release]; [_outlines release]; _tableView.delegate = nil; _tableView.dataSource = nil; [_tableView release]; [super dealloc]; } #pragma mark - UIViewController Methods - (void)loadOutline:(CPDFOutline *)outline level:(NSInteger)level forOutlines:(NSMutableArray *)outlines { for (int i=0; i<[outline numberOfChildren]; i++) { CPDFOutline *data = [outline childAtIndex:i]; CPDFDestination *destination = [data destination]; if (!destination) { CPDFAction *action = [data action]; if (action && [action isKindOfClass:[CPDFGoToAction class]]) { destination = [(CPDFGoToAction *)action destination]; } } PDFOutlineModel *model = [[PDFOutlineModel alloc] init]; model.level = level; model.hide = (1 << (kPDFOutlineItemMaxDeep - level)) - 1; model.title = data.label; model.count = data.numberOfChildren; model.number = destination.pageIndex; model.isShow = NO; [outlines addObject:model]; [self loadOutline:data level:level+1 forOutlines:outlines]; } } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. CPDFOutline *outlineRoot = [self.pdfViewController.pdfView.document outlineRoot]; NSMutableArray *array = [NSMutableArray array]; [self loadOutline:outlineRoot level:0 forOutlines:array]; self.outlines = array; self.tableView = [[[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain] autorelease]; self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; self.tableView.dataSource = self; self.tableView.delegate = self; self.tableView.rowHeight = UITableViewAutomaticDimension; self.tableView.estimatedRowHeight = 60; self.tableView.tableFooterView = [[[UIView alloc] init] autorelease]; [self.tableView registerNib:[UINib nibWithNibName:@"PDFOutlineViewCell" bundle:nil] forCellReuseIdentifier:@"cell"]; [self.view addSubview:self.tableView]; self.noDataLabel = [[[UILabel alloc] init] autorelease]; self.noDataLabel.textColor = [UIColor grayColor]; self.noDataLabel.text = NSLocalizedString(@"No outlines", nil); [self.noDataLabel sizeToFit]; self.noDataLabel.center = CGPointMake(self.view.bounds.size.width/2.0, self.view.bounds.size.height/2.0); self.noDataLabel.autoresizingMask = UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin; [self.view addSubview:self.noDataLabel]; } #pragma mark - UITableViewDataSource const static int kShowFlag = (1 << kPDFOutlineItemMaxDeep) -1; - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { int n = 0; for (PDFOutlineModel *outline in self.outlines) { if (outline.hide == kShowFlag) n ++ ; } if (n > 0) { self.noDataLabel.hidden = YES; } else { self.noDataLabel.hidden = NO; } return n; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { int t = -1; PDFOutlineModel *outline = nil; for (PDFOutlineModel *model in self.outlines) { if (model.hide == kShowFlag) t++; if (t == indexPath.row) { outline = model; break; } } PDFOutlineViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; cell.outline = outline; cell.delegate = self; return cell; } #pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:NO]; [self dismissViewControllerAnimated:YES completion:^{ PDFOutlineViewCell *cell = (PDFOutlineViewCell *)[tableView cellForRowAtIndexPath:indexPath]; PDFOutlineModel *outline = cell.outline; [self.pdfViewController.pdfView goToPageIndex:outline.number animated:NO]; }]; } #pragma mark - Button Event Action - (void)buttonItemClicked_Arrow:(PDFOutlineViewCell *)cell { NSIndexPath *indexPath = [self.tableView indexPathForCell:cell]; int t = -1, p = 0; PDFOutlineModel *outline = nil; for (PDFOutlineModel *model in self.outlines) { if (model.hide == kShowFlag) t++; if (t == indexPath.row) { outline = model; break; } p++; } if (outline.level == kPDFOutlineItemMaxDeep-1) return; p++; if (p == self.outlines.count) return; PDFOutlineModel *nextOutline = self.outlines[p]; if (nextOutline.level > outline.level) { if (nextOutline.hide == kShowFlag) { [(PDFOutlineViewCell *)[self.tableView cellForRowAtIndexPath:indexPath] setIsShow:NO]; NSMutableArray *array = [NSMutableArray array]; while (true) { if (nextOutline.hide == kShowFlag) { t ++; NSIndexPath* path = [NSIndexPath indexPathForRow:t inSection:0]; [array addObject:path]; } nextOutline.hide ^= 1 << (kPDFOutlineItemMaxDeep - outline.level - 1); p++; if (p == self.outlines.count) break; nextOutline = self.outlines[p]; if (nextOutline.level <= outline.level) break; } [self.tableView deleteRowsAtIndexPaths:array withRowAnimation:UITableViewRowAnimationFade]; } else { [(PDFOutlineViewCell *)[self.tableView cellForRowAtIndexPath:indexPath] setIsShow:YES]; NSMutableArray *array = [NSMutableArray array]; while (true) { nextOutline.hide ^= 1 << (kPDFOutlineItemMaxDeep - outline.level - 1); if (nextOutline.hide == kShowFlag) { t ++; NSIndexPath* path = [NSIndexPath indexPathForRow:t inSection:0]; [array addObject:path]; } p++; if (p == self.outlines.count) break; nextOutline = self.outlines[p]; if (nextOutline.level <= outline.level) break; } [self.tableView insertRowsAtIndexPaths:array withRowAnimation:UITableViewRowAnimationFade]; } } } @end