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..132b2142ab5
--- /dev/null
+++ b/binding/src/main/java/ch/cyberduck/binding/foundation/NSProgress.java
@@ -0,0 +1,331 @@
+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);
+
+ /**
+ * 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";
+ /**
+ * 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/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..666d39b144a
--- /dev/null
+++ b/core/dylib/src/main/java/ch/cyberduck/core/local/FinderProgressIconService.java
@@ -0,0 +1,73 @@
+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.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 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 Transfer.Type type, final Local file) {
+ this.file = file;
+ progress = NSProgress.discreteProgressWithTotalUnitCount(0L);
+ progress.setKind(NSProgress.NSProgressKindFile);
+ progress.setCancellable(false);
+ progress.setPausable(false);
+ switch(type) {
+ case download:
+ progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindDownloading);
+ break;
+ case upload:
+ progress.setFileOperationKind(NSProgress.NSProgressFileOperationKindUploading);
+ break;
+ }
+ progress.setFileURL(NSURL.fileURLWithPath(file.getAbsolute()));
+ 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;
+ }
+
+ @Override
+ public boolean remove() {
+ 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 48e1ad9d02a..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
@@ -1,42 +1,70 @@
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;
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.TransferStatus;
+import ch.cyberduck.core.transfer.Transfer;
+import ch.cyberduck.core.transfer.TransferProgress;
import ch.cyberduck.core.unicode.NFDNormalizer;
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();
+ private static final NSWorkspace workspace = NSWorkspace.sharedWorkspace();
@Override
- public boolean set(final Local file, final String image) {
- return this.update(file, IconCacheFactory.get().iconNamed(image));
+ 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)));
+ }
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean remove() {
+ // The Finder will display the default icon for this file type
+ return WorkspaceIconService.update(file, null);
+ }
+ };
+ }
+ return disabled;
}
- protected 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))) {
@@ -46,25 +74,4 @@ protected boolean update(final Local file, final NSImage icon) {
return false;
}
}
-
- @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.set(file, String.format("download%d.icns", ++fraction));
- }
- else {
- return this.set(file, String.format("download%d.icns", 0));
- }
- }
- }
-
- @Override
- public boolean remove(final Local file) {
- return this.update(file, null);
- }
}
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());
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 748e4982756..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,21 +19,12 @@
*/
import ch.cyberduck.core.Local;
-import ch.cyberduck.core.transfer.TransferStatus;
+import ch.cyberduck.core.transfer.Transfer;
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;
- }
@Override
- public boolean remove(final Local file) {
- return false;
+ 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 d661a86470f..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,29 +19,43 @@
*/
import ch.cyberduck.core.Local;
-import ch.cyberduck.core.transfer.TransferStatus;
+import ch.cyberduck.core.transfer.Transfer;
+import ch.cyberduck.core.transfer.TransferProgress;
public interface IconService {
- /**
- * @param file File
- * @param image Image name
- * @return True if icon is set
- */
- boolean set(Local file, String image);
+ Icon disabled = new Icon() {
+ @Override
+ public boolean update(final TransferProgress progress) {
+ return false;
+ }
- /**
- * @param file File
- * @param progress An integer from -1 and 9. If -1 is passed, the icon should be removed.
- * @return True if icon is set
- */
- boolean set(Local file, TransferStatus progress);
+ @Override
+ public boolean remove() {
+ return false;
+ }
+ };
/**
- * 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(Transfer.Type type, 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/local/IconServiceFactory.java b/core/src/main/java/ch/cyberduck/core/local/IconServiceFactory.java
index 5f97f08f633..2eefedde25f 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,8 @@
*/
import ch.cyberduck.core.Factory;
+import ch.cyberduck.core.Local;
+import ch.cyberduck.core.transfer.Transfer;
public class IconServiceFactory extends Factory {
@@ -29,4 +31,8 @@ private IconServiceFactory() {
public static IconService get() {
return new IconServiceFactory().create();
}
+
+ 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/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/CopyTransfer.java b/core/src/main/java/ch/cyberduck/core/transfer/CopyTransfer.java
index a956abc53d8..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,11 +232,11 @@ 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 TransferOptions options, final TransferStatus segment,
+ 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 aa48093cdbc..bf5a8c901d9 100644
--- a/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java
+++ b/core/src/main/java/ch/cyberduck/core/transfer/DownloadTransfer.java
@@ -37,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.IconUpdateStreamListener;
import ch.cyberduck.core.transfer.download.OverwriteFilter;
import ch.cyberduck.core.transfer.download.RenameExistingFilter;
import ch.cyberduck.core.transfer.download.RenameFilter;
@@ -279,8 +278,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 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)) {
@@ -294,7 +293,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()) {
@@ -302,8 +301,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() ?
- new IconUpdateStreamListener(streamListener, segment, local) : streamListener, segment, connectionCallback);
+ download.download(file, local, bandwidth, listener, segment, prompt);
}
}
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..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 connectionCallback,
- final ProgressListener progressListener, final StreamListener streamListener) throws BackgroundException {
+ 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, 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, 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, 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..131f6719c57 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,19 @@ 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 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 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/TransferProgress.java b/core/src/main/java/ch/cyberduck/core/transfer/TransferProgress.java
index 39ab6b1f11e..c1451c74dbb 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,10 @@ public final class TransferProgress {
private final String progress;
private final Double speed;
+ public TransferProgress(final Long size, final Long transferred) {
+ this(size, transferred, StringUtils.EMPTY, -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/UploadTransfer.java b/core/src/main/java/ch/cyberduck/core/transfer/UploadTransfer.java
index ab5e06c8011..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,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 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/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java b/core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java
index 9eece598754..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
@@ -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;
@@ -178,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()) {
@@ -279,11 +277,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.set(local, status);
- 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/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/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java b/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java
new file mode 100644
index 00000000000..88be09ae164
--- /dev/null
+++ b/core/src/main/java/ch/cyberduck/core/transfer/download/IconServiceStreamListener.java
@@ -0,0 +1,43 @@
+package ch.cyberduck.core.transfer.download;
+
+/*
+ * Copyright (c) 2002-2013 David Kocher. All rights reserved.
+ * http://cyberduck.ch/
+ *
+ * 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
+ * (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:
+ * feedback@cyberduck.ch
+ */
+
+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;
+
+public class IconServiceStreamListener extends DelegateStreamListener {
+
+ private final Transfer transfer;
+ private final IconService.Icon icon;
+
+ public IconServiceStreamListener(final Transfer transfer, final IconService.Icon icon, final StreamListener delegate) {
+ super(delegate);
+ this.transfer = transfer;
+ this.icon = icon;
+ }
+
+ @Override
+ public void sent(final long bytes) {
+ super.sent(bytes);
+ icon.update(new TransferProgress(transfer.getSize(), transfer.getTransferred()));
+ }
+}
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
deleted file mode 100644
index 2e2774bb8da..00000000000
--- a/core/src/main/java/ch/cyberduck/core/transfer/download/IconUpdateStreamListener.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package ch.cyberduck.core.transfer.download;
-
-/*
- * Copyright (c) 2002-2013 David Kocher. All rights reserved.
- * http://cyberduck.ch/
- *
- * 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
- * (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:
- * feedback@cyberduck.ch
- */
-
-import ch.cyberduck.core.BytecountStreamListener;
-import ch.cyberduck.core.Local;
-import ch.cyberduck.core.io.StreamListener;
-import ch.cyberduck.core.local.IconService;
-import ch.cyberduck.core.local.IconServiceFactory;
-import ch.cyberduck.core.transfer.TransferStatus;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-
-public class IconUpdateStreamListener extends BytecountStreamListener {
-
- private final IconService icon = IconServiceFactory.get();
- 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) {
- super(delegate);
- this.status = status;
- this.file = file;
- }
-
- @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, status);
- step++;
- }
- }
-}
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..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, status, segment, connect, progress, counter);
+ 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/core/src/test/java/ch/cyberduck/core/transfer/UploadTransferTest.java b/core/src/test/java/ch/cyberduck/core/transfer/UploadTransferTest.java
index 9f07d311f65..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,9 +159,9 @@ 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 ConnectionCallback connectionCallback,
- final ProgressListener listener, final StreamListener streamListener) {
+ final TransferOptions options, final TransferStatus segment,
+ final ConnectionCallback prompt,
+ final ProgressListener progress, final StreamListener listener) {
assertTrue(options.resumeRequested);
}
}.withCache(cache);
@@ -245,9 +245,9 @@ 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 ConnectionCallback connectionCallback,
- final ProgressListener listener, final StreamListener streamListener) {
+ final TransferOptions options, final TransferStatus segment,
+ final ConnectionCallback prompt,
+ final ProgressListener progress, final StreamListener listener) {
//
}
}.withCache(cache);
@@ -414,8 +414,8 @@ 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 ConnectionCallback connectionCallback, final ProgressListener listener, final StreamListener streamListener) {
+ 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/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/core/src/test/java/ch/cyberduck/core/worker/ConcurrentTransferWorkerTest.java b/core/src/test/java/ch/cyberduck/core/worker/ConcurrentTransferWorkerTest.java
index 557078f8fa0..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,9 +152,9 @@ 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 TransferOptions options, final TransferStatus segment,
+ 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..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,9 +70,9 @@ 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 ConnectionCallback connectionCallback,
- final ProgressListener listener, final StreamListener streamListener) {
+ final TransferOptions options, final TransferStatus segment,
+ final ConnectionCallback prompt,
+ final ProgressListener progress, final StreamListener listener) {
//
}
};
@@ -130,9 +130,9 @@ 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 ConnectionCallback connectionCallback,
- final ProgressListener listener, final StreamListener streamListener) {
+ final TransferOptions options, final TransferStatus segment,
+ final ConnectionCallback prompt,
+ final ProgressListener progress, final StreamListener listener) {
if(file.equals(root)) {
assertTrue(segment.isExists());
}
@@ -200,9 +200,9 @@ 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 ConnectionCallback connectionCallback,
- final ProgressListener listener, final StreamListener streamListener) {
+ final TransferOptions options, final TransferStatus segment,
+ final ConnectionCallback prompt,
+ final ProgressListener progress, final StreamListener listener) {
if(file.equals(root)) {
assertTrue(segment.isExists());
}
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 1ee94f9acd7..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
@@ -56,7 +56,6 @@
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.pasteboard.PathPasteboard;
import ch.cyberduck.core.pasteboard.PathPasteboardFactory;
@@ -69,7 +68,6 @@
import ch.cyberduck.core.transfer.DownloadTransfer;
import ch.cyberduck.core.transfer.Transfer;
import ch.cyberduck.core.transfer.TransferItem;
-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;
@@ -390,7 +388,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;
@@ -631,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();
@@ -647,9 +644,6 @@ public NSArray namesOfPromisedFilesDroppedAtDestination(final NSURL url) {
if(!file.exists()) {
try {
LocalTouchFactory.get().touch(file);
- if(options.icon) {
- IconServiceFactory.get().set(file, new TransferStatus().withLength(0L));
- }
}
catch(AccessDeniedException e) {
log.warn("Failure creating file {} {}", file, e.getMessage());
@@ -678,7 +672,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();
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();