testdev/ite/src/com.nokia.testfw.codegen.ui/src/com/nokia/testfw/codegen/ui/wizard/AbstractTemplateWizard.java
author Johnson Ma <johnson.ma@nokia.com>
Tue, 30 Mar 2010 14:39:29 +0800
changeset 1 96906a986c3b
permissions -rw-r--r--
contribute ITE to symbian foundation

/*
 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of "Eclipse Public License v1.0"
 * which accompanies this distribution, and is available
 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
 *
 * Initial Contributors:
 * Nokia Corporation - initial contribution.
 *
 * Contributors:
 *
 * Description: 
 *
 */

package com.nokia.testfw.codegen.ui.wizard;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ISourceEntry;
import org.eclipse.cdt.core.settings.model.CSourceEntry;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICSourceEntry;
import org.eclipse.cdt.core.settings.model.WriteAccessException;
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.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IPageChangingListener;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.PageChangingEvent;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.wizards.newresource.BasicNewResourceWizard;

import com.nokia.carbide.cdt.builder.CarbideBuilderPlugin;
import com.nokia.carbide.cdt.builder.project.ICarbideBuildConfiguration;
import com.nokia.carbide.cdt.builder.project.ICarbideProjectInfo;
import com.nokia.carbide.cpp.internal.project.ui.ProjectUIPlugin;
import com.nokia.carbide.cpp.project.core.ProjectCorePlugin;
import com.nokia.carbide.cpp.project.ui.sharedui.NewProjectPage;
import com.nokia.carbide.cpp.sdk.core.ISymbianBuildContext;
import com.nokia.carbide.cpp.sdk.core.ISymbianSDK;
import com.nokia.carbide.cpp.sdk.ui.shared.BuildTargetsPage;
import com.nokia.testfw.codegen.ChangeFileContent;
import com.nokia.testfw.codegen.CodegenEngine;
import com.nokia.testfw.codegen.ui.CodegenUIPlugin;
import com.nokia.testfw.codegen.ui.ResourceChangeListener;
import com.nokia.testfw.codegen.ui.parser.Parser;
import com.nokia.testfw.codegen.ui.parser.ProjectInfoHelper;

