From 82e4404406189dea2ddb18d9c3f10ecceef8d461 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Tue, 26 Nov 2024 09:14:54 +0100 Subject: [PATCH] Show progress icon for uploads. --- .../core/local/FinderProgressIconService.java | 16 +++++-- .../core/local/WorkspaceIconService.java | 47 ++++++++++--------- .../core/local/DisabledIconService.java | 16 +------ .../ch/cyberduck/core/local/IconService.java | 15 +++++- .../core/local/IconServiceFactory.java | 5 +- .../core/transfer/DownloadTransfer.java | 11 +---- .../core/worker/AbstractTransferWorker.java | 19 +++++++- .../src/main/resources/default.properties | 2 +- .../datasource/BrowserTableDataSource.java | 9 ++-- 9 files changed, 81 insertions(+), 59 deletions(-) diff --git a/core/dylib/src/main/java/ch/cyberduck/core/local/FinderProgressIconService.java b/core/dylib/src/main/java/ch/cyberduck/core/local/FinderProgressIconService.java index 139ef603c5a..f3f031412e3 100644 --- a/core/dylib/src/main/java/ch/cyberduck/core/local/FinderProgressIconService.java +++ b/core/dylib/src/main/java/ch/cyberduck/core/local/FinderProgressIconService.java @@ -18,25 +18,33 @@ import ch.cyberduck.binding.foundation.NSProgress; import ch.cyberduck.binding.foundation.NSURL; import ch.cyberduck.core.Local; +import ch.cyberduck.core.transfer.Transfer; import ch.cyberduck.core.transfer.TransferProgress; import ch.cyberduck.core.transfer.TransferStatus; public class FinderProgressIconService implements IconService { @Override - public Icon get(final Local file) { - return new FinderProgressIcon(file); + public Icon get(final Transfer.Type type, final Local file) { + return new FinderProgressIcon(type, file); } private static final class FinderProgressIcon implements Icon { private final NSProgress progress; - public FinderProgressIcon(final Local file) { + public FinderProgressIcon(final Transfer.Type type, final Local file) { progress = NSProgress.discreteProgressWithTotalUnitCount(0L); progress.setKind(NSProgress.NSProgressKindFile); progress.setCancellable(false); progress.setPausable(false); - progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindDownloading); + switch(type) { + case download: + progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindDownloading); + break; + case upload: + progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindUploading); + break; + } progress.setFileURL(NSURL.fileURLWithPath(file.getAbsolute())); progress.publish(); } diff --git a/core/dylib/src/main/java/ch/cyberduck/core/local/WorkspaceIconService.java b/core/dylib/src/main/java/ch/cyberduck/core/local/WorkspaceIconService.java index df579db94c1..d663dd53c33 100644 --- a/core/dylib/src/main/java/ch/cyberduck/core/local/WorkspaceIconService.java +++ b/core/dylib/src/main/java/ch/cyberduck/core/local/WorkspaceIconService.java @@ -20,6 +20,7 @@ import ch.cyberduck.core.Local; import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.resources.IconCacheFactory; +import ch.cyberduck.core.transfer.Transfer; import ch.cyberduck.core.transfer.TransferProgress; import ch.cyberduck.core.unicode.NFDNormalizer; @@ -33,30 +34,34 @@ public final class WorkspaceIconService implements IconService { private static final NSWorkspace workspace = NSWorkspace.sharedWorkspace(); @Override - public Icon get(final Local file) { - return new Icon() { - // An integer between 0 and 9 - private int step = 0; + public Icon get(final Transfer.Type type, final Local file) { + switch(type) { + case download: + return new Icon() { + // An integer between 0 and 9 + private int step = 0; - @Override - public boolean update(final TransferProgress progress) { - if(progress.getSize() > PreferencesFactory.get().getLong("queue.download.icon.threshold")) { - final int fraction = new BigDecimal(progress.getTransferred()).divide(new BigDecimal(progress.getSize()), 1, RoundingMode.DOWN).multiply(BigDecimal.TEN).intValue(); - if(fraction >= step) { - // Another 10 percent of the file has been transferred - return WorkspaceIconService.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", step = fraction))); + @Override + public boolean update(final TransferProgress progress) { + if(progress.getSize() > PreferencesFactory.get().getLong("queue.download.icon.threshold")) { + final int fraction = new BigDecimal(progress.getTransferred()).divide(new BigDecimal(progress.getSize()), 1, RoundingMode.DOWN).multiply(BigDecimal.TEN).intValue(); + if(fraction >= step) { + // Another 10 percent of the file has been transferred + return WorkspaceIconService.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", step = fraction))); + } + return false; + } + return false; } - return false; - } - return false; - } - @Override - public boolean remove() { - // The Finder will display the default icon for this file type - return WorkspaceIconService.update(file, null); - } - }; + @Override + public boolean remove() { + // The Finder will display the default icon for this file type + return WorkspaceIconService.update(file, null); + } + }; + } + return disabled; } public static boolean update(final Local file, final NSImage icon) { diff --git a/core/src/main/java/ch/cyberduck/core/local/DisabledIconService.java b/core/src/main/java/ch/cyberduck/core/local/DisabledIconService.java index 7ac53f525d3..8d898854e5c 100644 --- a/core/src/main/java/ch/cyberduck/core/local/DisabledIconService.java +++ b/core/src/main/java/ch/cyberduck/core/local/DisabledIconService.java @@ -19,24 +19,12 @@ */ import ch.cyberduck.core.Local; -import ch.cyberduck.core.transfer.TransferProgress; +import ch.cyberduck.core.transfer.Transfer; public final class DisabledIconService implements IconService { - private static final Icon disabled = new Icon() { - @Override - public boolean update(final TransferProgress progress) { - return false; - } - - @Override - public boolean remove() { - return false; - } - }; - @Override - public Icon get(final Local file) { + public Icon get(final Transfer.Type type, final Local file) { return disabled; } } diff --git a/core/src/main/java/ch/cyberduck/core/local/IconService.java b/core/src/main/java/ch/cyberduck/core/local/IconService.java index adc04beb1d7..ee50d483222 100644 --- a/core/src/main/java/ch/cyberduck/core/local/IconService.java +++ b/core/src/main/java/ch/cyberduck/core/local/IconService.java @@ -19,17 +19,30 @@ */ import ch.cyberduck.core.Local; +import ch.cyberduck.core.transfer.Transfer; import ch.cyberduck.core.transfer.TransferProgress; public interface IconService { + Icon disabled = new Icon() { + @Override + public boolean update(final TransferProgress progress) { + return false; + } + + @Override + public boolean remove() { + return false; + } + }; + /** * Get icon updater to track progress * * @param file Local file * @return Updater to send continious progress updates to */ - Icon get(Local file); + Icon get(Transfer.Type type, Local file); interface Icon { /** diff --git a/core/src/main/java/ch/cyberduck/core/local/IconServiceFactory.java b/core/src/main/java/ch/cyberduck/core/local/IconServiceFactory.java index 1b69b4648e5..2eefedde25f 100644 --- a/core/src/main/java/ch/cyberduck/core/local/IconServiceFactory.java +++ b/core/src/main/java/ch/cyberduck/core/local/IconServiceFactory.java @@ -20,6 +20,7 @@ import ch.cyberduck.core.Factory; import ch.cyberduck.core.Local; +import ch.cyberduck.core.transfer.Transfer; public class IconServiceFactory extends Factory { @@ -31,7 +32,7 @@ public static IconService get() { return new IconServiceFactory().create(); } - public static IconService.Icon iconFor(final Local file) { - return get().get(file); + public static IconService.Icon iconFor(final Transfer.Type type, final Local file) { + return get().get(type, file); } } \ No newline at end of file diff --git a/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java b/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java index 0dcab0e0621..bf5a8c901d9 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java @@ -29,8 +29,6 @@ import ch.cyberduck.core.io.BandwidthThrottle; import ch.cyberduck.core.io.StreamListener; import ch.cyberduck.core.local.DefaultLocalDirectoryFeature; -import ch.cyberduck.core.local.IconService; -import ch.cyberduck.core.local.IconServiceFactory; import ch.cyberduck.core.local.LocalSymlinkFactory; import ch.cyberduck.core.local.features.Symlink; import ch.cyberduck.core.preferences.PreferencesFactory; @@ -39,7 +37,6 @@ import ch.cyberduck.core.transfer.download.CompareFilter; import ch.cyberduck.core.transfer.download.DownloadFilterOptions; import ch.cyberduck.core.transfer.download.DownloadRegexPriorityComparator; -import ch.cyberduck.core.transfer.download.IconServiceStreamListener; import ch.cyberduck.core.transfer.download.OverwriteFilter; import ch.cyberduck.core.transfer.download.RenameExistingFilter; import ch.cyberduck.core.transfer.download.RenameFilter; @@ -304,13 +301,7 @@ public void transfer(final Session source, final Session destination, fina } // Transfer final Download download = source.getFeature(Download.class); - final IconService.Icon icon = IconServiceFactory.iconFor(segment.isSegment() ? folder : local); - download.download(file, local, bandwidth, this.options.icon ? - new IconServiceStreamListener(this, icon, listener) : listener, segment, prompt); - // Remove custom icon if complete - if(segment.isComplete()) { - icon.remove(); - } + download.download(file, local, bandwidth, listener, segment, prompt); } } diff --git a/core/src/main/java/ch/cyberduck/core/worker/AbstractTransferWorker.java b/core/src/main/java/ch/cyberduck/core/worker/AbstractTransferWorker.java index 8c79edc151e..d083c00b8ee 100644 --- a/core/src/main/java/ch/cyberduck/core/worker/AbstractTransferWorker.java +++ b/core/src/main/java/ch/cyberduck/core/worker/AbstractTransferWorker.java @@ -24,7 +24,10 @@ import ch.cyberduck.core.exception.TransferCanceledException; import ch.cyberduck.core.exception.TransferStatusCanceledException; import ch.cyberduck.core.io.StreamListener; +import ch.cyberduck.core.local.IconService; +import ch.cyberduck.core.local.IconServiceFactory; import ch.cyberduck.core.notification.NotificationService; +import ch.cyberduck.core.preferences.HostPreferences; import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.threading.TransferBackgroundActionState; import ch.cyberduck.core.transfer.SynchronizingTransferErrorCallback; @@ -38,6 +41,7 @@ import ch.cyberduck.core.transfer.TransferSpeedometer; import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.transfer.TransferStreamListener; +import ch.cyberduck.core.transfer.download.IconServiceStreamListener; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.concurrent.ConcurrentUtils; @@ -380,12 +384,25 @@ private void transferSegment(final TransferStatus segment) throws BackgroundExce log.debug("Transfer item {} with status {}", item, segment); final Session s = borrow(Connection.source); final Session d = borrow(Connection.destination); - final BytecountStreamListener counter = new TransferStreamListener(transfer, stream); + final IconService.Icon icon; + if(new HostPreferences(s.getHost()).getBoolean(String.format("queue.%s.icon.update", transfer.getType().name()))) { + icon = IconServiceFactory.iconFor(transfer.getType(), + segment.getRename().local != null ? segment.isSegment() ? segment.getRename().local.getParent() : segment.getRename().local : item.local); + } + else { + icon = IconService.disabled; + } + final BytecountStreamListener counter = new TransferStreamListener(transfer, + new IconServiceStreamListener(transfer, icon, stream)); try { transfer.transfer(s, d, segment.getRename().remote != null ? segment.getRename().remote : item.remote, segment.getRename().local != null ? segment.getRename().local : item.local, options, segment, connect, progress, counter); + if(transfer.isComplete()) { + // Remove custom icon if complete + icon.remove(); + } } catch(BackgroundException e) { release(s, Connection.source, e); diff --git a/defaults/src/main/resources/default.properties b/defaults/src/main/resources/default.properties index 3f1b9c16423..8bb5cb49a3f 100644 --- a/defaults/src/main/resources/default.properties +++ b/defaults/src/main/resources/default.properties @@ -213,7 +213,7 @@ queue.connections.limit.default=5 queue.connections.limit.ftp=1 # Auto determine number of connections queue.connections.options=0,1,2,3,4,5,10,15,20 - +queue.upload.icon.update=true # While downloading, update the icon of the downloaded file as a progress indicator queue.download.icon.update=true queue.download.icon.threshold=5242880 diff --git a/osx/src/main/java/ch/cyberduck/ui/cocoa/datasource/BrowserTableDataSource.java b/osx/src/main/java/ch/cyberduck/ui/cocoa/datasource/BrowserTableDataSource.java index 29777e27bef..6aa59de3655 100644 --- a/osx/src/main/java/ch/cyberduck/ui/cocoa/datasource/BrowserTableDataSource.java +++ b/osx/src/main/java/ch/cyberduck/ui/cocoa/datasource/BrowserTableDataSource.java @@ -56,8 +56,8 @@ import ch.cyberduck.core.local.DefaultLocalDirectoryFeature; import ch.cyberduck.core.local.FileDescriptor; import ch.cyberduck.core.local.FileDescriptorFactory; -import ch.cyberduck.core.local.IconServiceFactory; import ch.cyberduck.core.local.LocalTouchFactory; +import ch.cyberduck.core.local.WorkspaceIconService; import ch.cyberduck.core.pasteboard.PathPasteboard; import ch.cyberduck.core.pasteboard.PathPasteboardFactory; import ch.cyberduck.core.preferences.Preferences; @@ -69,7 +69,6 @@ import ch.cyberduck.core.transfer.DownloadTransfer; import ch.cyberduck.core.transfer.Transfer; import ch.cyberduck.core.transfer.TransferItem; -import ch.cyberduck.core.transfer.TransferProgress; import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.transfer.download.DownloadFilterOptions; import ch.cyberduck.ui.browser.BrowserColumn; @@ -390,7 +389,7 @@ public boolean acceptDrop(final NSTableView view, final Path destination, final for(int i = 0; i < elements.count().intValue(); i++) { final Local local = LocalFactory.get(elements.objectAtIndex(new NSUInteger(i)).toString()); roots.add(new TransferItem(new Path(destination, local.getName(), - local.isDirectory() ? EnumSet.of(Path.Type.directory) : EnumSet.of(Path.Type.file)), local)); + local.isDirectory() ? EnumSet.of(Path.Type.directory) : EnumSet.of(Path.Type.file)), local)); } controller.transfer(new UploadTransfer(controller.getSession().getHost(), roots)); return true; @@ -648,7 +647,7 @@ public NSArray namesOfPromisedFilesDroppedAtDestination(final NSURL url) { try { LocalTouchFactory.get().touch(file); if(options.icon) { - IconServiceFactory.iconFor(file).update(new TransferProgress(0L, 0L)); + WorkspaceIconService.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", 0))); } } catch(AccessDeniedException e) { @@ -678,7 +677,7 @@ public NSArray namesOfPromisedFilesDroppedAtDestination(final NSURL url) { } else { final Transfer transfer = new DownloadTransfer(controller.getSession().getHost(), downloads) - .withOptions(options); + .withOptions(options); controller.transfer(transfer, Collections.emptyList()); } pasteboard.clear();