Skip to content

Commit b1604fd

Browse files
authored
Merge pull request #17154 from iterate-ch/feature/GH-17147-refactor-alert-sheets
Refactor alerts to allow display as sheet or modal.
2 parents 3bdb5a8 + 3da102a commit b1604fd

File tree

191 files changed

+1497
-8176
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

191 files changed

+1497
-8176
lines changed

Cyberduck.xcodeproj/project.pbxproj

Lines changed: 0 additions & 82 deletions
Large diffs are not rendered by default.

binding/src/main/java/ch/cyberduck/binding/AlertController.java

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import ch.cyberduck.binding.application.NSButton;
2020
import ch.cyberduck.binding.application.NSCell;
2121
import ch.cyberduck.binding.application.NSView;
22-
import ch.cyberduck.binding.application.SheetCallback;
22+
import ch.cyberduck.binding.application.NSWindow;
2323
import ch.cyberduck.binding.foundation.NSEnumerator;
2424
import ch.cyberduck.binding.foundation.NSObject;
2525
import ch.cyberduck.core.ProviderHelpServiceFactory;
@@ -31,9 +31,10 @@
3131
import org.rococoa.Foundation;
3232
import org.rococoa.Rococoa;
3333
import org.rococoa.cocoa.CGFloat;
34+
import org.rococoa.cocoa.foundation.NSPoint;
3435
import org.rococoa.cocoa.foundation.NSRect;
3536

