From 381a6ff4b7a1937723bdbd4e352a8fd25a0fa1fd Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 31 Aug 2022 17:18:04 +0200 Subject: [PATCH 01/21] Remove unused method from interface. Signed-off-by: David Kocher --- .../ch/cyberduck/core/local/WorkspaceIconService.java | 9 ++------- .../ch/cyberduck/core/local/DisabledIconService.java | 5 ----- .../main/java/ch/cyberduck/core/local/IconService.java | 8 -------- 3 files changed, 2 insertions(+), 20 deletions(-) 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 48e1ad9d02a..4c00eafb5e3 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 @@ -31,11 +31,6 @@ public final class WorkspaceIconService implements IconService { private final NSWorkspace workspace = NSWorkspace.sharedWorkspace(); - @Override - public boolean set(final Local file, final String image) { - return this.update(file, IconCacheFactory.get().iconNamed(image)); - } - protected boolean update(final Local file, final NSImage icon) { synchronized(NSWorkspace.class) { // Specify 0 if you want to generate icons in all available icon representation formats @@ -55,10 +50,10 @@ public boolean set(final Local file, final TransferStatus status) { else { if(status.getLength() > 0) { int fraction = (int) (status.getOffset() / (status.getOffset() + status.getLength()) * 10); - return this.set(file, String.format("download%d.icns", ++fraction)); + return this.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", ++fraction))); } else { - return this.set(file, String.format("download%d.icns", 0)); + return this.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", 0))); } } } 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 748e4982756..72c428ce7b6 100644 --- a/core/src/main/java/ch/cyberduck/core/local/DisabledIconService.java +++ b/core/src/main/java/ch/cyberduck/core/local/DisabledIconService.java @@ -22,11 +22,6 @@ import ch.cyberduck.core.transfer.TransferStatus; public final class DisabledIconService implements IconService { - @Override - public boolean set(final Local file, final String image) { - return false; - } - @Override public boolean set(final Local file, final TransferStatus progress) { return false; 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 d661a86470f..47189b5b998 100644 --- a/core/src/main/java/ch/cyberduck/core/local/IconService.java +++ b/core/src/main/java/ch/cyberduck/core/local/IconService.java @@ -22,14 +22,6 @@ import ch.cyberduck.core.transfer.TransferStatus; public interface IconService { - - /** - * @param file File - * @param image Image name - * @return True if icon is set - */ - boolean set(Local file, String image); - /** * @param file File * @param progress An integer from -1 and 9. If -1 is passed, the icon should be removed. From 0f91673faea529dad9e45e934d7d9e39b92486cf Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 31 Aug 2022 17:18:15 +0200 Subject: [PATCH 02/21] Add `NSProgress`. Signed-off-by: David Kocher --- .../binding/foundation/NSProgress.java | 290 ++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 binding/src/main/java/ch/cyberduck/binding/foundation/NSProgress.java diff --git a/binding/src/main/java/ch/cyberduck/binding/foundation/NSProgress.java b/binding/src/main/java/ch/cyberduck/binding/foundation/NSProgress.java new file mode 100644 index 00000000000..8004ad5ad5b --- /dev/null +++ b/binding/src/main/java/ch/cyberduck/binding/foundation/NSProgress.java @@ -0,0 +1,290 @@ +package ch.cyberduck.binding.foundation;/* + * Copyright (c) 2002-2022 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Copyright (c) 2002-2022 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import org.rococoa.ObjCClass; +import org.rococoa.Rococoa; + +public abstract class NSProgress extends NSObject { + private static final _Class CLASS = Rococoa.createClass("NSProgress", _Class.class); + + public interface _Class extends ObjCClass { + NSProgress alloc(); + + NSProgress progressWithTotalUnitCount(long count); + + NSProgress discreteProgressWithTotalUnitCount(long count); + + NSProgress currentProgress(); + } + + public static NSProgress progressWithParent(NSProgress parent, NSDictionary userInfo) { + return CLASS.alloc().initWithParent_userInfo(parent, userInfo); + } + + /** + * Creates and returns an NSProgress instance, initialized using initWithParent:userInfo:. + *

+ * The initializer is passed the current progress object, if there is one, and the value of the totalUnitCount property is set. + *

+ * In many cases you can simply precede code that does a substantial amount of work with an invocation of this method, then repeatedly set the completedUnitCount or cancelled property in the loop that does the work. + *

+ * You can invoke this method on one thread and then message the returned NSProgress on another thread. For example, you can capture the created progress instance in a block that you pass to dispatch_async. In that block you can invoke methods like becomeCurrentWithPendingUnitCount: or resignCurrent, and set the completedUnitCount or cancelled properties as work is carried out. + * + * @param unitCount The total number of units of work to be carried out. + * @return Creates and returns an NSProgress instance + */ + public static NSProgress progressWithTotalUnitCount(long unitCount) { + return CLASS.progressWithTotalUnitCount(unitCount); + } + + /** + * Creates and returns an NSProgress instance with the specified totalUnitCount that is not part of any existing + * progress tree. The instance is initialized using initWithParent:userInfo: with the parent set to nil. + *

+ * Use this method to create the top level progress object returned by your own custom classes. The user of the returned progress object can add it to a progress tree using addChild:withPendingUnitCount:. + *

+ * You are responsible for updating the progress count of the created progress object. You can invoke this method on one thread and then message the returned NSProgress on another thread. For example, you can capture the created progress instance in a block that you pass to dispatch_async. In that block you can invoke methods like becomeCurrentWithPendingUnitCount: or resignCurrent, and set the completedUnitCount or cancelled properties as work is carried out. + * + * @param unitCount The total number of units of work to be carried out. + * @return Creates and returns an NSProgress instance + */ + public static NSProgress discreteProgressWithTotalUnitCount(long unitCount) { + return CLASS.discreteProgressWithTotalUnitCount(unitCount); + } + + /** + * Returns the NSProgress instance, if any, associated with the current thread by a previous invocation of becomeCurrentWithPendingUnitCount:. + *

+ * Use this per-thread currentProgress value to allow code that performs work to report useful progress even when it + * is widely separated from the code that actually presents progress information to the user, without requiring layers + * of intervening code to pass around an NSProgress instance. + *

+ * When reporting progress, you typically work with a child progress object, created by calling + * discreteProgressWithTotalUnitCount:, to ensure that you report progress in known units of work. + * + * @return The NSProgress instance associated with the current thread, if any. + */ + public static NSProgress currentProgress() { + return CLASS.currentProgress(); + } + + /** + * Initializes a newly allocated NSProgress instance. + * + * @param parent The parent NSProgress object, if any, to notify when reporting progress or to consult + * when checking for cancellation. + *

+ * The only valid values are [NSProgress currentProgress] or nil. + * @param userInfo The user information dictionary for the progress object. May be nil. + * @return This is the designated initializer for the NSProgress class. + */ + public abstract NSProgress initWithParent_userInfo(NSProgress parent, NSDictionary userInfo); + + /** + * This property identifies the kind of progress being made, such as NSProgressKindFile. It can be nil. + *

+ * If the value of the localizedDescription property has not previously been set to a non-nil value, the + * default localizedDescription getter uses the progress kind to determine how to use the values of other + * properties, as well as values in the user info dictionary, to create a string that is presentable to the user. + * + * @param kind A string identifying the kind of progress being made. + */ + public abstract void setKind(String kind); + + /** + * Balance the most recent previous invocation of becomeCurrentWithPendingUnitCount: on the same thread by + * restoring the current progress object to what it was before becomeCurrentWithPendingUnitCount: was invoked. + */ + public abstract void resignCurrent(); + + /** + * By default, NSProgress objects are not pausable. + *

+ * You typically use this property to communicate whether controls for pausing should appear in a progress + * reporting user interface. NSProgress itself does not do anything with this property other than help pass + * the value from progress reporters to progress observers. + *

+ * If an NSProgress is pausable, you should implement the ability to pause either by setting a block for the + * pausingHandler property, or by polling the paused property periodically while performing the relevant work. + *

+ * It is valid for the value of this property to change during the lifetime of an NSProgress object. By default, + * NSProgress is KVO-compliant for this property, sending notifications on the same thread that updates the property. + * + * @param value Indicates whether the receiver is tracking work that can be paused. + */ + public abstract void setPausable(boolean value); + + /** + *

+ * By default, NSProgress objects are cancellable. + *

+ * You typically use this property to communicate whether controls for canceling should appear in a progress reporting + * user interface. NSProgress itself does not do anything with this property other than help pass the value from + * progress reporters to progress observers. + *

+ * If an NSProgress is cancellable, you should implement the ability to cancel progress either by setting a block + * or the cancellationHandler property, or by polling the cancelled property periodically while performing the relevant work. + *

+ * It is valid for the value of this property to change during the lifetime of an NSProgress object. By default, + * NSProgress is KVO-compliant for this property, sending notifications on the same thread that updates the property. + * + * @param value Indicates whether the receiver is tracking work that can be cancelled. + */ + public abstract void setCancellable(boolean value); + + /** + * For an NSProgress with a kind of NSProgressKindFile, the unit of this property is bytes while the NSProgressFileTotalCountKey + * and NSProgressFileCompletedCountKey keys in the userInfo dictionary are used for the overall count of files. + *

+ * For any other kind of NSProgress, the unit of measurement does not matter as long as it is consistent. The values + * may be reported to the user in the localizedDescription and localizedAdditionalDescription. + * + * @param completedUnitCount The number of units of work for the current job that have already been completed. + */ + public abstract void setCompletedUnitCount(long completedUnitCount); + + /** + * For an NSProgress with a kind of NSProgressKindFile, the unit of this property is bytes while the + * NSProgressFileTotalCountKey and NSProgressFileCompletedCountKey keys in the userInfo dictionary are used for the overall count of files. + * + * @param totalUnitCount The total number of units of work tracked for the current progress. + */ + public abstract void setTotalUnitCount(long totalUnitCount); + + /** + * For an NSProgress with a kind of NSProgressKindFile, the unit of this property is bytes, and the NSProgressFileTotalCountKey and + * NSProgressFileCompletedCountKey keys in the userInfo dictionary report the overall count of files. + *

+ * For any other kind of NSProgress, the unit of measurement doesn’t matter as long as it’s consistent. You can report the values to + * the user in the localizedDescription and localizedAdditionalDescription. + * + * @return The total number of tracked units of work for the current progress. + */ + public abstract long totalUnitCount(); + + /** + * For an NSProgress with a kind of NSProgressKindFile, the unit of this property is bytes, and the NSProgressFileTotalCountKey and + * NSProgressFileCompletedCountKey keys in the userInfo dictionary report the overall count of files. + *

+ * For any other kind of NSProgress, the unit of measurement doesn’t matter as long as it’s consistent. You can report the values to + * the user in the localizedDescription and localizedAdditionalDescription. + * + * @return The number of completed units of work for the current job. + */ + public abstract long completedUnitCount(); + + /** + * If the current progress is operating on a set of files, set this property to the total number of files in the operation. + *

+ * If present, NSProgress presents additional information in its localized description by setting a value in the userInfo dictionary. + * + * @return The total number of files for a file progress object. + */ + public abstract NSNumber fileTotalCount(); + + /** + * If the current progress is operating on a set of files, set this property to the number of completed files in the operation. + *

+ * If present, NSProgress presents additional information in its localized description by setting a value in the userInfo dictionary. + * + * @return The number of completed files for a file progress object. + */ + public abstract NSNumber fileCompletedCount(); + + /** + * A KVO-compliant dictionary that changes in response to setUserInfoObject:forKey:. The dictionary sends all of + * its KVO notifications on the thread that updates the property. + *

+ * Some entries have meanings that the NSProgress class recognizes. For more information, see Recognizing Kinds of Progress, Using General Keys, Using + * File Operation Keys, and Recognizing Kinds of File Operations. + * + * @return A dictionary of arbitrary values for the receiver. + */ + public abstract NSDictionary userInfo(); + + /** + * Publishes the progress object for other processes to observe it. + */ + public abstract void publish(); + + /** + * Removes a progress object from publication, making it unobservable by other processes. + */ + public abstract void unpublish(); + + /** + * Sets the receiver as the current progress object of the current thread and specifies the portion of work to be + * performed by the next child progress object of the receiver. + * + * @param unitCount The number of units of work to be carried out by the next progress object that is initialized by + * invoking the initWithParent:userInfo: method in the current thread with the receiver set as the parent. + * This number represents the portion of work to be performed in relation to the total number of units + * of work to be performed by the receiver (represented by the value of the receiver’s totalUnitCount + * property). The units of work represented by this parameter must be the same units of work that are + * used in the receiver’s totalUnitCount property. + */ + public abstract void becomeCurrentWithPendingUnitCount(long unitCount); + + /** + * Sets a value in the user info dictionary. + * + * @param objectOrNil The object to set for the specified key, or nil to remove an existing entry in the dictionary. + * @param key The key for storing the specified object. + */ + public abstract void setUserInfoObject_forKey(NSObject objectOrNil, String key); + + /** + * The value that indicates that the progress is tracking a file operation. + * If you set this value for the progress kind, set a value in the user info dictionary for the NSProgressFileOperationKindKey. + */ + public static final String NSProgressKindFile = "NSProgressKindFile"; + /** + * A key with a corresponding value that indicates the kind of file operation a progress object represents. + */ + public static final String NSProgressFileOperationKindKey = "NSProgressFileOperationKindKey"; + public static final String NSProgressFileDownloadingSourceURLKey = "NSProgressFileDownloadingSourceURLKey"; + public static final String NSProgressFileURLKey = "NSProgressFileURLKey"; + /** + * The progress is tracking a file upload operation. + */ + public static final String NSProgressFileOperationKindUploading = "NSProgressFileOperationKindUploading"; + /** + * The progress is tracking a file download operation. + */ + public static final String NSProgressFileOperationKindDownloading = "NSProgressFileOperationKindDownloading"; + /** + * A key with a corresponding value that represents the time remaining, in seconds. + */ + public static final String NSProgressEstimatedTimeRemainingKey = "NSProgressEstimatedTimeRemainingKey"; + /** + * A key with a corresponding value that indicates the speed of data processing, in bytes per second. + */ + public static final String NSProgressThroughputKey = "NSProgressThroughputKey"; +} From a8582052c6c0fc6fc8762784118b9bd8e01816f0 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 31 Aug 2022 17:33:42 +0200 Subject: [PATCH 03/21] Fix to have current offset in status. Signed-off-by: David Kocher --- core/src/main/java/ch/cyberduck/core/local/IconService.java | 2 +- .../core/transfer/download/IconUpdateStreamListener.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 47189b5b998..19afa0117b2 100644 --- a/core/src/main/java/ch/cyberduck/core/local/IconService.java +++ b/core/src/main/java/ch/cyberduck/core/local/IconService.java @@ -24,7 +24,7 @@ public interface IconService { /** * @param file File - * @param progress An integer from -1 and 9. If -1 is passed, the icon should be removed. + * @param progress Transfer status with transferred bytes set in offset * @return True if icon is set */ boolean set(Local file, TransferStatus progress); diff --git a/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java b/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java index 2e2774bb8da..85f44e23d48 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java @@ -49,7 +49,7 @@ public void sent(final long bytes) { final BigDecimal fraction = new BigDecimal(this.getSent()).divide(new BigDecimal(status.getLength()), 1, RoundingMode.DOWN); if(fraction.multiply(BigDecimal.TEN).intValue() > step) { // Another 10 percent of the file has been transferred - icon.set(file, status); + icon.set(file, new TransferStatus(status).withOffset(this.getSent())); step++; } } From 23735b5077c64919dbff79009fd53b279daeb8a0 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 31 Aug 2022 21:07:34 +0200 Subject: [PATCH 04/21] Set icon on 0B. Signed-off-by: David Kocher --- .../core/transfer/download/IconUpdateStreamListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java b/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java index 85f44e23d48..dc5acb6200c 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java @@ -47,7 +47,7 @@ public IconUpdateStreamListener(final StreamListener delegate, final TransferSta public void sent(final long bytes) { super.sent(bytes); final BigDecimal fraction = new BigDecimal(this.getSent()).divide(new BigDecimal(status.getLength()), 1, RoundingMode.DOWN); - if(fraction.multiply(BigDecimal.TEN).intValue() > step) { + if(fraction.multiply(BigDecimal.TEN).intValue() >= step) { // Another 10 percent of the file has been transferred icon.set(file, new TransferStatus(status).withOffset(this.getSent())); step++; From b4e1912811f478fe41d052bd27767c02389267a0 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 31 Aug 2022 21:09:48 +0200 Subject: [PATCH 05/21] Remove redundant set. Signed-off-by: David Kocher --- .../cyberduck/core/transfer/download/AbstractDownloadFilter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java b/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java index 9eece598754..0b489a739b3 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java @@ -281,7 +281,6 @@ public void complete(final Path file, final Local local, launcher.bounce(local); // Remove custom icon if complete. The Finder will display the default icon for this file type if(options.icon) { - icon.set(local, status); icon.remove(local); } if(options.quarantine || options.wherefrom) { From e9fcff87d616a06c3421b557786a07a9e3d1dd5c Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 31 Aug 2022 21:20:14 +0200 Subject: [PATCH 06/21] Change interface. Signed-off-by: David Kocher --- .../core/local/WorkspaceIconService.java | 18 ++++-------------- .../core/local/DisabledIconService.java | 4 ++-- .../ch/cyberduck/core/local/IconService.java | 4 ++-- .../core/transfer/TransferProgress.java | 9 +++++++++ .../download/IconUpdateStreamListener.java | 3 ++- .../datasource/BrowserTableDataSource.java | 3 ++- 6 files changed, 21 insertions(+), 20 deletions(-) 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 4c00eafb5e3..c7d7c41cfa7 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 @@ -22,7 +22,7 @@ import ch.cyberduck.binding.application.NSWorkspace; import ch.cyberduck.core.Local; import ch.cyberduck.core.resources.IconCacheFactory; -import ch.cyberduck.core.transfer.TransferStatus; +import ch.cyberduck.core.transfer.TransferProgress; import ch.cyberduck.core.unicode.NFDNormalizer; import org.rococoa.cocoa.foundation.NSUInteger; @@ -43,19 +43,9 @@ protected boolean update(final Local file, final NSImage icon) { } @Override - public boolean set(final Local file, final TransferStatus status) { - if(status.isComplete()) { - return this.remove(file); - } - else { - if(status.getLength() > 0) { - int fraction = (int) (status.getOffset() / (status.getOffset() + status.getLength()) * 10); - return this.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", ++fraction))); - } - else { - return this.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", 0))); - } - } + public boolean set(final Local file, final TransferProgress status) { + int fraction = (int) (status.getTransferred() / (status.getTransferred() + status.getSize()) * 10); + return this.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", ++fraction))); } @Override 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 72c428ce7b6..67b864440f2 100644 --- a/core/src/main/java/ch/cyberduck/core/local/DisabledIconService.java +++ b/core/src/main/java/ch/cyberduck/core/local/DisabledIconService.java @@ -19,11 +19,11 @@ */ import ch.cyberduck.core.Local; -import ch.cyberduck.core.transfer.TransferStatus; +import ch.cyberduck.core.transfer.TransferProgress; public final class DisabledIconService implements IconService { @Override - public boolean set(final Local file, final TransferStatus progress) { + public boolean set(final Local file, final TransferProgress progress) { return false; } 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 19afa0117b2..88739c999e4 100644 --- a/core/src/main/java/ch/cyberduck/core/local/IconService.java +++ b/core/src/main/java/ch/cyberduck/core/local/IconService.java @@ -19,7 +19,7 @@ */ import ch.cyberduck.core.Local; -import ch.cyberduck.core.transfer.TransferStatus; +import ch.cyberduck.core.transfer.TransferProgress; public interface IconService { /** @@ -27,7 +27,7 @@ public interface IconService { * @param progress Transfer status with transferred bytes set in offset * @return True if icon is set */ - boolean set(Local file, TransferStatus progress); + boolean set(Local file, TransferProgress progress); /** * Remove custom icon diff --git a/core/src/main/java/ch/cyberduck/core/transfer/TransferProgress.java b/core/src/main/java/ch/cyberduck/core/transfer/TransferProgress.java index 39ab6b1f11e..b9abedf52e9 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/TransferProgress.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/TransferProgress.java @@ -17,6 +17,8 @@ * Bug fixes, suggestions and comments should be sent to feedback@cyberduck.ch */ +import org.apache.commons.lang3.StringUtils; + public final class TransferProgress { private final Long size; @@ -25,6 +27,13 @@ public final class TransferProgress { private final String progress; private final Double speed; + public TransferProgress(final Long size, final Long transferred) { + this.size = size; + this.transferred = transferred; + this.progress = StringUtils.EMPTY; + this.speed = -1d; + } + public TransferProgress(final Long size, final Long transferred, final String progress, final Double speed) { this.size = size; this.transferred = transferred; diff --git a/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java b/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java index dc5acb6200c..877c4dc9c93 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java @@ -23,6 +23,7 @@ import ch.cyberduck.core.io.StreamListener; import ch.cyberduck.core.local.IconService; import ch.cyberduck.core.local.IconServiceFactory; +import ch.cyberduck.core.transfer.TransferProgress; import ch.cyberduck.core.transfer.TransferStatus; import java.math.BigDecimal; @@ -49,7 +50,7 @@ public void sent(final long bytes) { final BigDecimal fraction = new BigDecimal(this.getSent()).divide(new BigDecimal(status.getLength()), 1, RoundingMode.DOWN); if(fraction.multiply(BigDecimal.TEN).intValue() >= step) { // Another 10 percent of the file has been transferred - icon.set(file, new TransferStatus(status).withOffset(this.getSent())); + icon.set(file, new TransferProgress(status.getLength(), this.getSent())); step++; } } 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 1ee94f9acd7..e4218a8d02b 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 @@ -69,6 +69,7 @@ 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.TransferStatus; import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.transfer.download.DownloadFilterOptions; @@ -648,7 +649,7 @@ public NSArray namesOfPromisedFilesDroppedAtDestination(final NSURL url) { try { LocalTouchFactory.get().touch(file); if(options.icon) { - IconServiceFactory.get().set(file, new TransferStatus().withLength(0L)); + IconServiceFactory.get().set(file, new TransferProgress(0L, 0L)); } } catch(AccessDeniedException e) { From 3eae979941fb89d8a6ddce1de3c9725bfcef58d2 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 31 Aug 2022 21:29:13 +0200 Subject: [PATCH 07/21] New implementation using `NSProgress` to provide progress in Finder. Signed-off-by: David Kocher --- .../ApplicationTerminalPreferences.java | 4 +- .../core/local/FinderProgressIconService.java | 61 +++++++++++++++++++ .../preferences/ApplicationPreferences.java | 4 +- 3 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 core/dylib/src/main/java/ch/cyberduck/core/local/FinderProgressIconService.java diff --git a/cli/osx/src/main/java/ch/cyberduck/core/preferences/ApplicationTerminalPreferences.java b/cli/osx/src/main/java/ch/cyberduck/core/preferences/ApplicationTerminalPreferences.java index 73736a11f0c..5d857c84dd6 100644 --- a/cli/osx/src/main/java/ch/cyberduck/core/preferences/ApplicationTerminalPreferences.java +++ b/cli/osx/src/main/java/ch/cyberduck/core/preferences/ApplicationTerminalPreferences.java @@ -24,12 +24,12 @@ import ch.cyberduck.core.local.DisabledFilesystemBookmarkResolver; import ch.cyberduck.core.local.FileManagerWorkingDirectoryFinder; import ch.cyberduck.core.local.FinderLocal; +import ch.cyberduck.core.local.FinderProgressIconService; import ch.cyberduck.core.local.LaunchServicesApplicationFinder; import ch.cyberduck.core.local.LaunchServicesFileDescriptor; import ch.cyberduck.core.local.LaunchServicesQuarantineService; import ch.cyberduck.core.local.WorkspaceApplicationLauncher; import ch.cyberduck.core.local.WorkspaceBrowserLauncher; -import ch.cyberduck.core.local.WorkspaceIconService; import ch.cyberduck.core.local.WorkspaceSymlinkFeature; import ch.cyberduck.core.proxy.SystemConfigurationProxy; import ch.cyberduck.core.threading.AutoreleaseActionOperationBatcher; @@ -64,7 +64,7 @@ protected void setFactories() { this.setDefault("factory.sleeppreventer.class", IOKitSleepPreventer.class.getName()); this.setDefault("factory.reachability.class", SystemConfigurationReachability.class.getName()); this.setDefault("factory.quarantine.class", LaunchServicesQuarantineService.class.getName()); - this.setDefault("factory.iconservice.class", WorkspaceIconService.class.getName()); + this.setDefault("factory.iconservice.class", FinderProgressIconService.class.getName()); this.setDefault("factory.filedescriptor.class", LaunchServicesFileDescriptor.class.getName()); this.setDefault("factory.workingdirectory.class", FileManagerWorkingDirectoryFinder.class.getName()); this.setDefault("factory.symlink.class", WorkspaceSymlinkFeature.class.getName()); 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 new file mode 100644 index 00000000000..ada1aa238ea --- /dev/null +++ b/core/dylib/src/main/java/ch/cyberduck/core/local/FinderProgressIconService.java @@ -0,0 +1,61 @@ +package ch.cyberduck.core.local; + +/* + * Copyright (c) 2002-2022 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.binding.foundation.NSProgress; +import ch.cyberduck.binding.foundation.NSString; +import ch.cyberduck.binding.foundation.NSURL; +import ch.cyberduck.core.Local; +import ch.cyberduck.core.transfer.TransferProgress; +import ch.cyberduck.core.transfer.TransferStatus; + +public class FinderProgressIconService implements IconService { + + @Override + public boolean set(final Local file, final TransferProgress status) { + NSProgress progress = NSProgress.currentProgress(); + if(null == progress) { + progress = NSProgress.discreteProgressWithTotalUnitCount(status.getSize()); + progress.setKind(NSProgress.NSProgressKindFile); + progress.setCancellable(false); + progress.setPausable(false); + progress.setUserInfoObject_forKey(NSString.stringWithString(NSProgress.NSProgressFileOperationKindDownloading), NSProgress.NSProgressFileOperationKindKey); + progress.setUserInfoObject_forKey(NSURL.fileURLWithPath(file.getAbsolute()), NSProgress.NSProgressFileURLKey); + progress.publish(); + progress.becomeCurrentWithPendingUnitCount(status.getSize() - status.getTransferred()); + } + if(TransferStatus.UNKNOWN_LENGTH == status.getSize()) { + return false; + } + if(TransferStatus.UNKNOWN_LENGTH == status.getTransferred()) { + return false; + } + progress.setTotalUnitCount(status.getSize()); + progress.setCompletedUnitCount(status.getTransferred()); + return true; + } + + @Override + public boolean remove(final Local file) { + final NSProgress progress = NSProgress.currentProgress(); + if(null == progress) { + return false; + } + progress.resignCurrent(); + progress.unpublish(); + return true; + } +} diff --git a/core/dylib/src/main/java/ch/cyberduck/core/preferences/ApplicationPreferences.java b/core/dylib/src/main/java/ch/cyberduck/core/preferences/ApplicationPreferences.java index 9f37baa6aee..67326ed656d 100644 --- a/core/dylib/src/main/java/ch/cyberduck/core/preferences/ApplicationPreferences.java +++ b/core/dylib/src/main/java/ch/cyberduck/core/preferences/ApplicationPreferences.java @@ -31,6 +31,7 @@ import ch.cyberduck.core.local.FileManagerTrashFeature; import ch.cyberduck.core.local.FileManagerWorkingDirectoryFinder; import ch.cyberduck.core.local.FinderLocal; +import ch.cyberduck.core.local.FinderProgressIconService; import ch.cyberduck.core.local.LaunchServicesApplicationFinder; import ch.cyberduck.core.local.LaunchServicesFileDescriptor; import ch.cyberduck.core.local.LaunchServicesQuarantineService; @@ -38,7 +39,6 @@ import ch.cyberduck.core.local.WorkspaceApplicationBadgeLabeler; import ch.cyberduck.core.local.WorkspaceApplicationLauncher; import ch.cyberduck.core.local.WorkspaceBrowserLauncher; -import ch.cyberduck.core.local.WorkspaceIconService; import ch.cyberduck.core.local.WorkspaceRevealService; import ch.cyberduck.core.local.WorkspaceSymlinkFeature; import ch.cyberduck.core.notification.NotificationCenter; @@ -100,7 +100,7 @@ protected void setFactories() { this.setDefault("factory.watchservice.class", FSEventWatchService.class.getName()); this.setDefault("factory.editorfactory.class", FSEventWatchEditorFactory.class.getName()); this.setDefault("factory.notification.class", NotificationCenter.class.getName()); - this.setDefault("factory.iconservice.class", WorkspaceIconService.class.getName()); + this.setDefault("factory.iconservice.class", FinderProgressIconService.class.getName()); this.setDefault("factory.filedescriptor.class", LaunchServicesFileDescriptor.class.getName()); if(Factory.Platform.osversion.matches("(10|11)\\..*")) { this.setDefault("factory.schemehandler.class", LaunchServicesSchemeHandler.class.getName()); From 1562da1621eb5bc8b046e94274aa8efb6a401ff6 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 31 Aug 2022 21:45:20 +0200 Subject: [PATCH 08/21] Enable progress icon for segments. Signed-off-by: David Kocher --- .../java/ch/cyberduck/core/local/FinderProgressIconService.java | 2 +- .../main/java/ch/cyberduck/core/transfer/DownloadTransfer.java | 2 +- 2 files changed, 2 insertions(+), 2 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 ada1aa238ea..2e191638f84 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 @@ -28,7 +28,7 @@ public class FinderProgressIconService implements IconService { public boolean set(final Local file, final TransferProgress status) { NSProgress progress = NSProgress.currentProgress(); if(null == progress) { - progress = NSProgress.discreteProgressWithTotalUnitCount(status.getSize()); + progress = NSProgress.progressWithTotalUnitCount(status.getSize()); progress.setKind(NSProgress.NSProgressKindFile); progress.setCancellable(false); progress.setPausable(false); 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 aa48093cdbc..9be5b350839 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java @@ -302,7 +302,7 @@ public void transfer(final Session source, final Session destination, fina } // Transfer final Download download = source.getFeature(Download.class); - download.download(file, local, bandwidth, this.options.icon && segment.getLength() > PreferencesFactory.get().getLong("queue.download.icon.threshold") && !overall.isSegmented() ? + download.download(file, local, bandwidth, this.options.icon && segment.getLength() > PreferencesFactory.get().getLong("queue.download.icon.threshold") ? new IconUpdateStreamListener(streamListener, segment, local) : streamListener, segment, connectionCallback); } } From 0557b0f165fd91bc789e5ed58a41430aa6122972 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Sat, 23 Nov 2024 16:30:26 +0100 Subject: [PATCH 09/21] Single progress for every download segment. --- .../core/local/FinderProgressIconService.java | 19 ++++++++----------- .../core/local/WorkspaceIconService.java | 11 ++++++++--- .../core/transfer/DownloadTransfer.java | 11 +++++++++-- .../download/AbstractDownloadFilter.java | 7 ------- .../download/IconUpdateStreamListener.java | 7 ++++++- 5 files changed, 31 insertions(+), 24 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 2e191638f84..dece70de2b9 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 @@ -24,9 +24,16 @@ public class FinderProgressIconService implements IconService { + private NSProgress progress; + @Override public boolean set(final Local file, final TransferProgress status) { - NSProgress progress = NSProgress.currentProgress(); + if(TransferStatus.UNKNOWN_LENGTH == status.getSize()) { + return false; + } + if(TransferStatus.UNKNOWN_LENGTH == status.getTransferred()) { + return false; + } if(null == progress) { progress = NSProgress.progressWithTotalUnitCount(status.getSize()); progress.setKind(NSProgress.NSProgressKindFile); @@ -35,26 +42,16 @@ public boolean set(final Local file, final TransferProgress status) { progress.setUserInfoObject_forKey(NSString.stringWithString(NSProgress.NSProgressFileOperationKindDownloading), NSProgress.NSProgressFileOperationKindKey); progress.setUserInfoObject_forKey(NSURL.fileURLWithPath(file.getAbsolute()), NSProgress.NSProgressFileURLKey); progress.publish(); - progress.becomeCurrentWithPendingUnitCount(status.getSize() - status.getTransferred()); - } - if(TransferStatus.UNKNOWN_LENGTH == status.getSize()) { - return false; - } - if(TransferStatus.UNKNOWN_LENGTH == status.getTransferred()) { - return false; } - progress.setTotalUnitCount(status.getSize()); progress.setCompletedUnitCount(status.getTransferred()); return true; } @Override public boolean remove(final Local file) { - final NSProgress progress = NSProgress.currentProgress(); if(null == progress) { return false; } - progress.resignCurrent(); progress.unpublish(); return true; } 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 c7d7c41cfa7..febdc9f2203 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 @@ -21,6 +21,7 @@ import ch.cyberduck.binding.application.NSImage; import ch.cyberduck.binding.application.NSWorkspace; import ch.cyberduck.core.Local; +import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.resources.IconCacheFactory; import ch.cyberduck.core.transfer.TransferProgress; import ch.cyberduck.core.unicode.NFDNormalizer; @@ -31,7 +32,7 @@ public final class WorkspaceIconService implements IconService { private final NSWorkspace workspace = NSWorkspace.sharedWorkspace(); - protected boolean update(final Local file, final NSImage icon) { + public boolean update(final Local file, final NSImage icon) { synchronized(NSWorkspace.class) { // Specify 0 if you want to generate icons in all available icon representation formats if(workspace.setIcon_forFile_options(icon, file.getAbsolute(), new NSUInteger(0))) { @@ -44,12 +45,16 @@ protected boolean update(final Local file, final NSImage icon) { @Override public boolean set(final Local file, final TransferProgress status) { - int fraction = (int) (status.getTransferred() / (status.getTransferred() + status.getSize()) * 10); - return this.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", ++fraction))); + if(status.getSize() > PreferencesFactory.get().getLong("queue.download.icon.threshold")) { + int fraction = (int) (status.getTransferred() / (status.getTransferred() + status.getSize()) * 10); + return this.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", ++fraction))); + } + return false; } @Override public boolean remove(final Local file) { + // The Finder will display the default icon for this file type return this.update(file, null); } } 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 9be5b350839..1ffeb506ee8 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java @@ -29,6 +29,8 @@ 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; @@ -302,8 +304,13 @@ public void transfer(final Session source, final Session destination, fina } // Transfer final Download download = source.getFeature(Download.class); - download.download(file, local, bandwidth, this.options.icon && segment.getLength() > PreferencesFactory.get().getLong("queue.download.icon.threshold") ? - new IconUpdateStreamListener(streamListener, segment, local) : streamListener, segment, connectionCallback); + final IconService icon = IconServiceFactory.get(); + download.download(file, local, bandwidth, this.options.icon ? + new IconUpdateStreamListener(icon, streamListener, segment, local) : streamListener, segment, connectionCallback); + // Remove custom icon if complete + if(segment.isComplete()) { + icon.remove(local); + } } } diff --git a/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java b/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java index 0b489a739b3..0d493fd57b0 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java @@ -41,8 +41,6 @@ import ch.cyberduck.core.io.ChecksumComputeFactory; import ch.cyberduck.core.local.ApplicationLauncher; import ch.cyberduck.core.local.ApplicationLauncherFactory; -import ch.cyberduck.core.local.IconService; -import ch.cyberduck.core.local.IconServiceFactory; import ch.cyberduck.core.local.QuarantineService; import ch.cyberduck.core.local.QuarantineServiceFactory; import ch.cyberduck.core.preferences.HostPreferences; @@ -74,7 +72,6 @@ public abstract class AbstractDownloadFilter implements TransferPathFilter { private final SymlinkResolver symlinkResolver; private final QuarantineService quarantine = QuarantineServiceFactory.get(); private final ApplicationLauncher launcher = ApplicationLauncherFactory.get(); - private final IconService icon = IconServiceFactory.get(); protected final AttributesFinder attribute; protected final DownloadFilterOptions options; @@ -279,10 +276,6 @@ public void complete(final Path file, final Local local, if(file.isFile()) { // Bounce Downloads folder dock icon by sending download finished notification launcher.bounce(local); - // Remove custom icon if complete. The Finder will display the default icon for this file type - if(options.icon) { - icon.remove(local); - } if(options.quarantine || options.wherefrom) { final DescriptiveUrlBag provider = session.getFeature(UrlProvider.class).toUrl(file, EnumSet.of(DescriptiveUrl.Type.provider)).filter(DescriptiveUrl.Type.provider, DescriptiveUrl.Type.http); diff --git a/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java b/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java index 877c4dc9c93..28c91840aef 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java @@ -31,7 +31,7 @@ public class IconUpdateStreamListener extends BytecountStreamListener { - private final IconService icon = IconServiceFactory.get(); + private final IconService icon; private final TransferStatus status; private final Local file; @@ -39,7 +39,12 @@ public class IconUpdateStreamListener extends BytecountStreamListener { private int step = 0; public IconUpdateStreamListener(final StreamListener delegate, final TransferStatus status, final Local file) { + this(IconServiceFactory.get(), delegate, status, file); + } + + public IconUpdateStreamListener(final IconService icon, final StreamListener delegate, final TransferStatus status, final Local file) { super(delegate); + this.icon = icon; this.status = status; this.file = file; } From fb66ff376653ed4ca96291b4cbeb50e2ebee36a7 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Sat, 23 Nov 2024 16:47:26 +0100 Subject: [PATCH 10/21] Add mapping for new file properties. --- .../binding/foundation/NSProgress.java | 43 ++++++++++++++++++- .../core/local/FinderProgressIconService.java | 5 +-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/binding/src/main/java/ch/cyberduck/binding/foundation/NSProgress.java b/binding/src/main/java/ch/cyberduck/binding/foundation/NSProgress.java index 8004ad5ad5b..132b2142ab5 100644 --- a/binding/src/main/java/ch/cyberduck/binding/foundation/NSProgress.java +++ b/binding/src/main/java/ch/cyberduck/binding/foundation/NSProgress.java @@ -260,31 +260,72 @@ public static NSProgress currentProgress() { */ public abstract void setUserInfoObject_forKey(NSObject objectOrNil, String key); + /** + * Set this value when the kind property is NSProgressKindFile to describe the kind of file operation. + * + * @param kind The kind of file operation for the progress object. + * @since macOS 10.13+ + */ + public abstract void setFileOperationKind(String kind); + + /** + * Set this value for a progress that you publish to subscribers that register for updates using addSubscriberForFileURL:withPublishingHandler:. + * + * @param url A URL that represents the file for the current progress object. + * @since macOS 10.13+ + */ + public abstract void setFileURL(NSURL url); + + /** + * If present, NSProgress presents additional information in its localized description by setting a value in the userInfo dictionary. + * + * @param throughput A value that represents the speed of data processing, in bytes per second. + * @since macOS 10.13+ + */ + public abstract void setThroughput(NSNumber throughput); + /** * The value that indicates that the progress is tracking a file operation. * If you set this value for the progress kind, set a value in the user info dictionary for the NSProgressFileOperationKindKey. + * @since macOS 10.9+ */ public static final String NSProgressKindFile = "NSProgressKindFile"; /** * A key with a corresponding value that indicates the kind of file operation a progress object represents. + * @since macOS 10.9+ */ public static final String NSProgressFileOperationKindKey = "NSProgressFileOperationKindKey"; - public static final String NSProgressFileDownloadingSourceURLKey = "NSProgressFileDownloadingSourceURLKey"; + /** + * A key with a corresponding value that represents the file URL of a file operation for the progress object. + * + * @since macOS 10.9+ + */ public static final String NSProgressFileURLKey = "NSProgressFileURLKey"; /** * The progress is tracking a file upload operation. + * @since macOS 10.9+ */ public static final String NSProgressFileOperationKindUploading = "NSProgressFileOperationKindUploading"; /** * The progress is tracking a file download operation. + * + * @since macOS 10.9+ */ public static final String NSProgressFileOperationKindDownloading = "NSProgressFileOperationKindDownloading"; + /** + * The progress is tracking file decompression after a download. + * + * @since macOS 10.9+ + */ + public static final String NSProgressFileOperationKindDecompressingAfterDownloading = "NSProgressFileOperationKindDecompressingAfterDownloading"; /** * A key with a corresponding value that represents the time remaining, in seconds. + * @since macOS 10.9+ */ public static final String NSProgressEstimatedTimeRemainingKey = "NSProgressEstimatedTimeRemainingKey"; /** * A key with a corresponding value that indicates the speed of data processing, in bytes per second. + * @since macOS 10.9+ */ public static final String NSProgressThroughputKey = "NSProgressThroughputKey"; } 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 dece70de2b9..51ac2d4f3a1 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 @@ -16,7 +16,6 @@ */ import ch.cyberduck.binding.foundation.NSProgress; -import ch.cyberduck.binding.foundation.NSString; import ch.cyberduck.binding.foundation.NSURL; import ch.cyberduck.core.Local; import ch.cyberduck.core.transfer.TransferProgress; @@ -39,8 +38,8 @@ public boolean set(final Local file, final TransferProgress status) { progress.setKind(NSProgress.NSProgressKindFile); progress.setCancellable(false); progress.setPausable(false); - progress.setUserInfoObject_forKey(NSString.stringWithString(NSProgress.NSProgressFileOperationKindDownloading), NSProgress.NSProgressFileOperationKindKey); - progress.setUserInfoObject_forKey(NSURL.fileURLWithPath(file.getAbsolute()), NSProgress.NSProgressFileURLKey); + progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindDownloading); + progress.setFileURL(NSURL.fileURLWithPath(file.getAbsolute())); progress.publish(); } progress.setCompletedUnitCount(status.getTransferred()); From dc7e8f3e5d60bc39e33d4beb5fc92930d3bd44a6 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Sat, 23 Nov 2024 16:47:46 +0100 Subject: [PATCH 11/21] Review. --- .../java/ch/cyberduck/core/transfer/TransferProgress.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/src/main/java/ch/cyberduck/core/transfer/TransferProgress.java b/core/src/main/java/ch/cyberduck/core/transfer/TransferProgress.java index b9abedf52e9..c1451c74dbb 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/TransferProgress.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/TransferProgress.java @@ -28,10 +28,7 @@ public final class TransferProgress { private final Double speed; public TransferProgress(final Long size, final Long transferred) { - this.size = size; - this.transferred = transferred; - this.progress = StringUtils.EMPTY; - this.speed = -1d; + this(size, transferred, StringUtils.EMPTY, -1d); } public TransferProgress(final Long size, final Long transferred, final String progress, final Double speed) { From de899476a0324de525b858f44cb241f604fbf3d4 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Sun, 24 Nov 2024 12:30:33 +0100 Subject: [PATCH 12/21] Logging. --- .../core/transfer/download/AbstractDownloadFilter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java b/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java index 0d493fd57b0..f1095032093 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java @@ -175,8 +175,9 @@ public TransferStatus prepare(final Path file, final Local local, final Transfer } status.setAcl(attributes.getAcl()); if(options.segments) { - if(!session.getFeature(Read.class).offset(file)) { - log.warn("Reading with offsets not supported for {}", file); + final Read read = session.getFeature(Read.class); + if(!read.offset(file)) { + log.warn("Reading with offset not supported with {} for {}", read, file); } else { if(file.isFile()) { From aa811b9f961dbee514b48a3e48e3e2e9c52d4871 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Sun, 24 Nov 2024 12:52:29 +0100 Subject: [PATCH 13/21] Rename parameters. --- .../cyberduck/core/transfer/CopyTransfer.java | 8 +++--- .../core/transfer/DownloadTransfer.java | 8 +++--- .../cyberduck/core/transfer/SyncTransfer.java | 10 +++---- .../ch/cyberduck/core/transfer/Transfer.java | 26 +++++++++---------- .../core/transfer/UploadTransfer.java | 8 +++--- .../core/transfer/UploadTransferTest.java | 10 +++---- .../worker/ConcurrentTransferWorkerTest.java | 4 +-- .../core/worker/SingleTransferWorkerTest.java | 12 ++++----- 8 files changed, 42 insertions(+), 44 deletions(-) diff --git a/core/src/main/java/ch/cyberduck/core/transfer/CopyTransfer.java b/core/src/main/java/ch/cyberduck/core/transfer/CopyTransfer.java index a956abc53d8..d0e39abf5f3 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/CopyTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/CopyTransfer.java @@ -233,10 +233,10 @@ public void post(final Session source, final Session destination, final Ma @Override public void transfer(final Session session, final Session destination, final Path source, final Local n, final TransferOptions options, final TransferStatus overall, final TransferStatus segment, - final ConnectionCallback connectionCallback, - final ProgressListener listener, final StreamListener streamListener) throws BackgroundException { + final ConnectionCallback prompt, + final ProgressListener progress, final StreamListener listener) throws BackgroundException { log.debug("Transfer file {} with options {}", source, options); - listener.message(MessageFormat.format(LocaleFactory.localizedString("Copying {0} to {1}", "Status"), + progress.message(MessageFormat.format(LocaleFactory.localizedString("Copying {0} to {1}", "Status"), source.getName(), mapping.get(source).getName())); if(source.isDirectory()) { if(!segment.isExists()) { @@ -248,7 +248,7 @@ public void transfer(final Session session, final Session destination, fin else { // Transfer final Copy feature = new DefaultCopyFeature(session).withTarget(destination); - feature.copy(source, mapping.get(source), segment, connectionCallback, streamListener); + feature.copy(source, mapping.get(source), segment, prompt, listener); } } 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 1ffeb506ee8..461fff57d01 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java @@ -281,8 +281,8 @@ public void post(final Session source, final Session destination, final Ma @Override public void transfer(final Session source, final Session destination, final Path file, final Local local, final TransferOptions options, - final TransferStatus overall, final TransferStatus segment, final ConnectionCallback connectionCallback, - final ProgressListener listener, final StreamListener streamListener) throws BackgroundException { + final TransferStatus overall, final TransferStatus segment, final ConnectionCallback prompt, + final ProgressListener progress, final StreamListener listener) throws BackgroundException { log.debug("Transfer file {} with options {} and status {}", file, options, segment); if(file.isSymbolicLink()) { if(symlinkResolver.resolve(file)) { @@ -296,7 +296,7 @@ public void transfer(final Session source, final Session destination, fina } } if(file.isFile()) { - listener.message(MessageFormat.format(LocaleFactory.localizedString("Downloading {0}", "Status"), + progress.message(MessageFormat.format(LocaleFactory.localizedString("Downloading {0}", "Status"), file.getName())); final Local folder = local.getParent(); if(!folder.exists()) { @@ -306,7 +306,7 @@ public void transfer(final Session source, final Session destination, fina final Download download = source.getFeature(Download.class); final IconService icon = IconServiceFactory.get(); download.download(file, local, bandwidth, this.options.icon ? - new IconUpdateStreamListener(icon, streamListener, segment, local) : streamListener, segment, connectionCallback); + new IconUpdateStreamListener(icon, listener, segment, local) : listener, segment, prompt); // Remove custom icon if complete if(segment.isComplete()) { icon.remove(local); diff --git a/core/src/main/java/ch/cyberduck/core/transfer/SyncTransfer.java b/core/src/main/java/ch/cyberduck/core/transfer/SyncTransfer.java index cf1e8b5a56d..660dd63a433 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/SyncTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/SyncTransfer.java @@ -210,15 +210,15 @@ public TransferAction action(final Session source, final Session destinati @Override public void transfer(final Session source, final Session destination, final Path file, final Local local, - final TransferOptions options, final TransferStatus overall, final TransferStatus segment, final ConnectionCallback connectionCallback, - final ProgressListener progressListener, final StreamListener streamListener) throws BackgroundException { + final TransferOptions options, final TransferStatus overall, final TransferStatus segment, final ConnectionCallback prompt, + final ProgressListener progress, final StreamListener listener) throws BackgroundException { log.debug("Transfer file {} with options {}", file, options); - switch(comparison.compare(file, local, progressListener)) { + switch(comparison.compare(file, local, progress)) { case remote: - download.transfer(source, destination, file, local, options, overall, segment, connectionCallback, progressListener, streamListener); + download.transfer(source, destination, file, local, options, overall, segment, prompt, progress, listener); break; case local: - upload.transfer(source, destination, file, local, options, overall, segment, connectionCallback, progressListener, streamListener); + upload.transfer(source, destination, file, local, options, overall, segment, prompt, progress, listener); break; } } diff --git a/core/src/main/java/ch/cyberduck/core/transfer/Transfer.java b/core/src/main/java/ch/cyberduck/core/transfer/Transfer.java index 378951709ff..533c82c8f4f 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/Transfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/Transfer.java @@ -360,22 +360,20 @@ public void post(final Session source, final Session destination, final Ma /** * The actual transfer implementation * - * @param source Connection to source server of transfer - * @param destination Connection to target server of transfer - * @param file Remote file path - * @param local Local file reference - * @param options Quarantine option - * @param overall Overall transfer status - * @param segment Segment transfer status - * @param connectionCallback Prompt for alerts to user - * @param progressListener Progress messages listener - * @param streamListener Byte count listener + * @param source Connection to source server of transfer + * @param destination Connection to target server of transfer + * @param file Remote file path + * @param local Local file reference + * @param options Quarantine option + * @param overall Overall transfer status + * @param segment Segment transfer status + * @param prompt Prompt for alerts to user + * @param progress Progress messages listener + * @param listener Byte count listener */ public abstract void transfer(Session source, Session destination, Path file, Local local, - TransferOptions options, final TransferStatus overall, TransferStatus segment, - ConnectionCallback connectionCallback, - ProgressListener progressListener, - StreamListener streamListener) throws BackgroundException; + TransferOptions options, TransferStatus overall, TransferStatus segment, + ConnectionCallback prompt, ProgressListener progress, StreamListener listener) throws BackgroundException; public void start() { state = State.running; diff --git a/core/src/main/java/ch/cyberduck/core/transfer/UploadTransfer.java b/core/src/main/java/ch/cyberduck/core/transfer/UploadTransfer.java index ab5e06c8011..f690d00379d 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/UploadTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/UploadTransfer.java @@ -312,8 +312,8 @@ public void post(final Session source, final Session destination, final Ma @Override public void transfer(final Session source, final Session destination, final Path file, final Local local, final TransferOptions options, - final TransferStatus overall, final TransferStatus segment, final ConnectionCallback connectionCallback, - final ProgressListener listener, final StreamListener streamListener) throws BackgroundException { + final TransferStatus overall, final TransferStatus segment, final ConnectionCallback prompt, + final ProgressListener progress, final StreamListener listener) throws BackgroundException { log.debug("Transfer file {} with options {} and status {}", file, options, segment); if(local.isSymbolicLink()) { final Symlink feature = source.getFeature(Symlink.class); @@ -329,11 +329,11 @@ public void transfer(final Session source, final Session destination, fina } } if(file.isFile()) { - listener.message(MessageFormat.format(LocaleFactory.localizedString("Uploading {0}", "Status"), + progress.message(MessageFormat.format(LocaleFactory.localizedString("Uploading {0}", "Status"), file.getName())); // Transfer final Upload upload = source.getFeature(Upload.class); - final Object reply = upload.upload(file, local, bandwidth, streamListener, segment, connectionCallback); + final Object reply = upload.upload(file, local, bandwidth, listener, segment, prompt); } } diff --git a/core/src/test/java/ch/cyberduck/core/transfer/UploadTransferTest.java b/core/src/test/java/ch/cyberduck/core/transfer/UploadTransferTest.java index 9f07d311f65..5e3b388e98d 100755 --- a/core/src/test/java/ch/cyberduck/core/transfer/UploadTransferTest.java +++ b/core/src/test/java/ch/cyberduck/core/transfer/UploadTransferTest.java @@ -160,8 +160,8 @@ public AttributedList list(final Path folder, final ListProgressListener l @Override public void transfer(final Session source, final Session destination, final Path file, Local local, final TransferOptions options, final TransferStatus overall, final TransferStatus segment, - final ConnectionCallback connectionCallback, - final ProgressListener listener, final StreamListener streamListener) { + final ConnectionCallback prompt, + final ProgressListener progress, final StreamListener listener) { assertTrue(options.resumeRequested); } }.withCache(cache); @@ -246,8 +246,8 @@ public AttributedList list(final Path folder, final ListProgressListener l @Override public void transfer(final Session source, final Session destination, final Path file, Local local, final TransferOptions options, final TransferStatus overall, final TransferStatus segment, - final ConnectionCallback connectionCallback, - final ProgressListener listener, final StreamListener streamListener) { + final ConnectionCallback prompt, + final ProgressListener progress, final StreamListener listener) { // } }.withCache(cache); @@ -415,7 +415,7 @@ public StatusOutputStream write(final Path file, final TransferStatus status, fi @Override public void transfer(final Session source, final Session destination, final Path file, Local local, final TransferOptions options, final TransferStatus overall, final TransferStatus segment, - final ConnectionCallback connectionCallback, final ProgressListener listener, final StreamListener streamListener) { + final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) { segment.setComplete(); set.set(true); } diff --git a/core/src/test/java/ch/cyberduck/core/worker/ConcurrentTransferWorkerTest.java b/core/src/test/java/ch/cyberduck/core/worker/ConcurrentTransferWorkerTest.java index 557078f8fa0..7b5fc2cae64 100644 --- a/core/src/test/java/ch/cyberduck/core/worker/ConcurrentTransferWorkerTest.java +++ b/core/src/test/java/ch/cyberduck/core/worker/ConcurrentTransferWorkerTest.java @@ -153,8 +153,8 @@ public void testConcurrentSessions() throws Exception { @Override public void transfer(final Session source, final Session destination, final Path file, final Local local, final TransferOptions options, final TransferStatus overall, final TransferStatus segment, - final ConnectionCallback connectionCallback, - final ProgressListener listener, final StreamListener streamListener) { + final ConnectionCallback prompt, + final ProgressListener progress, final StreamListener listener) { assertNotNull(source); transferred.add(file); } diff --git a/core/src/test/java/ch/cyberduck/core/worker/SingleTransferWorkerTest.java b/core/src/test/java/ch/cyberduck/core/worker/SingleTransferWorkerTest.java index ae819adec8a..074c7f728bd 100644 --- a/core/src/test/java/ch/cyberduck/core/worker/SingleTransferWorkerTest.java +++ b/core/src/test/java/ch/cyberduck/core/worker/SingleTransferWorkerTest.java @@ -71,8 +71,8 @@ public boolean exists() { @Override public void transfer(final Session source, final Session destination, final Path file, Local local, final TransferOptions options, final TransferStatus overall, final TransferStatus segment, - final ConnectionCallback connectionCallback, - final ProgressListener listener, final StreamListener streamListener) { + final ConnectionCallback prompt, + final ProgressListener progress, final StreamListener listener) { // } }; @@ -131,8 +131,8 @@ public boolean exists() { @Override public void transfer(final Session source, final Session destination, final Path file, Local local, final TransferOptions options, final TransferStatus overall, final TransferStatus segment, - final ConnectionCallback connectionCallback, - final ProgressListener listener, final StreamListener streamListener) { + final ConnectionCallback prompt, + final ProgressListener progress, final StreamListener listener) { if(file.equals(root)) { assertTrue(segment.isExists()); } @@ -201,8 +201,8 @@ public AttributedList list() { @Override public void transfer(final Session source, final Session destination, final Path file, Local local, final TransferOptions options, final TransferStatus overall, final TransferStatus segment, - final ConnectionCallback connectionCallback, - final ProgressListener listener, final StreamListener streamListener) { + final ConnectionCallback prompt, + final ProgressListener progress, final StreamListener listener) { if(file.equals(root)) { assertTrue(segment.isExists()); } From e0f8c69bce395b358942051a99b7bc80f894abdc Mon Sep 17 00:00:00 2001 From: David Kocher Date: Sun, 24 Nov 2024 12:57:55 +0100 Subject: [PATCH 14/21] Rename parameter. --- .../core/local/FinderProgressIconService.java | 24 +++++++++---------- .../core/local/WorkspaceIconService.java | 6 ++--- 2 files changed, 15 insertions(+), 15 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 51ac2d4f3a1..412ea9771b6 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 @@ -26,23 +26,23 @@ public class FinderProgressIconService implements IconService { private NSProgress progress; @Override - public boolean set(final Local file, final TransferProgress status) { - if(TransferStatus.UNKNOWN_LENGTH == status.getSize()) { + public boolean set(final Local file, final TransferProgress progress) { + if(TransferStatus.UNKNOWN_LENGTH == progress.getSize()) { return false; } - if(TransferStatus.UNKNOWN_LENGTH == status.getTransferred()) { + if(TransferStatus.UNKNOWN_LENGTH == progress.getTransferred()) { return false; } - if(null == progress) { - progress = NSProgress.progressWithTotalUnitCount(status.getSize()); - progress.setKind(NSProgress.NSProgressKindFile); - progress.setCancellable(false); - progress.setPausable(false); - progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindDownloading); - progress.setFileURL(NSURL.fileURLWithPath(file.getAbsolute())); - progress.publish(); + if(null == this.progress) { + this.progress = NSProgress.progressWithTotalUnitCount(progress.getSize()); + this.progress.setKind(NSProgress.NSProgressKindFile); + this.progress.setCancellable(false); + this.progress.setPausable(false); + this.progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindDownloading); + this.progress.setFileURL(NSURL.fileURLWithPath(file.getAbsolute())); + this.progress.publish(); } - progress.setCompletedUnitCount(status.getTransferred()); + this.progress.setCompletedUnitCount(progress.getTransferred()); return true; } 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 febdc9f2203..d92f23829c7 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 @@ -44,9 +44,9 @@ public boolean update(final Local file, final NSImage icon) { } @Override - public boolean set(final Local file, final TransferProgress status) { - if(status.getSize() > PreferencesFactory.get().getLong("queue.download.icon.threshold")) { - int fraction = (int) (status.getTransferred() / (status.getTransferred() + status.getSize()) * 10); + public boolean set(final Local file, final TransferProgress progress) { + if(progress.getSize() > PreferencesFactory.get().getLong("queue.download.icon.threshold")) { + int fraction = (int) (progress.getTransferred() / (progress.getTransferred() + progress.getSize()) * 10); return this.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", ++fraction))); } return false; From f1a0ff9453469b82a5196d53927afeb54d9e0e11 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Sun, 24 Nov 2024 13:40:24 +0100 Subject: [PATCH 15/21] Move implementation specific details to determine progress icon filename. --- .../core/local/WorkspaceIconService.java | 23 +++++++++++------- .../core/transfer/DownloadTransfer.java | 4 ++-- ...er.java => IconServiceStreamListener.java} | 24 ++++--------------- 3 files changed, 21 insertions(+), 30 deletions(-) rename core/src/main/java/ch/cyberduck/core/transfer/download/{IconUpdateStreamListener.java => IconServiceStreamListener.java} (56%) 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 d92f23829c7..e07d22d45d4 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 @@ -1,21 +1,18 @@ package ch.cyberduck.core.local; /* - * Copyright (c) 2012 David Kocher. All rights reserved. - * http://cyberduck.ch/ + * Copyright (c) 2002-2024 iterate GmbH. All rights reserved. + * https://cyberduck.io/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * Bug fixes, suggestions and comments should be sent to: - * dkocher@cyberduck.ch */ import ch.cyberduck.binding.application.NSImage; @@ -28,10 +25,16 @@ import org.rococoa.cocoa.foundation.NSUInteger; +import java.math.BigDecimal; +import java.math.RoundingMode; + public final class WorkspaceIconService implements IconService { private final NSWorkspace workspace = NSWorkspace.sharedWorkspace(); + // An integer between 0 and 9 + private int step = 0; + public boolean update(final Local file, final NSImage icon) { synchronized(NSWorkspace.class) { // Specify 0 if you want to generate icons in all available icon representation formats @@ -46,8 +49,12 @@ public boolean update(final Local file, final NSImage icon) { @Override public boolean set(final Local file, final TransferProgress progress) { if(progress.getSize() > PreferencesFactory.get().getLong("queue.download.icon.threshold")) { - int fraction = (int) (progress.getTransferred() / (progress.getTransferred() + progress.getSize()) * 10); - return this.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", ++fraction))); + 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 this.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", step = fraction))); + } + return false; } return false; } 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 461fff57d01..6bd6f1efa0a 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java @@ -39,7 +39,7 @@ 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.IconUpdateStreamListener; +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; @@ -306,7 +306,7 @@ public void transfer(final Session source, final Session destination, fina final Download download = source.getFeature(Download.class); final IconService icon = IconServiceFactory.get(); download.download(file, local, bandwidth, this.options.icon ? - new IconUpdateStreamListener(icon, listener, segment, local) : listener, segment, prompt); + new IconServiceStreamListener(icon, listener, segment, local) : listener, segment, prompt); // Remove custom icon if complete if(segment.isComplete()) { icon.remove(local); diff --git a/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java b/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java similarity index 56% rename from core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java rename to core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java index 28c91840aef..24f9e0f7539 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java @@ -18,31 +18,20 @@ * feedback@cyberduck.ch */ -import ch.cyberduck.core.BytecountStreamListener; import ch.cyberduck.core.Local; +import ch.cyberduck.core.io.DelegateStreamListener; import ch.cyberduck.core.io.StreamListener; import ch.cyberduck.core.local.IconService; -import ch.cyberduck.core.local.IconServiceFactory; import ch.cyberduck.core.transfer.TransferProgress; import ch.cyberduck.core.transfer.TransferStatus; -import java.math.BigDecimal; -import java.math.RoundingMode; - -public class IconUpdateStreamListener extends BytecountStreamListener { +public class IconServiceStreamListener extends DelegateStreamListener { private final IconService icon; private final TransferStatus status; private final Local file; - // An integer between 0 and 9 - private int step = 0; - - public IconUpdateStreamListener(final StreamListener delegate, final TransferStatus status, final Local file) { - this(IconServiceFactory.get(), delegate, status, file); - } - - public IconUpdateStreamListener(final IconService icon, final StreamListener delegate, final TransferStatus status, final Local file) { + public IconServiceStreamListener(final IconService icon, final StreamListener delegate, final TransferStatus status, final Local file) { super(delegate); this.icon = icon; this.status = status; @@ -52,11 +41,6 @@ public IconUpdateStreamListener(final IconService icon, final StreamListener del @Override public void sent(final long bytes) { super.sent(bytes); - final BigDecimal fraction = new BigDecimal(this.getSent()).divide(new BigDecimal(status.getLength()), 1, RoundingMode.DOWN); - if(fraction.multiply(BigDecimal.TEN).intValue() >= step) { - // Another 10 percent of the file has been transferred - icon.set(file, new TransferProgress(status.getLength(), this.getSent())); - step++; - } + icon.set(file, new TransferProgress(status.getLength(), bytes)); } } From 473bb38c4c1fd776b64ff1b518733d7bcbb67bd5 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Mon, 25 Nov 2024 11:39:05 +0100 Subject: [PATCH 16/21] Refactor to not handle state in service. --- .../core/local/FinderProgressIconService.java | 56 ++++++++++--------- .../core/local/WorkspaceIconService.java | 51 +++++++++-------- .../core/local/WorkspaceIconServiceTest.java | 27 ++------- .../core/local/DisabledIconService.java | 20 +++++-- .../ch/cyberduck/core/local/IconService.java | 29 ++++++---- .../core/proxy/DisabledProxyFinder.java | 1 + .../core/transfer/DownloadTransfer.java | 6 +- .../download/IconServiceStreamListener.java | 13 ++--- .../datasource/BrowserTableDataSource.java | 3 +- .../ch/cyberduck/core/s3/S3UrlProvider.java | 2 +- 10 files changed, 109 insertions(+), 99 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 412ea9771b6..139ef603c5a 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 @@ -23,35 +23,41 @@ public class FinderProgressIconService implements IconService { - private NSProgress progress; - @Override - public boolean set(final Local file, final TransferProgress progress) { - if(TransferStatus.UNKNOWN_LENGTH == progress.getSize()) { - return false; - } - if(TransferStatus.UNKNOWN_LENGTH == progress.getTransferred()) { - return false; + public Icon get(final Local file) { + return new FinderProgressIcon(file); + } + + private static final class FinderProgressIcon implements Icon { + private final NSProgress progress; + + public FinderProgressIcon(final Local file) { + progress = NSProgress.discreteProgressWithTotalUnitCount(0L); + progress.setKind(NSProgress.NSProgressKindFile); + progress.setCancellable(false); + progress.setPausable(false); + progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindDownloading); + progress.setFileURL(NSURL.fileURLWithPath(file.getAbsolute())); + progress.publish(); } - if(null == this.progress) { - this.progress = NSProgress.progressWithTotalUnitCount(progress.getSize()); - this.progress.setKind(NSProgress.NSProgressKindFile); - this.progress.setCancellable(false); - this.progress.setPausable(false); - this.progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindDownloading); - this.progress.setFileURL(NSURL.fileURLWithPath(file.getAbsolute())); - this.progress.publish(); + + @Override + public boolean update(final TransferProgress status) { + if(TransferStatus.UNKNOWN_LENGTH == status.getSize()) { + return false; + } + if(TransferStatus.UNKNOWN_LENGTH == status.getTransferred()) { + return false; + } + progress.setTotalUnitCount(status.getSize()); + progress.setCompletedUnitCount(status.getTransferred()); + return true; } - this.progress.setCompletedUnitCount(progress.getTransferred()); - return true; - } - @Override - public boolean remove(final Local file) { - if(null == progress) { - return false; + @Override + public boolean remove() { + progress.unpublish(); + return true; } - progress.unpublish(); - return true; } } 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 e07d22d45d4..df579db94c1 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 @@ -30,12 +30,36 @@ public final class WorkspaceIconService implements IconService { - private final NSWorkspace workspace = NSWorkspace.sharedWorkspace(); + private static final NSWorkspace workspace = NSWorkspace.sharedWorkspace(); - // An integer between 0 and 9 - private int step = 0; + @Override + public Icon get(final Local file) { + 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))); + } + return false; + } + return false; + } + + @Override + public boolean remove() { + // The Finder will display the default icon for this file type + return WorkspaceIconService.update(file, null); + } + }; + } - public boolean update(final Local file, final NSImage icon) { + public static boolean update(final Local file, final NSImage icon) { synchronized(NSWorkspace.class) { // Specify 0 if you want to generate icons in all available icon representation formats if(workspace.setIcon_forFile_options(icon, file.getAbsolute(), new NSUInteger(0))) { @@ -45,23 +69,4 @@ public boolean update(final Local file, final NSImage icon) { return false; } } - - @Override - public boolean set(final Local file, 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 this.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", step = fraction))); - } - return false; - } - return false; - } - - @Override - public boolean remove(final Local file) { - // The Finder will display the default icon for this file type - return this.update(file, null); - } } diff --git a/core/dylib/src/test/java/ch/cyberduck/core/local/WorkspaceIconServiceTest.java b/core/dylib/src/test/java/ch/cyberduck/core/local/WorkspaceIconServiceTest.java index c705dd0a5c0..5cdf3d4eeb1 100644 --- a/core/dylib/src/test/java/ch/cyberduck/core/local/WorkspaceIconServiceTest.java +++ b/core/dylib/src/test/java/ch/cyberduck/core/local/WorkspaceIconServiceTest.java @@ -28,42 +28,27 @@ public class WorkspaceIconServiceTest { @Test - public void testSetProgressNoFile() { - final WorkspaceIconService s = new WorkspaceIconService(); + public void testUpdateProgressNoFile() { final Local file = new Local(PreferencesFactory.get().getProperty("tmp.dir"), UUID.randomUUID().toString()); - assertFalse(s.update(file, NSImage.imageWithContentsOfFile("../../img/download0.icns"))); + assertFalse(WorkspaceIconService.update(file, NSImage.imageWithContentsOfFile("../../img/download0.icns"))); } @Test - public void testSetProgressFolder() throws Exception { - final WorkspaceIconService s = new WorkspaceIconService(); + public void testUpdateProgressFolder() throws Exception { final Local file = new Local(PreferencesFactory.get().getProperty("tmp.dir"), UUID.randomUUID().toString()); new DefaultLocalDirectoryFeature().mkdir(file); - assertTrue(s.update(file, NSImage.imageWithContentsOfFile("../../img/download0.icns"))); + assertTrue(WorkspaceIconService.update(file, NSImage.imageWithContentsOfFile("../../img/download0.icns"))); } @Test - public void testSetProgress() throws Exception { - final WorkspaceIconService s = new WorkspaceIconService(); + public void testUpdateProgress() throws Exception { final Local file = new Local(PreferencesFactory.get().getProperty("tmp.dir"), UUID.randomUUID().toString()); - LocalTouchFactory.get().touch(file); - assertTrue(s.update(file, NSImage.imageWithContentsOfFile("../../img/download0.icns"))); - file.delete(); - } - - @Test - public void testRemove() throws Exception { final WorkspaceIconService s = new WorkspaceIconService(); - final Local file = new Local(PreferencesFactory.get().getProperty("tmp.dir"), - UUID.randomUUID().toString()); - assertFalse(s.remove(file)); LocalTouchFactory.get().touch(file); - assertFalse(s.remove(file)); - assertTrue(s.update(file, NSImage.imageWithContentsOfFile("../../img/download0.icns"))); - assertTrue(s.remove(file)); + assertTrue(WorkspaceIconService.update(file, NSImage.imageWithContentsOfFile("../../img/download0.icns"))); file.delete(); } } 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 67b864440f2..7ac53f525d3 100644 --- a/core/src/main/java/ch/cyberduck/core/local/DisabledIconService.java +++ b/core/src/main/java/ch/cyberduck/core/local/DisabledIconService.java @@ -22,13 +22,21 @@ import ch.cyberduck.core.transfer.TransferProgress; public final class DisabledIconService implements IconService { - @Override - public boolean set(final Local file, final TransferProgress progress) { - return false; - } + + private static final Icon disabled = new Icon() { + @Override + public boolean update(final TransferProgress progress) { + return false; + } + + @Override + public boolean remove() { + return false; + } + }; @Override - public boolean remove(final Local file) { - return false; + public Icon get(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 88739c999e4..adc04beb1d7 100644 --- a/core/src/main/java/ch/cyberduck/core/local/IconService.java +++ b/core/src/main/java/ch/cyberduck/core/local/IconService.java @@ -22,18 +22,27 @@ import ch.cyberduck.core.transfer.TransferProgress; public interface IconService { - /** - * @param file File - * @param progress Transfer status with transferred bytes set in offset - * @return True if icon is set - */ - boolean set(Local file, TransferProgress progress); /** - * Remove custom icon + * Get icon updater to track progress * - * @param file File - * @return True if icon is set + * @param file Local file + * @return Updater to send continious progress updates to */ - boolean remove(Local file); + Icon get(Local file); + + interface Icon { + /** + * @param progress Transfer status with transferred bytes set in offset + * @return True if icon is set + */ + boolean update(TransferProgress progress); + + /** + * Remove custom icon + * + * @return True if icon is set + */ + boolean remove(); + } } diff --git a/core/src/main/java/ch/cyberduck/core/proxy/DisabledProxyFinder.java b/core/src/main/java/ch/cyberduck/core/proxy/DisabledProxyFinder.java index b4fe1bbd0b7..6958a238ec0 100644 --- a/core/src/main/java/ch/cyberduck/core/proxy/DisabledProxyFinder.java +++ b/core/src/main/java/ch/cyberduck/core/proxy/DisabledProxyFinder.java @@ -22,5 +22,6 @@ public class DisabledProxyFinder implements ProxyFinder { @Override public Proxy find(final String target) { return Proxy.DIRECT; +// return new Proxy(Proxy.Type.HTTPS, "127.0.0.1", 9090); } } 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 6bd6f1efa0a..e57ba412e77 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java @@ -304,12 +304,12 @@ public void transfer(final Session source, final Session destination, fina } // Transfer final Download download = source.getFeature(Download.class); - final IconService icon = IconServiceFactory.get(); + final IconService.Icon icon = IconServiceFactory.get().get(local); download.download(file, local, bandwidth, this.options.icon ? - new IconServiceStreamListener(icon, listener, segment, local) : listener, segment, prompt); + new IconServiceStreamListener(icon, listener, segment) : listener, segment, prompt); // Remove custom icon if complete if(segment.isComplete()) { - icon.remove(local); + icon.remove(); } } } diff --git a/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java b/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java index 24f9e0f7539..5db9263e7f1 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java @@ -18,29 +18,26 @@ * feedback@cyberduck.ch */ -import ch.cyberduck.core.Local; -import ch.cyberduck.core.io.DelegateStreamListener; +import ch.cyberduck.core.BytecountStreamListener; import ch.cyberduck.core.io.StreamListener; import ch.cyberduck.core.local.IconService; import ch.cyberduck.core.transfer.TransferProgress; import ch.cyberduck.core.transfer.TransferStatus; -public class IconServiceStreamListener extends DelegateStreamListener { +public class IconServiceStreamListener extends BytecountStreamListener { - private final IconService icon; + private final IconService.Icon icon; private final TransferStatus status; - private final Local file; - public IconServiceStreamListener(final IconService icon, final StreamListener delegate, final TransferStatus status, final Local file) { + public IconServiceStreamListener(final IconService.Icon icon, final StreamListener delegate, final TransferStatus status) { super(delegate); this.icon = icon; this.status = status; - this.file = file; } @Override public void sent(final long bytes) { super.sent(bytes); - icon.set(file, new TransferProgress(status.getLength(), bytes)); + icon.update(new TransferProgress(status.getLength(), this.getSent())); } } 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 e4218a8d02b..456e1337c64 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 @@ -70,7 +70,6 @@ import ch.cyberduck.core.transfer.Transfer; import ch.cyberduck.core.transfer.TransferItem; import ch.cyberduck.core.transfer.TransferProgress; -import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.transfer.download.DownloadFilterOptions; import ch.cyberduck.ui.browser.BrowserColumn; @@ -649,7 +648,7 @@ public NSArray namesOfPromisedFilesDroppedAtDestination(final NSURL url) { try { LocalTouchFactory.get().touch(file); if(options.icon) { - IconServiceFactory.get().set(file, new TransferProgress(0L, 0L)); + IconServiceFactory.get().get(file).update(new TransferProgress(0L, 0L)); } } catch(AccessDeniedException e) { diff --git a/s3/src/main/java/ch/cyberduck/core/s3/S3UrlProvider.java b/s3/src/main/java/ch/cyberduck/core/s3/S3UrlProvider.java index 63ceee9ae78..d4ee6719572 100644 --- a/s3/src/main/java/ch/cyberduck/core/s3/S3UrlProvider.java +++ b/s3/src/main/java/ch/cyberduck/core/s3/S3UrlProvider.java @@ -206,7 +206,7 @@ public String getUrl() { secret = store.findLoginPassword(session.getHost()); } if(StringUtils.isBlank(secret)) { - log.warn("No secret found in password store required to sign temporary URL"); + log.error("No secret found in password store required to sign temporary URL"); return DescriptiveUrl.EMPTY.getUrl(); } String region = session.getHost().getRegion(); From 56a099e766ea6d952af0e670fc3fb4c9dfc35f31 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Mon, 25 Nov 2024 22:08:24 +0100 Subject: [PATCH 17/21] Add shortcut. --- .../java/ch/cyberduck/core/local/IconServiceFactory.java | 5 +++++ .../java/ch/cyberduck/core/transfer/DownloadTransfer.java | 2 +- .../ui/cocoa/datasource/BrowserTableDataSource.java | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) 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 5f97f08f633..1b69b4648e5 100644 --- a/core/src/main/java/ch/cyberduck/core/local/IconServiceFactory.java +++ b/core/src/main/java/ch/cyberduck/core/local/IconServiceFactory.java @@ -19,6 +19,7 @@ */ import ch.cyberduck.core.Factory; +import ch.cyberduck.core.Local; public class IconServiceFactory extends Factory { @@ -29,4 +30,8 @@ private IconServiceFactory() { public static IconService get() { return new IconServiceFactory().create(); } + + public static IconService.Icon iconFor(final Local file) { + return get().get(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 e57ba412e77..6a50f07b9d3 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java @@ -304,7 +304,7 @@ public void transfer(final Session source, final Session destination, fina } // Transfer final Download download = source.getFeature(Download.class); - final IconService.Icon icon = IconServiceFactory.get().get(local); + final IconService.Icon icon = IconServiceFactory.iconFor(local); download.download(file, local, bandwidth, this.options.icon ? new IconServiceStreamListener(icon, listener, segment) : listener, segment, prompt); // Remove custom icon if complete 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 456e1337c64..29777e27bef 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 @@ -648,7 +648,7 @@ public NSArray namesOfPromisedFilesDroppedAtDestination(final NSURL url) { try { LocalTouchFactory.get().touch(file); if(options.icon) { - IconServiceFactory.get().get(file).update(new TransferProgress(0L, 0L)); + IconServiceFactory.iconFor(file).update(new TransferProgress(0L, 0L)); } } catch(AccessDeniedException e) { From 7137aa6660903dcca2e1c5b357016f51a54d5e51 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Mon, 25 Nov 2024 22:22:46 +0100 Subject: [PATCH 18/21] Remove unused parameter. --- .../main/java/ch/cyberduck/core/transfer/CopyTransfer.java | 2 +- .../java/ch/cyberduck/core/transfer/DownloadTransfer.java | 2 +- .../main/java/ch/cyberduck/core/transfer/SyncTransfer.java | 6 +++--- core/src/main/java/ch/cyberduck/core/transfer/Transfer.java | 5 ++--- .../java/ch/cyberduck/core/transfer/UploadTransfer.java | 2 +- .../ch/cyberduck/core/worker/AbstractTransferWorker.java | 2 +- .../java/ch/cyberduck/core/transfer/UploadTransferTest.java | 6 +++--- .../cyberduck/core/worker/ConcurrentTransferWorkerTest.java | 2 +- .../ch/cyberduck/core/worker/SingleTransferWorkerTest.java | 6 +++--- 9 files changed, 16 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/ch/cyberduck/core/transfer/CopyTransfer.java b/core/src/main/java/ch/cyberduck/core/transfer/CopyTransfer.java index d0e39abf5f3..2365f8f8c65 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/CopyTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/CopyTransfer.java @@ -232,7 +232,7 @@ public void post(final Session source, final Session destination, final Ma @Override public void transfer(final Session session, final Session destination, final Path source, final Local n, - final TransferOptions options, final TransferStatus overall, final TransferStatus segment, + final TransferOptions options, final TransferStatus segment, final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) throws BackgroundException { log.debug("Transfer file {} with options {}", source, options); 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 6a50f07b9d3..cd71cdacb18 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java @@ -281,7 +281,7 @@ public void post(final Session source, final Session destination, final Ma @Override public void transfer(final Session source, final Session destination, final Path file, final Local local, final TransferOptions options, - final TransferStatus overall, final TransferStatus segment, final ConnectionCallback prompt, + final TransferStatus segment, final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) throws BackgroundException { log.debug("Transfer file {} with options {} and status {}", file, options, segment); if(file.isSymbolicLink()) { diff --git a/core/src/main/java/ch/cyberduck/core/transfer/SyncTransfer.java b/core/src/main/java/ch/cyberduck/core/transfer/SyncTransfer.java index 660dd63a433..89b077651d6 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/SyncTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/SyncTransfer.java @@ -210,15 +210,15 @@ public TransferAction action(final Session source, final Session destinati @Override public void transfer(final Session source, final Session destination, final Path file, final Local local, - final TransferOptions options, final TransferStatus overall, final TransferStatus segment, final ConnectionCallback prompt, + final TransferOptions options, final TransferStatus segment, final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) throws BackgroundException { log.debug("Transfer file {} with options {}", file, options); switch(comparison.compare(file, local, progress)) { case remote: - download.transfer(source, destination, file, local, options, overall, segment, prompt, progress, listener); + download.transfer(source, destination, file, local, options, segment, prompt, progress, listener); break; case local: - upload.transfer(source, destination, file, local, options, overall, segment, prompt, progress, listener); + upload.transfer(source, destination, file, local, options, segment, prompt, progress, listener); break; } } diff --git a/core/src/main/java/ch/cyberduck/core/transfer/Transfer.java b/core/src/main/java/ch/cyberduck/core/transfer/Transfer.java index 533c82c8f4f..131f6719c57 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/Transfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/Transfer.java @@ -365,14 +365,13 @@ public void post(final Session source, final Session destination, final Ma * @param file Remote file path * @param local Local file reference * @param options Quarantine option - * @param overall Overall transfer status * @param segment Segment transfer status * @param prompt Prompt for alerts to user * @param progress Progress messages listener - * @param listener Byte count listener + * @param listener Byte count listener */ public abstract void transfer(Session source, Session destination, Path file, Local local, - TransferOptions options, TransferStatus overall, TransferStatus segment, + TransferOptions options, TransferStatus segment, ConnectionCallback prompt, ProgressListener progress, StreamListener listener) throws BackgroundException; public void start() { diff --git a/core/src/main/java/ch/cyberduck/core/transfer/UploadTransfer.java b/core/src/main/java/ch/cyberduck/core/transfer/UploadTransfer.java index f690d00379d..a80db4aa006 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/UploadTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/UploadTransfer.java @@ -312,7 +312,7 @@ public void post(final Session source, final Session destination, final Ma @Override public void transfer(final Session source, final Session destination, final Path file, final Local local, final TransferOptions options, - final TransferStatus overall, final TransferStatus segment, final ConnectionCallback prompt, + final TransferStatus segment, final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) throws BackgroundException { log.debug("Transfer file {} with options {} and status {}", file, options, segment); if(local.isSymbolicLink()) { 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 864c9ba14f9..8c79edc151e 100644 --- a/core/src/main/java/ch/cyberduck/core/worker/AbstractTransferWorker.java +++ b/core/src/main/java/ch/cyberduck/core/worker/AbstractTransferWorker.java @@ -385,7 +385,7 @@ private void transferSegment(final TransferStatus segment) throws BackgroundExce transfer.transfer(s, d, segment.getRename().remote != null ? segment.getRename().remote : item.remote, segment.getRename().local != null ? segment.getRename().local : item.local, - options, status, segment, connect, progress, counter); + options, segment, connect, progress, counter); } catch(BackgroundException e) { release(s, Connection.source, e); diff --git a/core/src/test/java/ch/cyberduck/core/transfer/UploadTransferTest.java b/core/src/test/java/ch/cyberduck/core/transfer/UploadTransferTest.java index 5e3b388e98d..03395c1b90d 100755 --- a/core/src/test/java/ch/cyberduck/core/transfer/UploadTransferTest.java +++ b/core/src/test/java/ch/cyberduck/core/transfer/UploadTransferTest.java @@ -159,7 +159,7 @@ public AttributedList list(final Path folder, final ListProgressListener l final Transfer t = new UploadTransfer(new Host(new TestProtocol()), root, local) { @Override public void transfer(final Session source, final Session destination, final Path file, Local local, - final TransferOptions options, final TransferStatus overall, final TransferStatus segment, + final TransferOptions options, final TransferStatus segment, final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) { assertTrue(options.resumeRequested); @@ -245,7 +245,7 @@ public AttributedList list(final Path folder, final ListProgressListener l final Transfer t = new UploadTransfer(new Host(new TestProtocol()), root, local) { @Override public void transfer(final Session source, final Session destination, final Path file, Local local, - final TransferOptions options, final TransferStatus overall, final TransferStatus segment, + final TransferOptions options, final TransferStatus segment, final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) { // @@ -414,7 +414,7 @@ public StatusOutputStream write(final Path file, final TransferStatus status, fi final Transfer transfer = new UploadTransfer(host, test, local) { @Override public void transfer(final Session source, final Session destination, final Path file, Local local, - final TransferOptions options, final TransferStatus overall, final TransferStatus segment, + final TransferOptions options, final TransferStatus segment, final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) { segment.setComplete(); set.set(true); diff --git a/core/src/test/java/ch/cyberduck/core/worker/ConcurrentTransferWorkerTest.java b/core/src/test/java/ch/cyberduck/core/worker/ConcurrentTransferWorkerTest.java index 7b5fc2cae64..a2eea07d650 100644 --- a/core/src/test/java/ch/cyberduck/core/worker/ConcurrentTransferWorkerTest.java +++ b/core/src/test/java/ch/cyberduck/core/worker/ConcurrentTransferWorkerTest.java @@ -152,7 +152,7 @@ public void testConcurrentSessions() throws Exception { @Override public void transfer(final Session source, final Session destination, final Path file, final Local local, - final TransferOptions options, final TransferStatus overall, final TransferStatus segment, + final TransferOptions options, final TransferStatus segment, final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) { assertNotNull(source); diff --git a/core/src/test/java/ch/cyberduck/core/worker/SingleTransferWorkerTest.java b/core/src/test/java/ch/cyberduck/core/worker/SingleTransferWorkerTest.java index 074c7f728bd..35ee3185007 100644 --- a/core/src/test/java/ch/cyberduck/core/worker/SingleTransferWorkerTest.java +++ b/core/src/test/java/ch/cyberduck/core/worker/SingleTransferWorkerTest.java @@ -70,7 +70,7 @@ public boolean exists() { final Transfer t = new UploadTransfer(new Host(new TestProtocol()), root, local) { @Override public void transfer(final Session source, final Session destination, final Path file, Local local, - final TransferOptions options, final TransferStatus overall, final TransferStatus segment, + final TransferOptions options, final TransferStatus segment, final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) { // @@ -130,7 +130,7 @@ public boolean exists() { final Transfer t = new UploadTransfer(new Host(new TestProtocol()), root, local) { @Override public void transfer(final Session source, final Session destination, final Path file, Local local, - final TransferOptions options, final TransferStatus overall, final TransferStatus segment, + final TransferOptions options, final TransferStatus segment, final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) { if(file.equals(root)) { @@ -200,7 +200,7 @@ public AttributedList list() { final Transfer t = new DownloadTransfer(new Host(new TestProtocol()), root, local) { @Override public void transfer(final Session source, final Session destination, final Path file, Local local, - final TransferOptions options, final TransferStatus overall, final TransferStatus segment, + final TransferOptions options, final TransferStatus segment, final ConnectionCallback prompt, final ProgressListener progress, final StreamListener listener) { if(file.equals(root)) { From 0e9e46aa52a357dfe59ef94602e526764c7ec836 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Mon, 25 Nov 2024 23:23:17 +0100 Subject: [PATCH 19/21] Show progress on .cyberducksegment parent folder for segemented downloads. --- .../cyberduck/core/transfer/DownloadTransfer.java | 4 ++-- .../download/IconServiceStreamListener.java | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) 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 cd71cdacb18..0dcab0e0621 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java @@ -304,9 +304,9 @@ public void transfer(final Session source, final Session destination, fina } // Transfer final Download download = source.getFeature(Download.class); - final IconService.Icon icon = IconServiceFactory.iconFor(local); + final IconService.Icon icon = IconServiceFactory.iconFor(segment.isSegment() ? folder : local); download.download(file, local, bandwidth, this.options.icon ? - new IconServiceStreamListener(icon, listener, segment) : listener, segment, prompt); + new IconServiceStreamListener(this, icon, listener) : listener, segment, prompt); // Remove custom icon if complete if(segment.isComplete()) { icon.remove(); diff --git a/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java b/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java index 5db9263e7f1..88be09ae164 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java @@ -18,26 +18,26 @@ * feedback@cyberduck.ch */ -import ch.cyberduck.core.BytecountStreamListener; +import ch.cyberduck.core.io.DelegateStreamListener; import ch.cyberduck.core.io.StreamListener; import ch.cyberduck.core.local.IconService; +import ch.cyberduck.core.transfer.Transfer; import ch.cyberduck.core.transfer.TransferProgress; -import ch.cyberduck.core.transfer.TransferStatus; -public class IconServiceStreamListener extends BytecountStreamListener { +public class IconServiceStreamListener extends DelegateStreamListener { + private final Transfer transfer; private final IconService.Icon icon; - private final TransferStatus status; - public IconServiceStreamListener(final IconService.Icon icon, final StreamListener delegate, final TransferStatus status) { + public IconServiceStreamListener(final Transfer transfer, final IconService.Icon icon, final StreamListener delegate) { super(delegate); + this.transfer = transfer; this.icon = icon; - this.status = status; } @Override public void sent(final long bytes) { super.sent(bytes); - icon.update(new TransferProgress(status.getLength(), this.getSent())); + icon.update(new TransferProgress(transfer.getSize(), transfer.getTransferred())); } } From 7127144d1a233de2ff28fcc29816a7eb27161391 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Tue, 26 Nov 2024 09:14:54 +0100 Subject: [PATCH 20/21] Show progress icon for uploads. --- .../core/local/FinderProgressIconService.java | 19 ++++++-- .../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, 84 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..880447192b6 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,35 @@ 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; + private final Local file; - public FinderProgressIcon(final Local file) { + public FinderProgressIcon(final Transfer.Type type, final Local file) { + this.file = 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(); } @@ -57,6 +67,7 @@ public boolean update(final TransferProgress status) { @Override public boolean remove() { progress.unpublish(); + WorkspaceIconService.update(file, null); return true; } } 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(); From 654c60a28b7efb6580ac5b7d3bc319b7dfc7fef5 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Tue, 26 Nov 2024 21:21:58 +0100 Subject: [PATCH 21/21] Drop support for custom file icon. --- .../ch/cyberduck/core/local/FinderProgressIconService.java | 1 - .../core/transfer/download/DownloadFilterOptions.java | 3 --- .../core/transfer/download/RenameExistingFilterTest.java | 1 - .../ui/cocoa/datasource/BrowserTableDataSource.java | 5 ----- 4 files changed, 10 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 880447192b6..666d39b144a 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 @@ -67,7 +67,6 @@ public boolean update(final TransferProgress status) { @Override public boolean remove() { progress.unpublish(); - WorkspaceIconService.update(file, null); return true; } } diff --git a/core/src/main/java/ch/cyberduck/core/transfer/download/DownloadFilterOptions.java b/core/src/main/java/ch/cyberduck/core/transfer/download/DownloadFilterOptions.java index b9aa90c902d..9c5e1dd52b2 100644 --- a/core/src/main/java/ch/cyberduck/core/transfer/download/DownloadFilterOptions.java +++ b/core/src/main/java/ch/cyberduck/core/transfer/download/DownloadFilterOptions.java @@ -31,7 +31,6 @@ public final class DownloadFilterOptions { public boolean permissions; public boolean timestamp; public boolean wherefrom; - public boolean icon; public boolean checksum; /** * Add quarantine flag to downloaded file @@ -45,7 +44,6 @@ public DownloadFilterOptions(final Host bookmark) { permissions = preferences.getBoolean("queue.download.permissions.change"); timestamp = preferences.getBoolean("queue.download.timestamp.change"); wherefrom = preferences.getBoolean("queue.download.wherefrom"); - icon = preferences.getBoolean("queue.download.icon.update"); checksum = preferences.getBoolean("queue.download.checksum.calculate"); quarantine = preferences.getBoolean("queue.download.quarantine"); open = preferences.getBoolean("queue.download.complete.open"); @@ -58,7 +56,6 @@ public String toString() { sb.append(", permissions=").append(permissions); sb.append(", timestamp=").append(timestamp); sb.append(", wherefrom=").append(wherefrom); - sb.append(", icon=").append(icon); sb.append(", checksum=").append(checksum); sb.append(", quarantine=").append(quarantine); sb.append(", open=").append(open); diff --git a/core/src/test/java/ch/cyberduck/core/transfer/download/RenameExistingFilterTest.java b/core/src/test/java/ch/cyberduck/core/transfer/download/RenameExistingFilterTest.java index eb01b0ea412..1155ea00466 100755 --- a/core/src/test/java/ch/cyberduck/core/transfer/download/RenameExistingFilterTest.java +++ b/core/src/test/java/ch/cyberduck/core/transfer/download/RenameExistingFilterTest.java @@ -28,7 +28,6 @@ public class RenameExistingFilterTest { public void testPrepare() throws Exception { final Host host = new Host(new TestProtocol()); final DownloadFilterOptions options = new DownloadFilterOptions(host); - options.icon = false; RenameExistingFilter f = new RenameExistingFilter(new DisabledDownloadSymlinkResolver(), new NullTransferSession(host), options); final String name = new AsciiRandomStringService().random(); 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 6aa59de3655..e9d516ee913 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 @@ -57,7 +57,6 @@ import ch.cyberduck.core.local.FileDescriptor; import ch.cyberduck.core.local.FileDescriptorFactory; 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; @@ -630,7 +629,6 @@ public NSArray namesOfPromisedFilesDroppedAtDestination(final NSURL url) { final Local destination = LocalFactory.get(url.path()); final DownloadFilterOptions options = new DownloadFilterOptions(controller.getSession().getHost()); if(destination.isChild(new TemporarySupportDirectoryFinder().find())) { - options.icon = false; options.segments = false; } final PathPasteboard pasteboard = controller.getPasteboard(); @@ -646,9 +644,6 @@ public NSArray namesOfPromisedFilesDroppedAtDestination(final NSURL url) { if(!file.exists()) { try { LocalTouchFactory.get().touch(file); - if(options.icon) { - WorkspaceIconService.update(file, IconCacheFactory.get().iconNamed(String.format("download%d.icns", 0))); - } } catch(AccessDeniedException e) { log.warn("Failure creating file {} {}", file, e.getMessage());