/*==========================================================================*\
| $Id: FilePickerDialog.java,v 1.5 2012/06/22 16:23:18 aallowat Exp $
|*-------------------------------------------------------------------------*|
| Copyright (C) 2011-2012 Virginia Tech
|
| This file is part of Web-CAT.
|
| Web-CAT is free software; you can redistribute it and/or modify
| it under the terms of the GNU Affero General Public License as published
| by the Free Software Foundation; either version 3 of the License, or
| (at your option) any later version.
|
| Web-CAT is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU Affero General Public License
| along with Web-CAT; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/
package org.webcat.core;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.webcat.archives.ArchiveManager;
import org.webcat.core.git.GitCommit;
import org.webcat.core.git.GitRef;
import org.webcat.core.git.GitRepository;
import org.webcat.core.git.GitTreeEntry;
import org.webcat.core.git.GitUtilities;
import org.webcat.ui.generators.JavascriptGenerator;
import org.webcat.ui.util.ComponentIDGenerator;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WOResponse;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSData;
import com.webobjects.foundation.NSSet;
import com.webobjects.foundation.NSTimestamp;
//-------------------------------------------------------------------------
/**
* A modal dialog that lets the user choose a file from any of the
* repositories that they have access to.
*
* @author Tony Allevato
* @author Last changed by $Author: aallowat $
* @version $Revision: 1.5 $, $Date: 2012/06/22 16:23:18 $
*/
public class FilePickerDialog
extends WCComponent
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
public FilePickerDialog(WOContext context)
{
super(context);
}
//~ KVC attributes (must be public) .......................................
public String id;
public String title;
public RepositoryRefModel refModel;
public Object repositoryItem;
public RepositoryEntryModel entryModel;
public GitTreeEntry entry;
public RepositoryEntryRef initialSelection;
public GitRepository createFolderRepo;
public String createFolderLocation;
public String newFolderName;
public String uploadedFilePath;
public NSData uploadedFileData;
public String commitMessageForUpload;
public boolean expandIfArchive;
public ComponentIDGenerator idFor = new ComponentIDGenerator(this);
//~ Methods ...............................................................
// ----------------------------------------------------------
@Override
public void appendToResponse(WOResponse response, WOContext context)
{
if (id == null)
{
id = idFor.get();
}
updateRefModel();
super.appendToResponse(response, context);
}
// ----------------------------------------------------------
public String onLoad()
{
updateRefModel();
return null;
}
// ----------------------------------------------------------
private void updateRefModel()
{
NSArray<? extends EOBase> providers =
RepositoryManager.getInstance().repositoriesPresentedToUser(
user(), localContext());
refModel = new RepositoryRefModel(providers);
if (initialSelection != null)
{
refModel.setSelectionFromEntryRef(initialSelection,
localContext(), user());
}
updateEntryModel();
}
// ----------------------------------------------------------
private GitRef refForModelObject(Object object)
{
GitRef ref;
if (object instanceof EOBase)
{
GitRepository repo = GitRepository.repositoryForObject(
(EOBase) object);
ref = repo.refWithName(Constants.R_HEADS + Constants.MASTER);
}
else
{
ref = (GitRef) object;
}
return ref;
}
// ----------------------------------------------------------
private void updateEntryModel()
{
NSSet<?> selectedRefs = refModel.selectedObjects();
if (selectedRefs.isEmpty())
{
entryModel = new RepositoryEntryModel(null);
}
else
{
entryModel = new RepositoryEntryModel(
refForModelObject(selectedRefs.anyObject()))
{
@Override
public boolean canSelectObject(GitTreeEntry anEntry)
{
return delegate.fileCanBeSelected(
filePickerItemForEntry(anEntry), anEntry.isTree());
}
};
if (initialSelection != null)
{
entryModel.setSelectionFromEntryRef(initialSelection,
localContext());
}
}
}
// ----------------------------------------------------------
public boolean canSelectEntry()
{
return entryModel.canSelectObject(entry);
}
// ----------------------------------------------------------
public String cssStyleForItem()
{
if (canSelectEntry())
{
return null;
}
else
{
return "opacity: 0.4;";
}
}
// ----------------------------------------------------------
public boolean canModifySelectedBranch()
{
boolean canModify = false;
Object refModelObject = refModel.selectedObjects().anyObject();
if (refModelObject != null)
{
GitRef ref = refForModelObject(refModelObject);
canModify = (ref != null && ref.isMaster());
}
return canModify;
}
// ----------------------------------------------------------
public JavascriptGenerator refWasSelected()
{
initialSelection = null;
updateEntryModel();
JavascriptGenerator js = new JavascriptGenerator();
js.refresh(idFor.get("entryTree"));
if (canModifySelectedBranch())
{
js.dijit(idFor.get("createFolder")).enable();
js.dijit(idFor.get("uploadFile")).enable();
}
else
{
js.dijit(idFor.get("createFolder")).disable();
js.dijit(idFor.get("uploadFile")).disable();
}
return js;
}
// ----------------------------------------------------------
public JavascriptGenerator entryWasDoubleClicked()
{
JavascriptGenerator js = new JavascriptGenerator();
js.dijit(id).call("hide");
js.append(okPressed());
return js;
}
// ----------------------------------------------------------
public String displayNameForRepositoryItem()
{
if (repositoryItem instanceof EOBase)
{
return RepositoryManager.getInstance().repositoryNameForObject(
(EOBase) repositoryItem);
}
else
{
return ((GitRef) repositoryItem).shortName();
}
}
// ----------------------------------------------------------
public String iconPathForRepositoryItem()
{
if (repositoryItem instanceof EOEnterpriseObject)
{
return "icons/filetypes/drawer.png";
}
else
{
return ((GitRef) repositoryItem).isTag() ?
"icons/tag.png" : "icons/node.png";
}
}
// ----------------------------------------------------------
public Long sizeForEntry()
{
return entry.isTree() ? null : entry.size();
}
// ----------------------------------------------------------
public String iconPathForEntry()
{
return entry.isTree() ? "icons/filetypes/folder.png" :
FileUtilities.iconURL(entry.name());
}
// ----------------------------------------------------------
public NSTimestamp lastModifiedTimeForEntry()
{
GitRef ref = refForModelObject(refModel.selectedObjects().anyObject());
NSArray<GitCommit> commits =
entry.repository().commitsWithId(ref.objectId(), entry.path());
if (commits != null && commits.count() > 0)
{
return commits.objectAtIndex(0).commitTime();
}
else
{
return null;
}
}
// ----------------------------------------------------------
public FilePickerDelegate delegate()
{
return delegate;
}
// ----------------------------------------------------------
public void setDelegate(FilePickerDelegate delegate)
{
this.delegate = delegate;
}
// ----------------------------------------------------------
private RepositoryEntryRef filePickerItemForEntry(GitTreeEntry anEntry)
{
NSSet<?> selectedRepos = refModel.selectedObjects();
if (!selectedRepos.isEmpty())
{
GitRef ref = refForModelObject(selectedRepos.anyObject());
String providerName = RepositoryManager.getInstance()
.repositoryNameForObject(ref.repository().provider());
String path = anEntry.path();
if (anEntry.isTree())
{
path += "/";
}
RepositoryEntryRef item = new RepositoryEntryRef(
providerName, path, ref.name());
return item;
}
else
{
return null;
}
}
// ----------------------------------------------------------
public JavascriptGenerator okPressed()
{
NSSet<GitTreeEntry> selectedEntries = entryModel.selectedObjects();
if (selectedEntries.isEmpty())
{
return null;
}
else
{
GitTreeEntry anEntry = selectedEntries.anyObject();
if (delegate != null)
{
return delegate.fileWasSelected(
filePickerItemForEntry(anEntry));
}
else
{
return null;
}
}
}
// ----------------------------------------------------------
public JavascriptGenerator displayCreateFolderDialog()
{
return showModifierDialog("createFolderDialog");
}
// ----------------------------------------------------------
public JavascriptGenerator createFolderOkPressed()
{
JavascriptGenerator js = new JavascriptGenerator();
js.dijit(idFor.get("createFolderDialog")).call("hide");
Repository workingCopy = GitUtilities.workingCopyForRepository(
createFolderRepo.repository(), true);
File file = workingCopy.getWorkTree();
File destDir = file;
if (createFolderLocation != null)
{
destDir = new File(file, createFolderLocation);
}
File newFolder = new File(destDir, newFolderName);
if (newFolder.exists())
{
js.alert("Notice", "The folder already exists.");
return js;
}
try
{
newFolder.mkdirs();
File gitIgnore = new File(newFolder, ".gitignore");
FileOutputStream os = new FileOutputStream(gitIgnore);
os.close();
GitUtilities.pushWorkingCopyImmediately(workingCopy, user(),
"Created folder \"" + newFolderName + "\"");
}
catch (Exception e)
{
log.error("error creating the folder " + newFolderName + " as "
+ newFolder + ": ", e);
js.alert("Notice", "The following error occurred trying to create "
+ "the folder \"" + newFolderName + "\": " + e.getMessage());
return js;
}
updateRefModel();
js.refresh(idFor.get("repositoryTree"), idFor.get("entryTree"));
return js;
}
// ----------------------------------------------------------
private JavascriptGenerator showModifierDialog(String dialogId)
{
NSSet<?> selectedRepos = refModel.selectedObjects();
if (selectedRepos.isEmpty())
{
return new JavascriptGenerator().alert(
"Notice", "You must select the master branch of a "
+ "repository first.");
}
if (!canModifySelectedBranch())
{
return new JavascriptGenerator().alert("Notice",
"You may only modify the master branch of a "
+ "repository through the web interface.");
}
GitRef ref = refForModelObject(selectedRepos.anyObject());
createFolderRepo = ref.repository();
NSSet<GitTreeEntry> selectedEntries = entryModel.selectedObjects();
if (selectedEntries.isEmpty())
{
createFolderLocation = null;
}
else
{
GitTreeEntry anEntry = selectedEntries.anyObject();
if (anEntry.isTree())
{
createFolderLocation = anEntry.path();
}
else
{
File file = new File(anEntry.path());
createFolderLocation = file.getParent();
}
}
JavascriptGenerator js = new JavascriptGenerator();
js.dijit(idFor.get(dialogId)).call("show");
return js;
}
// ----------------------------------------------------------
public JavascriptGenerator displayUploadFileDialog()
{
if (commitMessageForUpload == null)
{
commitMessageForUpload = "Uploaded from my web browser";
}
return showModifierDialog("uploadFileDialog");
}
// ----------------------------------------------------------
public JavascriptGenerator fileWasUploaded()
{
uploadedFilePath = new File(uploadedFilePath).getName();
JavascriptGenerator js = new JavascriptGenerator();
// FIXME Why doesn't this code run on the production server? Problem
// because it gets sent back in a textarea due to iframe I/O weirdness?
/* boolean isArchive = FileUtilities.isArchiveFile(uploadedFilePath);
js.style(idFor.get("expandIfArchiveContainer"), "visibility",
isArchive ? "visible" : "hidden");
js.dijit(idFor.get("uploadFileOk")).enable();*/
return js;
}
// ----------------------------------------------------------
public JavascriptGenerator uploadFileOkPressed()
{
JavascriptGenerator js = new JavascriptGenerator();
js.dijit(idFor.get("uploadFileDialog")).call("hide");
if (uploadedFilePath == null)
{
return js;
}
Repository workingCopy = GitUtilities.workingCopyForRepository(
createFolderRepo.repository(), true);
File file = workingCopy.getWorkTree();
File destDir = file;
if (createFolderLocation != null)
{
destDir = new File(file, createFolderLocation);
}
File destFile = new File(destDir, uploadedFilePath);
try
{
if (expandIfArchive
&& FileUtilities.isArchiveFile(uploadedFilePath))
{
ArchiveManager.getInstance().unpack(
destDir, uploadedFilePath, uploadedFileData.stream());
}
else
{
FileOutputStream os = new FileOutputStream(destFile);
uploadedFileData.writeToStream(os);
os.close();
}
GitUtilities.pushWorkingCopyImmediately(
workingCopy, user(), commitMessageForUpload);
}
catch (IOException e)
{
log.error("error uploading file " + uploadedFilePath + " as "
+ destFile + ": ", e);
js.alert("Error", "The following error occurred trying to upload the "
+ "file \"" + uploadedFilePath + "\": " + e.getMessage());
return js;
}
updateRefModel();
js.refresh(idFor.get("repositoryTree"), idFor.get("entryTree"));
return js;
}
//~ Static/instance variables .............................................
private FilePickerDelegate delegate;
}