/******************************************************************************* * Copyright (c) 2008, 2011 Institute for Software, HSR Hochschule fuer Technik * Rapperswil, University of applied sciences 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: * Institute for Software - initial API and implementation * Marc-Andre Laperle *******************************************************************************/ package org.eclipse.cdt.internal.ui.refactoring.implementmethod; import java.util.HashMap; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.CompositeChange; import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.text.edits.InsertEdit; import org.eclipse.text.edits.MultiTextEdit; import org.eclipse.text.edits.TextEdit; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.refactoring.CTextFileChange; import org.eclipse.cdt.internal.ui.preferences.formatter.TranslationUnitPreview; import org.eclipse.cdt.internal.ui.refactoring.CCompositeChange; import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector; import org.eclipse.cdt.internal.ui.refactoring.dialogs.ValidatingLabeledTextField; /** * InputPage used by the ImplementMethod refactoring if its necessary to enter additional parameter names. * * @author Mirko Stocker * */ public class ParameterNamesInputPage extends UserInputWizardPage { private static final int PREVIEW_UPDATE_DELAY = 500; private MethodToImplementConfig config; private TranslationUnitPreview translationUnitPreview; private Job delayedPreviewUpdater; private ImplementMethodRefactoringWizard wizard; public ParameterNamesInputPage(MethodToImplementConfig config, ImplementMethodRefactoringWizard wizard) { super(Messages.ParameterNamesInputPage_Title); this.config = config; this.wizard = wizard; } public void createControl(Composite parent) { Composite superComposite = new Composite(parent, SWT.NONE); superComposite.setLayout(new GridLayout()); setTitle(Messages.ImplementMethodInputPage_PageTitle); setMessage(Messages.ParameterNamesInputPage_CompleteMissingMails); ValidatingLabeledTextField validatingLabeledTextField = new ValidatingLabeledTextField(superComposite); validatingLabeledTextField.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); for (final ParameterInfo actParameterInfo : config.getParaHandler().getParameterInfos()) { String type = actParameterInfo.getTypeName(); String content = actParameterInfo.getParameterName(); boolean readOnly = !actParameterInfo.hasNewName(); validatingLabeledTextField.addElement(type, content, readOnly, new ValidatingLabeledTextField.Validator(){ @Override public void hasErrors() { setPageComplete(false); } @Override public void hasNoErrors() { setPageComplete(true); } @Override public boolean isValidInput(String newName) { actParameterInfo.setParameterName(newName); updatePreview(); return true; }}); } createPreview(superComposite); setControl(superComposite); } private InsertEdit getInsertEdit(CompositeChange compositeChange) { for (Change actChange : compositeChange.getChildren()) { if (actChange instanceof CompositeChange) { return getInsertEdit((CompositeChange) actChange); } else if (actChange instanceof CTextFileChange) { CTextFileChange textFileChange = (CTextFileChange) actChange; TextEdit edit = textFileChange.getEdit(); if (edit instanceof MultiTextEdit) { MultiTextEdit multiEdit = (MultiTextEdit) edit; if (multiEdit.getChildrenSize() == 0) { continue; } TextEdit textEdit = multiEdit.getChildren()[0]; if (textEdit instanceof InsertEdit) { return (InsertEdit) textEdit; } } } } return null; } public String createFunctionDefinitionSignature(IProgressMonitor monitor) { try { ModificationCollector collector = new ModificationCollector(); ImplementMethodRefactoring implementMethodRefactoring = (ImplementMethodRefactoring)wizard.getRefactoring(); CCompositeChange finalChange = null; // We can have multiple preview jobs. We don't // want multiple jobs concurrently using the same ASTs synchronized (implementMethodRefactoring) { implementMethodRefactoring.createDefinition(collector, config, monitor); finalChange = collector.createFinalChange(); } InsertEdit insertEdit = getInsertEdit(finalChange); if (insertEdit == null) { return Messages.ImplementMethodRefactoringPage_PreviewGenerationNotPossible; } return insertEdit.getText().trim(); } catch (OperationCanceledException e) { return Messages.ImplementMethodRefactoringPage_PreviewCanceled; } catch (CoreException e) { return Messages.ImplementMethodRefactoringPage_PreviewGenerationNotPossible; } } private void createPreview(Composite superComposite) { translationUnitPreview = new TranslationUnitPreview(new HashMap<String, String>(), superComposite); translationUnitPreview.getControl().setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); delayedPreviewUpdater = new Job(Messages.ImplementMethodRefactoringPage_GeneratingPreview) { @Override protected IStatus run(IProgressMonitor monitor) { setPreviewText(Messages.ImplementMethodRefactoringPage_GeneratingPreview); String functionDefinitionSignature = createFunctionDefinitionSignature(monitor); if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } setPreviewText(functionDefinitionSignature); return Status.OK_STATUS; } private void setPreviewText(final String text) { if (getShell() != null && getShell().getDisplay() != null) { getShell().getDisplay().asyncExec(new Runnable() { public void run() { if (translationUnitPreview.getControl() != null && !translationUnitPreview.getControl().isDisposed()) { translationUnitPreview.setPreviewText(text); } }}); } } }; delayedPreviewUpdater.schedule(PREVIEW_UPDATE_DELAY); } @Override public boolean canFlipToNextPage() { return isPageComplete(); } @Override public IWizardPage getNextPage() { MethodToImplementConfig nextConfig = ((ImplementMethodRefactoring)wizard.getRefactoring()).getRefactoringData().getNextConfigNeedingParameterNames(config); if (nextConfig != null) { return wizard.getPageForConfig(nextConfig); } else { wizard.cancelAndJoinPreviewJobs(); return computeSuccessorPage(); } } protected boolean cancelPreviewJob() { // We cannot rely on getState being accurate in all cases so we only use this // as a hint to change the preview text if (delayedPreviewUpdater.getState() != Job.NONE) { translationUnitPreview.setPreviewText(Messages.ImplementMethodRefactoringPage_PreviewCanceled); } return !delayedPreviewUpdater.cancel(); } protected void joinPreviewJob() { try { delayedPreviewUpdater.join(); } catch (InterruptedException e1) { CUIPlugin.log(e1); } } private void updatePreview() { if (translationUnitPreview == null) { return; } delayedPreviewUpdater.schedule(PREVIEW_UPDATE_DELAY); } @Override public boolean isPageComplete() { if (!config.isChecked()) { return true; } return super.isPageComplete(); } }