1 package ch
.cyberduck
.ui
.cocoa
;
4 * Copyright (c) 2005 David Kocher. All rights reserved.
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 2 of the License, or
10 * (at your option) any later version.
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.
17 * Bug fixes, suggestions and comments should be sent to:
18 * dkocher@cyberduck.ch
21 import ch
.cyberduck
.binding
.application
.NSAlert
;
22 import ch
.cyberduck
.binding
.application
.NSApplication
;
23 import ch
.cyberduck
.binding
.application
.NSButton
;
24 import ch
.cyberduck
.binding
.application
.NSCell
;
25 import ch
.cyberduck
.binding
.application
.NSPrintInfo
;
26 import ch
.cyberduck
.binding
.application
.NSPrintOperation
;
27 import ch
.cyberduck
.binding
.application
.NSPrintPanel
;
28 import ch
.cyberduck
.binding
.application
.NSTextField
;
29 import ch
.cyberduck
.binding
.application
.NSTextView
;
30 import ch
.cyberduck
.binding
.application
.NSView
;
31 import ch
.cyberduck
.binding
.application
.NSWindow
;
32 import ch
.cyberduck
.binding
.application
.SheetCallback
;
33 import ch
.cyberduck
.binding
.foundation
.NSArray
;
34 import ch
.cyberduck
.binding
.foundation
.NSAttributedString
;
35 import ch
.cyberduck
.binding
.foundation
.NSDictionary
;
36 import ch
.cyberduck
.binding
.foundation
.NSNotification
;
37 import ch
.cyberduck
.core
.Host
;
38 import ch
.cyberduck
.core
.LocaleFactory
;
39 import ch
.cyberduck
.core
.exception
.BackgroundException
;
40 import ch
.cyberduck
.core
.local
.BrowserLauncherFactory
;
41 import ch
.cyberduck
.core
.preferences
.PreferencesFactory
;
42 import ch
.cyberduck
.ui
.cocoa
.threading
.PanelAlertCallback
;
44 import org
.apache
.commons
.lang3
.StringUtils
;
45 import org
.apache
.log4j
.Logger
;
46 import org
.rococoa
.Foundation
;
47 import org
.rococoa
.ID
;
48 import org
.rococoa
.Rococoa
;
49 import org
.rococoa
.cocoa
.foundation
.NSPoint
;
50 import org
.rococoa
.cocoa
.foundation
.NSUInteger
;
52 import java
.util
.Collections
;
53 import java
.util
.HashSet
;
59 public abstract class WindowController
extends BundleController
implements NSWindow
.Delegate
{
60 private static Logger log
= Logger
.getLogger(WindowController
.class);
62 protected static final String DEFAULT
= LocaleFactory
.localizedString("Default");
64 public WindowController() {
69 public void invalidate() {
72 window
.setDelegate(null);
78 * The window this controller is owner of
81 protected NSWindow window
;
83 private Set
<WindowListener
> listeners
84 = Collections
.synchronizedSet(new HashSet
<WindowListener
>());
87 * @param listener Callback on window close
89 public void addListener(final WindowListener listener
) {
90 listeners
.add(listener
);
94 * @param listener Callback on window close
96 public void removeListener(final WindowListener listener
) {
97 listeners
.remove(listener
);
100 public void setWindow(final NSWindow window
) {
101 this.window
= window
;
102 window
.setReleasedWhenClosed(!this.isSingleton());
103 window
.setDelegate(this.id());
106 public NSWindow
window() {
111 * A singleton window is not released when closed and the controller is not invalidated
113 * @return Always false
115 * @see ch.cyberduck.binding.application.NSWindow#setReleasedWhenClosed(boolean)
117 public boolean isSingleton() {
122 * @return True if the controller window is on screen.
124 public boolean isVisible() {
125 final NSWindow w
= this.window();
129 return w
.isVisible();
133 public void windowDidBecomeKey(final NSNotification notification
) {
138 public void windowDidResignKey(final NSNotification notification
) {
143 public void windowDidBecomeMain(final NSNotification notification
) {
148 public void windowDidResignMain(final NSNotification notification
) {
152 public void windowWillEnterFullScreen(final NSNotification notification
) {
156 public void windowWillExitFullScreen(final NSNotification notification
) {
160 public void windowDidFailToEnterFullScreen(final NSWindow window
) {
161 log
.error("Error entering full screen");
165 * @see ch.cyberduck.binding.application.NSWindow.Delegate
168 public boolean windowShouldClose(final NSWindow sender
) {
173 * Override this method if the controller should not be invalidated after its window closes
176 public void windowWillClose(final NSNotification notification
) {
177 if(log
.isDebugEnabled()) {
178 log
.debug(String
.format("Window will close %s", notification
));
180 for(WindowListener listener
: listeners
.toArray(new WindowListener
[listeners
.size()])) {
181 listener
.windowWillClose();
183 if(!this.isSingleton()) {
184 //If the window is closed it is assumed the controller object is no longer used
190 * Position this controller's window relative to other open windows
192 protected void cascade() {
193 NSArray windows
= NSApplication
.sharedApplication().windows();
194 int count
= windows
.count().intValue();
196 NSWindow w
= Rococoa
.cast(windows
.objectAtIndex(new NSUInteger(count
- 1)), NSWindow
.class);
197 NSPoint origin
= w
.frame().origin
;
198 origin
= new NSPoint(origin
.x
.doubleValue(), origin
.y
.doubleValue() + w
.frame().size
.height
.doubleValue());
199 window
.setFrameTopLeftPoint(window
.cascadeTopLeftFromPoint(origin
));
204 * @param toggle Checkbox
205 * @param select Selected
207 protected void setState(final NSButton toggle
, final boolean select
) {
209 toggle
.performClick(null);
211 toggle
.setState(select ? NSCell
.NSOnState
: NSCell
.NSOffState
);
215 * @return True if this window has a sheet attached
217 public boolean hasSheet() {
221 return window
.attachedSheet() != null;
225 public boolean alert(final Host host
, final BackgroundException failure
,
226 final StringBuilder transcript
) {
227 return new PanelAlertCallback(this).alert(host
, failure
, transcript
);
232 * @return Return code from the dialog if called from background thread.
235 protected int alert(final NSAlert alert
) {
236 return this.alert(alert
, (String
) null);
241 * @param help Help URL
242 * @return Button selection
244 protected int alert(final NSAlert alert
, final String help
) {
245 final int[] response
= new int[1];
246 this.alert(alert
, new SheetCallback() {
248 public void callback(final int returncode
) {
249 response
[0] = returncode
;
256 * Display alert as sheet to the window of this controller
259 * @param callback Dismissed notification
261 protected void alert(final NSAlert alert
, final SheetCallback callback
) {
262 this.alert(alert
, callback
, null);
267 * @param callback Dismissed notification
268 * @param help Help URL
270 protected void alert(final NSAlert alert
, final SheetCallback callback
, final String help
) {
271 final SheetController c
= new AlertController(this, alert
) {
273 public void callback(final int returncode
) {
274 callback
.callback(returncode
);
278 protected void help() {
279 if(StringUtils
.isBlank(help
)) {
283 BrowserLauncherFactory
.get().open(help
);
291 * Attach a sheet to this window
293 * @param sheet The sheet to be attached to this window
294 * @see SheetController#beginSheet()
296 protected void alert(final NSWindow sheet
) {
297 this.alert(sheet
, new SheetCallback() {
299 public void callback(final int returncode
) {
306 * Attach a sheet to this window
308 * @param sheet The sheet to be attached to this window
309 * @param callback The callback to call after the sheet is dismissed
310 * @see SheetController#beginSheet()
312 protected void alert(final NSWindow sheet
, final SheetCallback callback
) {
313 final SheetController c
= new SheetController(this) {
315 public void callback(final int returncode
) {
316 callback
.callback(returncode
);
320 public NSWindow
window() {
327 protected void updateField(final NSTextView f
, final String value
) {
328 f
.setString(StringUtils
.isNotBlank(value
) ? value
: StringUtils
.EMPTY
);
331 protected void updateField(final NSTextField f
, final String value
) {
332 f
.setStringValue(StringUtils
.isNotBlank(value
) ? value
: StringUtils
.EMPTY
);
335 protected void updateField(final NSTextField f
, final String value
, final NSDictionary attributes
) {
336 f
.setAttributedStringValue(NSAttributedString
.attributedStringWithAttributes(StringUtils
.isNotBlank(value
) ? value
: StringUtils
.EMPTY
, attributes
));
341 public void helpButtonClicked(final NSButton sender
) {
342 BrowserLauncherFactory
.get().open(PreferencesFactory
.get().getProperty("website.help"));
345 protected void print(NSView view
) {
346 NSPrintInfo print
= NSPrintInfo
.sharedPrintInfo();
347 print
.setOrientation(NSPrintInfo
.NSPrintingOrientation
.NSLandscapeOrientation
);
348 NSPrintOperation op
= NSPrintOperation
.printOperationWithView_printInfo(view
, print
);
349 op
.setShowsPrintPanel(true);
350 final NSPrintPanel panel
= op
.printPanel();
351 panel
.setOptions(panel
.options() | NSPrintPanel
.NSPrintPanelShowsOrientation
352 | NSPrintPanel
.NSPrintPanelShowsPaperSize
| NSPrintPanel
.NSPrintPanelShowsScaling
);
353 op
.runOperationModalForWindow_delegate_didRunSelector_contextInfo(this.window(), this.id(),
354 Foundation
.selector("printOperationDidRun:success:contextInfo:"), null);
357 public void printOperationDidRun_success_contextInfo(NSPrintOperation op
, boolean success
, ID contextInfo
) {
359 log
.warn(String
.format("Printing failed for context %s", contextInfo
));