1from AppKit import * 2from Quartz import * 3import objc 4 5from PyObjCTools import NibClassBuilder 6 7class MyPDFDocument (NibClassBuilder.AutoBaseClass): 8 _outline = objc.ivar() 9 _searchResults = objc.ivar() 10 11 12 def dealloc(self): 13 NSNotificationCenter.defaultCenter().removeObserver_(self) 14 self._searchResults = None 15 super(MyPDFDocument, self).dealloc() 16 17 def windowNibName(self): 18 return "MyDocument" 19 20 def windowControllerDidLoadNib_(self, controller): 21 super(MyPDFDocument, self).windowControllerDidLoadNib_(controller) 22 23 if self.fileName(): 24 pdfDoc = PDFDocument.alloc().initWithURL_( 25 NSURL.fileURLWithPath_(self.fileName())) 26 self._pdfView.setDocument_(pdfDoc) 27 28 # Page changed notification. 29 NSNotificationCenter.defaultCenter().addObserver_selector_name_object_( 30 self, "pageChanged:", PDFViewPageChangedNotification, self._pdfView) 31 32 # Find notifications. 33 center = NSNotificationCenter.defaultCenter() 34 center.addObserver_selector_name_object_( 35 self, 'startFind:', PDFDocumentDidBeginFindNotification, 36 self._pdfView.document()) 37 center.addObserver_selector_name_object_( 38 self, 'findProgress:', PDFDocumentDidEndPageFindNotification, 39 self._pdfView.document()) 40 center.addObserver_selector_name_object_( 41 self, 'endFind:', PDFDocumentDidEndFindNotification, 42 self._pdfView.document()) 43 44 # Set self to be delegate (find). 45 self._pdfView.document().setDelegate_(self) 46 47 # Get outline. 48 self._outline = self._pdfView.document().outlineRoot() 49 if self._outline is not None: 50 # Remove text that says, "No outline." 51 self._noOutlineText.removeFromSuperview() 52 self._noOutlineText = None 53 54 # Force it to load up. 55 self._outlineView.reloadData() 56 57 else: 58 # Remove outline view (leaving instead text that says, 59 # "No outline."). 60 self._outlineView.enclosingScrollView().removeFromSuperview() 61 self._outlineView = None 62 63 # Open drawer. 64 self._drawer.open() 65 66 # Size the window. 67 windowSize = self._pdfView.rowSizeForPage_( 68 self._pdfView.currentPage()) 69 70 if (self._pdfView.displayMode() & 0x01) and ( 71 self._pdfView.document().pageCount() > 1): 72 windowSize.width += NSScroller.scrollerWidth() 73 controller.window().setContentSize_(windowSize) 74 75 def dataRepresentationOfType_(self, aType): 76 return None 77 78 def loadDataRepresentation_ofType_(self, data, aType): 79 return True 80 81 @objc.IBAction 82 def toggleDrawer_(self, sender): 83 self._drawer.toggle_(self) 84 85 @objc.IBAction 86 def takeDestinationFromOutline_(self, sender): 87 # Get the destination associated with the search result list. 88 # Tell the PDFView to go there. 89 self._pdfView.goToDestination_( 90 sender.itemAtRow_(sender.selectedRow()).destination()) 91 92 @objc.IBAction 93 def displaySinglePage_(self, sender): 94 # Display single page mode. 95 if self._pdfView.displayMode() > kPDFDisplaySinglePageContinuous: 96 self._pdfView.setDisplayMode_(self._pdfView.displayMode() - 2) 97 98 @objc.IBAction 99 def displayTwoUp_(self, sender): 100 # Display two-up. 101 if self._pdfView.displayMode() < kPDFDisplayTwoUp: 102 self._pdfView.setDisplayMode_(self._pdfView.displayMode() + 2) 103 104 def pageChanged_(self, notification): 105 # Skip out if there is no outline. 106 if selfl_pdfView.document().outlineRoot() is None: 107 return 108 109 # What is the new page number (zero-based). 110 newPageIndex = self._pdfView.document().indexForPage_( 111 self._pdfView.currentPage()) 112 113 # Walk outline view looking for best firstpage number match. 114 newlySelectedRow = -1; 115 numRows = self._outlineView.numberOfRows() 116 for i in range(numRows): 117 outlineItem = self._outlineView.itemAtRow_(i) 118 119 if self._pdfView.document().indexForPage_( 120 outlineItem.destination().page()) == newPageIndex: 121 122 newlySelectedRow = i 123 self._outlineView.selectRow_byExtendingSelection_( 124 newlySelectedRow, False) 125 break 126 127 elif self._pdfView.document().indexForPage_(outlineItem.destionation().page()) > newPageIndex: 128 newlySelectedRow = i - 1 129 self._outlineView.selectRow_byExtendingSelection_( 130 newlySelectedRow, False) 131 break 132 133 # Auto-scroll. 134 if newlySelectedRow != -1: 135 self._outlineView.scrollRowToVisible_(newlySelectedRow) 136 137 138 def doFind_(self, sender): 139 if self._pdfView.document().isFinding(): 140 self._pdfView.document().cancelFindString() 141 142 143 # Lazily allocate _searchResults. 144 if self._searchResults is None: 145 self._searchResults = NSMutableArray.arrayWithCapacity_(10) 146 147 self._pdfView.document().beginFindString_withOptions_( 148 sender.stringValue(), NSCaseInsensitiveSearch) 149 150 def startFind_(self, notification): 151 # Empty arrays. 152 self._searchResults.removeAllObjects() 153 self._searchTable.reloadData() 154 self._searchProgress.startAnimation_(self) 155 156 def findProgress_(self, notification): 157 pageIndex = notification.userInfo().objectForKey_( 158 "PDFDocumentPageIndex") #.doubleValue() 159 self._searchProgress.setDoubleValue_( 160 pageIndex / self._pdfView.document().pageCount()) 161 162 def didMatchString_(self, instance): 163 # Add page label to our array. 164 self._searchResults.addObject_(instance.copy()) 165 self._searchTable.reloadData() 166 167 def endFind_(self, notification): 168 self._searchProgress.stopAnimation_(self) 169 self._searchProgress.setDoubleValue_(0) 170 171 # The table view is used to hold search results. Column 1 lists the 172 # page number for the search result, column two the section in the PDF 173 # (x-ref with the PDF outline) where the result appears. 174 175 def numberOfRowsInTableView_(self, aTableView): 176 if self._searchResults is None: 177 return 0 178 return self._searchResults.count() 179 180 def tableView_objectValueForTableColumn_row_( 181 self, aTableView, theColumn, rowIndex): 182 183 if theColumn.identifier() == "page": 184 return self._searchResults.objectAtIndex_(rowIndex).pages().objectAtIndex_(0).label() 185 186 elif theColumn.identifier() == 'section': 187 value = self._pdfView.document().outlineItemForSelection_( 188 self._searchResults.objectAtIndex_(rowIndex)) 189 190 if value is None: 191 return None 192 193 return value.label() 194 195 else: 196 return None 197 198 def tableViewSelectionDidChange_(self, notification): 199 # What was selected. Skip out if the row has not changed. 200 rowIndex = notification.object().selectedRow() 201 if rowIndex >= 0: 202 self._pdfView.setCurrentSelection_( 203 self._searchResults.objectAtIndex_(rowIndex)) 204 self._pdfView.centerSelectionInVisibleArea_(self) 205 206 207 # The outline view is for the PDF outline. Not all PDF's have an outline. 208 def outlineView_numberOfChildrenOfItem_(self, outlineView, item): 209 if item is None: 210 if self._outline is not None: 211 return self._outline.numberOfChildren() 212 else: 213 return 0 214 215 else: 216 return item.numberOfChildren() 217 218 def outlineView_child_ofItem_(self, outlineView, index, item): 219 if item is None: 220 if self._outline is not None: 221 return self._outline.childAtIndex_(index).retain() 222 else: 223 return None 224 225 else: 226 return item.childAtIndex_(index).retain() 227 228 def outlineView_isItemExpandable_(self, outlineView, item): 229 if item is None: 230 if self._outline: 231 return self._outline.numberOfChildren() > 0 232 233 else: 234 return False 235 236 else: 237 return item.numberOfChildren() > 0 238 239 def outlineView_objectValueForTableColumn_byItem_( 240 self, outlineView, tableColumn, item): 241 return item.label() 242