1 package ch
.cyberduck
.ui
.cocoa
;
4 * Copyright (c) 2005 David Kocher. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * Bug fixes, suggestions and comments should be sent to:
18 * dkocher@cyberduck.ch
21 import ch
.cyberduck
.binding
.ProxyController
;
22 import ch
.cyberduck
.binding
.application
.NSApplication
;
23 import ch
.cyberduck
.binding
.application
.NSDraggingInfo
;
24 import ch
.cyberduck
.binding
.application
.NSDraggingSource
;
25 import ch
.cyberduck
.binding
.application
.NSEvent
;
26 import ch
.cyberduck
.binding
.application
.NSImage
;
27 import ch
.cyberduck
.binding
.application
.NSPasteboard
;
28 import ch
.cyberduck
.binding
.application
.NSTableView
;
29 import ch
.cyberduck
.binding
.foundation
.NSArray
;
30 import ch
.cyberduck
.binding
.foundation
.NSAttributedString
;
31 import ch
.cyberduck
.binding
.foundation
.NSFileManager
;
32 import ch
.cyberduck
.binding
.foundation
.NSMutableArray
;
33 import ch
.cyberduck
.binding
.foundation
.NSObject
;
34 import ch
.cyberduck
.binding
.foundation
.NSString
;
35 import ch
.cyberduck
.binding
.foundation
.NSURL
;
36 import ch
.cyberduck
.core
.Acl
;
37 import ch
.cyberduck
.core
.AttributedList
;
38 import ch
.cyberduck
.core
.Cache
;
39 import ch
.cyberduck
.core
.HostParser
;
40 import ch
.cyberduck
.core
.Local
;
41 import ch
.cyberduck
.core
.LocalFactory
;
42 import ch
.cyberduck
.core
.LocaleFactory
;
43 import ch
.cyberduck
.core
.Path
;
44 import ch
.cyberduck
.core
.Permission
;
45 import ch
.cyberduck
.core
.ProtocolFactory
;
46 import ch
.cyberduck
.core
.UserDateFormatterFactory
;
47 import ch
.cyberduck
.core
.date
.AbstractUserDateFormatter
;
48 import ch
.cyberduck
.core
.exception
.AccessDeniedException
;
49 import ch
.cyberduck
.core
.features
.Touch
;
50 import ch
.cyberduck
.core
.formatter
.SizeFormatter
;
51 import ch
.cyberduck
.core
.formatter
.SizeFormatterFactory
;
52 import ch
.cyberduck
.core
.local
.FileDescriptor
;
53 import ch
.cyberduck
.core
.local
.FileDescriptorFactory
;
54 import ch
.cyberduck
.core
.local
.IconServiceFactory
;
55 import ch
.cyberduck
.core
.local
.LocalTouchFactory
;
56 import ch
.cyberduck
.core
.pasteboard
.PathPasteboard
;
57 import ch
.cyberduck
.core
.pasteboard
.PathPasteboardFactory
;
58 import ch
.cyberduck
.core
.preferences
.Preferences
;
59 import ch
.cyberduck
.core
.preferences
.PreferencesFactory
;
60 import ch
.cyberduck
.core
.resources
.IconCache
;
61 import ch
.cyberduck
.core
.resources
.IconCacheFactory
;
62 import ch
.cyberduck
.core
.transfer
.CopyTransfer
;
63 import ch
.cyberduck
.core
.transfer
.DownloadTransfer
;
64 import ch
.cyberduck
.core
.transfer
.TransferItem
;
65 import ch
.cyberduck
.core
.transfer
.TransferStatus
;
66 import ch
.cyberduck
.core
.transfer
.UploadTransfer
;
67 import ch
.cyberduck
.ui
.browser
.Column
;
69 import org
.apache
.commons
.collections
.map
.LRUMap
;
70 import org
.apache
.commons
.lang3
.StringUtils
;
71 import org
.apache
.log4j
.Logger
;
72 import org
.rococoa
.Rococoa
;
73 import org
.rococoa
.cocoa
.foundation
.NSInteger
;
74 import org
.rococoa
.cocoa
.foundation
.NSPoint
;
75 import org
.rococoa
.cocoa
.foundation
.NSRect
;
76 import org
.rococoa
.cocoa
.foundation
.NSSize
;
77 import org
.rococoa
.cocoa
.foundation
.NSUInteger
;
79 import java
.util
.ArrayList
;
80 import java
.util
.Collections
;
81 import java
.util
.EnumSet
;
82 import java
.util
.HashMap
;
83 import java
.util
.List
;
90 public abstract class BrowserTableDataSource
extends ProxyController
implements NSDraggingSource
{
91 private static final Logger log
= Logger
.getLogger(BrowserTableDataSource
.class);
93 private SizeFormatter sizeFormatter
= SizeFormatterFactory
.get();
95 private AbstractUserDateFormatter dateFormatter
= UserDateFormatterFactory
.get();
97 private IconCache
<NSImage
> icons
= IconCacheFactory
.<NSImage
>get();
99 private FileDescriptor descriptor
= FileDescriptorFactory
.get();
101 private final Preferences preferences
= PreferencesFactory
.get();
103 private final Map
<Item
, NSAttributedString
> attributed
= new LRUMap(
104 preferences
.getInteger("browser.model.cache.size")
107 protected BrowserController controller
;
109 protected Cache
<Path
> cache
;
111 private static final class Item
{
113 private String column
;
115 public Item(final Path file
, final String column
) {
117 this.column
= column
;
121 public boolean equals(final Object o
) {
125 if(o
== null || getClass() != o
.getClass()) {
128 final Item item
= (Item
) o
;
129 if(column
!= null ?
!column
.equals(item
.column
) : item
.column
!= null) {
132 if(file
!= null ?
!file
.equals(item
.file
) : item
.file
!= null) {
139 public int hashCode() {
140 int result
= file
!= null ? file
.hashCode() : 0;
141 result
= 31 * result
+ (column
!= null ? column
.hashCode() : 0);
146 public String
toString() {
147 final StringBuilder sb
= new StringBuilder("Item{");
148 sb
.append("file=").append(file
);
149 sb
.append(", column='").append(column
).append('\'');
151 return sb
.toString();
155 protected BrowserTableDataSource(final BrowserController controller
, final Cache
<Path
> cache
) {
156 this.controller
= controller
;
161 * Tell the browser view to reload the data
163 * @param folders Changed files
165 public abstract void render(final NSTableView view
, final List
<Path
> folders
);
167 protected AttributedList
<Path
> get(final Path directory
) {
168 return cache
.get(directory
).filter(controller
.getComparator(), controller
.getFilter());
171 public int indexOf(NSTableView view
, Path file
) {
172 return this.get(controller
.workdir()).indexOf(file
);
175 protected void setObjectValueForItem(final Path item
, final NSObject value
, final String identifier
) {
176 if(log
.isDebugEnabled()) {
177 log
.debug(String
.format("Set new value %s for item %s", value
, item
));
179 if(identifier
.equals(Column
.filename
.name())) {
180 if(StringUtils
.isNotBlank(value
.toString()) && !item
.getName().equals(value
.toString())) {
181 final Path renamed
= new Path(
182 item
.getParent(), value
.toString(), item
.getType());
183 controller
.renamePath(item
, renamed
);
188 protected NSImage
iconForPath(final Path item
) {
189 if(item
.isVolume()) {
190 return icons
.volumeIcon(controller
.getSession().getHost().getProtocol(), 16);
192 return icons
.fileIcon(item
, 16);
195 protected NSObject
objectValueForItem(final Path item
, final String identifier
) {
199 if(log
.isTraceEnabled()) {
200 log
.trace("objectValueForItem:" + item
.getAbsolute());
202 if(identifier
.equals(Column
.icon
.name())) {
203 return this.iconForPath(item
);
205 final Item key
= new Item(item
, identifier
);
206 NSAttributedString value
= attributed
.get(key
);
210 if(log
.isDebugEnabled()) {
211 log
.debug(String
.format("Lookup failed for %s in cache", key
));
213 if(identifier
.equals(Column
.filename
.name())) {
214 value
= NSAttributedString
.attributedStringWithAttributes(
216 TableCellAttributes
.browserFontLeftAlignment());
218 else if(identifier
.equals(Column
.size
.name())) {
219 value
= NSAttributedString
.attributedStringWithAttributes(
220 sizeFormatter
.format(item
.attributes().getSize()),
221 TableCellAttributes
.browserFontRightAlignment());
223 else if(identifier
.equals(Column
.modified
.name())) {
224 value
= NSAttributedString
.attributedStringWithAttributes(
225 dateFormatter
.getShortFormat(item
.attributes().getModificationDate(),
226 preferences
.getBoolean("browser.date.natural")),
227 TableCellAttributes
.browserFontLeftAlignment()
230 else if(identifier
.equals(Column
.owner
.name())) {
231 value
= NSAttributedString
.attributedStringWithAttributes(
232 StringUtils
.isBlank(item
.attributes().getOwner()) ?
233 LocaleFactory
.localizedString("Unknown") : item
.attributes().getOwner(),
234 TableCellAttributes
.browserFontLeftAlignment());
236 else if(identifier
.equals(Column
.group
.name())) {
237 value
= NSAttributedString
.attributedStringWithAttributes(
238 StringUtils
.isBlank(item
.attributes().getGroup()) ?
239 LocaleFactory
.localizedString("Unknown") : item
.attributes().getGroup(),
240 TableCellAttributes
.browserFontLeftAlignment());
242 else if(identifier
.equals(Column
.permission
.name())) {
243 final Acl acl
= item
.attributes().getAcl();
244 if(!Acl
.EMPTY
.equals(acl
)) {
245 final StringBuilder s
= new StringBuilder();
246 for(Map
.Entry
<Acl
.User
, Set
<Acl
.Role
>> entry
: acl
.entrySet()) {
247 s
.append(String
.format("%s%s:%s", s
.length() == 0 ? StringUtils
.EMPTY
: ", ",
248 entry
.getKey().getDisplayName(), entry
.getValue()));
250 value
= NSAttributedString
.attributedStringWithAttributes(s
.toString(),
251 TableCellAttributes
.browserFontLeftAlignment());
254 final Permission permission
= item
.attributes().getPermission();
255 value
= NSAttributedString
.attributedStringWithAttributes(
256 permission
.toString(),
257 TableCellAttributes
.browserFontLeftAlignment());
260 else if(identifier
.equals(Column
.kind
.name())) {
261 value
= NSAttributedString
.attributedStringWithAttributes(
262 descriptor
.getKind(item
),
263 TableCellAttributes
.browserFontLeftAlignment());
265 else if(identifier
.equals(Column
.extension
.name())) {
266 value
= NSAttributedString
.attributedStringWithAttributes(
267 item
.isFile() ? StringUtils
.isNotBlank(item
.getExtension()) ? item
.getExtension() :
268 LocaleFactory
.localizedString("None") : LocaleFactory
.localizedString("None"),
269 TableCellAttributes
.browserFontLeftAlignment());
271 else if(identifier
.equals(Column
.region
.name())) {
272 value
= NSAttributedString
.attributedStringWithAttributes(
273 StringUtils
.isNotBlank(item
.attributes().getRegion()) ? item
.attributes().getRegion() :
274 LocaleFactory
.localizedString("Unknown"),
275 TableCellAttributes
.browserFontLeftAlignment());
277 else if(identifier
.equals(Column
.version
.name())) {
278 value
= NSAttributedString
.attributedStringWithAttributes(
279 StringUtils
.isNotBlank(item
.attributes().getVersionId()) ? item
.attributes().getVersionId() :
280 LocaleFactory
.localizedString("None"),
281 TableCellAttributes
.browserFontLeftAlignment());
284 throw new IllegalArgumentException(String
.format("Unknown identifier %s", identifier
));
286 attributed
.put(key
, value
);
291 * Sets whether the use of modifier keys should have an effect on the type of operation performed.
293 * @return Always false
294 * @see NSDraggingSource
297 public boolean ignoreModifierKeysWhileDragging() {
298 // If this method is not implemented or returns false, the user can tailor the drag operation by
299 // holding down a modifier key during the drag.
304 * @param local indicates that the candidate destination object (the window or view over which the dragged
305 * image is currently poised) is in the same application as the source, while a NO value indicates that
306 * the destination object is in a different application
307 * @return A mask, created by combining the dragging operations listed in the NSDragOperation section of
308 * NSDraggingInfo protocol reference using the C bitwise OR operator.If the source does not permit
309 * any dragging operations, it should return NSDragOperationNone.
310 * @see NSDraggingSource
313 public NSUInteger
draggingSourceOperationMaskForLocal(final boolean local
) {
314 if(log
.isDebugEnabled()) {
315 log
.debug(String
.format("Request dragging source operation mask for %s", local
));
318 // Move or copy within the browser
319 return new NSUInteger(NSDraggingInfo
.NSDragOperationMove
.intValue() | NSDraggingInfo
.NSDragOperationCopy
.intValue());
321 // Copy to a thirdparty application or drag to trash to delete
322 return new NSUInteger(NSDraggingInfo
.NSDragOperationCopy
.intValue() | NSDraggingInfo
.NSDragOperationDelete
.intValue());
327 * @param destination A directory or null to mount an URL
328 * @param info Dragging pasteboard
329 * @return True if accepted
331 public boolean acceptDrop(final NSTableView view
, final Path destination
, final NSDraggingInfo info
) {
332 if(log
.isDebugEnabled()) {
333 log
.debug(String
.format("Accept drop for destination %s", destination
));
335 if(info
.draggingPasteboard().availableTypeFromArray(NSArray
.arrayWithObject(NSPasteboard
.URLPboardType
)) != null) {
336 final NSObject o
= info
.draggingPasteboard().propertyListForType(NSPasteboard
.URLPboardType
);
337 // Mount .webloc URLs dragged to browser window
339 if(o
.isKindOfClass(Rococoa
.createClass("NSArray", NSArray
._Class
.class))) {
340 final NSArray elements
= Rococoa
.cast(o
, NSArray
.class);
341 for(int i
= 0; i
< elements
.count().intValue(); i
++) {
342 if(ProtocolFactory
.isURL(elements
.objectAtIndex(new NSUInteger(i
)).toString())) {
343 controller
.mount(HostParser
.parse(elements
.objectAtIndex(new NSUInteger(i
)).toString()));
350 if(controller
.isMounted()) {
351 if(info
.draggingPasteboard().availableTypeFromArray(NSArray
.arrayWithObject(NSPasteboard
.FilenamesPboardType
)) != null) {
352 final NSObject o
= info
.draggingPasteboard().propertyListForType(NSPasteboard
.FilenamesPboardType
);
353 // A file drag has been received by another application; upload to the dragged directory
355 if(o
.isKindOfClass(Rococoa
.createClass("NSArray", NSArray
._Class
.class))) {
356 final NSArray elements
= Rococoa
.cast(o
, NSArray
.class);
357 final List
<TransferItem
> roots
= new ArrayList
<TransferItem
>();
358 for(int i
= 0; i
< elements
.count().intValue(); i
++) {
359 final Local local
= LocalFactory
.get(elements
.objectAtIndex(new NSUInteger(i
)).toString());
360 roots
.add(new TransferItem(new Path(destination
, local
.getName(),
361 local
.isDirectory() ? EnumSet
.of(Path
.Type
.directory
) : EnumSet
.of(Path
.Type
.file
)), local
));
363 controller
.transfer(new UploadTransfer(controller
.getSession().getHost(), roots
));
369 final List
<PathPasteboard
> pasteboards
= PathPasteboardFactory
.allPasteboards();
370 for(PathPasteboard pasteboard
: pasteboards
) {
371 // A file dragged within the browser has been received
372 if(pasteboard
.isEmpty()) {
375 if(info
.draggingSourceOperationMask().intValue() == NSDraggingInfo
.NSDragOperationCopy
.intValue()
376 || pasteboard
.getSession().getHost().compareTo(controller
.getSession().getHost()) != 0) {
377 // Drag to browser windows with different session or explicit copy requested by user.
378 final Map
<Path
, Path
> files
= new HashMap
<Path
, Path
>();
379 for(Path file
: pasteboard
) {
380 files
.put(file
, new Path(destination
, file
.getName(), file
.getType()));
382 controller
.transfer(new CopyTransfer(pasteboard
.getSession().getHost(),
383 controller
.getSession().getHost(),
384 files
), new ArrayList
<Path
>(files
.values()), false);
387 // The file should be renamed
388 final Map
<Path
, Path
> files
= new HashMap
<Path
, Path
>();
389 for(Path next
: pasteboard
) {
390 Path renamed
= new Path(
391 destination
, next
.getName(), next
.getType());
392 files
.put(next
, renamed
);
394 controller
.renamePaths(files
);
405 * @param destination A directory or null to mount an URL
407 * @param info Dragging pasteboard
408 * @return Drag operation
410 public NSUInteger
validateDrop(final NSTableView view
, final Path destination
, final NSInteger row
, final NSDraggingInfo info
) {
411 if(log
.isDebugEnabled()) {
412 log
.debug(String
.format("Validate drop for destination %s", destination
));
414 if(info
.draggingPasteboard().availableTypeFromArray(NSArray
.arrayWithObject(NSPasteboard
.URLPboardType
)) != null) {
415 // Dragging URLs to mount new session
416 final NSObject o
= info
.draggingPasteboard().propertyListForType(NSPasteboard
.URLPboardType
);
418 if(o
.isKindOfClass(Rococoa
.createClass("NSArray", NSArray
._Class
.class))) {
419 final NSArray elements
= Rococoa
.cast(o
, NSArray
.class);
420 for(int i
= 0; i
< elements
.count().intValue(); i
++) {
421 // Validate if .webloc URLs dragged to browser window have a known protocol
422 if(ProtocolFactory
.isURL(elements
.objectAtIndex(new NSUInteger(i
)).toString())) {
423 // Passing a value of –1 for row, and NSTableViewDropOn as the operation causes the
424 // entire table view to be highlighted rather than a specific row.
425 view
.setDropRow(new NSInteger(-1), NSTableView
.NSTableViewDropOn
);
426 return NSDraggingInfo
.NSDragOperationCopy
;
429 log
.warn(String
.format("Protocol not supported for URL %s", elements
.objectAtIndex(new NSUInteger(i
)).toString()));
435 log
.warn("URL dragging pasteboard is empty.");
438 if(controller
.isMounted()) {
439 if(null == destination
) {
440 log
.warn("Dragging destination is null.");
441 return NSDraggingInfo
.NSDragOperationNone
;
443 // Files dragged form other application
444 if(info
.draggingPasteboard().availableTypeFromArray(NSArray
.arrayWithObject(NSPasteboard
.FilenamesPboardType
)) != null) {
445 this.setDropRowAndDropOperation(view
, destination
, row
);
446 final NSObject o
= info
.draggingPasteboard().propertyListForType(NSPasteboard
.FilenamesPboardType
);
448 if(o
.isKindOfClass(Rococoa
.createClass("NSArray", NSArray
._Class
.class))) {
449 final NSArray elements
= Rococoa
.cast(o
, NSArray
.class);
450 for(int i
= 0; i
< elements
.count().intValue(); i
++) {
451 final Local local
= LocalFactory
.get(elements
.objectAtIndex(new NSUInteger(i
)).toString());
453 final Touch feature
= controller
.getSession().getFeature(Touch
.class);
454 if(!feature
.isSupported(destination
)) {
455 // Target file system does not support creating files. Creating files is not supported
456 // for example in root of cloud storage accounts.
457 return NSDraggingInfo
.NSDragOperationNone
;
463 return NSDraggingInfo
.NSDragOperationCopy
;
465 // Files dragged from browser
466 for(Path next
: controller
.getPasteboard()) {
467 if(destination
.equals(next
)) {
468 // Do not allow dragging onto myself
469 return NSDraggingInfo
.NSDragOperationNone
;
471 if(next
.isDirectory() && destination
.isChild(next
)) {
472 // Do not allow dragging a directory into its own containing items
473 return NSDraggingInfo
.NSDragOperationNone
;
475 if(next
.isFile() && next
.getParent().equals(destination
)) {
476 // Moving a file to the same destination makes no sense
477 return NSDraggingInfo
.NSDragOperationNone
;
480 if(log
.isDebugEnabled()) {
481 log
.debug(String
.format("Drag operation mask is %d", info
.draggingSourceOperationMask().intValue()));
483 this.setDropRowAndDropOperation(view
, destination
, row
);
484 final List
<PathPasteboard
> pasteboards
= PathPasteboardFactory
.allPasteboards();
485 for(PathPasteboard pasteboard
: pasteboards
) {
486 if(pasteboard
.isEmpty()) {
489 if(pasteboard
.getSession().getHost().compareTo(controller
.getSession().getHost()) == 0) {
490 if(info
.draggingSourceOperationMask().intValue() == NSDraggingInfo
.NSDragOperationCopy
.intValue()) {
491 // Explicit copy requested if drag operation is already NSDragOperationCopy. User is pressing the option key.
492 return NSDraggingInfo
.NSDragOperationCopy
;
494 // Defaulting to move for same session
495 return NSDraggingInfo
.NSDragOperationMove
;
498 // If copying between sessions is supported
499 return NSDraggingInfo
.NSDragOperationCopy
;
503 return NSDraggingInfo
.NSDragOperationNone
;
506 private void setDropRowAndDropOperation(final NSTableView view
, final Path destination
, final NSInteger row
) {
507 if(destination
.equals(controller
.workdir())) {
508 log
.debug("setDropRowAndDropOperation:-1");
509 // Passing a value of –1 for row, and NSTableViewDropOn as the operation causes the
510 // entire table view to be highlighted rather than a specific row.
511 view
.setDropRow(new NSInteger(-1), NSTableView
.NSTableViewDropOn
);
513 else if(destination
.isDirectory()) {
514 log
.debug("setDropRowAndDropOperation:" + row
.intValue());
515 view
.setDropRow(row
, NSTableView
.NSTableViewDropOn
);
519 public boolean writeItemsToPasteBoard(final NSTableView view
, final List
<Path
> selected
, final NSPasteboard pboard
) {
520 if(log
.isDebugEnabled()) {
521 log
.debug(String
.format("Write items to pasteboard %s", pboard
));
523 if(controller
.isMounted()) {
524 if(selected
.size() > 0) {
525 // The fileTypes argument is the list of fileTypes being promised.
526 // The array elements can consist of file extensions and HFS types encoded
527 // with the NSHFSFileTypes method fileTypeForHFSTypeCode. If promising a directory
528 // of files, only include the top directory in the array.
529 final NSMutableArray fileTypes
= NSMutableArray
.array();
530 final PathPasteboard pasteboard
= controller
.getPasteboard();
531 for(final Path f
: selected
) {
533 if(StringUtils
.isNotEmpty(f
.getExtension())) {
534 fileTypes
.addObject(NSString
.stringWithString(f
.getExtension()));
537 fileTypes
.addObject(NSString
.stringWithString(NSFileManager
.NSFileTypeRegular
));
540 else if(f
.isDirectory()) {
541 fileTypes
.addObject(NSString
.stringWithString("'fldr'")); //NSFileTypeForHFSTypeCode('fldr')
544 fileTypes
.addObject(NSString
.stringWithString(NSFileManager
.NSFileTypeUnknown
));
546 // Writing data for private use when the item gets dragged to the transfer queue.
549 NSEvent event
= NSApplication
.sharedApplication().currentEvent();
551 NSPoint dragPosition
= view
.convertPoint_fromView(event
.locationInWindow(), null);
552 NSRect imageRect
= new NSRect(new NSPoint(dragPosition
.x
.doubleValue() - 16, dragPosition
.y
.doubleValue() - 16), new NSSize(32, 32));
553 view
.dragPromisedFilesOfTypes(fileTypes
, imageRect
, this.id(), true, event
);
554 // @see http://www.cocoabuilder.com/archive/message/cocoa/2003/5/15/81424
563 public void draggedImage_beganAt(final NSImage image
, final NSPoint point
) {
564 if(log
.isTraceEnabled()) {
565 log
.trace("draggedImage_beganAt:" + point
);
570 * See http://www.cocoabuilder.com/archive/message/2005/10/5/118857
573 public void draggedImage_endedAt_operation(final NSImage image
, final NSPoint point
, final NSUInteger operation
) {
574 if(log
.isTraceEnabled()) {
575 log
.trace("draggedImage_endedAt_operation:" + operation
);
577 final PathPasteboard pasteboard
= controller
.getPasteboard();
578 if(NSDraggingInfo
.NSDragOperationDelete
.intValue() == operation
.intValue()) {
579 controller
.deletePaths(pasteboard
);
585 public void draggedImage_movedTo(final NSImage image
, final NSPoint point
) {
586 if(log
.isTraceEnabled()) {
587 log
.trace("draggedImage_movedTo:" + point
);
592 * @return the names (not full paths) of the files that the receiver promises to create at dropDestination.
593 * This method is invoked when the drop has been accepted by the destination and the destination, in the case of another
594 * Cocoa application, invokes the NSDraggingInfo method namesOfPromisedFilesDroppedAtDestination. For long operations,
595 * you can cache dropDestination and defer the creation of the files until the finishedDraggingImage method to avoid
596 * blocking the destination application.
599 public NSArray
namesOfPromisedFilesDroppedAtDestination(final NSURL url
) {
600 if(log
.isDebugEnabled()) {
601 log
.debug(String
.format("Return names of promised files dropped at %s", url
));
603 NSMutableArray promisedDragNames
= NSMutableArray
.array();
605 final Local destination
= LocalFactory
.get(url
.path());
606 final PathPasteboard pasteboard
= controller
.getPasteboard();
607 final List
<TransferItem
> downloads
= new ArrayList
<TransferItem
>();
608 for(Path p
: pasteboard
) {
609 downloads
.add(new TransferItem(p
, LocalFactory
.get(destination
, p
.getName())));
610 // Add to returned path names
611 promisedDragNames
.addObject(NSString
.stringWithString(p
.getName()));
613 if(downloads
.size() == 1) {
614 if(downloads
.iterator().next().remote
.isFile()) {
615 final Local file
= downloads
.iterator().next().local
;
618 LocalTouchFactory
.get().touch(file
);
619 IconServiceFactory
.get().set(file
, new TransferStatus());
621 catch(AccessDeniedException e
) {
622 log
.warn(String
.format("Failure creating file %s %s", file
, e
.getMessage()));
626 if(downloads
.iterator().next().remote
.isDirectory()) {
627 final Local file
= downloads
.iterator().next().local
;
632 catch(AccessDeniedException e
) {
633 log
.warn(e
.getMessage());
638 // kTemporaryFolderType
639 final boolean dock
= destination
.equals(LocalFactory
.get("~/Library/Caches/TemporaryItems"));
641 for(Path p
: pasteboard
) {
642 // Drag to application icon in dock.
647 final DownloadTransfer transfer
= new DownloadTransfer(controller
.getSession().getHost(), downloads
);
648 controller
.transfer(transfer
, Collections
.<Path
>emptyList());
653 return promisedDragNames
;