/*******************************************************************************
* Copyright (c) 2007-2011 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.jsf.ui.handlers;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.ISources;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.ui.StructuredTextEditor;
import org.eclipse.wst.xml.core.internal.document.NodeImpl;
import org.eclipse.wst.xml.core.internal.document.TextImpl;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.jboss.tools.common.model.XModelObjectConstants;
import org.jboss.tools.jsf.JSFModelPlugin;
import org.jboss.tools.jsf.jsf2.model.CompositeComponentConstants;
import org.jboss.tools.jsf.jsf2.util.JSF2ResourceUtil;
import org.jboss.tools.jsf.project.JSF2Util;
import org.jboss.tools.jst.web.ui.internal.editor.editor.IVisualContext;
import org.jboss.tools.jst.web.ui.internal.editor.jspeditor.JSPMultiPageEditor;
import org.jboss.tools.jst.web.ui.internal.editor.jspeditor.JSPTextEditor;
import org.jboss.tools.jst.web.ui.internal.editor.jspeditor.SourceEditorPageContext;
import org.jboss.tools.jst.web.ui.internal.editor.jspeditor.dnd.JSPPaletteInsertHelper;
import org.jboss.tools.jst.web.ui.internal.editor.jspeditor.dnd.PaletteTaglibInserter;
import org.jboss.tools.jst.web.tld.TaglibData;
import org.jboss.tools.jst.web.tld.URIConstants;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
public class CreateJSF2CompositeCommandHandler extends AbstractHandler {
private static final Pattern USED_TAGLIBS_PATTERN = Pattern.compile("<([a-zA-Z]+\\d*)+:"); //$NON-NLS-1$
private final String IMPLEMENTATION = "composite:implementation"; //$NON-NLS-1$
private NameInputValidator nameInputValidator;
private JSPMultiPageEditor editor;
@Override
public void setEnabled(Object evaluationContext) {
boolean enabled=false;
if (evaluationContext instanceof IEvaluationContext) {
IEvaluationContext context = (IEvaluationContext) evaluationContext;
Object activeEditor = context.getVariable(ISources.ACTIVE_EDITOR_NAME);
if (activeEditor instanceof ITextEditor) {
IEditorInput in = ((ITextEditor) activeEditor).getEditorInput();
if (in instanceof FileEditorInput) {
try {
enabled = JSF2Util.isJSF2(((FileEditorInput) in).getFile().getProject());
} catch (CoreException e) {
e.printStackTrace();
}
}
}
}
if (isEnabled() != enabled) {
setBaseEnabled(enabled);
}
}
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IEditorPart ep = HandlerUtil.getActiveEditorChecked(event);
if (ep instanceof JSPMultiPageEditor) {
editor = (JSPMultiPageEditor) ep;
/*
* Get the selected text
*/
ISelection selection = editor.getSelectionProvider().getSelection();
if ((selection instanceof TextSelection)
&& (selection instanceof IStructuredSelection)) {
TextSelection textSelection = (TextSelection) selection;
IStructuredSelection ss = (IStructuredSelection) selection;
final IProject project = editor.getProject();
/*
* Correct marked text if some tags were partially selected.
*/
int offset = 0;
int length = 0;
/*
* When there is only text node - use only selected text
*/
if ((ss.size() == 1) && (ss.getFirstElement() instanceof TextImpl)) {
offset = textSelection.getOffset();
length = textSelection.getLength();
} else {
/*
* Otherwise selection will be expanded
* to the whole selected element with its children
*/
Iterator it = ss.iterator();
boolean first = true;
while (it.hasNext()) {
Object ob = (Object) it.next();
if (ob instanceof NodeImpl) {
NodeImpl n = ((NodeImpl) ob);
if (first) {
offset = n.getStartOffset();
first = false;
}
length += n.getEndOffset() - n.getStartOffset();
}
}
}
/*
* Get composite's name and namespace from the popup dialog
*/
if (nameInputValidator == null) {
nameInputValidator = new NameInputValidator(project);
} else {
nameInputValidator.setProject(project);
}
InputDialog dlg = new InputDialog(Display.getCurrent().getActiveShell(),
"Creating composite component", //$NON-NLS-1$
"Enter component's namespace and name:", "namespace:name", //$NON-NLS-1$ //$NON-NLS-2$
nameInputValidator);
if (dlg.open() == Window.OK) {
/*
* Create all required files
*/
String componentName = dlg.getValue();
String[] split = componentName.split(":", 2); //$NON-NLS-1$
String path = ""; //$NON-NLS-1$
path = componentName.replaceAll(":", "/") + ".xhtml"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (project != null) {
IStructuredModel model = null;
try {
IFile createdFile = JSF2ResourceUtil
.createCompositeComponentFile(project, new Path(path));
/*
* Add selected text to the template
*/
IModelManager manager = StructuredModelManager.getModelManager();
if (manager != null) {
model = manager.getModelForEdit(createdFile);
if (model instanceof IDOMModel) {
IDOMModel domModel = (IDOMModel) model;
IDOMDocument document = domModel.getDocument();
NodeList list = document.getElementsByTagName(IMPLEMENTATION);
if (list.getLength() == 1) {
IDocument doc = editor.getDocumentProvider().getDocument(editor.getEditorInput());
String replacedText = doc.get(offset, length);
String content = document.getStructuredDocument().getText();
int index = content.indexOf("<"+IMPLEMENTATION+">") + ("<"+IMPLEMENTATION+">").length(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
content = content.subSequence(0, index) + "\n" + replacedText + content.subSequence(index, content.length()); //$NON-NLS-1$
domModel.reload(new ByteArrayInputStream(content.getBytes()));
model.save();
/*
* Register JSF 2 composite on the current page
*/
String replacement = "<" + componentName + "> </" + componentName + ">"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
doc.replace(offset, length, replacement);
/*
* Register the required taglib
*/
StructuredTextEditor ed = ((JSPMultiPageEditor) editor).getSourceEditor();
if (ed instanceof JSPTextEditor) {
String libraryUri = CompositeComponentConstants.COMPOSITE_XMLNS + "/" + split[0]; //$NON-NLS-1$
PaletteTaglibInserter PaletteTaglibInserter = new PaletteTaglibInserter();
Properties properties = new Properties();
properties.put("selectionProvider", editor.getSelectionProvider()); //$NON-NLS-1$
properties.setProperty(URIConstants.LIBRARY_URI, libraryUri);
properties.setProperty(URIConstants.LIBRARY_VERSION, ""); //$NON-NLS-1$
properties.setProperty(URIConstants.DEFAULT_PREFIX, split[0]);
properties.setProperty(JSPPaletteInsertHelper.PROPOPERTY_ADD_TAGLIB, "true"); //$NON-NLS-1$
properties.setProperty(XModelObjectConstants.REFORMAT, "yes"); //$NON-NLS-1$
properties.setProperty(XModelObjectConstants.START_TEXT,
"<%@ taglib uri=\""+libraryUri+"\" prefix=\"" +split[0]+ "\" %>\\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
PaletteTaglibInserter.inserTaglib(ed.getTextViewer().getDocument(), properties);
}
/*
* Add required taglibs to the composite file
*/
IVisualContext context = editor.getJspEditor().getPageContext();
List<TaglibData> tl = null;
if (context instanceof SourceEditorPageContext) {
SourceEditorPageContext sourcePageContext = (SourceEditorPageContext) context;
/*
* Get taglibs from the source file
*/
tl = sourcePageContext.getTagLibs();
Map<String, String> sourceTaglibs = new HashMap<String, String>();
Map<String, String> requiredTaglibs = new HashMap<String, String>();
Set<String> compositeTaglibs = new HashSet<String>();
for (TaglibData taglibData : tl) {
sourceTaglibs.put(taglibData.getPrefix(), taglibData.getUri());
}
/*
* Parse selected fragment to find used taglibs
*/
Matcher m = USED_TAGLIBS_PATTERN.matcher(replacedText);
while (m.find()) {
if (sourceTaglibs.keySet().contains(m.group(1))
&& !requiredTaglibs.keySet().contains(m.group(1))) {
requiredTaglibs.put(m.group(1), sourceTaglibs.get(m.group(1)));
}
}
/*
* Get the <html> tag of the created file
*/
list = document.getElementsByTagName("html"); //$NON-NLS-1$
if (list.getLength() == 1) {
Element html = ((Element)list.item(0));
NamedNodeMap map = html.getAttributes();
for (int i = 0; i < map.getLength(); i++) {
compositeTaglibs.add(map.item(i).getNodeName());
}
for (String key : requiredTaglibs.keySet()) {
String xmlns = "xmlns:" + key; //$NON-NLS-1$
if (!compositeTaglibs.contains(xmlns)) {
html.setAttribute(xmlns, requiredTaglibs.get(key));
}
}
}
}
/*
* Open created file
*/
if (null == createdFile) {
JSFModelPlugin.getPluginLog().logError(
"Composite file:'"+path.toString()+"' cannot be created!"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
FileEditorInput input = new FileEditorInput(createdFile);
JSPMultiPageEditor part = (JSPMultiPageEditor) PlatformUI
.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.openEditor(input, "org.jboss.tools.jst.jsp.jspeditor.JSPTextEditor", true); //$NON-NLS-1$
part.setFocus();
}
}
}
}
} catch (CoreException e) {
JSFModelPlugin.getPluginLog().logError(e);
} catch (IOException e) {
JSFModelPlugin.getPluginLog().logError(e);
} catch (BadLocationException e) {
JSFModelPlugin.getPluginLog().logError(e);
} finally {
if (model != null) {
model.releaseFromEdit();
}
}
}
}
}
}
return null;
}
}