/*
* Copyright (c) John C. Landers
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*******************************************************************************/
package net.sf.cvschangelog;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.IAction;
import org.eclipse.swt.widgets.Display;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.ccvs.core.*;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
import org.eclipse.team.internal.ccvs.core.util.Util;
import org.eclipse.team.internal.ccvs.ui.actions.CVSAction;
import org.eclipse.team.internal.ccvs.ui.operations.RemoteLogOperation;
import org.eclipse.team.internal.ccvs.ui.operations.RemoteLogOperation.LogEntryCache;
public class ChangeLog extends CVSAction implements ISchedulingRule {
private RemoteLogOperation rLogOperation = null;
private LogEntryCache lec = new RemoteLogOperation.LogEntryCache();
public ChangeLog() {
super();
}
private boolean isSameBranch(String localRevision, String remoteRevision) {
int localDigits[] = Util.convertToDigits(localRevision);
if (localDigits.length == 0) return false;
int remoteDigits[] = Util.convertToDigits(remoteRevision);
if (remoteDigits.length == 0) return false;
if (remoteDigits.length > localDigits.length) {
return false;
} else {
boolean retval = true;
int i;
for(i = 0; i < (remoteDigits.length - 1); i++) {
if (remoteDigits[i] != localDigits[i])
retval = false;
}
if (remoteDigits[i] > localDigits[i])
retval = false;
return retval;
}
}
public void getLogEntryForResource(IResource resource, Map authors)
throws CVSException, TeamException {
ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource);
if (cvsResource == null) {
return;
}
ICVSRemoteResource remote = CVSWorkspaceRoot.getRemoteResourceFor(cvsResource);
if (remote == null) {
return;
}
ResourceSyncInfo syncInfo = remote.getSyncInfo();
syncInfo.getTag();
ILogEntry entries[] = lec.getLogEntries(remote);
if (entries != null) {
for (int cc = 0; cc < entries.length; cc++) {
if(syncInfo == null || isSameBranch(syncInfo.getRevision(),
entries[cc].getRevision()))
{
Map comments = (Map) authors.get(entries[cc].getAuthor());
if (comments == null) {
comments = new HashMap();
authors.put(entries[cc].getAuthor(), comments);
}
ArrayListPlusProject list = (ArrayListPlusProject) comments.get(entries[cc].getComment());
if (list == null) {
list = new ArrayListPlusProject();
list.setProject(resource.getProject());
comments.put(entries[cc].getComment(), list);
}
list.add(entries[cc]);
}
}
}
}
public List buildChangeLog(Map authors) {
Comparator compare = new Comparator() {
public boolean equals(Object obj) {
return false;
}
public int compare(Object o1, Object o2) {
if (o1 instanceof ILogEntry && o2 instanceof ILogEntry) {
ILogEntry rev1 = (ILogEntry) o1;
ILogEntry rev2 = (ILogEntry) o2;
return rev1.getDate().compareTo(rev2.getDate());
}
return 0;
}
};
Map changeLog = new TreeMap();
for (Iterator iter = authors.entrySet().iterator(); iter.hasNext();) {
Map.Entry entry = (Map.Entry) iter.next();
Map msgs = (Map) entry.getValue();
for (Iterator iterMsgs = msgs.entrySet().iterator(); iterMsgs
.hasNext();) {
Map.Entry msgEntry = (Map.Entry) iterMsgs.next();
ArrayListPlusProject lst = (ArrayListPlusProject) msgEntry.getValue();
Collections.sort(lst, compare);
ILogEntry previousRev = null;
ArrayListPlusProject tempList = new ArrayListPlusProject();
tempList.setProject(lst.getProject());
// seconds times milliseconds.
long duration = 180L * 1000L;
for (int cc = 0; cc < lst.size(); cc++) {
ILogEntry rev = (ILogEntry) lst.get(cc);
if (previousRev != null) {
if ((rev.getDate().getTime() - previousRev.getDate()
.getTime()) < duration) {
} else {
tempList = new ArrayListPlusProject();
tempList.setProject(lst.getProject());
changeLog.put(rev.getDate(), tempList);
}
} else {
changeLog.put(rev.getDate(), tempList);
}
tempList.add(rev);
previousRev = rev;
}
}
}
List values[] = (List[]) changeLog.values().toArray(new List[0]);
List changeLogEntries = new ArrayList();
for (int cc = values.length - 1; cc > -1; cc--) {
ArrayListPlusProject revs = (ArrayListPlusProject) values[cc];
ChangeLogEntry entry = null;
for (Iterator iterRevs = revs.iterator(); iterRevs.hasNext();) {
ILogEntry rev = (ILogEntry) iterRevs.next();
if (entry == null) {
String msg = rev.getComment();
String origMsg = new String(msg);
msg = msg.replace('\n', ' ');
msg = msg.replace('\r', ' ');
entry = new ChangeLogEntry(rev.getAuthor(), msg, origMsg, rev
.getDate(), revs.getProject());
changeLogEntries.add(entry);
}
entry.addFilePaths(rev.getRemoteFile().getRepositoryRelativePath() + " " +
rev.getRevision());
entry.addFiles(rev.getRemoteFile().getName() + " "
+ rev.getRevision());
}
}
return changeLogEntries;
}
/**
* @see IActionDelegate#run(IAction)
*/
public void execute(IAction action) {
Job job = new ChangeLog.ChangeLogJob("ChangeLog");
job.schedule();
}
protected IResource[] getAllSelectedResources() throws CoreException {
if (this.selection.isEmpty())
return new IResource[0];
Iterator it = this.selection.iterator();
List resources = new ArrayList();
while (it.hasNext()) {
Object element = it.next();
Object adapter = getAdapter(element, IResource.class);
if (adapter instanceof IResource) {
IResource resource = (IResource) adapter;
if ((resource.getType() == IResource.PROJECT) ||
(resource.getType() == IResource.FOLDER)) {
resource.accept(new RV(resources));
} else {
resources.add(adapter);
}
}
}
return (IResource[]) resources.toArray(new IResource[resources.size()]);
}
public static class RV implements IResourceVisitor {
List lst = null;
public RV(List lst) {
this.lst = lst;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.resources.IResourceVisitor#visit(org.eclipse.core.resources.IResource)
*/
public boolean visit(IResource resource) throws CoreException {
if (resource.getType() == IResource.PROJECT) {
return true;
} else if (resource.getType() == IResource.FOLDER) {
return true;
} else if (resource.getType() == IResource.FILE) {
this.lst.add(resource);
return false;
}
return false;
}
}
protected boolean isEnabled() throws TeamException {
if (this.selection.isEmpty()) {
return false;
}
Object element = this.selection.getFirstElement();
IResource resource = (IResource) getAdapter(element, IResource.class);
if (resource == null) {
return false;
}
// only enable for resources in a project shared with CVS
if (RepositoryProvider.getProvider(resource.getProject(),
CVSProviderPlugin.getTypeId()) == null) {
return false;
}
return true;
}
public class ArrayListPlusProject extends ArrayList {
private IProject project;
public void setProject(IProject project) {
this.project = project;
}
public IProject getProject() {
return(project);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule)
*/
public boolean contains(ISchedulingRule rule) {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#isConflicting(org.eclipse.core.runtime.jobs.ISchedulingRule)
*/
public boolean isConflicting(ISchedulingRule rule) {
if (rule instanceof ChangeLog) {
return true;
}
return false;
}
public class ChangeLogJob extends Job {
ChangeLogView view = null;
/**
* @param name
*/
public ChangeLogJob(String name) {
super(name);
view = (ChangeLogView) showView("cvschangelog.ChangeLogView");
view.setChangeLogJob(this);
}
private Status displayErrorMessage(Exception ex) {
StringWriter sWriter = new StringWriter();
PrintWriter pWriter = new PrintWriter(sWriter);
ex.printStackTrace(pWriter);
return new Status(IStatus.ERROR, "CVSChangeLog", IStatus.OK,
sWriter.toString(), ex);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.internal.jobs.InternalJob#run(org.eclipse.core.runtime.IProgressMonitor)
*/
protected IStatus run(IProgressMonitor monitor) {
try {
IResource[] resources = ChangeLog.this.getAllSelectedResources();
List remoteResources = new ArrayList();
for(int i=0; i < resources.length; i++) {
ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resources[i]);
ICVSRemoteResource remote = CVSWorkspaceRoot.getRemoteResourceFor(cvsResource);
if (remote != null) {
remoteResources.add(remote);
}
}
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
Map authors = new HashMap();
ICVSRemoteResource[] remoteArray = ((ICVSRemoteResource[])
remoteResources.toArray(new ICVSRemoteResource[remoteResources.size()]));
rLogOperation = new RemoteLogOperation(view, remoteArray,null,null,lec);
rLogOperation.execute(monitor);
for (int cc = 0; cc < resources.length; cc++) {
ChangeLog.this.getLogEntryForResource(resources[cc],
authors);
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
}
final List changeLogEntries = ChangeLog.this
.buildChangeLog(authors);
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
Display display = view.getViewer().getControl().getDisplay();
if (!display.isDisposed()) {
display.asyncExec(new Runnable() {
public void run() {
view.showChangeLog(changeLogEntries);
}
});
}
} catch (CVSException ex) {
return(displayErrorMessage(ex));
} catch (TeamException ex) {
return(displayErrorMessage(ex));
} catch (CoreException ex) {
return(displayErrorMessage(ex));
} catch (OperationCanceledException ex) {
return new Status(IStatus.CANCEL, "CVSChangeLog", IStatus.OK,
"Cancelling CVS ChangeLog operation.", null);
} catch (Exception ex) {
return(displayErrorMessage(ex));
}
return new Status(IStatus.OK, "CVSChangeLog", IStatus.OK,
"Finished", null);
}
}
}