36-
public abstract class AlertController extends SheetController implements SheetCallback, InputValidator {
37+
public abstract class AlertController extends SheetController implements InputValidator {
3738
private static final Logger log = LogManager.getLogger(AlertController.class);
3839

3940
protected static final int SUBVIEWS_VERTICAL_SPACE = 4;
@@ -43,12 +44,12 @@ public abstract class AlertController extends SheetController implements SheetCa
4344
@Outlet
4445
private NSAlert alert;
4546

46-
public AlertController(final NSAlert alert) {
47-
this.loadBundle(alert);
47+
public AlertController() {
48+
super();
4849
}
4950

50-
public AlertController() {
51-
// No bundle
51+
public AlertController(final InputValidator callback) {
52+
super(callback);
5253
}
5354

5455
/**
@@ -63,72 +64,60 @@ public NSView getAccessoryView(final NSAlert alert) {
6364
return null;
6465
}
6566

66-
public int beginSheet(final WindowController parent) {
67-
return new SheetInvoker(this, parent, this).beginSheet();
68-
}
69-
70-
@Override
71-
public void callback(final int returncode) {
72-
log.warn("Ignore return code {}", returncode);
73-
}
74-
75-
@Override
76-
public void invalidate() {
77-
alert = null;
78-
super.invalidate();
79-
}
67+
public abstract NSAlert loadAlert();
8068

8169
@Override
8270
public void loadBundle() {
83-
//
84-
}
85-
86-
protected void loadBundle(final NSAlert alert) {
87-
this.alert = alert;
71+
alert = this.loadAlert();
72+
log.debug("Display alert {}", alert);
8873
alert.setShowsHelp(true);
8974
alert.setDelegate(this.id());
9075
if(alert.showsSuppressionButton()) {
9176
alert.suppressionButton().setTarget(this.id());
9277
alert.suppressionButton().setAction(Foundation.selector("suppressionButtonClicked:"));
9378
}
79+
final NSWindow window = alert.window();
80+
log.debug("Use window {}", window);
81+
this.setWindow(window);
9482
// Layout alert view on main thread
9583
this.focus(alert);
96-
this.setWindow(alert.window());
9784
}
9885

9986
protected void focus(final NSAlert alert) {
100-
NSEnumerator buttons = alert.buttons().objectEnumerator();
87+
log.debug("Focus alert {}", alert);
88+
final NSEnumerator buttons = alert.buttons().objectEnumerator();
10189
NSObject button;
10290
while((button = buttons.nextObject()) != null) {
10391
final NSButton b = Rococoa.cast(button, NSButton.class);
10492
b.setTarget(this.id());
105-
b.setAction(Foundation.selector("closeSheet:"));
93+
b.setAction(SheetController.BUTTON_CLOSE_SELECTOR);
10694
}
10795
final NSView accessory = this.getAccessoryView(alert);
10896
if(accessory != null) {
109-
final NSRect frame = this.getFrame(alert, accessory);
97+
final NSRect frame = this.getFrame(accessory);
11098
accessory.setFrameSize(frame.size);
11199
alert.setAccessoryView(accessory);
112-
alert.window().makeFirstResponder(accessory);
100+
window.makeFirstResponder(accessory);
113101
}
114102
// First call layout and then do any special positioning and sizing of the accessory view prior to running the alert
115103
alert.layout();
116-
alert.window().recalculateKeyViewLoop();
104+
window.recalculateKeyViewLoop();
117105
}
118106

119-
protected NSRect getFrame(final NSAlert alert, final NSView accessory) {
120-
final NSRect frame = new NSRect(alert.window().frame().size.width.doubleValue(), accessory.frame().size.height.doubleValue());
107+
protected NSRect getFrame(final NSView accessory) {
108+
final NSRect frame = new NSRect(window.frame().size.width.doubleValue(), accessory.frame().size.height.doubleValue());
121109
final NSEnumerator enumerator = accessory.subviews().objectEnumerator();
122110
NSObject next;
123111
while(null != (next = enumerator.nextObject())) {
124112
final NSView subview = Rococoa.cast(next, NSView.class);
125113
frame.size.height = new CGFloat(frame.size.height.doubleValue() + subview.frame().size.height.doubleValue() + SUBVIEWS_VERTICAL_SPACE * 2);
126114
}
115+
log.debug("Calculated frame {} for alert {} with accessory {}", frame, this, accessory);
127116
return frame;
128117
}
129118

130119
/**
131-
* Open help page.
120+
* @return Help page.
132121
*/
133122
protected String help() {
134123
return ProviderHelpServiceFactory.get().help();
@@ -147,9 +136,17 @@ public void alertShowHelp(final NSAlert alert) {
147136
@Action
148137
public void suppressionButtonClicked(final NSButton sender) {
149138
suppressed = sender.state() == NSCell.NSOnState;
139+
log.debug("Suppression state set to {}", suppressed);
150140
}
151141

152142
public boolean isSuppressed() {
153143
return suppressed;
154144
}
145+
146+
protected void addAccessorySubview(final NSView accessoryView, final NSView view) {
147+
view.setFrameSize(this.getFrame(view).size);
148+
view.setFrameOrigin(new NSPoint(0, this.getFrame(accessoryView).size.height.doubleValue()
149+
+ accessoryView.subviews().count().doubleValue() * SUBVIEWS_VERTICAL_SPACE));
150+
accessoryView.addSubview(view);
151+
}
155152
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package ch.cyberduck.binding;
2+
3+
/*
4+
* Copyright (c) 2002-2025 iterate GmbH. All rights reserved.
5+
* https://cyberduck.io/
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
import ch.cyberduck.binding.application.NSWindow;
19+
import ch.cyberduck.binding.application.SheetCallback;
20+
21+
/**
22+
* AlertRunner is an interface for managing the display and lifecycle
23+
* of modal or non-modal alert windows (sheets) in macOS applications.
24+
* <p>
25+
* Implementations of this interface allow invoking alert dialogs
26+
* attached to a parent window (sheet-based alerts) or as standalone
27+
* modal dialogs. The alert dialogs provide user feedback and receive
28+
* responses via the specified callback.
29+
* <p>
30+
* Method implementations typically interact with system-level APIs
31+
* or frameworks such as AppKit to display and manage the sheet/window.
32+
*/
33+
public interface AlertRunner {
34+
/**
35+
* Displays an alert dialog attached to the specified NSWindow (sheet).
36+
* The user interaction result is handled via the provided callback.
37+
*
38+
* @param sheet The alert dialog window
39+
* @param callback The callback to handle actions triggered by the alert
40+
*/
41+
void alert(NSWindow sheet, SheetCallback callback);
42+
43+
/**
44+
* Callback when alert is dismissed by user
45+
*/
46+
interface CloseHandler {
47+
/**
48+
* Notified when alert is closed by user input
49+
*
50+
* @param sheet Sheet window
51+
* @param returncode Selected option
52+
*/
53+
void closed(NSWindow sheet, int returncode);
54+
}
55+
}

0 commit comments

Comments
 (0)