Fix transcript in transfer window.
[cyberduck.git] / source / ch / cyberduck / ui / cocoa / SheetController.java
blobe9e69e69f09f79c17a7d9e1475859fffc3b829d6
1 package ch.cyberduck.ui.cocoa;
3 /*
4 * Copyright (c) 2005 David Kocher. All rights reserved.
5 * http://cyberduck.ch/
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.AppKitFunctionsLibrary;
22 import ch.cyberduck.binding.application.NSApplication;
23 import ch.cyberduck.binding.application.NSButton;
24 import ch.cyberduck.binding.application.NSPanel;
25 import ch.cyberduck.binding.application.NSWindow;
26 import ch.cyberduck.binding.application.SheetCallback;
27 import ch.cyberduck.binding.foundation.NSThread;
28 import ch.cyberduck.core.threading.ControllerMainAction;
30 import org.apache.log4j.Logger;
31 import org.rococoa.Foundation;
32 import org.rococoa.ID;
34 import java.util.HashSet;
35 import java.util.Set;
36 import java.util.concurrent.CountDownLatch;
38 /**
39 * @version $Id$
41 public abstract class SheetController extends WindowController implements SheetCallback {
42 private static Logger log = Logger.getLogger(SheetController.class);
44 /**
45 * Keep a reference to the sheet to protect it from being
46 * deallocated as a weak reference before the callback from the runtime
48 protected static final Set<SheetController> sheetRegistry
49 = new HashSet<SheetController>();
51 /**
52 * The controller of the parent window
54 protected final WindowController parent;
56 /**
57 * Dismiss button clicked
59 private int returncode;
61 private CountDownLatch signal;
63 /**
64 * The sheet window must be provided later with #setWindow (usually called when loading the NIB file)
66 * @param parent The controller of the parent window
68 public SheetController(final WindowController parent) {
69 this.parent = parent;
70 sheetRegistry.add(this);
73 /**
74 * @return Null by default, a sheet with no custom NIB
76 @Override
77 protected String getBundleName() {
78 return null;
81 /**
82 * Translate return codes from sheet selection
84 * @param selected Button pressed
85 * @return Sheet callback constant
86 * @see SheetCallback#DEFAULT_OPTION
87 * @see SheetCallback#CANCEL_OPTION
89 protected int getCallbackOption(NSButton selected) {
90 if(selected.tag() == NSPanel.NSCancelButton) {
91 return SheetCallback.CANCEL_OPTION;
93 return SheetCallback.DEFAULT_OPTION;
96 /**
97 * This must be the target action for any button in the sheet dialog. Will validate the input
98 * and close the sheet; #sheetDidClose will be called afterwards
100 * @param sender A button in the sheet dialog
102 @Action
103 public void closeSheet(final NSButton sender) {
104 if(log.isDebugEnabled()) {
105 log.debug(String.format("Close sheet with button %s", sender.title()));
107 if(this.getCallbackOption(sender) == DEFAULT_OPTION || this.getCallbackOption(sender) == ALTERNATE_OPTION) {
108 if(!this.validateInput()) {
109 AppKitFunctionsLibrary.beep();
110 return;
113 NSApplication.sharedApplication().endSheet(this.window(), this.getCallbackOption(sender));
117 * @return The tag of the button this sheet was dismissed with
119 public int returnCode() {
120 return this.returncode;
124 * Check input fields for any errors
126 * @return true if a valid input has been given
128 protected boolean validateInput() {
129 return true;
132 public void beginSheet() {
133 synchronized(parent.window()) {
134 signal = new CountDownLatch(1);
135 if(NSThread.isMainThread()) {
136 // No need to call invoke on main thread
137 this.beginSheetImpl();
139 else {
140 invoke(new ControllerMainAction(this) {
141 @Override
142 public void run() {
143 //Invoke again on main thread
144 beginSheetImpl();
146 }, true);
147 if(log.isDebugEnabled()) {
148 log.debug("Await sheet dismiss");
150 // Synchronize on parent controller. Only display one sheet at once.
151 try {
152 signal.await();
154 catch(InterruptedException e) {
155 log.error("Error waiting for sheet dismiss", e);
156 this.callback(CANCEL_OPTION);
162 protected void beginSheetImpl() {
163 this.loadBundle();
164 parent.window().makeKeyAndOrderFront(null);
165 NSApplication.sharedApplication().beginSheet(this.window(), //window
166 parent.window(), // modalForWindow
167 this.id(), // modalDelegate
168 Foundation.selector("sheetDidClose:returnCode:contextInfo:"),
169 null); //context
173 * Called by the runtime after a sheet has been dismissed. Ends any modal session and
174 * sends the returncode to the callback implementation. Also invalidates this controller to be
175 * garbage collected and notifies the lock object
177 * @param sheet Sheet window
178 * @param returncode Identifier for the button clicked by the user
179 * @param contextInfo Not used
181 public void sheetDidClose_returnCode_contextInfo(final NSWindow sheet, final int returncode, ID contextInfo) {
182 sheet.orderOut(null);
183 this.returncode = returncode;
184 this.callback(returncode);
185 signal.countDown();
186 if(!this.isSingleton()) {
187 this.invalidate();
191 @Override
192 public void invalidate() {
193 sheetRegistry.remove(this);
194 super.invalidate();
198 * @return True if the class is a singleton and the object should
199 * not be invlidated upon the sheet is closed
200 * @see #sheetDidClose_returnCode_contextInfo(ch.cyberduck.binding.application.NSWindow, int, org.rococoa.ID)
202 @Override
203 public boolean isSingleton() {
204 return false;