package it.tref.eclipse.wicket.plugin.editors;
import it.tref.eclipse.wicket.plugin.HTMLWicketParser;
import it.tref.eclipse.wicket.plugin.JavaWicketParser;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.propertiesfileeditor.PropertiesFileEditor;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.FindReplaceDocumentAdapter;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.wst.sse.ui.StructuredTextEditor;
@SuppressWarnings("restriction")
/**
* Editor class for multi-page wicket editor
*
* It is composed of 3 editor, java, html and properties.
*
* Next release will implement stats view.
*/
public class WicketFunEditor extends MultiPageEditorPart implements IResourceChangeListener
{
/**
* The java editor is a {@link CompilationUnitEditor}, is internal but it's a bug,
* future release will change the package
*/
private JavaEditor javaEditor;
private IFile javafile;
/**
* The html editor and the CSS editor
*/
private StructuredTextEditor htmlEditor, cssEditor;
/**
* A simple TextEditor for properties
*/
private List<PropertiesFileEditor> propertiesEditors;
private static final String PROPERTIES_REGEX = "(%1$s_\\D{2}_\\D{2}|%1$s)(.properties)";
private int htmlEditorIndex, reportEditorIndex = -1, cssEditorIndex;
private List<Integer> propertiesEditorIndexs;
public WicketFunEditor()
{
super();
// the editor will audit changes in workspace
ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
}
/**
* The <code>MultiPageEditorExample</code> implementation of this method
* checks that the input is an instance of <code>IFileEditorInput</code>.
*/
public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException
{
if (!(editorInput instanceof IFileEditorInput))
throw new PartInitException("Invalid Input: Must be a Wicket Java file");
super.init(site, editorInput);
}
/**
* Create the java editor
*/
private void createJavaEditor()
{
try
{
javaEditor = new CompilationUnitEditor();
javaEditor.init(getEditorSite(), getEditorInput());
WicketFunMarkOccurrenceInstaller wfmoi = new WicketFunMarkOccurrenceInstaller(javaEditor);
wfmoi.installOccurrencesFinder(true);
javafile = ((IFileEditorInput)getEditorInput()).getFile();
setPartName(javafile.getName().substring(0, javafile.getName().length() - javafile.getFileExtension().length() - 1));
int index = addPage(javaEditor, getEditorInput());
setPageText(index, javaEditor.getTitle());
} catch (PartInitException e) {
ErrorDialog.openError(getSite().getShell(), "Error creating Java editor", null, e.getStatus());
}
}
/**
* Create the html editor
*/
private void createHtmlEditor()
{
IPath filepath = getFilePath("html");
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
if(root.exists(filepath))
{
try
{
FileEditorInput htmlEditorInput = new FileEditorInput(root.getFile(filepath));
htmlEditor = new StructuredTextEditor();
htmlEditorIndex = addPage(htmlEditor, htmlEditorInput);
setPageText(htmlEditorIndex, htmlEditor.getTitle());
} catch (PartInitException e) {
ErrorDialog.openError(getSite().getShell(), "Error creating Html editor", null, e.getStatus());
}
}
}
/**
* Create the html editor
*/
private void createCssEditor()
{
IPath filepath = getFilePath("css");
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
if(root.exists(filepath))
{
try
{
FileEditorInput cssEditorInput = new FileEditorInput(root.getFile(filepath));
cssEditor = new StructuredTextEditor();
cssEditorIndex = addPage(cssEditor, cssEditorInput);
setPageText(cssEditorIndex, cssEditor.getTitle());
} catch (PartInitException e) {
ErrorDialog.openError(getSite().getShell(), "Error creating CSS editor", null, e.getStatus());
}
}
}
/**
* Create the properties editor
*/
private void createPropertiesEditors()
{
String propertiesRegEx = String.format(PROPERTIES_REGEX, getFileNameWithoutExtension(javafile));
propertiesEditors = new ArrayList<PropertiesFileEditor>();
propertiesEditorIndexs = new ArrayList<Integer>();
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IFolder folder = root.getFolder(javafile.getFullPath().removeLastSegments(1));
IResource[] members;
try {
members = folder.members();
} catch (CoreException e1) {
System.err.print("Folder members error");
return;
}
for(IResource res : members)
{
if(res.getName().matches(propertiesRegEx))
{
PropertiesFileEditor propertiesEditor = new PropertiesFileEditor();
int propertiesEditorIndex;
try {
propertiesEditorIndex = addPage(propertiesEditor, new FileEditorInput(((IFile)res)));
} catch (PartInitException e) {
ErrorDialog.openError(getSite().getShell(), "Error creating Properties editor", null, e.getStatus());
continue;
}
propertiesEditors.add(propertiesEditor);
propertiesEditorIndexs.add(propertiesEditorIndex);
setPageText(propertiesEditorIndex, propertiesEditor.getTitle());
}
}
}
/**
* Create the stats editor
*/
private void createReportEditor()
{
Composite composite = new Composite(getContainer(), SWT.NONE);
composite.setBackground(getSite().getShell().getDisplay().getSystemColor(SWT.COLOR_WHITE));
GridLayout layout = new GridLayout();
composite.setLayout(layout);
layout.numColumns = 1;
layout.marginTop = 5;
Label title = new Label(composite, SWT.LEFT);
title.setText("Wicket id stats");
title.setLayoutData(new GridData(GridData.BEGINNING));
final Table myTable = new Table(composite, SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION);
myTable.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
myTable.setHeaderVisible(true);
TableColumn col1 = new TableColumn(myTable, SWT.NONE);
col1.setText("Wicket ids");
TableColumn col2 = new TableColumn(myTable, SWT.CENTER);
col2.setText("Found on java code");
StringBuilder java = JavaWicketParser.read(getEditorFile(getJavaEditor().getEditorInput()).getLocation().toOSString());
String javafile = java.toString();
if(htmlEditor != null)
{
for(String id : HTMLWicketParser.parseWicketIds(getEditorFile(getHtmlEditor().getEditorInput()).getLocation().toOSString()))
{
TableItem tableItem1 = new TableItem(myTable, SWT.NULL);
tableItem1.setText(new String[] {id, javafile.contains("\"" + id + "\"") ? "yes" : "no"});
}
}
col1.pack();
col2.pack();
reportEditorIndex = addPage(composite);
setPageText(reportEditorIndex, "stats");
}
public IEditorPart getActiveEditor()
{
return super.getActiveEditor();
}
public PropertiesFileEditor getNextPropertiesEditor()
{
if(getActiveEditor() instanceof PropertiesFileEditor)
{
int i = propertiesEditors.indexOf(getActiveEditor());
if(i+1 < propertiesEditors.size())
return propertiesEditors.get(i+1);
else
return propertiesEditors.get(0);
}
else if(propertiesEditors.size()>0)
{
return propertiesEditors.get(0);
}
else
{
return null;
}
}
private void removeHtmlEditor()
{
if(htmlEditor != null)
{
removePage(htmlEditorIndex);
htmlEditor = null;
}
}
private void removeCssEditor()
{
if(cssEditor != null)
{
removePage(cssEditorIndex);
cssEditor = null;
}
}
private void removePropertiesEditors()
{
for(int pageIndex : propertiesEditorIndexs)
{
removePage(pageIndex);
}
propertiesEditors.clear();
propertiesEditorIndexs.clear();
}
private void removePropertiesEditor(IPath filePath)
{
int removeIndex = -1;
for(int i = 0; i<propertiesEditorIndexs.size(); i++)
{
if(((IFileEditorInput)propertiesEditors.get(i).getEditorInput()).getFile().getFullPath().equals(filePath))
{
removeIndex = i;
break;
}
}
if(removeIndex > -1)
{
removePage(propertiesEditorIndexs.get(removeIndex));
propertiesEditorIndexs.remove(removeIndex);
propertiesEditors.remove(removeIndex);
}
}
private void removeReportEditor()
{
if(reportEditorIndex > -1)
{
removePage(reportEditorIndex);
reportEditorIndex = -1;
}
}
public void setHtmlSelection(String wicketId)
{
final IDocument document = htmlEditor.getDocumentProvider().getDocument(htmlEditor.getEditorInput());
final FindReplaceDocumentAdapter frda = new FindReplaceDocumentAdapter(document);
String[] ids = wicketId.split("/");
try
{
IRegion region = null;
int index = 0;
for(int i=0; i<ids.length; i++)
{
region = frda.find(index, '"' + ids[i] + '"', true, true, false, false);
if(region != null)
{
index = region.getOffset();
}
}
if(region != null)
{
htmlEditor.selectAndReveal(region.getOffset()+1, region.getLength()-2);
}
setActiveEditor(htmlEditor);
htmlEditor.setFocus();
} catch (BadLocationException e) {
htmlEditor.resetHighlightRange();
}
}
private String getFileNameWithoutExtension(IFile file)
{
return file.getName().substring(0, file.getName().length() - file.getFileExtension().length() - 1);
}
/**
* Get the path of the editor file by the give extension (java, html, properties)
* @param extension
* @return
*/
private IPath getFilePath(String extension)
{
IPath filepath = javafile.getFullPath().removeFileExtension();
return filepath.addFileExtension(extension);
}
private IPath getPropertiesNewFilePath(String javaOriginalName, IFile propertiesFile)
{
String propertiesName = getFileNameWithoutExtension(propertiesFile);
IPath filepath;
if(propertiesName.length() > javaOriginalName.length())
{
String locale = propertiesName.substring(javaOriginalName.length());
filepath = new Path(javafile.getFullPath().removeFileExtension().toString() + locale);
}
else
{
filepath = javafile.getFullPath().removeFileExtension();
}
return filepath.addFileExtension("properties");
}
private boolean isPropertiesFile(String name)
{
String regex = String.format(PROPERTIES_REGEX, getFileNameWithoutExtension(javafile));
return name.matches(regex);
}
/**
* Get the resource file wrapped in the given input
* @param editorInput
* @return
*/
private IFile getEditorFile(IEditorInput editorInput)
{
return ((IFileEditorInput)editorInput).getFile();
}
/**
* Get the java editor
* @return
*/
public IEditorPart getJavaEditor() {
return javaEditor;
}
/**
* Get the html editor
* @return
*/
public StructuredTextEditor getHtmlEditor() {
return htmlEditor;
}
/**
* Get the properties editor
* @return
*/
public PropertiesFileEditor[] getPropertiesEditors() {
return propertiesEditors.toArray(new PropertiesFileEditor[0]);
}
/**
* Creates the pages of the multi-page editor.
*/
@Override
protected void createPages()
{
createJavaEditor();
createHtmlEditor();
createCssEditor();
createPropertiesEditors();
if(getHtmlEditor() != null)
createReportEditor();
}
/**
* Update the input of the derived editor, html and properties
*/
private void updateEditors()
{
if(htmlEditor != null)
{
htmlEditor.setInput(new FileEditorInput(ResourcesPlugin.getWorkspace().getRoot().getFile(getFilePath("html"))));
setPageText(htmlEditorIndex, htmlEditor.getTitle());
}
if(cssEditor != null)
{
htmlEditor.setInput(new FileEditorInput(ResourcesPlugin.getWorkspace().getRoot().getFile(getFilePath("css"))));
setPageText(cssEditorIndex, cssEditor.getTitle());
}
removePropertiesEditors();
createPropertiesEditors();
}
/**
* The <code>MultiPageEditorPart</code> implementation of this
* <code>IWorkbenchPart</code> method disposes all nested editors.
* Subclasses may extend.
*/
public void dispose() {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
super.dispose();
}
/**
* Saves the multi-page editor's document.
*/
public void doSave(IProgressMonitor monitor)
{
if(javaEditor != null) javaEditor.doSave(monitor);
if(htmlEditor != null) htmlEditor.doSave(monitor);
if(cssEditor != null) cssEditor.doSave(monitor);
for(TextEditor ed : propertiesEditors)
ed.doSave(monitor);
removeReportEditor();
createReportEditor();
}
/**
* Saves the multi-page editor's document as another file.
* Also updates the text for page 0's tab, and updates this multi-page editor's input
* to correspond to the nested editor's.
*/
public void doSaveAs()
{
javaEditor.doSaveAs();
setPageText(0, javaEditor.getTitle());
setInput(javaEditor.getEditorInput());
String javaOriginalName = javafile.getName().substring(0, javafile.getName().length() - javafile.getFileExtension().length() - 1);
javafile = ((IFileEditorInput)javaEditor.getEditorInput()).getFile();
try {
if(htmlEditor != null)
getEditorFile(htmlEditor.getEditorInput()).copy(getFilePath("html"), true, null);
for(TextEditor ed : propertiesEditors)
getEditorFile(ed.getEditorInput()).copy(getPropertiesNewFilePath(javaOriginalName, getEditorFile(ed.getEditorInput())), true, null);
if(cssEditor != null)
getEditorFile(cssEditor.getEditorInput()).copy(getFilePath("css"), true, null);
} catch (CoreException e) {
ErrorDialog.openError(getSite().getShell(), "Error saving html/properties file", null, e.getStatus());
e.printStackTrace();
}
updateEditors();
}
public void gotoMarker(IMarker marker) {
setActiveEditor(javaEditor);
IDE.gotoMarker(javaEditor, marker);
}
public boolean isSaveAsAllowed() {
return true;
}
/**
* If necessary implements what to do if page change
*/
protected void pageChange(int newPageIndex) {
super.pageChange(newPageIndex);
}
/**
* Audit workspace changes
*/
public void resourceChanged(final IResourceChangeEvent event)
{
if(event.getType() == IResourceChangeEvent.PRE_CLOSE)
{
// close all editors
Display.getDefault().asyncExec(new Runnable()
{
public void run()
{
IWorkbenchPage[] pages = getSite().getWorkbenchWindow().getPages();
for (int i = 0; i<pages.length; i++)
{
if(((FileEditorInput)javaEditor.getEditorInput()).getFile().getProject().equals(event.getResource()))
{
IEditorPart editorPart = pages[i].findEditor(javaEditor.getEditorInput());
pages[i].closeEditor(editorPart, true);
}
}
}
});
}
else if(event.getType() == IResourceChangeEvent.POST_CHANGE)
{
try {
event.getDelta().accept(new IResourceDeltaVisitor()
{
@Override
public boolean visit(final IResourceDelta delta) throws CoreException
{
if(delta.getKind() == IResourceDelta.REMOVED)
{
// if file removed, search and close the editor
if(delta.getResource().getFullPath().equals(getFilePath("java")))
{
Display.getDefault().asyncExec(new Runnable()
{
@Override
public void run() {
IEditorPart editorPart = getSite().getPage().findEditor(getEditorInput());
getSite().getPage().closeEditor(editorPart, true);
}
});
}
else if(delta.getResource().getFullPath().equals(getFilePath("html")))
{
Display.getDefault().asyncExec(new Runnable()
{
@Override
public void run() {
removeHtmlEditor();
}
});
}
else if(delta.getResource().getFullPath().equals(getFilePath("css")))
{
Display.getDefault().asyncExec(new Runnable()
{
@Override
public void run() {
removeCssEditor();
}
});
}
else if(isPropertiesFile(delta.getResource().getName()))
{
Display.getDefault().asyncExec(new Runnable()
{
@Override
public void run() {
removePropertiesEditor(delta.getResource().getFullPath());
}
});
}
}
else if(delta.getKind() == IResourceDelta.ADDED)
{
// on adding file open the new editor if necessary
if(delta.getResource().getFullPath().equals(getFilePath("html")))
{
Display.getDefault().asyncExec(new Runnable()
{
@Override
public void run() {
removeHtmlEditor();
createHtmlEditor();
}
});
}
if(delta.getResource().getFullPath().equals(getFilePath("css")))
{
Display.getDefault().asyncExec(new Runnable()
{
@Override
public void run() {
removeCssEditor();
createCssEditor();
}
});
}
else if(isPropertiesFile(delta.getResource().getName()))
{
Display.getDefault().asyncExec(new Runnable()
{
@Override
public void run() {
removePropertiesEditors();
createPropertiesEditors();
}
});
}
}
return true;
}
});
} catch (CoreException e) {
e.printStackTrace();
}
}
}
}