blob: 9452a15045dc1bbcb1c3c510d1c96e1fbb324bd7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.versioning.ui.history;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorSupport;
import java.io.File;
import java.io.IOException;
import javax.swing.Action;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.util.*;
import java.util.logging.Level;
import org.netbeans.modules.versioning.core.api.VCSFileProxy;
import org.openide.nodes.PropertySupport;
import org.openide.nodes.Sheet;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
/**
*
* @author Tomas Stupka
*
*/
class RevisionNode extends AbstractNode implements Comparable {
static final String PROPERTY_NAME_LABEL = "label"; // NOI18N
static final String PROPERTY_NAME_USER = "user"; // NOI18N
static final String PROPERTY_NAME_VERSION = "version"; // NOI18N
private HistoryEntry entry;
private static DateFormat dateFormat = DateFormat.getDateTimeInstance();
private static DateFormat timeFormat = DateFormat.getTimeInstance();
private RevisionNode(HistoryEntry entry, Lookup l) {
super(createChildren(entry), l);
this.entry = entry;
initProperties();
}
static RevisionNode create(HistoryEntry entry) {
List<Object> lookup = new LinkedList<Object>();
VCSFileProxy[] proxies = entry.getFiles();
for (VCSFileProxy proxy : proxies) {
lookup.add(proxy);
File f = proxy.toFile();
if(f != null) {
lookup.add(f);
}
}
lookup.addAll(Arrays.asList(entry.getLookupObjects()));
lookup.add(entry);
return new RevisionNode(entry, Lookups.fixed(lookup.toArray(new Object[lookup.size()])));
}
private static Children createChildren(HistoryEntry entry) {
if(entry.getFiles().length == 1) {
return Children.LEAF;
} else {
FileNode[] nodes = new FileNode[entry.getFiles().length];
int i = 0;
for (VCSFileProxy file : entry.getFiles()) {
nodes[i++] = new FileNode(entry, file);
}
Children.SortedArray children = new Children.SortedArray();
children.add(nodes);
return children;
}
}
private void initProperties() {
Sheet sheet = Sheet.createDefault();
Sheet.Set ps = Sheet.createPropertiesSet();
ps.put(new RevisionProperty()); // XXX show only if VCS available
ps.put(new UserProperty());
ps.put(entry.canEdit() ? new EditableMessageProperty() : new MessageProperty());
sheet.put(ps);
setSheet(sheet);
}
@Override
public String getDisplayName() {
return getName();
}
@Override
public String getName() {
return getFormatedDate(entry);
}
@Override
public String toString() {
return getName();
}
static String getFormatedDate(HistoryEntry se) {
int day = getDay(se.getDateTime().getTime());
switch(day) {
case 0: return NbBundle.getMessage(RevisionNode.class, "LBL_Today", new Object[] {timeFormat.format(se.getDateTime())});
case 1: return NbBundle.getMessage(RevisionNode.class, "LBL_Yesterday", new Object[] {timeFormat.format(se.getDateTime())});
default: return dateFormat.format(se.getDateTime());
}
}
private static int getDay(long ts) {
Date date = new Date(ts);
Calendar c = Calendar.getInstance();
c.setTime(new Date());
// set the cal at today midnight
int todayMillis = c.get(Calendar.HOUR_OF_DAY) * 60 * 60 * 1000 +
c.get(Calendar.MINUTE) * 60 * 1000 +
c.get(Calendar.SECOND) * 1000 +
c.get(Calendar.MILLISECOND);
c.add(Calendar.MILLISECOND, -1 * todayMillis);
if(c.getTime().compareTo(date) < 0) {
return 0;
}
return (int) ( (c.getTimeInMillis() - ts) / (24 * 60 * 60 * 1000) ) + 1;
}
@Override
public Action[] getActions(boolean context) {
return entry.getActions();
}
@Override
public int compareTo(Object obj) {
if(!(obj instanceof RevisionNode)) {
return -1;
}
RevisionNode node = (RevisionNode) obj;
return entry.getDateTime().compareTo(node.entry.getDateTime());
}
class MessageProperty extends PropertySupport.ReadOnly<TableEntry> {
private TableEntry te;
public MessageProperty() {
super(PROPERTY_NAME_LABEL, TableEntry.class, NbBundle.getMessage(RevisionNode.class, "LBL_LabelProperty_Name"), NbBundle.getMessage(RevisionNode.class, "LBL_LabelProperty_Desc"));
te = new TableEntry() {
@Override
public String getDisplayValue() {
return entry.getMessage();
}
@Override
public String getTooltip() {
return entry.getMessage();
}
};
}
@Override
public TableEntry getValue() throws IllegalAccessException, InvocationTargetException {
return te;
}
@Override
public String toString() {
return entry.getMessage();
}
}
class EditableMessageProperty extends PropertySupport.ReadWrite<TableEntry> {
private TableEntry te;
public EditableMessageProperty() {
super(PROPERTY_NAME_LABEL, TableEntry.class, NbBundle.getMessage(RevisionNode.class, "LBL_LabelProperty_Name"), NbBundle.getMessage(RevisionNode.class, "LBL_LabelProperty_Desc"));
te = new MsgEntry(entry);
}
@Override
public TableEntry getValue() throws IllegalAccessException, InvocationTargetException {
return te;
}
@Override
public void setValue(TableEntry te) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
this.te = te;
}
@Override
public PropertyEditor getPropertyEditor() {
return new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (text instanceof String) {
try {
entry.setMessage(!text.equals("") ? text : null);
} catch (IOException ex) {
History.LOG.log(Level.WARNING, null, ex);
}
return;
}
throw new java.lang.IllegalArgumentException(text);
}
@Override
public String getAsText() {
return te.getDisplayValue();
}
};
}
@Override
public String toString() {
return entry.getMessage();
}
private class MsgEntry extends TableEntry {
private final HistoryEntry entry;
public MsgEntry(HistoryEntry entry) {
this.entry = entry;
}
@Override
public String getDisplayValue() {
return entry.getMessage();
}
@Override
public String getTooltip() {
String tooltip = entry.getMessage();
if(tooltip == null || "".equals(tooltip.trim())) { // NOI18N
tooltip = NbBundle.getMessage(RevisionNode.class, "LBL_SetTooltip"); // NOI18N
}
return tooltip;
}
@Override
public String toString() {
return entry.getMessage();
}
@Override
public int hashCode() {
int hash = 7;
hash = 11 * hash + (this.entry.getMessage() != null ? this.entry.getMessage().hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final MsgEntry other = (MsgEntry) obj;
String msg1 = entry.getMessage();
String msg2 = other.entry.getMessage();
if (msg1 == null || !msg1.equals(msg2)) {
return false;
}
return true;
}
}
}
class UserProperty extends PropertySupport.ReadOnly<TableEntry> {
private TableEntry te;
public UserProperty() {
super(PROPERTY_NAME_USER, TableEntry.class, NbBundle.getMessage(RevisionNode.class, "LBL_UserProperty_Name"), NbBundle.getMessage(RevisionNode.class, "LBL_UserProperty_Desc"));
te = new UserEntry(entry);
}
@Override
public TableEntry getValue() throws IllegalAccessException, InvocationTargetException {
return te;
}
@Override
public String toString() {
return entry.getUsername();
}
private class UserEntry extends TableEntry {
private final HistoryEntry entry;
public UserEntry(HistoryEntry entry) {
this.entry = entry;
}
@Override
public String getDisplayValue() {
return entry.getUsernameShort();
}
@Override
public String getTooltip() {
return entry.getUsername();
}
@Override
public int hashCode() {
int hash = 7;
hash = 47 * hash + (this.entry.getUsernameShort() != null ? this.entry.getUsernameShort().hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final UserEntry other = (UserEntry) obj;
String un1 = this.entry.getUsernameShort();
String un2 = other.entry.getUsernameShort();
if (un1 == null || !un1.equals(un2)) {
return false;
}
return true;
}
}
}
class RevisionProperty extends PropertySupport.ReadOnly<TableEntry> {
private final TableEntry te;
public RevisionProperty() {
super(PROPERTY_NAME_VERSION, TableEntry.class, NbBundle.getMessage(RevisionNode.class, "LBL_VersionProperty_Name"), NbBundle.getMessage(RevisionNode.class, "LBL_VersionProperty_Desc"));
te = new RevisionEntry(entry);
}
@Override
public TableEntry getValue() throws IllegalAccessException, InvocationTargetException {
return te;
}
@Override
public String toString() {
return entry.getRevision();
}
private class RevisionEntry extends TableEntry {
private final HistoryEntry entry;
private RevisionEntry(HistoryEntry entry) {
this.entry = entry;
}
@Override
public String getDisplayValue() {
return entry.getRevisionShort();
}
@Override
public String getTooltip() {
return entry.getRevision();
}
@Override
public int compareTo(TableEntry e) {
if(e == null) return 1;
Integer i1;
Integer i2;
try {
i1 = Integer.parseInt(getDisplayValue());
i2 = Integer.parseInt(e.getDisplayValue());
return i1.compareTo(i2);
} catch (NumberFormatException ex) {}
return super.compareTo(e);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
String r1 = this.entry.getRevisionShort();
String r2 = ((RevisionEntry)obj).entry.getRevisionShort();
if (r1 == null || !r1.equals(r2)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 71 * hash + (this.entry.getRevisionShort() != null ? this.entry.getRevisionShort().hashCode() : 0);
return hash;
}
}
}
static class FileNode extends AbstractNode implements Comparable {
private final HistoryEntry entry;
private final VCSFileProxy file;
FileNode(HistoryEntry entry, VCSFileProxy file) {
super(Children.LEAF, createLookup(file, entry));
this.entry = entry;
this.file = file;
}
private static Lookup createLookup(VCSFileProxy proxy, HistoryEntry entry) {
List<Object> lookup = new LinkedList<Object>();
lookup.add(proxy);
File f = proxy.toFile();
if(f != null) {
lookup.add(f);
}
lookup.add(entry);
lookup.addAll(Arrays.asList(entry.getLookupObjects()));
return Lookups.fixed(lookup.toArray(new Object[lookup.size()]));
}
@Override
public Action[] getActions(boolean context) {
return entry.getActions();
}
@Override
public String getName() {
return file.getName();
}
@Override
public int compareTo(Object obj) {
if(!(obj instanceof FileNode)) {
return -1;
}
FileNode node = (FileNode) obj;
return getName().compareTo(node.getName());
}
}
}