// // KMPDFEditAppendWindow.m // PDF Reader // // Created by 丁林圭 on 2017/5/11. // Copyright © 2017年 zhangjie. All rights reserved. // #import "KMPDFEditAppendWindow.h" #import #import #import #import "CTBrowserWindowController.h" @interface KMPDFEditAppendTabelViewCell() @property (assign) IBOutlet NSTextField *pageCountLabel; @property (assign) IBOutlet NSTextField *indexLabel; @property (assign) IBOutlet NSTextField *fileNameLabel; @property (assign) IBOutlet NSTextField *pageRangeLabel; @property (assign) IBOutlet NSTextField *sizeLabel; @property (assign) IBOutlet NSImageView *fileImage; @property (assign) IBOutlet NSComboBox *pageRangeBox; @property (nonatomic, copy) void(^removeCallBack)(void); @end @implementation KMPDFEditAppendTabelViewCell - (void)dealloc {} - (IBAction)buttonClicked_Remove:(id)sender { if (self.removeCallBack) { self.removeCallBack(); } } - (void)awakeFromNib { [super awakeFromNib]; } @end @interface KMAppendPDFPage: PDFPage @property (nonatomic, strong)PDFPage *drawingPage; @end @implementation KMAppendPDFPage - (void)dealloc {} //- (void)drawWithBox:(PDFDisplayBox)box { // [super drawWithBox:box]; // // CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; // CGSize pageSize = [self boundsForBox:kPDFDisplayBoxCropBox].size; // [self drawPageWithContext:context Page:self.drawingPage PageSize:pageSize]; //} - (void)drawWithBox:(PDFDisplayBox)box toContext:(CGContextRef)context { [super drawWithBox:box toContext:context]; CGSize pageSize = [self boundsForBox:kPDFDisplayBoxCropBox].size; [self drawPageWithContext:context Page:self.drawingPage PageSize:pageSize]; } - (void)drawPageWithContext:(CGContextRef) context Page:(PDFPage *)page PageSize:(CGSize)pageSize { CGSize originalSize = [page boundsForBox:kPDFDisplayBoxCropBox].size; //如果page的旋转角度为90,或者270,宽高交换 if (page.rotation%180) { originalSize = CGSizeMake(originalSize.height, originalSize.width); } CGFloat wRatio = pageSize.width/originalSize.width; CGFloat hRatio = pageSize.height/originalSize.height; CGFloat ratio = MIN(wRatio, hRatio); CGContextSaveGState(context); CGFloat xTransform = (pageSize.width - originalSize.width * ratio)/2; CGFloat yTransform = (pageSize.height - originalSize.height * ratio)/2; CGContextTranslateCTM(context, xTransform, yTransform); CGContextScaleCTM(context, ratio, ratio); NSImage *image = [NSImage imageNamed:@"KMImageNameWatermark"]; if (@available(macOS 10.12, *)) { [page drawWithBox:kPDFDisplayBoxCropBox toContext:context]; // [image drawInRect:NSMakeRect(10, 350, 100, 30) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; NSData *data = [image TIFFRepresentation]; CGImageRef imageRef; if (data) { CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)data, NULL); imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL); CGContextDrawImage(context, CGRectMake(0, pageSize.height-32, 120, 32), imageRef); } [page transformContext:context forBox:kPDFDisplayBoxCropBox]; } else { [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:YES]]; [page drawWithBox:kPDFDisplayBoxCropBox toContext:context]; [NSGraphicsContext restoreGraphicsState]; [page transformContext:context forBox:kPDFDisplayBoxCropBox]; } CGContextRestoreGState(context); } @end #define MyTableCellViewDataType @"MyTableCellViewDataType" static NSString * const KMTableColumnFileNameID = @"fileName"; static NSString * const KMTableColumnPageRangeID = @"pageRangD"; static NSString * const KMTableColumnSizeID = @"size"; static KMPDFEditAppendWindow *windowController = nil; @interface KMPDFEditAppendWindow () { BOOL _isSuccessfully; NSInteger _insertRow; } @property (nonatomic, assign) NSInteger insertRow; @property (weak) IBOutlet NSBox *tableHeaderBox; @property (weak) IBOutlet NSTextField *fileNameLabel; @property (weak) IBOutlet NSTextField *pageRangeLabel; @property (weak) IBOutlet NSTextField *sizeLabel; @property (weak) IBOutlet NSBox *tableHeaderBottomLine; @property (assign) IBOutlet NSTableView *tableView; @property (assign) IBOutlet NSButton *removeButton; @property (assign) IBOutlet NSButton *appendButton; @property (assign) IBOutlet NSButton *cancelButton; //@property (assign) IBOutlet NSButton *addFileButton; @property (assign) IBOutlet NSBox *clearBox; @property (assign) IBOutlet NSBox *nMergeBox; @property (assign) IBOutlet NSBox *nCancelBox; @property (weak) IBOutlet NSBox *addBox; @property (nonatomic, strong) KMDesignSelect *addFileButton; @property (assign) IBOutlet NSProgressIndicator *progress; //宽输入框 @property (assign) IBOutlet NSTextField *pageSizeWidthTextField; //宽高输入连接符 @property (assign) IBOutlet NSTextField *pageSizeWidthHeightConnectorTextField; //高输入框 @property (assign) IBOutlet NSTextField *pageSizeHeightTextField; //宽高单位 @property (assign) IBOutlet NSTextField *pageSizeUnitLabel; @property (nonatomic,retain) NSMutableArray *files; @property (nonatomic,retain) NSArray *addFiles; @property (nonatomic, retain) NSMutableIndexSet *insertIndexSet; @property (nonatomic,retain) NSString *password; @property (nonatomic,retain) PDFDocument *PDFDocument; @property (nonatomic,assign) KMPDFPageEditType editType; @property (nonatomic,assign) CGFloat allFileSize; @property (nonatomic,retain) NSMutableArray *rootPDFOutlineArray; @property (nonatomic,assign) CGSize newPageSize; @property (nonatomic,retain) NSMutableArray *lockFilePathArr; @property (nonatomic,assign) NSInteger lockFileIndex; @property (weak) IBOutlet NSView *originalSizeButton; @property (weak) IBOutlet KMImageTitleButton *A4SizeButton; @property (weak) IBOutlet KMImageTitleButton *A3SizeButton; @property (weak) IBOutlet KMImageTitleButton *USLetterSizeButton; @property (weak) IBOutlet KMImageTitleButton *USLegalButton; @property (weak) IBOutlet KMImageTitleButton *customSizeButton; @property (assign) IBOutlet NSBox *box; @property (assign) IBOutlet NSTextField *boxLabel; @property (assign) IBOutlet KMBlankView *myBlankView; @property (weak) IBOutlet NSTextField *limitLable; @property (weak) IBOutlet NSImageView *limitTipIv; @property (nonatomic, strong) KMSavePanelAccessoryController *savePanelAccessoryViewController; @property (nonatomic, assign) BOOL canMerge; @property (nonatomic, strong) KMDesignButton *clearVC; @property (nonatomic, strong) KMDesignButton *nMergeVC; @property (nonatomic, strong) KMDesignButton *nCancelVC; @property (nonatomic, strong) NSButton *loading_backgroundView; @property (nonatomic, strong) NSAlert *alert; @property (nonatomic, assign) BOOL limit; @end @implementation KMPDFEditAppendWindow - (void)dealloc { _tableView.delegate = nil; _tableView.dataSource = nil; #if VERSION_DMG [[NSNotificationCenter defaultCenter] removeObserver:self]; #endif } //没有打开文档,选择he'bing - (id)initWithFilePaths:(NSArray *)files { if (self = [super initWithWindowNibName:@"KMPDFEditAppendWindow"]) { self.PDFDocument = [[PDFDocument alloc] init]; self.addFiles = files; self.editType = KMPDFPageEditMerge; _lockFilePathArr = [[NSMutableArray alloc] init]; _files = [[NSMutableArray alloc] init]; } return self; } - (id)initWithPDFDocument:(PDFDocument *)document password:(NSString *)password { if (self = [super initWithWindowNibName:@"KMPDFEditAppendWindow"]) { // self.PDFDocument = document; self.PDFDocument = [[PDFDocument alloc] init]; self.editType = KMPDFPageEditAppend; _lockFilePathArr = [[NSMutableArray alloc] init]; _files = [[NSMutableArray alloc] init]; KMFileAttribute *file = [[KMFileAttribute alloc] init]; file.myPDFDocument = document; file.filePath = document.documentURL.path; file.oriFilePath = self.oriDucumentUrl.path; if (password && password.length > 0) { file.password = password; file.isLocked = YES; } [self.files addObject:file]; } return self; } - (void)setOriDucumentUrl:(NSURL *)oriDucumentUrl { _oriDucumentUrl = oriDucumentUrl; KMFileAttribute *file = self.files.firstObject; file.oriFilePath = oriDucumentUrl.path; } - (void)km_windowWillCloseNotifation:(NSNotification *)noti { __weak typeof(self) weakSelf = self; BOOL result = [KMLightMemberManager.manager canPayFunction]; self.limit = !result; if (result) { self.limitLable.hidden = YES; self.limitTipIv.hidden = YES; } else { // [KMLightMemberManager.manager canUseAdvancedWithNeedNetworking:NO completionHandler:^(BOOL isLogin) { // dispatch_sync(dispatch_get_main_queue(), ^{ // if (isLogin) { // weakSelf.limitLable.hidden = NO; // weakSelf.limitTipIv.hidden = NO; // } else { // weakSelf.limitLable.hidden = YES; // weakSelf.limitTipIv.hidden = YES; // } // }); // }]; } } - (void)windowDidLoad { [super windowDidLoad]; #if VERSION_DMG [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(km_windowWillCloseNotifation:) name:NSWindowWillCloseNotification object:nil]; #endif if ([self mergeCountIsReach]) { NSLog(@"合并次数已达到限制. count: %ld", [self getMergeCount]); } self.window.contentView.wantsLayer = YES; // self.window.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua]; self.clearVC = [[KMDesignButton alloc] initWithType: DesignButtonTypeImage]; self.nMergeVC = [[KMDesignButton alloc] initWithType: DesignButtonTypeText]; self.nCancelVC = [[KMDesignButton alloc] initWithType: DesignButtonTypeText]; // self.nMergeVC.button.keyEquivalent = @"\\r"; self.clearBox.fillColor = NSColor.clearColor; self.clearBox.contentView = self.clearVC.view; self.nMergeBox.fillColor = NSColor.clearColor; self.nMergeBox.contentView = self.nMergeVC.view; self.nCancelBox.fillColor = NSColor.clearColor; self.nCancelBox.contentView = self.nCancelVC.view; self.box.cornerRadius = 0; self.box.fillColor = [NSColor colorWithRed:247/255.f green:248/255.f blue:250/255.f alpha:1.f]; self.window.title = NSLocalizedString(@"Merge PDF Files",nil); self.pageSizeWidthTextField.enabled = NO; self.pageSizeHeightTextField.enabled = NO; self.pageSizeWidthTextField.stringValue = @"595"; self.pageSizeHeightTextField.stringValue = @"841"; self.pageSizeWidthTextField.formatter = [[TextFieldFormatter alloc] init]; self.pageSizeHeightTextField.formatter = [[TextFieldFormatter alloc] init]; NSArray *titles = @[NSLocalizedString(@"Original Size", nil),@"A4",@"A3", NSLocalizedString(@"U.S.Letter", nil),NSLocalizedString(@"U.S.Legal", nil),NSLocalizedString(@"Custom", nil)]; __weak typeof(self) weakSelf = self; int i = 0; for (KMImageTitleButton *button in @[self.originalSizeButton, self.A4SizeButton, self.A3SizeButton, self.USLetterSizeButton, self.USLegalButton, self.customSizeButton]) { KMImageTitleButton *radio = [[KMImageTitleButton alloc] init]; [button addSubview:radio]; radio.frame = button.bounds; radio.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; radio.titleLabel.textColor = [NSColor colorWithRed:223/255.f green:225/255.f blue:229/255.f alpha:1.f]; radio.title = titles[i]; if (i == 0) { radio.state = NSControlStateValueOn; radio.imageName = @"btn_radio_sel_on"; } else { radio.state = NSControlStateValueOff; radio.imageName = @"btn_radio_unsel_on"; } radio.titleLabel.textColor = [NSColor colorWithRed:223/255.f green:225/255.f blue:229/255.f alpha:1.f]; radio.titleLabel.font = [NSFont fontWithName:@"SFProText-Regular" size:14]; radio.action = ^(KMImageTitleButton *view, NSButton *button) { [weakSelf buttonClicked_ChooseSize:view]; }; radio.contentButton.tag = i; i += 1; } self.nCancelVC.target = self; self.nCancelVC.action = @selector(buttonItemClicked_Cancel:); self.nCancelVC.stringValue = NSLocalizedString(@"Cancel", nil); [self.nCancelVC buttonWithType:TokenButtonTypeSec size:TokenButtonSizeM height:[[NSLayoutConstraint alloc] init]]; _removeButton.title = NSLocalizedString(@"Remove", nil); self.clearVC.target = self; self.clearVC.action = @selector(buttonItemClicked_Clear:); self.clearVC.image = [NSImage imageNamed:@"icon_btn_clear_false_norm"]; self.clearVC.image_hov = [NSImage imageNamed:@"icon_btn_clear_false_hov"]; self.clearVC.image_act = [NSImage imageNamed:@"icon_btn_clear_false_act"]; self.clearVC.image_disabled = [NSImage imageNamed:@"icon_btn_clear_Disabled_norm"]; [self.clearVC buttonWithType:TokenButtonTypeSec_Icon size:TokenButtonSizeM height:[[NSLayoutConstraint alloc] init]]; [_addFileButton setTitle:NSLocalizedString(@"Add Files", nil)]; self.nMergeVC.target = self; self.nMergeVC.action = @selector(buttonItemClicked_Append:); self.nMergeVC.stringValue = NSLocalizedString(@"Merge", nil); [self.nMergeVC buttonWithType:TokenButtonTypeCta size:TokenButtonSizeM height:[[NSLayoutConstraint alloc] init]]; self.tableView.delegate = self; self.tableView.dataSource = self; self.tableView.allowsMultipleSelection = YES; [_tableView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSPasteboardTypeString, NSPasteboardTypePDF, MyTableCellViewDataType, nil]]; NSArray *tableHeaderTitles = @[NSLocalizedString(@"File Name", nil),NSLocalizedString(@"Page Range", nil),NSLocalizedString(@"Size", nil)]; i = 0; for (NSTextField *label in @[self.fileNameLabel, self.pageRangeLabel, self.sizeLabel]) { label.stringValue = tableHeaderTitles[i]; label.textColor = [NSColor colorWithRed:97/255.f green:100/255.f blue:105/255.f alpha:1.f]; label.font = [NSFont fontWithName:@"SFProText-Regular" size:12]; i += 1; } self.tableHeaderBottomLine.fillColor = [NSColor colorWithRed:223/255.f green:225/255.f blue:229/255.f alpha:1.f]; [self.tableView removeTableColumn:self.tableView.tableColumns.firstObject]; NSTableColumn *column1 = [[NSTableColumn alloc] initWithIdentifier:KMTableColumnFileNameID]; column1.width = 446+16; column1.title = NSLocalizedString(@"File Name", nil); [self.tableView addTableColumn:column1]; NSTableColumn *column2 = [[NSTableColumn alloc] initWithIdentifier:KMTableColumnPageRangeID]; column2.width = 160+8; column2.title = NSLocalizedString(@"Page Range", nil); [self.tableView addTableColumn:column2]; NSTableColumn *column3 = [[NSTableColumn alloc] initWithIdentifier:KMTableColumnSizeID]; column3.width = 139+12; column3.title = NSLocalizedString(@"Size", nil); [self.tableView addTableColumn:column3]; self.tableView.rowHeight = 76; _insertIndexSet = [[NSMutableIndexSet alloc] init]; [self addFiles:_addFiles]; [_progress setHidden:YES]; [self.tableView addSubview:self.myBlankView]; [self.myBlankView registerDragged]; [self.myBlankView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.top.width.equalTo(self.tableView); make.height.equalTo(self.tableView).offset(0); }]; self.myBlankView.wantsLayer = YES; self.myBlankView.layer.backgroundColor = [NSColor clearColor].CGColor; self.myBlankView.titleLabel.stringValue = NSLocalizedString(@"Select Files", nil); self.myBlankView.titleLabel.textColor = [NSColor colorWithRed:97/255.f green:100/255.f blue:105/255.f alpha:1]; self.myBlankView.titleLabel.font = [NSFont fontWithName:@"SFProText-Regular" size:14]; self.myBlankView.secondTitleLabel.stringValue = NSLocalizedString(@"Drop files here or Click “+”. Drag files to reorder as you need. You can also add files or folders via the lower left button.", nil); self.myBlankView.secondTitleLabel.textColor = [NSColor colorWithRed:148/255.f green:152/255.f blue:156/255.f alpha:1]; self.myBlankView.secondTitleLabel.font = [NSFont fontWithName:@"SFProText-Regular" size:12]; self.myBlankView.imageView.image = [NSImage imageNamed:@"KMImageNameEmptyAddNormal"]; self.myBlankView.allowedFileTypes = [KMImageAccessoryController supportedImageTypes]; self.myBlankView.mouseActionCallBack = ^(KMBlankViewMouseEventType mouseType) { if (mouseType == KMBlankViewMouseEventTypeMouseEnter) { weakSelf.myBlankView.imageView.image = [NSImage imageNamed:@"KMImageNameEmptyAddHover"]; } else if (mouseType == KMBlankViewMouseEventTypeMouseExit) { weakSelf.myBlankView.imageView.image = [NSImage imageNamed:@"KMImageNameEmptyAddNormal"]; } else if (mouseType == KMBlankViewMouseEventTypeMouseDown) { weakSelf.myBlankView.imageView.image = [NSImage imageNamed:@"KMImageNameEmptyAddHover"]; [weakSelf itemAddFileAction]; } else if (mouseType == KMBlankViewMouseEventTypeMouseUp) { weakSelf.myBlankView.imageView.image = [NSImage imageNamed:@"KMImageNameEmptyAddHover"]; } }; self.myBlankView.dragSuccessBlock = ^(NSArray * fileNames) { NSMutableArray *array = [NSMutableArray array]; for(NSString *path in fileNames){ if (![weakSelf isExistAtFilepath:path]) { continue; } NSDictionary *attrib = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil]; CGFloat fileSize = [[attrib objectForKey:NSFileSize] floatValue]; weakSelf.allFileSize = weakSelf.allFileSize + fileSize; if (![KMMemberInfo shared].isMemberAllFunction) { //免費版只支援2個檔案做合併小于20M的文件合并 if (self->_files.count >= 2 || self.allFileSize > (20 * 1024 * 1024)) { [[KMMemberInfo shared] advancedFunctionUsage]; self.allFileSize = self.allFileSize - fileSize; [self addFiles:array]; return; } } [array addObject:path]; } [weakSelf addFiles:array]; }; [self updateButtonState]; id outputBookMarkObject = [[NSUserDefaults standardUserDefaults] objectForKey:@"kmAppendOutputPath"]; if ([outputBookMarkObject isKindOfClass:[NSData class]]) { NSData* outputBookMarkData = (NSData*)outputBookMarkObject; NSURL *bookmarkedURL = [NSURL URLByResolvingBookmarkData:outputBookMarkData options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:nil error:nil]; [bookmarkedURL startAccessingSecurityScopedResource]; if (bookmarkedURL) { // _outputText.stringValue = [bookmarkedURL path]; } } self.boxLabel.stringValue = NSLocalizedString(@"Page size:", nil); self.boxLabel.textColor = [NSColor colorWithRed:37/255.f green:38/255.f blue:41/255.f alpha:1.f]; self.boxLabel.font = [NSFont fontWithName:@"SFProText-Regular" size:16]; self.addFileButton = [[KMDesignSelect alloc] initWithType:1]; self.addBox.fillColor = [NSColor clearColor]; self.addBox.contentView = self.addFileButton.view; [self.addFileButton removeAllItems]; [self.addFileButton addItemsWithObjectValues:@[NSLocalizedString(@"Add Files", ""),NSLocalizedString(@"Add Folder", ""),NSLocalizedString(@"Add Open Files", "")]]; [self.addFileButton selectItemAt:0]; self.addFileButton.editable = false; //默认属性,初始化可不设置 self.addFileButton.delete = self; [self.addFileButton updateUI]; self.loading_backgroundView = [[NSButton alloc] init]; [self.window.contentView addSubview:self.loading_backgroundView]; self.loading_backgroundView.frame = self.window.contentView.bounds; self.loading_backgroundView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; self.loading_backgroundView.title = @""; self.loading_backgroundView.bordered = NO; self.loading_backgroundView.wantsLayer = YES; self.loading_backgroundView.layer.backgroundColor = [NSColor clearColor].CGColor; self.loading_backgroundView.hidden = YES; self.limitLable.stringValue = NSLocalizedString(@"Merge 2 files at a time", ""); self.limitLable.font = [NSFont SFProTextRegularFont:12]; self.limitLable.textColor = [NSColor km_initWithHex:@"#F3465B" alpha:1]; self.limit = NO; BOOL result = [KMLightMemberManager.manager canPayFunction]; self.limit = !result; if (result) { self.limitLable.hidden = YES; self.limitTipIv.hidden = YES; } else { //#if VERSION_DMG // [KMLightMemberManager.manager canUseAdvancedWithNeedNetworking:NO completionHandler:^(BOOL isLogin) { // dispatch_sync(dispatch_get_main_queue(), ^{ // if (isLogin) { // weakSelf.limitLable.hidden = NO; // weakSelf.limitTipIv.hidden = NO; // } else { // weakSelf.limitLable.hidden = YES; // weakSelf.limitTipIv.hidden = YES; // } // }); // }]; // //#else self.limitLable.hidden = NO; self.limitTipIv.hidden = NO; //#endif } } - (void)updateButtonState { if (_files.count > 0) { self.myBlankView.hidden = YES; self.tableHeaderBox.hidden = NO; [_removeButton setEnabled:YES]; [self.clearVC setEnabled:YES]; if (self.files.count > 1) { [self.nMergeVC setEnabled:YES]; self.canMerge = YES; } else { self.canMerge = NO; [self.nMergeVC setEnabled:NO]; } } else { self.myBlankView.hidden = NO; self.tableHeaderBox.hidden = YES; [_removeButton setEnabled:NO]; [self.clearVC setEnabled:NO]; self.canMerge = NO; [self.nMergeVC setEnabled:NO]; } } #pragma mark -NSTextFieldDelegate - (void)controlTextDidChange:(NSNotification *)obj { NSTextField *textField = (NSTextField*)[obj object]; NSInteger index = textField.tag; [[_files objectAtIndex:index] setPagesString:textField.stringValue]; } #pragma mark Show Methods - (void)didEndSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { if (contextInfo != NULL) { void (^handler)(BOOL isSuccessfully ,NSIndexSet * selectedIndexSet) = CFBridgingRelease(contextInfo); handler(_isSuccessfully,self.insertIndexSet); } windowController = nil; } - (void)beginSheetModalForWindow:(NSWindow *)window completionHandler:(void (^)(BOOL isSuccessfully,NSIndexSet * selectedIndexSet))handler { if (windowController.window.isSheet) { #if DEBUG NSLog(@"合并窗口已显示"); #endif return; } windowController = self; [NSApp beginSheet:[self window] modalForWindow:window modalDelegate:self didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) contextInfo:handler ? CFBridgingRetain(handler) : NULL]; } #pragma mark Private methor - (void)viewFileAtFinder:(NSString *)filePath { NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; NSURL *url = [NSURL fileURLWithPath:filePath]; [workspace activateFileViewerSelectingURLs:[NSArray arrayWithObject:url]]; } - (void)addFiles:(NSArray*)files { [_lockFilePathArr removeAllObjects]; _lockFileIndex = 0; for (NSString *filePath in files) { if ([filePath.pathExtension.lowercaseString isEqualToString:@"pdf"]) { KMFileAttribute *file = [[KMFileAttribute alloc] init]; file.filePath = filePath; PDFDocument *document = [[PDFDocument alloc] initWithURL:[NSURL fileURLWithPath:filePath]]; NSDictionary *attrib = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil]; self.allFileSize = [[attrib objectForKey:NSFileSize] floatValue]; if ([document isLocked]) { [_lockFilePathArr addObject:filePath]; } else if ([KMTools hasPermissionsLimit:document]) { [_lockFilePathArr addObject:filePath]; } else { if ([NSDocument isDamageWithUrl:[NSURL fileURLWithPath:filePath]]) { NSAlert *alert = [[NSAlert alloc] init]; alert.messageText = NSLocalizedString(@"The file was not added successfully, please select the file again.", @""); [alert runModal]; } else { [_files addObject:file]; } } } else { KMFileAttribute *file = [[KMFileAttribute alloc] init]; file.filePath = filePath; PDFDocument *document = [[PDFDocument alloc] init]; NSImage *image = [[NSImage alloc] initWithContentsOfFile:filePath]; if (image == nil) { continue; } // [document insertPage:image.size withImage:filePath atIndex:0]; [document insertPage:[[PDFPage alloc] initWithImage:image] atIndex:0]; file.myPDFDocument = document; NSDictionary *attrib = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil]; self.allFileSize = [[attrib objectForKey:NSFileSize] floatValue]; if ([NSDocument isDamageWithUrl:[NSURL fileURLWithPath:filePath]]) { NSAlert *alert = [[NSAlert alloc] init]; alert.messageText = NSLocalizedString(@"The file was not added successfully, please select the file again.", @""); [alert runModal]; } else { [_files addObject:file]; } } } [self updateButtonState]; [_tableView reloadData]; if ([_lockFilePathArr count]) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ if (self.files.count == 0) { self.insertRow = 0; } else { self.insertRow = self.files.count; } [self openPasswordWindow]; }); } } - (BOOL)isExistAtFilepath:(NSString *)filePath { NSMutableArray *array = [NSMutableArray array]; for (KMFileAttribute *file in self.files) { [array addObject:file.filePath]; } if ([array containsObject:filePath]) { return NO; } return YES; } -(void)openPasswordWindow { if ([_lockFilePathArr count] > _lockFileIndex) { NSString *filePath = [_lockFilePathArr objectAtIndex:_lockFileIndex]; __weak typeof(self) weakSelf = self; [KMPasswordInputWindow openWindowWithWindow:self.window type:KMPasswordInputWindowTypeOwner url:[NSURL fileURLWithPath:filePath] callback:^(enum KMPasswordInputWindowResult result, NSString * _Nullable password) { if (password.length > 0) { KMFileAttribute *file = [[KMFileAttribute alloc] init]; file.filePath = filePath; file.isLocked = YES; file.password = password; [weakSelf.files insertObject:file atIndex:weakSelf.insertRow]; weakSelf.insertRow ++; } weakSelf.lockFileIndex++; // if ([self.lockFilePathArr count] > self.lockFileIndex) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [weakSelf openPasswordWindow]; }); // } else { [weakSelf.tableView reloadData]; [weakSelf updateButtonState]; // } }]; } } - (void)comboBoxAction:(NSInteger)itemIndex atRow:(NSInteger)row { NSInteger index = row; // 数组不存在,或者索引超出数组长度 if ((!_files) || (index > ((NSInteger)[_files count] - 1))) { return; } if (itemIndex == 0) { KMFileAttribute *currentFile = [_files objectAtIndex:index]; [currentFile setBAllPage:YES]; currentFile.pagesType = KMPageRangeAll; [self.window makeFirstResponder:self]; } else if (itemIndex == 1) { KMFileAttribute *currentFile = [_files objectAtIndex:index]; currentFile.pagesType = KMPageRangeOdd; [currentFile setBAllPage:NO]; PDFDocument *tDocument = currentFile.myPDFDocument; if (tDocument == nil) { tDocument = [[PDFDocument alloc] initWithURL:[NSURL fileURLWithPath:currentFile.filePath]]; } if ([currentFile isLocked]) { [tDocument unlockWithPassword:currentFile.password]; } NSString *tPagesString = @""; for (NSInteger i = 0; i < tDocument.pageCount; i++) { if (i%2 == 0) { if (tPagesString.length == 0) { tPagesString = [tPagesString stringByAppendingString:[NSString stringWithFormat:@"%ld",i +1]]; }else{ tPagesString = [tPagesString stringByAppendingString:[NSString stringWithFormat:@",%ld",i +1]]; } } } currentFile.pagesString = tPagesString; [self.window makeFirstResponder:self]; } else if (itemIndex == 2) { KMFileAttribute *currentFile = [_files objectAtIndex:index]; currentFile.pagesType = KMPageRangeEven; [currentFile setBAllPage:NO]; NSString *tPagesString = @""; PDFDocument *tDocument = currentFile.myPDFDocument; if (tDocument == nil) { tDocument = [[PDFDocument alloc] initWithURL:[NSURL fileURLWithPath:currentFile.filePath]]; } if ([currentFile isLocked]) { [tDocument unlockWithPassword:currentFile.password]; } for (NSInteger i = 0; i = weakSelf.files.count) { return; } KMFileAttribute *file = [weakSelf.files objectAtIndex:row]; [file setPagesString:string]; // file.pageRangeError = NO; // dispatch_async(dispatch_get_main_queue(), ^{ // [weakSelf.tableView reloadData]; // }); }; cell.textDidEndEdit = ^(NSString * _Nonnull string, KMPDFMergePageRangeTabelViewCell *pageRangeCell) { if (row >= weakSelf.files.count || [string isEqual: @""]) { return; } KMFileAttribute *file = [weakSelf.files objectAtIndex:row]; if (!file.fetchSelectPages) { // file.pageRangeError = YES; if (weakSelf.alert) { return; } dispatch_async(dispatch_get_main_queue(), ^{ // [weakSelf.tableView reloadData]; NSAlert *alert = [[NSAlert alloc] init]; // weakSelf.alert = alert; [alert setAlertStyle:NSAlertStyleCritical]; [alert setMessageText:[NSString stringWithFormat:@"%@ %@",[file.filePath lastPathComponent],NSLocalizedString(@"Invalid page range or the page number is out of range. Please try again.", nil)]]; [alert runModal]; file.pagesString = @""; [pageRangeCell updatePageRange:file.pagesType pageStrings:file.pagesString isFirstResponser:NO]; // dispatch_async(dispatch_get_main_queue(), ^{ // weakSelf.alert = nil; // }); // [weakSelf.tableView reloadData]; // [weakSelf.tableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:row] columnIndexes:[NSIndexSet indexSetWithIndex:1]]; }); } else { [pageRangeCell updatePageRange:file.pagesType pageStrings:file.pagesString isFirstResponser:YES]; } }; return cell; } if (tableColumn.identifier == KMTableColumnSizeID) { KMPDFMergeSizeTabelViewCell *cell = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self]; if (cell == nil) { cell = [[KMPDFMergeSizeTabelViewCell alloc] init]; } NSString *filePath = pdf.documentURL.path; if (!filePath) { filePath = fileAttribute.filePath; } NSDictionary *attributesDic = [[NSFileManager defaultManager]attributesOfItemAtPath:filePath error:nil]; float size = [[attributesDic objectForKey:NSFileSize] floatValue]/1024; cell.label.stringValue = [NSString stringWithFormat:@"%0.1f %c", truesize(size) , moniker(size)]; cell.button.hidden = YES; __weak typeof(self) weakSelf = self; cell.callback = ^{ NSDictionary *attrib = [[NSFileManager defaultManager] attributesOfItemAtPath:fileAttribute.filePath error:nil]; CGFloat fileSize = [[attrib objectForKey:NSFileSize] floatValue]; weakSelf.allFileSize = weakSelf.allFileSize - fileSize; [weakSelf.files removeObject:fileAttribute]; [weakSelf.tableView reloadData]; [weakSelf updateButtonState]; }; return cell; } KMPDFMergeFileNameTabelViewCell *cell = [tableView makeViewWithIdentifier:@"fileName" owner:self]; if (cell == nil) { cell = [[KMPDFMergeFileNameTabelViewCell alloc] init]; } NSString *fileName = [fileAttribute.filePath lastPathComponent]; if (fileAttribute.oriFilePath.length > 0) { fileName = fileAttribute.oriFilePath.stringByDeletingPathExtension.lastPathComponent; } cell.numberLabel.stringValue = [NSString stringWithFormat:@"%ld",(row + 1)];; cell.fileNameLabel.stringValue = fileName; cell.pageNumberLabel.stringValue = [NSString stringWithFormat:@"%ld %@",pdf.pageCount,NSLocalizedString(@"Pages", nil)];; // cell.iconImageView.image = [[pdf pageAtIndex:0] thumbnailWithSize:60*2 forBox:kPDFDisplayBoxCropBox]; if (pdf.documentURL) { if (fileAttribute.password.length > 0) { cell.iconImageView.image = [[pdf pageAtIndex:0] thumbnailOfSize:NSMakeSize(120, 120) forBox:kPDFDisplayBoxCropBox]; } else { cell.iconImageView.image = [NSImage previewForFileWithPath:pdf.documentURL ofSize:NSMakeSize(120, 120) asIcon:YES]; } } else if (fileAttribute.filePath) { // if ([fileAttribute.filePath.pathExtension.lowercaseString isEqualToString:@"pdf"]) { cell.iconImageView.image = [NSImage previewForFileWithPath:[NSURL fileURLWithPath:fileAttribute.filePath] ofSize:NSMakeSize(120, 120) asIcon:YES]; // } else { // cell.iconImageView.image = [NSImage previewForFileWithPath:fileAttribute.filePath ofSize:NSMakeSize(120, 120) asIcon:YES]; // } } else { cell.iconImageView.image = nil; } return cell; } - (BOOL)tableView:(NSTableView *)tableView shouldSelectTableColumn:(NSTableColumn *)tableColumn { return NO; } #pragma mark -NSTableViewDelegate - (BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard { // Copy the row numbers to the pasteboard. NSData *zNSIndexSetData = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes]; [pboard declareTypes:[NSArray arrayWithObject:MyTableCellViewDataType] owner:self]; [pboard setData:zNSIndexSetData forType:MyTableCellViewDataType]; return YES; } - (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id )info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation { if (dropOperation == NSTableViewDropOn) { return NSDragOperationNone; } BOOL isCanDrag = NO; NSDragOperation result = NSDragOperationNone; NSPasteboard *pboard = [info draggingPasteboard]; if ([pboard availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]]) { NSArray *fileNames = [pboard propertyListForType:NSFilenamesPboardType]; for (NSString* path in fileNames) { if ([[KMImageAccessoryController supportedImageTypes] containsObject:path.pathExtension.lowercaseString]) { isCanDrag = YES; }else{ isCanDrag = NO; break; } } }else if ([pboard availableTypeFromArray:[NSArray arrayWithObject:MyTableCellViewDataType]]){ result = NSDragOperationEvery; } if (isCanDrag) { result = NSDragOperationCopy; } return result; } - (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id )info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation { BOOL result = NO; NSPasteboard *pboard = [info draggingPasteboard]; _insertRow = row; if ([pboard availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]]) { NSMutableArray *fileNames = [pboard propertyListForType:NSFilenamesPboardType]; NSMutableArray *array = [NSMutableArray array]; for(NSString *path in fileNames){ if (![self isExistAtFilepath:path]) { continue; } NSDictionary *attrib = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil]; CGFloat fileSize = [[attrib objectForKey:NSFileSize] floatValue]; self.allFileSize = self.allFileSize + fileSize; if (![KMMemberInfo shared].isMemberAllFunction) { //免費版只支援2個檔案做合併小于20M的文件合并 if (_files.count >= 2 || self.allFileSize > (20 * 1024 * 1024)) { [[KMMemberInfo shared] advancedFunctionUsage]; self.allFileSize = self.allFileSize - fileSize; [self addFiles:array]; result = YES; return NO; } } [array addObject:path]; } [self addFiles:array]; result = YES; } else if ([pboard availableTypeFromArray:[NSArray arrayWithObject:MyTableCellViewDataType]]){ NSData* rowData = [pboard dataForType:MyTableCellViewDataType]; NSIndexSet* rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:rowData]; NSMutableArray *moveArray = [[NSMutableArray alloc] init]; NSMutableArray *allPhoto = [_files mutableCopy]; NSInteger index = 0; [rowIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) { KMFileAttribute * file = allPhoto[idx]; [moveArray addObject:file]; [_files removeObject:file]; }]; if (row > 0) { KMFileAttribute * indexFile = allPhoto[row -1]; while([moveArray containsObject:indexFile]){ row --; if ((row < 0)) { indexFile = nil; break; } else { indexFile = allPhoto[row]; } } if(indexFile){ index = [_files indexOfObject:indexFile]+1; } } for (NSInteger i = 0; i< moveArray.count; i++) { [_files insertObject:moveArray[i] atIndex:(index +i)]; } [_tableView reloadData]; result = YES; // [moveArray release]; // [allPhoto release]; } else { result = NO; } return result; } - (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row { KMBatchTableRowView *rowView = [[KMBatchTableRowView alloc] init]; rowView.backgroundView.layer.backgroundColor = [NSColor colorWithRed:237/255.f green:238/255.f blue:240/255.f alpha:1.f].CGColor; rowView.backgroundView.layer.cornerRadius = 4.f; rowView.selectionInset = NSEdgeInsetsMake(0, 16, 0, 16); rowView.selectionRadius = 4.f; rowView.selectionBackgroundColorBlock = ^NSColor * _Nonnull{ return [NSColor colorWithRed:206/255.f green:208/255.f blue:212/255.f alpha:0.6f]; }; return rowView; } - (void)tableViewSelectionDidChange:(NSNotification *)notification { } #pragma mark Buutton Action - (void)_clearData { for (KMFileAttribute *file in self.files) { if (file.oriFilePath.length > 0 && [[NSFileManager defaultManager] fileExistsAtPath:file.filePath]) { [[NSFileManager defaultManager] removeItemAtURL:[NSURL fileURLWithPath:file.filePath] error:nil]; } } } - (IBAction)buttonItemClicked_Cancel:(id)sender { [self _clearData]; _isSuccessfully = NO; [NSApp endSheet:[self window] returnCode:[(NSView *)sender tag]]; [[self window] orderOut:self]; } - (IBAction)buttonItemClicked_Append:(id)sender { if (!self.canMerge) { return; } //#if VERSION_DMG // [KMLightMemberManager.manager canUseAdvancedWithNeedNetworking:NO completionHandler:^(BOOL result) { // dispatch_async(dispatch_get_main_queue(), ^{ // if (result) { // [self doAppend]; // } else { // [KMComparativeTableViewController showWithWindow:self.window :KMComparativeInputTypeMerge inputType:KMSubscribeWaterMarkTypeMerge]; // } // }); // }]; //#else [self doAppend]; //#endif } - (IBAction)doAppend { // if (KMLightMemberManager.manager.purchaseState != KMPurchaseManagerStateSubscription && _files.count > 2) { //// [KMSubscribeWaterMarkWindowController showWithWindow: self.window isContinue: false limit type:KMSubscribeWaterMarkTypeMerge subscribeDidClick:^{ //// //// } completion:^(BOOL isSub, BOOL isWater, BOOL isClose) { //// //// }]; // [KMSubscribeWaterMarkWindowController showWithWindow:self.window isContinue:false limit:[self mergeCountIsReach] type:KMSubscribeWaterMarkTypeMerge subscribeDidClick:^{ // // } completion:^(BOOL, BOOL, BOOL) { // // }]; // return; // } else if (KMLightMemberManager.manager.purchaseState != KMPurchaseManagerStateSubscription && _files.count <= 2) { // __weak typeof(self) weakSelf = self; //// [KMSubscribeWaterMarkWindowController showWithWindow: self.window isContinue:true type:KMSubscribeWaterMarkTypeMerge subscribeDidClick:^{ //// //// } completion:^(BOOL isSub, BOOL isWater, BOOL isClose) { //// if (isWater) { //// dispatch_async(dispatch_get_main_queue(), ^{ //// [weakSelf buttonItemClick_Append: sender]; //// }); //// } //// }]; // BOOL isContinue = YES; // BOOL limit = [self mergeCountIsReach]; // if (limit) { // isContinue = NO; // } // // [KMSubscribeWaterMarkWindowController showWithWindow:self.window isContinue:isContinue limit:limit type:KMSubscribeWaterMarkTypeMerge subscribeDidClick:^{ // // } completion:^(BOOL isSub, BOOL isWater, BOOL isClose) { // if (isClose) { // return; // } // if (isSub) { // dispatch_async(dispatch_get_main_queue(), ^{ // [weakSelf buttonItemClick_Append: nil]; // }); // return; // } // if (isWater && !limit) { // dispatch_async(dispatch_get_main_queue(), ^{ // [weakSelf buttonItemClick_Append: nil]; // }); // return; // } // }]; // return; // } [self buttonItemClick_Append: nil]; } - (void)buttonItemClick_Append:(id)sender { KMImageTitleButton *customSizeButton = self.customSizeButton.subviews.lastObject; if (customSizeButton.state == NSControlStateValueOn) { NSInteger widthFloat = [self.pageSizeWidthTextField.stringValue integerValue]; NSInteger heightFloat = [self.pageSizeHeightTextField.stringValue integerValue]; NSString *widthString = [NSString stringWithFormat:@"%ld",widthFloat]; NSString *heightString = [NSString stringWithFormat:@"%ld",heightFloat]; if (![widthString isEqualToString:self.pageSizeWidthTextField.stringValue] ||![heightString isEqualToString:self.pageSizeHeightTextField.stringValue]||widthFloat <= 0 ||heightFloat <= 0 ) { NSBeep(); return; }else{ self.newPageSize = CGSizeMake(widthFloat, heightFloat); } } //初始化数组 if (!self.rootPDFOutlineArray) { self.rootPDFOutlineArray = [NSMutableArray new]; }else{ [self.rootPDFOutlineArray removeAllObjects]; } //如果是合并,文件路径不存在,或者文件个数小于等于1 return if (_editType == KMPDFPageEditMerge) { if (_files.count <= 1 ) { NSAlert *alert = [[NSAlert alloc] init]; [alert setAlertStyle:NSAlertStyleCritical]; [alert setMessageText:NSLocalizedString(@"To start merging, please select at least 2 files.", nil)]; [alert runModal]; return; } } //计算所有文件的大小,非会员如果超过20M,不允许继续操作 CGFloat allSize; for (KMFileAttribute *file in _files) { NSDictionary *attrib = [[NSFileManager defaultManager] attributesOfItemAtPath:[file filePath] error:nil]; allSize = [[attrib objectForKey:NSFileSize] floatValue] + allSize; } if (![KMMemberInfo shared].isMemberAllFunction) { if (allSize > (20 * 1024 * 1024) || _files.count > 2) { [[KMMemberInfo shared] advancedFunctionUsage]; return; } } _isSuccessfully = NO; [self.nCancelVC setEnabled:NO]; self.canMerge = NO; BOOL allPage = YES;//只有是全部才支持大纲的合并 for (KMFileAttribute *file in _files) { if (!file.fetchSelectPages) { dispatch_async(dispatch_get_main_queue(), ^{ NSAlert *alert = [[NSAlert alloc] init]; [alert setAlertStyle:NSAlertStyleCritical]; [alert setMessageText:[NSString stringWithFormat:@"%@ %@",[file.filePath lastPathComponent],NSLocalizedString(@"Invalid page range or the page number is out of range. Please try again.", nil)]]; [alert runModal]; [self.nCancelVC setEnabled:YES]; self.canMerge = YES; }); return; } } [_progress setHidden:NO]; [_progress startAnimation:nil]; self.loading_backgroundView.hidden = NO; for(KMFileAttribute *file in _files){ //只要有一个文件不是全部page,那么就不合并大纲 if (allPage == YES) { allPage = file.bAllPage; } //通过路径获取文件 PDFDocument *tdocument = file.myPDFDocument; if (tdocument == nil) { tdocument = [[PDFDocument alloc] initWithURL:[NSURL fileURLWithPath:[file filePath]]]; file.myPDFDocument = tdocument; } //所有的outline数组 NSMutableArray *PDFOutlineArr = [NSMutableArray new]; //需要解锁 if (file.isLocked) { [tdocument unlockWithPassword:file.password]; } //如果根存在,那么遍历出所有的outline,添加到数组中,如果不存在,那么就创建一个根 if (tdocument.outlineRoot) { [self.rootPDFOutlineArray addObject:tdocument.outlineRoot]; [self fetchAllOfChildren:tdocument.outlineRoot containerArray:PDFOutlineArr]; [PDFOutlineArr removeObject:tdocument.outlineRoot]; } else { PDFOutline *rootOutline = [[PDFOutline alloc] init]; tdocument.outlineRoot = rootOutline; if (tdocument.outlineRoot) { [self.rootPDFOutlineArray addObject:tdocument.outlineRoot]; } } // for (CPDFOutline *tOutline in PDFOutlineArr) { //这段代码主要是调用他的getter方法;outline显示正确 // [tOutline.destination.page dataRepresentation]; // } for (NSNumber *number in file.fetchSelectPages) { PDFPage *page = [tdocument pageAtIndex:[number integerValue]-1]; [self.PDFDocument insertPage:page atIndex:[self.PDFDocument pageCount]]; // [self.PDFDocument insertPageObject:page atIndex:self.PDFDocument.pageCount]; [self.insertIndexSet addIndex:(self.PDFDocument.pageCount - 1)]; } _isSuccessfully = YES; } KMFileAttribute *file = self.files.firstObject; NSString *fileName = file.filePath.stringByDeletingPathExtension.lastPathComponent; if (file.oriFilePath.length > 0) { fileName = file.oriFilePath.stringByDeletingPathExtension.lastPathComponent; } fileName = [NSString stringWithFormat:@"%@_Merged", fileName]; if (_editType == KMPDFPageEditMerge) { _isSuccessfully = NO; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ PDFOutline *rootline = [[PDFOutline alloc] init]; self.PDFDocument.outlineRoot = rootline; if (allPage) { NSInteger insertIndex = 0; for (NSUInteger i = 0; i < self.rootPDFOutlineArray.count; i++) { PDFOutline *rootPDFOutline = self->_rootPDFOutlineArray[i]; for (NSUInteger j = 0; j < rootPDFOutline.numberOfChildren; j ++) { [self.PDFDocument.outlineRoot insertChild:[rootPDFOutline childAtIndex:j] atIndex: insertIndex]; insertIndex ++; } } } dispatch_async(dispatch_get_main_queue(), ^{ if (self.limit) { [self handerReDraw]; } KMSavePanelAccessoryController *savePanelAccessoryViewController = [[KMSavePanelAccessoryController alloc] init]; NSSavePanel *savePanel = [NSSavePanel savePanel]; savePanel.nameFieldStringValue = fileName; savePanel.allowedFileTypes = @[@"pdf"]; savePanel.accessoryView = savePanelAccessoryViewController.view; self.savePanelAccessoryViewController = savePanelAccessoryViewController; [savePanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) { if (result) { NSString * outputSavePanel = savePanel.URL.path; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ self->_isSuccessfully = [self.PDFDocument writeToFile:outputSavePanel]; if (!self->_isSuccessfully) { self->_isSuccessfully = [self.PDFDocument.dataRepresentation writeToFile:outputSavePanel atomically:YES]; } dispatch_async(dispatch_get_main_queue(), ^{ [self->_progress setHidden:YES]; [self.nCancelVC setEnabled:YES]; self.canMerge = YES; self.loading_backgroundView.hidden = YES; if (self->_isSuccessfully) { [self _clearData]; [self recordMergeCount]; [NSApp endSheet:[self window] returnCode:[(NSView *)sender tag]]; [[self window] orderOut:self]; if (self.saveAsPDFFilePath) { BOOL autoOpen = self.savePanelAccessoryViewController.needOpen; if (autoOpen) { self.saveAsPDFFilePath(outputSavePanel); self.saveAsPDFFilePath = nil; } else { [self viewFileAtFinder:outputSavePanel]; } } else { BOOL autoOpen = self.savePanelAccessoryViewController.needOpen; if (autoOpen) { [[NSDocumentController sharedDocumentController] openDocumentWithContentsOfURL:[NSURL fileURLWithPath:outputSavePanel] display:YES completionHandler:^(NSDocument * _Nullable document, BOOL documentWasAlreadyOpen, NSError * _Nullable error) { }]; } else { [self viewFileAtFinder:outputSavePanel]; } } } else { NSAlert *alert = [[NSAlert alloc] init]; [alert setAlertStyle:NSAlertStyleCritical]; [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"Failed to merge!", nil)]]; NSModalResponse response = [alert runModal]; if (response == 0 ) { [NSApp endSheet:[self window] returnCode:[(NSView *)sender tag]]; [[self window] orderOut:self]; } } }); }); } else { [self->_progress setHidden:YES]; [self.nCancelVC setEnabled:YES]; self.canMerge = YES; self.loading_backgroundView.hidden = YES; } }]; }); }); } else { [self.nCancelVC setEnabled:YES]; self.canMerge = YES; if (allPage) { if (!self.PDFDocument.outlineRoot) { PDFOutline *outline = [[PDFOutline alloc] init]; self.PDFDocument.outlineRoot = outline; } for (NSInteger i = 0; i < self.rootPDFOutlineArray.count; i++) { PDFOutline *rootPDFOutline = _rootPDFOutlineArray[i]; for (NSInteger j = 0; j < rootPDFOutline.numberOfChildren; j ++) { [self.PDFDocument.outlineRoot insertChild:[rootPDFOutline childAtIndex:j] atIndex:self.PDFDocument.outlineRoot.numberOfChildren]; } } } if (_isSuccessfully) { if (self.limit) { [self handerReDraw]; } KMSavePanelAccessoryController *savePanelAccessoryViewController = [[KMSavePanelAccessoryController alloc] init]; NSSavePanel *savePanel = [NSSavePanel savePanel]; savePanel.nameFieldStringValue = fileName; savePanel.allowedFileTypes = @[@"pdf"]; savePanel.accessoryView = savePanelAccessoryViewController.view; self.savePanelAccessoryViewController = savePanelAccessoryViewController; [savePanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) { if (result) { NSString * outputSavePanel = savePanel.URL.path; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ self->_isSuccessfully = [self.PDFDocument writeToFile:outputSavePanel]; if (!self->_isSuccessfully) { self->_isSuccessfully = [self.PDFDocument.dataRepresentation writeToFile:outputSavePanel atomically:YES]; } dispatch_async(dispatch_get_main_queue(), ^{ [self->_progress setHidden:YES]; [self.nCancelVC setEnabled:YES]; self.canMerge = YES; self.loading_backgroundView.hidden = YES; if (self->_isSuccessfully) { [self _clearData]; [self recordMergeCount]; [NSApp endSheet:[self window] returnCode:[(NSView *)sender tag]]; [[self window] orderOut:self]; if (self.saveAsPDFFilePath) { BOOL autoOpen = self.savePanelAccessoryViewController.needOpen; if (autoOpen) { self.saveAsPDFFilePath(outputSavePanel); self.saveAsPDFFilePath = nil; } else { [self viewFileAtFinder:outputSavePanel]; } } else { BOOL autoOpen = self.savePanelAccessoryViewController.needOpen; if (autoOpen) { [[NSDocumentController sharedDocumentController] openDocumentWithContentsOfURL:[NSURL fileURLWithPath:outputSavePanel] display:YES completionHandler:^(NSDocument * _Nullable document, BOOL documentWasAlreadyOpen, NSError * _Nullable error) { }]; } else { [self viewFileAtFinder:outputSavePanel]; } } } else { NSAlert *alert = [[NSAlert alloc] init]; [alert setAlertStyle:NSAlertStyleCritical]; [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"Failed to merge!", nil)]]; NSModalResponse response = [alert runModal]; if (response == 0 ) { [NSApp endSheet:[self window] returnCode:[(NSView *)sender tag]]; [[self window] orderOut:self]; } } }); }); } else { [self->_progress setHidden:YES]; [self.nCancelVC setEnabled:YES]; self.canMerge = YES; self.loading_backgroundView.hidden = YES; } }]; } else { NSAlert *alert = [[NSAlert alloc] init]; [alert setAlertStyle:NSAlertStyleCritical]; [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"Failed to merge!", nil)]]; NSModalResponse response = [alert runModal]; if (response == 0 ) { [NSApp endSheet:[self window] returnCode:[(NSView *)sender tag]]; [[self window] orderOut:self]; } } } } - (IBAction)buttonItemClicked_Clear:(id)sender { [_files removeAllObjects]; [self updateButtonState]; [self.tableView reloadData]; self.allFileSize = 0; } - (IBAction)buttonItemClicked_AddFile:(id)sender { if (![KMMemberInfo shared].isMemberAllFunction) { //免費版只支援2個檔案做合併小于20M的文件合并 if (_files.count >= 2 || self.allFileSize > (20 * 1024 * 1024)) { [[KMMemberInfo shared] advancedFunctionUsage]; return; } } NSMenu *menu = [[NSMenu alloc] init]; NSMenuItem *addFileItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"add files", "") action:@selector(itemAddFileAction) keyEquivalent:@""]; addFileItem.target = self; [menu addItem:addFileItem]; NSMenuItem *addFolderitem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"add Folder", "") action:@selector(itemAddFolderAction) keyEquivalent:@""]; addFolderitem.target = self; [menu addItem:addFolderitem]; NSMenuItem *addOpenFileitem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"add Open Files", "") action:@selector(itemAddOpenFileAction) keyEquivalent:@""]; addOpenFileitem.target = self; [menu addItem:addOpenFileitem]; [menu popUpMenuPositioningItem:nil atLocation:NSMakePoint(100, 10) inView:sender]; } - (void)itemAddFileAction { NSOpenPanel *openPanel = [[NSOpenPanel alloc] init]; [openPanel setAllowedFileTypes:[KMImageAccessoryController supportedImageTypes]]; [openPanel setAllowsMultipleSelection:YES]; openPanel.message = NSLocalizedString(@"Press ⌘/⇧ to select multiple files", nil); [openPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result){ if (result == NSModalResponseOK) { NSMutableArray *array = [NSMutableArray array]; for (NSURL *fileURL in [openPanel URLs]) { if (fileURL) { if (![self isExistAtFilepath:fileURL.path]) { continue; } NSDictionary *attrib = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:nil]; CGFloat fileSize = [[attrib objectForKey:NSFileSize] floatValue]; self.allFileSize = self.allFileSize + fileSize; [array addObject:fileURL.path]; } } [self addFiles:array]; } }]; } - (void)itemAddFolderAction { NSOpenPanel *openPanel = [[NSOpenPanel alloc] init]; [openPanel setAllowedFileTypes:[KMImageAccessoryController supportedImageTypes]]; [openPanel setAllowsMultipleSelection:YES]; openPanel.canChooseFiles = NO; openPanel.canChooseDirectories = YES; openPanel.message = NSLocalizedString(@"Press ⌘/⇧ to select multiple files", nil); [openPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result){ if (result == NSModalResponseOK) { NSMutableArray *result = [NSMutableArray array]; for (NSURL *url in openPanel.URLs) { [self findAllFiles:url result:result]; } NSMutableArray *array = [NSMutableArray array]; for (NSURL *fileURL in result) { if (fileURL) { if (![self isExistAtFilepath:fileURL.path]) { continue; } NSDictionary *attrib = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:nil]; CGFloat fileSize = [[attrib objectForKey:NSFileSize] floatValue]; self.allFileSize = self.allFileSize + fileSize; [array addObject:fileURL.path]; } } [self addFiles:array]; } }]; } - (void)itemAddOpenFileAction { [_lockFilePathArr removeAllObjects]; _lockFileIndex = 0; for (NSWindow *window in NSApp.windows) { NSWindowController *controller = [window windowController]; if (![controller isKindOfClass:[CTBrowserWindowController class]]) { continue; } CTTabStripModel *model = ((CTBrowserWindowController *)controller).browser.tabStripModel; for (int i = 0; i < model.count; i++) { KMMainDocument *document = (KMMainDocument *)[model tabContentsAtIndex:i]; // if (document.windowControllers.count == 0) { // break; // } if (document.isHome) { continue; } KMMainViewController *mainViewController = document.mainViewController; if ([self.PDFDocument.documentURL.path isEqualToString:document.fileURL.path]) { continue; } if (![self isExistAtFilepath:document.fileURL.path]) { continue; } CPDFDocument *pdfDocument = mainViewController.listView.document; if (pdfDocument.isLocked || (!pdfDocument.allowsCopying || !pdfDocument.allowsPrinting)) { [_lockFilePathArr addObject:pdfDocument.documentURL.path]; } else { KMFileAttribute *file = [[KMFileAttribute alloc] init]; file.filePath = document.fileURL.path; file.pdfDocument = mainViewController.document; [_files addObject:file]; } } } [self updateButtonState]; [_tableView reloadData]; if ([_lockFilePathArr count]) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ if (self.files.count == 0) { self.insertRow = 0; } else { self.insertRow = self.files.count; } [self openPasswordWindow]; }); } } - (void)findAllFiles:(NSURL *)folderURL result:(NSMutableArray *)result { NSFileManager *fm = [NSFileManager defaultManager]; BOOL isDirectory = NO; [fm fileExistsAtPath:folderURL.path isDirectory:&isDirectory]; if (!isDirectory) { return; } NSArray *contents = [fm contentsOfDirectoryAtURL:folderURL includingPropertiesForKeys:nil options:0 error:nil]; if (contents.count == 0) { return; } NSArray *array = @[@"jpg",@"cur",@"bmp",@"jpeg",@"gif",@"png",@"tiff",@"tif",/*@"pic",*/@"ico",@"icns",@"tga",@"psd",@"eps",@"hdr",@"jp2",@"jpc",@"pict",@"sgi",@"heic",@"pdf"]; for (NSURL *documentURL in contents) { BOOL isDirectory = NO; [fm fileExistsAtPath:documentURL.path isDirectory:&isDirectory]; if (isDirectory) { [self findAllFiles:documentURL result:result]; } else { if (![array containsObject:[documentURL.pathExtension lowercaseString]]) { continue; } [result addObject:documentURL]; } } } - (IBAction)buttonClicked_ChooseSize:(KMImageTitleButton *)sender { int i = 0; for (KMImageTitleButton *button in @[self.originalSizeButton, self.A4SizeButton, self.A3SizeButton, self.USLetterSizeButton, self.USLegalButton, self.customSizeButton]) { KMImageTitleButton *radio = button.subviews.lastObject; radio.state = NSControlStateValueOff; radio.imageName = @"btn_radio_unsel_on"; i += 1; } sender.state = NSControlStateValueOn; sender.imageName = @"btn_radio_sel_on"; KMImageTitleButton *customSizeButton = self.customSizeButton.subviews.lastObject; self.pageSizeHeightTextField.enabled = self.pageSizeWidthTextField.enabled = [sender isEqual:customSizeButton]; switch (sender.contentButton.tag) { case 0: break; case 1: self.newPageSize = CGSizeMake(595, 841); break; case 2: self.newPageSize = CGSizeMake(841, 1190); break; case 3: self.newPageSize = CGSizeMake(612, 792); break; case 4: self.newPageSize = CGSizeMake(612, 1108); break; case 5: self.newPageSize = CGSizeMake(595, 841); self.pageSizeWidthTextField.stringValue = [NSString stringWithFormat:@"%.0f",self.newPageSize.width]; self.pageSizeHeightTextField.stringValue = [NSString stringWithFormat:@"%.0f",self.newPageSize.height]; break; default: break; } } #pragma mark - Private Method //获取所有的子节点 - (void)fetchAllOfChildren:(PDFOutline *)aOutline containerArray:(NSMutableArray *)aMArray { if (![aMArray containsObject:aOutline]) { [aMArray addObject:aOutline]; } for (NSInteger i = 0; i < aOutline.numberOfChildren; i++) { [aMArray addObject:[aOutline childAtIndex:i]]; [self fetchAllOfChildren:[aOutline childAtIndex:i] containerArray:aMArray]; } } @end static NSString *kKMMergeCountKey = @"KMMergeCountKey"; static NSInteger kKMMergeCountMax = 2; @implementation KMPDFEditAppendWindow (KMExtension) - (BOOL)mergeCountIsReach { #if VERSION_DMG return NO; #else if ([KMLightMemberManager manager].isLogin) { return NO; } NSInteger cnt = [self getMergeCount]; if (cnt >= kKMMergeCountMax) { return YES; } return NO; #endif } - (void)recordMergeCount { NSInteger cnt = [self getMergeCount]; [[NSUserDefaults standardUserDefaults] setInteger:cnt+1 forKey:kKMMergeCountKey]; [[NSUserDefaults standardUserDefaults] synchronize]; } - (void)clearMergeCount { [[NSUserDefaults standardUserDefaults] setInteger:0 forKey:kKMMergeCountKey]; [[NSUserDefaults standardUserDefaults] synchronize]; } - (NSInteger)getMergeCount { return [[NSUserDefaults standardUserDefaults] integerForKey:kKMMergeCountKey]; } @end