public abstract class AbstractTemplateWizard extends BasicNewResourceWizard
		implements IPreviewResult, INewWizard {

	public static final String PROJECT_OBJECT = "project_object";
	public static final String PROJECT_NAME = "project_name";
	public static final String LOCATION = "location";

	protected boolean iShowNewProjectPage = true;
	protected NewProjectPage iNewProjectPage;
	protected BuildTargetsPage iBuildTargetsPage;
	protected List<ISymbianBuildContext> iBuildConfigs;
	protected ISymbianSDK iDefaultSDK;

	protected IProject iTargetProject;
	protected String iProjectName;
	protected String iProjectLocation;
	protected boolean iSelfCreateProject = false;
	protected String iTestFolderLocation = null;

	protected Map<String, Object> iDataMap = new HashMap<String, Object>();
	protected Map<String, ChangeFileContent> iResultMap;
	protected final String iTemplateName;
	protected boolean iTestMMP = true;

	public AbstractTemplateWizard(String template) {
		iTemplateName = template;
		setNeedsProgressMonitor(true);
	}

	@Override
	public void init(IWorkbench workbench, IStructuredSelection currentSelection) {
		super.init(workbench, currentSelection);
		if (iShowNewProjectPage == false) {
			Object sel = selection.getFirstElement();
			if (sel == null)
				return;
			if (sel instanceof ICElement) {
				iTargetProject = ((ICElement) sel).getCProject().getProject();
			} else if (sel instanceof IResource) {
				iTargetProject = ((IResource) sel).getProject();
			}
			iProjectName = iTargetProject.getName();
			iProjectLocation = iTargetProject.getLocation().toOSString();
			iDataMap.put(PROJECT_NAME, iProjectName);
			iDefaultSDK = getDefaultSDK(iTargetProject);
		}
	}

	protected ISymbianSDK getDefaultSDK(IProject project) {
		if (project != null
				&& CarbideBuilderPlugin.getBuildManager().isCarbideProject(
						project) && project.isAccessible()) {
			ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager()
					.getProjectInfo(project);
			if (cpi != null) {
				ICarbideBuildConfiguration config = cpi
						.getDefaultConfiguration();
				if (config != null) {
					return config.getSDK();
				}
			}
		}
		return null;
	}

	public void addPages() {
		if (iShowNewProjectPage) {
			iNewProjectPage = new NewProjectPage("Symbian Test Framework",
					"Create a new Symbian Test Framework project") {
				@Override
				public void createControl(Composite parent) {
					super.createControl(parent);
					((WizardDialog) getContainer())
							.addPageChangingListener(new IPageChangingListener() {
								public void handlePageChanging(
										PageChangingEvent event) {
									if (event.getCurrentPage() instanceof NewProjectPage) {
										iProjectName = iNewProjectPage
												.getProjectName();
										iProjectLocation = iNewProjectPage
												.getLocationPath().append(
														iProjectName)
												.toOSString();
										iDataMap
												.put(PROJECT_NAME, iProjectName);
									}
								}
							});
				}
			};
			addPage(iNewProjectPage);

			iBuildTargetsPage = new BuildTargetsPage() {
				@Override
				public void createControl(Composite parent) {
					super.createControl(parent);
					((WizardDialog) getContainer())
							.addPageChangingListener(new IPageChangingListener() {
								public void handlePageChanging(
										PageChangingEvent event) {
									if (event.getCurrentPage() instanceof BuildTargetsPage) {
										iBuildConfigs = getSelectedBuildConfigs();
										iDefaultSDK = iBuildConfigs.get(0)
												.getSDK();
										initPages();
									}
								}
							});
				}

				protected boolean validatePage() {
					boolean valid = super.validatePage();
					if (valid)
						checkPathWithSDKs(iNewProjectPage.getLocationPath());
					return valid;
				}
			};
			addPage(iBuildTargetsPage);
		}
	}

	public ISymbianSDK getDefaultSDK() {
		if (iDefaultSDK == null) {
			iDefaultSDK = getDefaultSDK(iTargetProject);
		}
		return iDefaultSDK;
	}

	public void createPageControls(Composite pageContainer) {
		super.createPageControls(pageContainer);
		if (initPagesConditon()) {
			initPages();
		}
	}

	protected abstract boolean initPagesConditon();

	public List<ISymbianBuildContext> getBuildConfigs() {
		return iBuildConfigs;
	}

	@Override
	public boolean performFinish() {
		int oldAddFilesOption = ProjectUIPlugin.getAddFilesToProjectOption();
		int oldChangedFilesOption = ProjectUIPlugin
				.getChangedFilesInProjectOption();
		ProjectUIPlugin.setAddFilesToProjectOption(2);
		ProjectUIPlugin.setChangedFilesInProjectOption(2);
		ResourceChangeListener.setEnable(false);

		IRunnableWithProgress op = new IRunnableWithProgress() {
			public void run(IProgressMonitor monitor)
					throws InvocationTargetException {
				monitor.beginTask("Starting...", IProgressMonitor.UNKNOWN);
				try {
					if (iTargetProject == null) {
						iTargetProject = createTargetProject(monitor);
					}
					if (iResultMap == null) {
						iResultMap = generateFiles(monitor);
					}
					if (iResultMap != null && iTargetProject != null) {
						writeResultMapToFiles(iTargetProject, monitor);
					} else {
						MessageDialog.openError(getShell(), "Error",
								"Exception was thrown while generating files");
					}
				} catch (Throwable e) {
					throw new InvocationTargetException(e);
				} finally {
					monitor.done();
				}
			}
		};

		try {
			new ProgressMonitorDialog(getShell()).run(true, false, op);
		} catch (InterruptedException e) {
		} catch (InvocationTargetException e) {
			IStatus lStatus = new Status(IStatus.ERROR,
					AbstractTemplateWizard.class.getName(),
					"Exception was thrown while generating files.", e
							.getTargetException());
			CodegenUIPlugin.getDefault().getLog().log(lStatus);
			MessageDialog.openError(getShell(),
					"Exception was thrown while generating files", e
							.getTargetException().getMessage());
		} finally {
			ProjectUIPlugin.setAddFilesToProjectOption(oldAddFilesOption);
			ProjectUIPlugin
					.setChangedFilesInProjectOption(oldChangedFilesOption);
			ResourceChangeListener.setEnable(true);
		}
		return true;
	}

	@Override
	public boolean performCancel() {
		if (iSelfCreateProject && iTargetProject != null) {
			IRunnableWithProgress op = new IRunnableWithProgress() {
				public void run(IProgressMonitor monitor)
						throws InvocationTargetException {
					try {
						iTargetProject.delete(true, null);
					} catch (Throwable e) {
						throw new InvocationTargetException(e);
					} finally {
						monitor.done();
					}
				}
			};

			try {
				new ProgressMonitorDialog(getShell()).run(true, false, op);
			} catch (InterruptedException e) {
			} catch (InvocationTargetException e) {
				IStatus lStatus = new Status(IStatus.ERROR,
						AbstractTemplateWizard.class.getName(),
						"Exception was thrown while delete temporary project.",
						e.getTargetException());
				CodegenUIPlugin.getDefault().getLog().log(lStatus);
			}

		}
		return super.performCancel();
	}

	public void setSelection(IStructuredSelection currentSelection) {
		selection = currentSelection;
	}

	public IProject createTargetProject(IProgressMonitor monitor)
			throws CoreException {
		if (monitor != null) {
			monitor.subTask("Creating new project");
		}
		if (iTargetProject == null) {
			iTargetProject = ProjectCorePlugin.createProject(iProjectName,
					iProjectLocation);
			iSelfCreateProject = true;
		}
		return iTargetProject;
	}

	protected void setProjectInfo(IProject project, IFile bldInf,
			IProgressMonitor monitor) throws CoreException {
		monitor.subTask("Setting project information");
		if (iShowNewProjectPage) {
			// Convert IProject to ICProject;
			IFolder groupFolder = iTargetProject.getFolder("group");
			if (groupFolder.exists() == false) {
				groupFolder.create(true, true, monitor);
			}
			IFile mainBldInf = groupFolder.getFile("bld.inf");
			if (mainBldInf.exists() == false) {
				String content = "";
				if (bldInf != null) {
					content = abstractBldInf(bldInf);
				}
				mainBldInf.create(new ByteArrayInputStream(content.getBytes()),
						true, monitor);
			}
			ProjectCorePlugin
					.postProjectCreatedActions(iTargetProject, mainBldInf
							.getProjectRelativePath().toString(),
							iBuildConfigs, new ArrayList<String>(), null, null,
							monitor);
		}

		ProjectInfoHelper.setProjectTemplate(project, iTemplateName);
		if (iTestFolderLocation != null) {
			Set<String> testFoldersSet = ProjectInfoHelper.getTestFolders(
					project, iTemplateName);
			if (!testFoldersSet.contains(iTestFolderLocation)) {
				try {
					ProjectInfoHelper.addTestFolders(project, iTemplateName,
							iTestFolderLocation);
				} catch (CoreException e) {
					CodegenUIPlugin.getDefault().getLog().log(e.getStatus());
				}
			}
		}
	}

	private String abstractBldInf(IFile bldInf) throws CoreException {
		boolean inBlock = false;
		StringBuilder sb = new StringBuilder();
		BufferedReader reader = new BufferedReader(new InputStreamReader(bldInf
				.getContents()));
		String line;
		try {
			while ((line = reader.readLine()) != null) {
				if (inBlock == false) {
					sb.append(line).append("\n");
				}
				if (line.indexOf("] Begin - Do not remove") > 0) {
					inBlock = true;
				} else if (line.indexOf("] End - Do not remove") > 0) {
					sb.append(line).append("\n");
					inBlock = false;
				}
			}
		} catch (IOException e) {
			IStatus lStatus = new Status(IStatus.ERROR, Parser.class.getName(),
					IStatus.ERROR, "Exception while reading file", e);
			CodegenUIPlugin.getDefault().getLog().log(lStatus);
		}
		return sb.toString();
	}

	private void writeResultMapToFiles(final IProject project,
			IProgressMonitor monitor) throws CoreException, IOException {
		monitor.subTask("Writing new test codes to file");
		Set<IPath> lSourcePathSet = new HashSet<IPath>();
		IFile bldinf = null;
		ICProject lCProject = CoreModel.getDefault().create(iTargetProject);
		Set<IFile> mmpSet = new HashSet<IFile>();
		for (String path : iResultMap.keySet()) {
			IPath newFilePath = new Path(path);
			IFile newFile = project.getFile(newFilePath);
			ChangeFileContent lChangeContent = iResultMap.get(path);
			ByteArrayInputStream inputStream = new ByteArrayInputStream(
					lChangeContent.getNewContent().getBytes());
			if (newFile.exists()) {
				newFile.setContents(inputStream, true, true, monitor);
			} else {
				createParentFolder(newFile, monitor);
				newFile.create(inputStream, true, monitor);
			}
			String lFileExtension = newFilePath.getFileExtension();
			if ("h".equalsIgnoreCase(lFileExtension)
					|| "cpp".equalsIgnoreCase(lFileExtension)
					|| "hrh".equalsIgnoreCase(lFileExtension)) {
				if (!lCProject.isOnSourceRoot(newFile)) {
					lSourcePathSet.add(newFilePath.uptoSegment(1));
				}
			}
			if (newFilePath.lastSegment().equalsIgnoreCase("bld.inf")) {
				bldinf = newFile;
			} else if (newFilePath.lastSegment().endsWith(".mmp")) {
				mmpSet.add(newFile);
			}
			monitor.worked(1);
		}
		setProjectInfo(project, bldinf, monitor);
		if (bldinf != null) {
			ProjectInfoHelper.addSubBldInfToProject(project, bldinf
					.getProjectRelativePath());
		} else {
			for (IFile mmpFile : mmpSet) {
				ProjectInfoHelper.addMMPFileToProject(project, mmpFile
						.getProjectRelativePath(), iTestMMP);
			}
		}

		if (lSourcePathSet.size() > 0) {
			CoreModel lCoreModel = CoreModel.getDefault();
			if (lCoreModel.isNewStyleProject(iTargetProject)) {
				ArrayList<ICSourceEntry> lSourcePathList = new ArrayList<ICSourceEntry>();
				for (IPath lSourcePath : lSourcePathSet) {
					lSourcePathList.add(new CSourceEntry(lSourcePath, null, 0));
				}
				ICSourceEntry[] lCSourceEntry = lSourcePathList
						.toArray(new ICSourceEntry[0]);
				ICProjectDescription des = CCorePlugin.getDefault()
						.getProjectDescription(iTargetProject, true);
				addEntryToAllCfgs(des, lCSourceEntry, false);
				CCorePlugin.getDefault().setProjectDescription(iTargetProject,
						des, false, monitor);
			} else {
				ArrayList<ISourceEntry> lSourcePathList = new ArrayList<ISourceEntry>();
				for (IPath lSourcePath : lSourcePathSet) {
					lSourcePathList.add(CoreModel.newSourceEntry(lSourcePath));
				}
				ISourceEntry[] lSourceEntry = lSourcePathList
						.toArray(new ISourceEntry[0]);
				CoreModel.getDefault().create(iTargetProject)
						.setRawPathEntries(lSourceEntry, monitor);
			}
		}
		// project.refreshLocal(IResource.DEPTH_ONE, monitor);
	}

	private void addEntryToAllCfgs(ICProjectDescription des,
			ICSourceEntry[] entry, boolean removeProj)
			throws WriteAccessException, CoreException {
		ICConfigurationDescription cfgs[] = des.getConfigurations();
		ICConfigurationDescription aicconfigurationdescription[];
		int j = (aicconfigurationdescription = cfgs).length;
		for (int i = 0; i < j; i++) {
			ICConfigurationDescription cfg = aicconfigurationdescription[i];
			ICSourceEntry entries[] = cfg.getSourceEntries();
			entries = addEntry(entries, entry, removeProj);
			cfg.setSourceEntries(entries);
		}

	}

	private ICSourceEntry[] addEntry(ICSourceEntry entries[],
			ICSourceEntry[] entry, boolean removeProj) {
		Set<ICSourceEntry> set = new HashSet<ICSourceEntry>();
		ICSourceEntry aicsourceentry[];
		int j = (aicsourceentry = entries).length;
		for (int i = 0; i < j; i++) {
			ICSourceEntry se = aicsourceentry[i];
			if (!removeProj || (new Path(se.getValue())).segmentCount() != 1)
				set.add(se);
		}
		for (ICSourceEntry en : entry) {
			set.add(en);
		}
		return (ICSourceEntry[]) set.toArray(new ICSourceEntry[set.size()]);
	}

	private Map<String, ChangeFileContent> generateFiles(
			IProgressMonitor monitor) throws Exception {
		Map<String, ChangeFileContent> lResultMap = new HashMap<String, ChangeFileContent>();
		collectPagesData();

		monitor.subTask("Creating new test codes");

		String output = iTargetProject.getLocation().toOSString();
		if (iTestFolderLocation != null && iTestFolderLocation.length() > 0) {
			output = iTargetProject.getLocation().append(iTestFolderLocation)
					.toOSString();
		}

		CodegenEngine engine = new CodegenEngine(output, iDataMap);
		engine.init();
		engine.setWriteToFile(false);
		Map<String, ChangeFileContent> result = engine.generate(iTemplateName);

		if (iTestFolderLocation != null && iTestFolderLocation.length() > 0) {
			Map<String, ChangeFileContent> new_result = new HashMap<String, ChangeFileContent>();
			IPath testFolder = new Path(iTestFolderLocation);
			for (String path : result.keySet()) {
				new_result.put(testFolder.append(path).toString(), result
						.get(path));
			}
			result = new_result;
		}

		lResultMap.putAll(result);
		monitor.worked(1);
		return lResultMap;
	}

	/**
	 * @return the iTargetProject
	 */
	public IProject getTargetProject() {
		return iTargetProject;
	}

	/**
	 * @param targetProject
	 *            the iTargetProject to set
	 */
	public void setTargetProject(IProject project) {
		iTargetProject = project;
	}

	/**
	 * @return the iShowChooseProjectPage
	 */
	public boolean isShowNewProjectPage() {
		return iShowNewProjectPage;
	}

	/**
	 * @param iShowChooseProjectPage
	 *            the iShowChooseProjectPage to set
	 */
	public void setShowNewProjectPage(boolean showNewProjectPage) {
		this.iShowNewProjectPage = showNewProjectPage;
	}

	protected void initPages() {
		IWizardPage[] pages = getPages();
		for (IWizardPage page : pages) {
			if (page instanceof AbstractTemplateWizardPage) {
				((AbstractTemplateWizardPage) page).initPage(iDataMap);
			}
		}
	}

	protected void collectPagesData() {
		IWizardPage[] pages = getPages();
		for (IWizardPage page : pages) {
			if (page instanceof AbstractTemplateWizardPage) {
				((AbstractTemplateWizardPage) page).collectData();
			}
		}
	}

	public Map<String, Object> getDataMap() {
		return iDataMap;
	}

	private void createParentFolder(IResource resource, IProgressMonitor monitor)
			throws CoreException {
		if (!resource.getParent().exists()) {
			createParentFolder(resource.getParent(), monitor);
			((IFolder) resource.getParent()).create(true, true, monitor);
		}
	}

	public String getTemplateName() {
		return iTemplateName;
	}

	public String getProjectName() {
		return iProjectName;
	}

	public String getProjectLocation() {
		return iProjectLocation;
	}

	public void setProjectLocation(String projectLocation) {
		iProjectLocation = projectLocation;
	}

	public String getTestFolderLocation() {
		return iTestFolderLocation;
	}

	public void setTestFolderLocation(String location) {
		iTestFolderLocation = location;
	}

	/**
	 * @return the testFoldersSet
	 */
	public Set<String> getTestFoldersSet() {
		try {
			if (iTargetProject != null
					&& CarbideBuilderPlugin.getBuildManager().isCarbideProject(
							iTargetProject) && iTargetProject.isAccessible()) {
				return ProjectInfoHelper.getTestFolders(iTargetProject,
						iTemplateName);
			}
		} catch (CoreException e) {
			IStatus lStatus = new Status(
					IStatus.ERROR,
					SUTNewTestWizard.class.getName(),
					"Exception was thrown while accessing project persistent property.",
					e);
			CodegenUIPlugin.getDefault().getLog().log(lStatus);
			MessageDialog.openError(getShell(),
					"Exception was thrown while generating files", e
							.getMessage());
		}
		return null;
	}

	public Map<String, ChangeFileContent> getPreviewResult() {
		IRunnableWithProgress op = new IRunnableWithProgress() {
			public void run(IProgressMonitor monitor)
					throws InvocationTargetException {
				monitor.beginTask("Creating new test codes",
						IProgressMonitor.UNKNOWN);
				try {
					iResultMap = generateFiles(monitor);
				} catch (Throwable e) {
					throw new InvocationTargetException(e);
				} finally {
					monitor.done();
				}
			}
		};

		try {
			new ProgressMonitorDialog(getShell()).run(true, true, op);
		} catch (InterruptedException e) {
			return null;
		} catch (InvocationTargetException e) {
			IStatus lStatus = new Status(IStatus.ERROR,
					AbstractTemplateWizard.class.getName(),
					"Exception was thrown while generating files.", e
							.getTargetException());
			CodegenUIPlugin.getDefault().getLog().log(lStatus);
			MessageDialog.openError(getShell(),
					"Exception was thrown while generating files", e
							.getTargetException().getMessage());
			return null;
		}

		return iResultMap;
	}

	public void setPreviewResult(Map<String, ChangeFileContent> result) {
		iResultMap = result;
	}
}