/******************************************************************************* * Copyright © 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are 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: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.ide.ui.wizards; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; 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.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.edt.compiler.core.IEGLConstants; import org.eclipse.edt.ide.core.model.EGLCore; import org.eclipse.edt.ide.core.model.EGLModelException; import org.eclipse.edt.ide.core.model.IBuffer; import org.eclipse.edt.ide.core.model.IEGLElement; import org.eclipse.edt.ide.core.model.IEGLFile; import org.eclipse.edt.ide.core.model.IEGLPathEntry; import org.eclipse.edt.ide.core.model.IEGLProject; import org.eclipse.edt.ide.core.model.IImportContainer; import org.eclipse.edt.ide.core.model.IImportDeclaration; import org.eclipse.edt.ide.core.model.IMember; import org.eclipse.edt.ide.core.model.IPackageFragment; import org.eclipse.edt.ide.core.model.IPackageFragmentRoot; import org.eclipse.edt.ide.core.model.IPart; import org.eclipse.edt.ide.core.model.IProperty; import org.eclipse.edt.ide.core.model.ISourceRange; import org.eclipse.edt.ide.core.model.ISourceReference; import org.eclipse.edt.ide.ui.internal.EGLLogger; import org.eclipse.edt.ide.ui.internal.wizards.NewWizardMessages; import org.eclipse.ui.actions.WorkspaceModifyOperation; public class EGLFileOperation extends WorkspaceModifyOperation { static protected String newLine = System.getProperty("line.separator"); //$NON-NLS-1$ private EGLFileConfiguration configuration; protected IProject project; public EGLFileOperation(EGLFileConfiguration configuration) { super(); this.configuration = configuration; } public EGLFileOperation(EGLFileConfiguration configuration, ISchedulingRule rule) { super(rule); this.configuration = configuration; } /* (non-Javadoc) * @see org.eclipse.ui.actions.WorkspaceModifyOperation#execute(org.eclipse.core.runtime.IProgressMonitor) */ protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { project = ResourcesPlugin.getWorkspace().getRoot().getProject(configuration.getProjectName()); IEGLProject eproject = EGLCore.create(project); IPath sourcePath = new Path(configuration.getContainerName()); IPackageFragmentRoot root = eproject.findPackageFragmentRoot(sourcePath.makeAbsolute()); String packName = configuration.getFPackage(); IPackageFragment frag = root.getPackageFragment(packName); IContainer container = (IContainer) frag.getResource(); final IFile file = container.getFile(new Path(configuration.getFileName() + ".egl")); //$NON-NLS-1$ if(file.exists()) updateExistingFile(root, frag, file, monitor); else writeFileWithNewContent(root, frag, file, monitor); configuration.setFile(file); updateEGLPathIfNeeded(monitor); } /** * overwrite file with new content wether or not the file already existed * * @param root * @param frag * @param file * @param monitor * @throws CoreException * @throws InterruptedException */ protected void writeFileWithNewContent(IPackageFragmentRoot root, IPackageFragment frag, IFile file, IProgressMonitor monitor) throws CoreException, InterruptedException { try { createFile(root, frag); } catch(CoreException e) { EGLLogger.log(this, e); throw e; } catch(InterruptedException e0) { EGLLogger.log(this, e0); } try { String fileOutputString; String fileHeader = getFileHeader(configuration.getFPackage()); String fileContents = getFileContents(); fileOutputString = fileHeader + fileContents; String encoding = null; if(file.exists()) encoding = file.getCharset(); else { IContainer folder = (IContainer)frag.getResource(); encoding = folder.getDefaultCharset(); } InputStream stream = new ByteArrayInputStream(encoding == null ? fileOutputString.getBytes():fileOutputString.getBytes(encoding)); if (file.exists()) { file.setContents(stream, true, true, monitor); } else { file.create(stream, true, monitor); } stream.close(); } catch (IOException e1) { EGLLogger.log(this, e1); } } /** * child class can override this method to do what it wants, this implmentation just calls the writeFileWithNewContent method * so it will overwrite the existing file with the new content * * @param root * @param frag * @param file * @param monitor * @throws CoreException * @throws InterruptedException */ protected void updateExistingFile(IPackageFragmentRoot root, IPackageFragment frag, IFile file, IProgressMonitor monitor) throws CoreException, InterruptedException { writeFileWithNewContent(root, frag, file, monitor); } protected String getFileHeader(String packName) { String fileContents = ""; //$NON-NLS-1$ if(packName.compareTo("")!=0){ //$NON-NLS-1$ fileContents = fileContents.concat("package " + packName + ";\n\n"); //$NON-NLS-1$ //$NON-NLS-2$ } else{ fileContents = ""; //$NON-NLS-1$ } return fileContents; } protected String getFileContents() throws PartTemplateException { return NewWizardMessages.NewEGLFileWizardPageFilecontents; } private void createFile(IPackageFragmentRoot root, IPackageFragment pack) throws CoreException, InterruptedException { IEGLFile createdWorkingCopy= null; try { if (pack == null) { pack= root.getPackageFragment(""); //$NON-NLS-1$ } if (!pack.exists()) { String packName= pack.getElementName(); pack= root.createPackageFragment(packName, true, null); } String fileOutputString=""; //$NON-NLS-1$ pack.createEGLFile(configuration.getFileName() + ".egl", fileOutputString, true, new NullProgressMonitor()); //$NON-NLS-1$ } finally { if (createdWorkingCopy != null) { createdWorkingCopy.destroy(); } } } //utility function protected String RemoveRemainingTemplateTags(String outputString, String firstHalfOutputString, String secondHalfOutputString) { //Remove remaining template tags int tagStart; int tagEnd; while(outputString.indexOf("${")!=-1){ //$NON-NLS-1$ tagStart = outputString.indexOf("${"); //$NON-NLS-1$ tagEnd = outputString.indexOf("}", tagStart); //$NON-NLS-1$ firstHalfOutputString = outputString.substring(0, tagStart); secondHalfOutputString = outputString.substring(tagStart + 2, outputString.length()); outputString = firstHalfOutputString + secondHalfOutputString; firstHalfOutputString = outputString.substring(0, tagEnd -2); secondHalfOutputString = outputString.substring(tagEnd - 1, outputString.length()); //Check for (and remove) cursor variable if(firstHalfOutputString.endsWith("cursor")) //$NON-NLS-1$ firstHalfOutputString = firstHalfOutputString.substring(0, firstHalfOutputString.length()-6); outputString = firstHalfOutputString + secondHalfOutputString; } return outputString; } /** * utiltiy method * @param strPropName * @param strPropValue * @param addCommaAtBeginning * @param addNewLine * @return */ static protected boolean getPropertyValueString(boolean first, String strPropName, String strPropValue, boolean addNewLine, boolean addQuote, StringBuffer str) { if(strPropValue != null && strPropValue.length()>0) { if(!first) str.append(", "); //$NON-NLS-1$ first = false; if(addNewLine) str.append(newLine); str.append(strPropName); str.append("="); //$NON-NLS-1$ if(addQuote) str.append("\""); //open quote //$NON-NLS-1$ str.append(strPropValue); if(addQuote) str.append("\""); //close quote //$NON-NLS-1$ } return first; } static protected boolean getPropertyQuoteValueString(boolean first, String strPropName, String strPropValue, boolean addNewLine, StringBuffer str) { return getPropertyValueString(first, strPropName, strPropValue, addNewLine, true, str); } static protected boolean getPropertyBooleanValueString(boolean first, String strPropName, boolean booleanvalue, boolean addNewLine, StringBuffer str) { String strValue = Boolean.toString(booleanvalue); return getPropertyValueString(first, strPropName, strValue, addNewLine, false, str); } static protected boolean getPropertyBoolValueString(boolean first, String strPropName, boolean booleanvalue, boolean addNewLine, StringBuffer str) { String strYesNoValue = booleanvalue ? IEGLConstants.KEYWORD_YES : IEGLConstants.KEYWORD_NO; return getPropertyValueString(first, strPropName, strYesNoValue, addNewLine, false, str); } /** * utility method * @param strNameSpace * @param strElemName * @return */ static protected StringBuffer getXMLAnnotationString(String strNameSpace, String strName) { StringBuffer str = new StringBuffer(); if((strNameSpace != null && strNameSpace.length()>0) || (strName != null && strName.length()>0)) { str.append("{@"); //$NON-NLS-1$ str.append(IEGLConstants.PROPERTY_XML); //TODO add XML property constant str.append(" {"); //open brace //$NON-NLS-1$ boolean firstProp = true; firstProp = getPropertyQuoteValueString(firstProp, IEGLConstants.PROPERTY_NAME, strName, false, str); firstProp = getPropertyQuoteValueString(firstProp, IEGLConstants.PROPERTY_NAMESPACE, strNameSpace, false, str); str.append("}}"); //closing brace //$NON-NLS-1$ } return str; } static protected StringBuffer getXMLAnnotationString(IProperty[] xmlProperties){ StringBuffer str = new StringBuffer(); str.append("{"); str.append("@XML"); str.append("{"); str.append(getProperty(xmlProperties)); str.append("}"); str.append("}"); return str; } static private StringBuffer getProperty(IProperty[] properties){ StringBuffer str = new StringBuffer(); for(IProperty prop: properties){ boolean isNestedProp = false; try { if(prop.getValue() instanceof IProperty[]){ isNestedProp = true; } if(isNestedProp){ str.append("@"); } str.append(prop.getElementName()); if(isNestedProp){ str.append("{"); str.append(getProperty((IProperty[])prop.getValue())); str.append("}"); } else{ str.append("="); if(prop.getValueType() == IProperty.VALUE_TYPE_STRING){ str.append("\""); str.append(prop.getValue()); str.append("\""); } else{ str.append(prop.getValue()); } } } catch (EGLModelException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return str; } protected void updateEGLPathIfNeeded(IProgressMonitor monitor) throws EGLModelException { if(configuration.isNeed2UpdateEGLPath()) { String currProjName = configuration.getProjectName(); String initialProjName = configuration.getInitialProjectName(); //will update the current project's EGL Path, add the initial project as a referenced project //if the current project differs from the initial project //AND user wants to update egl path(by default, yes) if(!currProjName.equals(initialProjName) && configuration.isUpdateEGLPath()) { //get the current project's EGL Path IProject currProject = configuration.fWorkspaceRoot.getProject(currProjName); IEGLProject currEGLProj = EGLCore.create(currProject); IProject initialProj = configuration.fWorkspaceRoot.getProject(initialProjName); IEGLPathEntry newEntry = EGLCore.newProjectEntry(initialProj.getFullPath()); //if it's not there, and by adding it won't cause circular link, we'll add to the egl path if(!currEGLProj.isOnEGLPath(initialProj) && !currEGLProj.hasEGLPathCycle(new IEGLPathEntry[]{newEntry})) { IEGLPathEntry[] eglPathEntries = currEGLProj.getRawEGLPath(); int oldLen = eglPathEntries.length; IEGLPathEntry[] newEGLPathEntries = new IEGLPathEntry[oldLen+1]; for(int i=0; i<oldLen; i++) newEGLPathEntries[i] = eglPathEntries[i]; newEGLPathEntries[oldLen] = newEntry; //update the egl path currEGLProj.setRawEGLPath(newEGLPathEntries, monitor); } } } } private void doUpdateEGLBuffer(IEGLFile file, int position, int length, String text) throws EGLModelException, CoreException { IBuffer buffer = file.getBuffer(); buffer.replace(position, length, text); } protected void saveExistingFileWithNewBuffer(IPackageFragment frag, IEGLFile eglfile, IFile file, IProgressMonitor monitor) throws CoreException { IBuffer buffer = eglfile.getBuffer(); String newFileContents = buffer.getContents(); buffer.close(); frag.createEGLFile(file.getName(), newFileContents, true, new NullProgressMonitor()); //$NON-NLS-1$ String encoding=null; if(file.exists()) encoding = file.getCharset(); else //get the folder's default char set { IContainer folder = (IContainer) frag.getResource(); encoding = folder.getDefaultCharset(); } try { InputStream stream = new ByteArrayInputStream(encoding == null ? newFileContents.getBytes() : newFileContents.getBytes(encoding)); if(file.exists()) file.setContents(stream, true, true, monitor); stream.close(); } catch (IOException e) { EGLLogger.log(this, e); } } /** * This method will check for duplicate imports, will not add duplicate imports * @param file * @param lstImportElemName - list of String, each element is the import element name without ; at the end * i.e. for "import a.b.c;" the element is "a.b.c" * @throws EGLModelException * @throws CoreException */ protected void addImports(IEGLFile file, List lstImportElemName) throws EGLModelException, CoreException { StringBuffer importStringBuffer = new StringBuffer(); if (file != null) { IImportDeclaration[] imports = file.getImports(); ISourceRange range = null; IEGLElement[] elements = file.getChildren(); IEGLElement importBlock = null; IEGLElement packageBlock = null; //Make sure not to add dupes Iterator it = lstImportElemName.iterator(); while(it.hasNext()) { String newImportElemName = (String)(it.next()); boolean fndDup = false; for(int i=0; i< imports.length && !fndDup; i++) { String existingElementName = imports[i].getElementName(); if(newImportElemName.equalsIgnoreCase(existingElementName)) fndDup = true; } if(!fndDup) { importStringBuffer.append(IEGLConstants.KEYWORD_IMPORT); importStringBuffer.append(" "); //$NON-NLS-1$ importStringBuffer.append(newImportElemName); importStringBuffer.append(";"); //$NON-NLS-1$ importStringBuffer.append(newLine); } } // Try to find the property block for(int i=0; i<elements.length; i++) { if(elements[i].getElementType() == IEGLFile.PACKAGE_DECLARATION) { packageBlock = elements[i]; continue; } if(elements[i].getElementType() == IEGLFile.IMPORT_CONTAINER) { importBlock = elements[i]; break; } } int rangeOffset = 0; if(importBlock != null) { // The block was found range = ((IImportContainer)importBlock).getSourceRange(); rangeOffset = (range != null) ? range.getOffset() : 0; } else if (packageBlock != null) { // We have no imports // insert after the package range = ((ISourceReference)packageBlock).getSourceRange(); rangeOffset = (range != null) ? range.getOffset() + range.getLength() : 0; } String importString = importStringBuffer.toString(); if(importString.length()>0) doUpdateEGLBuffer(file, rangeOffset, 0, importString); } } /** * The strategy here is to always insert after the property block or teh name (if no property block is found) * @param insertionString * @throws CoreException */ protected void insertMemeberPart(IEGLFile eglfile, IPart sourcePart, String insertionString) throws CoreException { if(sourcePart != null) { StringBuffer insertStringBuf = new StringBuffer(insertionString); try { ISourceRange range = null; IEGLElement[] elements = sourcePart.getChildren(); IEGLElement propBlock = null; // Try to find the property block for(int i=0; i<elements.length; i++) { if(elements[i].getElementType() == IEGLFile.PROPERTY_BLOCK) { propBlock = elements[i]; break; } } int insertposition = 0; if(propBlock != null) { // The block was found range = ((IMember)propBlock).getSourceRange(); String propBlockSource = ((IMember)propBlock).getSource(); // whatever whitespace is between the property block and the first element in the CBF is going to appear // between the property block and our newly inserted field. Make sure we insert at least one tab between the two // if none is found at the end. if(propBlockSource.charAt(propBlockSource.length() - 1) != '\t') { insertStringBuf.insert(0, "\t"); //$NON-NLS-1$ } insertposition = range.getOffset() + range.getLength(); } else { insertposition = getInsertPosition(eglfile, sourcePart, insertStringBuf); } // If we are inserting the first field, put a new line after it. //if(fields.length == 0) { insertStringBuf.append("\n"); //$NON-NLS-1$ } // Insert a trailing tab if we are not inserting the first element in the page handler // (other than the property block). Since we are always inserting at the top, if there // are elements other than the property block in the page handler, they will be below this // one after insertion. Do not insert the trailing tab if we don't have a property block, // since we are using the name range to figure out the insertion and it doesn't eat the trailing // tabs. if(propBlock != null && elements.length > 1) { insertStringBuf.append("\t"); //$NON-NLS-1$ } //if(range != null) if(insertposition > 0) { doUpdateEGLBuffer(eglfile, insertposition, 0, insertStringBuf.toString()); } } catch (EGLModelException e) { } } } /** * Child class should overwrite this method * @param eglfile * @param sourcePart * @param insertStringBuf * @return * @throws EGLModelException */ protected int getInsertPosition(IEGLFile eglfile, IPart sourcePart, StringBuffer insertStringBuf) throws EGLModelException { return 0; } }