package org.nbgit.ui.status;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import javax.swing.Action;
import org.nbgit.StatusInfo;
import org.nbgit.Git;
import org.nbgit.ui.GitFileNode;
import org.nbgit.ui.diff.DiffAction;
import org.nbgit.util.GitUtils;
import org.nbgit.util.HtmlFormatter;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.util.lookup.Lookups;
/**
* The node that is rendered in the SyncTable view. It gets values to display
* from the GitFileNode which serves as the 'data' node for this 'visual' node.
*
* @author Maros Sandor
*/
public class SyncFileNode extends AbstractNode {
private GitFileNode node;
static final String COLUMN_NAME_NAME = "name"; // NOI18N;
static final String COLUMN_NAME_PATH = "path"; // NOI18N;
static final String COLUMN_NAME_STATUS = "status"; // NOI18N;
static final String COLUMN_NAME_BRANCH = "branch"; // NOI18N;
private String htmlDisplayName;
private RequestProcessor.Task repoload;
private final VersioningPanel panel;
public SyncFileNode(GitFileNode node, VersioningPanel _panel) {
this(Children.LEAF, node, _panel);
}
private SyncFileNode(Children children, GitFileNode node, VersioningPanel _panel) {
super(children, Lookups.fixed(node.getLookupObjects()));
this.node = node;
this.panel = _panel;
initProperties();
refreshHtmlDisplayName();
}
public File getFile() {
return node.getFile();
}
public StatusInfo getFileInformation() {
return node.getInformation();
}
@Override
public String getName() {
return node.getName();
}
@Override
public Action getPreferredAction() {
// TODO: getPreferedAction
if (node.getInformation().getStatus() == StatusInfo.STATUS_VERSIONED_CONFLICT) {
return null;
}
return new DiffAction(null, GitUtils.getCurrentContext(null));
}
/**
* Provide cookies to actions.
* If a node represents primary file of a DataObject
* it has respective DataObject cookies.
*/
@SuppressWarnings("unchecked") // Adding getCookie(Class<Cookie> klass) results in name clash
@Override
public Cookie getCookie(Class klass) {
FileObject fo = FileUtil.toFileObject(getFile());
if (fo != null) {
try {
DataObject dobj = DataObject.find(fo);
if (fo.equals(dobj.getPrimaryFile())) {
return dobj.getCookie(klass);
}
} catch (DataObjectNotFoundException e) {
// ignore file without data objects
}
}
return super.getCookie(klass);
}
private void initProperties() {
if (node.getFile().isDirectory()) {
setIconBaseWithExtension("org/openide/loaders/defaultFolder.gif"); // NOI18N
}
Sheet sheet = Sheet.createDefault();
Sheet.Set ps = Sheet.createPropertiesSet();
ps.put(new NameProperty());
ps.put(new PathProperty());
ps.put(new StatusProperty());
ps.put(new BranchProperty());
sheet.put(ps);
setSheet(sheet);
}
private void refreshHtmlDisplayName() {
StatusInfo info = node.getInformation();
int status = info.getStatus();
// Special treatment: Mergeable status should be annotated as Conflict in Versioning view according to UI spec
if (status == StatusInfo.STATUS_VERSIONED_MERGE) {
status = StatusInfo.STATUS_VERSIONED_CONFLICT;
}
htmlDisplayName = HtmlFormatter.getInstance().annotateNameHtml(node.getFile().getName(), info, null);
fireDisplayNameChange(node.getName(), node.getName());
}
@Override
public String getHtmlDisplayName() {
return htmlDisplayName;
}
public void refresh() {
refreshHtmlDisplayName();
}
private abstract class SyncFileProperty extends org.openide.nodes.PropertySupport.ReadOnly {
@SuppressWarnings("unchecked")
protected SyncFileProperty(String name, Class type, String displayName, String shortDescription) {
super(name, type, displayName, shortDescription);
}
@Override
public String toString() {
try {
return getValue().toString();
} catch (Exception e) {
Git.LOG.log(Level.INFO, null, e);
return e.getLocalizedMessage();
}
}
}
private class BranchProperty extends SyncFileProperty {
public BranchProperty() {
super(COLUMN_NAME_BRANCH, String.class, NbBundle.getMessage(SyncFileNode.class, "BK2001"), NbBundle.getMessage(SyncFileNode.class, "BK2002")); // NOI18N
}
public Object getValue() {
String branchInfo = panel.getDisplayBranchInfo();
return branchInfo == null ? "" : branchInfo; // NOI18N
}
}
private class PathProperty extends SyncFileProperty {
private String shortPath;
public PathProperty() {
super(COLUMN_NAME_PATH, String.class, NbBundle.getMessage(SyncFileNode.class, "BK2003"), NbBundle.getMessage(SyncFileNode.class, "BK2004")); // NOI18N
shortPath = GitUtils.getRelativePath(node.getFile());
setValue("sortkey", shortPath + "\t" + SyncFileNode.this.getName()); // NOI18N
}
public Object getValue() throws IllegalAccessException, InvocationTargetException {
return shortPath;
}
}
// XXX it's not probably called, are there another Node lifecycle events
@Override
public void destroy() throws IOException {
super.destroy();
if (repoload != null) {
repoload.cancel();
}
}
private class NameProperty extends SyncFileProperty {
public NameProperty() {
super(COLUMN_NAME_NAME, String.class, NbBundle.getMessage(SyncFileNode.class, "BK2005"), NbBundle.getMessage(SyncFileNode.class, "BK2006")); // NOI18N
setValue("sortkey", SyncFileNode.this.getName()); // NOI18N
}
public Object getValue() throws IllegalAccessException, InvocationTargetException {
return SyncFileNode.this.getDisplayName();
}
}
private static final String[] zeros = new String[]{"", "00", "0", ""}; // NOI18N
private class StatusProperty extends SyncFileProperty {
public StatusProperty() {
super(COLUMN_NAME_STATUS, String.class, NbBundle.getMessage(SyncFileNode.class, "BK2007"), NbBundle.getMessage(SyncFileNode.class, "BK2008")); // NOI18N
String shortPath = GitUtils.getRelativePath(node.getFile()); // NOI18N
String sortable = Integer.toString(GitUtils.getComparableStatus(node.getInformation().getStatus()));
setValue("sortkey", zeros[sortable.length()] + sortable + "\t" + shortPath + "\t" + SyncFileNode.this.getName()); // NOI18N
}
public Object getValue() throws IllegalAccessException, InvocationTargetException {
StatusInfo finfo = node.getInformation();
//TODO: finfo.getEntry(node.getFile()); // XXX not interested in return value, side effect loads ISVNStatus structure
int mask = panel.getDisplayStatuses();
return finfo.getStatusText(mask);
}
}
}