How to get full history of IFile Eclipse Team IFileHistoryProvider when file has been moved within multimodule project? - eclipse

I am trying to access the full repository history of an IFile object programatically from an Eclipse plugin. When the file has never been renamed or moved, the following code snippet works:
public long getFileHistoryTimestamp(IFile file, IProgressMonitor monitor, boolean lastModified) {
IProject project = file.getProject();
RepositoryProvider rProv = RepositoryProvider.getProvider(project);
long createdMillis, lastModifiedMillis;
if (rProv !=null) {
IFileHistoryProvider fhp = rProv.getFileHistoryProvider();
if (fhp != null) {
IFileHistory fHist = fhp.getFileHistoryFor((IResource) file,
IFileHistoryProvider.NONE, null);
IFileRevision[] revs = fHist.getFileRevisions();
Arrays.sort(revs, new Comparator<IFileRevision>(){
public int compare(IFileRevision o1, IFileRevision o2) {
return Long.compare(o1.getTimestamp(), o2.getTimestamp());
}
});
for (IFileRevision rev : revs) {
if (rev.getTimestamp() >= 0) {
createdMillis = rev.getTimestamp();
break;
}
}
if (revs.length > 0) {
lastModifiedMillis = revs[revs.length - 1].getTimestamp();
}
}
return lastModified ? lastModifiedMillis : createdMillis;
}
But, if the file has been moved (e.g. with a multi-module maven project to a new or different module/project), then the values returned above are only for the file in it's current location - i.e. it does not track any rename/moves. The same file in the Eclipse Team History view does track the full version history.
How can I access this full history within the Eclipse Team API?

Related

Hide template visibility depending on VS version?

I have created a VSIX with 2 templates, one is for VS2012 and another is for VS2013.
But if I use the VSIX, both templates are visible for both VS versions in "New Project" window. I want to restrict it. Is there any way?
This is not a great solution, but only one I've found for this problem.
You can register your package to initialize early on in the Visual Studio startup with the following attribute.
[ProvideAutoLoad(UIContextGuids80.NoSolution)]
public sealed YourPackage : Package
Then in your override void Initialize() method you'll want to register a new DTEEvent.
DTEEvents dte_events;
private void RegisterStartupEvents()
{
if(dte == null)
dte = (DTE)GetService(typeof(DTE));
if (dte != null)
{
dte_events = dte.Events.DTEEvents;
dte_events.OnStartupComplete += OnStartupComplete;
}
}
The OnStartupComplete will fire on startup before any templates have been initialized. To remove them from the list for the current VS version, the bundled zip template files that are copied when your VSIX package is installed will have to be deleted. This method could probably be nicer, but you get the idea.
private void OnStartupComplete()
{
dte_events.OnStartupComplete -= OnStartupComplete;
dte_events = null;
var cleanupList = TemplateCleanupByVsVersion[MajorVisualStudioVersion];
foreach (var deleteTemplate in cleanupList)
{
DirectoryInfo localVsDir = new DirectoryInfo(UserLocalDataPath);
// Locate root path of your extension installation directory.
var packageDllFileInfo = localVsDir.GetFiles("MyVsPackage.dll", SearchOption.AllDirectories)[0];
DirectoryInfo extensionDirInfo = packageDllFileInfo.Directory;
if (extensionDirInfo == null)
{
// Failed to locate extension install directory, bail.
return;
}
var files = extensionDirInfo.GetFiles(deleteTemplate + ".zip", SearchOption.AllDirectories);
if (files.Length > 0)
{
File.Delete(files[0].FullName);
}
}
ServiceProvider.GetWritableSettingsStore().SetPackageReady(true);
}
TemplateCleanupByVsVersion is a Dictionart<int,List<string>> that maps Visual Studio Major version with a list of zip file names (without extension) that you don't want showing up in the mapped Visual Studio version. Eg,
public readonly Dictionary<int, List<string>> TemplateCleanupByVsVersion = new Dictionary<int, List<string>>
{
{11,new List<string> { "MyTemplate1.csharp", "MyTemplate2.csharp", "MyTemplate3.csharp" } },
{12,new List<string> { "MyTemplate1.csharp" }},
{14,new List<string>()}
};
MajorVisualStudioVersion comes from parsing dte.Version. eg,
public int MajorVisualStudioVersion => int.Parse(dte.Version.Substring(0, 2));
The result being specific Visual Studio versions can remove any templates from your VSIX that don't work well. Hope that helps.

How to programmatically find a .java file in an Eclipse plugin from full classname?

Inside an Eclipse plugin, I'd like to open a file in editor.
I know the full package and class name
How can I determine the path of the .java file from this?
Take a look at IJavaProject.findType( name ) method. Once you have an IType, you can use getPath or getResource methods to locate the file. This method searches across a project and everything visible from that project.
To search the whole workspace, iterate through all the Java projects in the workspace, calling the findType method on each in turn.
You also need to know the source folder.
IProject prj = ResourcePlugin.getWorkspace().getRoot().getProject("project-name");
IFile theFile = prj.getFile(sourceFolder + packageName.replace('.','/') + className + ".java");
Generally you specify the file for an editor with an IFile. You can also ask an IFile for variants of the file's path.
I know this is a bit old but I had the same need and I had a look at how eclipse does it for stack trace elements (they have a hyperlink on them). The code is in org.eclipse.jdt.internal.debug.ui.console.JavaStackTraceHyperlink (the link is "lazy" so the editor to open is resolved only when you click on it).
What it does is it first searches for the type in the context of the launched application, then for in the whole workspace (method startSourceSearch) :
IType result = OpenTypeAction.findTypeInWorkspace(typeName, false);
And then opens the associated editor (method processSearchResult, source is the type retrieved above) :
protected void processSearchResult(Object source, String typeName, int lineNumber) {
IDebugModelPresentation presentation = JDIDebugUIPlugin.getDefault().getModelPresentation();
IEditorInput editorInput = presentation.getEditorInput(source);
if (editorInput != null) {
String editorId = presentation.getEditorId(editorInput, source);
if (editorId != null) {
try {
IEditorPart editorPart = JDIDebugUIPlugin.getActivePage().openEditor(editorInput, editorId);
if (editorPart instanceof ITextEditor && lineNumber >= 0) {
ITextEditor textEditor = (ITextEditor)editorPart;
IDocumentProvider provider = textEditor.getDocumentProvider();
provider.connect(editorInput);
IDocument document = provider.getDocument(editorInput);
try {
IRegion line = document.getLineInformation(lineNumber);
textEditor.selectAndReveal(line.getOffset(), line.getLength());
} catch (BadLocationException e) {
MessageDialog.openInformation(JDIDebugUIPlugin.getActiveWorkbenchShell(), ConsoleMessages.JavaStackTraceHyperlink_0, NLS.bind("{0}{1}{2}", new String[] {(lineNumber+1)+"", ConsoleMessages.JavaStackTraceHyperlink_1, typeName})); //$NON-NLS-2$ //$NON-NLS-1$
}
provider.disconnect(editorInput);
}
} catch (CoreException e) {
JDIDebugUIPlugin.statusDialog(e.getStatus());
}
}
}
}
Code has copyright from eclipse. Hopfully I'm allowed to reproduced it if this is mentionned.

Does exists Eclipse plugin for log files?

I have check very long logs after each start of Tomcat (from Eclipse).
Does exist a plugin or editor that I can use inside Eclipse? At least it must have colored for errors, debug and info messages.
Thanks.
I would recommend using Log4j:
http://logging.apache.org/log4j/1.2/
http://en.wikipedia.org/wiki/Log4j
It works great with eclipse and has the color scheme built in. It's highly customizable, takes some time to figure out but it's worth it.
The code to do this is rather simple, aside from syntax coloring. Just start a plugin project, add dependancies for org.eclipse.ui.console and do something like this:
public void log() {
BufferedReader br = new BufferedReader(new FileReader("path of log file"));
String line = null;
while (br.nextLine ) {
line = br.readLine();
if (line == null) {
Thread.sleep(1000);
}
else {
MessageConsole console = findConsole("tomcat log");
MessageConsoleStream stream = console.newMessageStream();
stream.println(message);
}
}
}
private MessageConsole findConsole(String name) {
ConsolePlugin plugin = ConsolePlugin.getDefault();
IConsoleManager conMan = plugin.getConsoleManager();
IConsole[] existing = conMan.getConsoles();
for (IConsole element : existing)
if (name.equals(element.getName()))
return (MessageConsole) element;
// no console found, so create a new one
MessageConsole myConsole = new MessageConsole(name, null);
conMan.addConsoles(new IConsole[] { myConsole });
return myConsole;
}

How to change the order of entries in "order and export tab" of eclipse java build path programmatically?

I need to change the order of two jar files in java build path of eclipse.
There is some operation on which the junit3.jar will be set before junit4.jar, but I am not able to find any clue.
You can obtain the raw classpath for the project, then find each Junit entry based on its kind and path, if they're in the "wrong order", you can then modify the raw classpath and set the modified path on to the project.
The snippet below outlines how it can be done, note there's no exception handling in this example:
//get the project by name, you probably want to use another method to
//obtain it
IProject project = ResourcesPlugin.getWorkspace().getRoot()
.getProject("foo");
IJavaProject javaProject = JavaCore.create(project);
IClasspathEntry[] entries = javaProject.getRawClasspath();
// find the JUnit 3 and Junit 4 entry index
int junit3Index = -1;
int junit4Index = -1;
for (int i = 0; i < entries.length; i++) {
if (entries[i].getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
if (entries[i].getPath().equals(
JUnitContainerInitializer.JUNIT3_PATH)) {
junit3Index = i;
} else if (entries[i].getPath().equals(
JUnitContainerInitializer.JUNIT4_PATH)) {
junit4Index = i;
}
}
}
if (junit3Index != -1 && junit4Index != -1
&& junit3Index > junit4Index) {
// swap the two entries
IClasspathEntry temp = entries[junit4Index];
entries[junit4Index] = entries[junit3Index];
entries[junit3Index] = temp;
//update the project with the modified path
javaProject.setRawClasspath(entries, new NullProgressMonitor());
}

In an Eclipse plugin, how can I make a DirectoryFieldEditor start with a particular path?

I am making an Eclipse plugin which on right clicking a project produces a UI.
In this UI I have used DirectoryFieldEditor. This produces directory dialog starting at "MyComputer" as root. What i want is it to show paths starting at the project which i right clicked. how can this be achieved?
I am trying to mimic when you right click a project and say "new package" - the source folder browse give a directory dialog with only those folders which are open projects.... I want a similar directory dialog.
Can somebody help and give me some code snippets or suggestions?
Well, considering the "new package" is actually the class:
org.eclipse.jdt.internal.ui.wizards.NewPackageCreationWizard
which uses NewPackageWizardPage (source code), you will see:
public void init(IStructuredSelection selection) {
IJavaElement jelem = getInitialJavaElement(selection);
initContainerPage(jelem);
String pName = ""; //$NON-NLS-1$
if (jelem != null) {
IPackageFragment pf = (IPackageFragment) jelem
.getAncestor(IJavaElement.PACKAGE_FRAGMENT);
if (pf != null && !pf.isDefaultPackage())
pName = pf.getElementName();
}
setPackageText(pName, true);
updateStatus(new IStatus[] { fContainerStatus, fPackageStatus });
}
With the getInitialJavaElement() being part of superclass NewContainerWizardPage:
/**
* Utility method to inspect a selection to find a Java element.
*
* #param selection the selection to be inspected
* #return a Java element to be used as the initial selection, or <code>null</code>,
* if no Java element exists in the given selection
*/
protected IJavaElement getInitialJavaElement(
IStructuredSelection selection) {
IJavaElement jelem = null;
if (selection != null && !selection.isEmpty()) {
Object selectedElement = selection.getFirstElement();
if (selectedElement instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) selectedElement;
jelem = (IJavaElement) adaptable
.getAdapter(IJavaElement.class);
if (jelem == null) {
IResource resource = (IResource) adaptable
.getAdapter(IResource.class);
if (resource != null
&& resource.getType() != IResource.ROOT) {
while (jelem == null
&& resource.getType() != IResource.PROJECT) {
resource = resource.getParent();
jelem = (IJavaElement) resource
.getAdapter(IJavaElement.class);
}
if (jelem == null) {
jelem = JavaCore.create(resource); // java project
}
}
}
}
}
if (jelem == null) {
IWorkbenchPart part = JavaPlugin.getActivePage()
.getActivePart();
if (part instanceof ContentOutline) {
part = JavaPlugin.getActivePage().getActiveEditor();
}
if (part instanceof IViewPartInputProvider) {
Object elem = ((IViewPartInputProvider) part)
.getViewPartInput();
if (elem instanceof IJavaElement) {
jelem = (IJavaElement) elem;
}
}
}
if (jelem == null
|| jelem.getElementType() == IJavaElement.JAVA_MODEL) {
try {
IJavaProject[] projects = JavaCore.create(
getWorkspaceRoot()).getJavaProjects();
if (projects.length == 1) {
jelem = projects[0];
}
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
}
return jelem;
}
Between those two methods, you should be able to initialize your custom UI with the exact information (i.e., "relative source path") you want.
If you look at the source of DirectoryFieldEditor, you will see it open its directory chooser dialog based on the value if its main Text field defined in StringFieldEditor:doLoad():
String JavaDoc value = getPreferenceStore().getString(getPreferenceName());
textField.setText(value);
That means you need, in your custom UI, to get the preference store and associate the right path with an id. You will use that id for your DirectoryFieldEditor initialization. Y oucan see an example here.
public static final String MY_PATH = "my.init.path";
IPreferenceStore store = myPlugin.getDefault().getPreferenceStore();
store.setValue(MY_PATH, theRightPath);
myDirFieldEditor = new DirectoryFieldEditor(MY_PATH, "&My path", getFieldEditorParent());
As you mention in the comments, all this will only initialize the eclipse-part GUI, not the native windows explorer launched by a DirectoryDialog:
this (the native interface) is based on:
parameters stored in BROWSEINFO Structure
used by the actual GUI SHBrowseForFolder Function, which actually displays a dialog box that enables the user to select a Shell folder.
That GUI initialize a root path based on filter path, so you need to also initialize (on eclipse side) that filter field with a path in order to get it pick up by the Windows-GUI SHBrowseForFolder.
According to DirectoryFieldEditor, that is exactly what getTextControl() (the field you initialized above) is for.
But the problem comes from the fact that field has been initialized with a relative path. Since that path is unknown by the underlying OS, it defaults back to root OS path.
You need to find a way to store the full system path of the project, not the relative path.
That way, that full path will be recognized by the Os and used as initial path.
For instance, from a IJavaElement, you can get its associated resource, and try to get the (full system) path from there.
Actually, from the IPackageFragment you should be able to call getPath(), and check if the IPath returned contains the full system path.