Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
cc9cc2d
Only run auto configuration when no credentials are set.
dkocher Nov 6, 2025
0b4cafe
Review implementations.
dkocher Nov 6, 2025
97871c8
Auto size popup button.
dkocher Sep 15, 2025
9259638
Add annotation.
dkocher Sep 15, 2025
488e0e5
Increase padding.
dkocher Sep 15, 2025
87a5c71
Increase height and add padding in bottom bar.
dkocher Sep 15, 2025
197dbbf
Review view layout.
dkocher Sep 15, 2025
3670696
Use system symbols.
dkocher Sep 15, 2025
632af5b
Remove fill in symbols.
dkocher Sep 15, 2025
bd05a31
Changes.
dkocher Sep 16, 2025
da2b7c6
Switch to constraint layout.
dkocher Sep 23, 2025
976cb3d
Use system icons.
dkocher Sep 30, 2025
724a68c
Add system icons for menu items.
dkocher Sep 30, 2025
960fc79
Add implementation to run alerts as popover.
dkocher Oct 5, 2025
0ab303c
Remove URL field.
dkocher Oct 5, 2025
4d75b62
Use system images.
dkocher Oct 23, 2025
4d4eefe
Remove custom disclosable view implementation.
dkocher Oct 24, 2025
81ea665
Switch to constraint layout. Use popover for file details.
dkocher Oct 25, 2025
419e1af
Use system image.
dkocher Oct 26, 2025
d05395d
Allow custom positioning rect.
dkocher Oct 26, 2025
4b0d437
Auto resize window from constraints.
dkocher Oct 26, 2025
d9d1e05
Rename field.
dkocher Oct 26, 2025
16c224f
Remove toggle.
dkocher Oct 26, 2025
a172ee9
Remove comment field.
dkocher Oct 26, 2025
a1164e9
Add keyword.
dkocher Oct 26, 2025
69767d0
Display bookmark window as popover.
dkocher Oct 26, 2025
4f754ac
Replace with lambda.
dkocher Oct 27, 2025
e100989
Add flag for popover or floating window display.
dkocher Oct 27, 2025
a4f0e07
Switch to constraint layout.
dkocher Oct 27, 2025
dab5888
Hide controls when configuration option not available.
dkocher Oct 27, 2025
cc84de1
Move field up.
dkocher Oct 27, 2025
218a780
Change to local scope.
dkocher Oct 27, 2025
de27985
Move field up.
dkocher Oct 27, 2025
18feb34
Use regular bookmark panel.
dkocher Oct 27, 2025
5ef4651
Localize.
dkocher Oct 27, 2025
529d483
Add images for local and server URL.
dkocher Oct 27, 2025
0bbfe01
Move to upper class.
dkocher Oct 28, 2025
f1302bb
Add setter for translating auto resize mask to constraints.
dkocher Oct 29, 2025
8c9e7fd
Bookmark editing frame with content view loaded separately.
dkocher Oct 30, 2025
0890248
New connection editing frame with content view loaded separately.
dkocher Oct 30, 2025
4794cec
Allow custom behaviour.
dkocher Oct 30, 2025
d5ea9f5
Synchronize access.
dkocher Oct 30, 2025
f4726f5
Move out of window.
dkocher Oct 30, 2025
78285cf
Remove non-generic controls.
dkocher Oct 31, 2025
8b2c719
Add options.
dkocher Oct 31, 2025
8e3c8cd
Default to utility panel.
dkocher Oct 31, 2025
8bfb34c
Reuse content view to edit bookmark.
dkocher Oct 31, 2025
c435d14
Implement tabs.
dkocher Oct 31, 2025
29a8367
Resize on tab selection change.
dkocher Oct 31, 2025
ff6fb28
Rename class.
dkocher Nov 1, 2025
539f28e
Rename outlets.
dkocher Nov 1, 2025
b8936ce
Remove custom class in file owner
dkocher Nov 2, 2025
b3d3dc3
Remove custom class in file owner
dkocher Nov 2, 2025
d894f04
Remove custom class in file owner
dkocher Nov 2, 2025
1599841
Refactor using inheritance loading both container and content XIB int…
dkocher Nov 2, 2025
5f0a748
Set window title from bookmark.
dkocher Nov 2, 2025
4f5b397
Make controls regular sized.
dkocher Nov 2, 2025
54a63db
Transparent title bar.
dkocher Nov 2, 2025
d74af4f
Add "Connect" and "Disconnect" menu items to "Go" menu.
dkocher Nov 3, 2025
2bba637
Add "Connect" and "Disconnect" menu items to context menu.
dkocher Nov 3, 2025
e1467b7
Updated constraints.
dkocher Nov 3, 2025
d041704
Move to upper class.
dkocher Nov 4, 2025
1da62f0
Set ascent colour.
dkocher Nov 4, 2025
5931033
Javadoc.
dkocher Nov 4, 2025
35036ca
Do not set application name in window title.
dkocher Nov 4, 2025
2070d72
Extract navigation controller.
dkocher Nov 4, 2025
654ef7b
Allow annotating methods.
dkocher Nov 4, 2025
7fe8138
Extract status controller.
dkocher Nov 4, 2025
aea3dde
Add type.
dkocher Nov 4, 2025
5048dae
Skip manually setting first responder.
dkocher Nov 4, 2025
99f3b86
Always reload after setting filter.
dkocher Nov 4, 2025
992b3b9
Recalculate key loop after toggling controls.
dkocher Nov 4, 2025
1f7f802
Add NSWindowStyleMask constants.
dkocher Nov 5, 2025
3c1a85a
Remove unnecessary variable.
dkocher Nov 5, 2025
d4414f7
Set window title and subtitle depending on selected tab.
dkocher Nov 5, 2025
fd0e891
Formatting.
dkocher Nov 5, 2025
ab8e50f
Javadoc.
dkocher Nov 5, 2025
abc77bf
Remove instance variable.
dkocher Nov 5, 2025
669d806
Remove custom configuration.
dkocher Nov 5, 2025
faa019e
Formatting.
dkocher Nov 5, 2025
f3ff04c
Explicitly set transparent titlebar.
dkocher Nov 5, 2025
d5ca633
Add observer in constructor to notify collection.
dkocher Nov 6, 2025
460fa70
Always create new controller when displayed in popover.
dkocher Nov 6, 2025
3aa2ce3
Revert "Default to utility panel."
dkocher Nov 6, 2025
fb2ed23
Add constraints.
dkocher Nov 6, 2025
f20ca64
Auto configure on username change.
dkocher Nov 6, 2025
4ea944e
Use intrinsic size to fix proper resize of popover.
dkocher Nov 6, 2025
e4e0e3a
Switch to icon only default mode for toolbar.
dkocher Nov 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* [Feature] Connect with Multi-Bucket Application Keys that grant access to a specific group of buckets within an
account, including the option to limit access based on a single file prefix (
B2) ([#17139](https://trac.cyberduck.io/ticket/17139))
* [Feature] Support for Liquid Glass (macOS) ([#17459](https://trac.cyberduck.io/ticket/17459))
* [Feature] Connect with connection profile obtaining temporary credentials from AWS Security Token Service (STS) by
assuming role with optional Multi-Factor Authentication (MFA) input (
S3) ([#17437](https://trac.cyberduck.io/ticket/17437))
Expand Down
2 changes: 0 additions & 2 deletions Credits.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@
\cf3 Synapticloop\
\cf0 {\field{\*\fldinst{HYPERLINK "http://zathras.de/"}}{\fldrslt UKCrashReporter}}\
\cf3 M. Uli Kusterer\
\cf0 {\field{\*\fldinst{HYPERLINK "http://www.snoize.com/"}}{\fldrslt SNDisclosableView}}\
\cf3 Kurt Revis\
\cf0 {\field{\*\fldinst{HYPERLINK "https://opensource.apple.com/tarballs/mDNSResponder/"}}{\fldrslt mDNSResponder}}\
\cf3 Apple Inc.\
\cf0 {\field{\*\fldinst{HYPERLINK "https://sparkle-project.org/"}}{\fldrslt Sparkle}}\
Expand Down
104 changes: 96 additions & 8 deletions Cyberduck.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,17 @@
import ch.cyberduck.core.Factory;
import ch.cyberduck.core.FactoryException;

import ch.cyberduck.core.LocaleFactory;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public abstract class BundleController extends ProxyController {
private static final Logger log = LogManager.getLogger(BundleController.class);

protected static final String DEFAULT = LocaleFactory.localizedString("Default");

public static final NSMutableParagraphStyle PARAGRAPH_STYLE_LEFT_ALIGNMENT_TRUNCATE_MIDDLE;
public static final NSMutableParagraphStyle PARAGRAPH_STYLE_LEFT_ALIGNMENT_TRUNCATE_TAIL;
public static final NSMutableParagraphStyle PARAGRAPH_STYLE_RIGHT_ALIGNMENT_TRUNCATE_TAIL;
Expand Down
2 changes: 1 addition & 1 deletion binding/src/main/java/ch/cyberduck/binding/Outlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

@java.lang.annotation.Target({ElementType.FIELD})
@java.lang.annotation.Target({ElementType.FIELD, ElementType.METHOD})
@java.lang.annotation.Retention(RetentionPolicy.SOURCE)
public @interface Outlet {
}
127 changes: 125 additions & 2 deletions binding/src/main/java/ch/cyberduck/binding/ProxyController.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@

import ch.cyberduck.binding.application.NSAlert;
import ch.cyberduck.binding.application.NSApplication;
import ch.cyberduck.binding.application.NSPopover;
import ch.cyberduck.binding.application.NSView;
import ch.cyberduck.binding.application.NSViewController;
import ch.cyberduck.binding.application.NSWindow;
import ch.cyberduck.binding.application.SheetCallback;
import ch.cyberduck.binding.application.WindowListener;
import ch.cyberduck.binding.foundation.FoundationKitFunctions;
import ch.cyberduck.binding.foundation.NSNotification;
import ch.cyberduck.binding.foundation.NSObject;
import ch.cyberduck.binding.foundation.NSThread;
import ch.cyberduck.core.AbstractController;
import ch.cyberduck.core.threading.DefaultMainAction;
Expand All @@ -28,11 +34,14 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.rococoa.ID;
import org.rococoa.cocoa.foundation.NSRect;
import org.rococoa.cocoa.foundation.NSSize;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

import com.google.common.util.concurrent.Uninterruptibles;

Expand Down Expand Up @@ -153,6 +162,16 @@ public int alert(final SheetController sheet, final AlertRunner runner, final Co
protected static final Set<AlertRunner> alerts
= new HashSet<>();

/**
* @param sheet Controller for alert window
* @param callback Handler invoked after sheet is dismissed with selected option
* @param runner Implementation to display alert window
* @return Selected alert option by user
*/
public int alert(final SheetController sheet, final SheetCallback callback, final AlertRunner runner) {
return this.alert(sheet, callback, runner, new CountDownLatch(1));
}

/**
* Display as sheet attached to window of parent controller
*
Expand All @@ -164,7 +183,9 @@ public int alert(final SheetController sheet, final AlertRunner runner, final Co
*/
public int alert(final SheetController sheet, final SheetCallback callback, final AlertRunner runner, final CountDownLatch signal) {
log.debug("Alert with runner {} and callback {}", runner, callback);
alerts.add(runner);
synchronized(alerts) {
alerts.add(runner);
}
final AtomicInteger option = new AtomicInteger(SheetCallback.CANCEL_OPTION);
final CountDownLatch state = new CountDownLatch(1);
final SheetCallback.DelegatingSheetCallback chain = new SheetCallback.DelegatingSheetCallback(new SheetCallback.ReturnCodeSheetCallback(option), sheet, callback);
Expand All @@ -174,7 +195,11 @@ public void run() {
log.info("Load bundle for alert {}", sheet);
sheet.loadBundle();
runner.alert(sheet.window(), new SheetCallback.DelegatingSheetCallback(new SignalSheetCallback(state),
chain, new SignalSheetCallback(signal), (returncode) -> alerts.remove(runner)));
chain, new SignalSheetCallback(signal), (returncode) -> {
synchronized(alerts) {
alerts.remove(runner);
}
}));
}
}, true);
if(!NSThread.isMainThread()) {
Expand Down Expand Up @@ -310,4 +335,102 @@ public void callback(final int returncode) {
signal.countDown();
}
}

public static final class PopoverAlertRunner extends Proxy implements AlertRunner, AlertRunner.CloseHandler, WindowListener {
private final NSPopover popover = NSPopover.create();
private final NSView positioningView;
private final NSRect positioningRect;
private final SheetController controller;
private final AtomicReference<Proxy> reference = new AtomicReference<>();
private final AtomicInteger option = new AtomicInteger(SheetCallback.CANCEL_OPTION);
private final int behaviour;

public PopoverAlertRunner(final NSView positioningView, final SheetController controller) {
this(positioningView, positioningView.frame(), controller);
}

public PopoverAlertRunner(final NSView positioningView, final NSRect positioningRect, final SheetController controller) {
this(positioningView, positioningRect, controller, NSPopover.NSPopoverBehaviorSemitransient);
}

public PopoverAlertRunner(final NSView positioningView, final NSRect positioningRect, final SheetController controller, final int behaviour) {
this.positioningView = positioningView;
this.positioningRect = positioningRect;
this.controller = controller;
this.behaviour = behaviour;
}

@Override
public void alert(final NSWindow sheet, final SheetCallback callback) {
NSApplication.sharedApplication().activateIgnoringOtherApps(true);
final Proxy proxy = new PopoverDelegate(controller, option, callback);
reference.set(proxy);
popover.setDelegate(proxy.id());
popover.setAnimates(false);
popover.setBehavior(behaviour);
final NSViewController viewController = NSViewController.create();
viewController.setView(sheet.contentView());
popover.setContentViewController(viewController);
popover.showRelativeToRect_ofView_preferredEdge(positioningRect, positioningView,
FoundationKitFunctions.NSRectEdge.NSMinYEdge);
controller.addListener(this);
}

@Override
public void windowDidResize(final NSSize windowFrame) {
log.debug("Resize popover to {}", windowFrame);
popover.setContentSize(controller.view().intrinsicContentSize());
}

@Override
public void closed(final NSWindow sheet, final int returncode) {
option.set(returncode);
popover.performClose(null);
}
}

public static final class PopoverDelegate extends Proxy {
private final SheetController controller;
private final AtomicInteger returncode;
private final SheetCallback callback;

public PopoverDelegate(final SheetController controller, final AtomicInteger returncode, final SheetCallback callback) {
this.controller = controller;
this.returncode = returncode;
this.callback = callback;
}

@Delegate
public void popoverWillClose(final NSNotification notification) {
final NSObject popoverCloseReasonValue = notification.userInfo().objectForKey(NSPopover.NSPopoverCloseReasonKey);
if(popoverCloseReasonValue != null) {
if(NSPopover.NSPopoverCloseReasonValue.NSPopoverCloseReasonStandard.equals(popoverCloseReasonValue.toString())) {
log.debug("Notify {} of return code {}", callback, returncode.get());
// No window close notification for popover
controller.invalidate();
callback.callback(returncode.get());
}
else {
log.debug("Ignore notification {}", notification);
}
}
}

@Delegate
public boolean popoverShouldDetach(final NSPopover popover) {
return true;
}
}

/**
* Adjust frame of subview to match the parent view and attach with translating autoresizing mask into constraints
*
* @param parent Container View
* @param subview Content View
*/
protected void addSubview(final NSView parent, final NSView subview) {
subview.setTranslatesAutoresizingMaskIntoConstraints(true);
subview.setFrame(parent.bounds());
parent.addSubview(subview);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@
public abstract class WindowController extends BundleController implements NSWindow.Delegate {
private static final Logger log = LogManager.getLogger(WindowController.class);

protected static final String DEFAULT = LocaleFactory.localizedString("Default");

protected final Set<WindowListener> listeners
= Collections.synchronizedSet(new HashSet<>());
/**
Expand All @@ -57,11 +55,6 @@ public abstract class WindowController extends BundleController implements NSWin
@Outlet
protected NSWindow window;

/**
* Main content view of window
*/
protected NSView view;

public WindowController() {
super();
}
Expand Down Expand Up @@ -91,7 +84,6 @@ public void removeListener(final WindowListener listener) {

public void setWindow(final NSWindow window) {
this.window = window;
this.view = window.contentView();
this.window.recalculateKeyViewLoop();
this.window.setReleasedWhenClosed(true);
this.window.setDelegate(this.id());
Expand All @@ -103,7 +95,7 @@ public NSWindow window() {

@Override
public NSView view() {
return view;
return window.contentView();
}

/**
Expand Down Expand Up @@ -252,14 +244,14 @@ protected double getMinWindowWidth() {

protected double toolbarHeightForWindow() {
final NSRect windowFrame = NSWindow.contentRectForFrameRect_styleMask(window.frame(), window.styleMask());
return windowFrame.size.height.doubleValue() - view.frame().size.height.doubleValue();
return windowFrame.size.height.doubleValue() - window.contentView().frame().size.height.doubleValue();
}

/**
* @return Minimum size to fit content view of currently selected tab.
*/
protected NSRect getContentRect() {
return view.frame();
return window.contentView().frame();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.rococoa.cocoa.CGFloat;
import org.rococoa.cocoa.foundation.NSInteger;
import org.rococoa.cocoa.foundation.NSPoint;
import org.rococoa.cocoa.foundation.NSRect;
import org.rococoa.cocoa.foundation.NSUInteger;

/// <i>native declaration : :69</i>
Expand Down Expand Up @@ -841,4 +842,13 @@ public void editRow(NSInteger column, NSInteger row, boolean select) {
* <i>from NSDeprecated native declaration : :528</i><br>
* Conversion Error : NSRect
*/

/**
* Returns the rectangle containing the row at the specified index.
*
* @param row Table row
* @return The rectangle containing the row at rowIndex. Returns NSZeroRect if rowIndex lies outside the range of valid row indexes for the table view.
*/
public abstract NSRect rectOfRow(NSInteger row);

}
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ public interface _Class extends ObjCClass {
*/
public abstract NSSize fittingSize();

/**
* The natural size for the receiving view, considering only properties of the view itself.
*
* @return A size indicating the natural size for the receiving view based on its intrinsic properties.
*/
public abstract NSSize intrinsicContentSize();

/**
* Original signature : <code>void setAutoresizesSubviews(BOOL)</code><br>
* <i>native declaration : :155</i>
Expand Down Expand Up @@ -1162,4 +1169,13 @@ public boolean dragPromisedFilesOfTypes(
* <i>from NSFullScreenMode native declaration : :419</i>
*/
public abstract boolean isInFullScreenMode();

/**
* When this property is set to true, the view’s superview looks at the view’s autoresizing mask, produces constraints
* that implement it, and adds those constraints to itself (the superview). If your view has flexible constraints that
* require dynamic adjustment, set this property to false and apply the constraints yourself.
*
* @param flag A Boolean value indicating whether the view’s autoresizing mask is translated into constraints for the constraint-based layout system.
*/
public abstract void setTranslatesAutoresizingMaskIntoConstraints(final boolean flag);
}
Loading
Loading