SKInfoWindowController.m 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. //
  2. // SKInfoWindowController.m
  3. // Skim
  4. //
  5. // Created by Christiaan Hofman on 12/17/06.
  6. /*
  7. This software is Copyright (c) 2006-2018
  8. Christiaan Hofman. All rights reserved.
  9. Redistribution and use in source and binary forms, with or without
  10. modification, are permitted provided that the following conditions
  11. are met:
  12. - Redistributions of source code must retain the above copyright
  13. notice, this list of conditions and the following disclaimer.
  14. - Redistributions in binary form must reproduce the above copyright
  15. notice, this list of conditions and the following disclaimer in
  16. the documentation and/or other materials provided with the
  17. distribution.
  18. - Neither the name of Christiaan Hofman nor the names of any
  19. contributors may be used to endorse or promote products derived
  20. from this software without specific prior written permission.
  21. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  27. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. */
  33. #import "SKInfoWindowController.h"
  34. //#import "SKMainDocument.h"
  35. //#import "NSDocument_SKExtensions.h"
  36. #import "PDFPage_SKExtensions.h"
  37. #import <Quartz/Quartz.h>
  38. //#import "SKMainWindowController.h"
  39. #if VERSION_DMG
  40. #import <PDF_Master-Swift.h>
  41. #else
  42. #import <PDF_Master-Swift.h>
  43. #endif
  44. #define SKInfoWindowFrameAutosaveName @"SKInfoWindow"
  45. #define SKInfoVersionKey @"Version"
  46. #define SKInfoPageCountKey @"PageCount"
  47. #define SKInfoPageSizeKey @"PageSize"
  48. #define SKInfoPageWidthKey @"PageWidth"
  49. #define SKInfoPageHeightKey @"PageHeight"
  50. #define SKInfoKeywordsStringKey @"KeywordsString"
  51. #define SKInfoEncryptedKey @"Encrypted"
  52. #define SKInfoAllowsPrintingKey @"AllowsPrinting"
  53. #define SKInfoAllowsCopyingKey @"AllowsCopying"
  54. #define SKInfoAllowsDocumentAssemblyKey @"AllowsDocumentAssembly"
  55. #define SKInfoAllowsContentAccessibilityKey @"AllowsContentAccessibility"
  56. #define SKInfoAllowsCommentingKey @"AllowsCommenting"
  57. #define SKInfoAllowsFormFieldEntryKey @"AllowsFormFieldEntry"
  58. #define SKInfoFileNameKey @"FileName"
  59. #define SKInfoFileSizeKey @"FileSize"
  60. #define SKInfoPhysicalSizeKey @"PhysicalSize"
  61. #define SKInfoLogicalSizeKey @"LogicalSize"
  62. #define SKInfoTagsKey @"Tags"
  63. #define SKInfoRatingKey @"Rating"
  64. #define LABEL_COLUMN_ID @"label"
  65. #define VALUE_COLUMN_ID @"value"
  66. NSString * const kKMWindowDidBecomeMainNotificationName = @"KMWindowDidBecomeMainNotificationName";
  67. @interface SKInfoWindowController (SKPrivate) <NSTextFieldDelegate>
  68. - (void)handleViewFrameDidChangeNotification:(NSNotification *)notification;
  69. - (void)handleWindowDidBecomeMainNotification:(NSNotification *)notification;
  70. - (void)handleWindowDidResignMainNotification:(NSNotification *)notification;
  71. - (void)handlePDFDocumentInfoDidChangeNotification:(NSNotification *)notification;
  72. - (void)handleDocumentFileURLDidChangeNotification:(NSNotification *)notification;
  73. @end
  74. @interface SKInfoWindowController ()
  75. @property (nonatomic, weak) NSDocument *currentDocument;
  76. @end
  77. @implementation SKInfoWindowController
  78. @synthesize summaryTableView, attributesTableView, tabView, info, editDictionary;
  79. @dynamic keys;
  80. static SKInfoWindowController *sharedInstance = nil;
  81. + (id)sharedInstance {
  82. @synchronized (self) {
  83. if (sharedInstance == nil) {
  84. sharedInstance = [[super allocWithZone:NULL] init];
  85. }
  86. }
  87. return sharedInstance;
  88. }
  89. + (instancetype)allocWithZone:(struct _NSZone *)zone {
  90. return [self sharedInstance];
  91. }
  92. - (id)init {
  93. if (sharedInstance) NSLog(@"Attempt to allocate second instance of %@", [self class]);
  94. self = [super initWithWindowNibName:@"InfoWindow"];
  95. if (self){
  96. info = nil;
  97. if (@available(macOS 10.13, *)) {
  98. summaryKeys = [[NSArray alloc] initWithObjects:
  99. SKInfoFileNameKey,
  100. SKInfoFileSizeKey,
  101. SKInfoPageSizeKey,
  102. SKInfoPageCountKey,
  103. SKInfoVersionKey,
  104. @"",
  105. SKInfoEncryptedKey,
  106. SKInfoAllowsPrintingKey,
  107. SKInfoAllowsCopyingKey,
  108. SKInfoAllowsDocumentAssemblyKey,
  109. SKInfoAllowsContentAccessibilityKey,
  110. SKInfoAllowsCommentingKey,
  111. SKInfoAllowsFormFieldEntryKey,nil];
  112. } else {
  113. summaryKeys = [[NSArray alloc] initWithObjects:
  114. SKInfoFileNameKey,
  115. SKInfoFileSizeKey,
  116. SKInfoPageSizeKey,
  117. SKInfoPageCountKey,
  118. SKInfoVersionKey,
  119. @"",
  120. SKInfoEncryptedKey,
  121. SKInfoAllowsPrintingKey,
  122. SKInfoAllowsCopyingKey, nil];
  123. }
  124. attributesKeys = [[NSArray alloc] initWithObjects:
  125. PDFDocumentTitleAttribute,
  126. PDFDocumentAuthorAttribute,
  127. PDFDocumentSubjectAttribute,
  128. PDFDocumentCreatorAttribute,
  129. PDFDocumentProducerAttribute,
  130. PDFDocumentCreationDateAttribute,
  131. PDFDocumentModificationDateAttribute,
  132. SKInfoKeywordsStringKey, nil];
  133. labels = [[NSDictionary alloc] initWithObjectsAndKeys:
  134. NSLocalizedString(@"File name:", @"Info label"), SKInfoFileNameKey,
  135. NSLocalizedString(@"File size:", @"Info label"), SKInfoFileSizeKey,
  136. NSLocalizedString(@"Page size:", @"Info label"), SKInfoPageSizeKey,
  137. NSLocalizedString(@"Page count:", @"Info label"), SKInfoPageCountKey,
  138. NSLocalizedString(@"PDF Version:", @"Info label"), SKInfoVersionKey,
  139. NSLocalizedString(@"Encrypted:", @"Info label"), SKInfoEncryptedKey,
  140. NSLocalizedString(@"Printing:", @"Info label"), SKInfoAllowsPrintingKey,
  141. NSLocalizedString(@"Content Copying:", @"Info label"), SKInfoAllowsCopyingKey,
  142. NSLocalizedString(@"Document Assembly:", @"Info label"), SKInfoAllowsDocumentAssemblyKey,
  143. NSLocalizedString(@"Content Copying for Accessibility:", @"Info label"), SKInfoAllowsContentAccessibilityKey,
  144. NSLocalizedString(@"Commenting:", @"Info label"), SKInfoAllowsCommentingKey,
  145. NSLocalizedString(@"Filling of form fields:", @"Info label"), SKInfoAllowsFormFieldEntryKey,
  146. NSLocalizedString(@"Title:", @"Info label"), PDFDocumentTitleAttribute,
  147. NSLocalizedString(@"Author:", @"Info label"), PDFDocumentAuthorAttribute,
  148. NSLocalizedString(@"Subject:", @"Info label"), PDFDocumentSubjectAttribute,
  149. NSLocalizedString(@"Content Creator:", @"Info label"), PDFDocumentCreatorAttribute,
  150. NSLocalizedString(@"PDF Producer:", @"Info label"), PDFDocumentProducerAttribute,
  151. NSLocalizedString(@"Creation date:", @"Info label"), PDFDocumentCreationDateAttribute,
  152. NSLocalizedString(@"Modification date:", @"Info label"), PDFDocumentModificationDateAttribute,
  153. NSLocalizedString(@"Keywords:", @"Info label"), SKInfoKeywordsStringKey, nil];
  154. }
  155. return self;
  156. }
  157. - (void)dealloc {
  158. [[NSNotificationCenter defaultCenter] removeObserver:self];
  159. }
  160. - (void)updateForDocument:(NSDocument *)doc {
  161. self.currentDocument = doc;
  162. NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:[self infoForDocument:doc]];
  163. for (NSString *key in self.editDictionary.allKeys) {
  164. [dic setObject:self.editDictionary[key] forKey:key];
  165. }
  166. [self setInfo:dic];
  167. [summaryTableView reloadData];
  168. [attributesTableView reloadData];
  169. }
  170. - (void)windowDidLoad {
  171. [self updateForDocument:[[[NSApp mainWindow] windowController] document]];
  172. if (@available(macOS 10.13, *)) {
  173. } else {
  174. [self.window setFrame:CGRectMake(self.window.frame.origin.x, self.window.frame.origin.y, 460, 310) display:YES animate:YES];
  175. }
  176. [summaryTableView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone];
  177. [attributesTableView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone];
  178. self.editDictionary = [NSMutableDictionary dictionary];
  179. [self.tabView selectTabViewItemAtIndex:1];
  180. [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleViewFrameDidChangeNotification:)
  181. name: NSViewFrameDidChangeNotification object: [attributesTableView enclosingScrollView]];
  182. [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleWindowDidBecomeMainNotification:)
  183. name: NSWindowDidBecomeMainNotification object: nil];
  184. [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleWindowDidResignMainNotification:)
  185. name: NSWindowDidResignMainNotification object: nil];
  186. [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePDFDocumentInfoDidChangeNotification:)
  187. name: PDFDocumentDidUnlockNotification object: nil];
  188. // [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePDFDocumentInfoDidChangeNotification:)
  189. // name: SKPDFPageBoundsDidChangeNotification object: nil];
  190. // [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleDocumentFileURLDidChangeNotification:)
  191. // name: SKDocumentFileURLDidChangeNotification object: nil];
  192. [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleWindowWillCloseNotification:)
  193. name: NSWindowWillCloseNotification object: nil];
  194. [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(km_handleWindowDidBecomeMainNotification:)
  195. name: kKMWindowDidBecomeMainNotificationName object: nil];
  196. }
  197. - (void)showWindow:(id)sender {
  198. [super showWindow:nil];
  199. [self.editDictionary removeAllObjects];
  200. [self.attributesTableView reloadData];
  201. }
  202. #define BYTE_FACTOR 1024
  203. #define BYTE_FACTOR_F 1024.0f
  204. #define BYTE_SHIFT 10
  205. static NSString *SKFileSizeStringForFileURL(NSURL *fileURL, unsigned long long *physicalSizePtr, unsigned long long *logicalSizePtr) {
  206. if (fileURL == nil)
  207. return @"";
  208. FSRef fileRef;
  209. FSCatalogInfo catalogInfo;
  210. unsigned long long size, logicalSize = 0;
  211. BOOL gotSize = NO, isDir = NO;
  212. NSMutableString *string = [NSMutableString string];
  213. Boolean gotRef = CFURLGetFSRef((CFURLRef)fileURL, &fileRef);
  214. if (gotRef && noErr == FSGetCatalogInfo(&fileRef, kFSCatInfoDataSizes | kFSCatInfoRsrcSizes | kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL, NULL)) {
  215. size = catalogInfo.dataPhysicalSize + catalogInfo.rsrcPhysicalSize;
  216. logicalSize = catalogInfo.dataLogicalSize + catalogInfo.rsrcLogicalSize;
  217. isDir = (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0;
  218. gotSize = YES;
  219. }
  220. if (gotSize == NO) {
  221. // this seems to give the logical size
  222. NSDictionary *fileAttrs = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:NULL];
  223. logicalSize = size = [[fileAttrs objectForKey:NSFileSize] unsignedLongLongValue];
  224. isDir = [[fileAttrs fileType] isEqualToString:NSFileTypeDirectory];
  225. }
  226. if (isDir) {
  227. NSString *path = [fileURL path];
  228. unsigned long long componentSize;
  229. unsigned long long logicalComponentSize;
  230. for (NSString *file in [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:path error:NULL]) {
  231. SKFileSizeStringForFileURL([NSURL fileURLWithPath:[path stringByAppendingPathComponent:file]], &componentSize, &logicalComponentSize);
  232. size += componentSize;
  233. logicalSize += logicalComponentSize;
  234. }
  235. }
  236. if (physicalSizePtr)
  237. *physicalSizePtr = size;
  238. if (logicalSizePtr)
  239. *logicalSizePtr = logicalSize;
  240. if (size < BYTE_FACTOR) {
  241. [string appendFormat:@"%qu %@", size, NSLocalizedString(@"bytes", @"size unit")];
  242. } else {
  243. #define numUnits 6
  244. NSString *units[numUnits] = {NSLocalizedString(@"kB", @"size unit"), NSLocalizedString(@"MB", @"size unit"), NSLocalizedString(@"GB", @"size unit"), NSLocalizedString(@"TB", @"size unit"), NSLocalizedString(@"PB", @"size unit"), NSLocalizedString(@"EB", @"size unit")};
  245. NSUInteger i;
  246. for (i = 0; i < numUnits; i++, size >>= BYTE_SHIFT) {
  247. if ((size >> BYTE_SHIFT) < BYTE_FACTOR || i == numUnits - 1) {
  248. [string appendFormat:@"%.1f %@", size / BYTE_FACTOR_F, units[i]];
  249. break;
  250. }
  251. }
  252. }
  253. NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
  254. [formatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
  255. [formatter setNumberStyle:NSNumberFormatterDecimalStyle];
  256. [string appendFormat:@" (%@ %@)", [formatter stringFromNumber:[NSNumber numberWithUnsignedLongLong:logicalSize]], NSLocalizedString(@"bytes", @"size unit")];
  257. return string;
  258. }
  259. #define CM_PER_POINT 0.035277778
  260. #define INCH_PER_POINT 0.013888889
  261. static inline
  262. NSString *SKSizeString(NSSize size, NSSize altSize) {
  263. BOOL useMetric = [[[NSLocale currentLocale] objectForKey:NSLocaleUsesMetricSystem] boolValue];
  264. NSString *units = useMetric ? NSLocalizedString(@"cm", @"size unit") : NSLocalizedString(@"in", @"size unit");
  265. CGFloat factor = useMetric ? CM_PER_POINT : INCH_PER_POINT;
  266. if (NSEqualSizes(size, altSize))
  267. return [NSString stringWithFormat:@"%.2f x %.2f %@", size.width * factor, size.height * factor, units];
  268. else
  269. return [NSString stringWithFormat:@"%.2f x %.2f %@ (%.2f x %.2f %@)", size.width * factor, size.height * factor, units, altSize.width * factor, altSize.height * factor, units];
  270. }
  271. - (NSDictionary *)infoForDocument:(NSDocument *)doc {
  272. NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
  273. unsigned long long logicalSize = 0, physicalSize = 0;
  274. if ([doc isKindOfClass:KMMainDocument.class]) {
  275. CPDFDocument *pdfDoc = ((KMMainDocument *)doc).mainViewController.document;
  276. if (pdfDoc != nil) {
  277. [dictionary addEntriesFromDictionary:[pdfDoc documentAttributes]];
  278. [dictionary setValue:[NSString stringWithFormat: @"%ld.%ld", (long)[pdfDoc majorVersion], (long)[pdfDoc minorVersion]] forKey:SKInfoVersionKey];
  279. [dictionary setValue:[NSNumber numberWithInteger:[pdfDoc pageCount]] forKey:SKInfoPageCountKey];
  280. if ([pdfDoc pageCount]) {
  281. NSSize cropSize = [[pdfDoc pageAtIndex:0] boundsForBox:CPDFDisplayCropBox].size;
  282. NSSize mediaSize = [[pdfDoc pageAtIndex:0] boundsForBox:CPDFDisplayMediaBox].size;
  283. [dictionary setValue:SKSizeString(cropSize, mediaSize) forKey:SKInfoPageSizeKey];
  284. [dictionary setValue:[NSNumber numberWithDouble:cropSize.width] forKey:SKInfoPageWidthKey];
  285. [dictionary setValue:[NSNumber numberWithDouble:cropSize.height] forKey:SKInfoPageHeightKey];
  286. }
  287. NSArray *keyworks = [dictionary valueForKey:CPDFDocumentKeywordsAttribute];
  288. if ([keyworks isKindOfClass:[NSArray class]]) {
  289. [dictionary setValue:[[dictionary valueForKey:CPDFDocumentKeywordsAttribute] componentsJoinedByString:@"\n"] forKey:SKInfoKeywordsStringKey];
  290. }
  291. [dictionary setValue:[NSNumber numberWithBool:[pdfDoc isEncrypted]] forKey:SKInfoEncryptedKey];
  292. [dictionary setValue:[NSNumber numberWithBool:[pdfDoc allowsPrinting]] forKey:SKInfoAllowsPrintingKey];
  293. [dictionary setValue:[NSNumber numberWithBool:[pdfDoc allowsCopying]] forKey:SKInfoAllowsCopyingKey];
  294. if (@available(macOS 10.13, *)) {
  295. // [dictionary setValue:[NSNumber numberWithBool:[pdfDoc allowsContentAccessibility]] forKey:SKInfoAllowsContentAccessibilityKey];
  296. [dictionary setValue:[NSNumber numberWithBool:[pdfDoc allowsCommenting]] forKey:SKInfoAllowsCommentingKey];
  297. [dictionary setValue:[NSNumber numberWithBool:[pdfDoc allowsDocumentAssembly]] forKey:SKInfoAllowsDocumentAssemblyKey];
  298. [dictionary setValue:[NSNumber numberWithBool:[pdfDoc allowsFormFieldEntry]] forKey:SKInfoAllowsFormFieldEntryKey];
  299. }
  300. }
  301. }
  302. [dictionary setValue:[[[doc fileURL] path] lastPathComponent] forKey:SKInfoFileNameKey];
  303. [dictionary setValue:SKFileSizeStringForFileURL([doc fileURL], &physicalSize, &logicalSize) forKey:SKInfoFileSizeKey];
  304. [dictionary setValue:[NSNumber numberWithUnsignedLongLong:physicalSize] forKey:SKInfoPhysicalSizeKey];
  305. [dictionary setValue:[NSNumber numberWithUnsignedLongLong:logicalSize] forKey:SKInfoLogicalSizeKey];
  306. // if ([doc respondsToSelector:@selector(tags)])
  307. // [dictionary setValue:[(KMMainDocument *)doc tags] ?: [NSArray array] forKey:SKInfoTagsKey];
  308. // if ([doc respondsToSelector:@selector(rating)])
  309. // [dictionary setValue:[NSNumber numberWithDouble:[(KMMainDocument *)doc rating]] forKey:SKInfoRatingKey];
  310. return dictionary;
  311. }
  312. - (NSArray *)keys {
  313. return [attributesKeys arrayByAddingObjectsFromArray:summaryKeys];
  314. }
  315. - (void)handleWindowWillCloseNotification:(NSNotification *)notification {
  316. id object = [notification object];
  317. if ([object isEqual:self.window]) {
  318. if (self.editDictionary.count > 0) {
  319. NSWindowController *windowController = [[NSApp mainWindow] windowController];
  320. if ([windowController isKindOfClass:[KMBrowserWindowController class]]) {
  321. KMMainDocument *document = (KMMainDocument *)[(KMBrowserWindowController *)windowController document];
  322. NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:[document.mainViewController.document documentAttributes]];
  323. BOOL isSave = NO;
  324. for (NSString *key in self.editDictionary) {
  325. if ([key isEqualToString:SKInfoKeywordsStringKey]) {
  326. NSString *string = self.editDictionary[key];
  327. // NSArray *array = [string componentsSeparatedByString:@"\n"];
  328. // if (array && ![dic[PDFDocumentKeywordsAttribute] isEqual:array]) {
  329. // isSave = YES;
  330. // [dic setObject:array forKey:PDFDocumentKeywordsAttribute];
  331. // }
  332. if (string && string.length > 0 && ![string isEqualToString:dic[PDFDocumentKeywordsAttribute]]) {
  333. isSave = YES;
  334. [dic setObject:string forKey:CPDFDocumentKeywordsAttribute];
  335. }
  336. } else {
  337. if (![dic[key] isEqualToString:self.editDictionary[key]]) {
  338. isSave = YES;
  339. [dic setObject:self.editDictionary[key] forKey:key];
  340. }
  341. }
  342. }
  343. if (isSave) {
  344. [document.mainViewController.document setDocumentAttributes:dic];
  345. [document saveDocument:nil];
  346. }
  347. }
  348. }
  349. [self.editDictionary removeAllObjects];
  350. }
  351. }
  352. - (void)handleViewFrameDidChangeNotification:(NSNotification *)notification {
  353. [attributesTableView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndex:[attributesKeys count] - 1]];
  354. }
  355. - (void)handleWindowDidBecomeMainNotification:(NSNotification *)notification {
  356. [self.editDictionary removeAllObjects];
  357. [self updateForDocument:[[[notification object] windowController] document]];
  358. }
  359. - (void)km_handleWindowDidBecomeMainNotification:(NSNotification *)notification {
  360. [self.editDictionary removeAllObjects];
  361. [self updateForDocument:notification.object];
  362. }
  363. - (void)handleWindowDidResignMainNotification:(NSNotification *)notification {
  364. [self.editDictionary removeAllObjects];
  365. [self updateForDocument:nil];
  366. }
  367. - (void)handlePDFDocumentInfoDidChangeNotification:(NSNotification *)notification {
  368. [self.editDictionary removeAllObjects];
  369. NSDocument *doc = [[[NSApp mainWindow] windowController] document];
  370. if ([doc isKindOfClass:[KMMainDocument class]]) {
  371. CPDFDocument *pdfDocument = ((KMMainDocument *)doc).mainViewController.document;
  372. if ([pdfDocument isEqual:notification.object]) {
  373. [self updateForDocument:doc];
  374. }
  375. }
  376. }
  377. - (void)handleDocumentFileURLDidChangeNotification:(NSNotification *)notification {
  378. [self.editDictionary removeAllObjects];
  379. NSDocument *doc = [[[NSApp mainWindow] windowController] document];
  380. if ([doc isEqual:[notification object]])
  381. [self updateForDocument:doc];
  382. }
  383. - (NSInteger)numberOfRowsInTableView:(NSTableView *)tv {
  384. NSArray *keys = nil;
  385. if ([tv isEqual:summaryTableView])
  386. keys = summaryKeys;
  387. else if ([tv isEqual:attributesTableView])
  388. keys = attributesKeys;
  389. return [keys count];
  390. }
  391. - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
  392. static NSDateFormatter *shortDateFormatter = nil;
  393. if(shortDateFormatter == nil) {
  394. shortDateFormatter = [[NSDateFormatter alloc] init];
  395. [shortDateFormatter setDateStyle:NSDateFormatterShortStyle];
  396. [shortDateFormatter setTimeStyle:NSDateFormatterNoStyle];
  397. }
  398. NSArray *keys = nil;
  399. if ([tableView isEqual:summaryTableView]) {
  400. keys = summaryKeys;
  401. } else if ([tableView isEqual:attributesTableView]) {
  402. keys = attributesKeys;
  403. }
  404. NSString *key = [keys objectAtIndex:row];
  405. NSString *tcID = [tableColumn identifier];
  406. id value = nil;
  407. if ([key length]) {
  408. if ([tcID isEqualToString:LABEL_COLUMN_ID]) {
  409. value = [labels objectForKey:key] ?: [key stringByAppendingString:@":"];
  410. } else if ([tcID isEqualToString:VALUE_COLUMN_ID]) {
  411. value = [info objectForKey:key];
  412. if (value == nil)
  413. value = @"-";
  414. else if ([value isKindOfClass:[NSDate class]])
  415. value = [shortDateFormatter stringFromDate:value];
  416. else if ([value isKindOfClass:[NSNumber class]]){
  417. if ([key isEqualToString:SKInfoEncryptedKey]) {
  418. value = [value boolValue] ? NSLocalizedString(@"Yes", @"") : NSLocalizedString(@"No", @"");
  419. } else {
  420. value = ([key isEqualToString:SKInfoPageCountKey] ? [value stringValue] : ([value boolValue] ? NSLocalizedString(@"Allowed", @"") : NSLocalizedString(@"Not Allowed", @"")));
  421. }
  422. }
  423. }
  424. } else {
  425. value = @"";
  426. }
  427. NSTableCellView *cellView = [tableView makeViewWithIdentifier:tcID owner:self];
  428. cellView.textField.stringValue = value;
  429. if ([tableView isEqual:attributesTableView] && [[tableColumn identifier] isEqualToString:VALUE_COLUMN_ID]) {
  430. if (row == 0 || row == 1 || row == 2 || row == 3 || row == 7) {
  431. cellView.textField.bezelStyle = NSTextFieldSquareBezel;
  432. cellView.textField.editable = YES;
  433. cellView.textField.selectable = YES;
  434. cellView.textField.bordered = YES;
  435. cellView.textField.bezeled = YES;
  436. cellView.textField.drawsBackground = YES;
  437. cellView.textField.delegate = self;
  438. if (row == 1) {
  439. NSTableCellView *cell = [tableView viewAtColumn:1 row:0 makeIfNecessary:YES];
  440. cell.textField.nextKeyView = cellView.textField;
  441. } else if (row == 2) {
  442. NSTableCellView *cell = [tableView viewAtColumn:1 row:1 makeIfNecessary:NO];
  443. cell.textField.nextKeyView = cellView.textField;
  444. } else if (row == 3) {
  445. NSTableCellView *cell = [tableView viewAtColumn:1 row:2 makeIfNecessary:NO];
  446. cell.textField.nextKeyView = cellView.textField;
  447. } else if (row == 7) {
  448. NSTableCellView *cell = [tableView viewAtColumn:1 row:3 makeIfNecessary:NO];
  449. cell.textField.nextKeyView = cellView.textField;
  450. }
  451. } else {
  452. cellView.textField.editable = NO;
  453. cellView.textField.selectable = NO;
  454. cellView.textField.bordered = NO;
  455. cellView.textField.bezeled = NO;
  456. cellView.textField.drawsBackground = NO;
  457. cellView.textField.delegate = nil;
  458. }
  459. cellView.textField.tag = row;
  460. }
  461. return cellView;
  462. }
  463. - (id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
  464. static NSDateFormatter *shortDateFormatter = nil;
  465. if(shortDateFormatter == nil) {
  466. shortDateFormatter = [[NSDateFormatter alloc] init];
  467. [shortDateFormatter setDateStyle:NSDateFormatterShortStyle];
  468. [shortDateFormatter setTimeStyle:NSDateFormatterNoStyle];
  469. }
  470. NSArray *keys = nil;
  471. if ([tv isEqual:summaryTableView])
  472. keys = summaryKeys;
  473. else if ([tv isEqual:attributesTableView])
  474. keys = attributesKeys;
  475. NSString *key = [keys objectAtIndex:row];
  476. NSString *tcID = [tableColumn identifier];
  477. id value = nil;
  478. if ([key length]) {
  479. if ([tcID isEqualToString:LABEL_COLUMN_ID]) {
  480. value = [labels objectForKey:key] ?: [key stringByAppendingString:@":"];
  481. } else if ([tcID isEqualToString:VALUE_COLUMN_ID]) {
  482. value = [info objectForKey:key];
  483. if (value == nil)
  484. value = @"-";
  485. else if ([value isKindOfClass:[NSDate class]])
  486. value = [shortDateFormatter stringFromDate:value];
  487. else if ([value isKindOfClass:[NSNumber class]]){
  488. if ([key isEqualToString:SKInfoEncryptedKey]) {
  489. value = [value boolValue] ? NSLocalizedString(@"Yes", @"") : NSLocalizedString(@"No", @"");
  490. } else {
  491. value = ([key isEqualToString:SKInfoPageCountKey] ? [value stringValue] : ([value boolValue] ? NSLocalizedString(@"Allowed", @"") : NSLocalizedString(@"Not Allowed", @"")));
  492. }
  493. }
  494. }
  495. }
  496. return value;
  497. }
  498. - (void)tableView:(NSTableView *)tv willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
  499. if ([tv isEqual:attributesTableView] && [[tableColumn identifier] isEqualToString:LABEL_COLUMN_ID])
  500. [cell setLineBreakMode:row == [tv numberOfRows] - 1 ? NSLineBreakByWordWrapping : NSLineBreakByTruncatingTail];
  501. }
  502. - (CGFloat)tableView:(NSTableView *)tv heightOfRow:(NSInteger)row {
  503. CGFloat rowHeight = [tv rowHeight];
  504. if ([tv isEqual:attributesTableView] && row == [tv numberOfRows] - 1)
  505. rowHeight = fmax(rowHeight, NSHeight([[tv enclosingScrollView] bounds]) - [tv numberOfRows] * (rowHeight + [tv intercellSpacing].height) + rowHeight);
  506. return rowHeight;
  507. }
  508. - (BOOL)tableView:(NSTableView *)tv shouldSelectRow:(NSInteger)row {
  509. return YES;
  510. }
  511. - (void)tabView:(NSTabView *)tabView willSelectTabViewItem:(nullable NSTabViewItem *)tabViewItem
  512. {
  513. if ([tabView indexOfTabViewItem:tabViewItem] == 1) {
  514. if (self.currentDocument) {
  515. NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:[self infoForDocument:self.currentDocument]];
  516. for (NSString *key in self.editDictionary.allKeys) {
  517. [dic setObject:self.editDictionary[key] forKey:key];
  518. }
  519. [self setInfo:dic];
  520. }
  521. [self.attributesTableView reloadData];
  522. } else {
  523. [self.summaryTableView reloadData];
  524. }
  525. }
  526. #pragma mark - NSTextFieldDelegate
  527. - (void)controlTextDidChange:(NSNotification *)obj {
  528. NSTextField *textField = (NSTextField*)[obj object];
  529. if (textField.tag == 0) {
  530. [self.editDictionary setObject:textField.stringValue forKey:PDFDocumentTitleAttribute];
  531. } else if (textField.tag == 1) {
  532. [self.editDictionary setObject:textField.stringValue forKey:PDFDocumentAuthorAttribute];
  533. } else if (textField.tag == 2) {
  534. [self.editDictionary setObject:textField.stringValue forKey:PDFDocumentSubjectAttribute];
  535. } else if (textField.tag == 3) {
  536. [self.editDictionary setObject:textField.stringValue forKey:PDFDocumentCreatorAttribute];
  537. } else if (textField.tag == 7) {
  538. [self.editDictionary setObject:textField.stringValue forKey:SKInfoKeywordsStringKey];
  539. }
  540. }
  541. @end