/******************************************************************************* * 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; } }