package org.objectstyle.wolips.componenteditor.actions; import java.io.StringWriter; import java.util.List; import java.util.Map; import org.eclipse.jface.action.IAction; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewerExtension; import org.eclipse.jface.text.Region; import org.eclipse.ui.actions.ActionDelegate; import org.objectstyle.wolips.bindings.api.Binding; import org.objectstyle.wolips.bindings.wod.SimpleWodBinding; import org.objectstyle.wolips.bindings.wod.SimpleWodElement; import org.objectstyle.wolips.componenteditor.ComponenteditorPlugin; import org.objectstyle.wolips.templateeditor.TemplateEditor; import org.objectstyle.wolips.wodclipse.editor.WodEditor; /** * <P> * This is the superclass of the actions that insert new components into the * component. Most of the guts of it are in the superclass here with the * configuration of the actions in the subclasses. * </P> * * @author apl * */ public abstract class InsertHtmlAndWodAction extends AbstractTemplateAction { protected InsertComponentSpecification _componentSpecification; public void setComponentSpecification(InsertComponentSpecification componentSpecification) { _componentSpecification = componentSpecification; } /** * <P> * This method should return the required bindings that the component must * have and so we may as well shove these in at the same time. * </P> */ protected abstract List<Binding> getRequiredBindings(String componentName); /** * Returns the InsertComponentSpecification for this component. This may * open a dialog, so it should only be called from the run method. * * @return the InsertComponentSpecification for this action */ protected abstract InsertComponentSpecification getComponentSpecification(); protected String getIndentText(IDocument doc, int offset) throws BadLocationException { IRegion indentRegion = getIndentRegion(doc, offset); String indentText = doc.get(indentRegion.getOffset(), indentRegion.getLength()); return indentText; } protected IRegion getIndentRegion(IDocument doc, int offset) throws BadLocationException { IRegion lineRegion = doc.getLineInformationOfOffset(offset); int lineStartOffset = lineRegion.getOffset(); int lineLength = lineRegion.getLength(); int lineEndOffset = lineStartOffset + lineLength; int indentOffset = -1; for (int i = lineStartOffset; indentOffset == -1 && i < lineEndOffset; i++) { char ch = doc.getChar(i); if (!Character.isWhitespace(ch)) { indentOffset = i; } } Region indentRegion; if (indentOffset == -1) { indentRegion = new Region(lineStartOffset, 0); } else { indentRegion = new Region(lineStartOffset, indentOffset - lineStartOffset); } return indentRegion; } protected boolean isLineEmpty(IDocument doc, int offset) throws BadLocationException { IRegion lineRegion = doc.getLineInformationOfOffset(offset); int lineStartOffset = lineRegion.getOffset(); int lineLength = lineRegion.getLength(); int lineEndOffset = lineStartOffset + lineLength; boolean isLineEmpty = true; for (int i = lineStartOffset; isLineEmpty && i < lineEndOffset; i++) { char ch = doc.getChar(i); if (!Character.isWhitespace(ch)) { isLineEmpty = false; } } return isLineEmpty; } /** * @see ActionDelegate#run(IAction) */ public void run(IAction action) { insert(); } public void insert() { TemplateEditor te = getTemplateEditor(); WodEditor we = getWodEditor(); InsertComponentSpecification ics = getComponentSpecification(); System.out.println("InsertHtmlAndWodAction.insert: " + te + ", " + we + ", " + ics); if (te != null && we != null && ics != null) { SimpleWodElement wodElement = new SimpleWodElement(ics.getComponentInstanceName(), ics.getComponentName()); List<Binding> bindings = ics.getRequiredBindings(); if (bindings != null) { for (Binding binding : bindings) { wodElement.addBinding(new SimpleWodBinding(null, binding.getName(), "", true)); } } // If the component name is blank, then this is an HTML tag if (ics.getComponentName() == null || ics.getComponentName().length() == 0) { wodElement.setTagName(ics.getTagName()); } SimpleWodElement htmlElement; if (ics.isInline()) { htmlElement = wodElement; } else { htmlElement = new SimpleWodElement("", ""); htmlElement.setTagName(ics.getTagName()); } Map<String, String> htmlAttributes = ics.getHtmlAttributes(); if (htmlAttributes != null) { for (Map.Entry<String, String> htmlAttribute : htmlAttributes.entrySet()) { htmlElement.addBinding(new SimpleWodBinding(null, htmlAttribute.getKey(), htmlAttribute.getValue(), true)); } } IDocument teDoc = te.getHtmlEditDocument(); IDocument weDoc = we.getWodEditDocument(); ITextSelection teDocTSel = (ITextSelection) te.getSourceEditor().getSelectionProvider().getSelection(); // insert the WebObjects component into the template portion. try { ITextViewerExtension teExt = (ITextViewerExtension) te.getSourceEditor().getViewer(); teExt.getRewriteTarget().beginCompoundChange(); try { int selectionStartOffset = teDocTSel.getOffset(); int selectionEndOffset = teDocTSel.getOffset() + teDocTSel.getLength(); if (ics.isComponentContent()) { int selectionStartLine = teDocTSel.getStartLine(); int selectionEndLine = teDocTSel.getEndLine(); StringWriter startTagWriter = new StringWriter(); htmlElement.writeInlineFormat(startTagWriter, "", true, true, false, false, "$", ""); String startTag = startTagWriter.toString(); StringWriter endTagWriter = new StringWriter(); htmlElement.writeInlineFormat(endTagWriter, "", true, false, false, true, "$", ""); String endTag = endTagWriter.toString(); String indentText = getIndentText(teDoc, selectionStartOffset); IRegion startLineRegion = teDoc.getLineInformationOfOffset(selectionStartOffset); IRegion endLineRegion = teDoc.getLineInformationOfOffset(selectionEndOffset); // MS: If the selection starts within the indent // area, then you're actually selecting // from the beginning of the line, not splitting an // existing line of HTML. int selectionLineStartOffset = (selectionStartOffset - startLineRegion.getOffset()); boolean selectionStartedInIndent = (indentText.length() >= selectionLineStartOffset); if (selectionStartLine == selectionEndLine) { if (selectionEndOffset == endLineRegion.getOffset() && selectionEndOffset > 0) { teDoc.replace(selectionEndOffset - 1, 0, endTag); } else { teDoc.replace(selectionEndOffset, 0, endTag); } if (selectionStartedInIndent) { if (indentText.length() == 0) { int offset = Math.max(startLineRegion.getOffset() - 1, 0); teDoc.replace(offset, 0, startTag); } else { teDoc.replace(startLineRegion.getOffset() + indentText.length(), 0, startTag); } } else { teDoc.replace(selectionStartOffset, 0, startTag); } } else { int indentEndOffset; String lastLineIndentText = getIndentText(teDoc, selectionEndOffset); int selectionLineEndOffset = (selectionEndOffset - endLineRegion.getOffset()); if (lastLineIndentText.length() >= selectionLineEndOffset) { String endText = indentText + endTag + "\n"; teDoc.replace(endLineRegion.getOffset(), 0, endText); indentEndOffset = 1; } else { String endText = "\n" + indentText + endTag + "\n" + indentText; teDoc.replace(selectionEndOffset, 0, endText); indentEndOffset = 2; } int indentStartOffset; if (selectionStartedInIndent) { indentStartOffset = 1; String startText = startTag + "\n" + indentText; teDoc.replace(startLineRegion.getOffset() + indentText.length(), 0, startText); } else { indentStartOffset = 2; String startText = "\n" + indentText + startTag + "\n" + indentText; teDoc.replace(selectionStartOffset, 0, startText); } for (int line = selectionStartLine + indentStartOffset; line <= selectionEndLine + indentEndOffset; line++) { int lineOffset = teDoc.getLineOffset(line); teDoc.replace(lineOffset, 0, "\t"); } } } else { StringWriter startTagWriter = new StringWriter(); htmlElement.writeInlineFormat(startTagWriter, null, true, true, false, true, "$", ""); String tag = startTagWriter.toString(); teDoc.replace(selectionStartOffset, 0, tag); } } finally { teExt.getRewriteTarget().endCompoundChange(); } // insert the WebObjects component into the bindings // portion. if (!ics.isInline()) { int firstBindingValueOffset = -1; int offset = weDoc.getLength(); StringWriter wodElementWriter = new StringWriter(); if (offset > 0) { wodElementWriter.write("\n"); } wodElement.writeWodFormat(wodElementWriter, true); wodElementWriter.flush(); String wodElementStr = wodElementWriter.toString(); weDoc.replace(offset, 0, wodElementStr); if (-1 != firstBindingValueOffset) { we.selectAndReveal(offset + firstBindingValueOffset, 0); } else { we.selectAndReveal(offset, wodElementStr.length()); } } } catch (Exception e) { e.printStackTrace(); ComponenteditorPlugin.getDefault().log(e); } } } }