// optional and CredentialsManager has credentials for this location, popup the authentication dialog to
// avoid waiting for an AuthException to be thrown.
else if(!folderURL.containsCredentials() &&
( (authenticationType==AuthenticationType.AUTHENTICATION_REQUIRED)
|| (authenticationType==AuthenticationType.AUTHENTICATION_OPTIONAL && CredentialsManager.getMatchingCredentials(folderURL).length>0))) {
AuthDialog authDialog = popAuthDialog(folderURL, false, null);
newCredentialsMapping = authDialog.getCredentialsMapping();
guestCredentialsSelected = authDialog.guestCredentialsSelected();
// User cancelled the authentication dialog, stop
if(newCredentialsMapping ==null)
userCancelled = true;
// Use the provided credentials and invalidate the folder AbstractFile instance (if any) so that
// it gets recreated with the new credentials
else {
CredentialsManager.authenticate(folderURL, newCredentialsMapping);
folder = null;
}
}
if(!userCancelled) {
boolean canonicalPathFollowed = false;
do {
// Set cursor to hourglass/wait
mainFrame.setCursor(new Cursor(Cursor.WAIT_CURSOR));
// Render all actions inactive while changing folder
mainFrame.setNoEventsMode(true);
try {
// 2 cases here :
// - Thread was created using an AbstractFile instance
// - Thread was created using a FileURL, corresponding AbstractFile needs to be resolved
// Thread was created using a FileURL
if(folder==null) {
AbstractFile file = FileFactory.getFile(folderURL, true);
synchronized(KILL_LOCK) {
if(killed) {
LOGGER.debug("this thread has been killed, returning");
break;
}
}
// File resolved -> 25% complete
folderPanel.setProgressValue(25);
// Popup an error dialog and abort folder change if the file could not be resolved
// or doesn't exist
if(file==null || !file.exists()) {
// Restore default cursor
mainFrame.setCursor(Cursor.getDefaultCursor());
showFolderDoesNotExistDialog();
break;
}
// File is a regular directory, all good
if(file.isDirectory()) {
// Just continue
}
// File is a browsable file (Zip archive for instance) but not a directory : Browse or Download ? => ask the user
else if(file.isBrowsable()) {
// If history already contains this file, do not ask the question again and assume
// the user wants to 'browse' the file. In particular, this prevent the 'Download or browse'
// dialog from popping up when going back or forward in history.
// The dialog is also not displayed if the file corresponds to the currently selected file,
// which is a weak (and not so accurate) way to know if the folder change is the result
// of the OpenAction (enter pressed on the file). This works well enough in practice.
if(!globalHistory.historyContains(folderURL) && !file.equals(folderPanel.getFileTable().getSelectedFile())) {
// Restore default cursor
mainFrame.setCursor(Cursor.getDefaultCursor());
// Download or browse file ?
QuestionDialog dialog = new QuestionDialog(mainFrame,
null,
Translator.get("table.download_or_browse"),
mainFrame,
new String[] {BROWSE_TEXT, DOWNLOAD_TEXT, CANCEL_TEXT},
new int[] {BROWSE_ACTION, DOWNLOAD_ACTION, CANCEL_ACTION},
0);
int ret = dialog.getActionValue();
if(ret==-1 || ret==CANCEL_ACTION)
break;
// Download file
if(ret==DOWNLOAD_ACTION) {
showDownloadDialog(file);
break;
}
// Continue if BROWSE_ACTION
// Set cursor to hourglass/wait
mainFrame.setCursor(new Cursor(Cursor.WAIT_CURSOR));
}
// else just continue and browse file's contents
}
// File is a regular file: show download dialog which allows to download (copy) the file
// to a directory specified by the user
else {
showDownloadDialog(file);
break;
}
this.folder = file;
}
// Thread was created using an AbstractFile instance, check file existence
else if(!folder.exists()) {
// Find a 'workable' folder if the requested folder doesn't exist anymore
if(findWorkableFolder) {
AbstractFile newFolder = getWorkableFolder(folder);
if(newFolder.equals(folder)) {
// If we've already tried the returned folder, give up (avoids a potentially endless loop)
showFolderDoesNotExistDialog();
break;
}
// Try again with the new folder
folder = newFolder;
folderURL = folder.getURL();
// Discard the file to select, if any
fileToSelect = null;
continue;
}
else {
showFolderDoesNotExistDialog();
break;
}
}
// Checks if canonical should be followed. If that is the case, the file is invalidated
// and resolved again. This happens only once at most, to avoid a potential infinite loop
// in the event that the absolute path still didn't match canonical one after the file is
// resolved again.
if(!canonicalPathFollowed && followCanonicalPath(folder)) {
try {
// Recreate the FileURL using the file's canonical path
FileURL newURL = FileURL.getFileURL(folder.getCanonicalPath());
// Keep the credentials and properties (if any)
newURL.setCredentials(folderURL.getCredentials());
newURL.importProperties(folderURL);
this.folderURL = newURL;
// Invalidate the AbstractFile instance
this.folder = null;
// There won't be any further attempts after this one
canonicalPathFollowed = true;
// Loop the resolve the file
continue;
}
catch(MalformedURLException e) {
// In the unlikely event of the canonical path being malformed, the AbstractFile
// and FileURL instances are left untouched
}
}
synchronized(KILL_LOCK) {
if(killed) {
LOGGER.debug("this thread has been killed, returning");
break;
}
}
// File tested -> 50% complete
folderPanel.setProgressValue(50);
/* TODO branch
AbstractFile children[] = new AbstractFile[0];
if (branchView) {
childrenList = new ArrayList();
readBranch(folder);
children = (AbstractFile[]) childrenList.toArray(children);
} else {
children = folder.ls(chainedFileFilter);
}*/
synchronized(KILL_LOCK) {
if(killed) {
LOGGER.debug("this thread has been killed, returning");
break;
}
// From now on, thread cannot be killed (would comprise table integrity)
doNotKill = true;
}
// files listed -> 75% complete
folderPanel.setProgressValue(75);
LOGGER.trace("calling setCurrentFolder");
// Change the file table's current folder and select the specified file (if any)
setCurrentFolder(folder, fileToSelect, changeLockedTab);
// folder set -> 95% complete
folderPanel.setProgressValue(95);
// If new credentials were entered by the user, these can now be considered valid
// (folder was changed successfully), so we add them to the CredentialsManager.
// Do not add the credentials if guest credentials were selected by the user.
if(newCredentialsMapping!=null && !guestCredentialsSelected)
CredentialsManager.addCredentials(newCredentialsMapping);
// All good !
folderChangedSuccessfully = true;
break;
}
catch(Exception e) {
LOGGER.debug("Caught exception", e);
if(killed) {
// If #tryKill() called #interrupt(), the exception we just caught was most likely
// thrown as a result of the thread being interrupted.
//
// The exception can be a java.lang.InterruptedException (Thread throws those),
// a java.nio.channels.ClosedByInterruptException (InterruptibleChannel throws those)
// or any other exception thrown by some code that swallowed the original exception
// and threw a new one.
LOGGER.debug("Thread was interrupted, ignoring exception");
break;
}
// Restore default cursor
mainFrame.setCursor(Cursor.getDefaultCursor());
if(e instanceof AuthException) {
AuthException authException = (AuthException)e;
// Retry (loop) if user provided new credentials, if not stop
AuthDialog authDialog = popAuthDialog(authException.getURL(), true, authException.getMessage());
newCredentialsMapping = authDialog.getCredentialsMapping();
guestCredentialsSelected = authDialog.guestCredentialsSelected();
if(newCredentialsMapping!=null) {
// Invalidate the existing AbstractFile instance
folder = null;
// Use the provided credentials