1# 2# DNDArrayController.py 3# Bookmarks 4# 5# Converted by u.fiedler on 10.02.05. 6# 7# The original version was written in Objective-C by Malcolm Crawford 8# at http://homepage.mac.com/mmalc/CocoaExamples/controllers.html 9# 10# See "Dragging Files" for a conceptual introduction: 11# file:///Developer/ADC%20Reference%20Library/documentation/Cocoa/Conceptual/DragandDrop/index.html#//apple_ref/doc/uid/10000069i 12# or http://developer.apple.com/documentation/Cocoa/Conceptual/DragandDrop/Tasks/DraggingFiles.html 13 14 15from Foundation import * 16from AppKit import * 17from BookmarksDocument import CopiedRowsType 18 19MovedRowsType = u"MOVED_ROWS_TYPE" 20 21class DNDArrayController (NSArrayController): 22 # DNDArrayController is delegate and dataSource of tableView 23 tableView = objc.IBOutlet() 24 25 def awakeFromNib(self): 26 "register for drag and drop" 27 self.tableView.registerForDraggedTypes_( 28 [CopiedRowsType, MovedRowsType, NSURLPboardType]) 29 self.tableView.setAllowsMultipleSelection_(True) 30 31 32 def tableView_writeRows_toPasteboard_(self, tv, rows, pboard): 33 # declare our own pasteboard types 34 typesArray = [CopiedRowsType, MovedRowsType] 35 36 # If the number of rows is not 1, then we only support our own types. 37 # If there is just one row, then try to create an NSURL from the url 38 # value in that row. If that's possible, add NSURLPboardType to the 39 # list of supported types, and add the NSURL to the pasteboard. 40 if len(rows) != 1: 41 pboard.declareTypes_owner_(typesArray, self) 42 else: 43 # Try to create an URL 44 # If we can, add NSURLPboardType to the declared types and write 45 # the URL to the pasteboard; otherwise declare existing types 46 row = rows[0] 47 urlString = self.arrangedObjects()[row].valueForKey_(u'url') 48 url = None 49 if urlString: 50 url = NSURL.URLWithString_(urlString) 51 if urlString and url: 52 typesArray.append(NSURLPboardType) 53 pboard.declareTypes_owner_(typesArray, self) 54 url.writeToPasteboard_(pboard) 55 else: 56 pboard.declareTypes_owner_(typesArray, self) 57 58 # add rows array for local move 59 pboard.setPropertyList_forType_(rows, MovedRowsType) 60 61 # create new array of selected rows for remote drop 62 # could do deferred provision, but keep it direct for clarity 63 rowCopies = self.arrangedObjects()[:] 64 65 # setPropertyList works here because we're using dictionaries, strings, 66 # and dates; otherwise, archive collection to NSData... 67 pboard.setPropertyList_forType_(rowCopies, CopiedRowsType) 68 return True 69 70 def tableView_validateDrop_proposedRow_proposedDropOperation_(self, tv, info, row, op): 71 dragOp = NSDragOperationCopy 72 # if drag source is self, it's a move 73 if info.draggingSource() == self.tableView: 74 dragOp = NSDragOperationMove 75 # we want to put the object at, not over, 76 # the current row (contrast NSTableViewDropOn) 77 tv.setDropRow_dropOperation_(row, NSTableViewDropAbove) 78 return dragOp 79 80 def tableView_acceptDrop_row_dropOperation_(self, tv, info, row, op): 81 if row < 0: 82 row = 0 83 if info.draggingSource() == self.tableView: 84 rows = info.draggingPasteboard().propertyListForType_(MovedRowsType) 85 indexSet = self.indexSetFromRows_(rows) 86 self.moveObjectsInArrangedObjectsFromIndexes_toIndex_(indexSet, row) 87 # set selected rows to those that were just moved 88 # Need to work out what moved where to determine proper selection... 89 rowsAbove = self.rowsAboveRow_inIndexSet_(row, indexSet) 90 aRange = NSMakeRange(row - rowsAbove, indexSet.count()) 91 indexSet = NSIndexSet.indexSetWithIndexesInRange_(aRange) 92 # set selected rows to those that were just copied 93 self.setSelectionIndexes_(indexSet) 94 return True 95 96 # Can we get rows from another document? If so, add them, then return. 97 newRows = info.draggingPasteboard().propertyListForType_(CopiedRowsType) 98 if newRows: 99 aRange = NSMakeRange(row, newRows.count()) 100 indexSet = NSIndexSet.indexSetWithIndexesInRange_(aRange) 101 self.insertObjects_atArrangedObjectIndexes_(newRows, indexSet) 102 self.setSelectionIndexes_(indexSet) 103 return True 104 105 # Can we get an URL? If so, add a new row, configure it, then return. 106 url = NSURL.URLFromPasteboard_(info.draggingPasteboard()) 107 if url: 108 newObject = self.newObject() 109 self.insertObject_atArrangedObjectIndex_(newObject, row) 110 newObject.setValue_forKey_(url.absoluteString(), u"url") 111 newObject.setValue_forKey_(NSCalendarDate.date(), u"date") 112 # set selected rows to those that were just copied 113 self.setSelectionIndex_(row) 114 return True 115 return False 116 117 def moveObjectsInArrangedObjectsFromIndexes_toIndex_(self, indexSet, insertIndex): 118 objects = self.arrangedObjects() 119 index = indexSet.lastIndex() 120 aboveInsertIndexCount = 0 121 removeIndex = 0 122 123 while index != NSNotFound: 124 if index >= insertIndex: 125 removeIndex = index + aboveInsertIndexCount 126 aboveInsertIndexCount += 1 127 else: 128 removeIndex = index 129 insertIndex -= 1 130 obj = objects.objectAtIndex_(removeIndex) 131 self.removeObjectAtArrangedObjectIndex_(removeIndex) 132 self.insertObject_atArrangedObjectIndex_(obj, insertIndex) 133 index = indexSet.indexLessThanIndex_(index) 134 135 def indexSetFromRows_(self, rows): 136 indexSet = NSMutableIndexSet.indexSet() 137 for row in rows: 138 indexSet.addIndex_(row) 139 return indexSet 140 141 def rowsAboveRow_inIndexSet_(self, row, indexSet): 142 currentIndex = indexSet.firstIndex() 143 i = 0 144 while currentIndex != NSNotFound: 145 if currentIndex < row: 146 i += 1 147 currentIndex = indexSet.indexGreaterThanIndex_(currentIndex) 148 return i 149