From 415d47ac4187d3d76b1680bf1c1962e19d5ffc55 Mon Sep 17 00:00:00 2001 From: Edward Mann Date: Fri, 27 Jun 2008 05:09:05 +0000 Subject: [PATCH] Compatibility fragment commit --- .../.classpath | 7 + .../.project | 28 + .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 12 + .../build.properties | 5 + .../fragment.xml | 5 + .../externaltools/actions/ExternalPHPParser.java | 345 ++ .../compiler/lookup/CompilationUnitScope.java | 728 +++ .../phpdt/internal/compiler/parser/Parser.java | 5118 +++++++++++++++++ .../phpdt/internal/core/JavaModelManager.java | 2482 ++++++++ .../phpdt/internal/corext/phpdoc/PHPDocUtil.java | 93 + .../phpdt/internal/corext/util/Resources.java | 211 + .../phpdt/internal/debug/core/PHPDBGProxy.java | 703 +++ .../ui/launcher/LoadPathEntryLabelProvider.java | 64 + .../debug/ui/launcher/PHPEnvironmentTab.java | 775 +++ .../internal/launching/InterpreterRunner.java | 140 + .../launching/InterpreterRunnerConfiguration.java | 207 + .../phpdt/internal/launching/PHPSourceLocator.java | 219 + .../ui/text/template/DeclarationProposal.java | 283 + .../phpdt/internal/ui/util/PHPFileUtil.java | 201 + .../phpdt/ltk/core/RenameIdentifierDelegate.java | 386 ++ .../ltk/core/RenameLocalVariableDelegate.java | 262 + .../phpeclipse/actions/IncludesScanner.java | 187 + .../actions/OpenDeclarationEditorAction.java | 304 + .../actions/PHPOpenAllIncludesEditorAction.java | 242 + .../phpeclipse/obfuscator/ObfuscatorIgnores.java | 119 + .../WizardObfuscatorResourceExportPage1.java | 505 ++ .../phpeclipse/phpeditor/PHPEditor.java | 6068 ++++++++++++++++++++ .../phpeclipse/phpeditor/PHPTextHover.java | 151 + .../src/net/sourceforge/phpeclipse/ui/WebUI.java | 190 + .../ui/editor/ShowExternalPreviewAction.java | 129 + .../internal/OpenWithBrowserActionDelegate.java | 98 + .../webbrowser/internal/WebBrowserEditor.java | 404 ++ .../phpeclipse/webbrowser/views/BrowserView.java | 155 + .../wizards/NewProjectCreationWizard.java | 119 + .../launching/PHPLaunchConfigurationDelegate.java | 155 + .../php/launching/PHPSourceLookupParticipant.java | 17 + .../phpeclipse/xdebug/php/model/XDebugTarget.java | 638 ++ .../xml/core/internal/model/XMLDocument.java | 160 + 39 files changed, 21922 insertions(+), 0 deletions(-) create mode 100644 net.sourceforge.phpeclipse.32.compatibility/.classpath create mode 100644 net.sourceforge.phpeclipse.32.compatibility/.project create mode 100644 net.sourceforge.phpeclipse.32.compatibility/.settings/org.eclipse.jdt.core.prefs create mode 100644 net.sourceforge.phpeclipse.32.compatibility/META-INF/MANIFEST.MF create mode 100644 net.sourceforge.phpeclipse.32.compatibility/build.properties create mode 100644 net.sourceforge.phpeclipse.32.compatibility/fragment.xml create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/externaltools/actions/ExternalPHPParser.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilationUnitScope.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/core/JavaModelManager.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/corext/phpdoc/PHPDocUtil.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/corext/util/Resources.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/core/PHPDBGProxy.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/LoadPathEntryLabelProvider.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/PHPEnvironmentTab.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunner.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunnerConfiguration.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/PHPSourceLocator.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/ui/text/template/DeclarationProposal.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/ui/util/PHPFileUtil.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/ltk/core/RenameIdentifierDelegate.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/ltk/core/RenameLocalVariableDelegate.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/IncludesScanner.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/OpenDeclarationEditorAction.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/PHPOpenAllIncludesEditorAction.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/obfuscator/ObfuscatorIgnores.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/obfuscator/export/WizardObfuscatorResourceExportPage1.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/phpeditor/PHPTextHover.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/ui/WebUI.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/ui/editor/ShowExternalPreviewAction.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/internal/OpenWithBrowserActionDelegate.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/internal/WebBrowserEditor.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/views/BrowserView.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/wizards/NewProjectCreationWizard.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPLaunchConfigurationDelegate.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPSourceLookupParticipant.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugTarget.java create mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xml/core/internal/model/XMLDocument.java diff --git a/net.sourceforge.phpeclipse.32.compatibility/.classpath b/net.sourceforge.phpeclipse.32.compatibility/.classpath new file mode 100644 index 0000000..ce73933 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/net.sourceforge.phpeclipse.32.compatibility/.project b/net.sourceforge.phpeclipse.32.compatibility/.project new file mode 100644 index 0000000..f3c7947 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/.project @@ -0,0 +1,28 @@ + + + net.sourceforge.phpeclipse.32.compatibility + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/net.sourceforge.phpeclipse.32.compatibility/.settings/org.eclipse.jdt.core.prefs b/net.sourceforge.phpeclipse.32.compatibility/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..8ba6423 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +#Thu Jun 26 21:18:27 CDT 2008 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2 +org.eclipse.jdt.core.compiler.compliance=1.4 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning +org.eclipse.jdt.core.compiler.source=1.3 diff --git a/net.sourceforge.phpeclipse.32.compatibility/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.32.compatibility/META-INF/MANIFEST.MF new file mode 100644 index 0000000..848862d --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Compatability Fragment +Bundle-SymbolicName: net.sourceforge.phpeclipse.32.compatibility +Bundle-Version: 1.0.0 +Fragment-Host: net.sourceforge.phpeclipse;bundle-version="0.0.0" +Bundle-RequiredExecutionEnvironment: J2SE-1.4 +Bundle-ClassPath: compatability.jar, + . +Eclipse-PatchFragment: true +Require-Bundle: net.sourceforge.phpeclipse.launching, + net.sourceforge.phpeclipse.core;bundle-version="0.0.0" diff --git a/net.sourceforge.phpeclipse.32.compatibility/build.properties b/net.sourceforge.phpeclipse.32.compatibility/build.properties new file mode 100644 index 0000000..e3c6d90 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/build.properties @@ -0,0 +1,5 @@ +bin.includes = META-INF/,\ + fragment.xml,\ + compatability.jar +source.compatability.jar = src/ +jars.compile.order = compatability.jar diff --git a/net.sourceforge.phpeclipse.32.compatibility/fragment.xml b/net.sourceforge.phpeclipse.32.compatibility/fragment.xml new file mode 100644 index 0000000..9441a04 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/fragment.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/externaltools/actions/ExternalPHPParser.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/externaltools/actions/ExternalPHPParser.java new file mode 100644 index 0000000..ffb9ca7 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/externaltools/actions/ExternalPHPParser.java @@ -0,0 +1,345 @@ +package net.sourceforge.phpdt.externaltools.actions; + +import java.io.IOException; +import java.io.InputStream; +import java.text.MessageFormat; +import java.util.Hashtable; + +import net.sourceforge.phpdt.externaltools.util.StringUtil; +import net.sourceforge.phpeclipse.externaltools.ExternalToolsPlugin; +import net.sourceforge.phpeclipse.externaltools.PHPConsole; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.ui.texteditor.MarkerUtilities; + +/** + * Calls the external parser and generates problem markers if necessary + */ +public class ExternalPHPParser { + private final static String PROBLEM_ID = "net.sourceforge.phpeclipse.problem"; + + // strings for external parser call + private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$ + + private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$ + + public static final int ERROR = 2; + + public static final int WARNING = 1; + + public static final int INFO = 0; + + public static final int TASK = 3; + + // TODO design error? Analyze why fileToParse must be static ??? + final protected IFile fFileToParse; + + public ExternalPHPParser(IFile file) { + fFileToParse = file; + } + + /** + * Call the php parse command ( php -l -f <filename> ) and create + * markers according to the external parser output. + * + * @param file + * the file that will be parsed + */ + public void phpExternalParse() { + // IFile file = (IFile) resource; + // final IPath path = file.getFullPath(); + final IPreferenceStore store = ExternalToolsPlugin.getDefault() + .getPreferenceStore(); + final String filename = fFileToParse.getLocation().toString(); + + final String[] arguments = { filename }; + final MessageFormat form = new MessageFormat(store + .getString(ExternalToolsPlugin.EXTERNAL_PARSER_PREF)); + final String command = form.format(arguments); + + final String parserResult = getParserOutput(command, + "External parser: "); + + try { + // parse the buffer to find the errors and warnings + createMarkers(parserResult, fFileToParse); + } catch (CoreException e) { + } + } + + /** + * Create markers according to the external parser output. + * + * @param output + * the external parser output + * @param file + * the file that was parsed. + */ + protected void createMarkers(final String output, final IFile file) + throws CoreException { + // delete all markers + file.deleteMarkers(PROBLEM_ID, false, 0); + + int indx = 0; + int brIndx; + boolean flag = true; + while ((brIndx = output.indexOf("
", indx)) != -1) { + // newer php error output (tested with 4.2.3) + scanLine(output, file, indx, brIndx); + indx = brIndx + 6; + flag = false; + } + if (flag) { + while ((brIndx = output.indexOf("
", indx)) != -1) { + // older php error output (tested with 4.2.3) + scanLine(output, file, indx, brIndx); + indx = brIndx + 4; + } + } + } + + private void scanLine(final String output, final IFile file, + final int indx, final int brIndx) throws CoreException { + String current; + // String outLineNumberString; never used + final StringBuffer lineNumberBuffer = new StringBuffer(10); + char ch; + current = output.substring(indx, brIndx); + + if (current.indexOf(PARSE_WARNING_STRING) != -1 + || current.indexOf(PARSE_ERROR_STRING) != -1) { + final int onLine = current.indexOf("on line "); + if (onLine != -1) { + lineNumberBuffer.delete(0, lineNumberBuffer.length()); + for (int i = onLine; i < current.length(); i++) { + ch = current.charAt(i); + if ('0' <= ch && '9' >= ch) { + lineNumberBuffer.append(ch); + } + } + + final int lineNumber = Integer.parseInt(lineNumberBuffer + .toString()); + + final Hashtable attributes = new Hashtable(); + + current = StringUtil.replaceAll(current, "\n", ""); + current = StringUtil.replaceAll(current, "", ""); + current = StringUtil.replaceAll(current, "", ""); + MarkerUtilities.setMessage(attributes, current); + + if (current.indexOf(PARSE_ERROR_STRING) != -1) + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_ERROR)); + else if (current.indexOf(PARSE_WARNING_STRING) != -1) + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_WARNING)); + else + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_INFO)); + MarkerUtilities.setLineNumber(attributes, lineNumber); + MarkerUtilities.createMarker(file, attributes, PROBLEM_ID); + } + } + } + + /** + * This will set a marker. + * + * @param file + * the file that generated the marker + * @param message + * the message + * @param charStart + * the starting character + * @param charEnd + * the end character + * @param errorLevel + * the error level ({@link ExternalPHPParser#ERROR},{@link ExternalPHPParser#INFO},{@link ExternalPHPParser#WARNING}), + * {@link ExternalPHPParser#TASK}) + * @throws CoreException + * an exception throwed by the MarkerUtilities + */ + private void setMarker(final IFile file, final String message, + final int charStart, final int charEnd, final int errorLevel) + throws CoreException { + if (file != null) { + final Hashtable attributes = new Hashtable(); + MarkerUtilities.setMessage(attributes, message); + switch (errorLevel) { + case ERROR: + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_ERROR)); + break; + case WARNING: + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_WARNING)); + break; + case INFO: + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_INFO)); + break; + case TASK: + attributes.put(IMarker.SEVERITY, new Integer(IMarker.TASK)); + break; + } + MarkerUtilities.setCharStart(attributes, charStart); + MarkerUtilities.setCharEnd(attributes, charEnd); + MarkerUtilities.createMarker(file, attributes, PROBLEM_ID); + } + } + + /** + * This will set a marker. + * + * @param file + * the file that generated the marker + * @param message + * the message + * @param line + * the line number + * @param errorLevel + * the error level ({@link ExternalPHPParser#ERROR},{@link ExternalPHPParser#INFO},{@link ExternalPHPParser#WARNING}) + * @throws CoreException + * an exception throwed by the MarkerUtilities + */ + private void setMarker(final IFile file, final String message, + final int line, final int errorLevel, final String location) + throws CoreException { + if (file != null) { + String markerKind = PROBLEM_ID; + final Hashtable attributes = new Hashtable(); + MarkerUtilities.setMessage(attributes, message); + switch (errorLevel) { + case ERROR: + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_ERROR)); + break; + case WARNING: + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_WARNING)); + break; + case INFO: + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_INFO)); + break; + case TASK: + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_INFO)); + markerKind = IMarker.TASK; + break; + } + attributes.put(IMarker.LOCATION, location); + MarkerUtilities.setLineNumber(attributes, line); + MarkerUtilities.createMarker(file, attributes, markerKind); + } + } + + /** + * This will set a marker. + * + * @param message + * the message + * @param charStart + * the starting character + * @param charEnd + * the end character + * @param errorLevel + * the error level ({@link ExternalPHPParser#ERROR},{@link ExternalPHPParser#INFO},{@link ExternalPHPParser#WARNING}) + * @throws CoreException + * an exception throwed by the MarkerUtilities + */ + private void setMarker(final String message, final int charStart, + final int charEnd, final int errorLevel, final String location) + throws CoreException { + if (fFileToParse != null) { + setMarker(fFileToParse, message, charStart, charEnd, errorLevel, + location); + } + } + + /** + * This will set a marker. + * + * @param file + * the file that generated the marker + * @param message + * the message + * @param charStart + * the starting character + * @param charEnd + * the end character + * @param errorLevel + * the error level ({@link ExternalPHPParser#ERROR},{@link ExternalPHPParser#INFO},{@link ExternalPHPParser#WARNING}) + * @param location + * the location of the error + * @throws CoreException + * an exception throwed by the MarkerUtilities + */ + private void setMarker(final IFile file, final String message, + final int charStart, final int charEnd, final int errorLevel, + final String location) throws CoreException { + if (file != null) { + final Hashtable attributes = new Hashtable(); + MarkerUtilities.setMessage(attributes, message); + switch (errorLevel) { + case ERROR: + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_ERROR)); + break; + case WARNING: + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_WARNING)); + break; + case INFO: + attributes.put(IMarker.SEVERITY, new Integer( + IMarker.SEVERITY_INFO)); + break; + case TASK: + attributes.put(IMarker.SEVERITY, new Integer(IMarker.TASK)); + break; + } + attributes.put(IMarker.LOCATION, location); + MarkerUtilities.setCharStart(attributes, charStart); + MarkerUtilities.setCharEnd(attributes, charEnd); + MarkerUtilities.createMarker(file, attributes, PROBLEM_ID); // IMarker.PROBLEM); + } + } + + private String getParserOutput(String command, String consoleMessage) { + try { + PHPConsole console = new PHPConsole(); + try { + console.println(consoleMessage + command); + } catch (Throwable th) { + + } + + Runtime runtime = Runtime.getRuntime(); + + // runs the command + Process p = runtime.exec(command); + + // gets the input stream to have the post-compile-time information + InputStream stream = p.getInputStream(); + + // get the string from Stream + String consoleOutput = PHPConsole.getStringFromStream(stream); + + // prints out the information + if (console != null) { + console.print(consoleOutput); + } + return consoleOutput; + + } catch (IOException e) { + MessageDialog + .openInformation(null, "IOException: ", e.getMessage()); + } + return ""; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilationUnitScope.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilationUnitScope.java new file mode 100644 index 0000000..0e03ef2 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilationUnitScope.java @@ -0,0 +1,728 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.lookup; + +import java.util.ArrayList; + +import net.sourceforge.phpdt.core.compiler.CharOperation; +import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; +import net.sourceforge.phpdt.internal.compiler.util.CompoundNameVector; +import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject; +import net.sourceforge.phpdt.internal.compiler.util.HashtableOfType; +import net.sourceforge.phpdt.internal.compiler.util.ObjectVector; +import net.sourceforge.phpdt.internal.compiler.util.SimpleNameVector; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IPath; + +public class CompilationUnitScope extends Scope { + + public LookupEnvironment environment; + + public CompilationUnitDeclaration referenceContext; + + public char[][] currentPackageName; + + public PackageBinding fPackage; + + public ImportBinding[] imports; + + public SourceTypeBinding[] topLevelTypes; + + private CompoundNameVector qualifiedReferences; + + private SimpleNameVector simpleNameReferences; + + private ObjectVector referencedTypes; + + HashtableOfType constantPoolNameUsage; + + public HashtableOfObject resolvedSingeTypeImports; + + public CompilationUnitScope(CompilationUnitDeclaration unit, + LookupEnvironment environment) { + super(COMPILATION_UNIT_SCOPE, null); + this.environment = environment; + this.referenceContext = unit; + unit.scope = this; + // this.currentPackageName = unit.currentPackage == null ? + // CharOperation.NO_CHAR_CHAR : unit.currentPackage.tokens; + this.currentPackageName = null; + // if (environment.options.produceReferenceInfo) { + // this.qualifiedReferences = new CompoundNameVector(); + // this.simpleNameReferences = new SimpleNameVector(); + // this.referencedTypes = new ObjectVector(); + // } else { + this.qualifiedReferences = null; // used to test if dependencies + // should be recorded + this.simpleNameReferences = null; + this.referencedTypes = null; + // } + } + + void buildFieldsAndMethods() { + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].scope.buildFieldsAndMethods(); + } + + void buildTypeBindings() { + if (referenceContext.compilationResult.compilationUnit != null) { + char[][] expectedPackageName = referenceContext.compilationResult.compilationUnit + .getPackageName(); + if (expectedPackageName != null + && !CharOperation.equals(currentPackageName, + expectedPackageName)) { + + // only report if the unit isn't structurally empty + // if (referenceContext.currentPackage != null + // || referenceContext.types != null + // || referenceContext.imports != null) { + // problemReporter().packageIsNotExpectedPackage(referenceContext); + // } + currentPackageName = expectedPackageName.length == 0 ? CharOperation.NO_CHAR_CHAR + : expectedPackageName; + } + } + if (currentPackageName == CharOperation.NO_CHAR_CHAR) { + if ((fPackage = environment.defaultPackage) == null) { + problemReporter().mustSpecifyPackage(referenceContext); + return; + } + } else { + if ((fPackage = environment.createPackage(currentPackageName)) == null) { + // problemReporter().packageCollidesWithType(referenceContext); + return; + } + recordQualifiedReference(currentPackageName); // always dependent + // on your own + // package + } + + // Skip typeDeclarations which know of previously reported errors + ArrayList types = referenceContext.types; + int typeLength = (types == null) ? 0 : types.size(); + topLevelTypes = new SourceTypeBinding[typeLength]; + int count = 0; + nextType: for (int i = 0; i < typeLength; i++) { + if (types.get(i) instanceof TypeDeclaration) { + TypeDeclaration typeDecl = (TypeDeclaration) types.get(i); + ReferenceBinding typeBinding = fPackage.getType0(typeDecl.name); + recordSimpleReference(typeDecl.name); // needed to detect + // collision cases + if (typeBinding != null + && !(typeBinding instanceof UnresolvedReferenceBinding)) { + // if a type exists, it must be a valid type - cannot be a + // NotFound problem type + // unless its an unresolved type which is now being defined + problemReporter() + .duplicateTypes(referenceContext, typeDecl); + continue nextType; + } + if (fPackage != environment.defaultPackage + && fPackage.getPackage(typeDecl.name) != null) { + // if a package exists, it must be a valid package - cannot + // be a NotFound problem package + problemReporter().typeCollidesWithPackage(referenceContext, + typeDecl); + continue nextType; + } + + if ((typeDecl.modifiers & AccPublic) != 0) { + char[] mainTypeName; + if ((mainTypeName = referenceContext.getMainTypeName()) != null + // mainTypeName == null means that implementor of + // ICompilationUnit decided to return null + && !CharOperation.equals(mainTypeName, + typeDecl.name)) { + problemReporter().publicClassMustMatchFileName( + referenceContext, typeDecl); + continue nextType; + } + } + + ClassScope child = new ClassScope(this, typeDecl); + SourceTypeBinding type = child.buildType(null, fPackage); + if (type != null) { + topLevelTypes[count++] = type; + } + } + } + + // shrink topLevelTypes... only happens if an error was reported + if (count != topLevelTypes.length) + System.arraycopy(topLevelTypes, 0, + topLevelTypes = new SourceTypeBinding[count], 0, count); + } + + void checkAndSetImports() { + // initialize the default imports if necessary... share the default + // java.lang.* import + if (environment.defaultImports == null) { + Binding importBinding = environment.getTopLevelPackage(JAVA); + if (importBinding != null) + importBinding = ((PackageBinding) importBinding) + .getTypeOrPackage(JAVA_LANG[1]); + + // abort if java.lang cannot be found... + if (importBinding == null || !importBinding.isValidBinding()) + problemReporter().isClassPathCorrect(JAVA_LANG_OBJECT, + referenceCompilationUnit()); + + environment.defaultImports = new ImportBinding[] { new ImportBinding( + JAVA_LANG, true, importBinding, null) }; + } + if (referenceContext.imports == null) { + imports = environment.defaultImports; + return; + } + + // allocate the import array, add java.lang.* by default + int numberOfStatements = referenceContext.imports.length; + // int numberOfImports = numberOfStatements + 1; + int numberOfImports = numberOfStatements; + // for (int i = 0; i < numberOfStatements; i++) { + // ImportReference importReference = referenceContext.imports[i]; + // if (importReference.onDemand && CharOperation.equals(JAVA_LANG, + // importReference.tokens)) { + // numberOfImports--; + // break; + // } + // } + ImportBinding[] resolvedImports = new ImportBinding[numberOfImports]; + resolvedImports[0] = environment.defaultImports[0]; + int index = 1; + + nextImport: for (int i = 0; i < numberOfStatements; i++) { + ImportReference importReference = referenceContext.imports[i]; + IFile file = importReference.getFile(); + SourceTypeBinding typeBinding; + // char[][] compoundName = importReference.tokens; + char[][] compoundName = null; + if (file != null) { + IPath path = file.getProjectRelativePath(); + String[] segs = path.segments(); + compoundName = new char[segs.length][]; + for (int j = 0; j < segs.length; j++) { + compoundName[j] = segs[j].toCharArray(); + } + } + if (compoundName == null) { + continue nextImport; + } + + // skip duplicates or imports of the current package + for (int j = 0; j < index; j++) + if (resolvedImports[j].onDemand == importReference.onDemand) + if (CharOperation.equals(compoundName, + resolvedImports[j].compoundName)) + continue nextImport; + if (importReference.onDemand == true) + if (CharOperation.equals(compoundName, currentPackageName)) + continue nextImport; + + if (importReference.onDemand) { + Binding importBinding = findOnDemandImport(compoundName); + if (!importBinding.isValidBinding()) + continue nextImport; // we report all problems in + // faultInImports() + resolvedImports[index++] = new ImportBinding(compoundName, + true, importBinding, importReference); + } else { + resolvedImports[index++] = new ImportBinding(compoundName, + false, null, importReference); + } + } + + // shrink resolvedImports... only happens if an error was reported + if (resolvedImports.length > index) + System.arraycopy(resolvedImports, 0, + resolvedImports = new ImportBinding[index], 0, index); + imports = resolvedImports; + } + + /* + * INTERNAL USE-ONLY Innerclasses get their name computed as they are + * generated, since some may not be actually outputed if sitting inside + * unreachable code. + */ + public char[] computeConstantPoolName(LocalTypeBinding localType) { + if (localType.constantPoolName() != null) { + return localType.constantPoolName(); + } + // delegates to the outermost enclosing classfile, since it is the only + // one with a global vision of its innertypes. + + if (constantPoolNameUsage == null) + constantPoolNameUsage = new HashtableOfType(); + + ReferenceBinding outerMostEnclosingType = localType.scope + .outerMostClassScope().enclosingSourceType(); + + // ensure there is not already such a local type name defined by the + // user + int index = 0; + char[] candidateName; + while (true) { + if (localType.isMemberType()) { + if (index == 0) { + candidateName = CharOperation.concat(localType + .enclosingType().constantPoolName(), + localType.sourceName, '$'); + } else { + // in case of collision, then member name gets extra $1 + // inserted + // e.g. class X { { class L{} new X(){ class L{} } } } + candidateName = CharOperation.concat(localType + .enclosingType().constantPoolName(), '$', String + .valueOf(index).toCharArray(), '$', + localType.sourceName); + } + } else if (localType.isAnonymousType()) { + candidateName = CharOperation.concat(outerMostEnclosingType + .constantPoolName(), String.valueOf(index + 1) + .toCharArray(), '$'); + } else { + candidateName = CharOperation.concat(outerMostEnclosingType + .constantPoolName(), '$', String.valueOf(index + 1) + .toCharArray(), '$', localType.sourceName); + } + if (constantPoolNameUsage.get(candidateName) != null) { + index++; + } else { + constantPoolNameUsage.put(candidateName, localType); + break; + } + } + return candidateName; + } + + void connectTypeHierarchy() { + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].scope.connectTypeHierarchy(); + } + + void faultInImports() { + if (referenceContext.imports == null) + return; + // + // // collect the top level type names if a single type import exists + int numberOfStatements = referenceContext.imports.length; + // HashtableOfType typesBySimpleNames = null; + // for (int i = 0; i < numberOfStatements; i++) { + // if (!referenceContext.imports[i].onDemand) { + // typesBySimpleNames = new HashtableOfType(topLevelTypes.length + + // numberOfStatements); + // for (int j = 0, length = topLevelTypes.length; j < length; j++) + // typesBySimpleNames.put(topLevelTypes[j].sourceName, + // topLevelTypes[j]); + // break; + // } + // } + // + // // allocate the import array, add java.lang.* by default + // int numberOfImports = numberOfStatements + 1; + // for (int i = 0; i < numberOfStatements; i++) { + // ImportReference importReference = referenceContext.imports[i]; + // if (importReference.onDemand && CharOperation.equals(JAVA_LANG, + // importReference.tokens)) { + // numberOfImports--; + // break; + // } + // } + ImportBinding[] resolvedImports = new ImportBinding[numberOfStatements]; + // resolvedImports[0] = environment.defaultImports[0]; + // int index = 1; + int index = 0; + nextImport: for (int i = 0; i < numberOfStatements; i++) { + ImportReference importReference = referenceContext.imports[i]; + // create the file name segments here: + // char[][] compoundName = importReference.tokens; + // + // // skip duplicates or imports of the current package + // for (int j = 0; j < index; j++) + // if (resolvedImports[j].onDemand == importReference.onDemand) + // if (CharOperation.equals(compoundName, + // resolvedImports[j].compoundName)) { + // problemReporter().unusedImport(importReference); // since + // skipped, must be reported now + // continue nextImport; + // } + // if (importReference.onDemand == true) + // if (CharOperation.equals(compoundName, currentPackageName)) { + // problemReporter().unusedImport(importReference); // since + // skipped, must be reported now + // continue nextImport; + // } + // if (importReference.onDemand) { + // Binding importBinding = findOnDemandImport(compoundName); + // if (!importBinding.isValidBinding()) { + // problemReporter().importProblem(importReference, importBinding); + // continue nextImport; + // } + // resolvedImports[index++] = new ImportBinding(compoundName, true, + // importBinding, importReference); + // } else { + IFile file = importReference.getFile(); + SourceTypeBinding typeBinding; + char[][] compoundName; + if (file != null) { + typeBinding = new SourceTypeBinding(); + // findSingleTypeImport(compoundName); + IPath path = file.getProjectRelativePath(); + String[] segs = path.segments(); + compoundName = new char[segs.length][]; + for (int j = 0; j < segs.length; j++) { + compoundName[j] = segs[j].toCharArray(); + } + typeBinding.compoundName = compoundName; // compoundName; + // this.fPackage = fPackage; + typeBinding.fileName = file.getLocation().toString() + .toCharArray(); + // typeBinding.modifiers = scope.referenceContext.modifiers; + // typeBinding.sourceName = scope.referenceContext.name; + typeBinding.sourceName = path.lastSegment().toCharArray(); + // this.scope = scope; + } else { + // if (!typeBinding.isValidBinding()) { + // problemReporter().importProblem(importReference, + // typeBinding); + continue nextImport; + // } + } + // if (typeBinding instanceof PackageBinding) { + // problemReporter().cannotImportPackage(importReference); + // continue nextImport; + // } + // if (typeBinding instanceof ReferenceBinding) { + // ReferenceBinding referenceBinding = (ReferenceBinding) + // typeBinding; + // if (importReference.isTypeUseDeprecated(referenceBinding, this)) + // { + // problemReporter().deprecatedType((TypeBinding) typeBinding, + // importReference); + // } + // } + // ReferenceBinding existingType = + // typesBySimpleNames.get(compoundName[compoundName.length - 1]); + // if (existingType != null) { + // // duplicate test above should have caught this case, but make + // sure + // if (existingType == typeBinding) { + // continue nextImport; + // } + // // either the type collides with a top level type or another + // imported type + // for (int j = 0, length = topLevelTypes.length; j < length; j++) { + // if (CharOperation.equals(topLevelTypes[j].sourceName, + // existingType.sourceName)) { + // problemReporter().conflictingImport(importReference); + // continue nextImport; + // } + // } + // problemReporter().duplicateImport(importReference); + // continue nextImport; + // } + resolvedImports[index++] = new ImportBinding(compoundName, false, + typeBinding, importReference); + imports = resolvedImports; + // typesBySimpleNames.put(compoundName[compoundName.length - 1], + // (ReferenceBinding) typeBinding); + // } + } + // + // // shrink resolvedImports... only happens if an error was reported + if (resolvedImports.length > index) + System.arraycopy(resolvedImports, 0, + resolvedImports = new ImportBinding[index], 0, index); + imports = resolvedImports; + + int length = imports.length; + resolvedSingeTypeImports = new HashtableOfObject(length); + for (int i = 0; i < length; i++) { + ImportBinding binding = imports[i]; + if (!binding.onDemand) + resolvedSingeTypeImports.put( + binding.compoundName[binding.compoundName.length - 1], + binding); + } + } + + public void faultInTypes() { + faultInImports(); + if (topLevelTypes == null) { + topLevelTypes = new SourceTypeBinding[0]; + } + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].faultInTypesForFieldsAndMethods(); + } + + private Binding findOnDemandImport(char[][] compoundName) { + recordQualifiedReference(compoundName); + + Binding binding = environment.getTopLevelPackage(compoundName[0]); + int i = 1; + int length = compoundName.length; + foundNothingOrType: if (binding != null) { + PackageBinding packageBinding = (PackageBinding) binding; + while (i < length) { + binding = packageBinding.getTypeOrPackage(compoundName[i++]); + if (binding == null || !binding.isValidBinding()) { + binding = null; + break foundNothingOrType; + } + if (!(binding instanceof PackageBinding)) + break foundNothingOrType; + + packageBinding = (PackageBinding) binding; + } + return packageBinding; + } + + ReferenceBinding type; + if (binding == null) { + // if (environment.defaultPackage == null + // || environment.options.complianceLevel >= + // CompilerOptions.JDK1_4){ + // return new ProblemReferenceBinding( + // CharOperation.subarray(compoundName, 0, i), + // NotFound); + // } + type = findType(compoundName[0], environment.defaultPackage, + environment.defaultPackage); + if (type == null || !type.isValidBinding()) + return new ProblemReferenceBinding(CharOperation.subarray( + compoundName, 0, i), NotFound); + i = 1; // reset to look for member types inside the default package + // type + } else { + type = (ReferenceBinding) binding; + } + + for (; i < length; i++) { + if (!type.canBeSeenBy(fPackage)) { + return new ProblemReferenceBinding(CharOperation.subarray( + compoundName, 0, i), type, NotVisible); + } + // does not look for inherited member types on purpose + if ((type = type.getMemberType(compoundName[i])) == null) { + return new ProblemReferenceBinding(CharOperation.subarray( + compoundName, 0, i + 1), NotFound); + } + } + if (!type.canBeSeenBy(fPackage)) + return new ProblemReferenceBinding(compoundName, type, NotVisible); + return type; + } + + private Binding findSingleTypeImport(char[][] compoundName) { + // if (compoundName.length == 1) { + // findType records the reference + // the name cannot be a package + // if (environment.defaultPackage == null + // || environment.options.complianceLevel >= CompilerOptions.JDK1_4) + // return new ProblemReferenceBinding(compoundName, NotFound); + ReferenceBinding typeBinding = findType(compoundName[0], + environment.defaultPackage, fPackage); + if (typeBinding == null) + return new ProblemReferenceBinding(compoundName, NotFound); + else + return typeBinding; + // } + // return findOnDemandImport(compoundName); + } + + /* + * Answer the problem reporter to use for raising new problems. + * + * Note that as a side-effect, this updates the current reference context + * (unit, type or method) in case the problem handler decides it is + * necessary to abort. + */ + + public ProblemReporter problemReporter() { + ProblemReporter problemReporter = referenceContext.problemReporter; + problemReporter.referenceContext = referenceContext; + return problemReporter; + } + + /* + * What do we hold onto: + * + * 1. when we resolve 'a.b.c', say we keep only 'a.b.c' & when we fail to + * resolve 'c' in 'a.b', lets keep 'a.b.c' THEN when we come across a + * new/changed/removed item named 'a.b.c', we would find all references to + * 'a.b.c' -> This approach fails because every type is resolved in every + * onDemand import to detect collision cases... so the references could be + * 10 times bigger than necessary. + * + * 2. when we resolve 'a.b.c', lets keep 'a.b' & 'c' & when we fail to + * resolve 'c' in 'a.b', lets keep 'a.b' & 'c' THEN when we come across a + * new/changed/removed item named 'a.b.c', we would find all references to + * 'a.b' & 'c' -> This approach does not have a space problem but fails to + * handle collision cases. What happens if a type is added named 'a.b'? We + * would search for 'a' & 'b' but would not find a match. + * + * 3. when we resolve 'a.b.c', lets keep 'a', 'a.b' & 'a', 'b', 'c' & when + * we fail to resolve 'c' in 'a.b', lets keep 'a', 'a.b' & 'a', 'b', 'c' + * THEN when we come across a new/changed/removed item named 'a.b.c', we + * would find all references to 'a.b' & 'c' OR 'a.b' -> 'a' & 'b' OR 'a' -> '' & + * 'a' -> As long as each single char[] is interned, we should not have a + * space problem and can handle collision cases. + * + * 4. when we resolve 'a.b.c', lets keep 'a.b' & 'a', 'b', 'c' & when we + * fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'a', 'b', 'c' THEN when + * we come across a new/changed/removed item named 'a.b.c', we would find + * all references to 'a.b' & 'c' OR 'a.b' -> 'a' & 'b' in the simple name + * collection OR 'a' -> 'a' in the simple name collection -> As long as each + * single char[] is interned, we should not have a space problem and can + * handle collision cases. + */ + void recordQualifiedReference(char[][] qualifiedName) { + if (qualifiedReferences == null) + return; // not recording dependencies + + int length = qualifiedName.length; + if (length > 1) { + while (!qualifiedReferences.contains(qualifiedName)) { + qualifiedReferences.add(qualifiedName); + if (length == 2) { + recordSimpleReference(qualifiedName[0]); + recordSimpleReference(qualifiedName[1]); + return; + } + length--; + recordSimpleReference(qualifiedName[length]); + System.arraycopy(qualifiedName, 0, + qualifiedName = new char[length][], 0, length); + } + } else if (length == 1) { + recordSimpleReference(qualifiedName[0]); + } + } + + void recordReference(char[][] qualifiedEnclosingName, char[] simpleName) { + recordQualifiedReference(qualifiedEnclosingName); + recordSimpleReference(simpleName); + } + + void recordSimpleReference(char[] simpleName) { + if (simpleNameReferences == null) + return; // not recording dependencies + + if (!simpleNameReferences.contains(simpleName)) + simpleNameReferences.add(simpleName); + } + + void recordTypeReference(TypeBinding type) { + if (referencedTypes == null) + return; // not recording dependencies + + if (type.isArrayType()) + type = ((ArrayBinding) type).leafComponentType; + if (!type.isBaseType() && !referencedTypes.containsIdentical(type)) + referencedTypes.add(type); + } + + void recordTypeReferences(TypeBinding[] types) { + if (qualifiedReferences == null) + return; // not recording dependencies + if (types == null || types.length == 0) + return; + + for (int i = 0, max = types.length; i < max; i++) { + // No need to record supertypes of method arguments & thrown + // exceptions, just the compoundName + // If a field/method is retrieved from such a type then a separate + // call does the job + TypeBinding type = types[i]; + if (type.isArrayType()) + type = ((ArrayBinding) type).leafComponentType; + if (!type.isBaseType()) { + ReferenceBinding actualType = (ReferenceBinding) type; + if (!actualType.isLocalType()) + recordQualifiedReference(actualType.isMemberType() ? CharOperation + .splitOn('.', actualType.readableName()) + : actualType.compoundName); + } + } + } + + Binding resolveSingleTypeImport(ImportBinding importBinding) { + if (importBinding.resolvedImport == null) { + importBinding.resolvedImport = findSingleTypeImport(importBinding.compoundName); + if (!importBinding.resolvedImport.isValidBinding() + || importBinding.resolvedImport instanceof PackageBinding) { + if (this.imports != null) { + ImportBinding[] newImports = new ImportBinding[imports.length - 1]; + for (int i = 0, n = 0, max = this.imports.length; i < max; i++) + if (this.imports[i] != importBinding) { + newImports[n++] = this.imports[i]; + } + this.imports = newImports; + } + return null; + } + } + return importBinding.resolvedImport; + } + + public void storeDependencyInfo() { + // add the type hierarchy of each referenced type + // cannot do early since the hierarchy may not be fully resolved + for (int i = 0; i < referencedTypes.size; i++) { // grows as more + // types are added + ReferenceBinding type = (ReferenceBinding) referencedTypes + .elementAt(i); + if (!type.isLocalType()) { + recordQualifiedReference(type.isMemberType() ? CharOperation + .splitOn('.', type.readableName()) : type.compoundName); + ReferenceBinding enclosing = type.enclosingType(); + if (enclosing != null + && !referencedTypes.containsIdentical(enclosing)) + referencedTypes.add(enclosing); // to record its supertypes + } + ReferenceBinding superclass = type.superclass(); + if (superclass != null + && !referencedTypes.containsIdentical(superclass)) + referencedTypes.add(superclass); // to record its supertypes + ReferenceBinding[] interfaces = type.superInterfaces(); + if (interfaces != null && interfaces.length > 0) + for (int j = 0, length = interfaces.length; j < length; j++) + if (!referencedTypes.containsIdentical(interfaces[j])) + referencedTypes.add(interfaces[j]); // to record its + // supertypes + } + + int size = qualifiedReferences.size; + char[][][] qualifiedRefs = new char[size][][]; + for (int i = 0; i < size; i++) + qualifiedRefs[i] = qualifiedReferences.elementAt(i); + referenceContext.compilationResult.qualifiedReferences = qualifiedRefs; + + size = simpleNameReferences.size; + char[][] simpleRefs = new char[size][]; + for (int i = 0; i < size; i++) + simpleRefs[i] = simpleNameReferences.elementAt(i); + referenceContext.compilationResult.simpleNameReferences = simpleRefs; + } + + public String toString() { + return "--- CompilationUnit Scope : " + new String(referenceContext.getFileName()); //$NON-NLS-1$ + } + + public void verifyMethods(MethodVerifier verifier) { + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].verifyMethods(verifier); + } +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java new file mode 100644 index 0000000..b27c78c --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java @@ -0,0 +1,5118 @@ +/*********************************************************************************************************************************** + * Copyright (c) 2002 www.phpeclipse.de All rights reserved. This program and the accompanying material are made available under the + * terms of the Common Public License v1.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: www.phpeclipse.de + **********************************************************************************************************************************/ +package net.sourceforge.phpdt.internal.compiler.parser; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; + +import net.sourceforge.phpdt.core.compiler.CharOperation; +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.ast.AND_AND_Expression; +import net.sourceforge.phpdt.internal.compiler.ast.ASTNode; +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.BinaryExpression; +import net.sourceforge.phpdt.internal.compiler.ast.Block; +import net.sourceforge.phpdt.internal.compiler.ast.BreakStatement; +import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ConditionalExpression; +import net.sourceforge.phpdt.internal.compiler.ast.ContinueStatement; +import net.sourceforge.phpdt.internal.compiler.ast.EqualExpression; +import net.sourceforge.phpdt.internal.compiler.ast.Expression; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.FieldReference; +import net.sourceforge.phpdt.internal.compiler.ast.IfStatement; +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; +import net.sourceforge.phpdt.internal.compiler.ast.InstanceOfExpression; +import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.OR_OR_Expression; +import net.sourceforge.phpdt.internal.compiler.ast.OperatorIds; +import net.sourceforge.phpdt.internal.compiler.ast.ReturnStatement; +import net.sourceforge.phpdt.internal.compiler.ast.SingleTypeReference; +import net.sourceforge.phpdt.internal.compiler.ast.Statement; +import net.sourceforge.phpdt.internal.compiler.ast.StringLiteral; +import net.sourceforge.phpdt.internal.compiler.ast.StringLiteralDQ; +import net.sourceforge.phpdt.internal.compiler.ast.StringLiteralSQ; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; +import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; +import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext; +import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities; +import net.sourceforge.phpdt.internal.compiler.util.Util; +import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil; +import net.sourceforge.phpeclipse.builder.IdentifierIndexManager; +import net.sourceforge.phpeclipse.ui.overlaypages.ProjectPrefUtil; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IPath; + +public class Parser implements ITerminalSymbols, CompilerModifiers, + ParserBasicInformation { + protected final static int StackIncrement = 255; + + protected int stateStackTop; + + // protected int[] stack = new int[StackIncrement]; + + public int firstToken; // handle for multiple parsing goals + + public int lastAct; // handle for multiple parsing goals + + // protected RecoveredElement currentElement; + + public static boolean VERBOSE_RECOVERY = false; + + protected boolean diet = false; // tells the scanner to jump over some + + /** + * the PHP token scanner + */ + public Scanner scanner; + + int token; + + protected int modifiers; + + protected int modifiersSourceStart; + + protected Parser(ProblemReporter problemReporter) { + this.problemReporter = problemReporter; + this.options = problemReporter.options; + this.token = TokenNameEOF; + this.initializeScanner(); + } + + public void setFileToParse(IFile fileToParse) { + this.token = TokenNameEOF; + this.initializeScanner(); + } + + /** + * ClassDeclaration Constructor. + * + * @param s + * @param sess + * Description of Parameter + * @see + */ + public Parser(IFile fileToParse) { + // if (keywordMap == null) { + // keywordMap = new HashMap(); + // for (int i = 0; i < PHP_KEYWORS.length; i++) { + // keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i])); + // } + // } + // this.currentPHPString = 0; + // PHPParserSuperclass.fileToParse = fileToParse; + // this.phpList = null; + this.includesList = null; + // this.str = ""; + this.token = TokenNameEOF; + // this.chIndx = 0; + // this.rowCount = 1; + // this.columnCount = 0; + // this.phpEnd = false; + // getNextToken(); + this.initializeScanner(); + } + + public void initializeScanner() { + this.scanner = new Scanner( + false /* comment */, + false /* whitespace */, + this.options.getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore /* nls */, + false, false, this.options.taskTags/* taskTags */, + this.options.taskPriorites/* taskPriorities */, true/* isTaskCaseSensitive */); + } + + /** + * Create marker for the parse error + */ + // private void setMarker(String message, int charStart, int charEnd, int + // errorLevel) { + // setMarker(fileToParse, message, charStart, charEnd, errorLevel); + // } + /** + * This method will throw the SyntaxError. It will add the good lines and + * columns to the Error + * + * @param error + * the error message + * @throws SyntaxError + * the error raised + */ + private void throwSyntaxError(String error) { + int problemStartPosition = scanner.getCurrentTokenStartPosition(); + int problemEndPosition = scanner.getCurrentTokenEndPosition() + 1; + if (scanner.source.length <= problemEndPosition + && problemEndPosition > 0) { + problemEndPosition = scanner.source.length - 1; + if (problemStartPosition > 0 + && problemStartPosition >= problemEndPosition + && problemEndPosition > 0) { + problemStartPosition = problemEndPosition - 1; + } + } + throwSyntaxError(error, problemStartPosition, problemEndPosition); + } + + /** + * This method will throw the SyntaxError. It will add the good lines and + * columns to the Error + * + * @param error + * the error message + * @throws SyntaxError + * the error raised + */ + // private void throwSyntaxError(String error, int startRow) { + // throw new SyntaxError(startRow, 0, " ", error); + // } + private void throwSyntaxError(String error, int problemStartPosition, + int problemEndPosition) { + if (referenceContext != null) { + problemReporter.phpParsingError(new String[] { error }, + problemStartPosition, problemEndPosition, referenceContext, + compilationUnit.compilationResult); + } + throw new SyntaxError(1, 0, " ", error); + } + + private void reportSyntaxError(String error) { + int problemStartPosition = scanner.getCurrentTokenStartPosition(); + int problemEndPosition = scanner.getCurrentTokenEndPosition(); + reportSyntaxError(error, problemStartPosition, problemEndPosition + 1); + } + + private void reportSyntaxError(String error, int problemStartPosition, + int problemEndPosition) { + if (referenceContext != null) { + problemReporter.phpParsingError(new String[] { error }, + problemStartPosition, problemEndPosition, referenceContext, + compilationUnit.compilationResult); + } + } + + // private void reportSyntaxWarning(String error, int problemStartPosition, + // int problemEndPosition) { + // if (referenceContext != null) { + // problemReporter.phpParsingWarning(new String[] { error }, + // problemStartPosition, problemEndPosition, referenceContext, + // compilationUnit.compilationResult); + // } + // } + + /** + * gets the next token from input + */ + private void getNextToken() { + try { + token = scanner.getNextToken(); + if (Scanner.DEBUG) { + int currentEndPosition = scanner.getCurrentTokenEndPosition(); + int currentStartPosition = scanner + .getCurrentTokenStartPosition(); + System.out.print(currentStartPosition + "," + + currentEndPosition + ": "); + System.out.println(scanner.toStringAction(token)); + } + } catch (InvalidInputException e) { + token = TokenNameERROR; + String detailedMessage = e.getMessage(); + + if (detailedMessage == Scanner.UNTERMINATED_STRING) { + throwSyntaxError("Unterminated string."); + } else if (detailedMessage == Scanner.UNTERMINATED_COMMENT) { + throwSyntaxError("Unterminated commment."); + } + } + return; + } + + public void init(String s) { + // this.str = s; + this.token = TokenNameEOF; + this.includesList = new ArrayList(); + // this.chIndx = 0; + // this.rowCount = 1; + // this.columnCount = 0; + // this.phpEnd = false; + // this.phpMode = false; + /* scanner initialization */ + scanner.setSource(s.toCharArray()); + scanner.setPHPMode(false); + astPtr = 0; + } + + protected void initialize(boolean phpMode) { + initialize(phpMode, null); + } + + protected void initialize(boolean phpMode, + IdentifierIndexManager indexManager) { + compilationUnit = null; + referenceContext = null; + this.includesList = new ArrayList(); + // this.indexManager = indexManager; + // this.str = ""; + this.token = TokenNameEOF; + // this.chIndx = 0; + // this.rowCount = 1; + // this.columnCount = 0; + // this.phpEnd = false; + // this.phpMode = phpMode; + scanner.setPHPMode(phpMode); + astPtr = 0; + } + + /** + * Parses a string with php tags i.e. '<body> <?php phpinfo() ?> + * </body>' + */ + public void parse(String s) { + parse(s, null); + } + + /** + * Parses a string with php tags i.e. '<body> <?php phpinfo() ?> + * </body>' + */ + public void parse(String s, HashMap variables) { + fMethodVariables = variables; + fStackUnassigned = new ArrayList(); + init(s); + parse(); + } + + /** + * Parses a string with php tags i.e. '<body> <?php phpinfo() ?> + * </body>' + */ + protected void parse() { + if (scanner.compilationUnit != null) { + IResource resource = scanner.compilationUnit.getResource(); + if (resource != null && resource instanceof IFile) { + // set the package name + consumePackageDeclarationName((IFile) resource); + } + } + getNextToken(); + do { + try { + if (token != TokenNameEOF && token != TokenNameERROR) { + statementList(); + } + if (token != TokenNameEOF) { + if (token == TokenNameERROR) { + throwSyntaxError("Scanner error (Found unknown token: " + + scanner.toStringAction(token) + ")"); + } + if (token == TokenNameRPAREN) { + throwSyntaxError("Too many closing ')'; end-of-file not reached."); + } + if (token == TokenNameRBRACE) { + throwSyntaxError("Too many closing '}'; end-of-file not reached."); + } + if (token == TokenNameRBRACKET) { + throwSyntaxError("Too many closing ']'; end-of-file not reached."); + } + if (token == TokenNameLPAREN) { + throwSyntaxError("Read character '('; end-of-file not reached."); + } + if (token == TokenNameLBRACE) { + throwSyntaxError("Read character '{'; end-of-file not reached."); + } + if (token == TokenNameLBRACKET) { + throwSyntaxError("Read character '['; end-of-file not reached."); + } + throwSyntaxError("End-of-file not reached."); + } + break; + } catch (SyntaxError syntaxError) { + // syntaxError.printStackTrace(); + break; + } + } while (true); + + endParse(0); + } + + /** + * Parses a string with php tags i.e. '<body> <?php phpinfo() ?> + * </body>' + */ + public void parseFunction(String s, HashMap variables) { + init(s); + scanner.phpMode = true; + parseFunction(variables); + } + + /** + * Parses a string with php tags i.e. '<body> <?php phpinfo() ?> + * </body>' + */ + protected void parseFunction(HashMap variables) { + getNextToken(); + boolean hasModifiers = member_modifiers(); + if (token == TokenNamefunction) { + if (!hasModifiers) { + checkAndSetModifiers(AccPublic); + } + this.fMethodVariables = variables; + + MethodDeclaration methodDecl = new MethodDeclaration(null); + methodDecl.declarationSourceStart = scanner + .getCurrentTokenStartPosition(); + methodDecl.modifiers = this.modifiers; + methodDecl.type = MethodDeclaration.METHOD_DEFINITION; + try { + getNextToken(); + functionDefinition(methodDecl); + } catch (SyntaxError sytaxErr1) { + return; + } finally { + int sourceEnd = methodDecl.sourceEnd; + if (sourceEnd <= 0 + || methodDecl.declarationSourceStart > sourceEnd) { + sourceEnd = methodDecl.declarationSourceStart + 1; + } + methodDecl.sourceEnd = sourceEnd; + methodDecl.declarationSourceEnd = sourceEnd; + } + } + } + + protected CompilationUnitDeclaration endParse(int act) { + + this.lastAct = act; + + // if (currentElement != null) { + // currentElement.topElement().updateParseTree(); + // if (VERBOSE_RECOVERY) { + // System.out.print(Util.bind("parser.syntaxRecovery")); //$NON-NLS-1$ + // System.out.println("--------------------------"); //$NON-NLS-1$ + // System.out.println(compilationUnit); + // System.out.println("----------------------------------"); + // //$NON-NLS-1$ + // } + // } else { + if (diet & VERBOSE_RECOVERY) { + System.out.print(Util.bind("parser.regularParse")); //$NON-NLS-1$ + System.out.println("--------------------------"); //$NON-NLS-1$ + System.out.println(compilationUnit); + System.out.println("----------------------------------"); //$NON-NLS-1$ + } + // } + if (scanner.recordLineSeparator) { + compilationUnit.compilationResult.lineSeparatorPositions = scanner + .getLineEnds(); + } + if (scanner.taskTags != null) { + for (int i = 0; i < scanner.foundTaskCount; i++) { + problemReporter().task( + new String(scanner.foundTaskTags[i]), + new String(scanner.foundTaskMessages[i]), + scanner.foundTaskPriorities[i] == null ? null + : new String(scanner.foundTaskPriorities[i]), + scanner.foundTaskPositions[i][0], + scanner.foundTaskPositions[i][1]); + } + } + compilationUnit.imports = new ImportReference[includesList.size()]; + for (int i = 0; i < includesList.size(); i++) { + compilationUnit.imports[i] = (ImportReference) includesList.get(i); + } + return compilationUnit; + } + + private Block statementList() { + boolean branchStatement = false; + Statement statement; + int blockStart = scanner.getCurrentTokenStartPosition(); + ArrayList blockStatements = new ArrayList(); + do { + try { + statement = statement(); + blockStatements.add(statement); + if (token == TokenNameEOF) { + return null; + } + if (branchStatement && statement != null) { + // reportSyntaxError("Unreachable code", + // statement.sourceStart, + // statement.sourceEnd); + if (!(statement instanceof BreakStatement)) { + /* + * don't give an error for break statement following + * return statement Technically it's unreachable code, + * but in switch-case it's recommended to avoid + * accidental fall-through later when editing the code + */ + problemReporter.unreachableCode(new String(scanner + .getCurrentIdentifierSource()), + statement.sourceStart, statement.sourceEnd, + referenceContext, + compilationUnit.compilationResult); + } + } + if ((token == TokenNameRBRACE) || (token == TokenNamecase) + || (token == TokenNamedefault) + || (token == TokenNameelse) + || (token == TokenNameelseif) + || (token == TokenNameendif) + || (token == TokenNameendfor) + || (token == TokenNameendforeach) + || (token == TokenNameendwhile) + || (token == TokenNameendswitch) + || (token == TokenNameenddeclare) + || (token == TokenNameEOF) || (token == TokenNameERROR)) { + return createBlock(blockStart, blockStatements); + } + branchStatement = checkUnreachableStatements(statement); + } catch (SyntaxError sytaxErr1) { + // if an error occured, + // try to find keywords + // to parse the rest of the string + boolean tokenize = scanner.tokenizeStrings; + if (!tokenize) { + scanner.tokenizeStrings = true; + } + try { + while (token != TokenNameEOF) { + if ((token == TokenNameRBRACE) + || (token == TokenNamecase) + || (token == TokenNamedefault) + || (token == TokenNameelse) + || (token == TokenNameelseif) + || (token == TokenNameendif) + || (token == TokenNameendfor) + || (token == TokenNameendforeach) + || (token == TokenNameendwhile) + || (token == TokenNameendswitch) + || (token == TokenNameenddeclare) + || (token == TokenNameEOF) + || (token == TokenNameERROR)) { + return createBlock(blockStart, blockStatements); + } + if (token == TokenNameif || token == TokenNameswitch + || token == TokenNamefor + || token == TokenNamewhile + || token == TokenNamedo + || token == TokenNameforeach + || token == TokenNamecontinue + || token == TokenNamebreak + || token == TokenNamereturn + || token == TokenNameexit + || token == TokenNameecho + || token == TokenNameECHO_INVISIBLE + || token == TokenNameglobal + || token == TokenNamestatic + || token == TokenNameunset + || token == TokenNamefunction + || token == TokenNamedeclare + || token == TokenNametry + || token == TokenNamecatch + || token == TokenNamethrow + || token == TokenNamefinal + || token == TokenNameabstract + || token == TokenNameclass + || token == TokenNameinterface) { + break; + } + // System.out.println(scanner.toStringAction(token)); + getNextToken(); + // System.out.println(scanner.toStringAction(token)); + } + if (token == TokenNameEOF) { + throw sytaxErr1; + } + } finally { + scanner.tokenizeStrings = tokenize; + } + } + } while (true); + } + + /** + * @param statement + * @return + */ + private boolean checkUnreachableStatements(Statement statement) { + if (statement instanceof ReturnStatement + || statement instanceof ContinueStatement + || statement instanceof BreakStatement) { + return true; + } else if (statement instanceof IfStatement + && ((IfStatement) statement).checkUnreachable) { + return true; + } + return false; + } + + /** + * @param blockStart + * @param blockStatements + * @return + */ + private Block createBlock(int blockStart, ArrayList blockStatements) { + int blockEnd = scanner.getCurrentTokenEndPosition(); + Block b = Block.EmptyWith(blockStart, blockEnd); + b.statements = new Statement[blockStatements.size()]; + blockStatements.toArray(b.statements); + return b; + } + + private void functionBody(MethodDeclaration methodDecl) { + // '{' [statement-list] '}' + if (token == TokenNameLBRACE) { + getNextToken(); + } else { + methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1; + throwSyntaxError("'{' expected in compound-statement."); + } + if (token != TokenNameRBRACE) { + statementList(); + } + if (token == TokenNameRBRACE) { + methodDecl.sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } else { + methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1; + throwSyntaxError("'}' expected in compound-statement."); + } + } + + private Statement statement() { + Statement statement = null; + Expression expression; + int sourceStart = scanner.getCurrentTokenStartPosition(); + int sourceEnd; + if (token == TokenNameif) { + // T_IF '(' expr ')' statement elseif_list else_single + // T_IF '(' expr ')' ':' inner_statement_list new_elseif_list + // new_else_single T_ENDIF ';' + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'if' keyword."); + } + expression = expr(); + if (token == TokenNameRPAREN) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'if' condition."); + } + // create basic IfStatement + IfStatement ifStatement = new IfStatement(expression, null, null, + sourceStart, -1); + if (token == TokenNameCOLON) { + getNextToken(); + ifStatementColon(ifStatement); + } else { + ifStatement(ifStatement); + } + return ifStatement; + } else if (token == TokenNameswitch) { + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'switch' keyword."); + } + expr(); + if (token == TokenNameRPAREN) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'switch' condition."); + } + switchStatement(); + return statement; + } else if (token == TokenNamefor) { + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'for' keyword."); + } + if (token == TokenNameSEMICOLON) { + getNextToken(); + } else { + expressionList(); + if (token == TokenNameSEMICOLON) { + getNextToken(); + } else { + throwSyntaxError("';' expected after 'for'."); + } + } + if (token == TokenNameSEMICOLON) { + getNextToken(); + } else { + expressionList(); + if (token == TokenNameSEMICOLON) { + getNextToken(); + } else { + throwSyntaxError("';' expected after 'for'."); + } + } + if (token == TokenNameRPAREN) { + getNextToken(); + } else { + expressionList(); + if (token == TokenNameRPAREN) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'for'."); + } + } + forStatement(); + return statement; + } else if (token == TokenNamewhile) { + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'while' keyword."); + } + expr(); + if (token == TokenNameRPAREN) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'while' condition."); + } + whileStatement(); + return statement; + } else if (token == TokenNamedo) { + getNextToken(); + if (token == TokenNameLBRACE) { + getNextToken(); + if (token != TokenNameRBRACE) { + statementList(); + } + if (token == TokenNameRBRACE) { + getNextToken(); + } else { + throwSyntaxError("'}' expected after 'do' keyword."); + } + } else { + statement(); + } + if (token == TokenNamewhile) { + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'while' keyword."); + } + expr(); + if (token == TokenNameRPAREN) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'while' condition."); + } + } else { + throwSyntaxError("'while' expected after 'do' keyword."); + } + if (token == TokenNameSEMICOLON) { + getNextToken(); + } else { + if (token != TokenNameINLINE_HTML) { + throwSyntaxError("';' expected after do-while statement."); + } + getNextToken(); + } + return statement; + } else if (token == TokenNameforeach) { + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'foreach' keyword."); + } + expr(); + if (token == TokenNameas) { + getNextToken(); + } else { + throwSyntaxError("'as' expected after 'foreach' exxpression."); + } + // variable(); + foreach_variable(); + foreach_optional_arg(); + if (token == TokenNameEQUAL_GREATER) { + getNextToken(); + variable(false, false); + } + if (token == TokenNameRPAREN) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'foreach' expression."); + } + foreachStatement(); + return statement; + } else if (token == TokenNamebreak) { + expression = null; + getNextToken(); + if (token != TokenNameSEMICOLON) { + expression = expr(); + } + if (token == TokenNameSEMICOLON) { + sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } else { + if (token != TokenNameINLINE_HTML) { + throwSyntaxError("';' expected after 'break'."); + } + sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } + return new BreakStatement(null, sourceStart, sourceEnd); + } else if (token == TokenNamecontinue) { + expression = null; + getNextToken(); + if (token != TokenNameSEMICOLON) { + expression = expr(); + } + if (token == TokenNameSEMICOLON) { + sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } else { + if (token != TokenNameINLINE_HTML) { + throwSyntaxError("';' expected after 'continue'."); + } + sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } + return new ContinueStatement(null, sourceStart, sourceEnd); + } else if (token == TokenNamereturn) { + expression = null; + getNextToken(); + if (token != TokenNameSEMICOLON) { + expression = expr(); + } + if (token == TokenNameSEMICOLON) { + sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } else { + if (token != TokenNameINLINE_HTML) { + throwSyntaxError("';' expected after 'return'."); + } + sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } + return new ReturnStatement(expression, sourceStart, sourceEnd); + } else if (token == TokenNameecho) { + getNextToken(); + expressionList(); + if (token == TokenNameSEMICOLON) { + getNextToken(); + } else { + if (token != TokenNameINLINE_HTML) { + throwSyntaxError("';' expected after 'echo' statement."); + } + getNextToken(); + } + return statement; + } else if (token == TokenNameECHO_INVISIBLE) { + // 0-length token directly after PHP short tag <?= + getNextToken(); + expressionList(); + if (token == TokenNameSEMICOLON) { + getNextToken(); + // if (token != TokenNameINLINE_HTML) { + // // TODO should this become a configurable warning? + // reportSyntaxError("Probably '?>' expected after PHP short tag + // expression (only the first expression will be echoed)."); + // } + } else { + if (token != TokenNameINLINE_HTML) { + throwSyntaxError("';' expected after PHP short tag ' sourceEnd) { + sourceEnd = methodDecl.declarationSourceStart + 1; + } + methodDecl.declarationSourceEnd = sourceEnd; + methodDecl.sourceEnd = sourceEnd; + } + return statement; + } else if (token == TokenNamedeclare) { + // T_DECLARE '(' declare_list ')' declare_statement + getNextToken(); + if (token != TokenNameLPAREN) { + throwSyntaxError("'(' expected in 'declare' statement."); + } + getNextToken(); + declare_list(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected in 'declare' statement."); + } + getNextToken(); + declare_statement(); + return statement; + } else if (token == TokenNametry) { + getNextToken(); + if (token != TokenNameLBRACE) { + throwSyntaxError("'{' expected in 'try' statement."); + } + getNextToken(); + statementList(); + if (token != TokenNameRBRACE) { + throwSyntaxError("'}' expected in 'try' statement."); + } + getNextToken(); + return statement; + } else if (token == TokenNamecatch) { + getNextToken(); + if (token != TokenNameLPAREN) { + throwSyntaxError("'(' expected in 'catch' statement."); + } + getNextToken(); + fully_qualified_class_name(); + if (token != TokenNameVariable) { + throwSyntaxError("Variable expected in 'catch' statement."); + } + addVariableSet(); + getNextToken(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected in 'catch' statement."); + } + getNextToken(); + if (token != TokenNameLBRACE) { + throwSyntaxError("'{' expected in 'catch' statement."); + } + getNextToken(); + if (token != TokenNameRBRACE) { + statementList(); + if (token != TokenNameRBRACE) { + throwSyntaxError("'}' expected in 'catch' statement."); + } + } + getNextToken(); + additional_catches(); + return statement; + } else if (token == TokenNamethrow) { + getNextToken(); + expr(); + if (token == TokenNameSEMICOLON) { + getNextToken(); + } else { + throwSyntaxError("';' expected after 'throw' exxpression."); + } + return statement; + } else if (token == TokenNamefinal || token == TokenNameabstract + || token == TokenNameclass || token == TokenNameinterface) { + try { + TypeDeclaration typeDecl = new TypeDeclaration( + this.compilationUnit.compilationResult); + typeDecl.declarationSourceStart = scanner + .getCurrentTokenStartPosition(); + typeDecl.declarationSourceEnd = scanner + .getCurrentTokenEndPosition(); + typeDecl.name = new char[] { ' ' }; + // default super class + typeDecl.superclass = new SingleTypeReference( + TypeConstants.OBJECT, 0); + compilationUnit.types.add(typeDecl); + pushOnAstStack(typeDecl); + unticked_class_declaration_statement(typeDecl); + } finally { + // reduce stack: + astPtr--; + astLengthPtr--; + } + return statement; + // } else { + // throwSyntaxError("Unexpected keyword '" + keyword + "'"); + } else if (token == TokenNameLBRACE) { + getNextToken(); + if (token != TokenNameRBRACE) { + statement = statementList(); + } + if (token == TokenNameRBRACE) { + getNextToken(); + return statement; + } else { + throwSyntaxError("'}' expected."); + } + } else { + if (token != TokenNameSEMICOLON) { + expr(); + } + if (token == TokenNameSEMICOLON) { + getNextToken(); + return statement; + } else { + if (token == TokenNameRBRACE) { + reportSyntaxError("';' expected after expression (Found token: " + + scanner.toStringAction(token) + ")"); + } else { + if (token != TokenNameINLINE_HTML && token != TokenNameEOF) { + throwSyntaxError("';' expected after expression (Found token: " + + scanner.toStringAction(token) + ")"); + } + getNextToken(); + } + } + } + // may be null + return statement; + } + + private void declare_statement() { + // statement + // | ':' inner_statement_list T_ENDDECLARE ';' + // ; + if (token == TokenNameCOLON) { + getNextToken(); + // TODO: implement inner_statement_list(); + statementList(); + if (token != TokenNameenddeclare) { + throwSyntaxError("'enddeclare' expected in 'declare' statement."); + } + getNextToken(); + if (token != TokenNameSEMICOLON) { + throwSyntaxError("';' expected after 'enddeclare' keyword."); + } + getNextToken(); + } else { + statement(); + } + } + + private void declare_list() { + // T_STRING '=' static_scalar + // | declare_list ',' T_STRING '=' static_scalar + while (true) { + if (token != TokenNameIdentifier) { + throwSyntaxError("Identifier expected in 'declare' list."); + } + getNextToken(); + if (token != TokenNameEQUAL) { + throwSyntaxError("'=' expected in 'declare' list."); + } + getNextToken(); + static_scalar(); + if (token != TokenNameCOMMA) { + break; + } + getNextToken(); + } + } + + private void additional_catches() { + while (token == TokenNamecatch) { + getNextToken(); + if (token != TokenNameLPAREN) { + throwSyntaxError("'(' expected in 'catch' statement."); + } + getNextToken(); + fully_qualified_class_name(); + if (token != TokenNameVariable) { + throwSyntaxError("Variable expected in 'catch' statement."); + } + addVariableSet(); + getNextToken(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected in 'catch' statement."); + } + getNextToken(); + if (token != TokenNameLBRACE) { + throwSyntaxError("'{' expected in 'catch' statement."); + } + getNextToken(); + if (token != TokenNameRBRACE) { + statementList(); + } + if (token != TokenNameRBRACE) { + throwSyntaxError("'}' expected in 'catch' statement."); + } + getNextToken(); + } + } + + private void foreach_variable() { + // w_variable + // | '&' w_variable + if (token == TokenNameAND) { + getNextToken(); + } + w_variable(true); + } + + private void foreach_optional_arg() { + // /* empty */ + // | T_DOUBLE_ARROW foreach_variable + if (token == TokenNameEQUAL_GREATER) { + getNextToken(); + foreach_variable(); + } + } + + private void global_var_list() { + // global_var_list: + // global_var_list ',' global_var + // | global_var + HashSet set = peekVariableSet(); + while (true) { + global_var(set); + if (token != TokenNameCOMMA) { + break; + } + getNextToken(); + } + } + + private void global_var(HashSet set) { + // global_var: + // T_VARIABLE + // | '$' r_variable + // | '$' '{' expr '}' + if (token == TokenNameVariable) { + if (fMethodVariables != null) { + VariableInfo info = new VariableInfo(scanner + .getCurrentTokenStartPosition(), + VariableInfo.LEVEL_GLOBAL_VAR); + fMethodVariables.put(new String(scanner + .getCurrentIdentifierSource()), info); + } + addVariableSet(set); + getNextToken(); + } else if (token == TokenNameDOLLAR) { + getNextToken(); + if (token == TokenNameLBRACE) { + getNextToken(); + expr(); + if (token != TokenNameRBRACE) { + throwSyntaxError("'}' expected in global variable."); + } + getNextToken(); + } else { + r_variable(); + } + } + } + + private void static_var_list() { + // static_var_list: + // static_var_list ',' T_VARIABLE + // | static_var_list ',' T_VARIABLE '=' static_scalar + // | T_VARIABLE + // | T_VARIABLE '=' static_scalar, + HashSet set = peekVariableSet(); + while (true) { + if (token == TokenNameVariable) { + if (fMethodVariables != null) { + VariableInfo info = new VariableInfo(scanner + .getCurrentTokenStartPosition(), + VariableInfo.LEVEL_STATIC_VAR); + fMethodVariables.put(new String(scanner + .getCurrentIdentifierSource()), info); + } + addVariableSet(set); + getNextToken(); + if (token == TokenNameEQUAL) { + getNextToken(); + static_scalar(); + } + if (token != TokenNameCOMMA) { + break; + } + getNextToken(); + } else { + break; + } + } + } + + private void unset_variables() { + // unset_variables: + // unset_variable + // | unset_variables ',' unset_variable + // unset_variable: + // variable + while (true) { + variable(false, false); + if (token != TokenNameCOMMA) { + break; + } + getNextToken(); + } + } + + private final void initializeModifiers() { + this.modifiers = 0; + this.modifiersSourceStart = -1; + } + + private final void checkAndSetModifiers(int flag) { + this.modifiers |= flag; + if (this.modifiersSourceStart < 0) + this.modifiersSourceStart = this.scanner.startPosition; + } + + private void unticked_class_declaration_statement(TypeDeclaration typeDecl) { + initializeModifiers(); + if (token == TokenNameinterface) { + // interface_entry T_STRING + // interface_extends_list + // '{' class_statement_list '}' + checkAndSetModifiers(AccInterface); + getNextToken(); + typeDecl.modifiers = this.modifiers; + typeDecl.sourceStart = scanner.getCurrentTokenStartPosition(); + typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition(); + if (token == TokenNameIdentifier || token > TokenNameKEYWORD) { + typeDecl.name = scanner.getCurrentIdentifierSource(); + if (token > TokenNameKEYWORD) { + problemReporter.phpKeywordWarning(new String[] { scanner + .toStringAction(token) }, scanner + .getCurrentTokenStartPosition(), scanner + .getCurrentTokenEndPosition(), referenceContext, + compilationUnit.compilationResult); + // throwSyntaxError("Don't use a keyword for interface + // declaration [" + // + scanner.toStringAction(token) + "].", + // typeDecl.sourceStart, typeDecl.sourceEnd); + } + getNextToken(); + interface_extends_list(typeDecl); + } else { + typeDecl.name = new char[] { ' ' }; + throwSyntaxError( + "Interface name expected after keyword 'interface'.", + typeDecl.sourceStart, typeDecl.sourceEnd); + return; + } + } else { + // class_entry_type T_STRING extends_from + // implements_list + // '{' class_statement_list'}' + class_entry_type(); + typeDecl.modifiers = this.modifiers; + typeDecl.sourceStart = scanner.getCurrentTokenStartPosition(); + typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition(); + // identifier + // identifier 'extends' identifier + if (token == TokenNameIdentifier || token > TokenNameKEYWORD) { + typeDecl.name = scanner.getCurrentIdentifierSource(); + if (token > TokenNameKEYWORD) { + problemReporter.phpKeywordWarning(new String[] { scanner + .toStringAction(token) }, scanner + .getCurrentTokenStartPosition(), scanner + .getCurrentTokenEndPosition(), referenceContext, + compilationUnit.compilationResult); + // throwSyntaxError("Don't use a keyword for class + // declaration [" + + // scanner.toStringAction(token) + "].", + // typeDecl.sourceStart, typeDecl.sourceEnd); + } + getNextToken(); + // extends_from: + // /* empty */ + // | T_EXTENDS fully_qualified_class_name + if (token == TokenNameextends) { + class_extends_list(typeDecl); + // getNextToken(); + // if (token != TokenNameIdentifier) { + // throwSyntaxError("Class name expected after keyword + // 'extends'.", + // scanner.getCurrentTokenStartPosition(), scanner + // .getCurrentTokenEndPosition()); + // } + } + implements_list(typeDecl); + } else { + typeDecl.name = new char[] { ' ' }; + throwSyntaxError("Class name expected after keyword 'class'.", + typeDecl.sourceStart, typeDecl.sourceEnd); + return; + } + } + // '{' class_statement_list '}' + if (token == TokenNameLBRACE) { + getNextToken(); + if (token != TokenNameRBRACE) { + ArrayList list = new ArrayList(); + class_statement_list(list); + typeDecl.fields = new FieldDeclaration[list.size()]; + for (int i = 0; i < list.size(); i++) { + typeDecl.fields[i] = (FieldDeclaration) list.get(i); + } + } + if (token == TokenNameRBRACE) { + typeDecl.declarationSourceEnd = scanner + .getCurrentTokenEndPosition(); + getNextToken(); + } else { + throwSyntaxError("'}' expected at end of class body."); + } + } else { + throwSyntaxError("'{' expected at start of class body."); + } + } + + private void class_entry_type() { + // T_CLASS + // | T_ABSTRACT T_CLASS + // | T_FINAL T_CLASS + if (token == TokenNameclass) { + getNextToken(); + } else if (token == TokenNameabstract) { + checkAndSetModifiers(AccAbstract); + getNextToken(); + if (token != TokenNameclass) { + throwSyntaxError("Keyword 'class' expected after keyword 'abstract'."); + } + getNextToken(); + } else if (token == TokenNamefinal) { + checkAndSetModifiers(AccFinal); + getNextToken(); + if (token != TokenNameclass) { + throwSyntaxError("Keyword 'class' expected after keyword 'final'."); + } + getNextToken(); + } else { + throwSyntaxError("Keyword 'class' 'final' or 'abstract' expected"); + } + } + + // private void class_extends(TypeDeclaration typeDecl) { + // // /* empty */ + // // | T_EXTENDS interface_list + // if (token == TokenNameextends) { + // getNextToken(); + // + // if (token == TokenNameIdentifier) { + // getNextToken(); + // } else { + // throwSyntaxError("Class name expected after keyword 'extends'."); + // } + // } + // } + + private void interface_extends_list(TypeDeclaration typeDecl) { + // /* empty */ + // | T_EXTENDS interface_list + if (token == TokenNameextends) { + getNextToken(); + interface_list(typeDecl); + } + } + + private void class_extends_list(TypeDeclaration typeDecl) { + // /* empty */ + // | T_EXTENDS interface_list + if (token == TokenNameextends) { + getNextToken(); + class_list(typeDecl); + } + } + + private void implements_list(TypeDeclaration typeDecl) { + // /* empty */ + // | T_IMPLEMENTS interface_list + if (token == TokenNameimplements) { + getNextToken(); + interface_list(typeDecl); + } + } + + private void class_list(TypeDeclaration typeDecl) { + // class_list: + // fully_qualified_class_name + do { + if (token == TokenNameIdentifier) { + char[] ident = scanner.getCurrentIdentifierSource(); + // TODO make this code working better: + // SingleTypeReference ref = + // ParserUtil.getTypeReference(scanner, + // includesList, ident); + // if (ref != null) { + // typeDecl.superclass = ref; + // } + getNextToken(); + } else { + throwSyntaxError("Classname expected after keyword 'extends'."); + } + if (token == TokenNameCOMMA) { + reportSyntaxError("No multiple inheritance allowed. Expected token 'implements' or '{'."); + getNextToken(); + continue; + } else { + break; + } + } while (true); + } + + private void interface_list(TypeDeclaration typeDecl) { + // interface_list: + // fully_qualified_class_name + // | interface_list ',' fully_qualified_class_name + do { + if (token == TokenNameIdentifier) { + getNextToken(); + } else { + throwSyntaxError("Interfacename expected after keyword 'implements'."); + } + if (token != TokenNameCOMMA) { + return; + } + getNextToken(); + } while (true); + } + + // private void classBody(TypeDeclaration typeDecl) { + // //'{' [class-element-list] '}' + // if (token == TokenNameLBRACE) { + // getNextToken(); + // if (token != TokenNameRBRACE) { + // class_statement_list(); + // } + // if (token == TokenNameRBRACE) { + // typeDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition(); + // getNextToken(); + // } else { + // throwSyntaxError("'}' expected at end of class body."); + // } + // } else { + // throwSyntaxError("'{' expected at start of class body."); + // } + // } + private void class_statement_list(ArrayList list) { + do { + try { + class_statement(list); + if (token == TokenNamepublic || token == TokenNameprotected + || token == TokenNameprivate + || token == TokenNamestatic + || token == TokenNameabstract + || token == TokenNamefinal + || token == TokenNamefunction || token == TokenNamevar + || token == TokenNameconst) { + continue; + } + if (token == TokenNameRBRACE) { + break; + } + throwSyntaxError("'}' at end of class statement."); + } catch (SyntaxError sytaxErr1) { + boolean tokenize = scanner.tokenizeStrings; + if (!tokenize) { + scanner.tokenizeStrings = true; + } + try { + // if an error occured, + // try to find keywords + // to parse the rest of the string + while (token != TokenNameEOF) { + if (token == TokenNamepublic + || token == TokenNameprotected + || token == TokenNameprivate + || token == TokenNamestatic + || token == TokenNameabstract + || token == TokenNamefinal + || token == TokenNamefunction + || token == TokenNamevar + || token == TokenNameconst) { + break; + } + // System.out.println(scanner.toStringAction(token)); + getNextToken(); + } + if (token == TokenNameEOF) { + throw sytaxErr1; + } + } finally { + scanner.tokenizeStrings = tokenize; + } + } + } while (true); + } + + private void class_statement(ArrayList list) { + // class_statement: + // variable_modifiers class_variable_declaration ';' + // | class_constant_declaration ';' + // | method_modifiers T_FUNCTION is_reference T_STRING + // '(' parameter_list ')' method_body + initializeModifiers(); + int declarationSourceStart = scanner.getCurrentTokenStartPosition(); + + if (token == TokenNamevar) { + checkAndSetModifiers(AccPublic); + problemReporter.phpVarDeprecatedWarning(scanner + .getCurrentTokenStartPosition(), scanner + .getCurrentTokenEndPosition(), referenceContext, + compilationUnit.compilationResult); + getNextToken(); + class_variable_declaration(declarationSourceStart, list); + } else if (token == TokenNameconst) { + checkAndSetModifiers(AccFinal | AccPublic); + class_constant_declaration(declarationSourceStart, list); + if (token != TokenNameSEMICOLON) { + throwSyntaxError("';' expected after class const declaration."); + } + getNextToken(); + } else { + boolean hasModifiers = member_modifiers(); + if (token == TokenNamefunction) { + if (!hasModifiers) { + checkAndSetModifiers(AccPublic); + } + MethodDeclaration methodDecl = new MethodDeclaration( + this.compilationUnit.compilationResult); + methodDecl.declarationSourceStart = scanner + .getCurrentTokenStartPosition(); + methodDecl.modifiers = this.modifiers; + methodDecl.type = MethodDeclaration.METHOD_DEFINITION; + try { + getNextToken(); + functionDefinition(methodDecl); + } finally { + int sourceEnd = methodDecl.sourceEnd; + if (sourceEnd <= 0 + || methodDecl.declarationSourceStart > sourceEnd) { + sourceEnd = methodDecl.declarationSourceStart + 1; + } + methodDecl.declarationSourceEnd = sourceEnd; + methodDecl.sourceEnd = sourceEnd; + } + } else { + if (!hasModifiers) { + throwSyntaxError("'public' 'private' or 'protected' modifier expected for field declarations."); + } + class_variable_declaration(declarationSourceStart, list); + } + } + } + + private void class_constant_declaration(int declarationSourceStart, + ArrayList list) { + // class_constant_declaration ',' T_STRING '=' static_scalar + // | T_CONST T_STRING '=' static_scalar + if (token != TokenNameconst) { + throwSyntaxError("'const' keyword expected in class declaration."); + } else { + getNextToken(); + } + while (true) { + if (token != TokenNameIdentifier) { + throwSyntaxError("Identifier expected in class const declaration."); + } + FieldDeclaration fieldDeclaration = new FieldDeclaration(scanner + .getCurrentIdentifierSource(), scanner + .getCurrentTokenStartPosition(), scanner + .getCurrentTokenEndPosition()); + fieldDeclaration.modifiers = this.modifiers; + fieldDeclaration.declarationSourceStart = declarationSourceStart; + fieldDeclaration.declarationSourceEnd = scanner + .getCurrentTokenEndPosition(); + fieldDeclaration.modifiersSourceStart = declarationSourceStart; + // fieldDeclaration.type + list.add(fieldDeclaration); + getNextToken(); + if (token != TokenNameEQUAL) { + throwSyntaxError("'=' expected in class const declaration."); + } + getNextToken(); + static_scalar(); + if (token != TokenNameCOMMA) { + break; // while(true)-loop + } + getNextToken(); + } + } + + // private void variable_modifiers() { + // // variable_modifiers: + // // non_empty_member_modifiers + // //| T_VAR + // initializeModifiers(); + // if (token == TokenNamevar) { + // checkAndSetModifiers(AccPublic); + // reportSyntaxError( + // "Keyword 'var' is deprecated. Please use 'public' 'private' or + // 'protected' + // modifier for field declarations.", + // scanner.getCurrentTokenStartPosition(), scanner + // .getCurrentTokenEndPosition()); + // getNextToken(); + // } else { + // if (!member_modifiers()) { + // throwSyntaxError("'public' 'private' or 'protected' modifier expected for + // field declarations."); + // } + // } + // } + // private void method_modifiers() { + // //method_modifiers: + // // /* empty */ + // //| non_empty_member_modifiers + // initializeModifiers(); + // if (!member_modifiers()) { + // checkAndSetModifiers(AccPublic); + // } + // } + private boolean member_modifiers() { + // T_PUBLIC + // | T_PROTECTED + // | T_PRIVATE + // | T_STATIC + // | T_ABSTRACT + // | T_FINAL + boolean foundToken = false; + while (true) { + if (token == TokenNamepublic) { + checkAndSetModifiers(AccPublic); + getNextToken(); + foundToken = true; + } else if (token == TokenNameprotected) { + checkAndSetModifiers(AccProtected); + getNextToken(); + foundToken = true; + } else if (token == TokenNameprivate) { + checkAndSetModifiers(AccPrivate); + getNextToken(); + foundToken = true; + } else if (token == TokenNamestatic) { + checkAndSetModifiers(AccStatic); + getNextToken(); + foundToken = true; + } else if (token == TokenNameabstract) { + checkAndSetModifiers(AccAbstract); + getNextToken(); + foundToken = true; + } else if (token == TokenNamefinal) { + checkAndSetModifiers(AccFinal); + getNextToken(); + foundToken = true; + } else { + break; + } + } + return foundToken; + } + + private void class_variable_declaration(int declarationSourceStart, + ArrayList list) { + // class_variable_declaration: + // class_variable_declaration ',' T_VARIABLE + // | class_variable_declaration ',' T_VARIABLE '=' static_scalar + // | T_VARIABLE + // | T_VARIABLE '=' static_scalar + char[] classVariable; + do { + if (token == TokenNameVariable) { + classVariable = scanner.getCurrentIdentifierSource(); + // indexManager.addIdentifierInformation('v', classVariable, + // buf, -1, + // -1); + FieldDeclaration fieldDeclaration = new FieldDeclaration( + classVariable, scanner.getCurrentTokenStartPosition(), + scanner.getCurrentTokenEndPosition()); + fieldDeclaration.modifiers = this.modifiers; + fieldDeclaration.declarationSourceStart = declarationSourceStart; + fieldDeclaration.declarationSourceEnd = scanner + .getCurrentTokenEndPosition(); + fieldDeclaration.modifiersSourceStart = declarationSourceStart; + list.add(fieldDeclaration); + if (fTypeVariables != null) { + VariableInfo info = new VariableInfo(scanner + .getCurrentTokenStartPosition(), + VariableInfo.LEVEL_CLASS_UNIT); + fTypeVariables.put(new String(scanner + .getCurrentIdentifierSource()), info); + } + getNextToken(); + if (token == TokenNameEQUAL) { + getNextToken(); + static_scalar(); + } + } else { + // if (token == TokenNamethis) { + // throwSyntaxError("'$this' not allowed after keyword 'public' + // 'protected' 'private' 'var'."); + // } + throwSyntaxError("Variable expected after keyword 'public' 'protected' 'private' 'var'."); + } + if (token != TokenNameCOMMA) { + break; + } + getNextToken(); + } while (true); + if (token != TokenNameSEMICOLON) { + throwSyntaxError("';' expected after field declaration."); + } + getNextToken(); + } + + private void functionDefinition(MethodDeclaration methodDecl) { + boolean isAbstract = false; + if (astPtr == 0) { + if (compilationUnit != null) { + compilationUnit.types.add(methodDecl); + } + } else { + ASTNode node = astStack[astPtr]; + if (node instanceof TypeDeclaration) { + TypeDeclaration typeDecl = ((TypeDeclaration) node); + if (typeDecl.methods == null) { + typeDecl.methods = new AbstractMethodDeclaration[] { methodDecl }; + } else { + AbstractMethodDeclaration[] newMethods; + System + .arraycopy( + typeDecl.methods, + 0, + newMethods = new AbstractMethodDeclaration[typeDecl.methods.length + 1], + 0, typeDecl.methods.length); + newMethods[typeDecl.methods.length] = methodDecl; + typeDecl.methods = newMethods; + } + if ((typeDecl.modifiers & AccAbstract) == AccAbstract) { + isAbstract = true; + } else if ((typeDecl.modifiers & AccInterface) == AccInterface) { + isAbstract = true; + } + } + } + try { + pushFunctionVariableSet(); + functionDeclarator(methodDecl); + if (token == TokenNameSEMICOLON) { + if (!isAbstract) { + methodDecl.sourceEnd = scanner + .getCurrentTokenStartPosition() - 1; + throwSyntaxError("Body declaration expected for method: " + + new String(methodDecl.selector)); + } + getNextToken(); + return; + } + functionBody(methodDecl); + } finally { + if (!fStackUnassigned.isEmpty()) { + fStackUnassigned.remove(fStackUnassigned.size() - 1); + } + } + } + + private void functionDeclarator(MethodDeclaration methodDecl) { + // identifier '(' [parameter-list] ')' + if (token == TokenNameAND) { + getNextToken(); + } + methodDecl.sourceStart = scanner.getCurrentTokenStartPosition(); + methodDecl.sourceEnd = scanner.getCurrentTokenEndPosition(); + if (Scanner.isIdentifierOrKeyword(token)) { + methodDecl.selector = scanner.getCurrentIdentifierSource(); + if (token > TokenNameKEYWORD) { + problemReporter.phpKeywordWarning(new String[] { scanner + .toStringAction(token) }, scanner + .getCurrentTokenStartPosition(), scanner + .getCurrentTokenEndPosition(), referenceContext, + compilationUnit.compilationResult); + } + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + } else { + methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1; + throwSyntaxError("'(' expected in function declaration."); + } + if (token != TokenNameRPAREN) { + parameter_list(methodDecl); + } + if (token != TokenNameRPAREN) { + methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1; + throwSyntaxError("')' expected in function declaration."); + } else { + methodDecl.bodyStart = scanner.getCurrentTokenEndPosition() + 1; + getNextToken(); + } + } else { + methodDecl.selector = "".toCharArray(); + methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1; + throwSyntaxError("Function name expected after keyword 'function'."); + } + } + + // + private void parameter_list(MethodDeclaration methodDecl) { + // non_empty_parameter_list + // | /* empty */ + non_empty_parameter_list(methodDecl, true); + } + + private void non_empty_parameter_list(MethodDeclaration methodDecl, + boolean empty_allowed) { + // optional_class_type T_VARIABLE + // | optional_class_type '&' T_VARIABLE + // | optional_class_type '&' T_VARIABLE '=' static_scalar + // | optional_class_type T_VARIABLE '=' static_scalar + // | non_empty_parameter_list ',' optional_class_type T_VARIABLE + // | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE + // | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '=' + // static_scalar + // | non_empty_parameter_list ',' optional_class_type T_VARIABLE '=' + // static_scalar + char[] typeIdentifier = null; + if (token == TokenNameIdentifier || token == TokenNamearray + || token == TokenNameVariable || token == TokenNameAND) { + HashSet set = peekVariableSet(); + while (true) { + if (token == TokenNameIdentifier || token == TokenNamearray) {// feature + // req. + // #1254275 + typeIdentifier = scanner.getCurrentIdentifierSource(); + getNextToken(); + } + if (token == TokenNameAND) { + getNextToken(); + } + if (token == TokenNameVariable) { + if (fMethodVariables != null) { + VariableInfo info; + if (methodDecl.type == MethodDeclaration.FUNCTION_DEFINITION) { + info = new VariableInfo(scanner + .getCurrentTokenStartPosition(), + VariableInfo.LEVEL_FUNCTION_DEFINITION); + } else { + info = new VariableInfo(scanner + .getCurrentTokenStartPosition(), + VariableInfo.LEVEL_METHOD_DEFINITION); + } + info.typeIdentifier = typeIdentifier; + fMethodVariables.put(new String(scanner + .getCurrentIdentifierSource()), info); + } + addVariableSet(set); + getNextToken(); + if (token == TokenNameEQUAL) { + getNextToken(); + static_scalar(); + } + } else { + throwSyntaxError("Variable expected in parameter list."); + } + if (token != TokenNameCOMMA) { + break; + } + getNextToken(); + } + return; + } + if (!empty_allowed) { + throwSyntaxError("Identifier expected in parameter list."); + } + } + + private void optional_class_type() { + // /* empty */ + // | T_STRING + } + + // private void parameterDeclaration() { + // //variable + // //variable-reference + // if (token == TokenNameAND) { + // getNextToken(); + // if (isVariable()) { + // getNextToken(); + // } else { + // throwSyntaxError("Variable expected after reference operator '&'."); + // } + // } + // //variable '=' constant + // if (token == TokenNameVariable) { + // getNextToken(); + // if (token == TokenNameEQUAL) { + // getNextToken(); + // static_scalar(); + // } + // return; + // } + // // if (token == TokenNamethis) { + // // throwSyntaxError("Reserved word '$this' not allowed in parameter + // // declaration."); + // // } + // } + + private void labeledStatementList() { + if (token != TokenNamecase && token != TokenNamedefault) { + throwSyntaxError("'case' or 'default' expected."); + } + do { + if (token == TokenNamecase) { + getNextToken(); + expr(); // constant(); + if (token == TokenNameCOLON || token == TokenNameSEMICOLON) { + getNextToken(); + if (token == TokenNameRBRACE) { + // empty case; assumes that the '}' token belongs to the + // wrapping + // switch statement - #1371992 + break; + } + if (token == TokenNamecase || token == TokenNamedefault) { + // empty case statement ? + continue; + } + statementList(); + } + // else if (token == TokenNameSEMICOLON) { + // setMarker( + // "':' expected after 'case' keyword (Found token: " + + // scanner.toStringAction(token) + ")", + // scanner.getCurrentTokenStartPosition(), + // scanner.getCurrentTokenEndPosition(), + // INFO); + // getNextToken(); + // if (token == TokenNamecase) { // empty case statement ? + // continue; + // } + // statementList(); + // } + else { + throwSyntaxError("':' character expected after 'case' constant (Found token: " + + scanner.toStringAction(token) + ")"); + } + } else { // TokenNamedefault + getNextToken(); + if (token == TokenNameCOLON || token == TokenNameSEMICOLON) { + getNextToken(); + if (token == TokenNameRBRACE) { + // empty default case; ; assumes that the '}' token + // belongs to the + // wrapping switch statement - #1371992 + break; + } + if (token != TokenNamecase) { + statementList(); + } + } else { + throwSyntaxError("':' character expected after 'default'."); + } + } + } while (token == TokenNamecase || token == TokenNamedefault); + } + + private void ifStatementColon(IfStatement iState) { + // T_IF '(' expr ')' ':' inner_statement_list new_elseif_list + // new_else_single T_ENDIF ';' + HashSet assignedVariableSet = null; + try { + Block b = inner_statement_list(); + iState.thenStatement = b; + checkUnreachable(iState, b); + } finally { + assignedVariableSet = removeIfVariableSet(); + } + if (token == TokenNameelseif) { + try { + pushIfVariableSet(); + new_elseif_list(iState); + } finally { + HashSet set = removeIfVariableSet(); + if (assignedVariableSet != null && set != null) { + assignedVariableSet.addAll(set); + } + } + } + try { + pushIfVariableSet(); + new_else_single(iState); + } finally { + HashSet set = removeIfVariableSet(); + if (assignedVariableSet != null) { + HashSet topSet = peekVariableSet(); + if (topSet != null) { + if (set != null) { + topSet.addAll(set); + } + topSet.addAll(assignedVariableSet); + } + } + } + if (token != TokenNameendif) { + throwSyntaxError("'endif' expected."); + } + getNextToken(); + if (token != TokenNameSEMICOLON) { + reportSyntaxError("';' expected after if-statement."); + iState.sourceEnd = scanner.getCurrentTokenStartPosition(); + } else { + iState.sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } + } + + private void ifStatement(IfStatement iState) { + // T_IF '(' expr ')' statement elseif_list else_single + HashSet assignedVariableSet = null; + try { + pushIfVariableSet(); + Statement s = statement(); + iState.thenStatement = s; + checkUnreachable(iState, s); + } finally { + assignedVariableSet = removeIfVariableSet(); + } + + if (token == TokenNameelseif) { + try { + pushIfVariableSet(); + elseif_list(iState); + } finally { + HashSet set = removeIfVariableSet(); + if (assignedVariableSet != null && set != null) { + assignedVariableSet.addAll(set); + } + } + } + try { + pushIfVariableSet(); + else_single(iState); + } finally { + HashSet set = removeIfVariableSet(); + if (assignedVariableSet != null) { + HashSet topSet = peekVariableSet(); + if (topSet != null) { + if (set != null) { + topSet.addAll(set); + } + topSet.addAll(assignedVariableSet); + } + } + } + } + + private void elseif_list(IfStatement iState) { + // /* empty */ + // | elseif_list T_ELSEIF '(' expr ')' statement + ArrayList conditionList = new ArrayList(); + ArrayList statementList = new ArrayList(); + Expression e; + Statement s; + while (token == TokenNameelseif) { + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'elseif' keyword."); + } + e = expr(); + conditionList.add(e); + if (token == TokenNameRPAREN) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'elseif' condition."); + } + s = statement(); + statementList.add(s); + checkUnreachable(iState, s); + } + iState.elseifConditions = new Expression[conditionList.size()]; + iState.elseifStatements = new Statement[statementList.size()]; + conditionList.toArray(iState.elseifConditions); + statementList.toArray(iState.elseifStatements); + } + + private void new_elseif_list(IfStatement iState) { + // /* empty */ + // | new_elseif_list T_ELSEIF '(' expr ')' ':' inner_statement_list + ArrayList conditionList = new ArrayList(); + ArrayList statementList = new ArrayList(); + Expression e; + Block b; + while (token == TokenNameelseif) { + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'elseif' keyword."); + } + e = expr(); + conditionList.add(e); + if (token == TokenNameRPAREN) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'elseif' condition."); + } + if (token == TokenNameCOLON) { + getNextToken(); + } else { + throwSyntaxError("':' expected after 'elseif' keyword."); + } + b = inner_statement_list(); + statementList.add(b); + checkUnreachable(iState, b); + } + iState.elseifConditions = new Expression[conditionList.size()]; + iState.elseifStatements = new Statement[statementList.size()]; + conditionList.toArray(iState.elseifConditions); + statementList.toArray(iState.elseifStatements); + } + + private void else_single(IfStatement iState) { + // /* empty */ + // T_ELSE statement + if (token == TokenNameelse) { + getNextToken(); + Statement s = statement(); + iState.elseStatement = s; + checkUnreachable(iState, s); + } else { + iState.checkUnreachable = false; + } + iState.sourceEnd = scanner.getCurrentTokenStartPosition(); + } + + private void new_else_single(IfStatement iState) { + // /* empty */ + // | T_ELSE ':' inner_statement_list + if (token == TokenNameelse) { + getNextToken(); + if (token == TokenNameCOLON) { + getNextToken(); + } else { + throwSyntaxError("':' expected after 'else' keyword."); + } + Block b = inner_statement_list(); + iState.elseStatement = b; + checkUnreachable(iState, b); + } else { + iState.checkUnreachable = false; + } + } + + private Block inner_statement_list() { + // inner_statement_list inner_statement + // /* empty */ + return statementList(); + } + + /** + * @param iState + * @param b + */ + private void checkUnreachable(IfStatement iState, Statement s) { + if (s instanceof Block) { + Block b = (Block) s; + if (b.statements == null || b.statements.length == 0) { + iState.checkUnreachable = false; + } else { + int off = b.statements.length - 1; + if (!(b.statements[off] instanceof ReturnStatement) + && !(b.statements[off] instanceof ContinueStatement) + && !(b.statements[off] instanceof BreakStatement)) { + if (!(b.statements[off] instanceof IfStatement) + || !((IfStatement) b.statements[off]).checkUnreachable) { + iState.checkUnreachable = false; + } + } + } + } else { + if (!(s instanceof ReturnStatement) + && !(s instanceof ContinueStatement) + && !(s instanceof BreakStatement)) { + if (!(s instanceof IfStatement) + || !((IfStatement) s).checkUnreachable) { + iState.checkUnreachable = false; + } + } + } + } + + // private void elseifStatementList() { + // do { + // elseifStatement(); + // switch (token) { + // case TokenNameelse: + // getNextToken(); + // if (token == TokenNameCOLON) { + // getNextToken(); + // if (token != TokenNameendif) { + // statementList(); + // } + // return; + // } else { + // if (token == TokenNameif) { //'else if' + // getNextToken(); + // } else { + // throwSyntaxError("':' expected after 'else'."); + // } + // } + // break; + // case TokenNameelseif: + // getNextToken(); + // break; + // default: + // return; + // } + // } while (true); + // } + + // private void elseifStatement() { + // if (token == TokenNameLPAREN) { + // getNextToken(); + // expr(); + // if (token != TokenNameRPAREN) { + // throwSyntaxError("')' expected in else-if-statement."); + // } + // getNextToken(); + // if (token != TokenNameCOLON) { + // throwSyntaxError("':' expected in else-if-statement."); + // } + // getNextToken(); + // if (token != TokenNameendif) { + // statementList(); + // } + // } + // } + + private void switchStatement() { + if (token == TokenNameCOLON) { + // ':' [labeled-statement-list] 'endswitch' ';' + getNextToken(); + labeledStatementList(); + if (token != TokenNameendswitch) { + throwSyntaxError("'endswitch' expected."); + } + getNextToken(); + if (token != TokenNameSEMICOLON) { + throwSyntaxError("';' expected after switch-statement."); + } + getNextToken(); + } else { + // '{' [labeled-statement-list] '}' + if (token != TokenNameLBRACE) { + throwSyntaxError("'{' expected in switch statement."); + } + getNextToken(); + if (token != TokenNameRBRACE) { + labeledStatementList(); + } + if (token != TokenNameRBRACE) { + throwSyntaxError("'}' expected in switch statement."); + } + getNextToken(); + } + } + + private void forStatement() { + if (token == TokenNameCOLON) { + getNextToken(); + statementList(); + if (token != TokenNameendfor) { + throwSyntaxError("'endfor' expected."); + } + getNextToken(); + if (token != TokenNameSEMICOLON) { + throwSyntaxError("';' expected after for-statement."); + } + getNextToken(); + } else { + statement(); + } + } + + private void whileStatement() { + // ':' statement-list 'endwhile' ';' + if (token == TokenNameCOLON) { + getNextToken(); + statementList(); + if (token != TokenNameendwhile) { + throwSyntaxError("'endwhile' expected."); + } + getNextToken(); + if (token != TokenNameSEMICOLON) { + throwSyntaxError("';' expected after while-statement."); + } + getNextToken(); + } else { + statement(); + } + } + + private void foreachStatement() { + if (token == TokenNameCOLON) { + getNextToken(); + statementList(); + if (token != TokenNameendforeach) { + throwSyntaxError("'endforeach' expected."); + } + getNextToken(); + if (token != TokenNameSEMICOLON) { + throwSyntaxError("';' expected after foreach-statement."); + } + getNextToken(); + } else { + statement(); + } + } + + // private void exitStatus() { + // if (token == TokenNameLPAREN) { + // getNextToken(); + // } else { + // throwSyntaxError("'(' expected in 'exit-status'."); + // } + // if (token != TokenNameRPAREN) { + // expression(); + // } + // if (token == TokenNameRPAREN) { + // getNextToken(); + // } else { + // throwSyntaxError("')' expected after 'exit-status'."); + // } + // } + private void expressionList() { + do { + expr(); + if (token == TokenNameCOMMA) { + getNextToken(); + } else { + break; + } + } while (true); + } + + private Expression expr() { + // r_variable + // | expr_without_variable + // if (token!=TokenNameEOF) { + if (Scanner.TRACE) { + System.out.println("TRACE: expr()"); + } + return expr_without_variable(true, null); + // } + } + + private Expression expr_without_variable(boolean only_variable, + UninitializedVariableHandler initHandler) { + int exprSourceStart = scanner.getCurrentTokenStartPosition(); + int exprSourceEnd = scanner.getCurrentTokenEndPosition(); + Expression expression = new Expression(); + expression.sourceStart = exprSourceStart; + // default, may be overwritten + expression.sourceEnd = exprSourceEnd; + try { + // internal_functions_in_yacc + // | T_CLONE expr + // | T_PRINT expr + // | '(' expr ')' + // | '@' expr + // | '+' expr + // | '-' expr + // | '!' expr + // | '~' expr + // | T_INC rw_variable + // | T_DEC rw_variable + // | T_INT_CAST expr + // | T_DOUBLE_CAST expr + // | T_STRING_CAST expr + // | T_ARRAY_CAST expr + // | T_OBJECT_CAST expr + // | T_BOOL_CAST expr + // | T_UNSET_CAST expr + // | T_EXIT exit_expr + // | scalar + // | T_ARRAY '(' array_pair_list ')' + // | '`' encaps_list '`' + // | T_LIST '(' assignment_list ')' '=' expr + // | T_NEW class_name_reference ctor_arguments + // | variable '=' expr + // | variable '=' '&' variable + // | variable '=' '&' T_NEW class_name_reference ctor_arguments + // | variable T_PLUS_EQUAL expr + // | variable T_MINUS_EQUAL expr + // | variable T_MUL_EQUAL expr + // | variable T_DIV_EQUAL expr + // | variable T_CONCAT_EQUAL expr + // | variable T_MOD_EQUAL expr + // | variable T_AND_EQUAL expr + // | variable T_OR_EQUAL expr + // | variable T_XOR_EQUAL expr + // | variable T_SL_EQUAL expr + // | variable T_SR_EQUAL expr + // | rw_variable T_INC + // | rw_variable T_DEC + // | expr T_BOOLEAN_OR expr + // | expr T_BOOLEAN_AND expr + // | expr T_LOGICAL_OR expr + // | expr T_LOGICAL_AND expr + // | expr T_LOGICAL_XOR expr + // | expr '|' expr + // | expr '&' expr + // | expr '^' expr + // | expr '.' expr + // | expr '+' expr + // | expr '-' expr + // | expr '*' expr + // | expr '/' expr + // | expr '%' expr + // | expr T_SL expr + // | expr T_SR expr + // | expr T_IS_IDENTICAL expr + // | expr T_IS_NOT_IDENTICAL expr + // | expr T_IS_EQUAL expr + // | expr T_IS_NOT_EQUAL expr + // | expr '<' expr + // | expr T_IS_SMALLER_OR_EQUAL expr + // | expr '>' expr + // | expr T_IS_GREATER_OR_EQUAL expr + // | expr T_INSTANCEOF class_name_reference + // | expr '?' expr ':' expr + if (Scanner.TRACE) { + System.out.println("TRACE: expr_without_variable() PART 1"); + } + switch (token) { + case TokenNameisset: + // T_ISSET '(' isset_variables ')' + getNextToken(); + if (token != TokenNameLPAREN) { + throwSyntaxError("'(' expected after keyword 'isset'"); + } + getNextToken(); + isset_variables(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected after keyword 'isset'"); + } + getNextToken(); + break; + case TokenNameempty: + getNextToken(); + if (token != TokenNameLPAREN) { + throwSyntaxError("'(' expected after keyword 'empty'"); + } + getNextToken(); + variable(true, false); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected after keyword 'empty'"); + } + getNextToken(); + break; + case TokenNameeval: + case TokenNameinclude: + case TokenNameinclude_once: + case TokenNamerequire: + case TokenNamerequire_once: + internal_functions_in_yacc(); + break; + // | '(' expr ')' + case TokenNameLPAREN: + getNextToken(); + expr(); + if (token == TokenNameRPAREN) { + getNextToken(); + } else { + throwSyntaxError("')' expected in expression."); + } + break; + // | T_CLONE expr + // | T_PRINT expr + // | '@' expr + // | '+' expr + // | '-' expr + // | '!' expr + // | '~' expr + // | T_INT_CAST expr + // | T_DOUBLE_CAST expr + // | T_STRING_CAST expr + // | T_ARRAY_CAST expr + // | T_OBJECT_CAST expr + // | T_BOOL_CAST expr + // | T_UNSET_CAST expr + case TokenNameclone: + case TokenNameprint: + case TokenNameAT: + case TokenNamePLUS: + case TokenNameMINUS: + case TokenNameNOT: + case TokenNameTWIDDLE: + case TokenNameintCAST: + case TokenNamedoubleCAST: + case TokenNamestringCAST: + case TokenNamearrayCAST: + case TokenNameobjectCAST: + case TokenNameboolCAST: + case TokenNameunsetCAST: + getNextToken(); + expr(); + break; + case TokenNameexit: + getNextToken(); + exit_expr(); + break; + // scalar: + // T_STRING + // | T_STRING_VARNAME + // | class_constant + // | T_START_HEREDOC encaps_list T_END_HEREDOC + // | '`' encaps_list '`' + // | common_scalar + // | '`' encaps_list '`' + // case TokenNameEncapsedString0: + // scanner.encapsedStringStack.push(new Character('`')); + // getNextToken(); + // try { + // if (token == TokenNameEncapsedString0) { + // } else { + // encaps_list(); + // if (token != TokenNameEncapsedString0) { + // throwSyntaxError("\'`\' expected at end of string" + "(Found + // token: " + + // scanner.toStringAction(token) + " )"); + // } + // } + // } finally { + // scanner.encapsedStringStack.pop(); + // getNextToken(); + // } + // break; + // // | '\'' encaps_list '\'' + // case TokenNameEncapsedString1: + // scanner.encapsedStringStack.push(new Character('\'')); + // getNextToken(); + // try { + // exprSourceStart = scanner.getCurrentTokenStartPosition(); + // if (token == TokenNameEncapsedString1) { + // expression = new + // StringLiteralSQ(scanner.getCurrentStringLiteralSource(exprSourceStart), + // exprSourceStart, scanner + // .getCurrentTokenEndPosition()); + // } else { + // encaps_list(); + // if (token != TokenNameEncapsedString1) { + // throwSyntaxError("\'\'\' expected at end of string" + "(Found + // token: " + // + scanner.toStringAction(token) + " )"); + // } else { + // expression = new + // StringLiteralSQ(scanner.getCurrentStringLiteralSource(exprSourceStart), + // exprSourceStart, scanner + // .getCurrentTokenEndPosition()); + // } + // } + // } finally { + // scanner.encapsedStringStack.pop(); + // getNextToken(); + // } + // break; + // //| '"' encaps_list '"' + // case TokenNameEncapsedString2: + // scanner.encapsedStringStack.push(new Character('"')); + // getNextToken(); + // try { + // exprSourceStart = scanner.getCurrentTokenStartPosition(); + // if (token == TokenNameEncapsedString2) { + // expression = new + // StringLiteralDQ(scanner.getCurrentStringLiteralSource(exprSourceStart), + // exprSourceStart, scanner + // .getCurrentTokenEndPosition()); + // } else { + // encaps_list(); + // if (token != TokenNameEncapsedString2) { + // throwSyntaxError("'\"' expected at end of string" + "(Found + // token: " + + // scanner.toStringAction(token) + " )"); + // } else { + // expression = new + // StringLiteralDQ(scanner.getCurrentStringLiteralSource(exprSourceStart), + // exprSourceStart, scanner + // .getCurrentTokenEndPosition()); + // } + // } + // } finally { + // scanner.encapsedStringStack.pop(); + // getNextToken(); + // } + // break; + case TokenNameStringDoubleQuote: + expression = new StringLiteralDQ(scanner + .getCurrentStringLiteralSource(), scanner + .getCurrentTokenStartPosition(), scanner + .getCurrentTokenEndPosition()); + common_scalar(); + break; + case TokenNameStringSingleQuote: + expression = new StringLiteralSQ(scanner + .getCurrentStringLiteralSource(), scanner + .getCurrentTokenStartPosition(), scanner + .getCurrentTokenEndPosition()); + common_scalar(); + break; + case TokenNameIntegerLiteral: + case TokenNameDoubleLiteral: + case TokenNameStringInterpolated: + case TokenNameFILE: + case TokenNameLINE: + case TokenNameCLASS_C: + case TokenNameMETHOD_C: + case TokenNameFUNC_C: + common_scalar(); + break; + case TokenNameHEREDOC: + getNextToken(); + break; + case TokenNamearray: + // T_ARRAY '(' array_pair_list ')' + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + if (token == TokenNameRPAREN) { + getNextToken(); + break; + } + array_pair_list(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' or ',' expected after keyword 'array'" + + "(Found token: " + + scanner.toStringAction(token) + ")"); + } + getNextToken(); + } else { + throwSyntaxError("'(' expected after keyword 'array'" + + "(Found token: " + scanner.toStringAction(token) + + ")"); + } + break; + case TokenNamelist: + // | T_LIST '(' assignment_list ')' '=' expr + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + assignment_list(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected after 'list' keyword."); + } + getNextToken(); + if (token != TokenNameEQUAL) { + throwSyntaxError("'=' expected after 'list' keyword."); + } + getNextToken(); + expr(); + } else { + throwSyntaxError("'(' expected after 'list' keyword."); + } + break; + case TokenNamenew: + // | T_NEW class_name_reference ctor_arguments + getNextToken(); + Expression typeRef = class_name_reference(); + ctor_arguments(); + if (typeRef != null) { + expression = typeRef; + } + break; + // | T_INC rw_variable + // | T_DEC rw_variable + case TokenNamePLUS_PLUS: + case TokenNameMINUS_MINUS: + getNextToken(); + rw_variable(); + break; + // | variable '=' expr + // | variable '=' '&' variable + // | variable '=' '&' T_NEW class_name_reference ctor_arguments + // | variable T_PLUS_EQUAL expr + // | variable T_MINUS_EQUAL expr + // | variable T_MUL_EQUAL expr + // | variable T_DIV_EQUAL expr + // | variable T_CONCAT_EQUAL expr + // | variable T_MOD_EQUAL expr + // | variable T_AND_EQUAL expr + // | variable T_OR_EQUAL expr + // | variable T_XOR_EQUAL expr + // | variable T_SL_EQUAL expr + // | variable T_SR_EQUAL expr + // | rw_variable T_INC + // | rw_variable T_DEC + case TokenNameIdentifier: + case TokenNameVariable: + case TokenNameDOLLAR: + Expression lhs = null; + boolean rememberedVar = false; + if (token == TokenNameIdentifier) { + lhs = identifier(true, true); + if (lhs != null) { + expression = lhs; + } + } else { + lhs = variable(true, true); + if (lhs != null) { + expression = lhs; + } + if (lhs != null && lhs instanceof FieldReference + && token != TokenNameEQUAL + && token != TokenNamePLUS_EQUAL + && token != TokenNameMINUS_EQUAL + && token != TokenNameMULTIPLY_EQUAL + && token != TokenNameDIVIDE_EQUAL + && token != TokenNameDOT_EQUAL + && token != TokenNameREMAINDER_EQUAL + && token != TokenNameAND_EQUAL + && token != TokenNameOR_EQUAL + && token != TokenNameXOR_EQUAL + && token != TokenNameRIGHT_SHIFT_EQUAL + && token != TokenNameLEFT_SHIFT_EQUAL) { + FieldReference ref = (FieldReference) lhs; + if (!containsVariableSet(ref.token)) { + if (null == initHandler + || initHandler.reportError()) { + problemReporter.uninitializedLocalVariable( + new String(ref.token), ref.sourceStart, + ref.sourceEnd, referenceContext, + compilationUnit.compilationResult); + } + addVariableSet(ref.token); + } + } + } + switch (token) { + case TokenNameEQUAL: + if (lhs != null && lhs instanceof FieldReference) { + addVariableSet(((FieldReference) lhs).token); + } + getNextToken(); + if (token == TokenNameAND) { + getNextToken(); + if (token == TokenNamenew) { + // | variable '=' '&' T_NEW class_name_reference + // ctor_arguments + getNextToken(); + SingleTypeReference classRef = class_name_reference(); + ctor_arguments(); + if (classRef != null) { + if (lhs != null + && lhs instanceof FieldReference) { + // example: + // $var = & new Object(); + if (fMethodVariables != null) { + VariableInfo lhsInfo = new VariableInfo( + ((FieldReference) lhs).sourceStart); + lhsInfo.reference = classRef; + lhsInfo.typeIdentifier = classRef.token; + fMethodVariables.put(new String( + ((FieldReference) lhs).token), + lhsInfo); + rememberedVar = true; + } + } + } + } else { + Expression rhs = variable(false, false); + if (rhs != null && rhs instanceof FieldReference + && lhs != null + && lhs instanceof FieldReference) { + // example: + // $var = &$ref; + if (fMethodVariables != null) { + VariableInfo rhsInfo = (VariableInfo) fMethodVariables + .get(((FieldReference) rhs).token); + if (rhsInfo != null + && rhsInfo.reference != null) { + VariableInfo lhsInfo = new VariableInfo( + ((FieldReference) lhs).sourceStart); + lhsInfo.reference = rhsInfo.reference; + lhsInfo.typeIdentifier = rhsInfo.typeIdentifier; + fMethodVariables.put(new String( + ((FieldReference) lhs).token), + lhsInfo); + rememberedVar = true; + } + } + } + } + } else { + Expression rhs = expr(); + if (lhs != null && lhs instanceof FieldReference) { + if (rhs != null && rhs instanceof FieldReference) { + // example: + // $var = $ref; + if (fMethodVariables != null) { + VariableInfo rhsInfo = (VariableInfo) fMethodVariables + .get(((FieldReference) rhs).token); + if (rhsInfo != null + && rhsInfo.reference != null) { + VariableInfo lhsInfo = new VariableInfo( + ((FieldReference) lhs).sourceStart); + lhsInfo.reference = rhsInfo.reference; + lhsInfo.typeIdentifier = rhsInfo.typeIdentifier; + fMethodVariables.put(new String( + ((FieldReference) lhs).token), + lhsInfo); + rememberedVar = true; + } + } + } else if (rhs != null + && rhs instanceof SingleTypeReference) { + // example: + // $var = new Object(); + if (fMethodVariables != null) { + VariableInfo lhsInfo = new VariableInfo( + ((FieldReference) lhs).sourceStart); + lhsInfo.reference = (SingleTypeReference) rhs; + lhsInfo.typeIdentifier = ((SingleTypeReference) rhs).token; + fMethodVariables.put(new String( + ((FieldReference) lhs).token), + lhsInfo); + rememberedVar = true; + } + } + } + } + if (rememberedVar == false && lhs != null + && lhs instanceof FieldReference) { + if (fMethodVariables != null) { + VariableInfo lhsInfo = new VariableInfo( + ((FieldReference) lhs).sourceStart); + fMethodVariables.put(new String( + ((FieldReference) lhs).token), lhsInfo); + } + } + break; + case TokenNamePLUS_EQUAL: + case TokenNameMINUS_EQUAL: + case TokenNameMULTIPLY_EQUAL: + case TokenNameDIVIDE_EQUAL: + case TokenNameDOT_EQUAL: + case TokenNameREMAINDER_EQUAL: + case TokenNameAND_EQUAL: + case TokenNameOR_EQUAL: + case TokenNameXOR_EQUAL: + case TokenNameRIGHT_SHIFT_EQUAL: + case TokenNameLEFT_SHIFT_EQUAL: + if (lhs != null && lhs instanceof FieldReference) { + addVariableSet(((FieldReference) lhs).token); + } + getNextToken(); + expr(); + break; + case TokenNamePLUS_PLUS: + case TokenNameMINUS_MINUS: + getNextToken(); + break; + default: + if (!only_variable) { + throwSyntaxError("Variable expression not allowed (found token '" + + scanner.toStringAction(token) + "')."); + } + if (lhs != null) { + expression = lhs; + } + } + break; + default: + if (token != TokenNameINLINE_HTML) { + if (token > TokenNameKEYWORD) { + getNextToken(); + break; + } else { + // System.out.println(scanner.getCurrentTokenStartPosition()); + // System.out.println(scanner.getCurrentTokenEndPosition()); + + throwSyntaxError("Error in expression (found token '" + + scanner.toStringAction(token) + "')."); + } + } + return expression; + } + if (Scanner.TRACE) { + System.out.println("TRACE: expr_without_variable() PART 2"); + } + // | expr T_BOOLEAN_OR expr + // | expr T_BOOLEAN_AND expr + // | expr T_LOGICAL_OR expr + // | expr T_LOGICAL_AND expr + // | expr T_LOGICAL_XOR expr + // | expr '|' expr + // | expr '&' expr + // | expr '^' expr + // | expr '.' expr + // | expr '+' expr + // | expr '-' expr + // | expr '*' expr + // | expr '/' expr + // | expr '%' expr + // | expr T_SL expr + // | expr T_SR expr + // | expr T_IS_IDENTICAL expr + // | expr T_IS_NOT_IDENTICAL expr + // | expr T_IS_EQUAL expr + // | expr T_IS_NOT_EQUAL expr + // | expr '<' expr + // | expr T_IS_SMALLER_OR_EQUAL expr + // | expr '>' expr + // | expr T_IS_GREATER_OR_EQUAL expr + while (true) { + switch (token) { + case TokenNameOR_OR: + getNextToken(); + expression = new OR_OR_Expression(expression, expr(), token); + break; + case TokenNameAND_AND: + getNextToken(); + expression = new AND_AND_Expression(expression, expr(), + token); + break; + case TokenNameEQUAL_EQUAL: + getNextToken(); + expression = new EqualExpression(expression, expr(), token); + break; + case TokenNameand: + case TokenNameor: + case TokenNamexor: + case TokenNameAND: + case TokenNameOR: + case TokenNameXOR: + case TokenNameDOT: + case TokenNamePLUS: + case TokenNameMINUS: + case TokenNameMULTIPLY: + case TokenNameDIVIDE: + case TokenNameREMAINDER: + case TokenNameLEFT_SHIFT: + case TokenNameRIGHT_SHIFT: + case TokenNameEQUAL_EQUAL_EQUAL: + case TokenNameNOT_EQUAL_EQUAL: + case TokenNameNOT_EQUAL: + case TokenNameLESS: + case TokenNameLESS_EQUAL: + case TokenNameGREATER: + case TokenNameGREATER_EQUAL: + getNextToken(); + expression = new BinaryExpression(expression, expr(), token); + break; + // | expr T_INSTANCEOF class_name_reference + // | expr '?' expr ':' expr + case TokenNameinstanceof: + getNextToken(); + TypeReference classRef = class_name_reference(); + if (classRef != null) { + expression = new InstanceOfExpression(expression, + classRef, OperatorIds.INSTANCEOF); + expression.sourceStart = exprSourceStart; + expression.sourceEnd = scanner + .getCurrentTokenEndPosition(); + } + break; + case TokenNameQUESTION: + getNextToken(); + Expression valueIfTrue = expr(); + if (token != TokenNameCOLON) { + throwSyntaxError("':' expected in conditional expression."); + } + getNextToken(); + Expression valueIfFalse = expr(); + + expression = new ConditionalExpression(expression, + valueIfTrue, valueIfFalse); + break; + default: + return expression; + } + } + } catch (SyntaxError e) { + // try to find next token after expression with errors: + if (token == TokenNameSEMICOLON) { + getNextToken(); + return expression; + } + if (token == TokenNameRBRACE || token == TokenNameRPAREN + || token == TokenNameRBRACKET) { + getNextToken(); + return expression; + } + throw e; + } + } + + private SingleTypeReference class_name_reference() { + // class_name_reference: + // T_STRING + // | dynamic_class_name_reference + SingleTypeReference ref = null; + if (Scanner.TRACE) { + System.out.println("TRACE: class_name_reference()"); + } + if (token == TokenNameIdentifier) { + ref = new SingleTypeReference(scanner.getCurrentIdentifierSource(), + scanner.getCurrentTokenStartPosition()); + getNextToken(); + } else { + ref = null; + dynamic_class_name_reference(); + } + return ref; + } + + private void dynamic_class_name_reference() { + // dynamic_class_name_reference: + // base_variable T_OBJECT_OPERATOR object_property + // dynamic_class_name_variable_properties + // | base_variable + if (Scanner.TRACE) { + System.out.println("TRACE: dynamic_class_name_reference()"); + } + base_variable(true); + if (token == TokenNameMINUS_GREATER) { + getNextToken(); + object_property(); + dynamic_class_name_variable_properties(); + } + } + + private void dynamic_class_name_variable_properties() { + // dynamic_class_name_variable_properties: + // dynamic_class_name_variable_properties + // dynamic_class_name_variable_property + // | /* empty */ + if (Scanner.TRACE) { + System.out + .println("TRACE: dynamic_class_name_variable_properties()"); + } + while (token == TokenNameMINUS_GREATER) { + dynamic_class_name_variable_property(); + } + } + + private void dynamic_class_name_variable_property() { + // dynamic_class_name_variable_property: + // T_OBJECT_OPERATOR object_property + if (Scanner.TRACE) { + System.out.println("TRACE: dynamic_class_name_variable_property()"); + } + if (token == TokenNameMINUS_GREATER) { + getNextToken(); + object_property(); + } + } + + private void ctor_arguments() { + // ctor_arguments: + // /* empty */ + // | '(' function_call_parameter_list ')' + if (token == TokenNameLPAREN) { + getNextToken(); + if (token == TokenNameRPAREN) { + getNextToken(); + return; + } + non_empty_function_call_parameter_list(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected in ctor_arguments."); + } + getNextToken(); + } + } + + private void assignment_list() { + // assignment_list: + // assignment_list ',' assignment_list_element + // | assignment_list_element + while (true) { + assignment_list_element(); + if (token != TokenNameCOMMA) { + break; + } + getNextToken(); + } + } + + private void assignment_list_element() { + // assignment_list_element: + // variable + // | T_LIST '(' assignment_list ')' + // | /* empty */ + if (token == TokenNameVariable) { + variable(true, false); + } else if (token == TokenNameDOLLAR) { + variable(false, false); + } else if (token == TokenNameIdentifier) { + identifier(true, true); + } else { + if (token == TokenNamelist) { + getNextToken(); + if (token == TokenNameLPAREN) { + getNextToken(); + assignment_list(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected after 'list' keyword."); + } + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'list' keyword."); + } + } + } + } + + private void array_pair_list() { + // array_pair_list: + // /* empty */ + // | non_empty_array_pair_list possible_comma + non_empty_array_pair_list(); + if (token == TokenNameCOMMA) { + getNextToken(); + } + } + + private void non_empty_array_pair_list() { + // non_empty_array_pair_list: + // non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr + // | non_empty_array_pair_list ',' expr + // | expr T_DOUBLE_ARROW expr + // | expr + // | non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_variable + // | non_empty_array_pair_list ',' '&' w_variable + // | expr T_DOUBLE_ARROW '&' w_variable + // | '&' w_variable + while (true) { + if (token == TokenNameAND) { + getNextToken(); + variable(true, false); + } else { + expr(); + if (token == TokenNameAND) { + getNextToken(); + variable(true, false); + } else if (token == TokenNameEQUAL_GREATER) { + getNextToken(); + if (token == TokenNameAND) { + getNextToken(); + variable(true, false); + } else { + expr(); + } + } + } + if (token != TokenNameCOMMA) { + return; + } + getNextToken(); + if (token == TokenNameRPAREN) { + return; + } + } + } + + // private void variableList() { + // do { + // variable(); + // if (token == TokenNameCOMMA) { + // getNextToken(); + // } else { + // break; + // } + // } while (true); + // } + private Expression variable_without_objects(boolean lefthandside, + boolean ignoreVar) { + // variable_without_objects: + // reference_variable + // | simple_indirect_reference reference_variable + if (Scanner.TRACE) { + System.out.println("TRACE: variable_without_objects()"); + } + while (token == TokenNameDOLLAR) { + getNextToken(); + } + return reference_variable(lefthandside, ignoreVar); + } + + private Expression function_call(boolean lefthandside, boolean ignoreVar) { + // function_call: + // T_STRING '(' function_call_parameter_list ')' + // | class_constant '(' function_call_parameter_list ')' + // | static_member '(' function_call_parameter_list ')' + // | variable_without_objects '(' function_call_parameter_list ')' + char[] defineName = null; + char[] ident = null; + int startPos = 0; + int endPos = 0; + Expression ref = null; + if (Scanner.TRACE) { + System.out.println("TRACE: function_call()"); + } + if (token == TokenNameIdentifier) { + ident = scanner.getCurrentIdentifierSource(); + defineName = ident; + startPos = scanner.getCurrentTokenStartPosition(); + endPos = scanner.getCurrentTokenEndPosition(); + getNextToken(); + switch (token) { + case TokenNamePAAMAYIM_NEKUDOTAYIM: + // static member: + defineName = null; + getNextToken(); + if (token == TokenNameIdentifier) { + // class _constant + getNextToken(); + } else { + // static member: + variable_without_objects(true, false); + } + break; + } + } else { + ref = variable_without_objects(lefthandside, ignoreVar); + } + if (token != TokenNameLPAREN) { + if (defineName != null) { + // does this identifier contain only uppercase characters? + if (defineName.length == 3) { + if (defineName[0] == 'd' && defineName[1] == 'i' + && defineName[2] == 'e') { + defineName = null; + } + } else if (defineName.length == 4) { + if (defineName[0] == 't' && defineName[1] == 'r' + && defineName[2] == 'u' && defineName[3] == 'e') { + defineName = null; + } else if (defineName[0] == 'n' && defineName[1] == 'u' + && defineName[2] == 'l' && defineName[3] == 'l') { + defineName = null; + } + } else if (defineName.length == 5) { + if (defineName[0] == 'f' && defineName[1] == 'a' + && defineName[2] == 'l' && defineName[3] == 's' + && defineName[4] == 'e') { + defineName = null; + } + } + if (defineName != null) { + for (int i = 0; i < defineName.length; i++) { + if (Character.isLowerCase(defineName[i])) { + problemReporter.phpUppercaseIdentifierWarning( + startPos, endPos, referenceContext, + compilationUnit.compilationResult); + break; + } + } + } + } + } else { + getNextToken(); + if (token == TokenNameRPAREN) { + getNextToken(); + return ref; + } + non_empty_function_call_parameter_list(); + if (token != TokenNameRPAREN) { + String functionName; + if (ident == null) { + functionName = new String(" "); + } else { + functionName = new String(ident); + } + throwSyntaxError("')' expected in function call (" + + functionName + ")."); + } + getNextToken(); + } + return ref; + } + + private void non_empty_function_call_parameter_list() { + this.non_empty_function_call_parameter_list(null); + } + + // private void function_call_parameter_list() { + // function_call_parameter_list: + // non_empty_function_call_parameter_list { $$ = $1; } + // | /* empty */ + // } + private void non_empty_function_call_parameter_list(String functionName) { + // non_empty_function_call_parameter_list: + // expr_without_variable + // | variable + // | '&' w_variable + // | non_empty_function_call_parameter_list ',' expr_without_variable + // | non_empty_function_call_parameter_list ',' variable + // | non_empty_function_call_parameter_list ',' '&' w_variable + if (Scanner.TRACE) { + System.out + .println("TRACE: non_empty_function_call_parameter_list()"); + } + UninitializedVariableHandler initHandler = new UninitializedVariableHandler(); + initHandler.setFunctionName(functionName); + while (true) { + initHandler.incrementArgumentCount(); + if (token == TokenNameAND) { + getNextToken(); + w_variable(true); + } else { + // if (token == TokenNameIdentifier || token == + // TokenNameVariable + // || token == TokenNameDOLLAR) { + // variable(); + // } else { + expr_without_variable(true, initHandler); + // } + } + if (token != TokenNameCOMMA) { + break; + } + getNextToken(); + } + } + + private void fully_qualified_class_name() { + if (token == TokenNameIdentifier) { + getNextToken(); + } else { + throwSyntaxError("Class name expected."); + } + } + + private void static_member() { + // static_member: + // fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM + // variable_without_objects + if (Scanner.TRACE) { + System.out.println("TRACE: static_member()"); + } + fully_qualified_class_name(); + if (token != TokenNamePAAMAYIM_NEKUDOTAYIM) { + throwSyntaxError("'::' expected after class name (static_member)."); + } + getNextToken(); + variable_without_objects(false, false); + } + + private Expression base_variable_with_function_calls(boolean lefthandside, + boolean ignoreVar) { + // base_variable_with_function_calls: + // base_variable + // | function_call + if (Scanner.TRACE) { + System.out.println("TRACE: base_variable_with_function_calls()"); + } + return function_call(lefthandside, ignoreVar); + } + + private Expression base_variable(boolean lefthandside) { + // base_variable: + // reference_variable + // | simple_indirect_reference reference_variable + // | static_member + Expression ref = null; + if (Scanner.TRACE) { + System.out.println("TRACE: base_variable()"); + } + if (token == TokenNameIdentifier) { + static_member(); + } else { + while (token == TokenNameDOLLAR) { + getNextToken(); + } + reference_variable(lefthandside, false); + } + return ref; + } + + // private void simple_indirect_reference() { + // // simple_indirect_reference: + // // '$' + // //| simple_indirect_reference '$' + // } + private Expression reference_variable(boolean lefthandside, + boolean ignoreVar) { + // reference_variable: + // reference_variable '[' dim_offset ']' + // | reference_variable '{' expr '}' + // | compound_variable + Expression ref = null; + if (Scanner.TRACE) { + System.out.println("TRACE: reference_variable()"); + } + ref = compound_variable(lefthandside, ignoreVar); + while (true) { + if (token == TokenNameLBRACE) { + ref = null; + getNextToken(); + expr(); + if (token != TokenNameRBRACE) { + throwSyntaxError("'}' expected in reference variable."); + } + getNextToken(); + } else if (token == TokenNameLBRACKET) { + // To remove "ref = null;" here, is probably better than the + // patch + // commented in #1368081 - axelcl + getNextToken(); + if (token != TokenNameRBRACKET) { + expr(); + // dim_offset(); + if (token != TokenNameRBRACKET) { + throwSyntaxError("']' expected in reference variable."); + } + } + getNextToken(); + } else { + break; + } + } + return ref; + } + + private Expression compound_variable(boolean lefthandside, boolean ignoreVar) { + // compound_variable: + // T_VARIABLE + // | '$' '{' expr '}' + if (Scanner.TRACE) { + System.out.println("TRACE: compound_variable()"); + } + if (token == TokenNameVariable) { + if (!lefthandside) { + if (!containsVariableSet()) { + // reportSyntaxError("The local variable " + new + // String(scanner.getCurrentIdentifierSource()) + // + " may not have been initialized"); + problemReporter.uninitializedLocalVariable(new String( + scanner.getCurrentIdentifierSource()), scanner + .getCurrentTokenStartPosition(), scanner + .getCurrentTokenEndPosition(), referenceContext, + compilationUnit.compilationResult); + } + } else { + if (!ignoreVar) { + addVariableSet(); + } + } + FieldReference ref = new FieldReference(scanner + .getCurrentIdentifierSource(), scanner + .getCurrentTokenStartPosition()); + getNextToken(); + return ref; + } else { + // because of simple_indirect_reference + while (token == TokenNameDOLLAR) { + getNextToken(); + } + if (token != TokenNameLBRACE) { + reportSyntaxError("'{' expected after compound variable token '$'."); + return null; + } + getNextToken(); + expr(); + if (token != TokenNameRBRACE) { + throwSyntaxError("'}' expected after compound variable token '$'."); + } + getNextToken(); + } + return null; + } // private void dim_offset() { // // dim_offset: // // /* empty */ + + // // | expr + // expr(); + // } + private void object_property() { + // object_property: + // object_dim_list + // | variable_without_objects + if (Scanner.TRACE) { + System.out.println("TRACE: object_property()"); + } + if (token == TokenNameVariable || token == TokenNameDOLLAR) { + variable_without_objects(false, false); + } else { + object_dim_list(); + } + } + + private void object_dim_list() { + // object_dim_list: + // object_dim_list '[' dim_offset ']' + // | object_dim_list '{' expr '}' + // | variable_name + if (Scanner.TRACE) { + System.out.println("TRACE: object_dim_list()"); + } + variable_name(); + while (true) { + if (token == TokenNameLBRACE) { + getNextToken(); + expr(); + if (token != TokenNameRBRACE) { + throwSyntaxError("'}' expected in object_dim_list."); + } + getNextToken(); + } else if (token == TokenNameLBRACKET) { + getNextToken(); + if (token == TokenNameRBRACKET) { + getNextToken(); + continue; + } + expr(); + if (token != TokenNameRBRACKET) { + throwSyntaxError("']' expected in object_dim_list."); + } + getNextToken(); + } else { + break; + } + } + } + + private void variable_name() { + // variable_name: + // T_STRING + // | '{' expr '}' + if (Scanner.TRACE) { + System.out.println("TRACE: variable_name()"); + } + if (token == TokenNameIdentifier || token > TokenNameKEYWORD) { + if (token > TokenNameKEYWORD) { + // TODO show a warning "Keyword used as variable" ? + } + getNextToken(); + } else { + if (token != TokenNameLBRACE) { + throwSyntaxError("'{' expected in variable name."); + } + getNextToken(); + expr(); + if (token != TokenNameRBRACE) { + throwSyntaxError("'}' expected in variable name."); + } + getNextToken(); + } + } + + private void r_variable() { + variable(false, false); + } + + private void w_variable(boolean lefthandside) { + variable(lefthandside, false); + } + + private void rw_variable() { + variable(false, false); + } + + private Expression variable(boolean lefthandside, boolean ignoreVar) { + // variable: + // base_variable_with_function_calls T_OBJECT_OPERATOR + // object_property method_or_not variable_properties + // | base_variable_with_function_calls + Expression ref = base_variable_with_function_calls(lefthandside, + ignoreVar); + if (token == TokenNameMINUS_GREATER) { + ref = null; + getNextToken(); + object_property(); + method_or_not(); + variable_properties(); + } + return ref; + } + + private void variable_properties() { + // variable_properties: + // variable_properties variable_property + // | /* empty */ + while (token == TokenNameMINUS_GREATER) { + variable_property(); + } + } + + private void variable_property() { + // variable_property: + // T_OBJECT_OPERATOR object_property method_or_not + if (Scanner.TRACE) { + System.out.println("TRACE: variable_property()"); + } + if (token == TokenNameMINUS_GREATER) { + getNextToken(); + object_property(); + method_or_not(); + } else { + throwSyntaxError("'->' expected in variable_property."); + } + } + + private Expression identifier(boolean lefthandside, boolean ignoreVar) { + // variable: + // base_variable_with_function_calls T_OBJECT_OPERATOR + // object_property method_or_not variable_properties + // | base_variable_with_function_calls + + // Expression ref = function_call(lefthandside, ignoreVar); + + // function_call: + // T_STRING '(' function_call_parameter_list ')' + // | class_constant '(' function_call_parameter_list ')' + // | static_member '(' function_call_parameter_list ')' + // | variable_without_objects '(' function_call_parameter_list ')' + char[] defineName = null; + char[] ident = null; + int startPos = 0; + int endPos = 0; + Expression ref = null; + if (Scanner.TRACE) { + System.out.println("TRACE: function_call()"); + } + if (token == TokenNameIdentifier) { + ident = scanner.getCurrentIdentifierSource(); + defineName = ident; + startPos = scanner.getCurrentTokenStartPosition(); + endPos = scanner.getCurrentTokenEndPosition(); + getNextToken(); + + if (token == TokenNameEQUAL || token == TokenNamePLUS_EQUAL + || token == TokenNameMINUS_EQUAL + || token == TokenNameMULTIPLY_EQUAL + || token == TokenNameDIVIDE_EQUAL + || token == TokenNameDOT_EQUAL + || token == TokenNameREMAINDER_EQUAL + || token == TokenNameAND_EQUAL + || token == TokenNameOR_EQUAL + || token == TokenNameXOR_EQUAL + || token == TokenNameRIGHT_SHIFT_EQUAL + || token == TokenNameLEFT_SHIFT_EQUAL) { + String error = "Assignment operator '" + + scanner.toStringAction(token) + + "' not allowed after identifier '" + + new String(ident) + + "' (use 'define(...)' to define constants)."; + reportSyntaxError(error); + } + + switch (token) { + case TokenNamePAAMAYIM_NEKUDOTAYIM: + // static member: + defineName = null; + getNextToken(); + if (token == TokenNameIdentifier) { + // class _constant + getNextToken(); + } else { + // static member: + variable_without_objects(true, false); + } + break; + } + } else { + ref = variable_without_objects(lefthandside, ignoreVar); + } + if (token != TokenNameLPAREN) { + if (defineName != null) { + // does this identifier contain only uppercase characters? + if (defineName.length == 3) { + if (defineName[0] == 'd' && defineName[1] == 'i' + && defineName[2] == 'e') { + defineName = null; + } + } else if (defineName.length == 4) { + if (defineName[0] == 't' && defineName[1] == 'r' + && defineName[2] == 'u' && defineName[3] == 'e') { + defineName = null; + } else if (defineName[0] == 'n' && defineName[1] == 'u' + && defineName[2] == 'l' && defineName[3] == 'l') { + defineName = null; + } + } else if (defineName.length == 5) { + if (defineName[0] == 'f' && defineName[1] == 'a' + && defineName[2] == 'l' && defineName[3] == 's' + && defineName[4] == 'e') { + defineName = null; + } + } + if (defineName != null) { + for (int i = 0; i < defineName.length; i++) { + if (Character.isLowerCase(defineName[i])) { + problemReporter.phpUppercaseIdentifierWarning( + startPos, endPos, referenceContext, + compilationUnit.compilationResult); + break; + } + } + } + } + // TODO is this ok ? + // return ref; + // throwSyntaxError("'(' expected in function call."); + } else { + getNextToken(); + + if (token == TokenNameRPAREN) { + getNextToken(); + ref = null; + } else { + String functionName; + if (ident == null) { + functionName = new String(" "); + } else { + functionName = new String(ident); + } + non_empty_function_call_parameter_list(functionName); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected in function call (" + + functionName + ")."); + } + getNextToken(); + } + } + if (token == TokenNameMINUS_GREATER) { + ref = null; + getNextToken(); + object_property(); + method_or_not(); + variable_properties(); + } + return ref; + } + + private void method_or_not() { + // method_or_not: + // '(' function_call_parameter_list ')' + // | /* empty */ + if (Scanner.TRACE) { + System.out.println("TRACE: method_or_not()"); + } + if (token == TokenNameLPAREN) { + getNextToken(); + if (token == TokenNameRPAREN) { + getNextToken(); + return; + } + non_empty_function_call_parameter_list(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected in method_or_not."); + } + getNextToken(); + } + } + + private void exit_expr() { + // /* empty */ + // | '(' ')' + // | '(' expr ')' + if (token != TokenNameLPAREN) { + return; + } + getNextToken(); + if (token == TokenNameRPAREN) { + getNextToken(); + return; + } + expr(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected after keyword 'exit'"); + } + getNextToken(); + } + + // private void encaps_list() { + // // encaps_list encaps_var + // // | encaps_list T_STRING + // // | encaps_list T_NUM_STRING + // // | encaps_list T_ENCAPSED_AND_WHITESPACE + // // | encaps_list T_CHARACTER + // // | encaps_list T_BAD_CHARACTER + // // | encaps_list '[' + // // | encaps_list ']' + // // | encaps_list '{' + // // | encaps_list '}' + // // | encaps_list T_OBJECT_OPERATOR + // // | /* empty */ + // while (true) { + // switch (token) { + // case TokenNameSTRING: + // getNextToken(); + // break; + // case TokenNameLBRACE: + // // scanner.encapsedStringStack.pop(); + // getNextToken(); + // break; + // case TokenNameRBRACE: + // // scanner.encapsedStringStack.pop(); + // getNextToken(); + // break; + // case TokenNameLBRACKET: + // // scanner.encapsedStringStack.pop(); + // getNextToken(); + // break; + // case TokenNameRBRACKET: + // // scanner.encapsedStringStack.pop(); + // getNextToken(); + // break; + // case TokenNameMINUS_GREATER: + // // scanner.encapsedStringStack.pop(); + // getNextToken(); + // break; + // case TokenNameVariable: + // case TokenNameDOLLAR_LBRACE: + // case TokenNameLBRACE_DOLLAR: + // encaps_var(); + // break; + // default: + // char encapsedChar = ((Character) + // scanner.encapsedStringStack.peek()).charValue(); + // if (encapsedChar == '$') { + // scanner.encapsedStringStack.pop(); + // encapsedChar = ((Character) + // scanner.encapsedStringStack.peek()).charValue(); + // switch (encapsedChar) { + // case '`': + // if (token == TokenNameEncapsedString0) { + // return; + // } + // token = TokenNameSTRING; + // continue; + // case '\'': + // if (token == TokenNameEncapsedString1) { + // return; + // } + // token = TokenNameSTRING; + // continue; + // case '"': + // if (token == TokenNameEncapsedString2) { + // return; + // } + // token = TokenNameSTRING; + // continue; + // } + // } + // return; + // } + // } + // } + + // private void encaps_var() { + // // T_VARIABLE + // // | T_VARIABLE '[' encaps_var_offset ']' + // // | T_VARIABLE T_OBJECT_OPERATOR T_STRING + // // | T_DOLLAR_OPEN_CURLY_BRACES expr '}' + // // | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}' + // // | T_CURLY_OPEN variable '}' + // switch (token) { + // case TokenNameVariable: + // getNextToken(); + // if (token == TokenNameLBRACKET) { + // getNextToken(); + // expr(); //encaps_var_offset(); + // if (token != TokenNameRBRACKET) { + // throwSyntaxError("']' expected after variable."); + // } + // // scanner.encapsedStringStack.pop(); + // getNextToken(); + // // } + // } else if (token == TokenNameMINUS_GREATER) { + // getNextToken(); + // if (token != TokenNameIdentifier) { + // throwSyntaxError("Identifier expected after '->'."); + // } + // // scanner.encapsedStringStack.pop(); + // getNextToken(); + // } + // // else { + // // // scanner.encapsedStringStack.pop(); + // // int tempToken = TokenNameSTRING; + // // if (!scanner.encapsedStringStack.isEmpty() + // // && (token == TokenNameEncapsedString0 + // // || token == TokenNameEncapsedString1 + // // || token == TokenNameEncapsedString2 || token == + // // TokenNameERROR)) { + // // char encapsedChar = ((Character) + // // scanner.encapsedStringStack.peek()) + // // .charValue(); + // // switch (token) { + // // case TokenNameEncapsedString0 : + // // if (encapsedChar == '`') { + // // tempToken = TokenNameEncapsedString0; + // // } + // // break; + // // case TokenNameEncapsedString1 : + // // if (encapsedChar == '\'') { + // // tempToken = TokenNameEncapsedString1; + // // } + // // break; + // // case TokenNameEncapsedString2 : + // // if (encapsedChar == '"') { + // // tempToken = TokenNameEncapsedString2; + // // } + // // break; + // // case TokenNameERROR : + // // if (scanner.source[scanner.currentPosition - 1] == '\\') { + // // scanner.currentPosition--; + // // getNextToken(); + // // } + // // break; + // // } + // // } + // // token = tempToken; + // // } + // break; + // case TokenNameDOLLAR_LBRACE: + // getNextToken(); + // if (token == TokenNameDOLLAR_LBRACE) { + // encaps_var(); + // } else if (token == TokenNameIdentifier) { + // getNextToken(); + // if (token == TokenNameLBRACKET) { + // getNextToken(); + // // if (token == TokenNameRBRACKET) { + // // getNextToken(); + // // } else { + // expr(); + // if (token != TokenNameRBRACKET) { + // throwSyntaxError("']' expected after '${'."); + // } + // getNextToken(); + // // } + // } + // } else { + // expr(); + // } + // if (token != TokenNameRBRACE) { + // throwSyntaxError("'}' expected."); + // } + // getNextToken(); + // break; + // case TokenNameLBRACE_DOLLAR: + // getNextToken(); + // if (token == TokenNameLBRACE_DOLLAR) { + // encaps_var(); + // } else if (token == TokenNameIdentifier || token > TokenNameKEYWORD) { + // getNextToken(); + // if (token == TokenNameLBRACKET) { + // getNextToken(); + // // if (token == TokenNameRBRACKET) { + // // getNextToken(); + // // } else { + // expr(); + // if (token != TokenNameRBRACKET) { + // throwSyntaxError("']' expected."); + // } + // getNextToken(); + // // } + // } else if (token == TokenNameMINUS_GREATER) { + // getNextToken(); + // if (token != TokenNameIdentifier && token != TokenNameVariable) { + // throwSyntaxError("String or Variable token expected."); + // } + // getNextToken(); + // if (token == TokenNameLBRACKET) { + // getNextToken(); + // // if (token == TokenNameRBRACKET) { + // // getNextToken(); + // // } else { + // expr(); + // if (token != TokenNameRBRACKET) { + // throwSyntaxError("']' expected after '${'."); + // } + // getNextToken(); + // // } + // } + // } + // // if (token != TokenNameRBRACE) { + // // throwSyntaxError("'}' expected after '{$'."); + // // } + // // // scanner.encapsedStringStack.pop(); + // // getNextToken(); + // } else { + // expr(); + // if (token != TokenNameRBRACE) { + // throwSyntaxError("'}' expected."); + // } + // // scanner.encapsedStringStack.pop(); + // getNextToken(); + // } + // break; + // } + // } + + // private void encaps_var_offset() { + // // T_STRING + // // | T_NUM_STRING + // // | T_VARIABLE + // switch (token) { + // case TokenNameSTRING: + // getNextToken(); + // break; + // case TokenNameIntegerLiteral: + // getNextToken(); + // break; + // case TokenNameVariable: + // getNextToken(); + // break; + // case TokenNameIdentifier: + // getNextToken(); + // break; + // default: + // throwSyntaxError("Variable or String token expected."); + // break; + // } + // } + + private void internal_functions_in_yacc() { + // int start = 0; + switch (token) { + // case TokenNameisset: + // // T_ISSET '(' isset_variables ')' + // getNextToken(); + // if (token != TokenNameLPAREN) { + // throwSyntaxError("'(' expected after keyword 'isset'"); + // } + // getNextToken(); + // isset_variables(); + // if (token != TokenNameRPAREN) { + // throwSyntaxError("')' expected after keyword 'isset'"); + // } + // getNextToken(); + // break; + // case TokenNameempty: + // // T_EMPTY '(' variable ')' + // getNextToken(); + // if (token != TokenNameLPAREN) { + // throwSyntaxError("'(' expected after keyword 'empty'"); + // } + // getNextToken(); + // variable(false); + // if (token != TokenNameRPAREN) { + // throwSyntaxError("')' expected after keyword 'empty'"); + // } + // getNextToken(); + // break; + case TokenNameinclude: + // T_INCLUDE expr + checkFileName(token); + break; + case TokenNameinclude_once: + // T_INCLUDE_ONCE expr + checkFileName(token); + break; + case TokenNameeval: + // T_EVAL '(' expr ')' + getNextToken(); + if (token != TokenNameLPAREN) { + throwSyntaxError("'(' expected after keyword 'eval'"); + } + getNextToken(); + expr(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected after keyword 'eval'"); + } + getNextToken(); + break; + case TokenNamerequire: + // T_REQUIRE expr + checkFileName(token); + break; + case TokenNamerequire_once: + // T_REQUIRE_ONCE expr + checkFileName(token); + break; + } + } + + /** + * Parse and check the include file name + * + * @param includeToken + */ + private void checkFileName(int includeToken) { + // expr + int start = scanner.getCurrentTokenStartPosition(); + boolean hasLPAREN = false; + getNextToken(); + if (token == TokenNameLPAREN) { + hasLPAREN = true; + getNextToken(); + } + Expression expression = expr(); + if (hasLPAREN) { + if (token == TokenNameRPAREN) { + getNextToken(); + } else { + throwSyntaxError("')' expected for keyword '" + + scanner.toStringAction(includeToken) + "'"); + } + } + char[] currTokenSource = scanner.getCurrentTokenSource(start); + IFile file = null; + if (scanner.compilationUnit != null) { + IResource resource = scanner.compilationUnit.getResource(); + if (resource != null && resource instanceof IFile) { + file = (IFile) resource; + } + } + char[][] tokens; + tokens = new char[1][]; + tokens[0] = currTokenSource; + + ImportReference impt = new ImportReference(tokens, currTokenSource, + start, scanner.getCurrentTokenEndPosition(), false); + impt.declarationSourceEnd = impt.sourceEnd; + impt.declarationEnd = impt.declarationSourceEnd; + // endPosition is just before the ; + impt.declarationSourceStart = start; + includesList.add(impt); + + if (expression instanceof StringLiteral) { + StringLiteral literal = (StringLiteral) expression; + char[] includeName = literal.source(); + if (includeName.length == 0) { + reportSyntaxError("Empty filename after keyword '" + + scanner.toStringAction(includeToken) + "'", + literal.sourceStart, literal.sourceStart + 1); + } + String includeNameString = new String(includeName); + if (literal instanceof StringLiteralDQ) { + if (includeNameString.indexOf('$') >= 0) { + // assuming that the filename contains a variable => no + // filename check + return; + } + } + if (includeNameString.startsWith("http://")) { + // assuming external include location + return; + } + if (file != null) { + // check the filename: + // System.out.println(new + // String(compilationUnit.getFileName())+" - "+ + // expression.toStringExpression()); + IProject project = file.getProject(); + if (project != null) { + IPath path = PHPFileUtil.determineFilePath( + includeNameString, file, project); + + if (path == null) { + // SyntaxError: "File: << >> doesn't exist in project." + String[] args = { expression.toStringExpression(), + project.getLocation().toString() }; + problemReporter.phpIncludeNotExistWarning(args, + literal.sourceStart, literal.sourceEnd, + referenceContext, + compilationUnit.compilationResult); + } else { + try { + String filePath = path.toString(); + String ext = file.getRawLocation() + .getFileExtension(); + int fileExtensionLength = ext == null ? 0 : ext + .length() + 1; + + IFile f = PHPFileUtil.createFile(path, project); + + impt.tokens = CharOperation.splitOn('/', filePath + .toCharArray(), 0, filePath.length() + - fileExtensionLength); + impt.setFile(f); + } catch (Exception e) { + // the file is outside of the workspace + } + } + } + } + } + } + + private void isset_variables() { + // variable + // | isset_variables ',' + if (token == TokenNameRPAREN) { + throwSyntaxError("Variable expected after keyword 'isset'"); + } + while (true) { + variable(true, false); + if (token == TokenNameCOMMA) { + getNextToken(); + } else { + break; + } + } + } + + private boolean common_scalar() { + // common_scalar: + // T_LNUMBER + // | T_DNUMBER + // | T_CONSTANT_ENCAPSED_STRING + // | T_LINE + // | T_FILE + // | T_CLASS_C + // | T_METHOD_C + // | T_FUNC_C + switch (token) { + case TokenNameIntegerLiteral: + getNextToken(); + return true; + case TokenNameDoubleLiteral: + getNextToken(); + return true; + case TokenNameStringDoubleQuote: + getNextToken(); + return true; + case TokenNameStringSingleQuote: + getNextToken(); + return true; + case TokenNameStringInterpolated: + getNextToken(); + return true; + case TokenNameFILE: + getNextToken(); + return true; + case TokenNameLINE: + getNextToken(); + return true; + case TokenNameCLASS_C: + getNextToken(); + return true; + case TokenNameMETHOD_C: + getNextToken(); + return true; + case TokenNameFUNC_C: + getNextToken(); + return true; + } + return false; + } + + private void scalar() { + // scalar: + // T_STRING + // | T_STRING_VARNAME + // | class_constant + // | common_scalar + // | '"' encaps_list '"' + // | '\'' encaps_list '\'' + // | T_START_HEREDOC encaps_list T_END_HEREDOC + throwSyntaxError("Not yet implemented (scalar)."); + } + + private void static_scalar() { + // static_scalar: /* compile-time evaluated scalars */ + // common_scalar + // | T_STRING + // | '+' static_scalar + // | '-' static_scalar + // | T_ARRAY '(' static_array_pair_list ')' + // | static_class_constant + if (common_scalar()) { + return; + } + switch (token) { + case TokenNameIdentifier: + getNextToken(); + // static_class_constant: + // T_STRING T_PAAMAYIM_NEKUDOTAYIM T_STRING + if (token == TokenNamePAAMAYIM_NEKUDOTAYIM) { + getNextToken(); + if (token == TokenNameIdentifier) { + getNextToken(); + } else { + throwSyntaxError("Identifier expected after '::' operator."); + } + } + break; + case TokenNameEncapsedString0: + try { + scanner.currentCharacter = scanner.source[scanner.currentPosition++]; + while (scanner.currentCharacter != '`') { + if (scanner.currentCharacter == '\\') { + scanner.currentPosition++; + } + scanner.currentCharacter = scanner.source[scanner.currentPosition++]; + } + getNextToken(); + } catch (IndexOutOfBoundsException e) { + throwSyntaxError("'`' expected at end of static string."); + } + break; + // case TokenNameEncapsedString1: + // try { + // scanner.currentCharacter = scanner.source[scanner.currentPosition++]; + // while (scanner.currentCharacter != '\'') { + // if (scanner.currentCharacter == '\\') { + // scanner.currentPosition++; + // } + // scanner.currentCharacter = scanner.source[scanner.currentPosition++]; + // } + // getNextToken(); + // } catch (IndexOutOfBoundsException e) { + // throwSyntaxError("'\'' expected at end of static string."); + // } + // break; + // case TokenNameEncapsedString2: + // try { + // scanner.currentCharacter = scanner.source[scanner.currentPosition++]; + // while (scanner.currentCharacter != '"') { + // if (scanner.currentCharacter == '\\') { + // scanner.currentPosition++; + // } + // scanner.currentCharacter = scanner.source[scanner.currentPosition++]; + // } + // getNextToken(); + // } catch (IndexOutOfBoundsException e) { + // throwSyntaxError("'\"' expected at end of static string."); + // } + // break; + case TokenNameStringSingleQuote: + getNextToken(); + break; + case TokenNameStringDoubleQuote: + getNextToken(); + break; + case TokenNamePLUS: + getNextToken(); + static_scalar(); + break; + case TokenNameMINUS: + getNextToken(); + static_scalar(); + break; + case TokenNamearray: + getNextToken(); + if (token != TokenNameLPAREN) { + throwSyntaxError("'(' expected after keyword 'array'"); + } + getNextToken(); + if (token == TokenNameRPAREN) { + getNextToken(); + break; + } + non_empty_static_array_pair_list(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' or ',' expected after keyword 'array'"); + } + getNextToken(); + break; + // case TokenNamenull : + // getNextToken(); + // break; + // case TokenNamefalse : + // getNextToken(); + // break; + // case TokenNametrue : + // getNextToken(); + // break; + default: + throwSyntaxError("Static scalar/constant expected."); + } + } + + private void non_empty_static_array_pair_list() { + // non_empty_static_array_pair_list: + // non_empty_static_array_pair_list ',' static_scalar T_DOUBLE_ARROW + // static_scalar + // | non_empty_static_array_pair_list ',' static_scalar + // | static_scalar T_DOUBLE_ARROW static_scalar + // | static_scalar + while (true) { + static_scalar(); + if (token == TokenNameEQUAL_GREATER) { + getNextToken(); + static_scalar(); + } + if (token != TokenNameCOMMA) { + break; + } + getNextToken(); + if (token == TokenNameRPAREN) { + break; + } + } + } + + // public void reportSyntaxError() { //int act, int currentKind, int + // // stateStackTop) { + // /* remember current scanner position */ + // int startPos = scanner.startPosition; + // int currentPos = scanner.currentPosition; + // + // this.checkAndReportBracketAnomalies(problemReporter()); + // /* reset scanner where it was */ + // scanner.startPosition = startPos; + // scanner.currentPosition = currentPos; + // } + + public static final int RoundBracket = 0; + + public static final int SquareBracket = 1; + + public static final int CurlyBracket = 2; + + public static final int BracketKinds = 3; + + protected int[] nestedMethod; // the ptr is nestedType + + protected int nestedType, dimensions; + + // variable set stack + final static int VariableStackIncrement = 10; + + HashMap fTypeVariables = null; + + HashMap fMethodVariables = null; + + ArrayList fStackUnassigned = new ArrayList(); + + // ast stack + final static int AstStackIncrement = 100; + + protected int astPtr; + + protected ASTNode[] astStack = new ASTNode[AstStackIncrement]; + + protected int astLengthPtr; + + protected int[] astLengthStack; + + ASTNode[] noAstNodes = new ASTNode[AstStackIncrement]; + + public CompilationUnitDeclaration compilationUnit; /* + * the result from + * parse() + */ + + protected ReferenceContext referenceContext; + + protected ProblemReporter problemReporter; + + protected CompilerOptions options; + + private ArrayList includesList; + + // protected CompilationResult compilationResult; + /** + * Returns this parser's problem reporter initialized with its reference + * context. Also it is assumed that a problem is going to be reported, so + * initializes the compilation result's line positions. + */ + public ProblemReporter problemReporter() { + if (scanner.recordLineSeparator) { + compilationUnit.compilationResult.lineSeparatorPositions = scanner + .getLineEnds(); + } + problemReporter.referenceContext = referenceContext; + return problemReporter; + } + + /* + * Reconsider the entire source looking for inconsistencies in {} () [] + */ + // public boolean checkAndReportBracketAnomalies(ProblemReporter + // problemReporter) { + // scanner.wasAcr = false; + // boolean anomaliesDetected = false; + // try { + // char[] source = scanner.source; + // int[] leftCount = { 0, 0, 0 }; + // int[] rightCount = { 0, 0, 0 }; + // int[] depths = { 0, 0, 0 }; + // int[][] leftPositions = new int[][] { new int[10], new int[10], new + // int[10] + // }; + // int[][] leftDepths = new int[][] { new int[10], new int[10], new int[10] + // }; + // int[][] rightPositions = new int[][] { new int[10], new int[10], new + // int[10] }; + // int[][] rightDepths = new int[][] { new int[10], new int[10], new int[10] + // }; + // scanner.currentPosition = scanner.initialPosition; //starting + // // point + // // (first-zero-based + // // char) + // while (scanner.currentPosition < scanner.eofPosition) { //loop for + // // jumping + // // over + // // comments + // try { + // // ---------Consume white space and handles + // // startPosition--------- + // boolean isWhiteSpace; + // do { + // scanner.startPosition = scanner.currentPosition; + // // if (((scanner.currentCharacter = + // // source[scanner.currentPosition++]) == '\\') && + // // (source[scanner.currentPosition] == 'u')) { + // // isWhiteSpace = scanner.jumpOverUnicodeWhiteSpace(); + // // } else { + // if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || + // (scanner.currentCharacter == '\n'))) { + // if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) { + // // only record line positions we have not + // // recorded yet + // scanner.pushLineSeparator(); + // } + // } + // isWhiteSpace = CharOperation.isWhitespace(scanner.currentCharacter); + // // } + // } while (isWhiteSpace && (scanner.currentPosition < + // scanner.eofPosition)); + // // -------consume token until } is found--------- + // switch (scanner.currentCharacter) { + // case '{': { + // int index = leftCount[CurlyBracket]++; + // if (index == leftPositions[CurlyBracket].length) { + // System.arraycopy(leftPositions[CurlyBracket], 0, + // (leftPositions[CurlyBracket] = new int[index * 2]), 0, index); + // System.arraycopy(leftDepths[CurlyBracket], 0, (leftDepths[CurlyBracket] = + // new int[index * 2]), 0, index); + // } + // leftPositions[CurlyBracket][index] = scanner.startPosition; + // leftDepths[CurlyBracket][index] = depths[CurlyBracket]++; + // } + // break; + // case '}': { + // int index = rightCount[CurlyBracket]++; + // if (index == rightPositions[CurlyBracket].length) { + // System.arraycopy(rightPositions[CurlyBracket], 0, + // (rightPositions[CurlyBracket] = new int[index * 2]), 0, index); + // System.arraycopy(rightDepths[CurlyBracket], 0, (rightDepths[CurlyBracket] + // = + // new int[index * 2]), 0, index); + // } + // rightPositions[CurlyBracket][index] = scanner.startPosition; + // rightDepths[CurlyBracket][index] = --depths[CurlyBracket]; + // } + // break; + // case '(': { + // int index = leftCount[RoundBracket]++; + // if (index == leftPositions[RoundBracket].length) { + // System.arraycopy(leftPositions[RoundBracket], 0, + // (leftPositions[RoundBracket] = new int[index * 2]), 0, index); + // System.arraycopy(leftDepths[RoundBracket], 0, (leftDepths[RoundBracket] = + // new int[index * 2]), 0, index); + // } + // leftPositions[RoundBracket][index] = scanner.startPosition; + // leftDepths[RoundBracket][index] = depths[RoundBracket]++; + // } + // break; + // case ')': { + // int index = rightCount[RoundBracket]++; + // if (index == rightPositions[RoundBracket].length) { + // System.arraycopy(rightPositions[RoundBracket], 0, + // (rightPositions[RoundBracket] = new int[index * 2]), 0, index); + // System.arraycopy(rightDepths[RoundBracket], 0, (rightDepths[RoundBracket] + // = + // new int[index * 2]), 0, index); + // } + // rightPositions[RoundBracket][index] = scanner.startPosition; + // rightDepths[RoundBracket][index] = --depths[RoundBracket]; + // } + // break; + // case '[': { + // int index = leftCount[SquareBracket]++; + // if (index == leftPositions[SquareBracket].length) { + // System.arraycopy(leftPositions[SquareBracket], 0, + // (leftPositions[SquareBracket] = new int[index * 2]), 0, index); + // System.arraycopy(leftDepths[SquareBracket], 0, (leftDepths[SquareBracket] + // = + // new int[index * 2]), 0, index); + // } + // leftPositions[SquareBracket][index] = scanner.startPosition; + // leftDepths[SquareBracket][index] = depths[SquareBracket]++; + // } + // break; + // case ']': { + // int index = rightCount[SquareBracket]++; + // if (index == rightPositions[SquareBracket].length) { + // System.arraycopy(rightPositions[SquareBracket], 0, + // (rightPositions[SquareBracket] = new int[index * 2]), 0, index); + // System.arraycopy(rightDepths[SquareBracket], 0, + // (rightDepths[SquareBracket] + // = new int[index * 2]), 0, index); + // } + // rightPositions[SquareBracket][index] = scanner.startPosition; + // rightDepths[SquareBracket][index] = --depths[SquareBracket]; + // } + // break; + // case '\'': { + // if (scanner.getNextChar('\\')) { + // scanner.scanEscapeCharacter(); + // } else { // consume next character + // scanner.unicodeAsBackSlash = false; + // // if (((scanner.currentCharacter = + // // source[scanner.currentPosition++]) == + // // '\\') && + // // (source[scanner.currentPosition] == + // // 'u')) { + // // scanner.getNextUnicodeChar(); + // // } else { + // if (scanner.withoutUnicodePtr != 0) { + // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = + // scanner.currentCharacter; + // } + // // } + // } + // scanner.getNextChar('\''); + // break; + // } + // case '"': + // // consume next character + // scanner.unicodeAsBackSlash = false; + // // if (((scanner.currentCharacter = + // // source[scanner.currentPosition++]) == '\\') && + // // (source[scanner.currentPosition] == 'u')) { + // // scanner.getNextUnicodeChar(); + // // } else { + // if (scanner.withoutUnicodePtr != 0) { + // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = + // scanner.currentCharacter; + // } + // // } + // while (scanner.currentCharacter != '"') { + // if (scanner.currentCharacter == '\r') { + // if (source[scanner.currentPosition] == '\n') + // scanner.currentPosition++; + // break; // the string cannot go further that + // // the line + // } + // if (scanner.currentCharacter == '\n') { + // break; // the string cannot go further that + // // the line + // } + // if (scanner.currentCharacter == '\\') { + // scanner.scanEscapeCharacter(); + // } + // // consume next character + // scanner.unicodeAsBackSlash = false; + // // if (((scanner.currentCharacter = + // // source[scanner.currentPosition++]) == '\\') + // // && (source[scanner.currentPosition] == 'u')) + // // { + // // scanner.getNextUnicodeChar(); + // // } else { + // if (scanner.withoutUnicodePtr != 0) { + // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = + // scanner.currentCharacter; + // } + // // } + // } + // break; + // case '/': { + // int test; + // if ((test = scanner.getNextChar('/', '*')) == 0) { //line + // // comment + // //get the next char + // if (((scanner.currentCharacter = source[scanner.currentPosition++]) == + // '\\') + // && (source[scanner.currentPosition] == 'u')) { + // //-------------unicode traitement + // // ------------ + // int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + // scanner.currentPosition++; + // while (source[scanner.currentPosition] == 'u') { + // scanner.currentPosition++; + // } + // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 || c1 < 0 + // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c2 < 0 + // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c3 < 0 + // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c4 < 0) { //error + // // don't + // // care of the + // // value + // scanner.currentCharacter = 'A'; + // } //something different from \n and \r + // else { + // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + // } + // } + // while (scanner.currentCharacter != '\r' && scanner.currentCharacter != + // '\n') { + // //get the next char + // scanner.startPosition = scanner.currentPosition; + // if (((scanner.currentCharacter = source[scanner.currentPosition++]) == + // '\\') + // && (source[scanner.currentPosition] == 'u')) { + // //-------------unicode traitement + // // ------------ + // int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + // scanner.currentPosition++; + // while (source[scanner.currentPosition] == 'u') { + // scanner.currentPosition++; + // } + // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 || c1 < 0 + // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c2 < 0 + // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c3 < 0 + // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c4 < 0) { //error + // // don't + // // care of the + // // value + // scanner.currentCharacter = 'A'; + // } //something different from \n + // // and \r + // else { + // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + // } + // } + // } + // if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || + // (scanner.currentCharacter == '\n'))) { + // if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) { + // // only record line positions we + // // have not recorded yet + // scanner.pushLineSeparator(); + // if (this.scanner.taskTags != null) { + // this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(), + // this.scanner + // .getCurrentTokenEndPosition()); + // } + // } + // } + // break; + // } + // if (test > 0) { //traditional and annotation + // // comment + // boolean star = false; + // // consume next character + // scanner.unicodeAsBackSlash = false; + // // if (((scanner.currentCharacter = + // // source[scanner.currentPosition++]) == + // // '\\') && + // // (source[scanner.currentPosition] == + // // 'u')) { + // // scanner.getNextUnicodeChar(); + // // } else { + // if (scanner.withoutUnicodePtr != 0) { + // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = + // scanner.currentCharacter; + // } + // // } + // if (scanner.currentCharacter == '*') { + // star = true; + // } + // //get the next char + // if (((scanner.currentCharacter = source[scanner.currentPosition++]) == + // '\\') + // && (source[scanner.currentPosition] == 'u')) { + // //-------------unicode traitement + // // ------------ + // int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + // scanner.currentPosition++; + // while (source[scanner.currentPosition] == 'u') { + // scanner.currentPosition++; + // } + // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 || c1 < 0 + // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c2 < 0 + // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c3 < 0 + // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c4 < 0) { //error + // // don't + // // care of the + // // value + // scanner.currentCharacter = 'A'; + // } //something different from * and / + // else { + // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + // } + // } + // //loop until end of comment */ + // while ((scanner.currentCharacter != '/') || (!star)) { + // star = scanner.currentCharacter == '*'; + // //get next char + // if (((scanner.currentCharacter = source[scanner.currentPosition++]) == + // '\\') + // && (source[scanner.currentPosition] == 'u')) { + // //-------------unicode traitement + // // ------------ + // int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + // scanner.currentPosition++; + // while (source[scanner.currentPosition] == 'u') { + // scanner.currentPosition++; + // } + // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 || c1 < 0 + // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c2 < 0 + // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c3 < 0 + // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > + // 15 + // || c4 < 0) { //error + // // don't + // // care of the + // // value + // scanner.currentCharacter = 'A'; + // } //something different from * and + // // / + // else { + // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + // } + // } + // } + // if (this.scanner.taskTags != null) { + // this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(), + // this.scanner.getCurrentTokenEndPosition()); + // } + // break; + // } + // break; + // } + // default: + // if (Scanner.isPHPIdentifierStart(scanner.currentCharacter)) { + // scanner.scanIdentifierOrKeyword(false); + // break; + // } + // if (Character.isDigit(scanner.currentCharacter)) { + // scanner.scanNumber(false); + // break; + // } + // } + // //-----------------end switch while + // // try-------------------- + // } catch (IndexOutOfBoundsException e) { + // break; // read until EOF + // } catch (InvalidInputException e) { + // return false; // no clue + // } + // } + // if (scanner.recordLineSeparator) { + // compilationUnit.compilationResult.lineSeparatorPositions = + // scanner.getLineEnds(); + // } + // // check placement anomalies against other kinds of brackets + // for (int kind = 0; kind < BracketKinds; kind++) { + // for (int leftIndex = leftCount[kind] - 1; leftIndex >= 0; leftIndex--) { + // int start = leftPositions[kind][leftIndex]; // deepest + // // first + // // find matching closing bracket + // int depth = leftDepths[kind][leftIndex]; + // int end = -1; + // for (int i = 0; i < rightCount[kind]; i++) { + // int pos = rightPositions[kind][i]; + // // want matching bracket further in source with same + // // depth + // if ((pos > start) && (depth == rightDepths[kind][i])) { + // end = pos; + // break; + // } + // } + // if (end < 0) { // did not find a good closing match + // problemReporter.unmatchedBracket(start, referenceContext, + // compilationUnit.compilationResult); + // return true; + // } + // // check if even number of opening/closing other brackets + // // in between this pair of brackets + // int balance = 0; + // for (int otherKind = 0; (balance == 0) && (otherKind < BracketKinds); + // otherKind++) { + // for (int i = 0; i < leftCount[otherKind]; i++) { + // int pos = leftPositions[otherKind][i]; + // if ((pos > start) && (pos < end)) + // balance++; + // } + // for (int i = 0; i < rightCount[otherKind]; i++) { + // int pos = rightPositions[otherKind][i]; + // if ((pos > start) && (pos < end)) + // balance--; + // } + // if (balance != 0) { + // problemReporter.unmatchedBracket(start, referenceContext, + // compilationUnit.compilationResult); //bracket + // // anomaly + // return true; + // } + // } + // } + // // too many opening brackets ? + // for (int i = rightCount[kind]; i < leftCount[kind]; i++) { + // anomaliesDetected = true; + // problemReporter.unmatchedBracket(leftPositions[kind][leftCount[kind] - i + // - + // 1], referenceContext, + // compilationUnit.compilationResult); + // } + // // too many closing brackets ? + // for (int i = leftCount[kind]; i < rightCount[kind]; i++) { + // anomaliesDetected = true; + // problemReporter.unmatchedBracket(rightPositions[kind][i], + // referenceContext, + // compilationUnit.compilationResult); + // } + // if (anomaliesDetected) + // return true; + // } + // return anomaliesDetected; + // } catch (ArrayStoreException e) { // jdk1.2.2 jit bug + // return anomaliesDetected; + // } catch (NullPointerException e) { // jdk1.2.2 jit bug + // return anomaliesDetected; + // } + // } + protected void pushOnAstLengthStack(int pos) { + try { + astLengthStack[++astLengthPtr] = pos; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = astLengthStack.length; + int[] oldPos = astLengthStack; + astLengthStack = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength); + astLengthStack[astLengthPtr] = pos; + } + } + + protected void pushOnAstStack(ASTNode node) { + /* + * add a new obj on top of the ast stack + */ + try { + astStack[++astPtr] = node; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = astStack.length; + ASTNode[] oldStack = astStack; + astStack = new ASTNode[oldStackLength + AstStackIncrement]; + System.arraycopy(oldStack, 0, astStack, 0, oldStackLength); + astPtr = oldStackLength; + astStack[astPtr] = node; + } + try { + astLengthStack[++astLengthPtr] = 1; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = astLengthStack.length; + int[] oldPos = astLengthStack; + astLengthStack = new int[oldStackLength + AstStackIncrement]; + System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength); + astLengthStack[astLengthPtr] = 1; + } + } + + protected void resetModifiers() { + this.modifiers = AccDefault; + this.modifiersSourceStart = -1; // <-- see comment into + // modifiersFlag(int) + this.scanner.commentPtr = -1; + } + + protected void consumePackageDeclarationName(IFile file) { + // create a package name similar to java package names + String projectPath = ProjectPrefUtil.getDocumentRoot(file.getProject()) + .toString(); + String filePath = file.getRawLocation().toString(); + String ext = file.getRawLocation().getFileExtension(); + int fileExtensionLength = ext == null ? 0 : ext.length() + 1; + ImportReference impt; + char[][] tokens; + if (filePath.startsWith(projectPath)) { + tokens = CharOperation.splitOn('/', filePath.toCharArray(), + projectPath.length() + 1, filePath.length() + - fileExtensionLength); + } else { + String name = file.getName(); + tokens = new char[1][]; + tokens[0] = name.substring(0, name.length() - fileExtensionLength) + .toCharArray(); + } + + this.compilationUnit.currentPackage = impt = new ImportReference( + tokens, new char[0], 0, 0, true); + + impt.declarationSourceStart = 0; + impt.declarationSourceEnd = 0; + impt.declarationEnd = 0; + // endPosition is just before the ; + + } + + public final static String[] GLOBALS = { "$this", "$_COOKIE", "$_ENV", + "$_FILES", "$_GET", "$GLOBALS", "$_POST", "$_REQUEST", "$_SESSION", + "$_SERVER" }; + + /** + * + */ + private void pushFunctionVariableSet() { + HashSet set = new HashSet(); + if (fStackUnassigned.isEmpty()) { + for (int i = 0; i < GLOBALS.length; i++) { + set.add(GLOBALS[i]); + } + } + fStackUnassigned.add(set); + } + + private void pushIfVariableSet() { + if (!fStackUnassigned.isEmpty()) { + HashSet set = new HashSet(); + fStackUnassigned.add(set); + } + } + + private HashSet removeIfVariableSet() { + if (!fStackUnassigned.isEmpty()) { + return (HashSet) fStackUnassigned + .remove(fStackUnassigned.size() - 1); + } + return null; + } + + /** + * Returns the set of assigned variables returns null if no Set is + * defined at the current scanner position + */ + private HashSet peekVariableSet() { + if (!fStackUnassigned.isEmpty()) { + return (HashSet) fStackUnassigned.get(fStackUnassigned.size() - 1); + } + return null; + } + + /** + * add the current identifier source to the set of assigned variables + * + * + * @param set + */ + private void addVariableSet(HashSet set) { + if (set != null) { + set.add(new String(scanner.getCurrentTokenSource())); + } + } + + /** + * add the current identifier source to the set of assigned variables + * + * + */ + private void addVariableSet() { + HashSet set = peekVariableSet(); + if (set != null) { + set.add(new String(scanner.getCurrentTokenSource())); + } + } + + /** + * add the current identifier source to the set of assigned variables + * + * + */ + private void addVariableSet(char[] token) { + HashSet set = peekVariableSet(); + if (set != null) { + set.add(new String(token)); + } + } + + /** + * check if the current identifier source is in the set of assigned + * variables Returns true, if no set is defined for the current scanner + * position + * + */ + private boolean containsVariableSet() { + return containsVariableSet(scanner.getCurrentTokenSource()); + } + + private boolean containsVariableSet(char[] token) { + + if (!fStackUnassigned.isEmpty()) { + HashSet set; + String str = new String(token); + for (int i = 0; i < fStackUnassigned.size(); i++) { + set = (HashSet) fStackUnassigned.get(i); + if (set.contains(str)) { + return true; + } + } + return false; + } + return true; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/core/JavaModelManager.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/core/JavaModelManager.java new file mode 100644 index 0000000..b64d468 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/core/JavaModelManager.java @@ -0,0 +1,2482 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package net.sourceforge.phpdt.internal.core; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.zip.ZipFile; + +import net.sourceforge.phpdt.core.ElementChangedEvent; +import net.sourceforge.phpdt.core.IClasspathEntry; +import net.sourceforge.phpdt.core.ICompilationUnit; +import net.sourceforge.phpdt.core.IElementChangedListener; +import net.sourceforge.phpdt.core.IJavaElement; +import net.sourceforge.phpdt.core.IJavaElementDelta; +import net.sourceforge.phpdt.core.IJavaModel; +import net.sourceforge.phpdt.core.IJavaProject; +import net.sourceforge.phpdt.core.IPackageFragment; +import net.sourceforge.phpdt.core.IPackageFragmentRoot; +import net.sourceforge.phpdt.core.IParent; +import net.sourceforge.phpdt.core.IProblemRequestor; +import net.sourceforge.phpdt.core.IWorkingCopy; +import net.sourceforge.phpdt.core.JavaCore; +import net.sourceforge.phpdt.core.JavaModelException; +import net.sourceforge.phpdt.core.WorkingCopyOwner; +import net.sourceforge.phpdt.core.compiler.IProblem; +import net.sourceforge.phpdt.internal.core.builder.PHPBuilder; +import net.sourceforge.phpdt.internal.core.util.Util; +import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; + +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.resources.IResourceDelta; +import org.eclipse.core.resources.ISaveContext; +import org.eclipse.core.resources.ISaveParticipant; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceDescription; +import org.eclipse.core.resources.IWorkspaceRoot; +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.ISafeRunnable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Preferences; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.Preferences.PropertyChangeEvent; + +/** + * The JavaModelManager manages instances of + * IJavaModel. IElementChangedListeners register + * with the JavaModelManager, and receive + * ElementChangedEvents for all IJavaModels. + *

+ * The single instance of JavaModelManager is available from the + * static method JavaModelManager.getJavaModelManager(). + */ +public class JavaModelManager implements ISaveParticipant { + /** + * Unique handle onto the JavaModel + */ + final JavaModel javaModel = new JavaModel(); + + // public IndexManager indexManager = new IndexManager(); + /** + * Classpath variables pool + */ + public static HashMap Variables = new HashMap(5); + + public static HashMap PreviousSessionVariables = new HashMap(5); + + public static HashSet OptionNames = new HashSet(20); + + public final static String CP_VARIABLE_PREFERENCES_PREFIX = PHPeclipsePlugin.PLUGIN_ID + + ".classpathVariable."; //$NON-NLS-1$ + + public final static String CP_CONTAINER_PREFERENCES_PREFIX = PHPeclipsePlugin.PLUGIN_ID + + ".classpathContainer."; //$NON-NLS-1$ + + public final static String CP_ENTRY_IGNORE = "####"; //$NON-NLS-1$ + + /** + * Classpath containers pool + */ + public static HashMap containers = new HashMap(5); + + public static HashMap PreviousSessionContainers = new HashMap(5); + + /** + * Name of the extension point for contributing classpath variable + * initializers + */ + // public static final String CPVARIABLE_INITIALIZER_EXTPOINT_ID = + // "classpathVariableInitializer" ; //$NON-NLS-1$ + /** + * Name of the extension point for contributing classpath container + * initializers + */ + // public static final String CPCONTAINER_INITIALIZER_EXTPOINT_ID = + // "classpathContainerInitializer" ; //$NON-NLS-1$ + /** + * Name of the extension point for contributing a source code formatter + */ + public static final String FORMATTER_EXTPOINT_ID = "codeFormatter"; // $/** + + /** + * Value of the content-type for Java source files + */ + public static final String JAVA_SOURCE_CONTENT_TYPE = PHPeclipsePlugin.PLUGIN_ID + + ".phpSource"; //$NON-NLS-1$NON-NLS-1$ + + /** + * Special value used for recognizing ongoing initialization and breaking + * initialization cycles + */ + public final static IPath VariableInitializationInProgress = new Path( + "Variable Initialization In Progress"); //$NON-NLS-1$ + // public final static IClasspathContainer ContainerInitializationInProgress + // = new IClasspathContainer() { + // public IClasspathEntry[] getClasspathEntries() { return null; } + // public String getDescription() { return "Container Initialization In + // Progress"; } //$NON-NLS-1$ + // public int getKind() { return 0; } + // public IPath getPath() { return null; } + // public String toString() { return getDescription(); } + // }; + + private static final String INDEX_MANAGER_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/indexmanager"; //$NON-NLS-1$ + + private static final String COMPILER_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/compiler"; //$NON-NLS-1$ + + private static final String JAVAMODEL_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/javamodel"; //$NON-NLS-1$ + + private static final String CP_RESOLVE_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/cpresolution"; //$NON-NLS-1$ + + private static final String ZIP_ACCESS_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/zipaccess"; //$NON-NLS-1$ + + private static final String DELTA_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/javadelta"; //$NON-NLS-1$ + + private static final String HIERARCHY_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/hierarchy"; //$NON-NLS-1$ + + private static final String POST_ACTION_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/postaction"; //$NON-NLS-1$ + + private static final String BUILDER_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/builder"; //$NON-NLS-1$ + + private static final String COMPLETION_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/completion"; //$NON-NLS-1$ + + private static final String SELECTION_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/selection"; //$NON-NLS-1$ + + private static final String SHARED_WC_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/sharedworkingcopy"; //$NON-NLS-1$ + + private static final String SEARCH_DEBUG = PHPeclipsePlugin.PLUGIN_ID + + "/debug/search"; //$NON-NLS-1$ + + public final static IWorkingCopy[] NoWorkingCopy = new IWorkingCopy[0]; + + /** + * Table from WorkingCopyOwner to a table of ICompilationUnit (working copy + * handle) to PerWorkingCopyInfo. NOTE: this object itself is used as a lock + * to synchronize creation/removal of per working copy infos + */ + protected Map perWorkingCopyInfos = new HashMap(5); + + /** + * Returns whether the given full path (for a package) conflicts with the + * output location of the given project. + */ + public static boolean conflictsWithOutputLocation(IPath folderPath, + JavaProject project) { + try { + IPath outputLocation = project.getOutputLocation(); + if (outputLocation == null) { + // in doubt, there is a conflict + return true; + } + if (outputLocation.isPrefixOf(folderPath)) { + // only allow nesting in project's output if there is a + // corresponding source folder + // or if the project's output is not used (in other words, if + // all source folders have their custom output) + IClasspathEntry[] classpath = project + .getResolvedClasspath(true); + boolean isOutputUsed = false; + for (int i = 0, length = classpath.length; i < length; i++) { + IClasspathEntry entry = classpath[i]; + if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { + if (entry.getPath().equals(outputLocation)) { + return false; + } + if (entry.getOutputLocation() == null) { + isOutputUsed = true; + } + } + } + return isOutputUsed; + } + return false; + } catch (JavaModelException e) { + // in doubt, there is a conflict + return true; + } + } + + // public static IClasspathContainer containerGet(IJavaProject project, + // IPath containerPath) { + // Map projectContainers = (Map)Containers.get(project); + // if (projectContainers == null){ + // return null; + // } + // IClasspathContainer container = + // (IClasspathContainer)projectContainers.get(containerPath); + // return container; + // } + + // public static void containerPut(IJavaProject project, IPath + // containerPath, IClasspathContainer container){ + // + // Map projectContainers = (Map)Containers.get(project); + // if (projectContainers == null){ + // projectContainers = new HashMap(1); + // Containers.put(project, projectContainers); + // } + // + // if (container == null) { + // projectContainers.remove(containerPath); + // Map previousContainers = (Map)PreviousSessionContainers.get(project); + // if (previousContainers != null){ + // previousContainers.remove(containerPath); + // } + // } else { + // projectContainers.put(containerPath, container); + // } + // + // // do not write out intermediate initialization value + // if (container == JavaModelManager.ContainerInitializationInProgress) { + // return; + // } + // Preferences preferences = + // PHPeclipsePlugin.getPlugin().getPluginPreferences(); + // String containerKey = + // CP_CONTAINER_PREFERENCES_PREFIX+project.getElementName() + // +"|"+containerPath;//$NON-NLS-1$ + // String containerString = CP_ENTRY_IGNORE; + // try { + // if (container != null) { + // containerString = + // ((JavaProject)project).encodeClasspath(container.getClasspathEntries(), + // null, false); + // } + // } catch(JavaModelException e){ + // } + // preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use this + // default to get rid of removed ones + // preferences.setValue(containerKey, containerString); + // PHPeclipsePlugin.getPlugin().savePluginPreferences(); + // } + + /** + * Returns the Java element corresponding to the given resource, or + * null if unable to associate the given resource with a Java + * element. + *

+ * The resource must be one of: + *

    + *
  • a project - the element returned is the corresponding + * IJavaProject
  • + *
  • a .java file - the element returned is the + * corresponding ICompilationUnit
  • + *
  • a .class file - the element returned is the + * corresponding IClassFile
  • + *
  • a .jar file - the element returned is the + * corresponding IPackageFragmentRoot
  • + *
  • a folder - the element returned is the corresponding + * IPackageFragmentRoot or IPackageFragment
  • + *
  • the workspace root resource - the element returned is the + * IJavaModel
  • + *
+ *

+ * Creating a Java element has the side effect of creating and opening all + * of the element's parents if they are not yet open. + */ + public static IJavaElement create(IResource resource, IJavaProject project) { + if (resource == null) { + return null; + } + int type = resource.getType(); + switch (type) { + case IResource.PROJECT: + return JavaCore.create((IProject) resource); + case IResource.FILE: + return create((IFile) resource, project); + case IResource.FOLDER: + return create((IFolder) resource, project); + case IResource.ROOT: + return JavaCore.create((IWorkspaceRoot) resource); + default: + return null; + } + } + + /** + * Returns the Java element corresponding to the given file, its project + * being the given project. Returns null if unable to + * associate the given file with a Java element. + * + *

+ * The file must be one of: + *

    + *
  • a .java file - the element returned is the + * corresponding ICompilationUnit
  • + *
  • a .class file - the element returned is the + * corresponding IClassFile
  • + *
  • a .jar file - the element returned is the + * corresponding IPackageFragmentRoot
  • + *
+ *

+ * Creating a Java element has the side effect of creating and opening all + * of the element's parents if they are not yet open. + */ + public static IJavaElement create(IFile file, IJavaProject project) { + if (file == null) { + return null; + } + if (project == null) { + project = JavaCore.create(file.getProject()); + } + + if (file.getFileExtension() != null) { + String name = file.getName(); + if (PHPFileUtil.isValidPHPUnitName(name)) + // if (PHPFileUtil.isPHPFile(file)) + return createCompilationUnitFrom(file, project); + // if (ProjectPrefUtil.isValidClassFileName(name)) + // return createClassFileFrom(file, project); + // if (ProjectPrefUtil.isArchiveFileName(name)) + // return createJarPackageFragmentRootFrom(file, project); + } + return null; + } + + /** + * Returns the package fragment or package fragment root corresponding to + * the given folder, its parent or great parent being the given project. or + * null if unable to associate the given folder with a Java + * element. + *

+ * Note that a package fragment root is returned rather than a default + * package. + *

+ * Creating a Java element has the side effect of creating and opening all + * of the element's parents if they are not yet open. + */ + public static IJavaElement create(IFolder folder, IJavaProject project) { + if (folder == null) { + return null; + } + if (project == null) { + project = JavaCore.create(folder.getProject()); + } + IJavaElement element = determineIfOnClasspath(folder, project); + if (conflictsWithOutputLocation(folder.getFullPath(), + (JavaProject) project) + || (folder.getName().indexOf('.') >= 0 && !(element instanceof IPackageFragmentRoot))) { + return null; // only package fragment roots are allowed with dot + // names + } else { + return element; + } + } + + /** + * Creates and returns a class file element for the given + * .class file, its project being the given project. Returns + * null if unable to recognize the class file. + */ + // public static IClassFile createClassFileFrom(IFile file, IJavaProject + // project ) { + // if (file == null) { + // return null; + // } + // if (project == null) { + // project = PHPCore.create(file.getProject()); + // } + // IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, + // project); + // if (pkg == null) { + // // fix for 1FVS7WE + // // not on classpath - make the root its folder, and a default package + // IPackageFragmentRoot root = + // project.getPackageFragmentRoot(file.getParent()); + // pkg = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME); + // } + // return pkg.getClassFile(file.getName()); + // } + /** + * Creates and returns a compilation unit element for the given + * .java file, its project being the given project. Returns + * null if unable to recognize the compilation unit. + */ + public static ICompilationUnit createCompilationUnitFrom(IFile file, + IJavaProject project) { + + if (file == null) + return null; + + if (project == null) { + project = JavaCore.create(file.getProject()); + } + IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, + project); + if (pkg == null) { + // not on classpath - make the root its folder, and a default + // package + IPackageFragmentRoot root = project.getPackageFragmentRoot(file + .getParent()); + pkg = root + .getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME); + + if (VERBOSE) { + System.out + .println("WARNING : creating unit element outside classpath (" + Thread.currentThread() + "): " + file.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$ + } + } + return pkg.getCompilationUnit(file.getName()); + } + + /** + * Creates and returns a handle for the given JAR file, its project being + * the given project. The Java model associated with the JAR's project may + * be created as a side effect. Returns null if unable to + * create a JAR package fragment root. (for example, if the JAR file + * represents a non-Java resource) + */ + // public static IPackageFragmentRoot createJarPackageFragmentRootFrom(IFile + // file, IJavaProject project) { + // if (file == null) { + // return null; + // } + // if (project == null) { + // project = PHPCore.create(file.getProject()); + // } + // + // // Create a jar package fragment root only if on the classpath + // IPath resourcePath = file.getFullPath(); + // try { + // IClasspathEntry[] entries = + // ((JavaProject)project).getResolvedClasspath(true); + // for (int i = 0, length = entries.length; i < length; i++) { + // IClasspathEntry entry = entries[i]; + // IPath rootPath = entry.getPath(); + // if (rootPath.equals(resourcePath)) { + // return project.getPackageFragmentRoot(file); + // } + // } + // } catch (JavaModelException e) { + // } + // return null; + // } + /** + * Returns the package fragment root represented by the resource, or the + * package fragment the given resource is located in, or null + * if the given resource is not on the classpath of the given project. + */ + public static IJavaElement determineIfOnClasspath(IResource resource, + IJavaProject project) { + + IPath resourcePath = resource.getFullPath(); + try { + IClasspathEntry[] entries = net.sourceforge.phpdt.internal.compiler.util.Util + .isJavaFileName(resourcePath.lastSegment()) ? project + .getRawClasspath() // JAVA file can only live inside SRC + // folder (on the raw path) + : ((JavaProject) project).getResolvedClasspath(true); + + for (int i = 0; i < entries.length; i++) { + IClasspathEntry entry = entries[i]; + if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) + continue; + IPath rootPath = entry.getPath(); + if (rootPath.equals(resourcePath)) { + return project.getPackageFragmentRoot(resource); + } else if (rootPath.isPrefixOf(resourcePath) + && !Util.isExcluded(resource, null, + ((ClasspathEntry) entry) + .fullExclusionPatternChars())) { + // given we have a resource child of the root, it cannot be + // a JAR pkg root + IPackageFragmentRoot root = ((JavaProject) project) + .getFolderPackageFragmentRoot(rootPath); + if (root == null) + return null; + IPath pkgPath = resourcePath.removeFirstSegments(rootPath + .segmentCount()); + if (resource.getType() == IResource.FILE) { + // if the resource is a file, then remove the last + // segment which + // is the file name in the package + pkgPath = pkgPath.removeLastSegments(1); + + // don't check validity of package name (see + // http://bugs.eclipse.org/bugs/show_bug.cgi?id=26706) + // String pkgName = pkgPath.toString().replace('/', + // '.'); + String pkgName = pkgPath.toString(); + return root.getPackageFragment(pkgName); + } else { + String pkgName = Util.packageName(pkgPath); + if (pkgName == null) {// || + // JavaConventions.validatePackageName(pkgName).getSeverity() + // == IStatus.ERROR) { + return null; + } + return root.getPackageFragment(pkgName); + } + } + } + } catch (JavaModelException npe) { + return null; + } + return null; + } + + /** + * The singleton manager + */ + private final static JavaModelManager Manager = new JavaModelManager(); + + /** + * Infos cache. + */ + protected JavaModelCache cache = new JavaModelCache(); + + /* + * Temporary cache of newly opened elements + */ + private ThreadLocal temporaryCache = new ThreadLocal(); + + /** + * Set of elements which are out of sync with their buffers. + */ + protected Map elementsOutOfSynchWithBuffers = new HashMap(11); + + /** + * Holds the state used for delta processing. + */ + public DeltaProcessingState deltaState = new DeltaProcessingState(); + + /** + * Turns delta firing on/off. By default it is on. + */ + private boolean isFiring = true; + + /** + * Queue of deltas created explicily by the Java Model that have yet to be + * fired. + */ + ArrayList javaModelDeltas = new ArrayList(); + + /** + * Queue of reconcile deltas on working copies that have yet to be fired. + * This is a table form IWorkingCopy to IJavaElementDelta + */ + HashMap reconcileDeltas = new HashMap(); + + /** + * Collection of listeners for Java element deltas + */ + private IElementChangedListener[] elementChangedListeners = new IElementChangedListener[5]; + + private int[] elementChangedListenerMasks = new int[5]; + + private int elementChangedListenerCount = 0; + + public int currentChangeEventType = ElementChangedEvent.PRE_AUTO_BUILD; + + public static final int DEFAULT_CHANGE_EVENT = 0; // must not collide with + // ElementChangedEvent + // event masks + + /** + * Used to convert IResourceDeltas into + * IJavaElementDeltas. + */ + // public final DeltaProcessor deltaProcessor = new DeltaProcessor(this); + /** + * Used to update the JavaModel for IJavaElementDeltas. + */ + private final ModelUpdater modelUpdater = new ModelUpdater(); + + /** + * Workaround for bug 15168 circular errors not reported This is a cache of + * the projects before any project addition/deletion has started. + */ + public IJavaProject[] javaProjectsCache; + + /** + * Table from IProject to PerProjectInfo. NOTE: this object itself is used + * as a lock to synchronize creation/removal of per project infos + */ + protected Map perProjectInfo = new HashMap(5); + + /** + * A map from ICompilationUnit to IWorkingCopy of the shared working copies. + */ + public Map sharedWorkingCopies = new HashMap(); + + /** + * A weak set of the known scopes. + */ + protected WeakHashMap searchScopes = new WeakHashMap(); + + // public static class PerProjectInfo { + // public IProject project; + // public Object savedState; + // public boolean triedRead; + // public IClasspathEntry[] classpath; + // public IClasspathEntry[] lastResolvedClasspath; + // public Map resolvedPathToRawEntries; // reverse map from resolved path to + // raw entries + // public IPath outputLocation; + // public Preferences preferences; + // public PerProjectInfo(IProject project) { + // + // this.triedRead = false; + // this.savedState = null; + // this.project = project; + // } + // } + + public static class PerProjectInfo { + + public IProject project; + + public Object savedState; + + public boolean triedRead; + + public IClasspathEntry[] rawClasspath; + + public IClasspathEntry[] resolvedClasspath; + + public Map resolvedPathToRawEntries; // reverse map from resolved + // path to raw entries + + public IPath outputLocation; + + public Preferences preferences; + + public PerProjectInfo(IProject project) { + + this.triedRead = false; + this.savedState = null; + this.project = project; + } + + // updating raw classpath need to flush obsoleted cached information + // about resolved entries + public synchronized void updateClasspathInformation( + IClasspathEntry[] newRawClasspath) { + + this.rawClasspath = newRawClasspath; + this.resolvedClasspath = null; + this.resolvedPathToRawEntries = null; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("Info for "); //$NON-NLS-1$ + buffer.append(this.project.getFullPath()); + buffer.append("\nRaw classpath:\n"); //$NON-NLS-1$ + if (this.rawClasspath == null) { + buffer.append(" \n"); //$NON-NLS-1$ + } else { + for (int i = 0, length = this.rawClasspath.length; i < length; i++) { + buffer.append(" "); //$NON-NLS-1$ + buffer.append(this.rawClasspath[i]); + buffer.append('\n'); + } + } + buffer.append("Resolved classpath:\n"); //$NON-NLS-1$ + IClasspathEntry[] resolvedCP = this.resolvedClasspath; + if (resolvedCP == null) { + buffer.append(" \n"); //$NON-NLS-1$ + } else { + for (int i = 0, length = resolvedCP.length; i < length; i++) { + buffer.append(" "); //$NON-NLS-1$ + buffer.append(resolvedCP[i]); + buffer.append('\n'); + } + } + buffer.append("Output location:\n "); //$NON-NLS-1$ + if (this.outputLocation == null) { + buffer.append(""); //$NON-NLS-1$ + } else { + buffer.append(this.outputLocation); + } + return buffer.toString(); + } + } + + public static class PerWorkingCopyInfo implements IProblemRequestor { + int useCount = 0; + + IProblemRequestor problemRequestor; + + ICompilationUnit workingCopy; + + public PerWorkingCopyInfo(ICompilationUnit workingCopy, + IProblemRequestor problemRequestor) { + this.workingCopy = workingCopy; + this.problemRequestor = problemRequestor; + } + + public void acceptProblem(IProblem problem) { + if (this.problemRequestor == null) + return; + this.problemRequestor.acceptProblem(problem); + } + + public void beginReporting() { + if (this.problemRequestor == null) + return; + this.problemRequestor.beginReporting(); + } + + public void endReporting() { + if (this.problemRequestor == null) + return; + this.problemRequestor.endReporting(); + } + + public ICompilationUnit getWorkingCopy() { + return this.workingCopy; + } + + public boolean isActive() { + return this.problemRequestor != null + && this.problemRequestor.isActive(); + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("Info for "); //$NON-NLS-1$ + buffer.append(((JavaElement) workingCopy).toStringWithAncestors()); + buffer.append("\nUse count = "); //$NON-NLS-1$ + buffer.append(this.useCount); + buffer.append("\nProblem requestor:\n "); //$NON-NLS-1$ + buffer.append(this.problemRequestor); + return buffer.toString(); + } + } + + public static boolean VERBOSE = false; + + public static boolean CP_RESOLVE_VERBOSE = false; + + public static boolean ZIP_ACCESS_VERBOSE = false; + + /** + * A cache of opened zip files per thread. (map from Thread to map of IPath + * to java.io.ZipFile) NOTE: this object itself is used as a lock to + * synchronize creation/removal of entries + */ + private HashMap zipFiles = new HashMap(); + + /** + * Update the classpath variable cache + */ + public static class PluginPreferencesListener implements + Preferences.IPropertyChangeListener { + /** + * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(PropertyChangeEvent) + */ + public void propertyChange(Preferences.PropertyChangeEvent event) { + // TODO : jsurfer temp-del + // String propertyName = event.getProperty(); + // if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)) { + // String varName = + // propertyName.substring(CP_VARIABLE_PREFERENCES_PREFIX.length()); + // String newValue = (String)event.getNewValue(); + // if (newValue != null && !(newValue = + // newValue.trim()).equals(CP_ENTRY_IGNORE)) { + // Variables.put(varName, new Path(newValue)); + // } else { + // Variables.remove(varName); + // } + // } + // if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) { + // recreatePersistedContainer(propertyName, + // (String)event.getNewValue(), false); + // } + } + } + + /** + * Line separator to use throughout the JavaModel for any source edit + * operation + */ + public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$ + + /** + * Constructs a new JavaModelManager + */ + private JavaModelManager() { + } + + /** + * @deprecated - discard once debug has converted to not using it + */ + public void addElementChangedListener(IElementChangedListener listener) { + this.addElementChangedListener(listener, + ElementChangedEvent.POST_CHANGE + | ElementChangedEvent.POST_RECONCILE); + } + + /** + * addElementChangedListener method comment. Need to clone defensively the + * listener information, in case some listener is reacting to some + * notification iteration by adding/changing/removing any of the other (for + * example, if it deregisters itself). + */ + public void addElementChangedListener(IElementChangedListener listener, + int eventMask) { + for (int i = 0; i < this.elementChangedListenerCount; i++) { + if (this.elementChangedListeners[i].equals(listener)) { + + // only clone the masks, since we could be in the middle of + // notifications and one listener decide to change + // any event mask of another listeners (yet not notified). + int cloneLength = this.elementChangedListenerMasks.length; + System + .arraycopy( + this.elementChangedListenerMasks, + 0, + this.elementChangedListenerMasks = new int[cloneLength], + 0, cloneLength); + this.elementChangedListenerMasks[i] = eventMask; // could be + // different + return; + } + } + // may need to grow, no need to clone, since iterators will have cached + // original arrays and max boundary and we only add to the end. + int length; + if ((length = this.elementChangedListeners.length) == this.elementChangedListenerCount) { + System + .arraycopy( + this.elementChangedListeners, + 0, + this.elementChangedListeners = new IElementChangedListener[length * 2], + 0, length); + System.arraycopy(this.elementChangedListenerMasks, 0, + this.elementChangedListenerMasks = new int[length * 2], 0, + length); + } + this.elementChangedListeners[this.elementChangedListenerCount] = listener; + this.elementChangedListenerMasks[this.elementChangedListenerCount] = eventMask; + this.elementChangedListenerCount++; + } + + /** + * Starts caching ZipFiles. Ignores if there are already clients. + */ + public void cacheZipFiles() { + synchronized (this.zipFiles) { + Thread currentThread = Thread.currentThread(); + if (this.zipFiles.get(currentThread) != null) + return; + this.zipFiles.put(currentThread, new HashMap()); + } + } + + public void closeZipFile(ZipFile zipFile) { + if (zipFile == null) + return; + synchronized (this.zipFiles) { + if (this.zipFiles.get(Thread.currentThread()) != null) { + return; // zip file will be closed by call to flushZipFiles + } + try { + if (JavaModelManager.ZIP_ACCESS_VERBOSE) { + System.out + .println("(" + Thread.currentThread() + ") [JavaModelManager.closeZipFile(ZipFile)] Closing ZipFile on " + zipFile.getName()); //$NON-NLS-1$ //$NON-NLS-2$ + } + zipFile.close(); + } catch (IOException e) { + } + } + } + + /** + * Configure the plugin with respect to option settings defined in + * ".options" file + */ + public void configurePluginDebugOptions() { + if (JavaCore.getPlugin().isDebugging()) { + // TODO jsurfer temp-del + + String option = Platform.getDebugOption(BUILDER_DEBUG); + // if(option != null) JavaBuilder.DEBUG = + // option.equalsIgnoreCase("true") ; //$NON-NLS-1$ + // + // option = Platform.getDebugOption(COMPILER_DEBUG); + // if(option != null) Compiler.DEBUG = + // option.equalsIgnoreCase("true") ; //$NON-NLS-1$ + // + // option = Platform.getDebugOption(COMPLETION_DEBUG); + // if(option != null) CompletionEngine.DEBUG = + // option.equalsIgnoreCase("true") ; //$NON-NLS-1$ + // + option = Platform.getDebugOption(CP_RESOLVE_DEBUG); + if (option != null) + JavaModelManager.CP_RESOLVE_VERBOSE = option + .equalsIgnoreCase("true"); //$NON-NLS-1$ + + option = Platform.getDebugOption(DELTA_DEBUG); + if (option != null) + DeltaProcessor.VERBOSE = option.equalsIgnoreCase("true"); //$NON-NLS-1$ + + // option = Platform.getDebugOption(HIERARCHY_DEBUG); + // if(option != null) TypeHierarchy.DEBUG = + // option.equalsIgnoreCase("true") ; //$NON-NLS-1$ + // + // option = Platform.getDebugOption(INDEX_MANAGER_DEBUG); + // if(option != null) IndexManager.VERBOSE = + // option.equalsIgnoreCase("true") ; //$NON-NLS-1$ + + option = Platform.getDebugOption(JAVAMODEL_DEBUG); + if (option != null) + JavaModelManager.VERBOSE = option.equalsIgnoreCase("true"); //$NON-NLS-1$ + + option = Platform.getDebugOption(POST_ACTION_DEBUG); + if (option != null) + JavaModelOperation.POST_ACTION_VERBOSE = option + .equalsIgnoreCase("true"); //$NON-NLS-1$ + + // option = Platform.getDebugOption(SEARCH_DEBUG); + // if(option != null) SearchEngine.VERBOSE = + // option.equalsIgnoreCase("true") ; //$NON-NLS-1$ + // + // option = Platform.getDebugOption(SELECTION_DEBUG); + // if(option != null) SelectionEngine.DEBUG = + // option.equalsIgnoreCase("true") ; //$NON-NLS-1$ + + option = Platform.getDebugOption(ZIP_ACCESS_DEBUG); + if (option != null) + JavaModelManager.ZIP_ACCESS_VERBOSE = option + .equalsIgnoreCase("true"); //$NON-NLS-1$ + } + } + + /* + * Discards the per working copy info for the given working copy (making it + * a compilation unit) if its use count was 1. Otherwise, just decrement the + * use count. If the working copy is primary, computes the delta between its + * state and the original compilation unit and register it. Close the + * working copy, its buffer and remove it from the shared working copy + * table. Ignore if no per-working copy info existed. NOTE: it must be + * synchronized as it may interact with the element info cache (if useCount + * is decremented to 0), see bug 50667. Returns the new use count (or -1 if + * it didn't exist). + */ + public synchronized int discardPerWorkingCopyInfo( + CompilationUnit workingCopy) throws JavaModelException { + synchronized (perWorkingCopyInfos) { + WorkingCopyOwner owner = workingCopy.owner; + Map workingCopyToInfos = (Map) this.perWorkingCopyInfos.get(owner); + if (workingCopyToInfos == null) + return -1; + + PerWorkingCopyInfo info = (PerWorkingCopyInfo) workingCopyToInfos + .get(workingCopy); + if (info == null) + return -1; + + if (--info.useCount == 0) { + // create the delta builder (this remembers the current content + // of the working copy) + JavaElementDeltaBuilder deltaBuilder = null; + if (workingCopy.isPrimary()) { + deltaBuilder = new JavaElementDeltaBuilder(workingCopy); + } + + // remove per working copy info + workingCopyToInfos.remove(workingCopy); + if (workingCopyToInfos.isEmpty()) { + this.perWorkingCopyInfos.remove(owner); + } + + // remove infos + close buffer (since no longer working copy) + removeInfoAndChildren(workingCopy); + workingCopy.closeBuffer(); + + // compute the delta if needed and register it if there are + // changes + if (deltaBuilder != null) { + deltaBuilder.buildDeltas(); + if ((deltaBuilder.delta != null) + && (deltaBuilder.delta.getAffectedChildren().length > 0)) { + getDeltaProcessor().registerJavaModelDelta( + deltaBuilder.delta); + } + } + + } + return info.useCount; + } + } + + /** + * @see ISaveParticipant + */ + public void doneSaving(ISaveContext context) { + } + + /** + * Fire Java Model delta, flushing them after the fact after post_change + * notification. If the firing mode has been turned off, this has no effect. + */ + public void fire(IJavaElementDelta customDelta, int eventType) { + + if (!this.isFiring) + return; + + if (DeltaProcessor.VERBOSE + && (eventType == DEFAULT_CHANGE_EVENT || eventType == ElementChangedEvent.PRE_AUTO_BUILD)) { + System.out + .println("-----------------------------------------------------------------------------------------------------------------------");//$NON-NLS-1$ + } + + IJavaElementDelta deltaToNotify; + if (customDelta == null) { + deltaToNotify = this.mergeDeltas(this.javaModelDeltas); + } else { + deltaToNotify = customDelta; + } + + // Refresh internal scopes + if (deltaToNotify != null) { + // TODO temp-del + // Iterator scopes = this.scopes.keySet().iterator(); + // while (scopes.hasNext()) { + // AbstractSearchScope scope = (AbstractSearchScope)scopes.next(); + // scope.processDelta(deltaToNotify); + // } + } + + // Notification + + // Important: if any listener reacts to notification by updating the + // listeners list or mask, these lists will + // be duplicated, so it is necessary to remember original lists in a + // variable (since field values may change under us) + IElementChangedListener[] listeners = this.elementChangedListeners; + int[] listenerMask = this.elementChangedListenerMasks; + int listenerCount = this.elementChangedListenerCount; + + switch (eventType) { + case DEFAULT_CHANGE_EVENT: + firePreAutoBuildDelta(deltaToNotify, listeners, listenerMask, + listenerCount); + firePostChangeDelta(deltaToNotify, listeners, listenerMask, + listenerCount); + fireReconcileDelta(listeners, listenerMask, listenerCount); + break; + case ElementChangedEvent.PRE_AUTO_BUILD: + firePreAutoBuildDelta(deltaToNotify, listeners, listenerMask, + listenerCount); + break; + case ElementChangedEvent.POST_CHANGE: + firePostChangeDelta(deltaToNotify, listeners, listenerMask, + listenerCount); + fireReconcileDelta(listeners, listenerMask, listenerCount); + break; + } + + } + + private void firePreAutoBuildDelta(IJavaElementDelta deltaToNotify, + IElementChangedListener[] listeners, int[] listenerMask, + int listenerCount) { + + if (DeltaProcessor.VERBOSE) { + System.out + .println("FIRING PRE_AUTO_BUILD Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$ + System.out + .println(deltaToNotify == null ? "" : deltaToNotify.toString()); //$NON-NLS-1$ + } + if (deltaToNotify != null) { + notifyListeners(deltaToNotify, ElementChangedEvent.PRE_AUTO_BUILD, + listeners, listenerMask, listenerCount); + } + } + + private void firePostChangeDelta(IJavaElementDelta deltaToNotify, + IElementChangedListener[] listeners, int[] listenerMask, + int listenerCount) { + + // post change deltas + if (DeltaProcessor.VERBOSE) { + System.out + .println("FIRING POST_CHANGE Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$ + System.out + .println(deltaToNotify == null ? "" : deltaToNotify.toString()); //$NON-NLS-1$ + } + if (deltaToNotify != null) { + // flush now so as to keep listener reactions to post their own + // deltas for subsequent iteration + this.flush(); + + notifyListeners(deltaToNotify, ElementChangedEvent.POST_CHANGE, + listeners, listenerMask, listenerCount); + } + } + + private void fireReconcileDelta(IElementChangedListener[] listeners, + int[] listenerMask, int listenerCount) { + + IJavaElementDelta deltaToNotify = mergeDeltas(this.reconcileDeltas + .values()); + if (DeltaProcessor.VERBOSE) { + System.out + .println("FIRING POST_RECONCILE Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$ + System.out + .println(deltaToNotify == null ? "" : deltaToNotify.toString()); //$NON-NLS-1$ + } + if (deltaToNotify != null) { + // flush now so as to keep listener reactions to post their own + // deltas for subsequent iteration + this.reconcileDeltas = new HashMap(); + + notifyListeners(deltaToNotify, ElementChangedEvent.POST_RECONCILE, + listeners, listenerMask, listenerCount); + } + } + + public void notifyListeners(IJavaElementDelta deltaToNotify, int eventType, + IElementChangedListener[] listeners, int[] listenerMask, + int listenerCount) { + final ElementChangedEvent extraEvent = new ElementChangedEvent( + deltaToNotify, eventType); + for (int i = 0; i < listenerCount; i++) { + if ((listenerMask[i] & eventType) != 0) { + final IElementChangedListener listener = listeners[i]; + long start = -1; + if (DeltaProcessor.VERBOSE) { + System.out + .print("Listener #" + (i + 1) + "=" + listener.toString());//$NON-NLS-1$//$NON-NLS-2$ + start = System.currentTimeMillis(); + } + // wrap callbacks with Safe runnable for subsequent listeners to + // be called when some are causing grief + Platform.run(new ISafeRunnable() { + public void handleException(Throwable exception) { + Util + .log(exception, + "Exception occurred in listener of Java element change notification"); //$NON-NLS-1$ + } + + public void run() throws Exception { + listener.elementChanged(extraEvent); + } + }); + if (DeltaProcessor.VERBOSE) { + System.out + .println(" -> " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } + } + + /** + * Flushes all deltas without firing them. + */ + protected void flush() { + this.javaModelDeltas = new ArrayList(); + } + + /** + * Flushes ZipFiles cache if there are no more clients. + */ + public void flushZipFiles() { + synchronized (this.zipFiles) { + Thread currentThread = Thread.currentThread(); + HashMap map = (HashMap) this.zipFiles.remove(currentThread); + if (map == null) + return; + Iterator iterator = map.values().iterator(); + while (iterator.hasNext()) { + try { + ZipFile zipFile = (ZipFile) iterator.next(); + if (JavaModelManager.ZIP_ACCESS_VERBOSE) { + System.out + .println("(" + currentThread + ") [JavaModelManager.flushZipFiles()] Closing ZipFile on " + zipFile.getName()); //$NON-NLS-1$//$NON-NLS-2$ + } + zipFile.close(); + } catch (IOException e) { + } + } + } + } + + public DeltaProcessor getDeltaProcessor() { + return this.deltaState.getDeltaProcessor(); + } + + /** + * Returns the set of elements which are out of synch with their buffers. + */ + protected Map getElementsOutOfSynchWithBuffers() { + return this.elementsOutOfSynchWithBuffers; + } + + // public IndexManager getIndexManager() { + // return this.indexManager; + // } + /** + * Returns the IJavaElement represented by the + * String memento. + */ + public IJavaElement getHandleFromMemento(String memento) + throws JavaModelException { + if (memento == null) { + return null; + } + JavaModel model = (JavaModel) getJavaModel(); + if (memento.equals("")) { // workspace memento //$NON-NLS-1$ + return model; + } + int modelEnd = memento.indexOf(JavaElement.JEM_JAVAPROJECT); + if (modelEnd == -1) { + return null; + } + boolean returnProject = false; + int projectEnd = memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENTROOT, + modelEnd); + if (projectEnd == -1) { + projectEnd = memento.length(); + returnProject = true; + } + String projectName = memento.substring(modelEnd + 1, projectEnd); + JavaProject proj = (JavaProject) model.getJavaProject(projectName); + if (returnProject) { + return proj; + } + int rootEnd = memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENT, + projectEnd + 1); + // TODO temp-del + // if (rootEnd == -1) { + // return model.getHandleFromMementoForRoot(memento, proj, projectEnd, + // memento.length()); + // } + // IPackageFragmentRoot root = + // model.getHandleFromMementoForRoot(memento, proj, projectEnd, + // rootEnd); + // if (root == null) + // return null; + // + // int end= memento.indexOf(JavaElement.JEM_COMPILATIONUNIT, rootEnd); + // if (end == -1) { + // end= memento.indexOf(JavaElement.JEM_CLASSFILE, rootEnd); + // if (end == -1) { + // if (rootEnd + 1 == memento.length()) { + // return + // root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME); + // } else { + // return root.getPackageFragment(memento.substring(rootEnd + 1)); + // } + // } + // //deal with class file and binary members + // return model.getHandleFromMementoForBinaryMembers(memento, root, + // rootEnd, end); + // } + // + // //deal with compilation units and source members + // return model.getHandleFromMementoForSourceMembers(memento, root, + // rootEnd, end); + return null; + } + + // public IndexManager getIndexManager() { + // return this.deltaProcessor.indexManager; + // } + + /** + * Returns the info for the element. + */ + public Object getInfo(IJavaElement element) { + return this.cache.getInfo(element); + } + + /** + * Returns the handle to the active Java Model. + */ + public final JavaModel getJavaModel() { + return javaModel; + } + + /** + * Returns the singleton JavaModelManager + */ + public final static JavaModelManager getJavaModelManager() { + return Manager; + } + + /** + * Returns the last built state for the given project, or null if there is + * none. Deserializes the state if necessary. + * + * For use by image builder and evaluation support only + */ + public Object getLastBuiltState(IProject project, IProgressMonitor monitor) { + if (!JavaProject.hasJavaNature(project)) + return null; // should never be requested on non-Java projects + PerProjectInfo info = getPerProjectInfo(project, true/* + * create if + * missing + */); + if (!info.triedRead) { + info.triedRead = true; + try { + if (monitor != null) + monitor.subTask(Util.bind( + "build.readStateProgress", project.getName())); //$NON-NLS-1$ + info.savedState = readState(project); + } catch (CoreException e) { + e.printStackTrace(); + } + } + return info.savedState; + } + + /* + * Returns the per-project info for the given project. If specified, create + * the info if the info doesn't exist. + */ + public PerProjectInfo getPerProjectInfo(IProject project, boolean create) { + synchronized (perProjectInfo) { // use the perProjectInfo collection as + // its own lock + PerProjectInfo info = (PerProjectInfo) perProjectInfo.get(project); + if (info == null && create) { + info = new PerProjectInfo(project); + perProjectInfo.put(project, info); + } + return info; + } + } + + /* + * Returns the per-project info for the given project. If the info doesn't + * exist, check for the project existence and create the info. @throws + * JavaModelException if the project doesn't exist. + */ + public PerProjectInfo getPerProjectInfoCheckExistence(IProject project) + throws JavaModelException { + JavaModelManager.PerProjectInfo info = getPerProjectInfo(project, false /* + * don't + * create + * info + */); + if (info == null) { + if (!JavaProject.hasJavaNature(project)) { + throw ((JavaProject) JavaCore.create(project)) + .newNotPresentException(); + } + info = getPerProjectInfo(project, true /* create info */); + } + return info; + } + + /* + * Returns the per-working copy info for the given working copy at the given + * path. If it doesn't exist and if create, add a new per-working copy info + * with the given problem requestor. If recordUsage, increment the + * per-working copy info's use count. Returns null if it doesn't exist and + * not create. + */ + public PerWorkingCopyInfo getPerWorkingCopyInfo( + CompilationUnit workingCopy, boolean create, boolean recordUsage, + IProblemRequestor problemRequestor) { + synchronized (perWorkingCopyInfos) { // use the perWorkingCopyInfo + // collection as its own lock + WorkingCopyOwner owner = workingCopy.owner; + Map workingCopyToInfos = (Map) this.perWorkingCopyInfos.get(owner); + if (workingCopyToInfos == null && create) { + workingCopyToInfos = new HashMap(); + this.perWorkingCopyInfos.put(owner, workingCopyToInfos); + } + + PerWorkingCopyInfo info = workingCopyToInfos == null ? null + : (PerWorkingCopyInfo) workingCopyToInfos.get(workingCopy); + if (info == null && create) { + info = new PerWorkingCopyInfo(workingCopy, problemRequestor); + workingCopyToInfos.put(workingCopy, info); + } + if (info != null && recordUsage) + info.useCount++; + return info; + } + } + + /** + * Returns the name of the variables for which an CP variable initializer is + * registered through an extension point + */ + public static String[] getRegisteredVariableNames() { + + Plugin jdtCorePlugin = JavaCore.getPlugin(); + if (jdtCorePlugin == null) + return null; + + ArrayList variableList = new ArrayList(5); + // IExtensionPoint extension = + // jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPVARIABLE_INITIALIZER_EXTPOINT_ID); + // if (extension != null) { + // IExtension[] extensions = extension.getExtensions(); + // for(int i = 0; i < extensions.length; i++){ + // IConfigurationElement [] configElements = + // extensions[i].getConfigurationElements(); + // for(int j = 0; j < configElements.length; j++){ + // String varAttribute = configElements[j].getAttribute("variable"); + // //$NON-NLS-1$ + // if (varAttribute != null) variableList.add(varAttribute); + // } + // } + // } + String[] variableNames = new String[variableList.size()]; + variableList.toArray(variableNames); + return variableNames; + } + + /** + * Returns the name of the container IDs for which an CP container + * initializer is registered through an extension point + */ + // public static String[] getRegisteredContainerIDs(){ + // + // Plugin jdtCorePlugin = PHPCore.getPlugin(); + // if (jdtCorePlugin == null) return null; + // + // ArrayList containerIDList = new ArrayList(5); + // IExtensionPoint extension = + // jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPCONTAINER_INITIALIZER_EXTPOINT_ID); + // if (extension != null) { + // IExtension[] extensions = extension.getExtensions(); + // for(int i = 0; i < extensions.length; i++){ + // IConfigurationElement [] configElements = + // extensions[i].getConfigurationElements(); + // for(int j = 0; j < configElements.length; j++){ + // String idAttribute = configElements[j].getAttribute("id"); //$NON-NLS-1$ + // if (idAttribute != null) containerIDList.add(idAttribute); + // } + // } + // } + // String[] containerIDs = new String[containerIDList.size()]; + // containerIDList.toArray(containerIDs); + // return containerIDs; + // } + /** + * Returns the File to use for saving and restoring the last built state for + * the given project. + */ + private File getSerializationFile(IProject project) { + if (!project.exists()) + return null; + IPath workingLocation = project.getWorkingLocation(JavaCore.PLUGIN_ID); + return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$ + } + + /* + * Returns the temporary cache for newly opened elements for the current + * thread. Creates it if not already created. + */ + public HashMap getTemporaryCache() { + HashMap result = (HashMap) this.temporaryCache.get(); + if (result == null) { + result = new HashMap(); + this.temporaryCache.set(result); + } + return result; + } + + /** + * Returns the open ZipFile at the given location. If the ZipFile does not + * yet exist, it is created, opened, and added to the cache of open + * ZipFiles. The location must be a absolute path. + * + * @exception CoreException + * If unable to create/open the ZipFile + */ + public ZipFile getZipFile(IPath path) throws CoreException { + + synchronized (this.zipFiles) { // TODO: use PeThreadObject which does + // synchronization + Thread currentThread = Thread.currentThread(); + HashMap map = null; + ZipFile zipFile; + if ((map = (HashMap) this.zipFiles.get(currentThread)) != null + && (zipFile = (ZipFile) map.get(path)) != null) { + + return zipFile; + } + String fileSystemPath = null; + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IResource file = root.findMember(path); + if (path.isAbsolute() && file != null) { + if (file == null) { // external file + fileSystemPath = path.toOSString(); + } else { // internal resource (not an IFile or not existing) + IPath location; + if (file.getType() != IResource.FILE + || (location = file.getLocation()) == null) { + throw new CoreException( + new Status( + IStatus.ERROR, + JavaCore.PLUGIN_ID, + -1, + Util + .bind( + "file.notFound", path.toString()), null)); //$NON-NLS-1$ + } + fileSystemPath = location.toOSString(); + } + } else if (!path.isAbsolute()) { + file = root.getFile(path); + if (file == null || file.getType() != IResource.FILE) { + throw new CoreException(new Status(IStatus.ERROR, + JavaCore.PLUGIN_ID, -1, Util.bind( + "file.notFound", path.toString()), null)); //$NON-NLS-1$ + } + IPath location = file.getLocation(); + if (location == null) { + throw new CoreException(new Status(IStatus.ERROR, + JavaCore.PLUGIN_ID, -1, Util.bind( + "file.notFound", path.toString()), null)); //$NON-NLS-1$ + } + fileSystemPath = location.toOSString(); + } else { + fileSystemPath = path.toOSString(); + } + + try { + if (ZIP_ACCESS_VERBOSE) { + System.out + .println("(" + currentThread + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + fileSystemPath); //$NON-NLS-1$ //$NON-NLS-2$ + } + zipFile = new ZipFile(fileSystemPath); + if (map != null) { + map.put(path, zipFile); + } + return zipFile; + } catch (IOException e) { + throw new CoreException(new Status(Status.ERROR, + JavaCore.PLUGIN_ID, -1, + Util.bind("status.IOException"), e)); //$NON-NLS-1$ + } + } + } + + /* + * Returns whether there is a temporary cache for the current thread. + */ + public boolean hasTemporaryCache() { + return this.temporaryCache.get() != null; + } + + // public void loadVariablesAndContainers() throws CoreException { + // + // // backward compatibility, consider persistent property + // QualifiedName qName = new QualifiedName(PHPCore.PLUGIN_ID, "variables"); + // //$NON-NLS-1$ + // String xmlString = + // ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(qName); + // + // try { + // if (xmlString != null){ + // StringReader reader = new StringReader(xmlString); + // Element cpElement; + // try { + // DocumentBuilder parser = + // DocumentBuilderFactory.newInstance().newDocumentBuilder(); + // cpElement = parser.parse(new InputSource(reader)).getDocumentElement(); + // } catch(SAXException e) { + // return; + // } catch(ParserConfigurationException e){ + // return; + // } finally { + // reader.close(); + // } + // if (cpElement == null) return; + // if (!cpElement.getNodeName().equalsIgnoreCase("variables")) { + // //$NON-NLS-1$ + // return; + // } + // + // NodeList list= cpElement.getChildNodes(); + // int length= list.getLength(); + // for (int i= 0; i < length; ++i) { + // Node node= list.item(i); + // short type= node.getNodeType(); + // if (type == Node.ELEMENT_NODE) { + // Element element= (Element) node; + // if (element.getNodeName().equalsIgnoreCase("variable")) { //$NON-NLS-1$ + // variablePut( + // element.getAttribute("name"), //$NON-NLS-1$ + // new Path(element.getAttribute("path"))); //$NON-NLS-1$ + // } + // } + // } + // } + // } catch(IOException e){ + // } finally { + // if (xmlString != null){ + // ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(qName, + // null); // flush old one + // } + // + // } + // + // // load variables and containers from preferences into cache + // Preferences preferences = + // PHPeclipsePlugin.getDefault().getPluginPreferences(); + + // // only get variable from preferences not set to their default + // String[] propertyNames = preferences.propertyNames(); + // int variablePrefixLength = CP_VARIABLE_PREFERENCES_PREFIX.length(); + // for (int i = 0; i < propertyNames.length; i++){ + // String propertyName = propertyNames[i]; + // if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)){ + // String varName = propertyName.substring(variablePrefixLength); + // IPath varPath = new Path(preferences.getString(propertyName).trim()); + // + // Variables.put(varName, varPath); + // PreviousSessionVariables.put(varName, varPath); + // } + // if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)){ + // recreatePersistedContainer(propertyName, + // preferences.getString(propertyName), true/*add to container values*/); + // } + // } + // // override persisted values for variables which have a registered + // initializer + // String[] registeredVariables = getRegisteredVariableNames(); + // for (int i = 0; i < registeredVariables.length; i++) { + // String varName = registeredVariables[i]; + // Variables.put(varName, null); // reset variable, but leave its entry in + // the Map, so it will be part of variable names. + // } + // // override persisted values for containers which have a registered + // initializer + // String[] registeredContainerIDs = getRegisteredContainerIDs(); + // for (int i = 0; i < registeredContainerIDs.length; i++) { + // String containerID = registeredContainerIDs[i]; + // Iterator projectIterator = Containers.keySet().iterator(); + // while (projectIterator.hasNext()){ + // IJavaProject project = (IJavaProject)projectIterator.next(); + // Map projectContainers = (Map)Containers.get(project); + // if (projectContainers != null){ + // Iterator containerIterator = projectContainers.keySet().iterator(); + // while (containerIterator.hasNext()){ + // IPath containerPath = (IPath)containerIterator.next(); + // if (containerPath.segment(0).equals(containerID)) { // registered + // container + // projectContainers.put(containerPath, null); // reset container value, but + // leave entry in Map + // } + // } + // } + // } + // } + // } + + /** + * Merged all awaiting deltas. + */ + public IJavaElementDelta mergeDeltas(Collection deltas) { + if (deltas.size() == 0) + return null; + if (deltas.size() == 1) + return (IJavaElementDelta) deltas.iterator().next(); + + if (DeltaProcessor.VERBOSE) { + System.out + .println("MERGING " + deltas.size() + " DELTAS [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + Iterator iterator = deltas.iterator(); + IJavaElement javaModel = this.getJavaModel(); + JavaElementDelta rootDelta = new JavaElementDelta(javaModel); + boolean insertedTree = false; + while (iterator.hasNext()) { + JavaElementDelta delta = (JavaElementDelta) iterator.next(); + if (DeltaProcessor.VERBOSE) { + System.out.println(delta.toString()); + } + IJavaElement element = delta.getElement(); + if (javaModel.equals(element)) { + IJavaElementDelta[] children = delta.getAffectedChildren(); + for (int j = 0; j < children.length; j++) { + JavaElementDelta projectDelta = (JavaElementDelta) children[j]; + rootDelta.insertDeltaTree(projectDelta.getElement(), + projectDelta); + insertedTree = true; + } + IResourceDelta[] resourceDeltas = delta.getResourceDeltas(); + if (resourceDeltas != null) { + for (int i = 0, length = resourceDeltas.length; i < length; i++) { + rootDelta.addResourceDelta(resourceDeltas[i]); + insertedTree = true; + } + } + } else { + rootDelta.insertDeltaTree(element, delta); + insertedTree = true; + } + } + if (insertedTree) { + return rootDelta; + } else { + return null; + } + } + + /** + * Returns the info for this element without disturbing the cache ordering. + */ + // TODO: should be synchronized, could answer unitialized info or if cache + // is in middle of rehash, could even answer distinct element info + protected Object peekAtInfo(IJavaElement element) { + return this.cache.peekAtInfo(element); + } + + /** + * @see ISaveParticipant + */ + public void prepareToSave(ISaveContext context) throws CoreException { + } + + protected void putInfo(IJavaElement element, Object info) { + this.cache.putInfo(element, info); + } + + /* + * Puts the infos in the given map (keys are IJavaElements and values are + * JavaElementInfos) in the Java model cache in an atomic way. First checks + * that the info for the opened element (or one of its ancestors) has not + * been added to the cache. If it is the case, another thread has opened the + * element (or one of its ancestors). So returns without updating the cache. + */ + protected synchronized void putInfos(IJavaElement openedElement, + Map newElements) { + // remove children + Object existingInfo = this.cache.peekAtInfo(openedElement); + if (openedElement instanceof IParent + && existingInfo instanceof JavaElementInfo) { + IJavaElement[] children = ((JavaElementInfo) existingInfo) + .getChildren(); + for (int i = 0, size = children.length; i < size; ++i) { + JavaElement child = (JavaElement) children[i]; + try { + child.close(); + } catch (JavaModelException e) { + // ignore + } + } + } + + Iterator iterator = newElements.keySet().iterator(); + while (iterator.hasNext()) { + IJavaElement element = (IJavaElement) iterator.next(); + Object info = newElements.get(element); + this.cache.putInfo(element, info); + } + } + + /** + * Reads the build state for the relevant project. + */ + protected Object readState(IProject project) throws CoreException { + File file = getSerializationFile(project); + if (file != null && file.exists()) { + try { + DataInputStream in = new DataInputStream( + new BufferedInputStream(new FileInputStream(file))); + try { + String pluginID = in.readUTF(); + if (!pluginID.equals(JavaCore.PLUGIN_ID)) + throw new IOException(Util + .bind("build.wrongFileFormat")); //$NON-NLS-1$ + String kind = in.readUTF(); + if (!kind.equals("STATE")) //$NON-NLS-1$ + throw new IOException(Util + .bind("build.wrongFileFormat")); //$NON-NLS-1$ + if (in.readBoolean()) + return PHPBuilder.readState(project, in); + if (PHPBuilder.DEBUG) + System.out + .println("Saved state thinks last build failed for " + project.getName()); //$NON-NLS-1$ + } finally { + in.close(); + } + } catch (Exception e) { + e.printStackTrace(); + throw new CoreException( + new Status( + IStatus.ERROR, + JavaCore.PLUGIN_ID, + Platform.PLUGIN_ERROR, + "Error reading last build state for project " + project.getName(), e)); //$NON-NLS-1$ + } + } + return null; + } + + // public static void recreatePersistedContainer(String propertyName, String + // containerString, boolean addToContainerValues) { + // int containerPrefixLength = CP_CONTAINER_PREFERENCES_PREFIX.length(); + // int index = propertyName.indexOf('|', containerPrefixLength); + // if (containerString != null) containerString = containerString.trim(); + // if (index > 0) { + // final String projectName = propertyName.substring(containerPrefixLength, + // index).trim(); + // JavaProject project = + // (JavaProject)getJavaModelManager().getJavaModel().getJavaProject(projectName); + // final IPath containerPath = new + // Path(propertyName.substring(index+1).trim()); + // + // if (containerString == null || containerString.equals(CP_ENTRY_IGNORE)) { + // containerPut(project, containerPath, null); + // } else { + // final IClasspathEntry[] containerEntries = + // project.decodeClasspath(containerString, false, false); + // if (containerEntries != null && containerEntries != + // JavaProject.INVALID_CLASSPATH) { + // IClasspathContainer container = new IClasspathContainer() { + // public IClasspathEntry[] getClasspathEntries() { + // return containerEntries; + // } + // public String getDescription() { + // return "Persisted container ["+containerPath+" for project ["+ + // projectName+"]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + // } + // public int getKind() { + // return 0; + // } + // public IPath getPath() { + // return containerPath; + // } + // public String toString() { + // return getDescription(); + // } + // + // }; + // if (addToContainerValues) { + // containerPut(project, containerPath, container); + // } + // Map projectContainers = (Map)PreviousSessionContainers.get(project); + // if (projectContainers == null){ + // projectContainers = new HashMap(1); + // PreviousSessionContainers.put(project, projectContainers); + // } + // projectContainers.put(containerPath, container); + // } + // } + // } + // } + + /** + * Registers the given delta with this manager. + */ + protected void registerJavaModelDelta(IJavaElementDelta delta) { + this.javaModelDeltas.add(delta); + } + + /** + * Remembers the given scope in a weak set (so no need to remove it: it will + * be removed by the garbage collector) + */ + // public void rememberScope(AbstractSearchScope scope) { + // // NB: The value has to be null so as to not create a strong reference on + // the scope + // this.scopes.put(scope, null); + // } + /** + * removeElementChangedListener method comment. + */ + public void removeElementChangedListener(IElementChangedListener listener) { + + for (int i = 0; i < this.elementChangedListenerCount; i++) { + + if (this.elementChangedListeners[i].equals(listener)) { + + // need to clone defensively since we might be in the middle of + // listener notifications (#fire) + int length = this.elementChangedListeners.length; + IElementChangedListener[] newListeners = new IElementChangedListener[length]; + System.arraycopy(this.elementChangedListeners, 0, newListeners, + 0, i); + int[] newMasks = new int[length]; + System.arraycopy(this.elementChangedListenerMasks, 0, newMasks, + 0, i); + + // copy trailing listeners + int trailingLength = this.elementChangedListenerCount - i - 1; + if (trailingLength > 0) { + System.arraycopy(this.elementChangedListeners, i + 1, + newListeners, i, trailingLength); + System.arraycopy(this.elementChangedListenerMasks, i + 1, + newMasks, i, trailingLength); + } + + // update manager listener state (#fire need to iterate over + // original listeners through a local variable to hold onto + // the original ones) + this.elementChangedListeners = newListeners; + this.elementChangedListenerMasks = newMasks; + this.elementChangedListenerCount--; + return; + } + } + } + + /** + * Remembers the given scope in a weak set (so no need to remove it: it will + * be removed by the garbage collector) + */ + // public void rememberScope(AbstractSearchScope scope) { + // // NB: The value has to be null so as to not create a strong reference on + // the scope + // this.searchScopes.put(scope, null); + // } + /* + * Removes all cached info for the given element (including all children) + * from the cache. Returns the info for the given element, or null if it was + * closed. + */ + public synchronized Object removeInfoAndChildren(JavaElement element) + throws JavaModelException { + Object info = this.cache.peekAtInfo(element); + if (info != null) { + boolean wasVerbose = false; + try { + if (VERBOSE) { + System.out + .println("CLOSING Element (" + Thread.currentThread() + "): " + element.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$ + wasVerbose = true; + VERBOSE = false; + } + element.closing(info); + if (element instanceof IParent + && info instanceof JavaElementInfo) { + IJavaElement[] children = ((JavaElementInfo) info) + .getChildren(); + for (int i = 0, size = children.length; i < size; ++i) { + JavaElement child = (JavaElement) children[i]; + child.close(); + } + } + this.cache.removeInfo(element); + if (wasVerbose) { + System.out + .println("-> Package cache size = " + this.cache.pkgSize()); //$NON-NLS-1$ + System.out + .println("-> Openable cache filling ratio = " + NumberFormat.getInstance().format(this.cache.openableFillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$ + } + } finally { + JavaModelManager.VERBOSE = wasVerbose; + } + return info; + } + return null; + } + + public void removePerProjectInfo(JavaProject javaProject) { + synchronized (perProjectInfo) { // use the perProjectInfo collection as + // its own lock + IProject project = javaProject.getProject(); + PerProjectInfo info = (PerProjectInfo) perProjectInfo.get(project); + if (info != null) { + perProjectInfo.remove(project); + } + } + } + + /* + * Resets the temporary cache for newly created elements to null. + */ + public void resetTemporaryCache() { + this.temporaryCache.set(null); + } + + /** + * @see ISaveParticipant + */ + public void rollback(ISaveContext context) { + } + + private void saveState(PerProjectInfo info, ISaveContext context) + throws CoreException { + + // passed this point, save actions are non trivial + if (context.getKind() == ISaveContext.SNAPSHOT) + return; + + // save built state + if (info.triedRead) + saveBuiltState(info); + } + + /** + * Saves the built state for the project. + */ + private void saveBuiltState(PerProjectInfo info) throws CoreException { + if (PHPBuilder.DEBUG) + System.out.println(Util.bind( + "build.saveStateProgress", info.project.getName())); //$NON-NLS-1$ + File file = getSerializationFile(info.project); + if (file == null) + return; + long t = System.currentTimeMillis(); + try { + DataOutputStream out = new DataOutputStream( + new BufferedOutputStream(new FileOutputStream(file))); + try { + out.writeUTF(JavaCore.PLUGIN_ID); + out.writeUTF("STATE"); //$NON-NLS-1$ + if (info.savedState == null) { + out.writeBoolean(false); + } else { + out.writeBoolean(true); + PHPBuilder.writeState(info.savedState, out); + } + } finally { + out.close(); + } + } catch (RuntimeException e) { + try { + file.delete(); + } catch (SecurityException se) { + } + throw new CoreException( + new Status( + IStatus.ERROR, + JavaCore.PLUGIN_ID, + Platform.PLUGIN_ERROR, + Util + .bind( + "build.cannotSaveState", info.project.getName()), e)); //$NON-NLS-1$ + } catch (IOException e) { + try { + file.delete(); + } catch (SecurityException se) { + } + throw new CoreException( + new Status( + IStatus.ERROR, + JavaCore.PLUGIN_ID, + Platform.PLUGIN_ERROR, + Util + .bind( + "build.cannotSaveState", info.project.getName()), e)); //$NON-NLS-1$ + } + if (PHPBuilder.DEBUG) { + t = System.currentTimeMillis() - t; + System.out.println(Util.bind( + "build.saveStateComplete", String.valueOf(t))); //$NON-NLS-1$ + } + } + + private synchronized Map containerClone(IJavaProject project) { + Map originalProjectContainers = (Map) this.containers.get(project); + if (originalProjectContainers == null) + return null; + Map projectContainers = new HashMap(originalProjectContainers.size()); + projectContainers.putAll(originalProjectContainers); + return projectContainers; + } + + /** + * @see ISaveParticipant + */ + public void saving(ISaveContext context) throws CoreException { + + // save container values on snapshot/full save + Preferences preferences = JavaCore.getPlugin().getPluginPreferences(); + IJavaProject[] projects = getJavaModel().getJavaProjects(); + for (int i = 0, length = projects.length; i < length; i++) { + IJavaProject project = projects[i]; + // clone while iterating (see + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638) + Map projectContainers = containerClone(project); + if (projectContainers == null) + continue; + for (Iterator keys = projectContainers.keySet().iterator(); keys + .hasNext();) { + IPath containerPath = (IPath) keys.next(); + // IClasspathContainer container = (IClasspathContainer) + // projectContainers.get(containerPath); + String containerKey = CP_CONTAINER_PREFERENCES_PREFIX + + project.getElementName() + "|" + containerPath;//$NON-NLS-1$ + String containerString = CP_ENTRY_IGNORE; + // try { + // if (container != null) { + // containerString = + // ((JavaProject)project).encodeClasspath(container.getClasspathEntries(), + // null, false); + // } + // } catch(JavaModelException e){ + // // could not encode entry: leave it as CP_ENTRY_IGNORE + // } + preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use + // this + // default + // to + // get + // rid + // of + // removed + // ones + preferences.setValue(containerKey, containerString); + } + } + JavaCore.getPlugin().savePluginPreferences(); + + // if (context.getKind() == ISaveContext.FULL_SAVE) { + // // will need delta since this save (see + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658) + // context.needDelta(); + // + // // clean up indexes on workspace full save + // // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52347) + // IndexManager manager = this.indexManager; + // if (manager != null) { + // manager.cleanUpIndexes(); + // } + // } + + IProject savedProject = context.getProject(); + if (savedProject != null) { + if (!JavaProject.hasJavaNature(savedProject)) + return; // ignore + PerProjectInfo info = getPerProjectInfo(savedProject, true /* + * create + * info + */); + saveState(info, context); + return; + } + + ArrayList vStats = null; // lazy initialized + for (Iterator iter = perProjectInfo.values().iterator(); iter.hasNext();) { + try { + PerProjectInfo info = (PerProjectInfo) iter.next(); + saveState(info, context); + } catch (CoreException e) { + if (vStats == null) + vStats = new ArrayList(); + vStats.add(e.getStatus()); + } + } + if (vStats != null) { + IStatus[] stats = new IStatus[vStats.size()]; + vStats.toArray(stats); + throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID, + IStatus.ERROR, stats, + Util.bind("build.cannotSaveStates"), null)); //$NON-NLS-1$ + } + } + + /** + * @see ISaveParticipant + */ + // public void saving(ISaveContext context) throws CoreException { + // + // IProject savedProject = context.getProject(); + // if (savedProject != null) { + // if (!JavaProject.hasJavaNature(savedProject)) return; // ignore + // PerProjectInfo info = getPerProjectInfo(savedProject, true /* create info + // */); + // saveState(info, context); + // return; + // } + // + // ArrayList vStats= null; // lazy initialized + // for (Iterator iter = perProjectInfo.values().iterator(); iter.hasNext();) + // { + // try { + // PerProjectInfo info = (PerProjectInfo) iter.next(); + // saveState(info, context); + // } catch (CoreException e) { + // if (vStats == null) + // vStats= new ArrayList(); + // vStats.add(e.getStatus()); + // } + // } + // if (vStats != null) { + // IStatus[] stats= new IStatus[vStats.size()]; + // vStats.toArray(stats); + // throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID, + // IStatus.ERROR, stats, Util.bind("build.cannotSaveStates"), null)); + // //$NON-NLS-1$ + // } + // } + /** + * Record the order in which to build the java projects (batch build). This + * order is based on the projects classpath settings. + */ + protected void setBuildOrder(String[] javaBuildOrder) + throws JavaModelException { + + // optional behaviour + // possible value of index 0 is Compute + if (!JavaCore.COMPUTE.equals(JavaCore + .getOption(JavaCore.CORE_JAVA_BUILD_ORDER))) + return; // cannot be customized at project level + + if (javaBuildOrder == null || javaBuildOrder.length <= 1) + return; + + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + IWorkspaceDescription description = workspace.getDescription(); + String[] wksBuildOrder = description.getBuildOrder(); + + String[] newOrder; + if (wksBuildOrder == null) { + newOrder = javaBuildOrder; + } else { + // remove projects which are already mentionned in java builder + // order + int javaCount = javaBuildOrder.length; + HashMap newSet = new HashMap(javaCount); // create a set for fast + // check + for (int i = 0; i < javaCount; i++) { + newSet.put(javaBuildOrder[i], javaBuildOrder[i]); + } + int removed = 0; + int oldCount = wksBuildOrder.length; + for (int i = 0; i < oldCount; i++) { + if (newSet.containsKey(wksBuildOrder[i])) { + wksBuildOrder[i] = null; + removed++; + } + } + // add Java ones first + newOrder = new String[oldCount - removed + javaCount]; + System.arraycopy(javaBuildOrder, 0, newOrder, 0, javaCount); // java + // projects + // are + // built + // first + + // copy previous items in their respective order + int index = javaCount; + for (int i = 0; i < oldCount; i++) { + if (wksBuildOrder[i] != null) { + newOrder[index++] = wksBuildOrder[i]; + } + } + } + // commit the new build order out + description.setBuildOrder(newOrder); + try { + workspace.setDescription(description); + } catch (CoreException e) { + throw new JavaModelException(e); + } + } + + /** + * Sets the last built state for the given project, or null to reset it. + */ + public void setLastBuiltState(IProject project, Object state) { + if (!JavaProject.hasJavaNature(project)) + return; // should never be requested on non-Java projects + PerProjectInfo info = getPerProjectInfo(project, true /* + * create if + * missing + */); + info.triedRead = true; // no point trying to re-read once using setter + info.savedState = state; + if (state == null) { // delete state file to ensure a full build + // happens if the workspace crashes + try { + File file = getSerializationFile(project); + if (file != null && file.exists()) + file.delete(); + } catch (SecurityException se) { + } + } + } + + public void shutdown() { + // TODO temp-del + // if (this.deltaProcessor.indexManager != null){ // no more indexing + // this.deltaProcessor.indexManager.shutdown(); + // } + try { + IJavaModel model = this.getJavaModel(); + if (model != null) { + + model.close(); + } + } catch (JavaModelException e) { + } + } + + /** + * Turns the firing mode to on. That is, deltas that are/have been + * registered will be fired. + */ + public void startDeltas() { + this.isFiring = true; + } + + /** + * Turns the firing mode to off. That is, deltas that are/have been + * registered will not be fired until deltas are started again. + */ + public void stopDeltas() { + this.isFiring = false; + } + + /** + * Update Java Model given some delta + */ + public void updateJavaModel(IJavaElementDelta customDelta) { + + if (customDelta == null) { + for (int i = 0, length = this.javaModelDeltas.size(); i < length; i++) { + IJavaElementDelta delta = (IJavaElementDelta) this.javaModelDeltas + .get(i); + this.modelUpdater.processJavaDelta(delta); + } + } else { + this.modelUpdater.processJavaDelta(customDelta); + } + } + + public static IPath variableGet(String variableName) { + return (IPath) Variables.get(variableName); + } + + public static String[] variableNames() { + int length = Variables.size(); + String[] result = new String[length]; + Iterator vars = Variables.keySet().iterator(); + int index = 0; + while (vars.hasNext()) { + result[index++] = (String) vars.next(); + } + return result; + } + + public static void variablePut(String variableName, IPath variablePath) { + + // update cache - do not only rely on listener refresh + if (variablePath == null) { + Variables.remove(variableName); + PreviousSessionVariables.remove(variableName); + } else { + Variables.put(variableName, variablePath); + } + + // do not write out intermediate initialization value + if (variablePath == JavaModelManager.VariableInitializationInProgress) { + return; + } + Preferences preferences = JavaCore.getPlugin().getPluginPreferences(); + String variableKey = CP_VARIABLE_PREFERENCES_PREFIX + variableName; + String variableString = variablePath == null ? CP_ENTRY_IGNORE + : variablePath.toString(); + preferences.setDefault(variableKey, CP_ENTRY_IGNORE); // use this + // default to + // get rid of + // removed ones + preferences.setValue(variableKey, variableString); + JavaCore.getPlugin().savePluginPreferences(); + } + + /* + * Returns all the working copies which have the given owner. Adds the + * working copies of the primary owner if specified. Returns null if it has + * none. + */ + public ICompilationUnit[] getWorkingCopies(WorkingCopyOwner owner, + boolean addPrimary) { + synchronized (perWorkingCopyInfos) { + ICompilationUnit[] primaryWCs = addPrimary + && owner != DefaultWorkingCopyOwner.PRIMARY ? getWorkingCopies( + DefaultWorkingCopyOwner.PRIMARY, false) + : null; + Map workingCopyToInfos = (Map) perWorkingCopyInfos.get(owner); + if (workingCopyToInfos == null) + return primaryWCs; + int primaryLength = primaryWCs == null ? 0 : primaryWCs.length; + int size = workingCopyToInfos.size(); // note size is > 0 + // otherwise + // pathToPerWorkingCopyInfos + // would be null + ICompilationUnit[] result = new ICompilationUnit[primaryLength + + size]; + if (primaryWCs != null) { + System.arraycopy(primaryWCs, 0, result, 0, primaryLength); + } + Iterator iterator = workingCopyToInfos.values().iterator(); + int index = primaryLength; + while (iterator.hasNext()) { + result[index++] = ((JavaModelManager.PerWorkingCopyInfo) iterator + .next()).getWorkingCopy(); + } + return result; + } + } + + /* + * A HashSet that contains the IJavaProject whose classpath is being + * resolved. + */ + private ThreadLocal classpathsBeingResolved = new ThreadLocal(); + + private HashSet getClasspathBeingResolved() { + HashSet result = (HashSet) this.classpathsBeingResolved.get(); + if (result == null) { + result = new HashSet(); + this.classpathsBeingResolved.set(result); + } + return result; + } + + public boolean isClasspathBeingResolved(IJavaProject project) { + return getClasspathBeingResolved().contains(project); + } + + public void setClasspathBeingResolved(IJavaProject project, + boolean classpathIsResolved) { + if (classpathIsResolved) { + getClasspathBeingResolved().add(project); + } else { + getClasspathBeingResolved().remove(project); + } + } +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/corext/phpdoc/PHPDocUtil.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/corext/phpdoc/PHPDocUtil.java new file mode 100644 index 0000000..0d477e1 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/corext/phpdoc/PHPDocUtil.java @@ -0,0 +1,93 @@ +package net.sourceforge.phpdt.internal.corext.phpdoc; + +import java.io.FileReader; +import java.io.IOException; + +import net.sourceforge.phpeclipse.builder.PHPIdentifierLocation; + +/** + * Utility class for static PHPdoc helper mehods + */ +public class PHPDocUtil { + + /** + * Generate a PHPDoc hover text if possible + * + * @param hoverInfoBuffer + * @param filename + * @param location + */ + public static void appendPHPDoc(StringBuffer hoverInfoBuffer, + String filename, PHPIdentifierLocation location) { + FileReader phpFileReader; + hoverInfoBuffer.append(location.toString()); + hoverInfoBuffer.append(" - "); + try { + hoverInfoBuffer.append(getUsage(filename, location)); + hoverInfoBuffer.append("
"); + + // read the phpdoc for the function + if (location.getPHPDocOffset() >= 0) { + phpFileReader = new FileReader(filename); + char[] phpDocDeclarationCharArray = new char[location + .getPHPDocLength()]; + phpFileReader.skip(location.getPHPDocOffset()); + phpFileReader.read(phpDocDeclarationCharArray, 0, location + .getPHPDocLength()); + PHPDocCharArrayCommentReader phpdocConverter = new PHPDocCharArrayCommentReader( + phpDocDeclarationCharArray); + hoverInfoBuffer.append(phpdocConverter.getString()); + // hoverInfoBuffer.append("

"); + phpFileReader.close(); + } + + } catch (IOException e) { + return; + } + } + + public static String getUsage(String filename, + PHPIdentifierLocation location) { + FileReader phpFileReader; + String usage = location.getUsage(); + if (usage != null) { + return usage; + } + usage = ""; + try { + + phpFileReader = new FileReader(filename); + // read the function declaration + if (location.getOffset() >= 0 + && (location.isMethod() || location.isConstructor() + || location.isFunction() || location.isDefine())) { + char[] functionDeclarationCharArray = new char[256]; + int offset = location.getOffset(); + phpFileReader.skip(offset); + int length = phpFileReader.read(functionDeclarationCharArray, + 0, 256); + if (length == -1) { + length = 256; + } + for (int i = 0; i < length; i++) { + if (functionDeclarationCharArray[i] == ')') { + length = i + 1; + break; + } + if (functionDeclarationCharArray[i] == '{' + || functionDeclarationCharArray[i] == '}') { + length = i; + break; + } + } + usage = new String(functionDeclarationCharArray, 0, length); + } + phpFileReader.close(); + } catch (IOException e) { + // do nothing + } + // cache the usage string: + location.setUsage(usage); + return usage; + } +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/corext/util/Resources.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/corext/util/Resources.java new file mode 100644 index 0000000..d03b7b3 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/corext/util/Resources.java @@ -0,0 +1,211 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package net.sourceforge.phpdt.internal.corext.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import net.sourceforge.phpdt.internal.corext.CorextMessages; +import net.sourceforge.phpdt.internal.ui.IJavaStatusConstants; +import net.sourceforge.phpdt.internal.ui.PHPUIStatus; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceStatus; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Status; + +public class Resources { + + private Resources() { + } + + /** + * Checks if the given resource is in sync with the underlying file system. + * + * @param resource + * the resource to be checked + * @return IStatus status describing the check's result. If status. + * isOK() + * returns true then the resource is in sync + */ + public static IStatus checkInSync(IResource resource) { + return checkInSync(new IResource[] { resource }); + } + + /** + * Checks if the given resources are in sync with the underlying file + * system. + * + * @param resources + * the resources to be checked + * @return IStatus status describing the check's result. If status. + * isOK() + * returns true then the resources are in sync + */ + public static IStatus checkInSync(IResource[] resources) { + IStatus result = null; + for (int i = 0; i < resources.length; i++) { + IResource resource = resources[i]; + if (!resource.isSynchronized(IResource.DEPTH_INFINITE)) { + result = addOutOfSync(result, resource); + } + } + if (result != null) + return result; + return new Status(IStatus.OK, PHPeclipsePlugin.getPluginId(), + IStatus.OK, "", null); //$NON-NLS-1$ + } + + /** + * Makes the given resource committable. Committable means that it is + * writeable and that its content hasn't changed by calling + * validateEdit for the given resource on IWorkspace. + * + * @param resource + * the resource to be checked + * @param context + * the context passed to validateEdit + * @return status describing the method's result. If + * status.isOK() returns true then the + * resources are committable. + * + * @see org.eclipse.core.resources.IWorkspace#validateEdit(org.eclipse.core.resources.IFile[], + * java.lang.Object) + */ + public static IStatus makeCommittable(IResource resource, Object context) { + return makeCommittable(new IResource[] { resource }, context); + } + + /** + * Makes the given resources committable. Committable means that all + * resources are writeable and that the content of the resources hasn't + * changed by calling validateEdit for a given file on + * IWorkspace. + * + * @param resources + * the resources to be checked + * @param context + * the context passed to validateEdit + * @return IStatus status describing the method's result. If status. + * isOK() + * returns true then the add resources are + * committable + * + * @see org.eclipse.core.resources.IWorkspace#validateEdit(org.eclipse.core.resources.IFile[], + * java.lang.Object) + */ + public static IStatus makeCommittable(IResource[] resources, Object context) { + List readOnlyFiles = new ArrayList(); + for (int i = 0; i < resources.length; i++) { + IResource resource = resources[i]; + if (resource.getType() == IResource.FILE + && resource.getResourceAttributes().isReadOnly()) + readOnlyFiles.add(resource); + } + if (readOnlyFiles.size() == 0) + return new Status(IStatus.OK, PHPeclipsePlugin.getPluginId(), + IStatus.OK, "", null); //$NON-NLS-1$ + + Map oldTimeStamps = createModificationStampMap(readOnlyFiles); + IStatus status = ResourcesPlugin.getWorkspace().validateEdit( + (IFile[]) readOnlyFiles + .toArray(new IFile[readOnlyFiles.size()]), context); + if (!status.isOK()) + return status; + + IStatus modified = null; + Map newTimeStamps = createModificationStampMap(readOnlyFiles); + for (Iterator iter = oldTimeStamps.keySet().iterator(); iter.hasNext();) { + IFile file = (IFile) iter.next(); + if (!oldTimeStamps.get(file).equals(newTimeStamps.get(file))) + modified = addModified(modified, file); + } + if (modified != null) + return modified; + return new Status(IStatus.OK, PHPeclipsePlugin.getPluginId(), + IStatus.OK, "", null); //$NON-NLS-1$ + } + + private static Map createModificationStampMap(List files) { + Map map = new HashMap(); + for (Iterator iter = files.iterator(); iter.hasNext();) { + IFile file = (IFile) iter.next(); + map.put(file, new Long(file.getModificationStamp())); + } + return map; + } + + private static IStatus addModified(IStatus status, IFile file) { + IStatus entry = PHPUIStatus + .createError( + IJavaStatusConstants.VALIDATE_EDIT_CHANGED_CONTENT, + CorextMessages + .getFormattedString( + "Resources.fileModified", file.getFullPath().toString()), //$NON-NLS-1$ + null); + if (status == null) { + return entry; + } else if (status.isMultiStatus()) { + ((MultiStatus) status).add(entry); + return status; + } else { + MultiStatus result = new MultiStatus( + PHPeclipsePlugin.getPluginId(), + IJavaStatusConstants.VALIDATE_EDIT_CHANGED_CONTENT, + CorextMessages.getString("Resources.modifiedResources"), null); //$NON-NLS-1$ + result.add(status); + result.add(entry); + return result; + } + } + + private static IStatus addOutOfSync(IStatus status, IResource resource) { + IStatus entry = new Status( + IStatus.ERROR, + ResourcesPlugin.PI_RESOURCES, + IResourceStatus.OUT_OF_SYNC_LOCAL, + CorextMessages + .getFormattedString( + "Resources.outOfSync", resource.getFullPath().toString()), //$NON-NLS-1$ + null); + if (status == null) { + return entry; + } else if (status.isMultiStatus()) { + ((MultiStatus) status).add(entry); + return status; + } else { + MultiStatus result = new MultiStatus(ResourcesPlugin.PI_RESOURCES, + IResourceStatus.OUT_OF_SYNC_LOCAL, CorextMessages + .getString("Resources.outOfSyncResources"), null); //$NON-NLS-1$ + result.add(status); + result.add(entry); + return result; + } + } + + public static String[] getLocationOSStrings(IResource[] resources) { + List result = new ArrayList(resources.length); + for (int i = 0; i < resources.length; i++) { + IPath location = resources[i].getLocation(); + if (location != null) + result.add(location.toOSString()); + } + return (String[]) result.toArray(new String[result.size()]); + } +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/core/PHPDBGProxy.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/core/PHPDBGProxy.java new file mode 100644 index 0000000..5c5b26b --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/core/PHPDBGProxy.java @@ -0,0 +1,703 @@ +/*********************************************************************************************************************************** + * Copyright (c) 2000, 2002 IBM Corp. and others. All rights reserved. This program and the accompanying materials are made + * available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: IBM Corporation - Initial implementation Vicente Fernando - www.alfersoft.com.ar Christian Perkonig - remote debug + **********************************************************************************************************************************/ +package net.sourceforge.phpdt.internal.debug.core; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.Map; +import java.util.Vector; + +import net.sourceforge.phpdt.internal.debug.core.breakpoints.PHPLineBreakpoint; +import net.sourceforge.phpdt.internal.debug.core.model.PHPDebugTarget; +import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame; +import net.sourceforge.phpdt.internal.debug.core.model.PHPThread; +import net.sourceforge.phpdt.internal.debug.core.model.PHPVariable; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.model.IBreakpoint; + +public class PHPDBGProxy { + + private ServerSocket server = null; + private BufferedReader reader = null; + private PHPDBGInterface DBGInt = null; // The DBG interface which is linked with the proxy + private PHPDebugTarget debugTarget = null; + private PHPDBGProxy thisProxy = null; + private PHPLoop phpLoop; + private PHPThread PHPMainThread; + private Socket socket; + private int port; + private boolean remote; + private boolean pathtranslation; + private Map pathmap; + private IPath remoteSourcePath; + + /** + */ + public PHPDBGProxy () { + thisProxy = this; + } + + /** + * @param remote + * @param remoteSourcePath + * @param pathTranslate + * @param paths + */ + public PHPDBGProxy (boolean remote, String remoteSourcePath, boolean pathTranslate, Map paths) { + thisProxy = this; + this.remote = remote; + this.remoteSourcePath = new Path (remoteSourcePath); + this.pathmap = paths; + this.pathtranslation = pathTranslate; + } + + /** + * + */ + public void start () { + createServerSocket (); // Create a server socket for communicatio with DBG + + this.startPHPLoop (); // + } + + /** + * + */ + public void stop () { + phpLoop.setShouldStop (); // Notify the thread's 'run loop' to stop + + if (DBGInt != null) { // If we have a DBG interface linked with this proxy + DBGInt.setShouldStop (); // Notify the DBG interface to stop the waiting for response + } + + if (!remote) { // If it's not a remote proxy session + try { + getDebugTarget ().getProcess ().terminate (); // + } catch (DebugException e) { + e.printStackTrace (); + } + } + + phpLoop.notifyWait (); + } + + public void setTerminated () { + try { + PHPMainThread.terminate (); + } + catch (DebugException e) { + } + } + + /** + * TODO Is this method called from anywhere? + * + * Returns a already created server socket, or + * creates a server socket if none exists, and + * returns the newly created one. + * + * @return A server socket + */ + protected ServerSocket getServerSocket () throws IOException { + if (server == null) { // Do we have already a server socket + createServerSocket (); // No, then create one + } + + return server; // Return the server socket + } + + /** + * Find a free unused port between 10001 and 10101 if the current debug session + * is for remote debugging, and a unused port 7869 if it is used as non remote debugging. + * + * For remote debugging the used port is submitted with the URL. + * E.g. http://localhost/index.php?DBGSESSID=1@localhost:10001 + * For non remote debugging (if PHPeclipse used e.g. php cli directly) no port + * can be submitted by parameter, and only the default port (7869) can be used. + * + * @note: The free dbg version doesn't allow to set the appropriate port within php.ini! + * + * + */ + protected void createServerSocket () { + if (this.remote) { + port = SocketUtil.findUnusedLocalPort ("localhost", 10001, 10101); // Get the first free port in the range from 10001 to 10101 + } + else { + port = SocketUtil.findUnusedLocalPort ("localhost", 7869, 7869); // Get the first free port in the range from 7869 to 7869 + } + + if (port == -1) { // Did we get a free port? + PHPDebugCorePlugin.log (5, "Cannot find free port!!!!"); // No, output a error message + + return; // And return + } + try { + if (server == null) { // If there is no server socket yet + server = new ServerSocket (port); // create a server socket for the free port + //System.out.println("ServerSocket on port: " + port); + } + } catch (IOException e) { + PHPDebugCorePlugin.log (e); + stop (); + } + } + + /** + * + */ + public Socket getSocket () throws IOException { + return socket; // Return the socket + } + + /** + * Set the DBG interface which is linked to this proxy + * + * @paran DBGInt The DGB interface which is linked with this proxy + */ + protected void setDBGInterface (PHPDBGInterface DBGInt) { + this.DBGInt = DBGInt; + } + + /** + * Get the DBG interface which is linked to this proxy + * + * @paran DBGInt The DGB interface which is linked with this proxy + */ + public PHPDBGInterface getDBGInterface () { + return DBGInt; + } + + /** + * Give back a buffered input stream for the socket which is + * linked with this proxy + */ + public BufferedReader getReader () throws IOException { + if (reader == null) { // Do we already have a buffered input stream + reader = new BufferedReader (new InputStreamReader (this.getSocket ().getInputStream (), + "ISO8859_1")); + } + + return reader; // Return the buffered input stream + } + + /** + * + */ + public BufferedReader getReader (Socket socket) throws IOException { + if (socket != null) { // Is a socket provided + return new BufferedReader (new InputStreamReader (socket.getInputStream (), + "ISO8859_1")); // Then create a buffered input stream + } + else { + return null; // Without a socket we can't create a input stream + } + } + + /** + * + * @return The output stream for this proxy's socket + */ + public OutputStream getOutputStream () throws IOException { + return this.getSocket ().getOutputStream (); + } + + /** + * + */ + protected void setBreakPoints () throws IOException, CoreException { + IBreakpoint[] breakpoints = DebugPlugin.getDefault ().getBreakpointManager ().getBreakpoints (); + + for (int i = 0; i < breakpoints.length; i++) { + if (breakpoints[i].isEnabled ()) { + addBreakpoint (breakpoints[i]); + } + } + } + + /** + * + */ + private String MapPath (PHPLineBreakpoint phpLBP) { + IPath filename; + IPath remotePath; + IPath newpath; + IPath localPath; + String local; + + if (remote) { + filename = phpLBP.getMarker().getResource().getProjectRelativePath(); + filename = remoteSourcePath.append (filename); + } else { + filename = phpLBP.getMarker().getResource().getLocation(); + } + + String path = filename.toOSString(); + + if ((pathmap != null) && remote) { + java.util.Iterator i = pathmap.keySet().iterator(); + + while (i.hasNext()) { + String k = (String) i.next(); + if (path.startsWith(k)) { + path = pathmap.get(k) + path.substring(k.length()); + break; + } + } + } + + if (remoteSourcePath.isEmpty ()) { + if ((pathmap != null) && remote) { + java.util.Iterator iterator = pathmap.keySet().iterator(); + + while (iterator.hasNext ()) { + local = (String) iterator.next (); // Get the local/client side path of the mapping + remotePath = new Path ((String) pathmap.get (local)); // Get the remote/server side path of the mapping + localPath = new Path (local); // Get the remote/server side path of the mapping + + if (localPath.isPrefixOf (filename)) { // Starts the remote/server side file path with the remote/server side mapping path + // dann prefix abhängen und den remote path davorhägen + newpath = filename.removeFirstSegments (localPath.matchingFirstSegments (filename)); + newpath = remotePath.append (newpath); + path = newpath.toString (); + + if (path.substring (0, 1).equals ("/")) { + path = path.replace ('\\', '/'); + } + else { + path = path.replace ('/', '\\'); + } + + return path; + } + } + } + } + else { + if (pathtranslation && remote) { + if (remoteSourcePath.toString ().substring (0, 1).equals ("/")) { + path = path.replace ('\\', '/'); + } + else { + path = path.replace ('/', '\\'); + } + } + } + + return path; + } + + /** + * + */ + public void addBreakpoint (IBreakpoint breakpoint) { + if (DBGInt == null) { + return; + } + + int bpNo = 0; + + try { + PHPLineBreakpoint phpLBP; + + if (breakpoint.getModelIdentifier() == PHPDebugCorePlugin.getUniqueIdentifier()) { + phpLBP = (PHPLineBreakpoint) breakpoint; + + // bpNo= DBGInt.addBreakpoint(phpLBP.getMarker().getResource().getLocation().toOSString(), phpLBP.getLineNumber()); + if (phpLBP.isConditionEnabled ()) { + bpNo = DBGInt.addBreakpoint (MapPath(phpLBP), + phpLBP.getLineNumber(), + phpLBP.getHitCount(), + phpLBP.getCondition ()); + } + else { + bpNo = DBGInt.addBreakpoint (MapPath(phpLBP), + phpLBP.getLineNumber(), + phpLBP.getHitCount(), + ""); + } + + phpLBP.setDBGBpNo(bpNo); + } + } catch (IOException e) { + PHPDebugCorePlugin.log(e); + stop(); + } catch (CoreException e) { + PHPDebugCorePlugin.log(e); + stop(); + } + } + + /** + * + */ + public void removeBreakpoint (IBreakpoint breakpoint) { + if (DBGInt == null) { + return; + } + + try { + PHPLineBreakpoint phpLBP; + + if (breakpoint.getModelIdentifier() == PHPDebugCorePlugin.getUniqueIdentifier ()) { + phpLBP = (PHPLineBreakpoint) breakpoint; + + // bpNo= DBGInt.addBreakpoint(filename.toOSString(), phpLBP.getLineNumber()); + + DBGInt.removeBreakpoint(MapPath(phpLBP), phpLBP.getLineNumber(), phpLBP.getDBGBpNo()); + } + } catch (IOException e) { + PHPDebugCorePlugin.log (e); + stop (); + } catch (CoreException e) { + PHPDebugCorePlugin.log (e); + stop (); + } + } + + /** + * + */ + public void phpLoopNotify () { + phpLoop.notifyWait (); + } + + /** + * + */ + public void startPHPLoop () { + phpLoop = new PHPLoop (); // Create a DBG communication loop object + + phpLoop.start (); // And start the communication loop + } + + /** + * + */ + public void resume () { + try { + DBGInt.continueExecution(); + phpLoop.notifyWait(); + } catch (IOException e) { + PHPeclipsePlugin.log("Debugging session ended.", e); + stop(); + } + } + + /** + * + */ + public void pause () { + try { + if (null != DBGInt) { + DBGInt.pauseExecution(); + } + else { + // TODO Make sure the Suspend action is grayed out + // when DBGInt is null + } + } catch (IOException e) { + PHPDebugCorePlugin.log (e); + stop (); + } + } + + /** + * + */ + protected PHPDebugTarget getDebugTarget() { + return debugTarget; + } + + /** + * Is called by the DebuggerRunner + * + * @param debugTarget + */ + public void setDebugTarget (PHPDebugTarget debugTarget) { + this.debugTarget = debugTarget; + debugTarget.setPHPDBGProxy(this); + } + + /** + * This method is called by a stackframe. + * It reads the variables from PHP via DBG + * + * @param frame The stackframe which wants the variables. + * @return The list of variables for this stackframe. + */ + public Vector readVariables (PHPStackFrame frame) { + try { + return DBGInt.getVariables (frame); // Get the variables from DBG interface + } catch (IOException ioex) { + ioex.printStackTrace (); + throw new RuntimeException (ioex.getMessage ()); + } catch (DebugException ex) { + ex.printStackTrace (); + throw new RuntimeException (ex.getMessage ()); + } + } + + /** + * + * @param frame + * @param evalString + * @return + */ + public PHPVariable[] eval (PHPStackFrame frame, String evalString) { + try { + return DBGInt.evalBlock (frame, evalString); + //return DBGInt.getVariables(frame); + } catch (IOException ioex) { + ioex.printStackTrace(); + throw new RuntimeException(ioex.getMessage()); + } catch (DebugException ex) { + ex.printStackTrace(); + throw new RuntimeException(ex.getMessage()); + } + } + + public void readStepOverEnd (PHPStackFrame stackFrame) { + try { + DBGInt.stepOver(); + phpLoop.notifyWait(); + } catch (Exception e) { + PHPDebugCorePlugin.log(e); + } + } + + public void readStepReturnEnd (PHPStackFrame stackFrame) { + try { + DBGInt.stepOut(); + phpLoop.notifyWait(); + } catch (Exception e) { + PHPDebugCorePlugin.log(e); + } + } + + public void readStepIntoEnd (PHPStackFrame stackFrame) { + try { + DBGInt.stepInto(); + phpLoop.notifyWait(); + } catch (Exception e) { + PHPDebugCorePlugin.log(e); + } + } + + /* + * public PHPStackFrame[] readFrames(PHPThread thread) { //try { //this.println("th " + thread.getId() + " ; f "); //return new + * FramesReader(getMultiReaderStrategy()).readFrames(thread); return null; //} catch (IOException e) { // + * PHPDebugCorePlugin.log(e); // return null; //} + * } + */ + + public void closeSocket() throws IOException { + if (socket != null) { + socket.close(); + } + } + + public void closeServerSocket() throws IOException { + if (server != null) { + server.close(); + } + } + + public int getPort() { + return port; + } + + /** + * + * + */ + class PHPLoop extends Thread { + private boolean shouldStop; + + public PHPLoop () { + shouldStop = false; + this.setName ("PHPDebuggerLoop"); + } + + /** + * + */ + public synchronized void setShouldStop () { + shouldStop = true; // The run loop should stop + + try { + // If the loop thread is blocked on the server socket, + // forcibly unblock it to avoid leaking the thread, + // the socket and the port + closeServerSocket (); + } catch (IOException x) { + // Log this as a warning? + PHPDebugCorePlugin.log (x); + } + } + + /** + * + */ + public synchronized void notifyWait () { + notify (); + } + + /** + * + * + */ + public void run () { + try { + int i; + int timeout; + long interval = 200; // Wait 200 ms maximum for a DBG response + boolean newconnect = false; // + Socket newSocket = null; + PHPStackFrame[] StackList; + PHPDBGInterface newDBGInt; + + // synchronized (this) { + // wait(); + // } + + PHPMainThread = new PHPThread (getDebugTarget (), getPort ()); + PHPMainThread.setName ("Thread [main]"); + timeout = 0; + + // while ((getDebugTarget() == null) && (timeout < 100)) { + // sleep(100); + // timeout++; + // } + // Be sure debug target is set + // PHPMainThread.setDebugTarget(getDebugTarget()); + + getDebugTarget ().addThread (PHPMainThread); + + //System.out.println("Waiting for breakpoints."); + + while (!shouldStop) { // As long as nobody will stop us + newconnect = true; // The first time + + try { + newSocket = server.accept(); // Waits until DBG want to connect + //System.out.println("Accepted! : " + socket.toString()); + } catch (SocketTimeoutException e) { + newconnect = false; // No one wants to connect (connection already done) + } catch (IOException e) { + PHPDebugCorePlugin.log(e); + return; + } + + if (newconnect) { // Is it just after a new connection + if (DBGInt == null) { // Do we have a DBG interface? + server.setSoTimeout(1); // ??? + } + + newDBGInt = new PHPDBGInterface (getReader (newSocket), // Create a new interface + newSocket.getOutputStream (), + thisProxy); + newDBGInt.waitResponse (1000); // Wait for the initial DBG response + newDBGInt.flushAllPackets (); // Read and process the DBG response + + // Check version and session ID + if ((DBGInt == null) || // If we have no interface + (DBGInt.getSID () == newDBGInt.getSID ())) {// or the new session ID is different to the old one + DBGInt = newDBGInt; // Set the new interface as current one + + try { + closeSocket (); + } + catch (IOException e) { + PHPDebugCorePlugin.log (e); + shouldStop = true; + } + + socket = newSocket; + setBreakPoints (); + DBGInt.continueExecution (); // Notify DBG that PHP should continue + } + else { + newDBGInt.continueExecution (); // Notify DBG that PHP should continue + newSocket.close (); + } + } + + if (DBGInt.waitResponse (interval)) { // Wait for a DBG response (200 ms) + DBGInt.flushAllPackets (); // If we got something, read and process it + + if (DBGInt.BPUnderHit != 0) { // ??? + StackList = DBGInt.getStackList (); // Get the stack list from DBGInterface + + if (StackList.length > 0) { // If there is something in stack list + for (i = 0; i < StackList.length; i++) { // For all stack list + StackList[i].setThread (PHPMainThread); // Set the PHPTread for all PHPStackFrames + + if (DBGInt.getModByNo (StackList[i].getModNo ()).equals ("")) { + DBGInt.getSourceTree (); + } + + StackList[i].setFile (DBGInt.getModByNo (StackList[i].getModNo ())); + } + + PHPMainThread.setStackFrames (StackList); + } + + PHPMainThread.suspend (); // Fire debug event + + synchronized (this) { + wait (); + } + } + } + + if (remote) { + if (PHPMainThread.isTerminated ()) { + shouldStop = true; + + break; // Go for terminating the thread + } + } else { + if (PHPMainThread.isTerminated () || + getDebugTarget ().getProcess ().isTerminated ()) { + shouldStop = true; + + break; // Go for terminating the thread + } + } + } + } catch (Exception ex) { + PHPDebugCorePlugin.log (ex); + System.out.println (ex); + } finally { + try { + getDebugTarget ().terminate (); + closeSocket(); + closeServerSocket (); + } catch (IOException e) { + PHPDebugCorePlugin.log (e); + + return; + } + + //System.out.println("Socket loop finished."); + } + } + } +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/LoadPathEntryLabelProvider.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/LoadPathEntryLabelProvider.java new file mode 100644 index 0000000..7831922 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/LoadPathEntryLabelProvider.java @@ -0,0 +1,64 @@ +package net.sourceforge.phpdt.internal.debug.ui.launcher; + +import net.sourceforge.phpdt.internal.debug.ui.PHPDebugUiPlugin; +import net.sourceforge.phpeclipse.LoadPathEntry; + +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.swt.graphics.Image; + +/** + * @author xp4 + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + */ +public class LoadPathEntryLabelProvider implements ILabelProvider { + + /** + * @see ILabelProvider#getImage(Object) + */ + public Image getImage(Object element) { + return null; + } + + /** + * @see ILabelProvider#getText(Object) + */ + public String getText(Object element) { + if (element != null && element.getClass() == LoadPathEntry.class) + return ((LoadPathEntry) element).getProject().getLocation() + .toOSString(); + + PHPDebugUiPlugin + .log(new RuntimeException("Unable to render load path.")); + return null; + } + + /** + * @see IBaseLabelProvider#addListener(ILabelProviderListener) + */ + public void addListener(ILabelProviderListener listener) { + } + + /** + * @see IBaseLabelProvider#dispose() + */ + public void dispose() { + } + + /** + * @see IBaseLabelProvider#isLabelProperty(Object, String) + */ + public boolean isLabelProperty(Object element, String property) { + return false; + } + + /** + * @see IBaseLabelProvider#removeListener(ILabelProviderListener) + */ + public void removeListener(ILabelProviderListener listener) { + } + +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/PHPEnvironmentTab.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/PHPEnvironmentTab.java new file mode 100644 index 0000000..0257ce1 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/PHPEnvironmentTab.java @@ -0,0 +1,775 @@ +package net.sourceforge.phpdt.internal.debug.ui.launcher; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import net.sourceforge.phpdt.internal.debug.ui.PHPDebugUiMessages; +import net.sourceforge.phpdt.internal.debug.ui.PHPDebugUiPlugin; +import net.sourceforge.phpdt.internal.debug.ui.preferences.EditPathMapDialog; +import net.sourceforge.phpdt.internal.debug.ui.preferences.PHPInterpreterPreferencePage; +import net.sourceforge.phpdt.internal.launching.PHPInterpreter; +import net.sourceforge.phpdt.internal.launching.PHPLaunchConfigurationAttribute; +import net.sourceforge.phpdt.internal.launching.PHPRuntime; +import net.sourceforge.phpdt.internal.ui.PHPUiImages; + +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.Path; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.ListViewer; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.TabItem; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; + +public class PHPEnvironmentTab extends AbstractLaunchConfigurationTab { + protected ListViewer loadPathListViewer; + + protected java.util.List installedInterpretersWorkingCopy; + + protected Combo interpreterCombo; + + // protected Button loadPathDefaultButton; + protected Button fRemoteDebugCheckBox; + + protected Button fRemoteDebugTranslate; + + protected Button fOpenDBGSessionInBrowserCheckBox; + + protected Button fPathMapRemoveButton; + + protected Button fPathMapAddButton; + + protected Button fPathMapEditButton; + + protected Text fRemoteSourcePath; + + protected Table fRemoteDebugPathMapTable; + + protected TabFolder tabFolder; + + private class RemoteDebugTabListener extends SelectionAdapter implements + ModifyListener { + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent) + */ + public void modifyText(ModifyEvent e) { + updateLaunchConfigurationDialog(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) + */ + public void widgetSelected(SelectionEvent e) { + Object source = e.getSource(); + if (source == fRemoteDebugPathMapTable) { + setPathMapButtonsEnableState(); + } else if (source == fPathMapAddButton) { + handlePathMapAddButtonSelected(); + } else if (source == fPathMapEditButton) { + handlePathMapEditButtonSelected(); + } else if (source == fPathMapRemoveButton) { + handlePathMapRemoveButtonSelected(); + } else if (source == fRemoteDebugCheckBox) { + setRemoteTabEnableState(); + } else if (source == fRemoteDebugTranslate) { + setRemoteTabEnableState(); + } else { + updateLaunchConfigurationDialog(); + ; + } + + } + + } + + private static final String EMPTY_STRING = ""; //$NON-NLS-1$ + + private RemoteDebugTabListener fListener = new RemoteDebugTabListener(); + + private static final boolean DEFAULT_REMOTE_DEBUG = false; + + private static final boolean DEFAULT_REMOTE_DEBUG_TRANSLATE = false; + + private static final boolean DEFAULT_OPEN_DBGSESSION_IN_BROWSER = true; + + static String[] columnTitles = { + PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.PathMapTableTitle.local"), + PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.PathMapTableTitle.remote") }; + + public PHPEnvironmentTab() { + super(); + } + + public void createControl(Composite parent) { + Composite composite = createPageRoot(parent); + + tabFolder = new TabFolder(composite, SWT.NONE); + GridData gridData = new GridData(GridData.FILL_BOTH); + tabFolder.setLayoutData(gridData); + + // addLoadPathTab(tabFolder); + addInterpreterTab(tabFolder); + addRemoteDebugTab(tabFolder); + } + + protected void addRemoteDebugTab(TabFolder tabFolder) { + Label label; + + TabItem remoteDebugTab = new TabItem(tabFolder, SWT.NONE, 0); + remoteDebugTab + .setText(PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.label")); + + Composite comp = new Composite(tabFolder, SWT.NONE); + comp.setLayout(new GridLayout()); + remoteDebugTab.setControl(comp); + GridData gd; + + fRemoteDebugCheckBox = new Button(comp, SWT.CHECK); + fRemoteDebugCheckBox + .setText(PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.RemoteCheckBox.label")); + fRemoteDebugCheckBox.setLayoutData(new GridData( + GridData.HORIZONTAL_ALIGN_BEGINNING)); + fRemoteDebugCheckBox.addSelectionListener(fListener); + + fRemoteDebugTranslate = new Button(comp, SWT.CHECK); + fRemoteDebugTranslate + .setText(PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.RemoteTranslate.label")); + fRemoteDebugTranslate.setLayoutData(new GridData( + GridData.HORIZONTAL_ALIGN_BEGINNING)); + fRemoteDebugTranslate.addSelectionListener(fListener); + + fOpenDBGSessionInBrowserCheckBox = new Button(comp, SWT.CHECK); + fOpenDBGSessionInBrowserCheckBox + .setText(PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.OpenDBGSessionInBrowserCheckBox.label")); + fOpenDBGSessionInBrowserCheckBox.setLayoutData(new GridData( + GridData.HORIZONTAL_ALIGN_BEGINNING)); + fOpenDBGSessionInBrowserCheckBox.addSelectionListener(fListener); + + label = new Label(comp, SWT.NONE); + label + .setText(PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.RemoteSourcePath.label")); + fRemoteSourcePath = new Text(comp, SWT.BORDER | SWT.SINGLE); + gd = new GridData(GridData.FILL_HORIZONTAL); + fRemoteSourcePath.setLayoutData(gd); + fRemoteSourcePath.addModifyListener(fListener); + + createVerticalSpacer(comp, 1); + + Composite pathMapComp = new Composite(comp, SWT.NONE); + gd = new GridData(GridData.FILL_BOTH); + pathMapComp.setLayoutData(gd); + GridLayout parametersLayout = new GridLayout(); + parametersLayout.numColumns = 2; + parametersLayout.marginHeight = 0; + parametersLayout.marginWidth = 0; + pathMapComp.setLayout(parametersLayout); + + Label pathMapLabel = new Label(pathMapComp, SWT.NONE); + pathMapLabel + .setText(PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.PathMap.label")); + gd = new GridData(); + gd.horizontalSpan = 2; + pathMapLabel.setLayoutData(gd); + + fRemoteDebugPathMapTable = new Table(pathMapComp, SWT.BORDER + | SWT.MULTI); + TableLayout tableLayout = new TableLayout(); + fRemoteDebugPathMapTable.setLayout(tableLayout); + + gd = new GridData(GridData.FILL_BOTH); + fRemoteDebugPathMapTable.setLayoutData(gd); + TableColumn column1 = new TableColumn(this.fRemoteDebugPathMapTable, + SWT.NONE); + column1 + .setText(PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.PathMap.Table.Title.local")); //$NON-NLS-1$ + TableColumn column2 = new TableColumn(this.fRemoteDebugPathMapTable, + SWT.NONE); + column2 + .setText(PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.PathMap.Table.Title.remote")); //$NON-NLS-1$ + tableLayout.addColumnData(new ColumnWeightData(100)); + tableLayout.addColumnData(new ColumnWeightData(100)); + fRemoteDebugPathMapTable.setHeaderVisible(true); + fRemoteDebugPathMapTable.setLinesVisible(true); + fRemoteDebugPathMapTable.addSelectionListener(fListener); + fRemoteDebugPathMapTable.addMouseListener(new MouseAdapter() { + public void mouseDoubleClick(MouseEvent e) { + setPathMapButtonsEnableState(); + if (fPathMapEditButton.isEnabled()) { + handlePathMapEditButtonSelected(); + } + } + }); + // fRemoteDebugPathMapTable.setEnabled(false); + + Composite envButtonComp = new Composite(pathMapComp, SWT.NONE); + GridLayout envButtonLayout = new GridLayout(); + envButtonLayout.marginHeight = 0; + envButtonLayout.marginWidth = 0; + envButtonComp.setLayout(envButtonLayout); + gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING + | GridData.HORIZONTAL_ALIGN_FILL); + envButtonComp.setLayoutData(gd); + + fPathMapAddButton = createPushButton( + envButtonComp, + PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.PathMap.Button.Add.label"), null); //$NON-NLS-1$ + fPathMapAddButton.addSelectionListener(fListener); + // fPathMapAddButton.setEnabled(false); + + fPathMapEditButton = createPushButton( + envButtonComp, + PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.PathMap.Button.Edit.label"), null); //$NON-NLS-1$ + fPathMapEditButton.addSelectionListener(fListener); + // fPathMapEditButton.setEnabled(false); + + fPathMapRemoveButton = createPushButton( + envButtonComp, + PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.remoteDebugTab.PathMap.Button.Remove.label"), null); //$NON-NLS-1$ + fPathMapRemoveButton.addSelectionListener(fListener); + // fPathMapRemoveButton.setEnabled(false); + + } + + void handlePathMapAddButtonSelected() { + EditPathMapDialog dialog = new EditPathMapDialog(getShell(), + "Edit File Map", new String[] { EMPTY_STRING, EMPTY_STRING }); + openNewPathMapDialog(dialog, null); + // dialog.create(); + // if (dialog.open()==EditPathMapDialog.OK) + // { + // TableItem item = new TableItem (fRemoteDebugPathMapTable, SWT.NONE); + // item.setText(0,dialog.getLocalPath()); + // item.setText(1,dialog.getRemotePath()); + // updateLaunchConfigurationDialog(); + // } + // updateLaunchConfigurationDialog(); + setPathMapButtonsEnableState(); + } + + void handlePathMapRemoveButtonSelected() { + int[] selectedIndices = this.fRemoteDebugPathMapTable + .getSelectionIndices(); + this.fRemoteDebugPathMapTable.remove(selectedIndices); + setPathMapButtonsEnableState(); + updateLaunchConfigurationDialog(); + } + + void handlePathMapEditButtonSelected() { + TableItem selectedItem = this.fRemoteDebugPathMapTable.getSelection()[0]; + String local = selectedItem.getText(0); + String remote = selectedItem.getText(1); + EditPathMapDialog dialog = new EditPathMapDialog(getShell(), + "Edit File Map", new String[] { local, remote }); + openNewPathMapDialog(dialog, selectedItem); + } + + /** + * Set the enabled state of whole tab. + */ + private void setRemoteTabEnableState() { + boolean state = fRemoteDebugCheckBox.getSelection(); + fRemoteSourcePath.setEnabled(state); + fRemoteDebugTranslate.setEnabled(state); + + fRemoteDebugPathMapTable.setEnabled(state); + if (!state) { + fPathMapEditButton.setEnabled(false); + fPathMapRemoveButton.setEnabled(false); + fPathMapAddButton.setEnabled(false); + fOpenDBGSessionInBrowserCheckBox.setEnabled(false); + } else { + setPathMapButtonsEnableState(); + } + + updateLaunchConfigurationDialog(); + } + + /** + * Set the enabled state of the three environment variable-related buttons + * based on the selection in the PathMapTable widget. + */ + private void setPathMapButtonsEnableState() { + // just do nothing for now + // + if (fRemoteDebugCheckBox.getSelection()) { + fOpenDBGSessionInBrowserCheckBox.setEnabled(true); + fRemoteDebugTranslate.setEnabled(true); + int selectCount = this.fRemoteDebugPathMapTable + .getSelectionIndices().length; + if (selectCount < 1) { + fPathMapEditButton.setEnabled(false); + fPathMapRemoveButton.setEnabled(false); + } else { + fPathMapRemoveButton.setEnabled(true); + if (selectCount == 1) { + fPathMapEditButton.setEnabled(true); + } else { + fPathMapEditButton.setEnabled(false); + } + } + fPathMapAddButton.setEnabled(true); + } + } + + /** + * Show the specified dialog and update the pathMapTable table based on its + * results. + * + * @param updateItem + * the item to update, or null if adding a new + * item + */ + private void openNewPathMapDialog(EditPathMapDialog dialog, + TableItem updateItem) { + if (dialog.open() != EditPathMapDialog.OK) { + return; + } + String[] pathPair = dialog.getPathPair(); + TableItem tableItem = updateItem; + if (tableItem == null) { + tableItem = getTableItemForName(pathPair[0]); + if (tableItem == null) { + tableItem = new TableItem(this.fRemoteDebugPathMapTable, + SWT.NONE); + } + } + tableItem.setText(pathPair); + this.fRemoteDebugPathMapTable + .setSelection(new TableItem[] { tableItem }); + updateLaunchConfigurationDialog(); + } + + /** + * Helper method that indicates whether the specified parameter name is + * already present in the parameters table. + */ + private TableItem getTableItemForName(String candidateName) { + TableItem[] items = this.fRemoteDebugPathMapTable.getItems(); + for (int i = 0; i < items.length; i++) { + String name = items[i].getText(0); + if (name.equals(candidateName)) { + return items[i]; + } + } + return null; + } + + // protected void addLoadPathTab(TabFolder tabFolder) { + // Composite loadPathComposite = new Composite(tabFolder, SWT.NONE); + // loadPathComposite.setLayout(new GridLayout()); + // + // loadPathListViewer = new ListViewer(loadPathComposite, SWT.BORDER | + // SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL); + // loadPathListViewer.setContentProvider(new ListContentProvider()); + // loadPathListViewer.setLabelProvider(new LoadPathEntryLabelProvider()); + // loadPathListViewer.getList().setLayoutData(new + // GridData(GridData.FILL_BOTH)); + // + // TabItem loadPathTab = new TabItem(tabFolder, SWT.NONE, 0); + // loadPathTab.setText(PHPDebugUiMessages.getString("LaunchConfigurationTab.PHPEnvironment.loadPathTab.label")); + // loadPathTab.setControl(loadPathComposite); + // loadPathTab.setData(loadPathListViewer); + + // loadPathDefaultButton = new Button(loadPathComposite, SWT.CHECK); + // loadPathDefaultButton.setText(PHPDebugUiMessages.getString("LaunchConfigurationTab.PHPEnvironment.loadPathDefaultButton.label")); + // loadPathDefaultButton.setLayoutData(new + // GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); + // loadPathDefaultButton.addSelectionListener(getLoadPathDefaultButtonSelectionListener()); + // + // loadPathDefaultButton.setEnabled(false); //for now, until the load path + // is customizable on the configuration + // } + + protected SelectionListener getLoadPathSelectionListener() { + return new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + System.out.println("Loadpath list selection occurred: " + + e.getSource()); + } + }; + } + + protected SelectionListener getLoadPathDefaultButtonSelectionListener() { + return new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + setUseLoadPathDefaults(((Button) e.getSource()).getSelection()); + } + }; + } + + protected void addInterpreterTab(TabFolder tabFolder) { + Composite interpreterComposite = new Composite(tabFolder, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + layout.marginHeight = 0; + layout.marginWidth = 0; + interpreterComposite.setLayout(layout); + interpreterComposite.setLayoutData(new GridData( + GridData.FILL_HORIZONTAL)); + + createVerticalSpacer(interpreterComposite, 2); + + interpreterCombo = new Combo(interpreterComposite, SWT.READ_ONLY); + interpreterCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + initializeInterpreterCombo(interpreterCombo); + interpreterCombo.addModifyListener(getInterpreterComboModifyListener()); + + Button interpreterAddButton = new Button(interpreterComposite, SWT.PUSH); + interpreterAddButton + .setText(PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.interpreterAddButton.label")); + interpreterAddButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent evt) { + PHPInterpreter newInterpreter = new PHPInterpreter(null); + File phpRuntime = PHPInterpreterPreferencePage.getFile( + getShell(), null); + if (phpRuntime != null) { + newInterpreter.setInstallLocation(phpRuntime); + PHPRuntime.getDefault().addInstalledInterpreter( + newInterpreter); + interpreterCombo.add(newInterpreter.getInstallLocation() + .toString()); + interpreterCombo.select(interpreterCombo + .indexOf(newInterpreter.getInstallLocation() + .toString())); + } + } + }); + + TabItem interpreterTab = new TabItem(tabFolder, SWT.NONE); + interpreterTab + .setText(PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.interpreterTab.label")); + interpreterTab.setControl(interpreterComposite); + } + + protected ModifyListener getInterpreterComboModifyListener() { + return new ModifyListener() { + public void modifyText(ModifyEvent evt) { + updateLaunchConfigurationDialog(); + } + }; + } + + protected void createVerticalSpacer(Composite comp, int colSpan) { + Label label = new Label(comp, SWT.NONE); + GridData gd = new GridData(); + gd.horizontalSpan = colSpan; + label.setLayoutData(gd); + } + + public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { + PHPInterpreter selectedInterpreter = PHPRuntime.getDefault() + .getSelectedInterpreter(); + if (selectedInterpreter != null) { + String interpreterLocation = selectedInterpreter + .getInstallLocation().toString(); + configuration.setAttribute( + PHPLaunchConfigurationAttribute.SELECTED_INTERPRETER, + interpreterLocation); + } + try { + String projectName = configuration.getAttribute( + PHPLaunchConfigurationAttribute.PROJECT_NAME, ""); + if (projectName != "") { + IProject project = ResourcesPlugin.getWorkspace().getRoot() + .getProject(projectName); + if (project != null) { + IPath remotePath = project.getLocation(); + String fileName = configuration.getAttribute( + PHPLaunchConfigurationAttribute.FILE_NAME, ""); + if (fileName != "") { + Path filePath = new Path(fileName); + remotePath = remotePath.append(filePath + .removeLastSegments(1)); + } + configuration.setAttribute( + PHPLaunchConfigurationAttribute.REMOTE_PATH, + remotePath.toOSString()); + } + } + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void initializeFrom(ILaunchConfiguration configuration) { + // initializeLoadPath(configuration); + initializeInterpreterSelection(configuration); + initializeRemoteDebug(configuration); + } + + protected void initializeRemoteDebug(ILaunchConfiguration configuration) { + try { + fRemoteDebugCheckBox.setSelection(configuration.getAttribute( + PHPLaunchConfigurationAttribute.REMOTE_DEBUG, + DEFAULT_REMOTE_DEBUG)); + } catch (CoreException ce) { + fRemoteDebugCheckBox.setSelection(DEFAULT_REMOTE_DEBUG); + } + try { + fRemoteDebugTranslate.setSelection(configuration.getAttribute( + PHPLaunchConfigurationAttribute.REMOTE_DEBUG_TRANSLATE, + DEFAULT_REMOTE_DEBUG_TRANSLATE)); + } catch (CoreException ce) { + fRemoteDebugTranslate.setSelection(DEFAULT_REMOTE_DEBUG_TRANSLATE); + } + try { + fOpenDBGSessionInBrowserCheckBox + .setSelection(configuration + .getAttribute( + PHPLaunchConfigurationAttribute.OPEN_DBGSESSION_IN_BROWSER, + DEFAULT_OPEN_DBGSESSION_IN_BROWSER)); + } catch (CoreException ce) { + fOpenDBGSessionInBrowserCheckBox + .setSelection(DEFAULT_OPEN_DBGSESSION_IN_BROWSER); + } + setRemoteTabEnableState(); + try { + fRemoteSourcePath.setText(configuration.getAttribute( + PHPLaunchConfigurationAttribute.REMOTE_PATH, "")); + } catch (CoreException ce) { + fRemoteSourcePath.setText(""); + } + + updatePathMapFromConfig(configuration); + + } + + private void updatePathMapFromConfig(ILaunchConfiguration config) { + Map envVars = null; + try { + if (config != null) { + envVars = config.getAttribute( + PHPLaunchConfigurationAttribute.FILE_MAP, (Map) null); + } + updatePathMapTable(envVars, this.fRemoteDebugPathMapTable); + setPathMapButtonsEnableState(); + } catch (CoreException ce) { + log(ce); + } + } + + private void updatePathMapTable(Map map, Table tableWidget) { + tableWidget.removeAll(); + if (map == null) { + return; + } + Iterator iterator = map.keySet().iterator(); + while (iterator.hasNext()) { + String key = (String) iterator.next(); + String value = (String) map.get(key); + TableItem tableItem = new TableItem(tableWidget, SWT.NONE); + tableItem.setText(new String[] { key, value }); + } + } + + // protected void initializeLoadPath(ILaunchConfiguration configuration) { + // boolean useDefaultLoadPath = true; + // try { + // useDefaultLoadPath = + // configuration.getAttribute(PHPLaunchConfigurationAttribute.USE_DEFAULT_LOAD_PATH, + // true); + // setUseLoadPathDefaults(useDefaultLoadPath); + // if (useDefaultLoadPath) { + // String projectName = + // configuration.getAttribute(PHPLaunchConfigurationAttribute.PROJECT_NAME, + // ""); + // if (projectName != "") { + // IProject aProject = + // PHPeclipsePlugin.getWorkspace().getRoot().getProject(projectName); + // if ((aProject != null) && JavaCore.isPHPProject(aProject)) { + // JavaProject thePHPProject = new JavaProject(); + // thePHPProject.setProject(aProject); + // List loadPathEntries = thePHPProject.getLoadPathEntries(); + // loadPathListViewer.setInput(loadPathEntries); + // } + // } + // } + // } catch (CoreException e) { + // log(e); + // } + // } + + protected void setUseLoadPathDefaults(boolean useDefaults) { + loadPathListViewer.getList().setEnabled(!useDefaults); + // loadPathDefaultButton.setSelection(useDefaults); + } + + protected void initializeInterpreterSelection( + ILaunchConfiguration configuration) { + String interpreterName = null; + try { + interpreterName = configuration.getAttribute( + PHPLaunchConfigurationAttribute.SELECTED_INTERPRETER, ""); + } catch (CoreException e) { + log(e); + } + if (interpreterName != null && !interpreterName.equals("")) + interpreterCombo.select(interpreterCombo.indexOf(interpreterName)); + } + + protected void initializeInterpreterCombo(Combo interpreterCombo) { + installedInterpretersWorkingCopy = new ArrayList(); + installedInterpretersWorkingCopy.addAll(PHPRuntime.getDefault() + .getInstalledInterpreters()); + + String[] interpreterNames = new String[installedInterpretersWorkingCopy + .size()]; + for (int interpreterIndex = 0; interpreterIndex < installedInterpretersWorkingCopy + .size(); interpreterIndex++) { + PHPInterpreter interpreter = (PHPInterpreter) installedInterpretersWorkingCopy + .get(interpreterIndex); + interpreterNames[interpreterIndex] = interpreter + .getInstallLocation().toString(); + } + interpreterCombo.setItems(interpreterNames); + + PHPInterpreter selectedInterpreter = PHPRuntime.getDefault() + .getSelectedInterpreter(); + if (selectedInterpreter != null) + interpreterCombo.select(interpreterCombo + .indexOf(selectedInterpreter.getInstallLocation() + .toString())); + } + + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + int selectionIndex = interpreterCombo.getSelectionIndex(); + if (selectionIndex >= 0) + configuration.setAttribute( + PHPLaunchConfigurationAttribute.SELECTED_INTERPRETER, + interpreterCombo.getItem(selectionIndex)); + + // configuration.setAttribute(PHPLaunchConfigurationAttribute.USE_DEFAULT_LOAD_PATH, + // loadPathDefaultButton.getSelection()); + + // if (!loadPathDefaultButton.getSelection()) { + // List loadPathEntries = (List) loadPathListViewer.getInput(); + // List loadPathStrings = new ArrayList(); + // for (Iterator iterator = loadPathEntries.iterator(); + // iterator.hasNext();) { + // LoadPathEntry entry = (LoadPathEntry) iterator.next(); + // loadPathStrings.add(entry.getPath().toString()); + // } + // configuration.setAttribute(PHPLaunchConfigurationAttribute.CUSTOM_LOAD_PATH, + // loadPathStrings); + // } + + configuration.setAttribute( + PHPLaunchConfigurationAttribute.REMOTE_DEBUG, + fRemoteDebugCheckBox.getSelection()); + configuration.setAttribute( + PHPLaunchConfigurationAttribute.REMOTE_DEBUG_TRANSLATE, + fRemoteDebugTranslate.getSelection()); + configuration.setAttribute(PHPLaunchConfigurationAttribute.FILE_MAP, + getMapFromPathMapTable()); + configuration.setAttribute(PHPLaunchConfigurationAttribute.REMOTE_PATH, + fRemoteSourcePath.getText()); + configuration.setAttribute( + PHPLaunchConfigurationAttribute.OPEN_DBGSESSION_IN_BROWSER, + fOpenDBGSessionInBrowserCheckBox.getSelection()); + } + + protected Composite createPageRoot(Composite parent) { + Composite composite = new Composite(parent, SWT.NULL); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + composite.setLayout(layout); + createVerticalSpacer(composite, 2); + setControl(composite); + + return composite; + } + + private Map getMapFromPathMapTable() { + TableItem[] items = fRemoteDebugPathMapTable.getItems(); + if (items.length == 0) { + return null; + } + Map map = new HashMap(items.length); + for (int i = 0; i < items.length; i++) { + TableItem item = items[i]; + String key = item.getText(0); + String value = item.getText(1); + map.put(key, value); + } + return map; + } + + public String getName() { + return PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.name"); + } + + public boolean isValid(ILaunchConfiguration launchConfig) { + try { + String selectedInterpreter = launchConfig.getAttribute( + PHPLaunchConfigurationAttribute.SELECTED_INTERPRETER, ""); + if (selectedInterpreter.length() == 0) { + setErrorMessage(PHPDebugUiMessages + .getString("LaunchConfigurationTab.PHPEnvironment.interpreter_not_selected_error_message")); + return false; + } + } catch (CoreException e) { + log(e); + } + + setErrorMessage(null); + return true; + } + + protected void log(Throwable t) { + PHPDebugUiPlugin.log(t); + } + + public Image getImage() { + return PHPUiImages.get(PHPUiImages.IMG_CTOOLS_PHP); + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunner.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunner.java new file mode 100644 index 0000000..6aa5738 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunner.java @@ -0,0 +1,140 @@ +package net.sourceforge.phpdt.internal.launching; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; + +import net.sourceforge.phpdt.internal.core.JavaProject; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IProcess; + +public class InterpreterRunner { + + public InterpreterRunner() { + } + + public IProcess run(InterpreterRunnerConfiguration configuration, + ILaunch launch) { + String commandLine = renderCommandLine(configuration); + File workingDirectory = configuration.getAbsoluteWorkingDirectory(); + + setEnvironmentVariables(configuration); + String[] env = configuration.getEnvironment(); + Process nativePHPProcess = null; + try { + nativePHPProcess = configuration.getInterpreter().exec(commandLine, + workingDirectory, env); + } catch (IOException e) { + throw new RuntimeException("Unable to execute interpreter: " + + commandLine + workingDirectory); + } + + IProcess process = DebugPlugin.newProcess(launch, nativePHPProcess, + renderLabel(configuration)); + process + .setAttribute(PHPLaunchingPlugin.PLUGIN_ID + + ".launcher.cmdline", commandLine); + process.setAttribute(IProcess.ATTR_PROCESS_TYPE, + PHPLaunchConfigurationAttribute.PHP_LAUNCH_PROCESS_TYPE); + + return process; + } + + protected String renderLabel(InterpreterRunnerConfiguration configuration) { + StringBuffer buffer = new StringBuffer(); + + PHPInterpreter interpreter = configuration.getInterpreter(); + buffer.append("PHP "); + buffer.append(interpreter.getCommand()); + buffer.append(" : "); + buffer.append(configuration.getFileName()); + + return buffer.toString(); + } + + protected String renderCommandLine( + InterpreterRunnerConfiguration configuration) { + PHPInterpreter interpreter = configuration.getInterpreter(); + + StringBuffer buffer = new StringBuffer(); + buffer.append(this.getDebugCommandLineArgument()); + // buffer.append(renderLoadPath(configuration)); + buffer.append(" " + configuration.getInterpreterArguments()); + // buffer.append(interpreter.endOfOptionsDelimeter); + buffer.append(" " + + osDependentPath(configuration.getAbsoluteFileName())); + buffer.append(" " + configuration.getProgramArguments()); + + return buffer.toString(); + } + + protected void setEnvironmentVariables( + InterpreterRunnerConfiguration configuration) { + IPath FilePath = new Path(configuration.getAbsoluteFileName()); + String OSFilePath = FilePath.toOSString(); + configuration.addEnvironmentValue("REDIRECT_URL", OSFilePath, true); + configuration.addEnvironmentValue("REQUEST_URI", OSFilePath, true); + configuration.addEnvironmentValue("PATH_INFO", OSFilePath, true); + configuration.addEnvironmentValue("PATH_TRANSLATED", OSFilePath, true); + configuration.addEnvironmentValue("SCRIPT_FILENAME", configuration + .getInterpreter().getCommand(), true); + configuration + .addEnvironmentValue("SERVER_PROTOCOL", "HTTP / 1.1", true); + + configuration.addEnvironmentValue("REDIRECT_QUERY_STRING", "", true); + configuration.addEnvironmentValue("REDIRECT_STATUS", "200", true); + configuration.addEnvironmentValue("SERVER_SOFTWARE", "DBG / 2.1", true); + configuration.addEnvironmentValue("SERVER_NAME", "localhost", true); + configuration.addEnvironmentValue("SERVER_ADDR", "127.0.0.1", true); + configuration.addEnvironmentValue("SERVER_PORT", "80", true); + configuration.addEnvironmentValue("REMOTE_ADDR", "127.0.0.1", true); + + configuration.addEnvironmentValue("GATEWAY_INTERFACE", "CGI / 1.1", + true); + configuration.addEnvironmentValue("REQUEST_METHOD", "GET", true); + + Map stringVars = DebugPlugin.getDefault().getLaunchManager() + .getNativeEnvironment(); + if (stringVars.containsKey("SYSTEMROOT")) + configuration.addEnvironmentValue("SYSTEMROOT", (String) stringVars + .get("SYSTEMROOT"), true); + + } + + protected String renderLoadPath(InterpreterRunnerConfiguration configuration) { + StringBuffer loadPath = new StringBuffer(); + + JavaProject project = configuration.getProject(); + addToLoadPath(loadPath, project.getProject()); + + Iterator referencedProjects = project.getReferencedProjects() + .iterator(); + while (referencedProjects.hasNext()) + addToLoadPath(loadPath, (IProject) referencedProjects.next()); + + return loadPath.toString(); + } + + protected void addToLoadPath(StringBuffer loadPath, IProject project) { + loadPath.append(" -I " + + osDependentPath(project.getLocation().toOSString())); + } + + protected String osDependentPath(String aPath) { + if (Platform.getOS().equals(Platform.OS_WIN32)) + aPath = "\"" + aPath + "\""; + + return aPath; + } + + protected String getDebugCommandLineArgument() { + return ""; + } +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunnerConfiguration.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunnerConfiguration.java new file mode 100644 index 0000000..52fa78a --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunnerConfiguration.java @@ -0,0 +1,207 @@ +package net.sourceforge.phpdt.internal.launching; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import net.sourceforge.phpdt.internal.core.JavaProject; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.internal.ui.launchConfigurations.EnvironmentVariable; + +public class InterpreterRunnerConfiguration { + protected ILaunchConfiguration configuration; + + private HashMap fEnvironment; + + public InterpreterRunnerConfiguration(ILaunchConfiguration aConfiguration) { + configuration = aConfiguration; + fEnvironment = new HashMap(); + } + + public String getAbsoluteFileName() { + IPath path = new Path(getFileName()); + IProject project = getProject().getProject(); + + return project.getLocation().toOSString() + "/" + getFileName(); + } + + public String getFileName() { + String fileName = ""; + + try { + fileName = configuration.getAttribute( + PHPLaunchConfigurationAttribute.FILE_NAME, + "No file specified in configuration"); + } catch (CoreException e) { + } + + return fileName.replace('\\', '/'); + } + + public JavaProject getProject() { + String projectName = ""; + + try { + projectName = configuration.getAttribute( + PHPLaunchConfigurationAttribute.PROJECT_NAME, ""); + } catch (CoreException e) { + PHPLaunchingPlugin.log(e); + } + + IProject project = PHPLaunchingPlugin.getWorkspace().getRoot() + .getProject(projectName); + + JavaProject phpProject = new JavaProject(); + phpProject.setProject(project); + return phpProject; + } + + public File getAbsoluteWorkingDirectory() { + String file = null; + try { + file = configuration.getAttribute( + PHPLaunchConfigurationAttribute.WORKING_DIRECTORY, ""); + } catch (CoreException e) { + PHPLaunchingPlugin.log(e); + } + return new File(file); + } + + public String getInterpreterArguments() { + try { + return configuration.getAttribute( + PHPLaunchConfigurationAttribute.INTERPRETER_ARGUMENTS, ""); + } catch (CoreException e) { + } + + return ""; + } + + public String getProgramArguments() { + try { + return configuration.getAttribute( + PHPLaunchConfigurationAttribute.PROGRAM_ARGUMENTS, ""); + } catch (CoreException e) { + } + + return ""; + } + + public PHPInterpreter getInterpreter() { + String selectedInterpreter = null; + try { + selectedInterpreter = configuration.getAttribute( + PHPLaunchConfigurationAttribute.SELECTED_INTERPRETER, ""); + } catch (CoreException e) { + } + + return PHPRuntime.getDefault().getInterpreter(selectedInterpreter); + } + + public boolean useRemoteDebugger() { + try { + return configuration.getAttribute( + PHPLaunchConfigurationAttribute.REMOTE_DEBUG, false); + } catch (CoreException e) { + PHPLaunchingPlugin.log(e); + } + return false; + } + + public boolean usePathTranslation() { + try { + return configuration.getAttribute( + PHPLaunchConfigurationAttribute.REMOTE_DEBUG_TRANSLATE, + false); + } catch (CoreException e) { + PHPLaunchingPlugin.log(e); + } + return false; + } + + public Map getPathMap() { + try { + return configuration.getAttribute( + PHPLaunchConfigurationAttribute.FILE_MAP, (Map) null); + } catch (CoreException e) { + PHPLaunchingPlugin.log(e); + } + return (Map) null; + } + + public boolean useDBGSessionInBrowser() { + try { + return configuration.getAttribute( + PHPLaunchConfigurationAttribute.OPEN_DBGSESSION_IN_BROWSER, + true); + } catch (CoreException e) { + PHPLaunchingPlugin.log(e); + } + return false; + } + + public void setEnvironment(String[] envp) { + if (envp == null) + return; + for (int i = 0; i < envp.length; i++) { + addEnvironmentValue(envp[i], true); + } + } + + public void addEnvironmentValue(String env, boolean replace) { + String value = env.substring(env.indexOf('=') + 1); + String key = env.substring(0, env.indexOf('=')); + addEnvironmentValue(key, value, replace); + } + + public void addEnvironmentValue(String key, String value, boolean replace) { + if (!replace && fEnvironment.containsKey(key)) { + EnvironmentVariable ev = (EnvironmentVariable) fEnvironment + .get(key); + ev.setValue(ev.getValue() + ";" + value); + fEnvironment.put(key, ev); + } else + this.fEnvironment.put(key, new EnvironmentVariable(key, value)); + } + + public String[] getEnvironment() { + + Iterator iter = fEnvironment.entrySet().iterator(); + List strings = new ArrayList(fEnvironment.size()); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + StringBuffer buffer = new StringBuffer((String) entry.getKey()); + buffer.append('=').append( + ((EnvironmentVariable) entry.getValue()).getValue()); + strings.add(buffer.toString()); + } + return (String[]) strings.toArray(new String[strings.size()]); + + } + + public String getRemoteSourcePath() { + + IProject project = getProject().getProject(); + if (!useRemoteDebugger()) + return project.getLocation().toOSString(); + else { + try { + return configuration.getAttribute( + PHPLaunchConfigurationAttribute.REMOTE_PATH, ""); + } catch (CoreException e) { + PHPLaunchingPlugin.log(e); + } + } + + return ""; + } + +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/PHPSourceLocator.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/PHPSourceLocator.java new file mode 100644 index 0000000..652a6c7 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/PHPSourceLocator.java @@ -0,0 +1,219 @@ +package net.sourceforge.phpdt.internal.launching; + +import java.util.Iterator; +import java.util.Map; + +import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; +import net.sourceforge.phpeclipse.builder.ExternalEditorInput; +import net.sourceforge.phpeclipse.builder.FileStorage; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.model.IPersistableSourceLocator; +import org.eclipse.debug.core.model.IStackFrame; +import org.eclipse.debug.ui.ISourcePresentation; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.FileEditorInput; + +public class PHPSourceLocator implements IPersistableSourceLocator, ISourcePresentation { + private String absoluteWorkingDirectory; + private Map pathMap = null; + private boolean remoteDebug; + private IPath remoteSourcePath; + private String projectName; + + public PHPSourceLocator() { + + } + + public String getAbsoluteWorkingDirectory() { + return absoluteWorkingDirectory; + } + + /** + * @see org.eclipse.debug.core.model.IPersistableSourceLocator#getMemento() + */ + public String getMemento() throws CoreException { + return null; + } + + /** + * @see org.eclipse.debug.core.model.IPersistableSourceLocator#initializeFromMemento(String) + */ + public void initializeFromMemento(String memento) throws CoreException { + } + + /** + * @see org.eclipse.debug.core.model.IPersistableSourceLocator#initializeDefaults(ILaunchConfiguration) + */ + public void initializeDefaults (ILaunchConfiguration configuration) throws CoreException { + this.absoluteWorkingDirectory = configuration.getAttribute (PHPLaunchConfigurationAttribute.WORKING_DIRECTORY, ""); + this.remoteDebug = configuration.getAttribute (PHPLaunchConfigurationAttribute.REMOTE_DEBUG,false); + this.pathMap = configuration.getAttribute (PHPLaunchConfigurationAttribute.FILE_MAP, (Map)null); + this.projectName = configuration.getAttribute (PHPLaunchConfigurationAttribute.PROJECT_NAME, ""); + + if (Platform.getOS().equals(Platform.OS_WIN32)) { + this.remoteSourcePath = new Path ((configuration.getAttribute (PHPLaunchConfigurationAttribute.REMOTE_PATH, "")).toLowerCase()); + } + else { + this.remoteSourcePath = new Path (configuration.getAttribute (PHPLaunchConfigurationAttribute.REMOTE_PATH, "")); + } + +// system.os.name + } + + /** + * @see org.eclipse.debug.core.model.ISourceLocator#getSourceElement(IStackFrame) + * + * Return the client side source filename for the server side source file. + * E.g. when cross debugging, the server side filename could be /var/www/index.php + * on the client side it is either a Eclipse_PHP_projectname\index.php (when it is a linked file) + * + * + * @param stackFrame The stackframe for which we want the client side source file name + * @return The filename as it appears on the client side + */ + public Object getSourceElement (IStackFrame stackFrame) { + IPath projectPath; + IPath remotePath; + IPath path; + IPath localPath; + Iterator iterator; + String fileName; + String file; + String local; + + fileName = ((PHPStackFrame) stackFrame).getFileName (); // Get the filename as it is submitted by DBG + file = ""; + + if (remoteDebug) { // Is it a remote debugging session + path = new Path (fileName); // Create a IPath object for the server side filename + + if (!remoteSourcePath.isEmpty()) { + if (remoteSourcePath.isPrefixOf (path)) { // Is the server side filename with the remote source path + path = path.removeFirstSegments (remoteSourcePath.matchingFirstSegments (path)); // Remove the remote source path + file = path.toString (); // The filename without the remote source path + projectPath = (PHPeclipsePlugin.getWorkspace().getRoot().getProject(projectName).getLocation()); // Get the absolute project path + + return (projectPath.append (path)).toOSString (); // Return the filename as absolute client side path + } + } + else { + if (pathMap == null) { // Do we have path mapping (e.g. for cross platform debugging) + return fileName; // No, then return the filename as it given by DBG (the full server side path) + } + + iterator = pathMap.keySet().iterator(); + + while (iterator.hasNext ()) { + local = (String) iterator.next (); // Get the local/client side path of the mapping + remotePath = new Path ((String) pathMap.get (local)); // Get the remote/server side path of the mapping + + if (remotePath.isPrefixOf (path)) { // Starts the remote/server side file path with the remote/server side mapping path + path = path.removeFirstSegments (remotePath.matchingFirstSegments (path)); // Remove the absolute path from filename + localPath = new Path (local); // Create new IPath object for the local/client side path + path = localPath.append (path); // Prepend the project relative path to filename + + projectPath = (PHPeclipsePlugin.getWorkspace().getRoot().getProject(projectName).getLocation()); // Get the absolute project path + + return (projectPath.append (path)).toOSString (); // Return the filename as absolute client side path + } + } + } + + if (pathMap == null) { // Do we have path mapping (e.g. for cross platform debugging) + return fileName; // No, then return the filename as it given by DBG (the full server side path) + } + + iterator = pathMap.keySet().iterator(); + + while (iterator.hasNext ()) { + local = (String) iterator.next (); // Get the local/client side path of the mapping + remotePath = new Path ((String) pathMap.get (local)); // Get the remote/server side path of the mapping + + if (remotePath.isPrefixOf (path)) { // Starts the remote/server side file path with the remote/server side mapping path + path = path.removeFirstSegments (remotePath.matchingFirstSegments (path)); // Remove the absolute path from filename + localPath = new Path (local); // Create new IPath object for the local/client side path + + return localPath.append (path).toOSString (); // Append the remote filename to the client side path (So we return the absolute path + // to the source file as the client side sees it. + } + } + + return fileName; + } else { + return fileName; + } + } + + /** + * @see org.eclipse.debug.ui.ISourcePresentation#getEditorId(IEditorInput, Object) + */ + public String getEditorId(IEditorInput input, Object element) { + return PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor((String) element).getId(); + } + + /** + * @see org.eclipse.debug.ui.ISourcePresentation#getEditorInput(Object) + * + * @param element The absolute local/client side file path + */ + public IEditorInput getEditorInput (Object element) { + String filename; + IWorkbench workbench; + IWorkbenchWindow window; + IWorkbenchPage page; + IPath path; + IFile eclipseFile; + + filename = (String) element; + workbench = PlatformUI.getWorkbench (); + window = workbench.getWorkbenchWindows ()[0]; + page = window.getActivePage (); + path = new Path (filename); // Create an IPath object of the absolute local/client side file name + + // If the file exists in the workspace, open it + eclipseFile = PHPeclipsePlugin.getWorkspace().getRoot().getFileForLocation (path); + + // IFile eclipseFile = PHPeclipsePlugin.getWorkspace().getRoot().getFileForLocation(new Path(filename)); +// if (eclipseFile == null) { +// filename = this.getAbsoluteWorkingDirectory() + "/" + filename; +// eclipseFile = PHPeclipsePlugin.getWorkspace().getRoot().getFileForLocation(new Path(filename)); +// if (eclipseFile == null) { +// PHPeclipsePlugin.log(IStatus.INFO, "Could not find file \"" + element + "\"."); +// return null; +// } +// } else + + if (eclipseFile == null || !eclipseFile.exists ()) { + // Otherwise open the stream directly + // + if (page == null) { + PHPeclipsePlugin.log(IStatus.INFO, "Could not find file \"" + element + "\"."); + return null; + } + + FileStorage storage = new FileStorage (path); + storage.setReadOnly (); + + // IEditorRegistry registry = workbench.getEditorRegistry(); + // IEditorDescriptor desc = registry.getDefaultEditor(filename); + // if (desc == null) { + // desc = registry.getDefaultEditor(); + // } + return new ExternalEditorInput(storage); + } + + return new FileEditorInput (eclipseFile); + } +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/ui/text/template/DeclarationProposal.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/ui/text/template/DeclarationProposal.java new file mode 100644 index 0000000..d2edd51 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/ui/text/template/DeclarationProposal.java @@ -0,0 +1,283 @@ +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ +package net.sourceforge.phpdt.internal.ui.text.template; + +import net.sourceforge.phpdt.internal.corext.phpdoc.PHPDocUtil; +import net.sourceforge.phpdt.internal.corext.template.TemplateMessages; +import net.sourceforge.phpdt.internal.corext.template.php.JavaContext; +import net.sourceforge.phpdt.internal.ui.PHPUiImages; +import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionManager; +import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionUI; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; +import net.sourceforge.phpeclipse.builder.PHPIdentifierLocation; + +import org.eclipse.core.resources.IProject; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.contentassist.ContextInformation; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.jface.text.templates.TemplateContext; +import org.eclipse.swt.graphics.Image; + +// import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionManager; +// import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionUI; +// import net.sourceforge.phpdt.internal.ui.util.ExceptionHandler; + +/** + * A PHP identifier proposal. + */ +public class DeclarationProposal extends AbstractProposal { // implements + // IPHPCompletionProposal + // { + private IProject fProject; + + private final TemplateContext fContext; + + private final PHPIdentifierLocation fLocation; + + String fInfo; + + // private TemplateBuffer fTemplateBuffer; + // private String fOldText; + // private final Image fImage_fun; + // private final Image fImage_var; + private final IRegion fRegion; + + // private IRegion fSelectedRegion; // initialized by apply() + + private final String fIdentifierName; + + // private final ITextViewer fViewer; + + /** + * Creates a template proposal with a template and its context. + * + * @param template + * the template + * @param context + * the context in which the template was requested. + * @param image + * the icon of the proposal. + */ + public DeclarationProposal(IProject project, String identifierName, + PHPIdentifierLocation location, TemplateContext context, + IRegion region, ITextViewer viewer) { + super(viewer); + // Image image_fun, + // Image image_var) { + fProject = project; + fIdentifierName = identifierName; + fLocation = location; + fContext = context; + fRegion = region; + fInfo = null; + } + + /* + * @see ICompletionProposal#apply(IDocument) + */ + public void apply(IDocument document) { + try { + // if (fTemplateBuffer == null) + // fTemplateBuffer= fContext.evaluate(fTemplate); + + int start = fRegion.getOffset(); + int end = fRegion.getOffset() + fRegion.getLength(); + + switch (fLocation.getType()) { + case PHPIdentifierLocation.FUNCTION: + document.replace(start, end - start, fIdentifierName + "()"); + break; + case PHPIdentifierLocation.CONSTRUCTOR: + document.replace(start, end - start, fIdentifierName + "()"); + break; + case PHPIdentifierLocation.METHOD: + document.replace(start, end - start, fIdentifierName + "()"); + break; + + default: + document.replace(start, end - start, fIdentifierName); + } + + // translate positions + LinkedPositionManager manager = new LinkedPositionManager(document); + // TemplatePosition[] variables= fTemplateBuffer.getVariables(); + // for (int i= 0; i != variables.length; i++) { + // TemplatePosition variable= variables[i]; + // + // if (variable.isResolved()) + // continue; + // + // int[] offsets= variable.getOffsets(); + // int length= variable.getLength(); + // + // for (int j= 0; j != offsets.length; j++) + // manager.addPosition(offsets[j] + start, length); + // } + + LinkedPositionUI editor = new LinkedPositionUI(fViewer, manager); + switch (fLocation.getType()) { + case PHPIdentifierLocation.FUNCTION: + editor + .setFinalCaretOffset(fIdentifierName.length() + start + + 1); + break; + case PHPIdentifierLocation.CONSTRUCTOR: + editor + .setFinalCaretOffset(fIdentifierName.length() + start + + 1); + break; + case PHPIdentifierLocation.METHOD: + editor + .setFinalCaretOffset(fIdentifierName.length() + start + + 1); + break; + + default: + editor.setFinalCaretOffset(fIdentifierName.length() + start); + } + editor.enter(); + + fSelectedRegion = editor.getSelectedRegion(); + + } catch (BadLocationException e) { + PHPeclipsePlugin.log(e); + openErrorDialog(e); + + } + // catch (CoreException e) { + // handleException(e); + // } + } + + /* + * @see ICompletionProposal#getAdditionalProposalInfo() + */ + public String getAdditionalProposalInfo() { + if (fInfo == null) { + fInfo = computeProposalInfo(); + } + return fInfo; + } + + private String computeProposalInfo() { + StringBuffer hoverInfoBuffer = new StringBuffer(); + // String workspaceLocation = + // PHPeclipsePlugin.getWorkspace().getRoot().getLocation().toString(); + String workspaceLocation; + if (fProject != null) { + workspaceLocation = fProject.getLocation().toString() + '/'; + } else { + // should never happen? + workspaceLocation = PHPeclipsePlugin.getWorkspace().getRoot() + .getLocation().toString(); + } + String filename = workspaceLocation + fLocation.getFilename(); + PHPDocUtil.appendPHPDoc(hoverInfoBuffer, filename, fLocation); + return hoverInfoBuffer.toString(); + } + + public IContextInformation getContextInformation() { + if (fContextInfo == null) { + if (fLocation != null) { + fInfo = fLocation.getUsage(); + if (fInfo != null) { + // extract the parameter context information for the + // function: + int i0 = fInfo.indexOf('('); + int newline = fInfo.indexOf('\n'); + if (i0 >= 0 && (i0 < newline || newline < 0)) { + int i1 = fInfo.indexOf(')', i0 + 1); + if (i1 > 0) { + + fContextInfo = new ContextInformation(null, fInfo + .substring(i0 + 1, i1)); + } else { + fContextInfo = new ContextInformation(null, fInfo); + } + } else { + fContextInfo = new ContextInformation(null, fInfo); + } + } + } + } + return fContextInfo; + } + + /* + * @see ICompletionProposal#getDisplayString() + */ + public String getDisplayString() { + String workspaceLocation; + if (fProject != null) { + workspaceLocation = fProject.getName().toString() + '/'; + } else { + // should never happen? + workspaceLocation = PHPeclipsePlugin.getWorkspace().getRoot() + .getLocation().toString(); + } + String filename = workspaceLocation + fLocation.getFilename(); + String usage = PHPDocUtil.getUsage(filename, fLocation); + String result = fIdentifierName + + TemplateMessages.getString("TemplateProposal.delimiter"); + if (usage.length() > 0) { + result += usage + + TemplateMessages.getString("TemplateProposal.delimiter"); + } + result += filename; + return result; + } + + /* + * @see ICompletionProposal#getImage() + */ + public Image getImage() { + switch (fLocation.getType()) { + case PHPIdentifierLocation.FUNCTION: + return PHPUiImages.get(PHPUiImages.IMG_FUN); + case PHPIdentifierLocation.CLASS: + return PHPUiImages.get(PHPUiImages.IMG_CLASS); + case PHPIdentifierLocation.CONSTRUCTOR: + return PHPUiImages.get(PHPUiImages.IMG_CLASS); + case PHPIdentifierLocation.METHOD: + return PHPUiImages.get(PHPUiImages.IMG_FUN); + case PHPIdentifierLocation.DEFINE: + return PHPUiImages.get(PHPUiImages.IMG_DEFINE); + case PHPIdentifierLocation.VARIABLE: + return PHPUiImages.get(PHPUiImages.IMG_VAR); + case PHPIdentifierLocation.GLOBAL_VARIABLE: + return PHPUiImages.get(PHPUiImages.IMG_VAR); + } + return PHPUiImages.get(PHPUiImages.IMG_FUN); + } + + /* + * @see IJavaCompletionProposal#getRelevance() + */ + public int getRelevance() { + + if (fContext instanceof JavaContext) { + JavaContext context = (JavaContext) fContext; + switch (context.getCharacterBeforeStart()) { + // high relevance after whitespace + case ' ': + case '\r': + case '\n': + case '\t': + return 80; + case '>': // -> + case ':': // :: + return 85; + default: + return 0; + } + } else { + return 80; + } + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/ui/util/PHPFileUtil.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/ui/util/PHPFileUtil.java new file mode 100644 index 0000000..d17c8e4 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/ui/util/PHPFileUtil.java @@ -0,0 +1,201 @@ +/* + * Created on 09.08.2003 + * + */ +package net.sourceforge.phpdt.internal.ui.util; + +import java.io.File; +import java.util.List; + +import net.sourceforge.phpeclipse.PHPeclipsePlugin; +import net.sourceforge.phpeclipse.ui.overlaypages.ProjectPrefUtil; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.ui.IEditorDescriptor; +import org.eclipse.ui.IEditorRegistry; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; + +public class PHPFileUtil { + // private static String[] PHP_EXTENSIONS = null; + + public final static String[] SMARTY_EXTENSIONS = { "tpl" }; + + public static boolean isPHPFile(IFile file) { + // String extension = file.getFileExtension(); + return isPHPFileName(file.getLocation().toString()); + } + + // public final static String getFileExtension(String name) { + // int index = name.lastIndexOf('.'); + // if (index == -1) + // return null; + // if (index == (name.length() - 1)) + // return null; //$NON-NLS-1$ + // return name.substring(index + 1); + // } + + /** + * Returns true iff str.toLowerCase().endsWith(".php") implementation is not + * creating extra strings. + */ + public final static boolean isPHPFileName(String name) { + + // avoid handling a file without base name, e.g. ".php", which is a + // valid + // Eclipse resource name + File file = new File(name); + if (file.getName().startsWith(".")) { + return false; + } + IWorkbench workbench = PlatformUI.getWorkbench(); + IEditorRegistry registry = workbench.getEditorRegistry(); + IEditorDescriptor[] descriptors = registry.getEditors(name); + + for (int i = 0; i < descriptors.length; i++) { + if (descriptors[i].getId().equals(PHPeclipsePlugin.EDITOR_ID)) { + return true; + } + } + // String extension = getFileExtension(name); + // if (extension == null) { + // return false; + // } + // extension = extension.toLowerCase(); + // PHP_EXTENSIONS = getExtensions(); + // if (PHP_EXTENSIONS == null) { + // return false; + // } + // for (int i = 0; i < PHP_EXTENSIONS.length; i++) { + // if (extension.equals(PHP_EXTENSIONS[i])) { + // return true; + // } + // } + return false; + } + + /** + * Returns true iff the file extension is a valid PHP Unit name + * implementation is not creating extra strings. + */ + public final static boolean isValidPHPUnitName(String filename) { + return PHPFileUtil.isPHPFileName(filename); + } + + /** + * @return Returns the PHP extensions. + */ + // public static String[] getExtensions() { + // if (PHP_EXTENSIONS == null) { + // ArrayList list = new ArrayList(); + // final IPreferenceStore store = + // PHPeclipsePlugin.getDefault().getPreferenceStore(); + // String extensions = + // store.getString(PHPeclipsePlugin.PHP_EXTENSION_PREFS); + // extensions = extensions.trim(); + // if (extensions.length() != 0) { + // StringTokenizer tokenizer = new StringTokenizer(extensions, " ,;:/-|"); + // String token; + // while (tokenizer.hasMoreTokens()) { + // token = tokenizer.nextToken(); + // if (token != null && token.length() >= 1) { + // list.add(token); + // } + // } + // if (list.size() != 0) { + // PHP_EXTENSIONS = new String[list.size()]; + // for (int i = 0; i < list.size(); i++) { + // PHP_EXTENSIONS[i] = (String) list.get(i); + // } + // } + // } + // } + // return PHP_EXTENSIONS; + // } + /** + * @param php_extensions + * The PHP extensions to set. + */ + // public static void setExtensions(String[] php_extensions) { + // PHP_EXTENSIONS = php_extensions; + // } + /** + * Creata the file for the given absolute file path + * + * @param absoluteFilePath + * @param project + * @return the file for the given absolute file path or null + * if no existing file can be found + */ + public static IFile createFile(IPath absoluteFilePath, IProject project) { + if (absoluteFilePath == null || project == null) { + return null; + } + + String projectPath = project.getLocation().toString(); + String filePath = absoluteFilePath.toString().substring( + projectPath.length() + 1); + return project.getFile(filePath); + + } + + /** + * Determine the path of an include name string + * + * @param includeNameString + * @param resource + * @param project + * @return the path for the given include filename or null if + * no existing file can be found + */ + public static IPath determineFilePath(String includeNameString, + IResource resource, IProject project) { + IPath documentRootPath = ProjectPrefUtil.getDocumentRoot(project); + IPath resourcePath = resource.getProjectRelativePath(); + + File file = null; + IPath path = null; + path = documentRootPath.append(includeNameString); + file = path.toFile(); + if (file.exists()) { + return path; + } + + if (includeNameString.startsWith("../")) { + path = project.getLocation().append( + resourcePath.removeLastSegments(1)); + path = path.append(includeNameString); + file = path.toFile(); + if (file.exists()) { + return path; + } + } + + // includeNameString contains no path separator + path = project.getLocation().append(resourcePath.removeLastSegments(1)); + path = path.append(includeNameString); + file = path.toFile(); + if (file.exists()) { + return path; + } + // } + + List includePaths = ProjectPrefUtil.getIncludePaths(project); + if (includePaths.size() > 0) { + for (int i = 0; i < includePaths.size(); i++) { + path = new Path(includePaths.get(i).toString()) + .append(includeNameString); + file = path.toFile(); + if (file.exists()) { + return path; + } + } + } + return null; + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/ltk/core/RenameIdentifierDelegate.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/ltk/core/RenameIdentifierDelegate.java new file mode 100644 index 0000000..beaf423 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/ltk/core/RenameIdentifierDelegate.java @@ -0,0 +1,386 @@ +// Copyright (c) 2005 by Leif Frenzel. All rights reserved. +// See http://leiffrenzel.de +// modified for phpeclipse.de project by axelcl +package net.sourceforge.phpdt.ltk.core; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.parser.Scanner; +import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError; +import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.ltk.core.refactoring.Change; +import org.eclipse.ltk.core.refactoring.CompositeChange; +import org.eclipse.ltk.core.refactoring.RefactoringStatus; +import org.eclipse.ltk.core.refactoring.TextFileChange; +import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; +import org.eclipse.ltk.core.refactoring.participants.IConditionChecker; +import org.eclipse.ltk.core.refactoring.participants.ValidateEditChecker; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.text.edits.ReplaceEdit; + +/** + *

+ * delegate object that contains the logic used by the processor. + *

+ * + */ +public class RenameIdentifierDelegate { + + // private static final String EXT_PROPERTIES = "properties"; //$NON-NLS-1$ + + protected final RenameIdentifierInfo info; + + // PHP file with the identifier to rename -> offset of the key + protected final Map phpFiles; + + public RenameIdentifierDelegate(final RenameIdentifierInfo info) { + this.info = info; + phpFiles = new HashMap(); + } + + RefactoringStatus checkInitialConditions() { + RefactoringStatus result = new RefactoringStatus(); + IFile sourceFile = info.getSourceFile(); + if (sourceFile == null || !sourceFile.exists()) { + result.addFatalError(CoreTexts.renamePropertyDelegate_noSourceFile); + } else if (info.getSourceFile().isReadOnly()) { + result.addFatalError(CoreTexts.renamePropertyDelegate_roFile); + } else if (isEmpty(info.getOldName())) { + // || !isPropertyKey( info.getSourceFile(), info.getOldName() ) ) { + result.addFatalError(CoreTexts.renamePropertyDelegate_noPHPKey); + } + return result; + } + + RefactoringStatus checkFinalConditions(final IProgressMonitor pm, + final CheckConditionsContext ctxt) { + RefactoringStatus result = new RefactoringStatus(); + pm.beginTask(CoreTexts.renamePropertyDelegate_checking, 100); + // do something long-running here: traverse the entire project (or even + // workspace) to look for all *.properties files with the same bundle + // base name + IContainer rootContainer; + ArrayList phpProjects = new ArrayList(); + IProject project; + if (info.isAllProjects()) { + rootContainer = ResourcesPlugin.getWorkspace().getRoot(); + IResource[] members; + try { + members = rootContainer.members(); + for (int i = 0; i < members.length; i++) { + if (members[i] instanceof IProject) { + project = (IProject) members[i]; + try { + if (project + .isNatureEnabled(PHPeclipsePlugin.PHP_NATURE_ID)) { + search(project, result); + } + } catch (CoreException e) { + String msg = "Project: " + + project.getLocation().toOSString() + + " CoreException " + e.getMessage(); + result.addError(msg); + } catch (Exception e) { + String msg = "Project: " + + project.getLocation().toOSString() + + " Exception " + e.getMessage(); + result.addError(msg); + } + } + } + } catch (CoreException e) { + String msg = "Workspace: " + + rootContainer.getLocation().toOSString() + + " CoreException " + e.getMessage(); + result.addError(msg); + } + } else { + project = info.getSourceFile().getProject(); + try { + if (project.isNatureEnabled(PHPeclipsePlugin.PHP_NATURE_ID)) { + search(project, result); + } + } catch (CoreException e) { + String msg = "Project: " + project.getLocation().toOSString() + + " CoreException " + e.getMessage(); + result.addError(msg); + } catch (Exception e) { + String msg = "Project: " + project.getLocation().toOSString() + + " Exception " + e.getMessage(); + result.addError(msg); + } + } + + pm.worked(50); + + if (ctxt != null) { + IFile[] files = new IFile[phpFiles.size()]; + phpFiles.keySet().toArray(files); + IConditionChecker checker = ctxt + .getChecker(ValidateEditChecker.class); + ValidateEditChecker editChecker = (ValidateEditChecker) checker; + editChecker.addFiles(files); + } + pm.done(); + return result; + } + + protected void createChange(final IProgressMonitor pm, + final CompositeChange rootChange) { + try { + pm.beginTask(CoreTexts.renamePropertyDelegate_collectingChanges, + 100); + // all files in the same bundle + if (info.isUpdateProject()) { + rootChange.addAll(createChangesForContainer(pm)); + } + } finally { + pm.done(); + } + } + + // helping methods + // //////////////// + + // private Change createRenameChange() { + // // create a change object for the file that contains the property the + // // user has selected to rename + // IFile file = info.getSourceFile(); + // TextFileChange result = new TextFileChange(file.getName(), file); + // // a file change contains a tree of edits, first add the root of them + // MultiTextEdit fileChangeRootEdit = new MultiTextEdit(); + // result.setEdit(fileChangeRootEdit); + // + // // edit object for the text replacement in the file, this is the only + // child + // ReplaceEdit edit = new ReplaceEdit(info.getOffset(), + // info.getOldName().length(), info.getNewName()); + // fileChangeRootEdit.addChild(edit); + // return result; + // } + + protected Change[] createChangesForContainer(final IProgressMonitor pm) { + List result = new ArrayList(); + Iterator it = phpFiles.keySet().iterator(); + int numberOfFiles = phpFiles.size(); + double percent = 100 / numberOfFiles; + int work = 0; + int indx = 0; + while (it.hasNext()) { + IFile file = (IFile) it.next(); + List list = getKeyOffsets(file); + if (list != null && list.size() > 0) { + TextFileChange tfc = new TextFileChange(file.getName(), file); + MultiTextEdit fileChangeRootEdit = new MultiTextEdit(); + tfc.setEdit(fileChangeRootEdit); + + // edit object for the text replacement in the file, there could + // be + // multiple childs + ReplaceEdit edit; + for (int i = 0; i < list.size(); i++) { + edit = new ReplaceEdit(((Integer) list.get(i)).intValue(), + info.getOldName().length(), info.getNewName()); + fileChangeRootEdit.addChild(edit); + } + result.add(tfc); + } + work = new Double((++indx) * percent).intValue(); + pm.worked(work); + } + return (Change[]) result.toArray(new Change[result.size()]); + } + + protected boolean isEmpty(final String candidate) { + return candidate == null || candidate.trim().length() == 0; + } + + // private boolean isPropertyKey( final IFile file, final String candidate ) + // { + // boolean result = false; + // try { + // Properties props = new Properties(); + // props.load( file.getContents() ); + // result = props.containsKey( candidate ); + // } catch( Exception ex ) { + // // ignore this, we just assume this is not a favourable situation + // ex.printStackTrace(); + // } + // return result; + // } + + // // whether the file is a PHP file with the same base name as the + // // one we refactor and contains the key that interests us + // private boolean isToRefactor(final IFile file) { + // return PHPFileUtil.isPHPFile(file); + // // && !file.equals( info.getSourceFile() ) + // // && isPropertyKey( file, info.getOldName() ); + // } + + // private String getBundleBaseName() { + // String result = info.getSourceFile().getName(); + // int underscoreIndex = result.indexOf( '_' ); + // if( underscoreIndex != -1 ) { + // result = result.substring( 0, underscoreIndex ); + // } else { + // int index = result.indexOf( EXT_PROPERTIES ) - 1; + // result = result.substring( 0, index ); + // } + // return result; + // } + + private void search(final IContainer rootContainer, + final RefactoringStatus status) { + try { + IResource[] members = rootContainer.members(); + for (int i = 0; i < members.length; i++) { + if (members[i] instanceof IContainer) { + search((IContainer) members[i], status); + } else { + IFile file = (IFile) members[i]; + handleFile(file, status); + } + } + } catch (final CoreException cex) { + status.addFatalError(cex.getMessage()); + } + } + + private void handleFile(final IFile file, final RefactoringStatus status) { + if (PHPFileUtil.isPHPFile(file)) { + determineKeyOffsets(file, status); + // if (keyOffsets.size() > 0) { + // Integer offset = new Integer(keyOffsets); + // phpFiles.put(file, offset); + // } + } + } + + protected List getKeyOffsets(final IFile file) { + return (List) phpFiles.get(file); + } + + // finds the offsets of the identifier to rename + // usually, this would be the job of a proper parser; + // using a primitive brute-force approach here + private void determineKeyOffsets(final IFile file, + final RefactoringStatus status) { + ArrayList matches = new ArrayList(); + try { + String content = readFileContent(file, status); + Scanner scanner = new Scanner(true, false); + scanner.setSource(content.toCharArray()); + scanner.setPHPMode(false); + char[] word = info.getOldName().toCharArray(); + + int fToken = ITerminalSymbols.TokenNameEOF; + try { + fToken = scanner.getNextToken(); + while (fToken != ITerminalSymbols.TokenNameEOF) { + if (fToken == ITerminalSymbols.TokenNameVariable + || fToken == ITerminalSymbols.TokenNameIdentifier) { + if (scanner.equalsCurrentTokenSource(word)) { + matches.add(new Integer(scanner + .getCurrentTokenStartPosition())); + } + } + fToken = scanner.getNextToken(); + } + + } catch (InvalidInputException e) { + String msg = "File: " + file.getLocation().toOSString() + + " InvalidInputException " + e.getMessage(); + status.addError(msg); + } catch (SyntaxError e) { + String msg = "File: " + file.getLocation().toOSString() + + " SyntaxError " + e.getMessage(); + status.addError(msg); + } + + } catch (Exception e) { + String msg = "File: " + file.getLocation().toOSString() + + " Exception " + e.getMessage(); + status.addError(msg); + } + if (matches.size() > 0) { + phpFiles.put(file, matches); + } + + // int result = -1; + // int candidateIndex = content.indexOf(info.getOldName()); + // result = candidateIndex; + // while( result == -1 && candidateIndex != -1 ) { + // if( isKeyOccurrence( content, candidateIndex ) ) { + // result = candidateIndex; + // } + // } + // if( result == -1 ) { + // // still nothing found, we add a warning to the status + // // (we have checked the file contains the property, so that we can't + // // determine it's offset is probably because of the rough way + // employed + // // here to find it) + // String msg = CoreTexts.renamePropertyDelegate_propNotFound + // + file.getLocation().toOSString(); + // status.addWarning( msg ); + // } + // return result; + } + + private String readFileContent(final IFile file, + final RefactoringStatus refStatus) { + String result = null; + try { + InputStream is = file.getContents(); + byte[] buf = new byte[1024]; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + int len = is.read(buf); + while (len > 0) { + bos.write(buf, 0, len); + len = is.read(buf); + } + is.close(); + result = new String(bos.toByteArray()); + } catch (Exception ex) { + String msg = ex.toString(); + refStatus.addFatalError(msg); + String pluginId = PHPeclipsePlugin.getPluginId(); + IStatus status = new Status(IStatus.ERROR, pluginId, 0, msg, ex); + PHPeclipsePlugin.getDefault().getLog().log(status); + } + return result; + } + + // we check only that there is a separator before the next line break (this + // is not sufficient, the whole thing may be in a comment etc. ...) + // private boolean isKeyOccurrence( final String content, + // final int candidateIndex ) { + // int index = candidateIndex + info.getOldName().length(); + // // skip whitespace + // while( content.charAt( index ) == ' ' || content.charAt( index ) == '\t' + // ) + // { + // index++; + // } + // return content.charAt( index ) == '=' || content.charAt( index ) == ':'; + // } +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/ltk/core/RenameLocalVariableDelegate.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/ltk/core/RenameLocalVariableDelegate.java new file mode 100644 index 0000000..b61f6a4 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/ltk/core/RenameLocalVariableDelegate.java @@ -0,0 +1,262 @@ +// Copyright (c) 2005 by Leif Frenzel. All rights reserved. +// See http://leiffrenzel.de +// modified for phpeclipse.de project by axelcl +package net.sourceforge.phpdt.ltk.core; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.util.ArrayList; + +import net.sourceforge.phpdt.core.ISourceRange; +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.parser.Scanner; +import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError; +import net.sourceforge.phpdt.internal.core.SourceMethod; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.ltk.core.refactoring.CompositeChange; +import org.eclipse.ltk.core.refactoring.RefactoringStatus; +import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; +import org.eclipse.ltk.core.refactoring.participants.IConditionChecker; +import org.eclipse.ltk.core.refactoring.participants.ValidateEditChecker; + +/** + *

+ * delegate object that contains the logic used by the processor. + *

+ * + */ +public class RenameLocalVariableDelegate extends RenameIdentifierDelegate { + + public RenameLocalVariableDelegate(final RenameIdentifierInfo info) { + super(info); + } + + RefactoringStatus checkInitialConditions() { + RefactoringStatus result = new RefactoringStatus(); + IFile sourceFile = info.getSourceFile(); + if (sourceFile == null || !sourceFile.exists()) { + result.addFatalError(CoreTexts.renamePropertyDelegate_noSourceFile); + } else if (info.getSourceFile().isReadOnly()) { + result.addFatalError(CoreTexts.renamePropertyDelegate_roFile); + } else if (isEmpty(info.getOldName())) { + // || !isPropertyKey( info.getSourceFile(), info.getOldName() ) ) { + result.addFatalError(CoreTexts.renamePropertyDelegate_noPHPKey); + } + return result; + } + + RefactoringStatus checkFinalConditions(final IProgressMonitor pm, + final CheckConditionsContext ctxt) { + RefactoringStatus result = new RefactoringStatus(); + pm.beginTask(CoreTexts.renamePropertyDelegate_checking, 100); + // do something long-running here: traverse the entire project (or even + // workspace) to look for all *.p files with the same bundle + // base name + IFile file = info.getSourceFile(); + IProject project = file.getProject(); + try { + SourceMethod method = info.getMethod(); + ISourceRange range = method.getSourceRange(); + if (project.isNatureEnabled(PHPeclipsePlugin.PHP_NATURE_ID)) { + determineMethodOffsets(file, range.getOffset(), range + .getLength(), result); + } + } catch (CoreException e) { + String msg = "Project: " + project.getLocation().toOSString() + + " CoreException " + e.getMessage(); + result.addError(msg); + } catch (Exception e) { + String msg = "Project: " + project.getLocation().toOSString() + + " Exception " + e.getMessage(); + result.addError(msg); + } + + pm.worked(50); + + if (ctxt != null) { + IFile[] files = new IFile[phpFiles.size()]; + phpFiles.keySet().toArray(files); + IConditionChecker checker = ctxt + .getChecker(ValidateEditChecker.class); + ValidateEditChecker editChecker = (ValidateEditChecker) checker; + editChecker.addFiles(files); + } + pm.done(); + return result; + } + + protected void createChange(final IProgressMonitor pm, + final CompositeChange rootChange) { + try { + pm.beginTask(CoreTexts.renamePropertyDelegate_collectingChanges, + 100); + // all files in the same bundle + rootChange.addAll(createChangesForContainer(pm)); + } finally { + pm.done(); + } + } + + private void determineMethodOffsets(final IFile file, int offset, + int length, final RefactoringStatus status) { + ArrayList matches = new ArrayList(); + try { + String content = readFileContent(file, status); + + // + // Find a PHPdoc directly before the method + // + Scanner firstScanner = new Scanner(true, false); + firstScanner.setSource(content.toCharArray()); + int fToken = ITerminalSymbols.TokenNameEOF; + int start = 0; + int phpdocStart = -1; + try { + fToken = firstScanner.getNextToken(); + while (fToken != ITerminalSymbols.TokenNameEOF + && start < offset) { + if (fToken == ITerminalSymbols.TokenNameCOMMENT_PHPDOC) { + phpdocStart = firstScanner + .getCurrentTokenStartPosition(); + } else { + phpdocStart = -1; + } + fToken = firstScanner.getNextToken(); + start = firstScanner.getCurrentTokenStartPosition(); + } + + } catch (InvalidInputException e) { + String msg = "File: " + file.getLocation().toOSString() + + " InvalidInputException " + e.getMessage(); + status.addError(msg); + } catch (SyntaxError e) { + String msg = "File: " + file.getLocation().toOSString() + + " SyntaxError " + e.getMessage(); + status.addError(msg); + } + + // + // Find matches for the word in the PHPdoc+method declaration + // + if (phpdocStart >= 0 && phpdocStart < offset) { + length += offset - phpdocStart; + offset = phpdocStart; + } + String methodString = content.substring(offset, offset + length); + Scanner secondScanner = new Scanner(true, false); + secondScanner.setSource(methodString.toCharArray()); + secondScanner.setPHPMode(true); + String wordStr = info.getOldName(); + boolean renameDQString = info.isRenameDQString(); + boolean renamePHPdoc = info.isRenamePHPdoc(); + boolean renameOtherComments = info.isRenameOtherComments(); + char[] word = wordStr.toCharArray(); + + fToken = ITerminalSymbols.TokenNameEOF; + // double quoted string + String tokenString; + // double quoted string offset + int tokenOffset; + int index; + try { + fToken = secondScanner.getNextToken(); + while (fToken != ITerminalSymbols.TokenNameEOF) { + if (fToken == ITerminalSymbols.TokenNameVariable) { + if (secondScanner.equalsCurrentTokenSource(word)) { + // the current variable token is equal to the given + // word + matches.add(new Integer(secondScanner + .getCurrentTokenStartPosition() + + offset)); + } + } else if (fToken == ITerminalSymbols.TokenNameStringDoubleQuote + && renameDQString) { + // determine the word in double quoted strings: + tokenString = new String(secondScanner + .getCurrentTokenSource()); + tokenOffset = secondScanner + .getCurrentTokenStartPosition(); + index = -1; + while ((index = tokenString.indexOf(wordStr, index + 1)) >= 0) { + matches.add(new Integer(offset + tokenOffset + + index)); + } + } else if (fToken == ITerminalSymbols.TokenNameCOMMENT_PHPDOC + && renamePHPdoc) { + tokenString = new String(secondScanner + .getCurrentTokenSource()); + tokenOffset = secondScanner + .getCurrentTokenStartPosition(); + index = -1; + while ((index = tokenString.indexOf(wordStr, index + 1)) >= 0) { + matches.add(new Integer(offset + tokenOffset + + index)); + } + } else if ((fToken == ITerminalSymbols.TokenNameCOMMENT_BLOCK || fToken == ITerminalSymbols.TokenNameCOMMENT_LINE) + && renameOtherComments) { + tokenString = new String(secondScanner + .getCurrentTokenSource()); + tokenOffset = secondScanner + .getCurrentTokenStartPosition(); + index = -1; + while ((index = tokenString.indexOf(wordStr, index + 1)) >= 0) { + matches.add(new Integer(offset + tokenOffset + + index)); + } + } + fToken = secondScanner.getNextToken(); + } + + } catch (InvalidInputException e) { + String msg = "File: " + file.getLocation().toOSString() + + " InvalidInputException " + e.getMessage(); + status.addError(msg); + } catch (SyntaxError e) { + String msg = "File: " + file.getLocation().toOSString() + + " SyntaxError " + e.getMessage(); + status.addError(msg); + } + + } catch (Exception e) { + String msg = "File: " + file.getLocation().toOSString() + + " Exception " + e.getMessage(); + status.addError(msg); + } + if (matches.size() > 0) { + phpFiles.put(file, matches); + } + } + + private String readFileContent(final IFile file, + final RefactoringStatus refStatus) { + String result = null; + try { + InputStream is = file.getContents(); + byte[] buf = new byte[1024]; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + int len = is.read(buf); + while (len > 0) { + bos.write(buf, 0, len); + len = is.read(buf); + } + is.close(); + result = new String(bos.toByteArray()); + } catch (Exception ex) { + String msg = ex.toString(); + refStatus.addFatalError(msg); + String pluginId = PHPeclipsePlugin.getPluginId(); + IStatus status = new Status(IStatus.ERROR, pluginId, 0, msg, ex); + PHPeclipsePlugin.getDefault().getLog().log(status); + } + return result; + } + +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/IncludesScanner.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/IncludesScanner.java new file mode 100644 index 0000000..bb1c88f --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/IncludesScanner.java @@ -0,0 +1,187 @@ +package net.sourceforge.phpeclipse.actions; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.parser.Scanner; +import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError; +import net.sourceforge.phpdt.internal.compiler.util.Util; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Path; +import org.eclipse.ui.IFileEditorInput; + +public class IncludesScanner implements ITerminalSymbols { + // private final PHPOpenAllIncludesEditorAction fOpenAllIncludesAction; + private IProject fProject; + + private IFileEditorInput fEditorInput; + + private HashSet fSet; + + public IncludesScanner(IProject project, IFileEditorInput editorInput) { + fProject = project; + // fOpenAllIncludesAction = action; + fEditorInput = editorInput; + fSet = new HashSet(); + } + + /** + * Add the information for a given IFile resource + * + */ + public void addFile(IFile fileToParse) { + + try { + if (fileToParse.exists()) { + addInputStream(new BufferedInputStream(fileToParse + .getContents()), fileToParse.getProjectRelativePath() + .toString()); + } + } catch (CoreException e1) { + e1.printStackTrace(); + } + } + + private void addInputStream(InputStream stream, String filePath) + throws CoreException { + try { + if (fSet.add(filePath)) { // new entry in set + parseIdentifiers(Util.getInputStreamAsCharArray(stream, -1, + null)); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + } + } + } + + /** + * Get the next token from input + */ + private int getNextToken(Scanner scanner) { + int token; + try { + token = scanner.getNextToken(); + if (Scanner.DEBUG) { + int currentEndPosition = scanner.getCurrentTokenEndPosition(); + int currentStartPosition = scanner + .getCurrentTokenStartPosition(); + System.out.print(currentStartPosition + "," + + currentEndPosition + ": "); + System.out.println(scanner.toStringAction(token)); + } + return token; + } catch (InvalidInputException e) { + } + return TokenNameERROR; + } + + private void parseIdentifiers(char[] charArray) { + char[] ident; + IFile file; + String identifier; + int counter = 0; + + Scanner scanner = new Scanner(false, false, false, false, true, null, + null, true /* taskCaseSensitive */); + scanner.setSource(charArray); + scanner.setPHPMode(false); + int token = getNextToken(scanner); + try { + while (token != TokenNameEOF) { // && fToken != TokenNameERROR) { + if (token == TokenNameinclude || token == TokenNameinclude_once + || token == TokenNamerequire + || token == TokenNamerequire_once) { + while (token != TokenNameEOF && token != TokenNameERROR + && token != TokenNameSEMICOLON + && token != TokenNameRPAREN + && token != TokenNameLBRACE + && token != TokenNameRBRACE) { + token = getNextToken(scanner); + if (token == TokenNameStringDoubleQuote + || token == TokenNameStringSingleQuote) { + char[] includeName = scanner + .getCurrentStringLiteralSource(); + try { + file = getIncludeFile(new String(includeName)); + addFile(file); + } catch (Exception e) { + // ignore + } + break; + } + } + } + token = getNextToken(scanner); + } + } catch (SyntaxError e) { + // e.printStackTrace(); + } + } + + private IContainer getWorkingLocation(IFileEditorInput editorInput) { + if (editorInput == null || editorInput.getFile() == null) { + return null; + } + return editorInput.getFile().getParent(); + } + + public IFile getIncludeFile(String relativeFilename) { + IContainer container = getWorkingLocation(fEditorInput); + String fullPath = fProject.getLocation().toString(); + IFile file = null; + if (relativeFilename.startsWith("../")) { + Path path = new Path(relativeFilename); + file = container.getFile(path); + return file; + } + int index = relativeFilename.lastIndexOf('/'); + + if (index >= 0) { + Path path = new Path(relativeFilename); + file = fProject.getFile(path); + if (file.exists()) { + return file; + } + } + Path path = new Path(relativeFilename); + file = container.getFile(path); + + return file; + } + + /** + * Returns a list of includes + * + * @return the determined list of includes + */ + public List getList() { + ArrayList list = new ArrayList(); + list.addAll(fSet); + return list; + } + + /** + * @return Returns the set. + */ + public Set getSet() { + return fSet; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/OpenDeclarationEditorAction.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/OpenDeclarationEditorAction.java new file mode 100644 index 0000000..6d4e18b --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/OpenDeclarationEditorAction.java @@ -0,0 +1,304 @@ +/*********************************************************************************************************************************** + * Copyright (c) 2000, 2002 IBM Corp. and others. All rights reserved. This program and the accompanying materials are made + * available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: www.phpeclipse.de + **********************************************************************************************************************************/ +package net.sourceforge.phpeclipse.actions; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil; +import net.sourceforge.phpdt.internal.ui.viewsupport.ListContentProvider; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; +import net.sourceforge.phpeclipse.builder.IdentifierIndexManager; +import net.sourceforge.phpeclipse.builder.PHPIdentifierLocation; +import net.sourceforge.phpeclipse.phpeditor.PHPEditor; +import net.sourceforge.phpeclipse.phpeditor.php.PHPWordExtractor; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.graphics.Point; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.dialogs.ListSelectionDialog; + +public class OpenDeclarationEditorAction { + + private PHPEditor fEditor; + + private IProject fProject; + + private boolean isIncludeString; + + public OpenDeclarationEditorAction(PHPEditor editor) { + fEditor = editor; + fProject = null; + isIncludeString = false; + } + + /** + * @param selection + */ + protected void openSelectedElement(ITextSelection selection) { + IDocument doc = fEditor.getDocumentProvider().getDocument( + fEditor.getEditorInput()); + int pos = selection.getOffset(); + openSelectedPosition(doc, pos); + } + + protected void openSelectedPosition(IDocument doc, int position) { + IFile f = ((IFileEditorInput) fEditor.getEditorInput()).getFile(); + fProject = f.getProject(); + // System.out.println(selection.getText()); + String identifierOrInclude = getIdentifierOrInclude(doc, position); + // System.out.println(word); + if (identifierOrInclude != null && !identifierOrInclude.equals("")) { + if (isIncludeString) { + openIncludeFile(identifierOrInclude); + } else { + openIdentifierDeclaration(f, identifierOrInclude); + } + } + } + + /** + * @param filename + */ + private void openIncludeFile(String filename) { + if (filename != null && !filename.equals("")) { + try { + IFile currentFile = ((IFileEditorInput) fEditor + .getEditorInput()).getFile(); + IPath path = PHPFileUtil.determineFilePath(filename, + currentFile, fProject); + if (path != null) { + IFile file = PHPFileUtil.createFile(path, fProject); + if (file != null && file.exists()) { + PHPeclipsePlugin.getDefault().openFileInTextEditor( + file.getLocation().toString()); + return; + } + } + } catch (Exception e) { + // ignore + } + + try { + + IdentifierIndexManager indexManager = PHPeclipsePlugin + .getDefault().getIndexManager(fProject); + // filename = StringUtil.replaceRegExChars(filename); + List list = indexManager.getFileList(filename); + if (list != null && list.size() > 0) { + // String workspaceLocation = + // PHPeclipsePlugin.getWorkspace().getRoot().getLocation().toString(); + String workspaceLocation = fProject.getLocation() + .toString() + + java.io.File.separatorChar; + + ListSelectionDialog listSelectionDialog = new ListSelectionDialog( + PHPeclipsePlugin.getDefault().getWorkbench() + .getActiveWorkbenchWindow().getShell(), + list, new ListContentProvider(), + new LabelProvider(), "Select the includes to open."); + listSelectionDialog.setTitle("Multiple includes found"); + if (listSelectionDialog.open() == Window.OK) { + Object[] locations = listSelectionDialog.getResult(); + if (locations != null) { + try { + for (int i = 0; i < locations.length; i++) { + // PHPIdentifierLocation location = + // (PHPIdentifierLocation) + // locations[i]; + String openFilename = workspaceLocation + + ((String) locations[i]); + PHPeclipsePlugin.getDefault() + .openFileInTextEditor(openFilename); + } + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + } + } catch (Exception e) { + } + + } + return; + } + + /** + * @param f + * @param identiifer + */ + private void openIdentifierDeclaration(IFile f, String identiifer) { + if (identiifer != null && !identiifer.equals("")) { + IdentifierIndexManager indexManager = PHPeclipsePlugin.getDefault() + .getIndexManager(fProject); + List locationsList = indexManager.getLocations(identiifer); + if (locationsList != null && locationsList.size() > 0) { + + // String workspaceLocation = + // PHPeclipsePlugin.getWorkspace().getRoot() + // .getLocation().toString(); + + String workspaceLocation = fProject.getLocation().toString() + + java.io.File.separatorChar; + // TODO show all entries of the list in a dialog box + // at the moment always the first entry will be opened + if (locationsList.size() > 1) { + // determine all includes: + IncludesScanner includesScanner = new IncludesScanner( + fProject, (IFileEditorInput) fEditor + .getEditorInput()); + includesScanner.addFile(f); + Set exactIncludeSet = includesScanner.getSet(); + + PHPIdentifierLocation includeName; + for (int i = 0; i < locationsList.size(); i++) { + includeName = (PHPIdentifierLocation) locationsList + .get(i); + if (exactIncludeSet.contains(includeName.getFilename())) { + includeName + .setMatch(PHPIdentifierLocation.EXACT_MATCH); + } else { + includeName + .setMatch(PHPIdentifierLocation.UNDEFINED_MATCH); + } + } + Collections.sort(locationsList); + + ListSelectionDialog listSelectionDialog = new ListSelectionDialog( + PHPeclipsePlugin.getDefault().getWorkbench() + .getActiveWorkbenchWindow().getShell(), + locationsList, new ListContentProvider(), + new LabelProvider(), + "Select the resources to open."); + listSelectionDialog.setTitle("Multiple declarations found"); + if (listSelectionDialog.open() == Window.OK) { + Object[] locations = listSelectionDialog.getResult(); + if (locations != null) { + try { + for (int i = 0; i < locations.length; i++) { + PHPIdentifierLocation location = (PHPIdentifierLocation) locations[i]; + String filename = workspaceLocation + + location.getFilename(); + // System.out.println(filename); + if (location.getOffset() >= 0) { + PHPeclipsePlugin.getDefault() + .openFileAndGotoOffset( + filename, + location.getOffset(), + identiifer.length()); + } else { + PHPeclipsePlugin.getDefault() + .openFileAndFindString( + filename, identiifer); + } + } + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } else { + try { + PHPIdentifierLocation location = (PHPIdentifierLocation) locationsList + .get(0); + String filename = workspaceLocation + + location.getFilename(); + // System.out.println(filename); + if (location.getOffset() >= 0) { + PHPeclipsePlugin.getDefault() + .openFileAndGotoOffset(filename, + location.getOffset(), + identiifer.length()); + } else { + PHPeclipsePlugin + .getDefault() + .openFileAndFindString(filename, identiifer); + } + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + } + + private String getIdentifierOrInclude(IDocument doc, int pos) { + // private String getPHPIncludeText(IDocument doc, int pos) { + Point word = null; + int start = -1; + int end = -1; + isIncludeString = false; + try { + // try to find an include string + int position = pos; + char character = ' '; + + while (position >= 0) { + character = doc.getChar(position); + if ((character == '\"') || (character == '\'') + || (character == '\r') || (character == '\n')) + break; + --position; + } + if ((character == '\"') || (character == '\'')) { + start = position; + + position = pos; + int length = doc.getLength(); + character = ' '; + while (position < length) { + character = doc.getChar(position); + if ((character == '\"') || (character == '\'') + || (character == '\r') || (character == '\n')) + break; + ++position; + } + if ((character == '\"') || (character == '\'')) { + start++; + end = position; + + if (end > start) { + word = new Point(start, end - start); // include name + // found + isIncludeString = true; + } + } + } + + // try to find an identifier + if (word == null) { + word = PHPWordExtractor.findWord(doc, pos); // identifier found + isIncludeString = false; + } + } catch (BadLocationException x) { + } + + if (word != null) { + try { + return doc.get(word.x, word.y); + } catch (BadLocationException e) { + } + } + return ""; + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/PHPOpenAllIncludesEditorAction.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/PHPOpenAllIncludesEditorAction.java new file mode 100644 index 0000000..3dd63ff --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/actions/PHPOpenAllIncludesEditorAction.java @@ -0,0 +1,242 @@ +/******************************************************************************* + * Copyright (c) 2000, 2002 IBM Corp. and others. All rights reserved. This + * program and the accompanying materials are made available under the terms of + * the Common Public License v1.0 which accompanies this distribution, and is + * available at http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: www.phpeclipse.de + ******************************************************************************/ +package net.sourceforge.phpeclipse.actions; + +import java.io.File; +import java.util.List; + +import net.sourceforge.phpdt.internal.ui.viewsupport.ListContentProvider; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; +import net.sourceforge.phpeclipse.phpeditor.PHPEditor; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.graphics.Point; +import org.eclipse.ui.IEditorActionDelegate; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.actions.ActionDelegate; +import org.eclipse.ui.dialogs.ListSelectionDialog; + +public class PHPOpenAllIncludesEditorAction extends ActionDelegate implements + IEditorActionDelegate { + + private IWorkbenchWindow fWindow; + + private PHPEditor fEditor; + + private IProject fProject; + + private IncludesScanner fIncludesScanner; + + public void dispose() { + } + + public void init(IWorkbenchWindow window) { + this.fWindow = window; + } + + public void selectionChanged(IAction action, ISelection selection) { + if (!selection.isEmpty()) { + if (selection instanceof TextSelection) { + action.setEnabled(true); + } else if (fWindow.getActivePage() != null + && fWindow.getActivePage().getActivePart() != null) { + // + } + } + } + + private IWorkbenchPage getActivePage() { + IWorkbenchWindow workbenchWindow = fEditor.getEditorSite() + .getWorkbenchWindow(); + IWorkbenchPage page = workbenchWindow.getActivePage(); + return page; + } + + public IContainer getWorkingLocation(IFileEditorInput editorInput) { + if (editorInput == null || editorInput.getFile() == null) { + return null; + } + return editorInput.getFile().getParent(); + } + + private IFile getIncludeFile(IProject project, + IFileEditorInput editorInput, String relativeFilename) { + IContainer container = getWorkingLocation(editorInput); + String fullPath = project.getLocation().toString(); + IFile file = null; + if (relativeFilename.startsWith("../")) { + Path path = new Path(relativeFilename); + file = container.getFile(path); + return file; + } + int index = relativeFilename.lastIndexOf('/'); + + if (index >= 0) { + Path path = new Path(relativeFilename); + file = project.getFile(path); + if (file.exists()) { + return file; + } + } + + Path path = new Path(relativeFilename); + file = container.getFile(path); + + return file; + } + + public void run(IAction action) { + if (fEditor == null) { + IEditorPart targetEditor = fWindow.getActivePage() + .getActiveEditor(); + if (targetEditor != null && (targetEditor instanceof PHPEditor)) { + fEditor = (PHPEditor) targetEditor; + } + } + if (fEditor != null) { + // determine the current Project from a (file-based) Editor + IFile f = ((IFileEditorInput) fEditor.getEditorInput()).getFile(); + fProject = f.getProject(); + // System.out.println(fProject.toString()); + + ITextSelection selection = (ITextSelection) fEditor + .getSelectionProvider().getSelection(); + IDocument doc = fEditor.getDocumentProvider().getDocument( + fEditor.getEditorInput()); + fIncludesScanner = new IncludesScanner(fProject, + (IFileEditorInput) fEditor.getEditorInput()); + int pos = selection.getOffset(); + // System.out.println(selection.getText()); + String filename = getPHPIncludeText(doc, pos); + + if (filename != null && !filename.equals("")) { + try { + IFile file = fIncludesScanner.getIncludeFile(filename); + fIncludesScanner.addFile(file); + } catch (Exception e) { + // ignore + } + + try { + + List list = fIncludesScanner.getList(); + if (list != null && list.size() > 0) { + // String workspaceLocation = + // PHPeclipsePlugin.getWorkspace().getRoot().getLocation().toString(); + String workspaceLocation = fProject.getLocation() + .toString() + + File.separatorChar; + + ListSelectionDialog listSelectionDialog = new ListSelectionDialog( + PHPeclipsePlugin.getDefault().getWorkbench() + .getActiveWorkbenchWindow().getShell(), + list, new ListContentProvider(), + new LabelProvider(), + "Select the includes to open."); + listSelectionDialog.setTitle("Multiple includes found"); + if (listSelectionDialog.open() == Window.OK) { + Object[] locations = listSelectionDialog + .getResult(); + if (locations != null) { + try { + for (int i = 0; i < locations.length; i++) { + // PHPIdentifierLocation location = + // (PHPIdentifierLocation) + // locations[i]; + String openFilename = workspaceLocation + + ((String) locations[i]); + PHPeclipsePlugin.getDefault() + .openFileInTextEditor( + openFilename); + } + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + } + } catch (Exception e) { + } + + } + } + } + + public void setActiveEditor(IAction action, IEditorPart targetEditor) { + if (targetEditor != null && (targetEditor instanceof PHPEditor)) { + fEditor = (PHPEditor) targetEditor; + } + } + + private String getPHPIncludeText(IDocument doc, int pos) { + Point word = null; + int start = -1; + int end = -1; + + try { + + int position = pos; + char character; + + while (position >= 0) { + character = doc.getChar(position); + if ((character == '\"') || (character == '\'') + || (character == '\r') || (character == '\n')) + break; + --position; + } + + start = position; + + position = pos; + int length = doc.getLength(); + + while (position < length) { + character = doc.getChar(position); + if ((character == '\"') || (character == '\'') + || (character == '\r') || (character == '\n')) + break; + ++position; + } + + start++; + end = position; + + if (end > start) + word = new Point(start, end - start); + + } catch (BadLocationException x) { + } + + if (word != null) { + try { + return doc.get(word.x, word.y); + } catch (BadLocationException e) { + } + } + return ""; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/obfuscator/ObfuscatorIgnores.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/obfuscator/ObfuscatorIgnores.java new file mode 100644 index 0000000..46a585e --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/obfuscator/ObfuscatorIgnores.java @@ -0,0 +1,119 @@ +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ +package net.sourceforge.phpeclipse.obfuscator; + +import java.io.File; +import java.io.InputStream; + +import net.sourceforge.phpeclipse.PHPeclipsePlugin; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.dialogs.ErrorDialog; + +/** + * ObfuscatorIgnores gives access to the available templates. + */ +public class ObfuscatorIgnores extends ObfuscatorIgnoreSet { + + private static final String DEFAULT_FILE = "default-obfuscator.xml"; //$NON-NLS-1$ + + private static final String TEMPLATE_FILE = "obfuscator.xml"; //$NON-NLS-1$ + + /** Singleton. */ + private static ObfuscatorIgnores fgIgnores; + + private IProject fProject; + + public ObfuscatorIgnores(IProject project) { + fProject = project; + try { + File templateFile = getTemplateFile(); + if (templateFile.exists()) { + addFromFile(templateFile); + } else { + addFromStream(getDefaultsAsStream()); + saveToFile(templateFile); + } + + } catch (CoreException e) { + PHPeclipsePlugin.log(e); + ErrorDialog.openError(null, ObfuscatorMessages + .getString("Obfuscator.error.title"), //$NON-NLS-1$ + e.getMessage(), e.getStatus()); + + clear(); + } + } + + /** + * Returns an instance of templates. + */ + // public static ObfuscatorIgnores getInstance() { + // if (fgIgnores == null) + // fgIgnores = create(); + // + // return fgIgnores; + // } + // + // private static ObfuscatorIgnores create() { + // ObfuscatorIgnores templates = new ObfuscatorIgnores(); + // + // try { + // File templateFile = getTemplateFile(); + // if (templateFile.exists()) { + // templates.addFromFile(templateFile); + // } else { + // templates.addFromStream(getDefaultsAsStream()); + // templates.saveToFile(templateFile); + // } + // + // } catch (CoreException e) { + // PHPeclipsePlugin.log(e); + // ErrorDialog.openError(null, + // ObfuscatorMessages.getString("Templates.error.title"), //$NON-NLS-1$ + // e.getMessage(), e.getStatus()); + // + // templates.clear(); + // } + // + // return templates; + // } + /** + * Resets the template set. + */ + public void reset() throws CoreException { + clear(); + addFromFile(getTemplateFile()); + } + + /** + * Resets the template set with the default templates. + */ + public void restoreDefaults() throws CoreException { + clear(); + addFromStream(getDefaultsAsStream()); + } + + /** + * Saves the template set. + */ + public void save() throws CoreException { + saveToFile(getTemplateFile()); + } + + private InputStream getDefaultsAsStream() { + return ObfuscatorIgnores.class.getResourceAsStream(DEFAULT_FILE); + } + + private File getTemplateFile() { + IPath path = fProject.getLocation(); + // PHPeclipsePlugin.getDefault().getStateLocation(); + path = path.append(TEMPLATE_FILE); + + return path.toFile(); + } +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/obfuscator/export/WizardObfuscatorResourceExportPage1.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/obfuscator/export/WizardObfuscatorResourceExportPage1.java new file mode 100644 index 0000000..bb5dd99 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/obfuscator/export/WizardObfuscatorResourceExportPage1.java @@ -0,0 +1,505 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package net.sourceforge.phpeclipse.obfuscator.export; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Widget; +import org.eclipse.ui.dialogs.WizardExportResourcesPage; + +/** + * Page 1 of the base resource export-to-file-system Wizard + */ +/* package */ +class WizardObfuscatorResourceExportPage1 extends WizardExportResourcesPage + implements Listener { + + // widgets + private Combo destinationNameField; + + private Button destinationBrowseButton; + + protected Button overwriteExistingFilesCheckbox; + + // protected Button createDirectoryStructureButton; + // protected Button createSelectionOnlyButton; + + // constants + private static final int SIZING_TEXT_FIELD_WIDTH = 250; + + // dialog store id constants + private static final String STORE_DESTINATION_NAMES_ID = "WizardObfuscatorResourceExportPage1.STORE_DESTINATION_NAMES_ID"; //$NON-NLS-1$ + + private static final String STORE_OVERWRITE_EXISTING_FILES_ID = "WizardObfuscatorResourceExportPage1.STORE_OVERWRITE_EXISTING_FILES_ID"; //$NON-NLS-1$ + // private static final String STORE_CREATE_STRUCTURE_ID = + // "WizardObfuscatorResourceExportPage1.STORE_CREATE_STRUCTURE_ID"; + // //$NON-NLS-1$ + + // messages + private static final String SELECT_DESTINATION_MESSAGE = ObfuscatorExportMessages + .getString("FileExport.selectDestinationMessage"); //$NON-NLS-1$ + + private static final String SELECT_DESTINATION_TITLE = ObfuscatorExportMessages + .getString("FileExport.selectDestinationTitle"); //$NON-NLS-1$ + + /** + * Create an instance of this class + */ + protected WizardObfuscatorResourceExportPage1(String name, + IStructuredSelection selection) { + super(name, selection); + } + + /** + * Create an instance of this class + */ + public WizardObfuscatorResourceExportPage1(IStructuredSelection selection) { + this("fileSystemExportPage1", selection); //$NON-NLS-1$ + setTitle(ObfuscatorExportMessages + .getString("ObfuscatorTransfer.fileSystemTitle")); //$NON-NLS-1$ + setDescription(ObfuscatorExportMessages + .getString("FileExport.exportLocalFileSystem")); //$NON-NLS-1$ + } + + /** + * Add the passed value to self's destination widget's history + * + * @param value + * java.lang.String + */ + protected void addDestinationItem(String value) { + destinationNameField.add(value); + } + + /** + * (non-Javadoc) Method declared on IDialogPage. + */ + public void createControl(Composite parent) { + super.createControl(parent); + giveFocusToDestination(); + // WorkbenchHelp.setHelp( + // getControl(), + // IDataTransferHelpContextIds.FILE_SYSTEM_EXPORT_WIZARD_PAGE); + } + + /** + * Create the export destination specification widgets + * + * @param parent + * org.eclipse.swt.widgets.Composite + */ + protected void createDestinationGroup(Composite parent) { + + Font font = parent.getFont(); + // destination specification group + Composite destinationSelectionGroup = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + destinationSelectionGroup.setLayout(layout); + destinationSelectionGroup.setLayoutData(new GridData( + GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL)); + destinationSelectionGroup.setFont(font); + + Label destinationLabel = new Label(destinationSelectionGroup, SWT.NONE); + destinationLabel.setText(getDestinationLabel()); + destinationLabel.setFont(font); + + // destination name entry field + destinationNameField = new Combo(destinationSelectionGroup, SWT.SINGLE + | SWT.BORDER); + destinationNameField.addListener(SWT.Modify, this); + destinationNameField.addListener(SWT.Selection, this); + GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL + | GridData.GRAB_HORIZONTAL); + data.widthHint = SIZING_TEXT_FIELD_WIDTH; + destinationNameField.setLayoutData(data); + destinationNameField.setFont(font); + + // destination browse button + destinationBrowseButton = new Button(destinationSelectionGroup, + SWT.PUSH); + destinationBrowseButton.setText(ObfuscatorExportMessages + .getString("ObfuscatorTransfer.browse")); //$NON-NLS-1$ + destinationBrowseButton.addListener(SWT.Selection, this); + destinationBrowseButton.setFont(font); + setButtonLayoutData(destinationBrowseButton); + + new Label(parent, SWT.NONE); // vertical spacer + } + + /** + * Create the buttons in the options group. + */ + + protected void createOptionsGroupButtons(Group optionsGroup) { + + Font font = optionsGroup.getFont(); + createOverwriteExisting(optionsGroup, font); + + // createDirectoryStructureOptions(optionsGroup, font); + } + + /** + * Create the buttons for the group that determine if the entire or selected + * directory structure should be created. + * + * @param optionsGroup + * @param font + */ + // protected void createDirectoryStructureOptions( + // Group optionsGroup, + // Font font) { + // // create directory structure radios + // createDirectoryStructureButton = + // new Button(optionsGroup, SWT.RADIO | SWT.LEFT); + // createDirectoryStructureButton.setText(ObfuscatorExportMessages.getString("FileExport.createDirectoryStructure")); + // //$NON-NLS-1$ + // createDirectoryStructureButton.setSelection(false); + // createDirectoryStructureButton.setFont(font); + // + // // create directory structure radios + // createSelectionOnlyButton = + // new Button(optionsGroup, SWT.RADIO | SWT.LEFT); + // createSelectionOnlyButton.setText( + // ObfuscatorExportMessages.getString( + // "FileExport.createSelectedDirectories"));//$NON-NLS-1$ + // createSelectionOnlyButton.setSelection(true); + // createSelectionOnlyButton.setFont(font); + // } + /** + * Create the button for checking if we should ask if we are going to + * overwrite existing files. + * + * @param optionsGroup + * @param font + */ + protected void createOverwriteExisting(Group optionsGroup, Font font) { + // overwrite... checkbox + overwriteExistingFilesCheckbox = new Button(optionsGroup, SWT.CHECK + | SWT.LEFT); + overwriteExistingFilesCheckbox.setText(ObfuscatorExportMessages + .getString("ExportFile.overwriteExisting")); //$NON-NLS-1$ + overwriteExistingFilesCheckbox.setFont(font); + } + + /** + * Attempts to ensure that the specified directory exists on the local file + * system. Answers a boolean indicating success. + * + * @return boolean + * @param directory + * java.io.File + */ + protected boolean ensureDirectoryExists(File directory) { + if (!directory.exists()) { + if (!queryYesNoQuestion(ObfuscatorExportMessages + .getString("ObfuscatorTransfer.createTargetDirectory"))) //$NON-NLS-1$ + return false; + + if (!directory.mkdirs()) { + displayErrorDialog(ObfuscatorExportMessages + .getString("ObfuscatorTransfer.directoryCreationError")); //$NON-NLS-1$ + giveFocusToDestination(); + return false; + } + } + + return true; + } + + /** + * If the target for export does not exist then attempt to create it. Answer + * a boolean indicating whether the target exists (ie.- if it either + * pre-existed or this method was able to create it) + * + * @return boolean + */ + protected boolean ensureTargetIsValid(File targetDirectory) { + if (targetDirectory.exists() && !targetDirectory.isDirectory()) { + displayErrorDialog(ObfuscatorExportMessages + .getString("FileExport.directoryExists")); //$NON-NLS-1$ + giveFocusToDestination(); + return false; + } + + return ensureDirectoryExists(targetDirectory); + } + + /** + * Set up and execute the passed Operation. Answer a boolean indicating + * success. + * + * @return boolean + */ + protected boolean executeExportOperation(ObfuscatorExportOperation op) { + // op.setCreateLeadupStructure( + // createDirectoryStructureButton.getSelection()); + op.setOverwriteFiles(overwriteExistingFilesCheckbox.getSelection()); + + try { + getContainer().run(true, true, op); + } catch (InterruptedException e) { + return false; + } catch (InvocationTargetException e) { + displayErrorDialog(e.getTargetException()); + return false; + } + + IStatus status = op.getStatus(); + if (!status.isOK()) { + ErrorDialog.openError(getContainer().getShell(), + ObfuscatorExportMessages + .getString("ObfuscatorTransfer.exportProblems"), //$NON-NLS-1$ + null, // no special message + status); + return false; + } + + return true; + } + + /** + * The Finish button was pressed. Try to do the required work now and answer + * a boolean indicating success. If false is returned then the wizard will + * not close. + * + * @return boolean + */ + public boolean finish() { + if (!ensureTargetIsValid(new File(getDestinationValue()))) + return false; + + List resourcesToExport = getWhiteCheckedResources(); + + // Save dirty editors if possible but do not stop if not all are saved + saveDirtyEditors(); + // about to invoke the operation so save our state + saveWidgetValues(); + + if (resourcesToExport.size() > 0) + return executeExportOperation(new ObfuscatorExportOperation(null, + resourcesToExport, getDestinationValue(), this)); + + MessageDialog.openInformation(getContainer().getShell(), + ObfuscatorExportMessages + .getString("ObfuscatorTransfer.information"), //$NON-NLS-1$ + ObfuscatorExportMessages.getString("FileExport.noneSelected")); //$NON-NLS-1$ + + return false; + } + + /** + * Answer the string to display in self as the destination type + * + * @return java.lang.String + */ + protected String getDestinationLabel() { + return ObfuscatorExportMessages.getString("FileExport.toDirectory"); //$NON-NLS-1$ + } + + /** + * Answer the contents of self's destination specification widget + * + * @return java.lang.String + */ + protected String getDestinationValue() { + return destinationNameField.getText().trim(); + } + + /** + * Set the current input focus to self's destination entry field + */ + protected void giveFocusToDestination() { + destinationNameField.setFocus(); + } + + /** + * Open an appropriate destination browser so that the user can specify a + * source to import from + */ + protected void handleDestinationBrowseButtonPressed() { + DirectoryDialog dialog = new DirectoryDialog(getContainer().getShell(), + SWT.SAVE); + dialog.setMessage(SELECT_DESTINATION_MESSAGE); + dialog.setText(SELECT_DESTINATION_TITLE); + dialog.setFilterPath(getDestinationValue()); + String selectedDirectoryName = dialog.open(); + + if (selectedDirectoryName != null) { + setErrorMessage(null); + setDestinationValue(selectedDirectoryName); + } + } + + /** + * Handle all events and enablements for widgets in this page + * + * @param e + * Event + */ + public void handleEvent(Event e) { + Widget source = e.widget; + + if (source == destinationBrowseButton) + handleDestinationBrowseButtonPressed(); + + updatePageCompletion(); + } + + /** + * Hook method for saving widget values for restoration by the next instance + * of this class. + */ + protected void internalSaveWidgetValues() { + // update directory names history + IDialogSettings settings = getDialogSettings(); + if (settings != null) { + String[] directoryNames = settings + .getArray(STORE_DESTINATION_NAMES_ID); + if (directoryNames == null) + directoryNames = new String[0]; + + directoryNames = addToHistory(directoryNames, getDestinationValue()); + settings.put(STORE_DESTINATION_NAMES_ID, directoryNames); + + // options + settings.put(STORE_OVERWRITE_EXISTING_FILES_ID, + overwriteExistingFilesCheckbox.getSelection()); + + // settings.put( + // STORE_CREATE_STRUCTURE_ID, + // createDirectoryStructureButton.getSelection()); + + } + } + + /** + * Hook method for restoring widget values to the values that they held last + * time this wizard was used to completion. + */ + protected void restoreWidgetValues() { + IDialogSettings settings = getDialogSettings(); + if (settings != null) { + String[] directoryNames = settings + .getArray(STORE_DESTINATION_NAMES_ID); + if (directoryNames == null) + return; // ie.- no settings stored + + // destination + setDestinationValue(directoryNames[0]); + for (int i = 0; i < directoryNames.length; i++) + addDestinationItem(directoryNames[i]); + + // options + overwriteExistingFilesCheckbox.setSelection(settings + .getBoolean(STORE_OVERWRITE_EXISTING_FILES_ID)); + + // boolean createDirectories = + // settings.getBoolean(STORE_CREATE_STRUCTURE_ID); + // createDirectoryStructureButton.setSelection(createDirectories); + // createSelectionOnlyButton.setSelection(!createDirectories); + } + } + + /** + * Set the contents of the receivers destination specification widget to the + * passed value + * + */ + protected void setDestinationValue(String value) { + destinationNameField.setText(value); + } + + /** + * Answer a boolean indicating whether the receivers destination + * specification widgets currently all contain valid values. + */ + protected boolean validateDestinationGroup() { + String destinationValue = getDestinationValue(); + if (destinationValue.length() == 0) { + setMessage(destinationEmptyMessage()); + return false; + } + + String conflictingContainer = getConflictingContainerNameFor(destinationValue); + if (conflictingContainer == null) + setErrorMessage(""); //$NON-NLS-1$ + else { + setErrorMessage(ObfuscatorExportMessages.format( + "FileExport.conflictingContainer", //$NON-NLS-1$ + new Object[] { conflictingContainer })); + giveFocusToDestination(); + return false; + } + + return true; + } + + /** + * Get the message used to denote an empty destination. + */ + protected String destinationEmptyMessage() { + return ObfuscatorExportMessages + .getString("FileExport.destinationEmpty"); //$NON-NLS-1$ + } + + /** + * Returns the name of a container with a location that encompasses + * targetDirectory. Returns null if there is no conflict. + * + * @param targetDirectory + * the path of the directory to check. + * @return the conflicting container name or null + */ + protected String getConflictingContainerNameFor(String targetDirectory) { + + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IPath testPath = new Path(targetDirectory); + + if (root.getLocation().isPrefixOf(testPath)) + return ObfuscatorExportMessages.getString("FileExport.rootName"); //$NON-NLS-1$ + + IProject[] projects = root.getProjects(); + + for (int i = 0; i < projects.length; i++) { + if (projects[i].getLocation().isPrefixOf(testPath)) + return projects[i].getName(); + } + + return null; + + } + +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java new file mode 100644 index 0000000..4eb14da --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java @@ -0,0 +1,6068 @@ +package net.sourceforge.phpeclipse.phpeditor; + +/********************************************************************** + Copyright (c) 2000, 2002 IBM Corp. and others. + All rights reserved. This program and the accompanying materials + are made available under the terms of the Common Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/cpl-v10.html + + Contributors: + IBM Corporation - Initial implementation + www.phpeclipse.de + **********************************************************************/ +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.text.BreakIterator; +import java.text.CharacterIterator; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.StringTokenizer; + +import net.sourceforge.phpdt.core.ICompilationUnit; +import net.sourceforge.phpdt.core.IImportContainer; +import net.sourceforge.phpdt.core.IImportDeclaration; +import net.sourceforge.phpdt.core.IJavaElement; +import net.sourceforge.phpdt.core.IJavaProject; +import net.sourceforge.phpdt.core.IMember; +import net.sourceforge.phpdt.core.ISourceRange; +import net.sourceforge.phpdt.core.ISourceReference; +import net.sourceforge.phpdt.core.JavaCore; +import net.sourceforge.phpdt.core.JavaModelException; +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.parser.Scanner; +import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError; +import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup; +import net.sourceforge.phpdt.internal.ui.actions.FoldingActionGroup; +import net.sourceforge.phpdt.internal.ui.actions.SelectionConverter; +import net.sourceforge.phpdt.internal.ui.text.CustomSourceInformationControl; +import net.sourceforge.phpdt.internal.ui.text.DocumentCharacterIterator; +import net.sourceforge.phpdt.internal.ui.text.HTMLTextPresenter; +import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions; +import net.sourceforge.phpdt.internal.ui.text.JavaWordFinder; +import net.sourceforge.phpdt.internal.ui.text.JavaWordIterator; +import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher; +import net.sourceforge.phpdt.internal.ui.text.PreferencesAdapter; +import net.sourceforge.phpdt.internal.ui.text.java.hover.JavaExpandHover; +import net.sourceforge.phpdt.internal.ui.viewsupport.ISelectionListenerWithAST; +import net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider; +import net.sourceforge.phpdt.internal.ui.viewsupport.SelectionListenerWithASTManager; +import net.sourceforge.phpdt.ui.IContextMenuConstants; +import net.sourceforge.phpdt.ui.JavaUI; +import net.sourceforge.phpdt.ui.PreferenceConstants; +import net.sourceforge.phpdt.ui.actions.GotoMatchingBracketAction; +import net.sourceforge.phpdt.ui.actions.OpenEditorActionGroup; +import net.sourceforge.phpdt.ui.text.JavaTextTools; +import net.sourceforge.phpdt.ui.text.PHPSourceViewerConfiguration; +import net.sourceforge.phpdt.ui.text.folding.IJavaFoldingStructureProvider; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; +import net.sourceforge.phpeclipse.ui.editor.BrowserUtil; +import net.sourceforge.phpeclipse.webbrowser.views.BrowserView; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Preferences; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.GroupMarker; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DefaultInformationControl; +import org.eclipse.jface.text.DocumentEvent; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentExtension4; +import org.eclipse.jface.text.IDocumentListener; +import org.eclipse.jface.text.IInformationControl; +import org.eclipse.jface.text.IInformationControlCreator; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ISelectionValidator; +import org.eclipse.jface.text.ISynchronizable; +import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.ITextInputListener; +import org.eclipse.jface.text.ITextPresentationListener; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerExtension2; +import org.eclipse.jface.text.ITextViewerExtension4; +import org.eclipse.jface.text.ITextViewerExtension5; +import org.eclipse.jface.text.ITypedRegion; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.text.TextUtilities; +import org.eclipse.jface.text.information.IInformationProvider; +import org.eclipse.jface.text.information.InformationPresenter; +import org.eclipse.jface.text.link.LinkedModeModel; +import org.eclipse.jface.text.reconciler.IReconciler; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.AnnotationRulerColumn; +import org.eclipse.jface.text.source.CompositeRuler; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.IAnnotationModelExtension; +import org.eclipse.jface.text.source.IOverviewRuler; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.ISourceViewerExtension2; +import org.eclipse.jface.text.source.IVerticalRuler; +import org.eclipse.jface.text.source.IVerticalRulerColumn; +import org.eclipse.jface.text.source.OverviewRuler; +import org.eclipse.jface.text.source.SourceViewerConfiguration; +import org.eclipse.jface.text.source.projection.ProjectionSupport; +import org.eclipse.jface.text.source.projection.ProjectionViewer; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.ListenerList; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.IPostSelectionProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.BidiSegmentEvent; +import org.eclipse.swt.custom.BidiSegmentListener; +import org.eclipse.swt.custom.ST; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPartService; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWindowListener; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.ActionContext; +import org.eclipse.ui.actions.ActionGroup; +import org.eclipse.ui.editors.text.DefaultEncodingSupport; +import org.eclipse.ui.editors.text.EditorsUI; +import org.eclipse.ui.editors.text.IEncodingSupport; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.part.IShowInSource; +import org.eclipse.ui.part.IShowInTargetList; +import org.eclipse.ui.part.ShowInContext; +import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor; +import org.eclipse.ui.texteditor.AnnotationPreference; +import org.eclipse.ui.texteditor.ChainedPreferenceStore; +import org.eclipse.ui.texteditor.IDocumentProvider; +import org.eclipse.ui.texteditor.IEditorStatusLine; +import org.eclipse.ui.texteditor.ITextEditorActionConstants; +import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; +import org.eclipse.ui.texteditor.IUpdate; +import org.eclipse.ui.texteditor.MarkerAnnotation; +import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; +import org.eclipse.ui.texteditor.TextEditorAction; +import org.eclipse.ui.texteditor.TextNavigationAction; +import org.eclipse.ui.texteditor.TextOperationAction; +import org.eclipse.ui.views.contentoutline.ContentOutline; +import org.eclipse.ui.views.contentoutline.IContentOutlinePage; +import org.eclipse.ui.views.tasklist.TaskList; + +/** + * PHP specific text editor. + */ +public abstract class PHPEditor extends AbstractDecoratedTextEditor implements + IViewPartInputProvider, IShowInTargetList, IShowInSource { + // extends StatusTextEditor implements IViewPartInputProvider { // extends + // TextEditor { + + /** + * Internal implementation class for a change listener. + * + * @since 3.0 + */ + protected abstract class AbstractSelectionChangedListener implements + ISelectionChangedListener { + + /** + * Installs this selection changed listener with the given selection + * provider. If the selection provider is a post selection provider, + * post selection changed events are the preferred choice, otherwise + * normal selection changed events are requested. + * + * @param selectionProvider + */ + public void install(ISelectionProvider selectionProvider) { + if (selectionProvider == null) + return; + + if (selectionProvider instanceof IPostSelectionProvider) { + IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider; + provider.addPostSelectionChangedListener(this); + } else { + selectionProvider.addSelectionChangedListener(this); + } + } + + /** + * Removes this selection changed listener from the given selection + * provider. + * + * @param selectionProvider + * the selection provider + */ + public void uninstall(ISelectionProvider selectionProvider) { + if (selectionProvider == null) + return; + + if (selectionProvider instanceof IPostSelectionProvider) { + IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider; + provider.removePostSelectionChangedListener(this); + } else { + selectionProvider.removeSelectionChangedListener(this); + } + } + } + + /** + * Updates the Java outline page selection and this editor's range + * indicator. + * + * @since 3.0 + */ + private class EditorSelectionChangedListener extends + AbstractSelectionChangedListener { + + /* + * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) + */ + public void selectionChanged(SelectionChangedEvent event) { + // XXX: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=56161 + PHPEditor.this.selectionChanged(); + } + } + + /** + * "Smart" runnable for updating the outline page's selection. + */ + // class OutlinePageSelectionUpdater implements Runnable { + // + // /** Has the runnable already been posted? */ + // private boolean fPosted = false; + // + // public OutlinePageSelectionUpdater() { + // } + // + // /* + // * @see Runnable#run() + // */ + // public void run() { + // synchronizeOutlinePageSelection(); + // fPosted = false; + // } + // + // /** + // * Posts this runnable into the event queue. + // */ + // public void post() { + // if (fPosted) + // return; + // + // Shell shell = getSite().getShell(); + // if (shell != null & !shell.isDisposed()) { + // fPosted = true; + // shell.getDisplay().asyncExec(this); + // } + // } + // }; + class SelectionChangedListener implements ISelectionChangedListener { + public void selectionChanged(SelectionChangedEvent event) { + doSelectionChanged(event); + } + }; + + /** + * Adapts an options {@link java.util.Map}to + * {@link org.eclipse.jface.preference.IPreferenceStore}. + *

+ * This preference store is read-only i.e. write access throws an + * {@link java.lang.UnsupportedOperationException}. + *

+ * + * @since 3.0 + */ + private static class OptionsAdapter implements IPreferenceStore { + + /** + * A property change event filter. + */ + public interface IPropertyChangeEventFilter { + + /** + * Should the given event be filtered? + * + * @param event + * The property change event. + * @return true iff the given event should be + * filtered. + */ + public boolean isFiltered(PropertyChangeEvent event); + + } + + /** + * Property change listener. Listens for events in the options Map and + * fires a {@link org.eclipse.jface.util.PropertyChangeEvent}on this + * adapter with arguments from the received event. + */ + private class PropertyChangeListener implements IPropertyChangeListener { + + /** + * {@inheritDoc} + */ + public void propertyChange(PropertyChangeEvent event) { + if (getFilter().isFiltered(event)) + return; + + if (event.getNewValue() == null) + fOptions.remove(event.getProperty()); + else + fOptions.put(event.getProperty(), event.getNewValue()); + + firePropertyChangeEvent(event.getProperty(), event + .getOldValue(), event.getNewValue()); + } + } + + /** Listeners on this adapter */ + private ListenerList fListeners = new ListenerList(); + + /** Listener on the adapted options Map */ + private IPropertyChangeListener fListener = new PropertyChangeListener(); + + /** Adapted options Map */ + private Map fOptions; + + /** Preference store through which events are received. */ + private IPreferenceStore fMockupPreferenceStore; + + /** Property event filter. */ + private IPropertyChangeEventFilter fFilter; + + /** + * Initialize with the given options. + * + * @param options + * The options to wrap + * @param mockupPreferenceStore + * the mock-up preference store + * @param filter + * the property change filter + */ + public OptionsAdapter(Map options, + IPreferenceStore mockupPreferenceStore, + IPropertyChangeEventFilter filter) { + fMockupPreferenceStore = mockupPreferenceStore; + fOptions = options; + setFilter(filter); + } + + /** + * {@inheritDoc} + */ + public void addPropertyChangeListener(IPropertyChangeListener listener) { + if (fListeners.size() == 0) + fMockupPreferenceStore.addPropertyChangeListener(fListener); + fListeners.add(listener); + } + + /** + * {@inheritDoc} + */ + public void removePropertyChangeListener( + IPropertyChangeListener listener) { + fListeners.remove(listener); + if (fListeners.size() == 0) + fMockupPreferenceStore.removePropertyChangeListener(fListener); + } + + /** + * {@inheritDoc} + */ + public boolean contains(String name) { + return fOptions.containsKey(name); + } + + /** + * {@inheritDoc} + */ + public void firePropertyChangeEvent(String name, Object oldValue, + Object newValue) { + PropertyChangeEvent event = new PropertyChangeEvent(this, name, + oldValue, newValue); + Object[] listeners = fListeners.getListeners(); + for (int i = 0; i < listeners.length; i++) + ((IPropertyChangeListener) listeners[i]).propertyChange(event); + } + + /** + * {@inheritDoc} + */ + public boolean getBoolean(String name) { + boolean value = BOOLEAN_DEFAULT_DEFAULT; + String s = (String) fOptions.get(name); + if (s != null) + value = s.equals(TRUE); + return value; + } + + /** + * {@inheritDoc} + */ + public boolean getDefaultBoolean(String name) { + return BOOLEAN_DEFAULT_DEFAULT; + } + + /** + * {@inheritDoc} + */ + public double getDefaultDouble(String name) { + return DOUBLE_DEFAULT_DEFAULT; + } + + /** + * {@inheritDoc} + */ + public float getDefaultFloat(String name) { + return FLOAT_DEFAULT_DEFAULT; + } + + /** + * {@inheritDoc} + */ + public int getDefaultInt(String name) { + return INT_DEFAULT_DEFAULT; + } + + /** + * {@inheritDoc} + */ + public long getDefaultLong(String name) { + return LONG_DEFAULT_DEFAULT; + } + + /** + * {@inheritDoc} + */ + public String getDefaultString(String name) { + return STRING_DEFAULT_DEFAULT; + } + + /** + * {@inheritDoc} + */ + public double getDouble(String name) { + double value = DOUBLE_DEFAULT_DEFAULT; + String s = (String) fOptions.get(name); + if (s != null) { + try { + value = new Double(s).doubleValue(); + } catch (NumberFormatException e) { + } + } + return value; + } + + /** + * {@inheritDoc} + */ + public float getFloat(String name) { + float value = FLOAT_DEFAULT_DEFAULT; + String s = (String) fOptions.get(name); + if (s != null) { + try { + value = new Float(s).floatValue(); + } catch (NumberFormatException e) { + } + } + return value; + } + + /** + * {@inheritDoc} + */ + public int getInt(String name) { + int value = INT_DEFAULT_DEFAULT; + String s = (String) fOptions.get(name); + if (s != null) { + try { + value = new Integer(s).intValue(); + } catch (NumberFormatException e) { + } + } + return value; + } + + /** + * {@inheritDoc} + */ + public long getLong(String name) { + long value = LONG_DEFAULT_DEFAULT; + String s = (String) fOptions.get(name); + if (s != null) { + try { + value = new Long(s).longValue(); + } catch (NumberFormatException e) { + } + } + return value; + } + + /** + * {@inheritDoc} + */ + public String getString(String name) { + String value = (String) fOptions.get(name); + if (value == null) + value = STRING_DEFAULT_DEFAULT; + return value; + } + + /** + * {@inheritDoc} + */ + public boolean isDefault(String name) { + return false; + } + + /** + * {@inheritDoc} + */ + public boolean needsSaving() { + return !fOptions.isEmpty(); + } + + /** + * {@inheritDoc} + */ + public void putValue(String name, String value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, double value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, float value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, int value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, long value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, String defaultObject) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, boolean value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setToDefault(String name) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, double value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, float value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, int value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, long value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, String value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, boolean value) { + throw new UnsupportedOperationException(); + } + + /** + * Returns the adapted options Map. + * + * @return Returns the adapted options Map. + */ + public Map getOptions() { + return fOptions; + } + + /** + * Returns the mock-up preference store, events are received through + * this preference store. + * + * @return Returns the mock-up preference store. + */ + public IPreferenceStore getMockupPreferenceStore() { + return fMockupPreferenceStore; + } + + /** + * Set the event filter to the given filter. + * + * @param filter + * The new filter. + */ + public void setFilter(IPropertyChangeEventFilter filter) { + fFilter = filter; + } + + /** + * Returns the event filter. + * + * @return The event filter. + */ + public IPropertyChangeEventFilter getFilter() { + return fFilter; + } + } + + /* + * Link mode. + */ + // class MouseClickListener implements KeyListener, MouseListener, + // MouseMoveListener, FocusListener, PaintListener, + // IPropertyChangeListener, IDocumentListener, ITextInputListener { + // + // /** The session is active. */ + // private boolean fActive; + // + // /** The currently active style range. */ + // private IRegion fActiveRegion; + // + // /** The currently active style range as position. */ + // private Position fRememberedPosition; + // + // /** The hand cursor. */ + // private Cursor fCursor; + // + // /** The link color. */ + // private Color fColor; + // + // /** The key modifier mask. */ + // private int fKeyModifierMask; + // + // public void deactivate() { + // deactivate(false); + // } + // + // public void deactivate(boolean redrawAll) { + // if (!fActive) + // return; + // + // repairRepresentation(redrawAll); + // fActive = false; + // } + // + // public void install() { + // + // ISourceViewer sourceViewer = getSourceViewer(); + // if (sourceViewer == null) + // return; + // + // StyledText text = sourceViewer.getTextWidget(); + // if (text == null || text.isDisposed()) + // return; + // + // updateColor(sourceViewer); + // + // sourceViewer.addTextInputListener(this); + // + // IDocument document = sourceViewer.getDocument(); + // if (document != null) + // document.addDocumentListener(this); + // + // text.addKeyListener(this); + // text.addMouseListener(this); + // text.addMouseMoveListener(this); + // text.addFocusListener(this); + // text.addPaintListener(this); + // + // updateKeyModifierMask(); + // + // IPreferenceStore preferenceStore = getPreferenceStore(); + // preferenceStore.addPropertyChangeListener(this); + // } + // + // private void updateKeyModifierMask() { + // String modifiers = + // getPreferenceStore().getString(BROWSER_LIKE_LINKS_KEY_MODIFIER); + // fKeyModifierMask = computeStateMask(modifiers); + // if (fKeyModifierMask == -1) { + // // Fallback to stored state mask + // fKeyModifierMask = + // getPreferenceStore().getInt(BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK); + // } + // ; + // } + // + // private int computeStateMask(String modifiers) { + // if (modifiers == null) + // return -1; + // + // if (modifiers.length() == 0) + // return SWT.NONE; + // + // int stateMask = 0; + // StringTokenizer modifierTokenizer = new StringTokenizer(modifiers, + // ",;.:+-* + // "); //$NON-NLS-1$ + // while (modifierTokenizer.hasMoreTokens()) { + // int modifier = + // EditorUtility.findLocalizedModifier(modifierTokenizer.nextToken()); + // if (modifier == 0 || (stateMask & modifier) == modifier) + // return -1; + // stateMask = stateMask | modifier; + // } + // return stateMask; + // } + // + // public void uninstall() { + // + // if (fColor != null) { + // fColor.dispose(); + // fColor = null; + // } + // + // if (fCursor != null) { + // fCursor.dispose(); + // fCursor = null; + // } + // + // ISourceViewer sourceViewer = getSourceViewer(); + // if (sourceViewer == null) + // return; + // + // sourceViewer.removeTextInputListener(this); + // + // IDocument document = sourceViewer.getDocument(); + // if (document != null) + // document.removeDocumentListener(this); + // + // IPreferenceStore preferenceStore = getPreferenceStore(); + // if (preferenceStore != null) + // preferenceStore.removePropertyChangeListener(this); + // + // StyledText text = sourceViewer.getTextWidget(); + // if (text == null || text.isDisposed()) + // return; + // + // text.removeKeyListener(this); + // text.removeMouseListener(this); + // text.removeMouseMoveListener(this); + // text.removeFocusListener(this); + // text.removePaintListener(this); + // } + // + // /* + // * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent) + // */ + // public void propertyChange(PropertyChangeEvent event) { + // if (event.getProperty().equals(PHPEditor.LINK_COLOR)) { + // ISourceViewer viewer = getSourceViewer(); + // if (viewer != null) + // updateColor(viewer); + // } else if (event.getProperty().equals(BROWSER_LIKE_LINKS_KEY_MODIFIER)) { + // updateKeyModifierMask(); + // } + // } + // + // private void updateColor(ISourceViewer viewer) { + // if (fColor != null) + // fColor.dispose(); + // + // StyledText text = viewer.getTextWidget(); + // if (text == null || text.isDisposed()) + // return; + // + // Display display = text.getDisplay(); + // fColor = createColor(getPreferenceStore(), PHPEditor.LINK_COLOR, + // display); + // } + // + // /** + // * Creates a color from the information stored in the given preference + // store. Returns null if there is no such + // * information available. + // */ + // private Color createColor(IPreferenceStore store, String key, Display + // display) { + // + // RGB rgb = null; + // + // if (store.contains(key)) { + // + // if (store.isDefault(key)) + // rgb = PreferenceConverter.getDefaultColor(store, key); + // else + // rgb = PreferenceConverter.getColor(store, key); + // + // if (rgb != null) + // return new Color(display, rgb); + // } + // + // return null; + // } + // + // private void repairRepresentation() { + // repairRepresentation(false); + // } + // + // private void repairRepresentation(boolean redrawAll) { + // + // if (fActiveRegion == null) + // return; + // + // ISourceViewer viewer = getSourceViewer(); + // if (viewer != null) { + // resetCursor(viewer); + // + // int offset = fActiveRegion.getOffset(); + // int length = fActiveRegion.getLength(); + // + // // remove style + // if (!redrawAll && viewer instanceof ITextViewerExtension2) + // ((ITextViewerExtension2) viewer).invalidateTextPresentation(offset, + // length); + // else + // viewer.invalidateTextPresentation(); + // + // // remove underline + // if (viewer instanceof ITextViewerExtension3) { + // ITextViewerExtension3 extension = (ITextViewerExtension3) viewer; + // offset = extension.modelOffset2WidgetOffset(offset); + // } else { + // offset -= viewer.getVisibleRegion().getOffset(); + // } + // + // StyledText text = viewer.getTextWidget(); + // try { + // text.redrawRange(offset, length, true); + // } catch (IllegalArgumentException x) { + // PHPeclipsePlugin.log(x); + // } + // } + // + // fActiveRegion = null; + // } + // + // // will eventually be replaced by a method provided by jdt.core + // private IRegion selectWord(IDocument document, int anchor) { + // + // try { + // int offset = anchor; + // char c; + // + // while (offset >= 0) { + // c = document.getChar(offset); + // if (!Scanner.isPHPIdentifierPart(c)) + // break; + // --offset; + // } + // + // int start = offset; + // + // offset = anchor; + // int length = document.getLength(); + // + // while (offset < length) { + // c = document.getChar(offset); + // if (!Scanner.isPHPIdentifierPart(c)) + // break; + // ++offset; + // } + // + // int end = offset; + // + // if (start == end) + // return new Region(start, 0); + // else + // return new Region(start + 1, end - start - 1); + // + // } catch (BadLocationException x) { + // return null; + // } + // } + // + // IRegion getCurrentTextRegion(ISourceViewer viewer) { + // + // int offset = getCurrentTextOffset(viewer); + // if (offset == -1) + // return null; + // + // return null; + // // IJavaElement input= SelectionConverter.getInput(PHPEditor.this); + // // if (input == null) + // // return null; + // // + // // try { + // // + // // IJavaElement[] elements= null; + // // synchronized (input) { + // // elements= ((ICodeAssist) input).codeSelect(offset, 0); + // // } + // // + // // if (elements == null || elements.length == 0) + // // return null; + // // + // // return selectWord(viewer.getDocument(), offset); + // // + // // } catch (JavaModelException e) { + // // return null; + // // } + // } + // + // private int getCurrentTextOffset(ISourceViewer viewer) { + // + // try { + // StyledText text = viewer.getTextWidget(); + // if (text == null || text.isDisposed()) + // return -1; + // + // Display display = text.getDisplay(); + // Point absolutePosition = display.getCursorLocation(); + // Point relativePosition = text.toControl(absolutePosition); + // + // int widgetOffset = text.getOffsetAtLocation(relativePosition); + // if (viewer instanceof ITextViewerExtension3) { + // ITextViewerExtension3 extension = (ITextViewerExtension3) viewer; + // return extension.widgetOffset2ModelOffset(widgetOffset); + // } else { + // return widgetOffset + viewer.getVisibleRegion().getOffset(); + // } + // + // } catch (IllegalArgumentException e) { + // return -1; + // } + // } + // + // private void highlightRegion(ISourceViewer viewer, IRegion region) { + // + // if (region.equals(fActiveRegion)) + // return; + // + // repairRepresentation(); + // + // StyledText text = viewer.getTextWidget(); + // if (text == null || text.isDisposed()) + // return; + // + // // highlight region + // int offset = 0; + // int length = 0; + // + // if (viewer instanceof ITextViewerExtension3) { + // ITextViewerExtension3 extension = (ITextViewerExtension3) viewer; + // IRegion widgetRange = extension.modelRange2WidgetRange(region); + // if (widgetRange == null) + // return; + // + // offset = widgetRange.getOffset(); + // length = widgetRange.getLength(); + // + // } else { + // offset = region.getOffset() - viewer.getVisibleRegion().getOffset(); + // length = region.getLength(); + // } + // + // StyleRange oldStyleRange = text.getStyleRangeAtOffset(offset); + // Color foregroundColor = fColor; + // Color backgroundColor = oldStyleRange == null ? text.getBackground() : + // oldStyleRange.background; + // StyleRange styleRange = new StyleRange(offset, length, foregroundColor, + // backgroundColor); + // text.setStyleRange(styleRange); + // + // // underline + // text.redrawRange(offset, length, true); + // + // fActiveRegion = region; + // } + // + // private void activateCursor(ISourceViewer viewer) { + // StyledText text = viewer.getTextWidget(); + // if (text == null || text.isDisposed()) + // return; + // Display display = text.getDisplay(); + // if (fCursor == null) + // fCursor = new Cursor(display, SWT.CURSOR_HAND); + // text.setCursor(fCursor); + // } + // + // private void resetCursor(ISourceViewer viewer) { + // StyledText text = viewer.getTextWidget(); + // if (text != null && !text.isDisposed()) + // text.setCursor(null); + // + // if (fCursor != null) { + // fCursor.dispose(); + // fCursor = null; + // } + // } + // + // /* + // * @see + // org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent) + // */ + // public void keyPressed(KeyEvent event) { + // + // if (fActive) { + // deactivate(); + // return; + // } + // + // if (event.keyCode != fKeyModifierMask) { + // deactivate(); + // return; + // } + // + // fActive = true; + // + // // removed for #25871 + // // + // // ISourceViewer viewer= getSourceViewer(); + // // if (viewer == null) + // // return; + // // + // // IRegion region= getCurrentTextRegion(viewer); + // // if (region == null) + // // return; + // // + // // highlightRegion(viewer, region); + // // activateCursor(viewer); + // } + // + // /* + // * @see + // org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent) + // */ + // public void keyReleased(KeyEvent event) { + // + // if (!fActive) + // return; + // + // deactivate(); + // } + // + // /* + // * @see + // org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) + // */ + // public void mouseDoubleClick(MouseEvent e) { + // } + // + // /* + // * @see + // org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) + // */ + // public void mouseDown(MouseEvent event) { + // + // if (!fActive) + // return; + // + // if (event.stateMask != fKeyModifierMask) { + // deactivate(); + // return; + // } + // + // if (event.button != 1) { + // deactivate(); + // return; + // } + // } + // + // /* + // * @see + // org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) + // */ + // public void mouseUp(MouseEvent e) { + // + // if (!fActive) + // return; + // + // if (e.button != 1) { + // deactivate(); + // return; + // } + // + // boolean wasActive = fCursor != null; + // + // deactivate(); + // + // if (wasActive) { + // IAction action = getAction("OpenEditor"); //$NON-NLS-1$ + // if (action != null) + // action.run(); + // } + // } + // + // /* + // * @see + // org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent) + // */ + // public void mouseMove(MouseEvent event) { + // + // if (event.widget instanceof Control && !((Control) + // event.widget).isFocusControl()) { + // deactivate(); + // return; + // } + // + // if (!fActive) { + // if (event.stateMask != fKeyModifierMask) + // return; + // // modifier was already pressed + // fActive = true; + // } + // + // ISourceViewer viewer = getSourceViewer(); + // if (viewer == null) { + // deactivate(); + // return; + // } + // + // StyledText text = viewer.getTextWidget(); + // if (text == null || text.isDisposed()) { + // deactivate(); + // return; + // } + // + // if ((event.stateMask & SWT.BUTTON1) != 0 && text.getSelectionCount() != + // 0) + // { + // deactivate(); + // return; + // } + // + // IRegion region = getCurrentTextRegion(viewer); + // if (region == null || region.getLength() == 0) { + // repairRepresentation(); + // return; + // } + // + // highlightRegion(viewer, region); + // activateCursor(viewer); + // } + // + // /* + // * @see + // org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent) + // */ + // public void focusGained(FocusEvent e) { + // } + // + // /* + // * @see + // org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent) + // */ + // public void focusLost(FocusEvent event) { + // deactivate(); + // } + // + // /* + // * @see + // org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent) + // */ + // public void documentAboutToBeChanged(DocumentEvent event) { + // if (fActive && fActiveRegion != null) { + // fRememberedPosition = new Position(fActiveRegion.getOffset(), + // fActiveRegion.getLength()); + // try { + // event.getDocument().addPosition(fRememberedPosition); + // } catch (BadLocationException x) { + // fRememberedPosition = null; + // } + // } + // } + // + // /* + // * @see + // org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent) + // */ + // public void documentChanged(DocumentEvent event) { + // if (fRememberedPosition != null && !fRememberedPosition.isDeleted()) { + // event.getDocument().removePosition(fRememberedPosition); + // fActiveRegion = new Region(fRememberedPosition.getOffset(), + // fRememberedPosition.getLength()); + // } + // fRememberedPosition = null; + // + // ISourceViewer viewer = getSourceViewer(); + // if (viewer != null) { + // StyledText widget = viewer.getTextWidget(); + // if (widget != null && !widget.isDisposed()) { + // widget.getDisplay().asyncExec(new Runnable() { + // public void run() { + // deactivate(); + // } + // }); + // } + // } + // } + // + // /* + // * @see + // org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, + // * org.eclipse.jface.text.IDocument) + // */ + // public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument + // newInput) { + // if (oldInput == null) + // return; + // deactivate(); + // oldInput.removeDocumentListener(this); + // } + // + // /* + // * @see + // org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, + // * org.eclipse.jface.text.IDocument) + // */ + // public void inputDocumentChanged(IDocument oldInput, IDocument newInput) + // { + // if (newInput == null) + // return; + // newInput.addDocumentListener(this); + // } + // + // /* + // * @see PaintListener#paintControl(PaintEvent) + // */ + // public void paintControl(PaintEvent event) { + // if (fActiveRegion == null) + // return; + // + // ISourceViewer viewer = getSourceViewer(); + // if (viewer == null) + // return; + // + // StyledText text = viewer.getTextWidget(); + // if (text == null || text.isDisposed()) + // return; + // + // int offset = 0; + // int length = 0; + // + // if (viewer instanceof ITextViewerExtension3) { + // + // ITextViewerExtension3 extension = (ITextViewerExtension3) viewer; + // IRegion widgetRange = extension.modelRange2WidgetRange(new Region(offset, + // length)); + // if (widgetRange == null) + // return; + // + // offset = widgetRange.getOffset(); + // length = widgetRange.getLength(); + // + // } else { + // + // IRegion region = viewer.getVisibleRegion(); + // if (!includes(region, fActiveRegion)) + // return; + // + // offset = fActiveRegion.getOffset() - region.getOffset(); + // length = fActiveRegion.getLength(); + // } + // + // // support for bidi + // Point minLocation = getMinimumLocation(text, offset, length); + // Point maxLocation = getMaximumLocation(text, offset, length); + // + // int x1 = minLocation.x; + // int x2 = minLocation.x + maxLocation.x - minLocation.x - 1; + // int y = minLocation.y + text.getLineHeight() - 1; + // + // GC gc = event.gc; + // if (fColor != null && !fColor.isDisposed()) + // gc.setForeground(fColor); + // gc.drawLine(x1, y, x2, y); + // } + // + // private boolean includes(IRegion region, IRegion position) { + // return position.getOffset() >= region.getOffset() + // && position.getOffset() + position.getLength() <= region.getOffset() + + // region.getLength(); + // } + // + // private Point getMinimumLocation(StyledText text, int offset, int length) + // { + // Point minLocation = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE); + // + // for (int i = 0; i <= length; i++) { + // Point location = text.getLocationAtOffset(offset + i); + // + // if (location.x < minLocation.x) + // minLocation.x = location.x; + // if (location.y < minLocation.y) + // minLocation.y = location.y; + // } + // + // return minLocation; + // } + // + // private Point getMaximumLocation(StyledText text, int offset, int length) + // { + // Point maxLocation = new Point(Integer.MIN_VALUE, Integer.MIN_VALUE); + // + // for (int i = 0; i <= length; i++) { + // Point location = text.getLocationAtOffset(offset + i); + // + // if (location.x > maxLocation.x) + // maxLocation.x = location.x; + // if (location.y > maxLocation.y) + // maxLocation.y = location.y; + // } + // + // return maxLocation; + // } + // }; + /* + * Link mode. + */ + class MouseClickListener implements KeyListener, MouseListener, + MouseMoveListener, FocusListener, PaintListener, + IPropertyChangeListener, IDocumentListener, ITextInputListener, + ITextPresentationListener { + + /** The session is active. */ + private boolean fActive; + + /** The currently active style range. */ + private IRegion fActiveRegion; + + /** The currently active style range as position. */ + private Position fRememberedPosition; + + /** The hand cursor. */ + private Cursor fCursor; + + /** The link color. */ + private Color fColor; + + /** The key modifier mask. */ + private int fKeyModifierMask; + + public void deactivate() { + deactivate(false); + } + + public void deactivate(boolean redrawAll) { + if (!fActive) + return; + + repairRepresentation(redrawAll); + fActive = false; + } + + public void install() { + ISourceViewer sourceViewer = getSourceViewer(); + if (sourceViewer == null) + return; + + StyledText text = sourceViewer.getTextWidget(); + if (text == null || text.isDisposed()) + return; + + updateColor(sourceViewer); + + sourceViewer.addTextInputListener(this); + + IDocument document = sourceViewer.getDocument(); + if (document != null) + document.addDocumentListener(this); + + text.addKeyListener(this); + text.addMouseListener(this); + text.addMouseMoveListener(this); + text.addFocusListener(this); + text.addPaintListener(this); + + ((ITextViewerExtension4) sourceViewer) + .addTextPresentationListener(this); + + updateKeyModifierMask(); + + IPreferenceStore preferenceStore = getPreferenceStore(); + preferenceStore.addPropertyChangeListener(this); + } + + private void updateKeyModifierMask() { + String modifiers = getPreferenceStore().getString( + BROWSER_LIKE_LINKS_KEY_MODIFIER); + fKeyModifierMask = computeStateMask(modifiers); + if (fKeyModifierMask == -1) { + // Fall back to stored state mask + fKeyModifierMask = getPreferenceStore().getInt( + BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK); + } + } + + private int computeStateMask(String modifiers) { + if (modifiers == null) + return -1; + + if (modifiers.length() == 0) + return SWT.NONE; + + int stateMask = 0; + StringTokenizer modifierTokenizer = new StringTokenizer(modifiers, + ",;.:+-* "); //$NON-NLS-1$ + while (modifierTokenizer.hasMoreTokens()) { + int modifier = EditorUtility + .findLocalizedModifier(modifierTokenizer.nextToken()); + if (modifier == 0 || (stateMask & modifier) == modifier) + return -1; + stateMask = stateMask | modifier; + } + return stateMask; + } + + public void uninstall() { + + if (fColor != null) { + fColor.dispose(); + fColor = null; + } + + if (fCursor != null) { + fCursor.dispose(); + fCursor = null; + } + + ISourceViewer sourceViewer = getSourceViewer(); + if (sourceViewer != null) + sourceViewer.removeTextInputListener(this); + + IDocumentProvider documentProvider = getDocumentProvider(); + if (documentProvider != null) { + IDocument document = documentProvider + .getDocument(getEditorInput()); + if (document != null) + document.removeDocumentListener(this); + } + + IPreferenceStore preferenceStore = getPreferenceStore(); + if (preferenceStore != null) + preferenceStore.removePropertyChangeListener(this); + + if (sourceViewer == null) + return; + + StyledText text = sourceViewer.getTextWidget(); + if (text == null || text.isDisposed()) + return; + + text.removeKeyListener(this); + text.removeMouseListener(this); + text.removeMouseMoveListener(this); + text.removeFocusListener(this); + text.removePaintListener(this); + + ((ITextViewerExtension4) sourceViewer) + .removeTextPresentationListener(this); + } + + /* + * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent) + */ + public void propertyChange(PropertyChangeEvent event) { + if (event.getProperty().equals(PHPEditor.LINK_COLOR)) { + ISourceViewer viewer = getSourceViewer(); + if (viewer != null) + updateColor(viewer); + } else if (event.getProperty().equals( + BROWSER_LIKE_LINKS_KEY_MODIFIER)) { + updateKeyModifierMask(); + } + } + + private void updateColor(ISourceViewer viewer) { + if (fColor != null) + fColor.dispose(); + + StyledText text = viewer.getTextWidget(); + if (text == null || text.isDisposed()) + return; + + Display display = text.getDisplay(); + fColor = createColor(getPreferenceStore(), PHPEditor.LINK_COLOR, + display); + } + + /** + * Creates a color from the information stored in the given preference + * store. + * + * @param store + * the preference store + * @param key + * the key + * @param display + * the display + * @return the color or null if there is no such + * information available + */ + private Color createColor(IPreferenceStore store, String key, + Display display) { + + RGB rgb = null; + + if (store.contains(key)) { + + if (store.isDefault(key)) + rgb = PreferenceConverter.getDefaultColor(store, key); + else + rgb = PreferenceConverter.getColor(store, key); + + if (rgb != null) + return new Color(display, rgb); + } + + return null; + } + + private void repairRepresentation() { + repairRepresentation(false); + } + + private void repairRepresentation(boolean redrawAll) { + + if (fActiveRegion == null) + return; + + int offset = fActiveRegion.getOffset(); + int length = fActiveRegion.getLength(); + fActiveRegion = null; + + ISourceViewer viewer = getSourceViewer(); + if (viewer != null) { + + resetCursor(viewer); + + // Invalidate ==> remove applied text presentation + if (!redrawAll && viewer instanceof ITextViewerExtension2) + ((ITextViewerExtension2) viewer) + .invalidateTextPresentation(offset, length); + else + viewer.invalidateTextPresentation(); + + // Remove underline + if (viewer instanceof ITextViewerExtension5) { + ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; + offset = extension.modelOffset2WidgetOffset(offset); + } else { + offset -= viewer.getVisibleRegion().getOffset(); + } + try { + StyledText text = viewer.getTextWidget(); + + text.redrawRange(offset, length, false); + } catch (IllegalArgumentException x) { + // JavaPlugin.log(x); + } + } + } + + // will eventually be replaced by a method provided by jdt.core + private IRegion selectWord(IDocument document, int anchor) { + + try { + int offset = anchor; + char c; + + while (offset >= 0) { + c = document.getChar(offset); + if (!Scanner.isPHPIdentifierPart(c) && c != '$') + break; + --offset; + } + + int start = offset; + + offset = anchor; + int length = document.getLength(); + + while (offset < length) { + c = document.getChar(offset); + if (!Scanner.isPHPIdentifierPart(c) && c != '$') + break; + ++offset; + } + + int end = offset; + + if (start == end) + return new Region(start, 0); + else + return new Region(start + 1, end - start - 1); + + } catch (BadLocationException x) { + return null; + } + } + + IRegion getCurrentTextRegion(ISourceViewer viewer) { + + int offset = getCurrentTextOffset(viewer); + if (offset == -1) + return null; + + IJavaElement input = SelectionConverter.getInput(PHPEditor.this); + if (input == null) + return null; + + // try { + + // IJavaElement[] elements= null; + // synchronized (input) { + // elements= ((ICodeAssist) input).codeSelect(offset, 0); + // } + // + // if (elements == null || elements.length == 0) + // return null; + + return selectWord(viewer.getDocument(), offset); + + // } catch (JavaModelException e) { + // return null; + // } + } + + private int getCurrentTextOffset(ISourceViewer viewer) { + + try { + StyledText text = viewer.getTextWidget(); + if (text == null || text.isDisposed()) + return -1; + + Display display = text.getDisplay(); + Point absolutePosition = display.getCursorLocation(); + Point relativePosition = text.toControl(absolutePosition); + + int widgetOffset = text.getOffsetAtLocation(relativePosition); + if (viewer instanceof ITextViewerExtension5) { + ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; + return extension.widgetOffset2ModelOffset(widgetOffset); + } else { + return widgetOffset + viewer.getVisibleRegion().getOffset(); + } + + } catch (IllegalArgumentException e) { + return -1; + } + } + + public void applyTextPresentation(TextPresentation textPresentation) { + if (fActiveRegion == null) + return; + IRegion region = textPresentation.getExtent(); + if (fActiveRegion.getOffset() + fActiveRegion.getLength() >= region + .getOffset() + && region.getOffset() + region.getLength() > fActiveRegion + .getOffset()) + textPresentation.mergeStyleRange(new StyleRange(fActiveRegion + .getOffset(), fActiveRegion.getLength(), fColor, null)); + } + + private void highlightRegion(ISourceViewer viewer, IRegion region) { + + if (region.equals(fActiveRegion)) + return; + + repairRepresentation(); + + StyledText text = viewer.getTextWidget(); + if (text == null || text.isDisposed()) + return; + + // Underline + int offset = 0; + int length = 0; + if (viewer instanceof ITextViewerExtension5) { + ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; + IRegion widgetRange = extension.modelRange2WidgetRange(region); + if (widgetRange == null) + return; + + offset = widgetRange.getOffset(); + length = widgetRange.getLength(); + + } else { + offset = region.getOffset() + - viewer.getVisibleRegion().getOffset(); + length = region.getLength(); + } + text.redrawRange(offset, length, false); + + // Invalidate region ==> apply text presentation + fActiveRegion = region; + if (viewer instanceof ITextViewerExtension2) + ((ITextViewerExtension2) viewer).invalidateTextPresentation( + region.getOffset(), region.getLength()); + else + viewer.invalidateTextPresentation(); + } + + private void activateCursor(ISourceViewer viewer) { + StyledText text = viewer.getTextWidget(); + if (text == null || text.isDisposed()) + return; + Display display = text.getDisplay(); + if (fCursor == null) + fCursor = new Cursor(display, SWT.CURSOR_HAND); + text.setCursor(fCursor); + } + + private void resetCursor(ISourceViewer viewer) { + StyledText text = viewer.getTextWidget(); + if (text != null && !text.isDisposed()) + text.setCursor(null); + + if (fCursor != null) { + fCursor.dispose(); + fCursor = null; + } + } + + /* + * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent) + */ + public void keyPressed(KeyEvent event) { + + if (fActive) { + deactivate(); + return; + } + + if (event.keyCode != fKeyModifierMask) { + deactivate(); + return; + } + + fActive = true; + + // removed for #25871 + // + // ISourceViewer viewer= getSourceViewer(); + // if (viewer == null) + // return; + // + // IRegion region= getCurrentTextRegion(viewer); + // if (region == null) + // return; + // + // highlightRegion(viewer, region); + // activateCursor(viewer); + } + + /* + * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent) + */ + public void keyReleased(KeyEvent event) { + + if (!fActive) + return; + + deactivate(); + } + + /* + * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) + */ + public void mouseDoubleClick(MouseEvent e) { + } + + /* + * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) + */ + public void mouseDown(MouseEvent event) { + + if (!fActive) + return; + + if (event.stateMask != fKeyModifierMask) { + deactivate(); + return; + } + + if (event.button != 1) { + deactivate(); + return; + } + } + + /* + * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) + */ + public void mouseUp(MouseEvent e) { + + if (!fActive) + return; + + if (e.button != 1) { + deactivate(); + return; + } + + boolean wasActive = fCursor != null; + + deactivate(); + + if (wasActive) { + IAction action = getAction("OpenEditor"); //$NON-NLS-1$ + if (action != null) + action.run(); + } + } + + /* + * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent) + */ + public void mouseMove(MouseEvent event) { + + if (event.widget instanceof Control + && !((Control) event.widget).isFocusControl()) { + deactivate(); + return; + } + + if (!fActive) { + if (event.stateMask != fKeyModifierMask) + return; + // modifier was already pressed + fActive = true; + } + + ISourceViewer viewer = getSourceViewer(); + if (viewer == null) { + deactivate(); + return; + } + + StyledText text = viewer.getTextWidget(); + if (text == null || text.isDisposed()) { + deactivate(); + return; + } + + if ((event.stateMask & SWT.BUTTON1) != 0 + && text.getSelectionCount() != 0) { + deactivate(); + return; + } + + IRegion region = getCurrentTextRegion(viewer); + if (region == null || region.getLength() == 0) { + repairRepresentation(); + return; + } + + highlightRegion(viewer, region); + activateCursor(viewer); + } + + /* + * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent) + */ + public void focusGained(FocusEvent e) { + } + + /* + * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent) + */ + public void focusLost(FocusEvent event) { + deactivate(); + } + + /* + * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent) + */ + public void documentAboutToBeChanged(DocumentEvent event) { + if (fActive && fActiveRegion != null) { + fRememberedPosition = new Position(fActiveRegion.getOffset(), + fActiveRegion.getLength()); + try { + event.getDocument().addPosition(fRememberedPosition); + } catch (BadLocationException x) { + fRememberedPosition = null; + } + } + } + + /* + * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent) + */ + public void documentChanged(DocumentEvent event) { + if (fRememberedPosition != null) { + if (!fRememberedPosition.isDeleted()) { + + event.getDocument().removePosition(fRememberedPosition); + fActiveRegion = new Region(fRememberedPosition.getOffset(), + fRememberedPosition.getLength()); + fRememberedPosition = null; + + ISourceViewer viewer = getSourceViewer(); + if (viewer != null) { + StyledText widget = viewer.getTextWidget(); + if (widget != null && !widget.isDisposed()) { + widget.getDisplay().asyncExec(new Runnable() { + public void run() { + deactivate(); + } + }); + } + } + + } else { + fActiveRegion = null; + fRememberedPosition = null; + deactivate(); + } + } + } + + /* + * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, + * org.eclipse.jface.text.IDocument) + */ + public void inputDocumentAboutToBeChanged(IDocument oldInput, + IDocument newInput) { + if (oldInput == null) + return; + deactivate(); + oldInput.removeDocumentListener(this); + } + + /* + * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, + * org.eclipse.jface.text.IDocument) + */ + public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { + if (newInput == null) + return; + newInput.addDocumentListener(this); + } + + /* + * @see PaintListener#paintControl(PaintEvent) + */ + public void paintControl(PaintEvent event) { + if (fActiveRegion == null) + return; + + ISourceViewer viewer = getSourceViewer(); + if (viewer == null) + return; + + StyledText text = viewer.getTextWidget(); + if (text == null || text.isDisposed()) + return; + + int offset = 0; + int length = 0; + + if (viewer instanceof ITextViewerExtension5) { + + ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; + IRegion widgetRange = extension + .modelRange2WidgetRange(fActiveRegion); + if (widgetRange == null) + return; + + offset = widgetRange.getOffset(); + length = widgetRange.getLength(); + + } else { + + IRegion region = viewer.getVisibleRegion(); + if (!includes(region, fActiveRegion)) + return; + + offset = fActiveRegion.getOffset() - region.getOffset(); + length = fActiveRegion.getLength(); + } + + // support for bidi + Point minLocation = getMinimumLocation(text, offset, length); + Point maxLocation = getMaximumLocation(text, offset, length); + + int x1 = minLocation.x; + int x2 = minLocation.x + maxLocation.x - minLocation.x - 1; + int y = minLocation.y + text.getLineHeight() - 1; + + GC gc = event.gc; + if (fColor != null && !fColor.isDisposed()) + gc.setForeground(fColor); + gc.drawLine(x1, y, x2, y); + } + + private boolean includes(IRegion region, IRegion position) { + return position.getOffset() >= region.getOffset() + && position.getOffset() + position.getLength() <= region + .getOffset() + + region.getLength(); + } + + private Point getMinimumLocation(StyledText text, int offset, int length) { + Point minLocation = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE); + + for (int i = 0; i <= length; i++) { + Point location = text.getLocationAtOffset(offset + i); + + if (location.x < minLocation.x) + minLocation.x = location.x; + if (location.y < minLocation.y) + minLocation.y = location.y; + } + + return minLocation; + } + + private Point getMaximumLocation(StyledText text, int offset, int length) { + Point maxLocation = new Point(Integer.MIN_VALUE, Integer.MIN_VALUE); + + for (int i = 0; i <= length; i++) { + Point location = text.getLocationAtOffset(offset + i); + + if (location.x > maxLocation.x) + maxLocation.x = location.x; + if (location.y > maxLocation.y) + maxLocation.y = location.y; + } + + return maxLocation; + } + } + + /** + * This action dispatches into two behaviours: If there is no current text + * hover, the javadoc is displayed using information presenter. If there is + * a current text hover, it is converted into a information presenter in + * order to make it sticky. + */ + class InformationDispatchAction extends TextEditorAction { + + /** The wrapped text operation action. */ + private final TextOperationAction fTextOperationAction; + + /** + * Creates a dispatch action. + */ + public InformationDispatchAction(ResourceBundle resourceBundle, + String prefix, final TextOperationAction textOperationAction) { + super(resourceBundle, prefix, PHPEditor.this); + if (textOperationAction == null) + throw new IllegalArgumentException(); + fTextOperationAction = textOperationAction; + } + + /* + * @see org.eclipse.jface.action.IAction#run() + */ + public void run() { + + ISourceViewer sourceViewer = getSourceViewer(); + if (sourceViewer == null) { + fTextOperationAction.run(); + return; + } + + if (!(sourceViewer instanceof ITextViewerExtension2)) { + fTextOperationAction.run(); + return; + } + + ITextViewerExtension2 textViewerExtension2 = (ITextViewerExtension2) sourceViewer; + + // does a text hover exist? + ITextHover textHover = textViewerExtension2.getCurrentTextHover(); + if (textHover == null) { + fTextOperationAction.run(); + return; + } + + Point hoverEventLocation = textViewerExtension2 + .getHoverEventLocation(); + int offset = computeOffsetAtLocation(sourceViewer, + hoverEventLocation.x, hoverEventLocation.y); + if (offset == -1) { + fTextOperationAction.run(); + return; + } + + try { + // get the text hover content + IDocument document = sourceViewer.getDocument(); + String contentType = document.getContentType(offset); + + final IRegion hoverRegion = textHover.getHoverRegion( + sourceViewer, offset); + if (hoverRegion == null) + return; + + final String hoverInfo = textHover.getHoverInfo(sourceViewer, + hoverRegion); + + // with information provider + IInformationProvider informationProvider = new IInformationProvider() { + /* + * @see org.eclipse.jface.text.information.IInformationProvider#getSubject(org.eclipse.jface.text.ITextViewer, + * int) + */ + public IRegion getSubject(ITextViewer textViewer, int offset) { + return hoverRegion; + } + + /* + * @see org.eclipse.jface.text.information.IInformationProvider#getInformation(org.eclipse.jface.text.ITextViewer, + * org.eclipse.jface.text.IRegion) + */ + public String getInformation(ITextViewer textViewer, + IRegion subject) { + return hoverInfo; + } + }; + + fInformationPresenter.setOffset(offset); + fInformationPresenter.setInformationProvider( + informationProvider, contentType); + fInformationPresenter.showInformation(); + + } catch (BadLocationException e) { + } + } + + // modified version from TextViewer + private int computeOffsetAtLocation(ITextViewer textViewer, int x, int y) { + + StyledText styledText = textViewer.getTextWidget(); + IDocument document = textViewer.getDocument(); + + if (document == null) + return -1; + + try { + int widgetLocation = styledText.getOffsetAtLocation(new Point( + x, y)); + if (textViewer instanceof ITextViewerExtension5) { + ITextViewerExtension5 extension = (ITextViewerExtension5) textViewer; + return extension.widgetOffset2ModelOffset(widgetLocation); + } else { + IRegion visibleRegion = textViewer.getVisibleRegion(); + return widgetLocation + visibleRegion.getOffset(); + } + } catch (IllegalArgumentException e) { + return -1; + } + + } + }; + + /** + * This action implements smart home. + * + * Instead of going to the start of a line it does the following: - if smart + * home/end is enabled and the caret is after the line's first + * non-whitespace then the caret is moved directly before it, taking JavaDoc + * and multi-line comments into account. - if the caret is before the line's + * first non-whitespace the caret is moved to the beginning of the line - if + * the caret is at the beginning of the line see first case. + * + * @since 3.0 + */ + protected class SmartLineStartAction extends LineStartAction { + + /** + * Creates a new smart line start action + * + * @param textWidget + * the styled text widget + * @param doSelect + * a boolean flag which tells if the text up to the beginning + * of the line should be selected + */ + public SmartLineStartAction(final StyledText textWidget, + final boolean doSelect) { + super(textWidget, doSelect); + } + + /* + * @see org.eclipse.ui.texteditor.AbstractTextEditor.LineStartAction#getLineStartPosition(java.lang.String, + * int, java.lang.String) + */ + protected int getLineStartPosition(final IDocument document, + final String line, final int length, final int offset) { + + String type = IDocument.DEFAULT_CONTENT_TYPE; + try { + type = TextUtilities.getContentType(document, + IPHPPartitions.PHP_PARTITIONING, offset, true); + } catch (BadLocationException exception) { + // Should not happen + } + + int index = super.getLineStartPosition(document, line, length, + offset); + if (type.equals(IPHPPartitions.PHP_PHPDOC_COMMENT) + || type.equals(IPHPPartitions.PHP_MULTILINE_COMMENT)) { + if (index < length - 1 && line.charAt(index) == '*' + && line.charAt(index + 1) != '/') { + do { + ++index; + } while (index < length + && Character.isWhitespace(line.charAt(index))); + } + } else { + if (index < length - 1 && line.charAt(index) == '/' + && line.charAt(index + 1) == '/') { + index++; + do { + ++index; + } while (index < length + && Character.isWhitespace(line.charAt(index))); + } + } + return index; + } + } + + /** + * Text navigation action to navigate to the next sub-word. + * + * @since 3.0 + */ + protected abstract class NextSubWordAction extends TextNavigationAction { + + protected JavaWordIterator fIterator = new JavaWordIterator(); + + /** + * Creates a new next sub-word action. + * + * @param code + * Action code for the default operation. Must be an action + * code from + * @see org.eclipse.swt.custom.ST. + */ + protected NextSubWordAction(int code) { + super(getSourceViewer().getTextWidget(), code); + } + + /* + * @see org.eclipse.jface.action.IAction#run() + */ + public void run() { + // Check whether we are in a java code partition and the preference + // is + // enabled + final IPreferenceStore store = getPreferenceStore(); + if (!store + .getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) { + super.run(); + return; + } + + final ISourceViewer viewer = getSourceViewer(); + final IDocument document = viewer.getDocument(); + fIterator + .setText((CharacterIterator) new DocumentCharacterIterator( + document)); + int position = widgetOffset2ModelOffset(viewer, viewer + .getTextWidget().getCaretOffset()); + if (position == -1) + return; + + int next = findNextPosition(position); + if (next != BreakIterator.DONE) { + setCaretPosition(next); + getTextWidget().showSelection(); + fireSelectionChanged(); + } + + } + + /** + * Finds the next position after the given position. + * + * @param position + * the current position + * @return the next position + */ + protected int findNextPosition(int position) { + ISourceViewer viewer = getSourceViewer(); + int widget = -1; + while (position != BreakIterator.DONE && widget == -1) { // TODO: + // optimize + position = fIterator.following(position); + if (position != BreakIterator.DONE) + widget = modelOffset2WidgetOffset(viewer, position); + } + return position; + } + + /** + * Sets the caret position to the sub-word boundary given with + * position. + * + * @param position + * Position where the action should move the caret + */ + protected abstract void setCaretPosition(int position); + } + + /** + * Text navigation action to navigate to the next sub-word. + * + * @since 3.0 + */ + protected class NavigateNextSubWordAction extends NextSubWordAction { + + /** + * Creates a new navigate next sub-word action. + */ + public NavigateNextSubWordAction() { + super(ST.WORD_NEXT); + } + + /* + * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int) + */ + protected void setCaretPosition(final int position) { + getTextWidget().setCaretOffset( + modelOffset2WidgetOffset(getSourceViewer(), position)); + } + } + + /** + * Text operation action to delete the next sub-word. + * + * @since 3.0 + */ + protected class DeleteNextSubWordAction extends NextSubWordAction implements + IUpdate { + + /** + * Creates a new delete next sub-word action. + */ + public DeleteNextSubWordAction() { + super(ST.DELETE_WORD_NEXT); + } + + /* + * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int) + */ + protected void setCaretPosition(final int position) { + if (!validateEditorInputState()) + return; + + final ISourceViewer viewer = getSourceViewer(); + final int caret = widgetOffset2ModelOffset(viewer, viewer + .getTextWidget().getCaretOffset()); + + try { + viewer.getDocument().replace(caret, position - caret, ""); //$NON-NLS-1$ + } catch (BadLocationException exception) { + // Should not happen + } + } + + /* + * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#findNextPosition(int) + */ + protected int findNextPosition(int position) { + return fIterator.following(position); + } + + /* + * @see org.eclipse.ui.texteditor.IUpdate#update() + */ + public void update() { + setEnabled(isEditorInputModifiable()); + } + } + + /** + * Text operation action to select the next sub-word. + * + * @since 3.0 + */ + protected class SelectNextSubWordAction extends NextSubWordAction { + + /** + * Creates a new select next sub-word action. + */ + public SelectNextSubWordAction() { + super(ST.SELECT_WORD_NEXT); + } + + /* + * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int) + */ + protected void setCaretPosition(final int position) { + final ISourceViewer viewer = getSourceViewer(); + + final StyledText text = viewer.getTextWidget(); + if (text != null && !text.isDisposed()) { + + final Point selection = text.getSelection(); + final int caret = text.getCaretOffset(); + final int offset = modelOffset2WidgetOffset(viewer, position); + + if (caret == selection.x) + text.setSelectionRange(selection.y, offset - selection.y); + else + text.setSelectionRange(selection.x, offset - selection.x); + } + } + } + + /** + * Text navigation action to navigate to the previous sub-word. + * + * @since 3.0 + */ + protected abstract class PreviousSubWordAction extends TextNavigationAction { + + protected JavaWordIterator fIterator = new JavaWordIterator(); + + /** + * Creates a new previous sub-word action. + * + * @param code + * Action code for the default operation. Must be an action + * code from + * @see org.eclipse.swt.custom.ST. + */ + protected PreviousSubWordAction(final int code) { + super(getSourceViewer().getTextWidget(), code); + } + + /* + * @see org.eclipse.jface.action.IAction#run() + */ + public void run() { + // Check whether we are in a java code partition and the preference + // is + // enabled + final IPreferenceStore store = getPreferenceStore(); + if (!store + .getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) { + super.run(); + return; + } + + final ISourceViewer viewer = getSourceViewer(); + final IDocument document = viewer.getDocument(); + fIterator + .setText((CharacterIterator) new DocumentCharacterIterator( + document)); + int position = widgetOffset2ModelOffset(viewer, viewer + .getTextWidget().getCaretOffset()); + if (position == -1) + return; + + int previous = findPreviousPosition(position); + if (previous != BreakIterator.DONE) { + setCaretPosition(previous); + getTextWidget().showSelection(); + fireSelectionChanged(); + } + + } + + /** + * Finds the previous position before the given position. + * + * @param position + * the current position + * @return the previous position + */ + protected int findPreviousPosition(int position) { + ISourceViewer viewer = getSourceViewer(); + int widget = -1; + while (position != BreakIterator.DONE && widget == -1) { // TODO: + // optimize + position = fIterator.preceding(position); + if (position != BreakIterator.DONE) + widget = modelOffset2WidgetOffset(viewer, position); + } + return position; + } + + /** + * Sets the caret position to the sub-word boundary given with + * position. + * + * @param position + * Position where the action should move the caret + */ + protected abstract void setCaretPosition(int position); + } + + /** + * Text navigation action to navigate to the previous sub-word. + * + * @since 3.0 + */ + protected class NavigatePreviousSubWordAction extends PreviousSubWordAction { + + /** + * Creates a new navigate previous sub-word action. + */ + public NavigatePreviousSubWordAction() { + super(ST.WORD_PREVIOUS); + } + + /* + * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int) + */ + protected void setCaretPosition(final int position) { + getTextWidget().setCaretOffset( + modelOffset2WidgetOffset(getSourceViewer(), position)); + } + } + + /** + * Text operation action to delete the previous sub-word. + * + * @since 3.0 + */ + protected class DeletePreviousSubWordAction extends PreviousSubWordAction + implements IUpdate { + + /** + * Creates a new delete previous sub-word action. + */ + public DeletePreviousSubWordAction() { + super(ST.DELETE_WORD_PREVIOUS); + } + + /* + * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int) + */ + protected void setCaretPosition(final int position) { + if (!validateEditorInputState()) + return; + + final ISourceViewer viewer = getSourceViewer(); + final int caret = widgetOffset2ModelOffset(viewer, viewer + .getTextWidget().getCaretOffset()); + + try { + viewer.getDocument().replace(position, caret - position, ""); //$NON-NLS-1$ + } catch (BadLocationException exception) { + // Should not happen + } + } + + /* + * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#findPreviousPosition(int) + */ + protected int findPreviousPosition(int position) { + return fIterator.preceding(position); + } + + /* + * @see org.eclipse.ui.texteditor.IUpdate#update() + */ + public void update() { + setEnabled(isEditorInputModifiable()); + } + } + + /** + * Text operation action to select the previous sub-word. + * + * @since 3.0 + */ + protected class SelectPreviousSubWordAction extends PreviousSubWordAction { + + /** + * Creates a new select previous sub-word action. + */ + public SelectPreviousSubWordAction() { + super(ST.SELECT_WORD_PREVIOUS); + } + + /* + * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int) + */ + protected void setCaretPosition(final int position) { + final ISourceViewer viewer = getSourceViewer(); + + final StyledText text = viewer.getTextWidget(); + if (text != null && !text.isDisposed()) { + + final Point selection = text.getSelection(); + final int caret = text.getCaretOffset(); + final int offset = modelOffset2WidgetOffset(viewer, position); + + if (caret == selection.x) + text.setSelectionRange(selection.y, offset - selection.y); + else + text.setSelectionRange(selection.x, offset - selection.x); + } + } + } + + // static protected class AnnotationAccess implements IAnnotationAccess { + // /* + // * @see + // org.eclipse.jface.text.source.IAnnotationAccess#getType(org.eclipse.jface.text.source.Annotation) + // */ + // public Object getType(Annotation annotation) { + // if (annotation instanceof IJavaAnnotation) { + // IJavaAnnotation javaAnnotation = (IJavaAnnotation) annotation; + // // if (javaAnnotation.isRelevant()) + // // return javaAnnotation.getAnnotationType(); + // } + // return null; + // } + // + // /* + // * @see + // org.eclipse.jface.text.source.IAnnotationAccess#isMultiLine(org.eclipse.jface.text.source.Annotation) + // */ + // public boolean isMultiLine(Annotation annotation) { + // return true; + // } + // + // /* + // * @see + // org.eclipse.jface.text.source.IAnnotationAccess#isTemporary(org.eclipse.jface.text.source.Annotation) + // */ + // public boolean isTemporary(Annotation annotation) { + // if (annotation instanceof IJavaAnnotation) { + // IJavaAnnotation javaAnnotation = (IJavaAnnotation) annotation; + // if (javaAnnotation.isRelevant()) + // return javaAnnotation.isTemporary(); + // } + // return false; + // } + // }; + + private class PropertyChangeListener implements + org.eclipse.core.runtime.Preferences.IPropertyChangeListener { + /* + * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent) + */ + public void propertyChange( + org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) { + handlePreferencePropertyChanged(event); + } + }; + + /** + * Finds and marks occurrence annotations. + * + * @since 3.0 + */ + class OccurrencesFinderJob extends Job { + + private IDocument fDocument; + + private ISelection fSelection; + + private ISelectionValidator fPostSelectionValidator; + + private boolean fCanceled = false; + + private IProgressMonitor fProgressMonitor; + + private Position[] fPositions; + + public OccurrencesFinderJob(IDocument document, Position[] positions, + ISelection selection) { + super(PHPEditorMessages.JavaEditor_markOccurrences_job_name); + fDocument = document; + fSelection = selection; + fPositions = positions; + + if (getSelectionProvider() instanceof ISelectionValidator) + fPostSelectionValidator = (ISelectionValidator) getSelectionProvider(); + } + + // cannot use cancel() because it is declared final + void doCancel() { + fCanceled = true; + cancel(); + } + + private boolean isCanceled() { + return fCanceled + || fProgressMonitor.isCanceled() + || fPostSelectionValidator != null + && !(fPostSelectionValidator.isValid(fSelection) || fForcedMarkOccurrencesSelection == fSelection) + || LinkedModeModel.hasInstalledModel(fDocument); + } + + /* + * @see Job#run(org.eclipse.core.runtime.IProgressMonitor) + */ + public IStatus run(IProgressMonitor progressMonitor) { + + fProgressMonitor = progressMonitor; + + if (isCanceled()) + return Status.CANCEL_STATUS; + + ITextViewer textViewer = getViewer(); + if (textViewer == null) + return Status.CANCEL_STATUS; + + IDocument document = textViewer.getDocument(); + if (document == null) + return Status.CANCEL_STATUS; + + IDocumentProvider documentProvider = getDocumentProvider(); + if (documentProvider == null) + return Status.CANCEL_STATUS; + + IAnnotationModel annotationModel = documentProvider + .getAnnotationModel(getEditorInput()); + if (annotationModel == null) + return Status.CANCEL_STATUS; + + // Add occurrence annotations + int length = fPositions.length; + Map annotationMap = new HashMap(length); + for (int i = 0; i < length; i++) { + + if (isCanceled()) + return Status.CANCEL_STATUS; + + String message; + Position position = fPositions[i]; + + // Create & add annotation + try { + message = document.get(position.offset, position.length); + } catch (BadLocationException ex) { + // Skip this match + continue; + } + annotationMap + .put( + new Annotation( + "net.sourceforge.phpdt.ui.occurrences", false, message), //$NON-NLS-1$ + position); + } + + if (isCanceled()) + return Status.CANCEL_STATUS; + + synchronized (getLockObject(annotationModel)) { + if (annotationModel instanceof IAnnotationModelExtension) { + ((IAnnotationModelExtension) annotationModel) + .replaceAnnotations(fOccurrenceAnnotations, + annotationMap); + } else { + removeOccurrenceAnnotations(); + Iterator iter = annotationMap.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry mapEntry = (Map.Entry) iter.next(); + annotationModel.addAnnotation((Annotation) mapEntry + .getKey(), (Position) mapEntry.getValue()); + } + } + fOccurrenceAnnotations = (Annotation[]) annotationMap.keySet() + .toArray(new Annotation[annotationMap.keySet().size()]); + } + + return Status.OK_STATUS; + } + } + + /** + * Cancels the occurrences finder job upon document changes. + * + * @since 3.0 + */ + class OccurrencesFinderJobCanceler implements IDocumentListener, + ITextInputListener { + + public void install() { + ISourceViewer sourceViewer = getSourceViewer(); + if (sourceViewer == null) + return; + + StyledText text = sourceViewer.getTextWidget(); + if (text == null || text.isDisposed()) + return; + + sourceViewer.addTextInputListener(this); + + IDocument document = sourceViewer.getDocument(); + if (document != null) + document.addDocumentListener(this); + } + + public void uninstall() { + ISourceViewer sourceViewer = getSourceViewer(); + if (sourceViewer != null) + sourceViewer.removeTextInputListener(this); + + IDocumentProvider documentProvider = getDocumentProvider(); + if (documentProvider != null) { + IDocument document = documentProvider + .getDocument(getEditorInput()); + if (document != null) + document.removeDocumentListener(this); + } + } + + /* + * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent) + */ + public void documentAboutToBeChanged(DocumentEvent event) { + if (fOccurrencesFinderJob != null) + fOccurrencesFinderJob.doCancel(); + } + + /* + * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent) + */ + public void documentChanged(DocumentEvent event) { + } + + /* + * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, + * org.eclipse.jface.text.IDocument) + */ + public void inputDocumentAboutToBeChanged(IDocument oldInput, + IDocument newInput) { + if (oldInput == null) + return; + + oldInput.removeDocumentListener(this); + } + + /* + * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, + * org.eclipse.jface.text.IDocument) + */ + public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { + if (newInput == null) + return; + newInput.addDocumentListener(this); + } + } + + /** + * Internal activation listener. + * + * @since 3.0 + */ + private class ActivationListener implements IWindowListener { + + /* + * @see org.eclipse.ui.IWindowListener#windowActivated(org.eclipse.ui.IWorkbenchWindow) + * @since 3.1 + */ + public void windowActivated(IWorkbenchWindow window) { + if (window == getEditorSite().getWorkbenchWindow() + && fMarkOccurrenceAnnotations && isActivePart()) { + fForcedMarkOccurrencesSelection = getSelectionProvider() + .getSelection(); + SelectionListenerWithASTManager + .getDefault() + .forceSelectionChange( + PHPEditor.this, + (ITextSelection) fForcedMarkOccurrencesSelection); + } + } + + /* + * @see org.eclipse.ui.IWindowListener#windowDeactivated(org.eclipse.ui.IWorkbenchWindow) + * @since 3.1 + */ + public void windowDeactivated(IWorkbenchWindow window) { + if (window == getEditorSite().getWorkbenchWindow() + && fMarkOccurrenceAnnotations && isActivePart()) + removeOccurrenceAnnotations(); + } + + /* + * @see org.eclipse.ui.IWindowListener#windowClosed(org.eclipse.ui.IWorkbenchWindow) + * @since 3.1 + */ + public void windowClosed(IWorkbenchWindow window) { + } + + /* + * @see org.eclipse.ui.IWindowListener#windowOpened(org.eclipse.ui.IWorkbenchWindow) + * @since 3.1 + */ + public void windowOpened(IWorkbenchWindow window) { + } + } + + /** + * Updates the selection in the editor's widget with the selection of the + * outline page. + */ + class OutlineSelectionChangedListener extends + AbstractSelectionChangedListener { + public void selectionChanged(SelectionChangedEvent event) { + doSelectionChanged(event); + } + } + + /** + * The internal shell activation listener for updating occurrences. + * + * @since 3.0 + */ + private ActivationListener fActivationListener = new ActivationListener(); + + private ISelectionListenerWithAST fPostSelectionListenerWithAST; + + private OccurrencesFinderJob fOccurrencesFinderJob; + + /** The occurrences finder job canceler */ + private OccurrencesFinderJobCanceler fOccurrencesFinderJobCanceler; + + /** + * Holds the current occurrence annotations. + * + * @since 3.0 + */ + private Annotation[] fOccurrenceAnnotations = null; + + /** + * Tells whether all occurrences of the element at the current caret + * location are automatically marked in this editor. + * + * @since 3.0 + */ + private boolean fMarkOccurrenceAnnotations; + + /** + * The selection used when forcing occurrence marking through code. + * + * @since 3.0 + */ + private ISelection fForcedMarkOccurrencesSelection; + + /** + * The document modification stamp at the time when the last occurrence + * marking took place. + * + * @since 3.1 + */ + private long fMarkOccurrenceModificationStamp = IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; + + /** + * The region of the word under the caret used to when computing the current + * occurrence markings. + * + * @since 3.1 + */ + private IRegion fMarkOccurrenceTargetRegion; + + /** + * Tells whether the occurrence annotations are sticky i.e. whether they + * stay even if there's no valid Java element at the current caret position. + * Only valid if {@link #fMarkOccurrenceAnnotations} is true. + * + * @since 3.0 + */ + private boolean fStickyOccurrenceAnnotations; + + /** Preference key for showing the line number ruler */ + // private final static String LINE_NUMBER_RULER = + // PreferenceConstants.EDITOR_LINE_NUMBER_RULER; + /** Preference key for the foreground color of the line numbers */ + // private final static String LINE_NUMBER_COLOR = + // PreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR; + /** Preference key for the link color */ + private final static String LINK_COLOR = PreferenceConstants.EDITOR_LINK_COLOR; + + /** Preference key for compiler task tags */ + private final static String COMPILER_TASK_TAGS = JavaCore.COMPILER_TASK_TAGS; + + // protected PHPActionGroup fActionGroups; + // /** The outline page */ + // private AbstractContentOutlinePage fOutlinePage; + /** The outline page */ + protected JavaOutlinePage fOutlinePage; + + /** Outliner context menu Id */ + protected String fOutlinerContextMenuId; + + /** + * Indicates whether this editor should react on outline page selection + * changes + */ + private int fIgnoreOutlinePageSelection; + + /** The outline page selection updater */ + // private OutlinePageSelectionUpdater fUpdater; + // protected PHPSyntaxParserThread fValidationThread = null; + // private IPreferenceStore fPHPPrefStore; + /** The selection changed listener */ + // protected ISelectionChangedListener fSelectionChangedListener = new + // SelectionChangedListener(); + /** + * The editor selection changed listener. + * + * @since 3.0 + */ + private EditorSelectionChangedListener fEditorSelectionChangedListener; + + /** The selection changed listener */ + protected AbstractSelectionChangedListener fOutlineSelectionChangedListener = new OutlineSelectionChangedListener(); + + /** The editor's bracket matcher */ + private PHPPairMatcher fBracketMatcher = new PHPPairMatcher(BRACKETS); + + /** The line number ruler column */ + // private LineNumberRulerColumn fLineNumberRulerColumn; + /** This editor's encoding support */ + private DefaultEncodingSupport fEncodingSupport; + + /** The mouse listener */ + private MouseClickListener fMouseListener; + + /** + * Indicates whether this editor is about to update any annotation views. + * + * @since 3.0 + */ + private boolean fIsUpdatingAnnotationViews = false; + + /** + * The marker that served as last target for a goto marker request. + * + * @since 3.0 + */ + private IMarker fLastMarkerTarget = null; + + protected CompositeActionGroup fActionGroups; + + protected CompositeActionGroup fContextMenuGroup; + + /** + * This editor's projection support + * + * @since 3.0 + */ + private ProjectionSupport fProjectionSupport; + + /** + * This editor's projection model updater + * + * @since 3.0 + */ + private IJavaFoldingStructureProvider fProjectionModelUpdater; + + /** + * The override and implements indicator manager for this editor. + * + * @since 3.0 + */ + // protected OverrideIndicatorManager fOverrideIndicatorManager; + /** + * The action group for folding. + * + * @since 3.0 + */ + private FoldingActionGroup fFoldingGroup; + + /** The information presenter. */ + private InformationPresenter fInformationPresenter; + + /** The annotation access */ + // protected IAnnotationAccess fAnnotationAccess = new AnnotationAccess(); + /** The overview ruler */ + protected OverviewRuler isOverviewRulerVisible; + + /** The source viewer decoration support */ + // protected SourceViewerDecorationSupport fSourceViewerDecorationSupport; + /** The overview ruler */ + // protected OverviewRuler fOverviewRuler; + /** The preference property change listener for java core. */ + private org.eclipse.core.runtime.Preferences.IPropertyChangeListener fPropertyChangeListener = new PropertyChangeListener(); + + /** + * Returns the most narrow java element including the given offset + * + * @param offset + * the offset inside of the requested element + */ + abstract protected IJavaElement getElementAt(int offset); + + /** + * Returns the java element of this editor's input corresponding to the + * given IJavaElement + */ + abstract protected IJavaElement getCorrespondingElement(IJavaElement element); + + /** + * Sets the input of the editor's outline page. + */ + abstract protected void setOutlinePageInput(JavaOutlinePage page, + IEditorInput input); + + /** + * Default constructor. + */ + public PHPEditor() { + super(); + } + + /* + * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#initializeKeyBindingScopes() + */ + protected void initializeKeyBindingScopes() { + setKeyBindingScopes(new String[] { "net.sourceforge.phpdt.ui.phpEditorScope" }); //$NON-NLS-1$ + } + + /* + * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#initializeEditor() + */ + protected void initializeEditor() { + // jsurfer old code + // JavaTextTools textTools = + // PHPeclipsePlugin.getDefault().getJavaTextTools(); + // setSourceViewerConfiguration(new + // PHPSourceViewerConfiguration(textTools, + // this, IPHPPartitions.PHP_PARTITIONING)); //, + // IJavaPartitions.JAVA_PARTITIONING)); + IPreferenceStore store = createCombinedPreferenceStore(null); + setPreferenceStore(store); + JavaTextTools textTools = PHPeclipsePlugin.getDefault() + .getJavaTextTools(); + setSourceViewerConfiguration(new PHPSourceViewerConfiguration(textTools + .getColorManager(), store, this, + IPHPPartitions.PHP_PARTITIONING)); + + // TODO changed in 3.x ? + // setRangeIndicator(new DefaultRangeIndicator()); + // if + // (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE)) + // fUpdater = new OutlinePageSelectionUpdater(); + // jsurfer end + + // IPreferenceStore store= createCombinedPreferenceStore(null); + // setPreferenceStore(store); + // JavaTextTools textTools= + // PHPeclipsePlugin.getDefault().getJavaTextTools(); + // setSourceViewerConfiguration(new + // JavaSourceViewerConfiguration(textTools.getColorManager(), store, + // this, IJavaPartitions.JAVA_PARTITIONING)); + fMarkOccurrenceAnnotations = store + .getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES); + fStickyOccurrenceAnnotations = store + .getBoolean(PreferenceConstants.EDITOR_STICKY_OCCURRENCES); + // fMarkTypeOccurrences= + // store.getBoolean(PreferenceConstants.EDITOR_MARK_TYPE_OCCURRENCES); + // fMarkMethodOccurrences= + // store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_OCCURRENCES); + // fMarkConstantOccurrences= + // store.getBoolean(PreferenceConstants.EDITOR_MARK_CONSTANT_OCCURRENCES); + // fMarkFieldOccurrences= + // store.getBoolean(PreferenceConstants.EDITOR_MARK_FIELD_OCCURRENCES); + // fMarkLocalVariableypeOccurrences= + // store.getBoolean(PreferenceConstants.EDITOR_MARK_LOCAL_VARIABLE_OCCURRENCES); + // fMarkExceptions= + // store.getBoolean(PreferenceConstants.EDITOR_MARK_EXCEPTION_OCCURRENCES); + // fMarkImplementors= + // store.getBoolean(PreferenceConstants.EDITOR_MARK_IMPLEMENTORS); + // fMarkMethodExitPoints= + // store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_EXIT_POINTS); + + } + + /* + * @see org.eclipse.ui.texteditor.AbstractTextEditor#updatePropertyDependentActions() + */ + protected void updatePropertyDependentActions() { + super.updatePropertyDependentActions(); + if (fEncodingSupport != null) + fEncodingSupport.reset(); + } + + /* + * Update the hovering behavior depending on the preferences. + */ + private void updateHoverBehavior() { + SourceViewerConfiguration configuration = getSourceViewerConfiguration(); + String[] types = configuration + .getConfiguredContentTypes(getSourceViewer()); + + for (int i = 0; i < types.length; i++) { + + String t = types[i]; + + int[] stateMasks = configuration.getConfiguredTextHoverStateMasks( + getSourceViewer(), t); + + ISourceViewer sourceViewer = getSourceViewer(); + if (sourceViewer instanceof ITextViewerExtension2) { + if (stateMasks != null) { + for (int j = 0; j < stateMasks.length; j++) { + int stateMask = stateMasks[j]; + ITextHover textHover = configuration.getTextHover( + sourceViewer, t, stateMask); + ((ITextViewerExtension2) sourceViewer).setTextHover( + textHover, t, stateMask); + } + } else { + ITextHover textHover = configuration.getTextHover( + sourceViewer, t); + ((ITextViewerExtension2) sourceViewer).setTextHover( + textHover, t, + ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK); + } + } else + sourceViewer.setTextHover(configuration.getTextHover( + sourceViewer, t), t); + } + } + + public void updatedTitleImage(Image image) { + setTitleImage(image); + } + + /* + * @see net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput() + */ + public Object getViewPartInput() { + return getEditorInput().getAdapter(IResource.class); + } + + /* + * @see org.eclipse.ui.texteditor.AbstractTextEditor#doSetSelection(ISelection) + */ + protected void doSetSelection(ISelection selection) { + super.doSetSelection(selection); + synchronizeOutlinePageSelection(); + } + + boolean isFoldingEnabled() { + return PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean( + PreferenceConstants.EDITOR_FOLDING_ENABLED); + } + + /* + * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt. + * widgets.Composite) + */ + public void createPartControl(Composite parent) { + super.createPartControl(parent); + + // fSourceViewerDecorationSupport.install(getPreferenceStore()); + + ProjectionViewer projectionViewer = (ProjectionViewer) getSourceViewer(); + + fProjectionSupport = new ProjectionSupport(projectionViewer, + getAnnotationAccess(), getSharedColors()); + fProjectionSupport + .addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.error"); //$NON-NLS-1$ + fProjectionSupport + .addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.warning"); //$NON-NLS-1$ + fProjectionSupport + .setHoverControlCreator(new IInformationControlCreator() { + public IInformationControl createInformationControl( + Shell shell) { + return new CustomSourceInformationControl(shell, + IDocument.DEFAULT_CONTENT_TYPE); + } + }); + fProjectionSupport.install(); + + fProjectionModelUpdater = PHPeclipsePlugin.getDefault() + .getFoldingStructureProviderRegistry() + .getCurrentFoldingProvider(); + if (fProjectionModelUpdater != null) + fProjectionModelUpdater.install(this, projectionViewer); + + if (isFoldingEnabled()) + projectionViewer.doOperation(ProjectionViewer.TOGGLE); + Preferences preferences = PHPeclipsePlugin.getDefault() + .getPluginPreferences(); + preferences.addPropertyChangeListener(fPropertyChangeListener); + + IInformationControlCreator informationControlCreator = new IInformationControlCreator() { + public IInformationControl createInformationControl(Shell parent) { + boolean cutDown = false; + int style = cutDown ? SWT.NONE : (SWT.V_SCROLL | SWT.H_SCROLL); + return new DefaultInformationControl(parent, SWT.RESIZE, style, + new HTMLTextPresenter(cutDown)); + } + }; + + fInformationPresenter = new InformationPresenter( + informationControlCreator); + fInformationPresenter.setSizeConstraints(60, 10, true, true); + fInformationPresenter.install(getSourceViewer()); + + fEditorSelectionChangedListener = new EditorSelectionChangedListener(); + fEditorSelectionChangedListener.install(getSelectionProvider()); + + if (isBrowserLikeLinks()) + enableBrowserLikeLinks(); + + if (PreferenceConstants.getPreferenceStore().getBoolean( + PreferenceConstants.EDITOR_DISABLE_OVERWRITE_MODE)) + enableOverwriteMode(false); + + if (fMarkOccurrenceAnnotations) + installOccurrencesFinder(); + + PlatformUI.getWorkbench().addWindowListener(fActivationListener); + + setWordWrap(); + } + + private void setWordWrap() { + if (getSourceViewer() != null) { + getSourceViewer().getTextWidget().setWordWrap( + PHPeclipsePlugin.getDefault().getPreferenceStore() + .getBoolean(PreferenceConstants.EDITOR_WRAP_WORDS)); + } + } + + protected void configureSourceViewerDecorationSupport( + SourceViewerDecorationSupport support) { + + support.setCharacterPairMatcher(fBracketMatcher); + support.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, + MATCHING_BRACKETS_COLOR); + + super.configureSourceViewerDecorationSupport(support); + } + + /* + * @see org.eclipse.ui.texteditor.AbstractTextEditor#gotoMarker(org.eclipse.core.resources.IMarker) + */ + public void gotoMarker(IMarker marker) { + fLastMarkerTarget = marker; + if (!fIsUpdatingAnnotationViews) { + super.gotoMarker(marker); + } + } + + /** + * Jumps to the next enabled annotation according to the given direction. An + * annotation type is enabled if it is configured to be in the Next/Previous + * tool bar drop down menu and if it is checked. + * + * @param forward + * true if search direction is forward, + * false if backward + */ + public Annotation gotoAnnotation(boolean forward) { + ITextSelection selection = (ITextSelection) getSelectionProvider() + .getSelection(); + Position position = new Position(0, 0); + Annotation annotation = null; + if (false /* delayed - see bug 18316 */) { + annotation = getNextAnnotation(selection.getOffset(), selection + .getLength(), forward, position); + selectAndReveal(position.getOffset(), position.getLength()); + } else /* no delay - see bug 18316 */{ + annotation = getNextAnnotation(selection.getOffset(), selection + .getLength(), forward, position); + setStatusLineErrorMessage(null); + setStatusLineMessage(null); + if (annotation != null) { + updateAnnotationViews(annotation); + selectAndReveal(position.getOffset(), position.getLength()); + setStatusLineMessage(annotation.getText()); + } + } + return annotation; + } + + /** + * Returns the lock object for the given annotation model. + * + * @param annotationModel + * the annotation model + * @return the annotation model's lock object + * @since 3.0 + */ + private Object getLockObject(IAnnotationModel annotationModel) { + if (annotationModel instanceof ISynchronizable) + return ((ISynchronizable) annotationModel).getLockObject(); + else + return annotationModel; + } + + /** + * Updates the annotation views that show the given annotation. + * + * @param annotation + * the annotation + */ + private void updateAnnotationViews(Annotation annotation) { + IMarker marker = null; + if (annotation instanceof MarkerAnnotation) + marker = ((MarkerAnnotation) annotation).getMarker(); + else if (annotation instanceof IJavaAnnotation) { + Iterator e = ((IJavaAnnotation) annotation).getOverlaidIterator(); + if (e != null) { + while (e.hasNext()) { + Object o = e.next(); + if (o instanceof MarkerAnnotation) { + marker = ((MarkerAnnotation) o).getMarker(); + break; + } + } + } + } + + if (marker != null && !marker.equals(fLastMarkerTarget)) { + try { + boolean isProblem = marker.isSubtypeOf(IMarker.PROBLEM); + IWorkbenchPage page = getSite().getPage(); + IViewPart view = page + .findView(isProblem ? IPageLayout.ID_PROBLEM_VIEW + : IPageLayout.ID_TASK_LIST); //$NON-NLS-1$ //$NON-NLS-2$ + if (view != null) { + Method method = view + .getClass() + .getMethod( + "setSelection", new Class[] { IStructuredSelection.class, boolean.class }); //$NON-NLS-1$ + method.invoke(view, new Object[] { + new StructuredSelection(marker), Boolean.TRUE }); + } + } catch (CoreException x) { + } catch (NoSuchMethodException x) { + } catch (IllegalAccessException x) { + } catch (InvocationTargetException x) { + } + // ignore exceptions, don't update any of the lists, just set status + // line + } + } + + /** + * Returns this document's complete text. + * + * @return the document's complete text + */ + public String get() { + IDocument doc = this.getDocumentProvider().getDocument( + this.getEditorInput()); + return doc.get(); + } + + /** + * Sets the outliner's context menu ID. + */ + protected void setOutlinerContextMenuId(String menuId) { + fOutlinerContextMenuId = menuId; + } + + /** + * Returns the standard action group of this editor. + */ + protected ActionGroup getActionGroup() { + return fActionGroups; + } + + // public JavaOutlinePage getfOutlinePage() { + // return fOutlinePage; + // } + + /** + * The PHPEditor implementation of this + * AbstractTextEditor method extend the actions to add those + * specific to the receiver + */ + protected void createActions() { + super.createActions(); + + ActionGroup oeg, ovg, jsg, sg; + fActionGroups = new CompositeActionGroup( + new ActionGroup[] { oeg = new OpenEditorActionGroup(this), + // sg= new ShowActionGroup(this), + // ovg= new OpenViewActionGroup(this), + // jsg= new JavaSearchActionGroup(this) + }); + fContextMenuGroup = new CompositeActionGroup(new ActionGroup[] { oeg }); + // , ovg, sg, jsg}); + + fFoldingGroup = new FoldingActionGroup(this, getViewer()); + + // ResourceAction resAction = new + // TextOperationAction(PHPEditorMessages.getResourceBundle(), + // "ShowJavaDoc.", this, ISourceViewer.INFORMATION, true); //$NON-NLS-1$ + // resAction = new + // InformationDispatchAction(PHPEditorMessages.getResourceBundle(), + // "ShowJavaDoc.", (TextOperationAction) resAction); //$NON-NLS-1$ + // resAction.setActionDefinitionId(net.sourceforge.phpdt.ui.actions.PHPEditorActionDefinitionIds.SHOW_JAVADOC); + // setAction("ShowJavaDoc", resAction); //$NON-NLS-1$ + + // WorkbenchHelp.setHelp(resAction, + // IJavaHelpContextIds.SHOW_JAVADOC_ACTION); + + Action action = new GotoMatchingBracketAction(this); + action + .setActionDefinitionId(PHPEditorActionDefinitionIds.GOTO_MATCHING_BRACKET); + setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action); + + // action= new + // TextOperationAction(PHPEditorMessages.getResourceBundle(),"ShowOutline.", + // this, JavaSourceViewer.SHOW_OUTLINE, true); //$NON-NLS-1$ + // action.setActionDefinitionId(PHPEditorActionDefinitionIds.SHOW_OUTLINE); + // setAction(PHPEditorActionDefinitionIds.SHOW_OUTLINE, action); + // // WorkbenchHelp.setHelp(action, + // IJavaHelpContextIds.SHOW_OUTLINE_ACTION); + // + // action= new + // TextOperationAction(PHPEditorMessages.getResourceBundle(),"OpenStructure.", + // this, JavaSourceViewer.OPEN_STRUCTURE, true); //$NON-NLS-1$ + // action.setActionDefinitionId(PHPEditorActionDefinitionIds.SHOW_OUTLINE.OPEN_STRUCTURE); + // setAction(PHPEditorActionDefinitionIds.SHOW_OUTLINE.OPEN_STRUCTURE, + // action); + // // WorkbenchHelp.setHelp(action, + // IJavaHelpContextIds.OPEN_STRUCTURE_ACTION); + // + // action= new + // TextOperationAction(PHPEditorMessages.getResourceBundle(),"OpenHierarchy.", + // this, JavaSourceViewer.SHOW_HIERARCHY, true); //$NON-NLS-1$ + // action.setActionDefinitionId(PHPEditorActionDefinitionIds.SHOW_OUTLINE.OPEN_HIERARCHY); + // setAction(PHPEditorActionDefinitionIds.SHOW_OUTLINE.OPEN_HIERARCHY, + // action); + // // WorkbenchHelp.setHelp(action, + // IJavaHelpContextIds.OPEN_HIERARCHY_ACTION); + + fEncodingSupport = new DefaultEncodingSupport(); + fEncodingSupport.initialize(this); + + // fSelectionHistory= new SelectionHistory(this); + // + // action= new StructureSelectEnclosingAction(this, fSelectionHistory); + // action.setActionDefinitionId(PHPEditorActionDefinitionIds.SELECT_ENCLOSING); + // setAction(StructureSelectionAction.ENCLOSING, action); + // + // action= new StructureSelectNextAction(this, fSelectionHistory); + // action.setActionDefinitionId(PHPEditorActionDefinitionIds.SELECT_NEXT); + // setAction(StructureSelectionAction.NEXT, action); + // + // action= new StructureSelectPreviousAction(this, fSelectionHistory); + // action.setActionDefinitionId(PHPEditorActionDefinitionIds.SELECT_PREVIOUS); + // setAction(StructureSelectionAction.PREVIOUS, action); + // + // StructureSelectHistoryAction historyAction= new + // StructureSelectHistoryAction(this, fSelectionHistory); + // historyAction.setActionDefinitionId(PHPEditorActionDefinitionIds.SELECT_LAST); + // setAction(StructureSelectionAction.HISTORY, historyAction); + // fSelectionHistory.setHistoryAction(historyAction); + // + // action= GoToNextPreviousMemberAction.newGoToNextMemberAction(this); + // action.setActionDefinitionId(PHPEditorActionDefinitionIds.GOTO_NEXT_MEMBER); + // setAction(GoToNextPreviousMemberAction.NEXT_MEMBER, action); + // + // action= + // GoToNextPreviousMemberAction.newGoToPreviousMemberAction(this); + // action.setActionDefinitionId(PHPEditorActionDefinitionIds.GOTO_PREVIOUS_MEMBER); + // setAction(GoToNextPreviousMemberAction.PREVIOUS_MEMBER, action); + // + // action= new QuickFormatAction(); + // action.setActionDefinitionId(PHPEditorActionDefinitionIds.QUICK_FORMAT); + // setAction(IJavaEditorActionDefinitionIds.QUICK_FORMAT, action); + // + // action= new RemoveOccurrenceAnnotations(this); + // action.setActionDefinitionId(PHPEditorActionDefinitionIds.REMOVE_OCCURRENCE_ANNOTATIONS); + // setAction("RemoveOccurrenceAnnotations", action); //$NON-NLS-1$ + + // add annotation actions + action = new JavaSelectMarkerRulerAction2(PHPEditorMessages + .getResourceBundle(), "Editor.RulerAnnotationSelection.", this); //$NON-NLS-1$ + setAction("AnnotationAction", action); //$NON-NLS-1$ + } + + private void internalDoSetInput(IEditorInput input) throws CoreException { + super.doSetInput(input); + + if (getSourceViewer() instanceof JavaSourceViewer) { + JavaSourceViewer viewer = (JavaSourceViewer) getSourceViewer(); + if (viewer.getReconciler() == null) { + IReconciler reconciler = getSourceViewerConfiguration() + .getReconciler(viewer); + if (reconciler != null) { + reconciler.install(viewer); + viewer.setReconciler(reconciler); + } + } + } + + if (fEncodingSupport != null) + fEncodingSupport.reset(); + + setOutlinePageInput(fOutlinePage, input); + + if (fProjectionModelUpdater != null) + fProjectionModelUpdater.initialize(); + + // if (isShowingOverrideIndicators()) + // installOverrideIndicator(false); + } + + /* + * @see org.eclipse.ui.texteditor.AbstractTextEditor#setPreferenceStore(org.eclipse.jface.preference.IPreferenceStore) + * @since 3.0 + */ + protected void setPreferenceStore(IPreferenceStore store) { + super.setPreferenceStore(store); + if (getSourceViewerConfiguration() instanceof PHPSourceViewerConfiguration) { + JavaTextTools textTools = PHPeclipsePlugin.getDefault() + .getJavaTextTools(); + setSourceViewerConfiguration(new PHPSourceViewerConfiguration( + textTools.getColorManager(), store, this, + IPHPPartitions.PHP_PARTITIONING)); + } + if (getSourceViewer() instanceof JavaSourceViewer) + ((JavaSourceViewer) getSourceViewer()).setPreferenceStore(store); + } + + /** + * The PHPEditor implementation of this + * AbstractTextEditor method performs any extra disposal + * actions required by the php editor. + */ + public void dispose() { + if (fProjectionModelUpdater != null) { + fProjectionModelUpdater.uninstall(); + fProjectionModelUpdater = null; + } + + if (fProjectionSupport != null) { + fProjectionSupport.dispose(); + fProjectionSupport = null; + } + // PHPEditorEnvironment.disconnect(this); + if (fOutlinePage != null) + fOutlinePage.setInput(null); + + if (fActionGroups != null) + fActionGroups.dispose(); + + if (isBrowserLikeLinks()) + disableBrowserLikeLinks(); + + // cancel possible running computation + fMarkOccurrenceAnnotations = false; + uninstallOccurrencesFinder(); + + uninstallOverrideIndicator(); + + if (fActivationListener != null) { + PlatformUI.getWorkbench().removeWindowListener(fActivationListener); + fActivationListener = null; + } + + if (fEncodingSupport != null) { + fEncodingSupport.dispose(); + fEncodingSupport = null; + } + + if (fPropertyChangeListener != null) { + Preferences preferences = PHPeclipsePlugin.getDefault() + .getPluginPreferences(); + preferences.removePropertyChangeListener(fPropertyChangeListener); + fPropertyChangeListener = null; + } + + // if (fSourceViewerDecorationSupport != null) { + // fSourceViewerDecorationSupport.dispose(); + // fSourceViewerDecorationSupport = null; + // } + + if (fBracketMatcher != null) { + fBracketMatcher.dispose(); + fBracketMatcher = null; + } + + if (fEditorSelectionChangedListener != null) { + fEditorSelectionChangedListener.uninstall(getSelectionProvider()); + fEditorSelectionChangedListener = null; + } + + super.dispose(); + } + + /** + * The PHPEditor implementation of this + * AbstractTextEditor method performs any extra revert + * behavior required by the php editor. + */ + // public void doRevertToSaved() { + // super.doRevertToSaved(); + // if (fOutlinePage != null) + // fOutlinePage.update(); + // } + /** + * The PHPEditor implementation of this + * AbstractTextEditor method performs any extra save behavior + * required by the php editor. + */ + // public void doSave(IProgressMonitor monitor) { + // super.doSave(monitor); + // compile or not, according to the user preferences + // IPreferenceStore store = getPreferenceStore(); + // the parse on save was changed to the eclipse "builders" concept + // if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) { + // IAction a = PHPParserAction.getInstance(); + // if (a != null) + // a.run(); + // } + // if (SWT.getPlatform().equals("win32")) { + // IAction a = ShowExternalPreviewAction.getInstance(); + // if (a != null) + // a.run(); + // } + // if (fOutlinePage != null) + // fOutlinePage.update(); + // } + /** + * The PHPEditor implementation of this + * AbstractTextEditor method performs any extra save as + * behavior required by the php editor. + */ + // public void doSaveAs() { + // super.doSaveAs(); + // if (fOutlinePage != null) + // fOutlinePage.update(); + // } + /* + * @see StatusTextEditor#getStatusHeader(IStatus) + */ + protected String getStatusHeader(IStatus status) { + if (fEncodingSupport != null) { + String message = fEncodingSupport.getStatusHeader(status); + if (message != null) + return message; + } + return super.getStatusHeader(status); + } + + /* + * @see StatusTextEditor#getStatusBanner(IStatus) + */ + protected String getStatusBanner(IStatus status) { + if (fEncodingSupport != null) { + String message = fEncodingSupport.getStatusBanner(status); + if (message != null) + return message; + } + return super.getStatusBanner(status); + } + + /* + * @see StatusTextEditor#getStatusMessage(IStatus) + */ + protected String getStatusMessage(IStatus status) { + if (fEncodingSupport != null) { + String message = fEncodingSupport.getStatusMessage(status); + if (message != null) + return message; + } + return super.getStatusMessage(status); + } + + /** + * The PHPEditor implementation of this + * AbstractTextEditor method performs sets the input of the + * outline page after AbstractTextEditor has set input. + */ + // protected void doSetInput(IEditorInput input) throws CoreException { + // super.doSetInput(input); + // if (fEncodingSupport != null) + // fEncodingSupport.reset(); + // setOutlinePageInput(fOutlinePage, input); + // } + /* + * @see AbstractTextEditor#doSetInput + */ + protected void doSetInput(IEditorInput input) throws CoreException { + ISourceViewer sourceViewer = getSourceViewer(); + if (!(sourceViewer instanceof ISourceViewerExtension2)) { + setPreferenceStore(createCombinedPreferenceStore(input)); + internalDoSetInput(input); + return; + } + + // uninstall & unregister preference store listener + if (isBrowserLikeLinks()) + disableBrowserLikeLinks(); + getSourceViewerDecorationSupport(sourceViewer).uninstall(); + ((ISourceViewerExtension2) sourceViewer).unconfigure(); + + setPreferenceStore(createCombinedPreferenceStore(input)); + + // install & register preference store listener + sourceViewer.configure(getSourceViewerConfiguration()); + getSourceViewerDecorationSupport(sourceViewer).install( + getPreferenceStore()); + if (isBrowserLikeLinks()) + enableBrowserLikeLinks(); + + internalDoSetInput(input); + } + + /* + * @see org.phpeclipse.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput() + */ + // public Object getViewPartInput() { + // return getEditorInput().getAdapter(IFile.class); + // } + /** + * The PHPEditor implementation of this + * AbstractTextEditor method adds any PHPEditor specific + * entries. + */ + public void editorContextMenuAboutToShow(MenuManager menu) { + super.editorContextMenuAboutToShow(menu); + menu.appendToGroup(ITextEditorActionConstants.GROUP_UNDO, + new Separator(IContextMenuConstants.GROUP_OPEN)); + menu.insertAfter(IContextMenuConstants.GROUP_OPEN, new GroupMarker( + IContextMenuConstants.GROUP_SHOW)); + + ActionContext context = new ActionContext(getSelectionProvider() + .getSelection()); + fContextMenuGroup.setContext(context); + fContextMenuGroup.fillContextMenu(menu); + fContextMenuGroup.setContext(null); + // addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); + // //$NON-NLS-1$ + // + // ActionContext context = + // new ActionContext(getSelectionProvider().getSelection()); + // fContextMenuGroup.setContext(context); + // fContextMenuGroup.fillContextMenu(menu); + // fContextMenuGroup.setContext(null); + } + + /** + * Creates the outline page used with this editor. + */ + protected JavaOutlinePage createOutlinePage() { + JavaOutlinePage page = new JavaOutlinePage(fOutlinerContextMenuId, this); + fOutlineSelectionChangedListener.install(page); + setOutlinePageInput(page, getEditorInput()); + return page; + } + + /** + * Informs the editor that its outliner has been closed. + */ + public void outlinePageClosed() { + if (fOutlinePage != null) { + fOutlineSelectionChangedListener.uninstall(fOutlinePage); + fOutlinePage = null; + resetHighlightRange(); + } + } + + /** + * Synchronizes the outliner selection with the given element position in + * the editor. + * + * @param element + * the java element to select + */ + protected void synchronizeOutlinePage(ISourceReference element) { + synchronizeOutlinePage(element, true); + } + + /** + * Synchronizes the outliner selection with the given element position in + * the editor. + * + * @param element + * the java element to select + * @param checkIfOutlinePageActive + * true if check for active outline page needs to + * be done + */ + protected void synchronizeOutlinePage(ISourceReference element, + boolean checkIfOutlinePageActive) { + if (fOutlinePage != null && element != null + && !(checkIfOutlinePageActive && isJavaOutlinePageActive())) { + fOutlineSelectionChangedListener.uninstall(fOutlinePage); + fOutlinePage.select(element); + fOutlineSelectionChangedListener.install(fOutlinePage); + } + } + + /** + * Synchronizes the outliner selection with the actual cursor position in + * the editor. + */ + public void synchronizeOutlinePageSelection() { + synchronizeOutlinePage(computeHighlightRangeSourceReference()); + + // ISourceViewer sourceViewer = getSourceViewer(); + // if (sourceViewer == null || fOutlinePage == null) + // return; + // + // StyledText styledText = sourceViewer.getTextWidget(); + // if (styledText == null) + // return; + // + // int caret = 0; + // if (sourceViewer instanceof ITextViewerExtension3) { + // ITextViewerExtension3 extension = (ITextViewerExtension3) + // sourceViewer; + // caret = + // extension.widgetOffset2ModelOffset(styledText.getCaretOffset()); + // } else { + // int offset = sourceViewer.getVisibleRegion().getOffset(); + // caret = offset + styledText.getCaretOffset(); + // } + // + // IJavaElement element = getElementAt(caret); + // if (element instanceof ISourceReference) { + // fOutlinePage.removeSelectionChangedListener(fSelectionChangedListener); + // fOutlinePage.select((ISourceReference) element); + // fOutlinePage.addSelectionChangedListener(fSelectionChangedListener); + // } + } + + protected void setSelection(ISourceReference reference, boolean moveCursor) { + + ISelection selection = getSelectionProvider().getSelection(); + if (selection instanceof TextSelection) { + TextSelection textSelection = (TextSelection) selection; + if (textSelection.getOffset() != 0 + || textSelection.getLength() != 0) + markInNavigationHistory(); + } + + if (reference != null) { + + StyledText textWidget = null; + + ISourceViewer sourceViewer = getSourceViewer(); + if (sourceViewer != null) + textWidget = sourceViewer.getTextWidget(); + + if (textWidget == null) + return; + + try { + + ISourceRange range = reference.getSourceRange(); + if (range == null) + return; + + int offset = range.getOffset(); + int length = range.getLength(); + + if (offset < 0 || length < 0) + return; + + textWidget.setRedraw(false); + + setHighlightRange(offset, length, moveCursor); + + if (!moveCursor) + return; + + offset = -1; + length = -1; + + if (reference instanceof IMember) { + range = ((IMember) reference).getNameRange(); + if (range != null) { + offset = range.getOffset(); + length = range.getLength(); + } + } + // else if (reference instanceof IImportDeclaration) { + // String name= ((IImportDeclaration) + // reference).getElementName(); + // if (name != null && name.length() > 0) { + // String content= reference.getSource(); + // if (content != null) { + // offset= range.getOffset() + content.indexOf(name); + // length= name.length(); + // } + // } + // } else if (reference instanceof IPackageDeclaration) { + // String name= ((IPackageDeclaration) + // reference).getElementName(); + // if (name != null && name.length() > 0) { + // String content= reference.getSource(); + // if (content != null) { + // offset= range.getOffset() + content.indexOf(name); + // length= name.length(); + // } + // } + // } + + if (offset > -1 && length > 0) { + sourceViewer.revealRange(offset, length); + sourceViewer.setSelectedRange(offset, length); + } + + } catch (JavaModelException x) { + } catch (IllegalArgumentException x) { + } finally { + if (textWidget != null) + textWidget.setRedraw(true); + } + + } else if (moveCursor) { + resetHighlightRange(); + } + + markInNavigationHistory(); + } + + public void setSelection(IJavaElement element) { + if (element == null || element instanceof ICompilationUnit) { // || + // element + // instanceof + // IClassFile) + // { + /* + * If the element is an ICompilationUnit this unit is either the + * input of this editor or not being displayed. In both cases, + * nothing should happened. + * (http://dev.eclipse.org/bugs/show_bug.cgi?id=5128) + */ + return; + } + + IJavaElement corresponding = getCorrespondingElement(element); + if (corresponding instanceof ISourceReference) { + ISourceReference reference = (ISourceReference) corresponding; + // set highlight range + setSelection(reference, true); + // set outliner selection + if (fOutlinePage != null) { + fOutlineSelectionChangedListener.uninstall(fOutlinePage); + fOutlinePage.select(reference); + fOutlineSelectionChangedListener.install(fOutlinePage); + } + } + } + + public synchronized void editingScriptStarted() { + ++fIgnoreOutlinePageSelection; + } + + public synchronized void editingScriptEnded() { + --fIgnoreOutlinePageSelection; + } + + public synchronized boolean isEditingScriptRunning() { + return (fIgnoreOutlinePageSelection > 0); + } + + /** + * The PHPEditor implementation of this + * AbstractTextEditor method performs gets the java content + * outline page if request is for a an outline page. + */ + public Object getAdapter(Class required) { + + if (IContentOutlinePage.class.equals(required)) { + if (fOutlinePage == null) + fOutlinePage = createOutlinePage(); + return fOutlinePage; + } + + if (IEncodingSupport.class.equals(required)) + return fEncodingSupport; + + if (required == IShowInTargetList.class) { + return new IShowInTargetList() { + public String[] getShowInTargetIds() { + return new String[] { JavaUI.ID_PACKAGES, + IPageLayout.ID_OUTLINE, IPageLayout.ID_RES_NAV }; + } + + }; + } + if (fProjectionSupport != null) { + Object adapter = fProjectionSupport.getAdapter(getSourceViewer(), + required); + if (adapter != null) + return adapter; + } + + return super.getAdapter(required); + } + + // public Object getAdapter(Class required) { + // if (IContentOutlinePage.class.equals(required)) { + // if (fOutlinePage == null) { + // fOutlinePage = new PHPContentOutlinePage(getDocumentProvider(), this); + // if (getEditorInput() != null) + // fOutlinePage.setInput(getEditorInput()); + // } + // return fOutlinePage; + // } + // + // if (IEncodingSupport.class.equals(required)) + // return fEncodingSupport; + // + // return super.getAdapter(required); + // } + + protected void doSelectionChanged(SelectionChangedEvent event) { + ISourceReference reference = null; + + ISelection selection = event.getSelection(); + Iterator iter = ((IStructuredSelection) selection).iterator(); + while (iter.hasNext()) { + Object o = iter.next(); + if (o instanceof ISourceReference) { + reference = (ISourceReference) o; + break; + } + } + + if (!isActivePart() && PHPeclipsePlugin.getActivePage() != null) + PHPeclipsePlugin.getActivePage().bringToTop(this); + + try { + editingScriptStarted(); + setSelection(reference, !isActivePart()); + } finally { + editingScriptEnded(); + } + } + + /* + * @see AbstractTextEditor#adjustHighlightRange(int, int) + */ + protected void adjustHighlightRange(int offset, int length) { + + try { + + IJavaElement element = getElementAt(offset); + while (element instanceof ISourceReference) { + ISourceRange range = ((ISourceReference) element) + .getSourceRange(); + if (offset < range.getOffset() + range.getLength() + && range.getOffset() < offset + length) { + + ISourceViewer viewer = getSourceViewer(); + if (viewer instanceof ITextViewerExtension5) { + ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; + extension.exposeModelRange(new Region( + range.getOffset(), range.getLength())); + } + + setHighlightRange(range.getOffset(), range.getLength(), + true); + if (fOutlinePage != null) { + fOutlineSelectionChangedListener + .uninstall(fOutlinePage); + fOutlinePage.select((ISourceReference) element); + fOutlineSelectionChangedListener.install(fOutlinePage); + } + + return; + } + element = element.getParent(); + } + + } catch (JavaModelException x) { + PHPeclipsePlugin.log(x.getStatus()); + } + + ISourceViewer viewer = getSourceViewer(); + if (viewer instanceof ITextViewerExtension5) { + ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; + extension.exposeModelRange(new Region(offset, length)); + } else { + resetHighlightRange(); + } + + } + + protected boolean isActivePart() { + IWorkbenchWindow window = getSite().getWorkbenchWindow(); + IPartService service = window.getPartService(); + IWorkbenchPart part = service.getActivePart(); + return part != null && part.equals(this); + } + + // public void openContextHelp() { + // IDocument doc = + // this.getDocumentProvider().getDocument(this.getEditorInput()); + // ITextSelection selection = (ITextSelection) + // this.getSelectionProvider().getSelection(); + // int pos = selection.getOffset(); + // String word = getFunctionName(doc, pos); + // openContextHelp(word); + // } + // + // private void openContextHelp(String word) { + // open(word); + // } + // + // public static void open(String word) { + // IHelp help = WorkbenchHelp.getHelpSupport(); + // if (help != null) { + // IHelpResource helpResource = new PHPFunctionHelpResource(word); + // WorkbenchHelp.getHelpSupport().displayHelpResource(helpResource); + // } else { + // // showMessage(shell, dialogTitle, ActionMessages.getString("Open help + // not available"), false); //$NON-NLS-1$ + // } + // } + + // private String getFunctionName(IDocument doc, int pos) { + // Point word = PHPWordExtractor.findWord(doc, pos); + // if (word != null) { + // try { + // return doc.get(word.x, word.y).replace('_', '-'); + // } catch (BadLocationException e) { + // } + // } + // return ""; + // } + + /* + * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent) + */ + protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { + + try { + + ISourceViewer sourceViewer = getSourceViewer(); + if (sourceViewer == null) + return; + + String property = event.getProperty(); + + if (PreferenceConstants.EDITOR_TAB_WIDTH.equals(property)) { + Object value = event.getNewValue(); + if (value instanceof Integer) { + sourceViewer.getTextWidget().setTabs( + ((Integer) value).intValue()); + } else if (value instanceof String) { + try { + sourceViewer.getTextWidget().setTabs( + Integer.parseInt((String) value)); + } catch (NumberFormatException e) { + // bug #1038071 - set default tab: + sourceViewer.getTextWidget().setTabs(80); + } + } + return; + } + + // if (OVERVIEW_RULER.equals(property)) { + // if (isOverviewRulerVisible()) + // showOverviewRuler(); + // else + // hideOverviewRuler(); + // return; + // } + + // if (LINE_NUMBER_RULER.equals(property)) { + // if (isLineNumberRulerVisible()) + // showLineNumberRuler(); + // else + // hideLineNumberRuler(); + // return; + // } + + // if (fLineNumberRulerColumn != null + // && (LINE_NUMBER_COLOR.equals(property) || + // PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property) || + // PREFERENCE_COLOR_BACKGROUND.equals(property))) { + // + // initializeLineNumberRulerColumn(fLineNumberRulerColumn); + // } + + if (isJavaEditorHoverProperty(property)) + updateHoverBehavior(); + + if (BROWSER_LIKE_LINKS.equals(property)) { + if (isBrowserLikeLinks()) + enableBrowserLikeLinks(); + else + disableBrowserLikeLinks(); + return; + } + + if (PreferenceConstants.EDITOR_DISABLE_OVERWRITE_MODE + .equals(property)) { + if (event.getNewValue() instanceof Boolean) { + Boolean disable = (Boolean) event.getNewValue(); + enableOverwriteMode(!disable.booleanValue()); + } + return; + } + + boolean newBooleanValue = false; + Object newValue = event.getNewValue(); + if (newValue != null) + newBooleanValue = Boolean.valueOf(newValue.toString()) + .booleanValue(); + + if (PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE + .equals(property)) { + if (newBooleanValue) + selectionChanged(); + return; + } + + if (PreferenceConstants.EDITOR_MARK_OCCURRENCES.equals(property)) { + if (newBooleanValue != fMarkOccurrenceAnnotations) { + fMarkOccurrenceAnnotations = newBooleanValue; + if (!fMarkOccurrenceAnnotations) + uninstallOccurrencesFinder(); + else + installOccurrencesFinder(); + } + return; + } + + if (PreferenceConstants.EDITOR_STICKY_OCCURRENCES.equals(property)) { + fStickyOccurrenceAnnotations = newBooleanValue; + return; + } + // } + // } + // if + // (PreferenceConstants.EDITOR_STICKY_OCCURRENCES.equals(property)) + // { + // if (event.getNewValue() instanceof Boolean) { + // boolean stickyOccurrenceAnnotations= + // ((Boolean)event.getNewValue()).booleanValue(); + // if (stickyOccurrenceAnnotations != fStickyOccurrenceAnnotations) + // { + + ((PHPSourceViewerConfiguration) getSourceViewerConfiguration()) + .handlePropertyChangeEvent(event); + + // if (affectsOverrideIndicatorAnnotations(event)) { + // if (isShowingOverrideIndicators()) { + // if (fOverrideIndicatorManager == null) + // installOverrideIndicator(true); + // } else { + // if (fOverrideIndicatorManager != null) + // uninstallOverrideIndicator(); + // } + // return; + // } + + if (PreferenceConstants.EDITOR_FOLDING_PROVIDER.equals(property)) { + if (sourceViewer instanceof ProjectionViewer) { + ProjectionViewer projectionViewer = (ProjectionViewer) sourceViewer; + if (fProjectionModelUpdater != null) + fProjectionModelUpdater.uninstall(); + // either freshly enabled or provider changed + fProjectionModelUpdater = PHPeclipsePlugin.getDefault() + .getFoldingStructureProviderRegistry() + .getCurrentFoldingProvider(); + if (fProjectionModelUpdater != null) { + fProjectionModelUpdater.install(this, projectionViewer); + } + } + return; + } + } finally { + super.handlePreferenceStoreChanged(event); + } + } + + // /* + // * @see + // AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent) + // */ + // protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { + // + // try { + // + // ISourceViewer sourceViewer = getSourceViewer(); + // if (sourceViewer == null) + // return; + // + // String property = event.getProperty(); + // + // // if + // (JavaSourceViewerConfiguration.PREFERENCE_TAB_WIDTH.equals(property)) { + // // Object value= event.getNewValue(); + // // if (value instanceof Integer) { + // // sourceViewer.getTextWidget().setTabs(((Integer) value).intValue()); + // // } else if (value instanceof String) { + // // sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) + // value)); + // // } + // // return; + // // } + // + // if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) { + // if (isLineNumberRulerVisible()) + // showLineNumberRuler(); + // else + // hideLineNumberRuler(); + // return; + // } + // + // if (fLineNumberRulerColumn != null + // && (IPreferenceConstants.LINE_NUMBER_COLOR.equals(property) + // || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property) + // || PREFERENCE_COLOR_BACKGROUND.equals(property))) { + // + // initializeLineNumberRulerColumn(fLineNumberRulerColumn); + // } + // + // } finally { + // super.handlePreferenceStoreChanged(event); + // } + // } + + // private boolean isJavaEditorHoverProperty(String property) { + // return PreferenceConstants.EDITOR_DEFAULT_HOVER.equals(property) + // || PreferenceConstants.EDITOR_NONE_HOVER.equals(property) + // || PreferenceConstants.EDITOR_CTRL_HOVER.equals(property) + // || PreferenceConstants.EDITOR_SHIFT_HOVER.equals(property) + // || PreferenceConstants.EDITOR_CTRL_ALT_HOVER.equals(property) + // || PreferenceConstants.EDITOR_CTRL_SHIFT_HOVER.equals(property) + // || PreferenceConstants.EDITOR_CTRL_ALT_SHIFT_HOVER.equals(property) + // || PreferenceConstants.EDITOR_ALT_SHIFT_HOVER.equals(property); + // } + + /** + * Shows the line number ruler column. + */ + // private void showLineNumberRuler() { + // IVerticalRuler v = getVerticalRuler(); + // if (v instanceof CompositeRuler) { + // CompositeRuler c = (CompositeRuler) v; + // c.addDecorator(1, createLineNumberRulerColumn()); + // } + // } + private boolean isJavaEditorHoverProperty(String property) { + return PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS.equals(property); + } + + /** + * Return whether the browser like links should be enabled according to the + * preference store settings. + * + * @return true if the browser like links should be enabled + */ + private boolean isBrowserLikeLinks() { + IPreferenceStore store = getPreferenceStore(); + return store.getBoolean(BROWSER_LIKE_LINKS); + } + + /** + * Enables browser like links. + */ + private void enableBrowserLikeLinks() { + if (fMouseListener == null) { + fMouseListener = new MouseClickListener(); + fMouseListener.install(); + } + } + + /** + * Disables browser like links. + */ + private void disableBrowserLikeLinks() { + if (fMouseListener != null) { + fMouseListener.uninstall(); + fMouseListener = null; + } + } + + /** + * Handles a property change event describing a change of the java core's + * preferences and updates the preference related editor properties. + * + * @param event + * the property change event + */ + protected void handlePreferencePropertyChanged( + org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) { + if (COMPILER_TASK_TAGS.equals(event.getProperty())) { + ISourceViewer sourceViewer = getSourceViewer(); + if (sourceViewer != null + && affectsTextPresentation(new PropertyChangeEvent(event + .getSource(), event.getProperty(), event + .getOldValue(), event.getNewValue()))) + sourceViewer.invalidateTextPresentation(); + } + if (PreferenceConstants.EDITOR_WRAP_WORDS.equals(event.getProperty())) { + setWordWrap(); + } + } + + /** + * Return whether the line number ruler column should be visible according + * to the preference store settings. + * + * @return true if the line numbers should be visible + */ + // protected boolean isLineNumberRulerVisible() { + // IPreferenceStore store = getPreferenceStore(); + // return store.getBoolean(LINE_NUMBER_RULER); + // } + /** + * Hides the line number ruler column. + */ + // private void hideLineNumberRuler() { + // IVerticalRuler v = getVerticalRuler(); + // if (v instanceof CompositeRuler) { + // CompositeRuler c = (CompositeRuler) v; + // try { + // c.removeDecorator(1); + // } catch (Throwable e) { + // } + // } + // } + /* + * @see AbstractTextEditor#handleCursorPositionChanged() + */ + // protected void handleCursorPositionChanged() { + // super.handleCursorPositionChanged(); + // if (!isEditingScriptRunning() && fUpdater != null) + // fUpdater.post(); + // } + /* + * @see org.eclipse.ui.texteditor.AbstractTextEditor#handleElementContentReplaced() + */ + protected void handleElementContentReplaced() { + super.handleElementContentReplaced(); + if (fProjectionModelUpdater != null) + fProjectionModelUpdater.initialize(); + } + + /** + * Initializes the given line number ruler column from the preference store. + * + * @param rulerColumn + * the ruler column to be initialized + */ + // protected void initializeLineNumberRulerColumn(LineNumberRulerColumn + // rulerColumn) { + // JavaTextTools textTools = + // PHPeclipsePlugin.getDefault().getJavaTextTools(); + // IColorManager manager = textTools.getColorManager(); + // + // IPreferenceStore store = getPreferenceStore(); + // if (store != null) { + // + // RGB rgb = null; + // // foreground color + // if (store.contains(LINE_NUMBER_COLOR)) { + // if (store.isDefault(LINE_NUMBER_COLOR)) + // rgb = PreferenceConverter.getDefaultColor(store, LINE_NUMBER_COLOR); + // else + // rgb = PreferenceConverter.getColor(store, LINE_NUMBER_COLOR); + // } + // rulerColumn.setForeground(manager.getColor(rgb)); + // + // rgb = null; + // // background color + // if (!store.getBoolean(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) { + // if (store.contains(PREFERENCE_COLOR_BACKGROUND)) { + // if (store.isDefault(PREFERENCE_COLOR_BACKGROUND)) + // rgb = PreferenceConverter.getDefaultColor(store, + // PREFERENCE_COLOR_BACKGROUND); + // else + // rgb = PreferenceConverter.getColor(store, PREFERENCE_COLOR_BACKGROUND); + // } + // } + // rulerColumn.setBackground(manager.getColor(rgb)); + // } + // } + /** + * Creates a new line number ruler column that is appropriately initialized. + */ + // protected IVerticalRulerColumn createLineNumberRulerColumn() { + // fLineNumberRulerColumn = new LineNumberRulerColumn(); + // initializeLineNumberRulerColumn(fLineNumberRulerColumn); + // return fLineNumberRulerColumn; + // } + /* + * @see AbstractTextEditor#createVerticalRuler() + */ + // protected IVerticalRuler createVerticalRuler() { + // CompositeRuler ruler = new CompositeRuler(); + // ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH)); + // if (isLineNumberRulerVisible()) + // ruler.addDecorator(1, createLineNumberRulerColumn()); + // return ruler; + // } + // private static IRegion getSignedSelection(ITextViewer viewer) { + // + // StyledText text = viewer.getTextWidget(); + // int caretOffset = text.getCaretOffset(); + // Point selection = text.getSelection(); + // + // // caret left + // int offset, length; + // if (caretOffset == selection.x) { + // offset = selection.y; + // length = selection.x - selection.y; + // + // // caret right + // } else { + // offset = selection.x; + // length = selection.y - selection.x; + // } + // + // return new Region(offset, length); + // } + protected IRegion getSignedSelection(ISourceViewer sourceViewer) { + StyledText text = sourceViewer.getTextWidget(); + Point selection = text.getSelectionRange(); + + if (text.getCaretOffset() == selection.x) { + selection.x = selection.x + selection.y; + selection.y = -selection.y; + } + + selection.x = widgetOffset2ModelOffset(sourceViewer, selection.x); + + return new Region(selection.x, selection.y); + } + + /** Preference key for matching brackets */ + protected final static String MATCHING_BRACKETS = PreferenceConstants.EDITOR_MATCHING_BRACKETS; + + /** Preference key for matching brackets color */ + protected final static String MATCHING_BRACKETS_COLOR = PreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR; + + /** Preference key for highlighting current line */ + // protected final static String CURRENT_LINE = + // PreferenceConstants.EDITOR_CURRENT_LINE; + /** Preference key for highlight color of current line */ + // protected final static String CURRENT_LINE_COLOR = + // PreferenceConstants.EDITOR_CURRENT_LINE_COLOR; + /** Preference key for showing print marging ruler */ + // protected final static String PRINT_MARGIN = + // PreferenceConstants.EDITOR_PRINT_MARGIN; + /** Preference key for print margin ruler color */ + // protected final static String PRINT_MARGIN_COLOR = + // PreferenceConstants.EDITOR_PRINT_MARGIN_COLOR; + /** Preference key for print margin ruler column */ + // protected final static String PRINT_MARGIN_COLUMN = + // PreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN; + /** Preference key for error indication */ + // protected final static String ERROR_INDICATION = + // PreferenceConstants.EDITOR_PROBLEM_INDICATION; + /** Preference key for error color */ + // protected final static String ERROR_INDICATION_COLOR = + // PreferenceConstants.EDITOR_PROBLEM_INDICATION_COLOR; + /** Preference key for warning indication */ + // protected final static String WARNING_INDICATION = + // PreferenceConstants.EDITOR_WARNING_INDICATION; + /** Preference key for warning color */ + // protected final static String WARNING_INDICATION_COLOR = + // PreferenceConstants.EDITOR_WARNING_INDICATION_COLOR; + /** Preference key for task indication */ + protected final static String TASK_INDICATION = PreferenceConstants.EDITOR_TASK_INDICATION; + + /** Preference key for task color */ + protected final static String TASK_INDICATION_COLOR = PreferenceConstants.EDITOR_TASK_INDICATION_COLOR; + + /** Preference key for bookmark indication */ + protected final static String BOOKMARK_INDICATION = PreferenceConstants.EDITOR_BOOKMARK_INDICATION; + + /** Preference key for bookmark color */ + protected final static String BOOKMARK_INDICATION_COLOR = PreferenceConstants.EDITOR_BOOKMARK_INDICATION_COLOR; + + /** Preference key for search result indication */ + protected final static String SEARCH_RESULT_INDICATION = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION; + + /** Preference key for search result color */ + protected final static String SEARCH_RESULT_INDICATION_COLOR = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION_COLOR; + + /** Preference key for unknown annotation indication */ + protected final static String UNKNOWN_INDICATION = PreferenceConstants.EDITOR_UNKNOWN_INDICATION; + + /** Preference key for unknown annotation color */ + protected final static String UNKNOWN_INDICATION_COLOR = PreferenceConstants.EDITOR_UNKNOWN_INDICATION_COLOR; + + /** Preference key for shwoing the overview ruler */ + protected final static String OVERVIEW_RULER = PreferenceConstants.EDITOR_OVERVIEW_RULER; + + /** Preference key for error indication in overview ruler */ + protected final static String ERROR_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_ERROR_INDICATION_IN_OVERVIEW_RULER; + + /** Preference key for warning indication in overview ruler */ + protected final static String WARNING_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_WARNING_INDICATION_IN_OVERVIEW_RULER; + + /** Preference key for task indication in overview ruler */ + protected final static String TASK_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_TASK_INDICATION_IN_OVERVIEW_RULER; + + /** Preference key for bookmark indication in overview ruler */ + protected final static String BOOKMARK_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_BOOKMARK_INDICATION_IN_OVERVIEW_RULER; + + /** Preference key for search result indication in overview ruler */ + protected final static String SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER; + + /** Preference key for unknown annotation indication in overview ruler */ + protected final static String UNKNOWN_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_UNKNOWN_INDICATION_IN_OVERVIEW_RULER; + + // /** Preference key for compiler task tags */ + // private final static String COMPILER_TASK_TAGS= + // JavaCore.COMPILER_TASK_TAGS; + /** Preference key for browser like links */ + private final static String BROWSER_LIKE_LINKS = PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS; + + /** Preference key for key modifier of browser like links */ + private final static String BROWSER_LIKE_LINKS_KEY_MODIFIER = PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER; + + /** + * Preference key for key modifier mask of browser like links. The value is + * only used if the value of EDITOR_BROWSER_LIKE_LINKS cannot + * be resolved to valid SWT modifier bits. + * + * @since 2.1.1 + */ + private final static String BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK = PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK; + + private final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']' }; + + private static boolean isBracket(char character) { + for (int i = 0; i != BRACKETS.length; ++i) + if (character == BRACKETS[i]) + return true; + return false; + } + + private static boolean isSurroundedByBrackets(IDocument document, int offset) { + if (offset == 0 || offset == document.getLength()) + return false; + + try { + return isBracket(document.getChar(offset - 1)) + && isBracket(document.getChar(offset)); + + } catch (BadLocationException e) { + return false; + } + } + + // protected void configureSourceViewerDecorationSupport() { + // + // fSourceViewerDecorationSupport.setCharacterPairMatcher(fBracketMatcher); + // + // fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( + // AnnotationType.UNKNOWN, + // UNKNOWN_INDICATION_COLOR, + // UNKNOWN_INDICATION, + // UNKNOWN_INDICATION_IN_OVERVIEW_RULER, + // 0); + // fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( + // AnnotationType.BOOKMARK, + // BOOKMARK_INDICATION_COLOR, + // BOOKMARK_INDICATION, + // BOOKMARK_INDICATION_IN_OVERVIEW_RULER, + // 1); + // fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( + // AnnotationType.TASK, + // TASK_INDICATION_COLOR, + // TASK_INDICATION, + // TASK_INDICATION_IN_OVERVIEW_RULER, + // 2); + // fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( + // AnnotationType.SEARCH, + // SEARCH_RESULT_INDICATION_COLOR, + // SEARCH_RESULT_INDICATION, + // SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER, + // 3); + // fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( + // AnnotationType.WARNING, + // WARNING_INDICATION_COLOR, + // WARNING_INDICATION, + // WARNING_INDICATION_IN_OVERVIEW_RULER, + // 4); + // fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( + // AnnotationType.ERROR, + // ERROR_INDICATION_COLOR, + // ERROR_INDICATION, + // ERROR_INDICATION_IN_OVERVIEW_RULER, + // 5); + // + // fSourceViewerDecorationSupport.setCursorLinePainterPreferenceKeys(CURRENT_LINE, + // CURRENT_LINE_COLOR); + // fSourceViewerDecorationSupport.setMarginPainterPreferenceKeys(PRINT_MARGIN, + // PRINT_MARGIN_COLOR, PRINT_MARGIN_COLUMN); + // fSourceViewerDecorationSupport.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, + // MATCHING_BRACKETS_COLOR); + // + // fSourceViewerDecorationSupport.setSymbolicFontName(getFontPropertyPreferenceKey()); + // + // } + /** + * Returns the Java element wrapped by this editors input. + * + * @return the Java element wrapped by this editors input. + * @since 3.0 + */ + abstract protected IJavaElement getInputJavaElement(); + + protected void updateStatusLine() { + ITextSelection selection = (ITextSelection) getSelectionProvider() + .getSelection(); + Annotation annotation = getAnnotation(selection.getOffset(), selection + .getLength()); + setStatusLineErrorMessage(null); + setStatusLineMessage(null); + if (annotation != null) { + try { + fIsUpdatingAnnotationViews = true; + updateAnnotationViews(annotation); + } finally { + fIsUpdatingAnnotationViews = false; + } + if (annotation instanceof IJavaAnnotation + && ((IJavaAnnotation) annotation).isProblem()) + setStatusLineMessage(annotation.getText()); + } + } + + /** + * Jumps to the matching bracket. + */ + public void gotoMatchingBracket() { + + ISourceViewer sourceViewer = getSourceViewer(); + IDocument document = sourceViewer.getDocument(); + if (document == null) + return; + + IRegion selection = getSignedSelection(sourceViewer); + + int selectionLength = Math.abs(selection.getLength()); + if (selectionLength > 1) { + setStatusLineErrorMessage(PHPEditorMessages + .getString("GotoMatchingBracket.error.invalidSelection")); //$NON-NLS-1$ + sourceViewer.getTextWidget().getDisplay().beep(); + return; + } + + // #26314 + int sourceCaretOffset = selection.getOffset() + selection.getLength(); + if (isSurroundedByBrackets(document, sourceCaretOffset)) + sourceCaretOffset -= selection.getLength(); + + IRegion region = fBracketMatcher.match(document, sourceCaretOffset); + if (region == null) { + setStatusLineErrorMessage(PHPEditorMessages + .getString("GotoMatchingBracket.error.noMatchingBracket")); //$NON-NLS-1$ + sourceViewer.getTextWidget().getDisplay().beep(); + return; + } + + int offset = region.getOffset(); + int length = region.getLength(); + + if (length < 1) + return; + + int anchor = fBracketMatcher.getAnchor(); + int targetOffset = (PHPPairMatcher.RIGHT == anchor) ? offset : offset + + length - 1; + + boolean visible = false; + if (sourceViewer instanceof ITextViewerExtension5) { + ITextViewerExtension5 extension = (ITextViewerExtension5) sourceViewer; + visible = (extension.modelOffset2WidgetOffset(targetOffset) > -1); + } else { + IRegion visibleRegion = sourceViewer.getVisibleRegion(); + visible = (targetOffset >= visibleRegion.getOffset() && targetOffset < visibleRegion + .getOffset() + + visibleRegion.getLength()); + } + + if (!visible) { + setStatusLineErrorMessage(PHPEditorMessages + .getString("GotoMatchingBracket.error.bracketOutsideSelectedElement")); //$NON-NLS-1$ + sourceViewer.getTextWidget().getDisplay().beep(); + return; + } + + if (selection.getLength() < 0) + targetOffset -= selection.getLength(); + + sourceViewer.setSelectedRange(targetOffset, selection.getLength()); + sourceViewer.revealRange(targetOffset, selection.getLength()); + } + + /** + * Ses the given message as error message to this editor's status line. + * + * @param msg + * message to be set + */ + protected void setStatusLineErrorMessage(String msg) { + IEditorStatusLine statusLine = (IEditorStatusLine) getAdapter(IEditorStatusLine.class); + if (statusLine != null) + statusLine.setMessage(true, msg, null); + } + + /** + * Sets the given message as message to this editor's status line. + * + * @param msg + * message to be set + * @since 3.0 + */ + protected void setStatusLineMessage(String msg) { + IEditorStatusLine statusLine = (IEditorStatusLine) getAdapter(IEditorStatusLine.class); + if (statusLine != null) + statusLine.setMessage(false, msg, null); + } + + /** + * Returns the annotation closest to the given range respecting the given + * direction. If an annotation is found, the annotations current position is + * copied into the provided annotation position. + * + * @param offset + * the region offset + * @param length + * the region length + * @param forward + * true for forwards, false for + * backward + * @param annotationPosition + * the position of the found annotation + * @return the found annotation + */ + private Annotation getNextAnnotation(final int offset, final int length, + boolean forward, Position annotationPosition) { + + Annotation nextAnnotation = null; + Position nextAnnotationPosition = null; + Annotation containingAnnotation = null; + Position containingAnnotationPosition = null; + boolean currentAnnotation = false; + + IDocument document = getDocumentProvider() + .getDocument(getEditorInput()); + int endOfDocument = document.getLength(); + int distance = Integer.MAX_VALUE; + + IAnnotationModel model = getDocumentProvider().getAnnotationModel( + getEditorInput()); + Iterator e = new JavaAnnotationIterator(model, true, true); + while (e.hasNext()) { + Annotation a = (Annotation) e.next(); + if ((a instanceof IJavaAnnotation) + && ((IJavaAnnotation) a).hasOverlay() + || !isNavigationTarget(a)) + continue; + + Position p = model.getPosition(a); + if (p == null) + continue; + + if (forward && p.offset == offset || !forward + && p.offset + p.getLength() == offset + length) {// || + // p.includes(offset)) + // { + if (containingAnnotation == null + || (forward + && p.length >= containingAnnotationPosition.length || !forward + && p.length >= containingAnnotationPosition.length)) { + containingAnnotation = a; + containingAnnotationPosition = p; + currentAnnotation = p.length == length; + } + } else { + int currentDistance = 0; + + if (forward) { + currentDistance = p.getOffset() - offset; + if (currentDistance < 0) + currentDistance = endOfDocument + currentDistance; + + if (currentDistance < distance + || currentDistance == distance + && p.length < nextAnnotationPosition.length) { + distance = currentDistance; + nextAnnotation = a; + nextAnnotationPosition = p; + } + } else { + currentDistance = offset + length + - (p.getOffset() + p.length); + if (currentDistance < 0) + currentDistance = endOfDocument + currentDistance; + + if (currentDistance < distance + || currentDistance == distance + && p.length < nextAnnotationPosition.length) { + distance = currentDistance; + nextAnnotation = a; + nextAnnotationPosition = p; + } + } + } + } + if (containingAnnotationPosition != null + && (!currentAnnotation || nextAnnotation == null)) { + annotationPosition.setOffset(containingAnnotationPosition + .getOffset()); + annotationPosition.setLength(containingAnnotationPosition + .getLength()); + return containingAnnotation; + } + if (nextAnnotationPosition != null) { + annotationPosition.setOffset(nextAnnotationPosition.getOffset()); + annotationPosition.setLength(nextAnnotationPosition.getLength()); + } + + return nextAnnotation; + } + + /** + * Returns the annotation overlapping with the given range or + * null. + * + * @param offset + * the region offset + * @param length + * the region length + * @return the found annotation or null + * @since 3.0 + */ + private Annotation getAnnotation(int offset, int length) { + IAnnotationModel model = getDocumentProvider().getAnnotationModel( + getEditorInput()); + Iterator e = new JavaAnnotationIterator(model, true, true); + while (e.hasNext()) { + Annotation a = (Annotation) e.next(); + if (!isNavigationTarget(a)) + continue; + + Position p = model.getPosition(a); + if (p != null && p.overlapsWith(offset, length)) + return a; + } + + return null; + } + + /** + * Returns whether the given annotation is configured as a target for the + * "Go to Next/Previous Annotation" actions + * + * @param annotation + * the annotation + * @return true if this is a target, false + * otherwise + * @since 3.0 + */ + protected boolean isNavigationTarget(Annotation annotation) { + Preferences preferences = EditorsUI.getPluginPreferences(); + AnnotationPreference preference = getAnnotationPreferenceLookup() + .getAnnotationPreference(annotation); + // See bug 41689 + // String key= forward ? preference.getIsGoToNextNavigationTargetKey() : + // preference.getIsGoToPreviousNavigationTargetKey(); + String key = preference == null ? null : preference + .getIsGoToNextNavigationTargetKey(); + return (key != null && preferences.getBoolean(key)); + } + + /** + * Returns a segmentation of the line of the given document appropriate for + * bidi rendering. The default implementation returns only the string + * literals of a php code line as segments. + * + * @param document + * the document + * @param lineOffset + * the offset of the line + * @return the line's bidi segmentation + * @throws BadLocationException + * in case lineOffset is not valid in document + */ + public static int[] getBidiLineSegments(IDocument document, int lineOffset) + throws BadLocationException { + + IRegion line = document.getLineInformationOfOffset(lineOffset); + ITypedRegion[] linePartitioning = document.computePartitioning( + lineOffset, line.getLength()); + + List segmentation = new ArrayList(); + for (int i = 0; i < linePartitioning.length; i++) { + if (IPHPPartitions.PHP_STRING_DQ.equals(linePartitioning[i] + .getType())) { + segmentation.add(linePartitioning[i]); + } else if (IPHPPartitions.PHP_STRING_HEREDOC + .equals(linePartitioning[i].getType())) { + segmentation.add(linePartitioning[i]); + } + } + + if (segmentation.size() == 0) + return null; + + int size = segmentation.size(); + int[] segments = new int[size * 2 + 1]; + + int j = 0; + for (int i = 0; i < size; i++) { + ITypedRegion segment = (ITypedRegion) segmentation.get(i); + + if (i == 0) + segments[j++] = 0; + + int offset = segment.getOffset() - lineOffset; + if (offset > segments[j - 1]) + segments[j++] = offset; + + if (offset + segment.getLength() >= line.getLength()) + break; + + segments[j++] = offset + segment.getLength(); + } + + if (j < segments.length) { + int[] result = new int[j]; + System.arraycopy(segments, 0, result, 0, j); + segments = result; + } + + return segments; + } + + /** + * Returns a segmentation of the given line appropriate for bidi rendering. + * The default implementation returns only the string literals of a php code + * line as segments. + * + * @param lineOffset + * the offset of the line + * @param line + * the content of the line + * @return the line's bidi segmentation + */ + protected int[] getBidiLineSegments(int lineOffset, String line) { + IDocumentProvider provider = getDocumentProvider(); + if (provider != null && line != null && line.length() > 0) { + IDocument document = provider.getDocument(getEditorInput()); + if (document != null) + try { + return getBidiLineSegments(document, lineOffset); + } catch (BadLocationException x) { + // ignore + } + } + return null; + } + + /* + * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, + * int) + */ + // protected final ISourceViewer createSourceViewer( + // Composite parent, + // IVerticalRuler ruler, + // int styles) { + // ISourceViewer viewer = createJavaSourceViewer(parent, ruler, styles); + // StyledText text = viewer.getTextWidget(); + // text.addBidiSegmentListener(new BidiSegmentListener() { + // public void lineGetSegments(BidiSegmentEvent event) { + // event.segments = getBidiLineSegments(event.lineOffset, event.lineText); + // } + // }); + // // JavaUIHelp.setHelp(this, text, IJavaHelpContextIds.JAVA_EDITOR); + // return viewer; + // } + public final ISourceViewer getViewer() { + return getSourceViewer(); + } + + // protected void showOverviewRuler() { + // if (fOverviewRuler != null) { + // if (getSourceViewer() instanceof ISourceViewerExtension) { + // ((ISourceViewerExtension) + // getSourceViewer()).showAnnotationsOverview(true); + // fSourceViewerDecorationSupport.updateOverviewDecorations(); + // } + // } + // } + // + // protected void hideOverviewRuler() { + // if (getSourceViewer() instanceof ISourceViewerExtension) { + // fSourceViewerDecorationSupport.hideAnnotationOverview(); + // ((ISourceViewerExtension) + // getSourceViewer()).showAnnotationsOverview(false); + // } + // } + + // protected boolean isOverviewRulerVisible() { + // IPreferenceStore store = getPreferenceStore(); + // return store.getBoolean(OVERVIEW_RULER); + // } + /* + * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, + * int) + */ + // protected ISourceViewer createJavaSourceViewer( + // Composite parent, + // IVerticalRuler ruler, + // IOverviewRuler overviewRuler, + // boolean isOverviewRulerVisible, + // int styles) { + // return new SourceViewer(parent, ruler, overviewRuler, + // isOverviewRulerVisible(), styles); + // } + /* + * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, + * int) + */ + protected ISourceViewer createJavaSourceViewer(Composite parent, + IVerticalRuler verticalRuler, IOverviewRuler overviewRuler, + boolean isOverviewRulerVisible, int styles, IPreferenceStore store) { + return new JavaSourceViewer(parent, verticalRuler, getOverviewRuler(), + isOverviewRulerVisible(), styles, store); + } + + /* + * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, + * int) + */ + protected final ISourceViewer createSourceViewer(Composite parent, + IVerticalRuler verticalRuler, int styles) { + + ISourceViewer viewer = createJavaSourceViewer(parent, verticalRuler, + getOverviewRuler(), isOverviewRulerVisible(), styles, + getPreferenceStore()); + + StyledText text = viewer.getTextWidget(); + text.addBidiSegmentListener(new BidiSegmentListener() { + public void lineGetSegments(BidiSegmentEvent event) { + event.segments = getBidiLineSegments(event.lineOffset, + event.lineText); + } + }); + + // JavaUIHelp.setHelp(this, text, IJavaHelpContextIds.JAVA_EDITOR); + + // ensure source viewer decoration support has been created and + // configured + getSourceViewerDecorationSupport(viewer); + + return viewer; + } + + /* + * @see AbstractTextEditor#affectsTextPresentation(PropertyChangeEvent) + */ + protected boolean affectsTextPresentation(PropertyChangeEvent event) { + return ((PHPSourceViewerConfiguration) getSourceViewerConfiguration()) + .affectsTextPresentation(event) + || super.affectsTextPresentation(event); + } + + // + // protected boolean affectsTextPresentation(PropertyChangeEvent event) { + // JavaTextTools textTools = + // PHPeclipsePlugin.getDefault().getJavaTextTools(); + // return textTools.affectsBehavior(event); + // } + /** + * Creates and returns the preference store for this Java editor with the + * given input. + * + * @param input + * The editor input for which to create the preference store + * @return the preference store for this editor + * + * @since 3.0 + */ + private IPreferenceStore createCombinedPreferenceStore(IEditorInput input) { + List stores = new ArrayList(3); + + IJavaProject project = EditorUtility.getJavaProject(input); + if (project != null) + stores.add(new OptionsAdapter(project.getOptions(false), + PHPeclipsePlugin.getDefault().getMockupPreferenceStore(), + new OptionsAdapter.IPropertyChangeEventFilter() { + + public boolean isFiltered(PropertyChangeEvent event) { + IJavaElement inputJavaElement = getInputJavaElement(); + IJavaProject javaProject = inputJavaElement != null ? inputJavaElement + .getJavaProject() + : null; + if (javaProject == null) + return true; + + return !javaProject.getProject().equals( + event.getSource()); + } + + })); + + stores.add(PHPeclipsePlugin.getDefault().getPreferenceStore()); + stores.add(new PreferencesAdapter(JavaCore.getPlugin() + .getPluginPreferences())); + stores.add(EditorsUI.getPreferenceStore()); + + return new ChainedPreferenceStore((IPreferenceStore[]) stores + .toArray(new IPreferenceStore[stores.size()])); + } + + /** + * Jumps to the error next according to the given direction. + */ + public void gotoError(boolean forward) { + + ISelectionProvider provider = getSelectionProvider(); + + ITextSelection s = (ITextSelection) provider.getSelection(); + Position errorPosition = new Position(0, 0); + IJavaAnnotation nextError = getNextError(s.getOffset(), forward, + errorPosition); + + if (nextError != null) { + + IMarker marker = null; + if (nextError instanceof MarkerAnnotation) + marker = ((MarkerAnnotation) nextError).getMarker(); + else { + Iterator e = nextError.getOverlaidIterator(); + if (e != null) { + while (e.hasNext()) { + Object o = e.next(); + if (o instanceof MarkerAnnotation) { + marker = ((MarkerAnnotation) o).getMarker(); + break; + } + } + } + } + + if (marker != null) { + IWorkbenchPage page = getSite().getPage(); + IViewPart view = view = page + .findView("org.eclipse.ui.views.TaskList"); //$NON-NLS-1$ + if (view instanceof TaskList) { + StructuredSelection ss = new StructuredSelection(marker); + ((TaskList) view).setSelection(ss, true); + } + } + + selectAndReveal(errorPosition.getOffset(), errorPosition + .getLength()); + // setStatusLineErrorMessage(nextError.getMessage()); + + } else { + + setStatusLineErrorMessage(null); + + } + } + + private IJavaAnnotation getNextError(int offset, boolean forward, + Position errorPosition) { + + IJavaAnnotation nextError = null; + Position nextErrorPosition = null; + + IDocument document = getDocumentProvider() + .getDocument(getEditorInput()); + int endOfDocument = document.getLength(); + int distance = 0; + + IAnnotationModel model = getDocumentProvider().getAnnotationModel( + getEditorInput()); + Iterator e = new JavaAnnotationIterator(model, false); + while (e.hasNext()) { + + IJavaAnnotation a = (IJavaAnnotation) e.next(); + if (a.hasOverlay() || !a.isProblem()) + continue; + + Position p = model.getPosition((Annotation) a); + if (!p.includes(offset)) { + + int currentDistance = 0; + + if (forward) { + currentDistance = p.getOffset() - offset; + if (currentDistance < 0) + currentDistance = endOfDocument - offset + + p.getOffset(); + } else { + currentDistance = offset - p.getOffset(); + if (currentDistance < 0) + currentDistance = offset + endOfDocument + - p.getOffset(); + } + + if (nextError == null || currentDistance < distance) { + distance = currentDistance; + nextError = a; + nextErrorPosition = p; + } + } + } + + if (nextErrorPosition != null) { + errorPosition.setOffset(nextErrorPosition.getOffset()); + errorPosition.setLength(nextErrorPosition.getLength()); + } + + return nextError; + } + + protected void uninstallOverrideIndicator() { + // if (fOverrideIndicatorManager != null) { + // fOverrideIndicatorManager.removeAnnotations(); + // fOverrideIndicatorManager= null; + // } + } + + protected void installOverrideIndicator(boolean waitForReconcilation) { + uninstallOverrideIndicator(); + IAnnotationModel model = getDocumentProvider().getAnnotationModel( + getEditorInput()); + final IJavaElement inputElement = getInputJavaElement(); + + if (model == null || inputElement == null) + return; + + // fOverrideIndicatorManager= new OverrideIndicatorManager(model, + // inputElement, null); + // + // if (provideAST) { + // Job job= new + // Job(JavaEditorMessages.getString("OverrideIndicatorManager.intallJob")) + // { + // //$NON-NLS-1$ + // /* + // * @see + // org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) + // * @since 3.0 + // */ + // protected IStatus run(IProgressMonitor monitor) { + // CompilationUnit ast= + // JavaPlugin.getDefault().getASTProvider().getAST(inputElement, true, + // null); + // if (fOverrideIndicatorManager != null) // editor might have been + // closed + // in the meanwhile + // fOverrideIndicatorManager.reconciled(ast, true, monitor); + // return Status.OK_STATUS; + // } + // }; + // job.setPriority(Job.DECORATE); + // job.setSystem(true); + // job.schedule(); + // } + } + + /** + * Tells whether override indicators are shown. + * + * @return true if the override indicators are shown + * @since 3.0 + */ + // protected boolean isShowingOverrideIndicators() { + // AnnotationPreference preference= + // getAnnotationPreferenceLookup().getAnnotationPreference(OverrideIndicatorManager.ANNOTATION_TYPE); + // IPreferenceStore store= getPreferenceStore(); + // return getBoolean(store, preference.getHighlightPreferenceKey()) + // || getBoolean(store, preference.getVerticalRulerPreferenceKey()) + // || getBoolean(store, preference.getOverviewRulerPreferenceKey()) + // || getBoolean(store, preference.getTextPreferenceKey()); + // } + /** + * Returns the boolean preference for the given key. + * + * @param store + * the preference store + * @param key + * the preference key + * @return true if the key exists in the store and its value + * is true + * @since 3.0 + */ + private boolean getBoolean(IPreferenceStore store, String key) { + return key != null && store.getBoolean(key); + } + + protected boolean isPrefQuickDiffAlwaysOn() { + return false; // never show change ruler for the non-editable java + // editor. + // Overridden in subclasses like PHPUnitEditor + } + + /* + * @see org.eclipse.ui.texteditor.AbstractTextEditor#createNavigationActions() + */ + protected void createNavigationActions() { + super.createNavigationActions(); + + final StyledText textWidget = getSourceViewer().getTextWidget(); + + IAction action = new SmartLineStartAction(textWidget, false); + action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_START); + setAction(ITextEditorActionDefinitionIds.LINE_START, action); + + action = new SmartLineStartAction(textWidget, true); + action + .setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_LINE_START); + setAction(ITextEditorActionDefinitionIds.SELECT_LINE_START, action); + + action = new NavigatePreviousSubWordAction(); + action + .setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_PREVIOUS); + setAction(ITextEditorActionDefinitionIds.WORD_PREVIOUS, action); + textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_LEFT, SWT.NULL); + + action = new NavigateNextSubWordAction(); + action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_NEXT); + setAction(ITextEditorActionDefinitionIds.WORD_NEXT, action); + textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_RIGHT, SWT.NULL); + + action = new SelectPreviousSubWordAction(); + action + .setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS); + setAction(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, action); + textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_LEFT, + SWT.NULL); + + action = new SelectNextSubWordAction(); + action + .setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT); + setAction(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, action); + textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_RIGHT, + SWT.NULL); + } + + /* + * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createCompositeRuler() + */ + // protected CompositeRuler createCompositeRuler() { + // if + // (!getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER)) + // return super.createCompositeRuler(); + // + // CompositeRuler ruler = new CompositeRuler(); + // AnnotationRulerColumn column = new + // AnnotationRulerColumn(VERTICAL_RULER_WIDTH, getAnnotationAccess()); + // column.setHover(new JavaExpandHover(ruler, getAnnotationAccess(), new + // IDoubleClickListener() { + // + // public void doubleClick(DoubleClickEvent event) { + // // for now: just invoke ruler double click action + // triggerAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK); + // } + // + // private void triggerAction(String actionID) { + // IAction action = getAction(actionID); + // if (action != null) { + // if (action instanceof IUpdate) + // ((IUpdate) action).update(); + // // hack to propagate line change + // if (action instanceof ISelectionListener) { + // ((ISelectionListener) action).selectionChanged(null, null); + // } + // if (action.isEnabled()) + // action.run(); + // } + // } + // + // })); + // ruler.addDecorator(0, column); + // + // if (isLineNumberRulerVisible()) + // ruler.addDecorator(1, createLineNumberRulerColumn()); + // else if (isPrefQuickDiffAlwaysOn()) + // ruler.addDecorator(1, createChangeRulerColumn()); + // + // return ruler; + // } + /* + * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createAnnotationRulerColumn(org.eclipse.jface.text.source.CompositeRuler) + * @since 3.2 + */ + protected IVerticalRulerColumn createAnnotationRulerColumn( + CompositeRuler ruler) { + if (!getPreferenceStore().getBoolean( + PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER)) + return super.createAnnotationRulerColumn(ruler); + + AnnotationRulerColumn column = new AnnotationRulerColumn( + VERTICAL_RULER_WIDTH, getAnnotationAccess()); + column.setHover(new JavaExpandHover(ruler, getAnnotationAccess(), + new IDoubleClickListener() { + + public void doubleClick(DoubleClickEvent event) { + // for now: just invoke ruler double click action + triggerAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK); + } + + private void triggerAction(String actionID) { + IAction action = getAction(actionID); + if (action != null) { + if (action instanceof IUpdate) + ((IUpdate) action).update(); + // hack to propagate line change + if (action instanceof ISelectionListener) { + ((ISelectionListener) action).selectionChanged( + null, null); + } + if (action.isEnabled()) + action.run(); + } + } + + })); + + return column; + } + + /** + * Returns the folding action group, or null if there is + * none. + * + * @return the folding action group, or null if there is none + * @since 3.0 + */ + protected FoldingActionGroup getFoldingActionGroup() { + return fFoldingGroup; + } + + /* + * @see org.eclipse.ui.texteditor.AbstractTextEditor#performRevert() + */ + protected void performRevert() { + ProjectionViewer projectionViewer = (ProjectionViewer) getSourceViewer(); + projectionViewer.setRedraw(false); + try { + + boolean projectionMode = projectionViewer.isProjectionMode(); + if (projectionMode) { + projectionViewer.disableProjection(); + if (fProjectionModelUpdater != null) + fProjectionModelUpdater.uninstall(); + } + + super.performRevert(); + + if (projectionMode) { + if (fProjectionModelUpdater != null) + fProjectionModelUpdater.install(this, projectionViewer); + projectionViewer.enableProjection(); + } + + } finally { + projectionViewer.setRedraw(true); + } + } + + /** + * React to changed selection. + * + * @since 3.0 + */ + protected void selectionChanged() { + if (getSelectionProvider() == null) + return; + ISourceReference element = computeHighlightRangeSourceReference(); + if (getPreferenceStore().getBoolean( + PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE)) + synchronizeOutlinePage(element); + setSelection(element, false); + updateStatusLine(); + } + + private boolean isJavaOutlinePageActive() { + IWorkbenchPart part = getActivePart(); + return part instanceof ContentOutline + && ((ContentOutline) part).getCurrentPage() == fOutlinePage; + } + + private IWorkbenchPart getActivePart() { + IWorkbenchWindow window = getSite().getWorkbenchWindow(); + IPartService service = window.getPartService(); + IWorkbenchPart part = service.getActivePart(); + return part; + } + + /** + * Computes and returns the source reference that includes the caret and + * serves as provider for the outline page selection and the editor range + * indication. + * + * @return the computed source reference + * @since 3.0 + */ + protected ISourceReference computeHighlightRangeSourceReference() { + ISourceViewer sourceViewer = getSourceViewer(); + if (sourceViewer == null) + return null; + + StyledText styledText = sourceViewer.getTextWidget(); + if (styledText == null) + return null; + + int caret = 0; + if (sourceViewer instanceof ITextViewerExtension5) { + ITextViewerExtension5 extension = (ITextViewerExtension5) sourceViewer; + caret = extension.widgetOffset2ModelOffset(styledText + .getCaretOffset()); + } else { + int offset = sourceViewer.getVisibleRegion().getOffset(); + caret = offset + styledText.getCaretOffset(); + } + + IJavaElement element = getElementAt(caret, false); + + if (!(element instanceof ISourceReference)) + return null; + + if (element.getElementType() == IJavaElement.IMPORT_DECLARATION) { + + IImportDeclaration declaration = (IImportDeclaration) element; + IImportContainer container = (IImportContainer) declaration + .getParent(); + ISourceRange srcRange = null; + + try { + srcRange = container.getSourceRange(); + } catch (JavaModelException e) { + } + + if (srcRange != null && srcRange.getOffset() == caret) + return container; + } + + return (ISourceReference) element; + } + + /** + * Returns the most narrow java element including the given offset. + * + * @param offset + * the offset inside of the requested element + * @param reconcile + * true if editor input should be reconciled in + * advance + * @return the most narrow java element + * @since 3.0 + */ + protected IJavaElement getElementAt(int offset, boolean reconcile) { + return getElementAt(offset); + } + + public ShowInContext getShowInContext() { + FileEditorInput fei = (FileEditorInput) getEditorInput(); + ShowInContext context = BrowserUtil.getShowInContext(fei.getFile(), + false, ""); + if (context != null) { + return context; + } + return new ShowInContext(fei.getFile(), null); + } + + public String[] getShowInTargetIds() { + return new String[] { BrowserView.ID_BROWSER }; + } + + /** + * Updates the occurrences annotations based on the current selection. + * + * @param selection + * the text selection + * @param astRoot + * the compilation unit AST + * @since 3.0 + */ + protected void updateOccurrenceAnnotations(ITextSelection selection) {// , + // CompilationUnit + // astRoot) + // { + + if (fOccurrencesFinderJob != null) + fOccurrencesFinderJob.cancel(); + + if (!fMarkOccurrenceAnnotations) + return; + + // if (astRoot == null || selection == null) + if (selection == null) + return; + + IDocument document = getSourceViewer().getDocument(); + if (document == null) + return; + + fMarkOccurrenceTargetRegion = null; + if (document instanceof IDocumentExtension4) { + int offset = selection.getOffset(); + long currentModificationStamp = ((IDocumentExtension4) document) + .getModificationStamp(); + if (fMarkOccurrenceTargetRegion != null + && currentModificationStamp == fMarkOccurrenceModificationStamp) { + if (fMarkOccurrenceTargetRegion.getOffset() <= offset + && offset <= fMarkOccurrenceTargetRegion.getOffset() + + fMarkOccurrenceTargetRegion.getLength()) + return; + } + fMarkOccurrenceTargetRegion = JavaWordFinder.findWord(document, + offset); + fMarkOccurrenceModificationStamp = currentModificationStamp; + } + + if (fMarkOccurrenceTargetRegion == null + || fMarkOccurrenceTargetRegion.getLength() == 0) { + return; + } + + List matches = null; + + if (matches == null) { + try { + matches = new ArrayList(); + + Scanner fScanner = new Scanner(); + fScanner.setSource(document.get().toCharArray()); + fScanner.setPHPMode(false); + String wordStr; + char[] word; + + wordStr = document.get(fMarkOccurrenceTargetRegion.getOffset(), + fMarkOccurrenceTargetRegion.getLength()); + if (wordStr != null) { + word = wordStr.toCharArray(); + int fToken = ITerminalSymbols.TokenNameEOF; + try { + fToken = fScanner.getNextToken(); + while (fToken != ITerminalSymbols.TokenNameEOF) { // && + // fToken + // != + // TokenNameERROR) { + if (fToken == ITerminalSymbols.TokenNameVariable + || fToken == ITerminalSymbols.TokenNameIdentifier) { + // global variable + if (fScanner.equalsCurrentTokenSource(word)) { + matches + .add(new Region( + fScanner + .getCurrentTokenStartPosition(), + fScanner + .getCurrentTokenEndPosition() + - fScanner + .getCurrentTokenStartPosition() + + 1)); + } + } + fToken = fScanner.getNextToken(); + } + } catch (InvalidInputException e) { + // ignore errors + } catch (SyntaxError e) { + // ignore errors + } + } + } catch (BadLocationException e1) { + // ignore errors + } catch (Exception e) { + e.printStackTrace(); + // ignore errors + } + + } + + if (matches == null || matches.size() == 0) { + if (!fStickyOccurrenceAnnotations) + removeOccurrenceAnnotations(); + return; + } + + Position[] positions = new Position[matches.size()]; + int i = 0; + for (Iterator each = matches.iterator(); each.hasNext();) { + IRegion currentNode = (IRegion) each.next(); + positions[i++] = new Position(currentNode.getOffset(), currentNode + .getLength()); + } + + fOccurrencesFinderJob = new OccurrencesFinderJob(document, positions, + selection); + // fOccurrencesFinderJob.setPriority(Job.DECORATE); + // fOccurrencesFinderJob.setSystem(true); + // fOccurrencesFinderJob.schedule(); + fOccurrencesFinderJob.run(new NullProgressMonitor()); + } + + protected void installOccurrencesFinder() { + fMarkOccurrenceAnnotations = true; + + fPostSelectionListenerWithAST = new ISelectionListenerWithAST() { + public void selectionChanged(IEditorPart part, + ITextSelection selection) { // , + // CompilationUnit + // astRoot) + // { + updateOccurrenceAnnotations(selection);// , astRoot); + } + }; + SelectionListenerWithASTManager.getDefault().addListener(this, + fPostSelectionListenerWithAST); + if (getSelectionProvider() != null) { + fForcedMarkOccurrencesSelection = getSelectionProvider() + .getSelection(); + SelectionListenerWithASTManager.getDefault().forceSelectionChange( + this, (ITextSelection) fForcedMarkOccurrencesSelection); + } + + if (fOccurrencesFinderJobCanceler == null) { + fOccurrencesFinderJobCanceler = new OccurrencesFinderJobCanceler(); + fOccurrencesFinderJobCanceler.install(); + } + } + + protected void uninstallOccurrencesFinder() { + fMarkOccurrenceAnnotations = false; + + if (fOccurrencesFinderJob != null) { + fOccurrencesFinderJob.cancel(); + fOccurrencesFinderJob = null; + } + + if (fOccurrencesFinderJobCanceler != null) { + fOccurrencesFinderJobCanceler.uninstall(); + fOccurrencesFinderJobCanceler = null; + } + + if (fPostSelectionListenerWithAST != null) { + SelectionListenerWithASTManager.getDefault().removeListener(this, + fPostSelectionListenerWithAST); + fPostSelectionListenerWithAST = null; + } + + removeOccurrenceAnnotations(); + } + + protected boolean isMarkingOccurrences() { + return fMarkOccurrenceAnnotations; + } + + void removeOccurrenceAnnotations() { + fMarkOccurrenceModificationStamp = IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; + fMarkOccurrenceTargetRegion = null; + + IDocumentProvider documentProvider = getDocumentProvider(); + if (documentProvider == null) + return; + + IAnnotationModel annotationModel = documentProvider + .getAnnotationModel(getEditorInput()); + if (annotationModel == null || fOccurrenceAnnotations == null) + return; + + synchronized (getLockObject(annotationModel)) { + if (annotationModel instanceof IAnnotationModelExtension) { + ((IAnnotationModelExtension) annotationModel) + .replaceAnnotations(fOccurrenceAnnotations, null); + } else { + for (int i = 0, length = fOccurrenceAnnotations.length; i < length; i++) + annotationModel.removeAnnotation(fOccurrenceAnnotations[i]); + } + fOccurrenceAnnotations = null; + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/phpeditor/PHPTextHover.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/phpeditor/PHPTextHover.java new file mode 100644 index 0000000..08c077e --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/phpeditor/PHPTextHover.java @@ -0,0 +1,151 @@ +/********************************************************************** + Copyright (c) 2000, 2002 IBM Corp. and others. + All rights reserved. This program and the accompanying materials + are made available under the terms of the Common Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/cpl-v10.html + + Contributors: + IBM Corporation - Initial implementation + www.phpeclipse.de + **********************************************************************/ +package net.sourceforge.phpeclipse.phpeditor; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import net.sourceforge.phpdt.internal.corext.phpdoc.PHPDocUtil; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; +import net.sourceforge.phpeclipse.builder.IdentifierIndexManager; +import net.sourceforge.phpeclipse.builder.PHPIdentifierLocation; +import net.sourceforge.phpeclipse.phpeditor.php.PHPElement; +import net.sourceforge.phpeclipse.phpeditor.php.PHPFunction; +import net.sourceforge.phpeclipse.phpeditor.php.PHPWordExtractor; + +import org.eclipse.core.resources.IProject; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; +import org.eclipse.swt.graphics.Point; + +/** + * Implementation for an ITextHover which hovers over PHP code. + */ +public class PHPTextHover implements ITextHover { + private static HashMap functionDescriptions = null; + + private static HashMap identDescriptions = null; + + /** + * The current project; maybe null for preference pages + */ + private IProject fProject; + + public PHPTextHover(IProject project) { + fProject = project; + } + + /* + * (non-Javadoc) Method declared on ITextHover + */ + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + if (hoverRegion != null) { + try { + if (hoverRegion.getLength() > -1) { + String word = textViewer.getDocument().get( + hoverRegion.getOffset(), hoverRegion.getLength()); + if (functionDescriptions == null) { + functionDescriptions = new HashMap(); + identDescriptions = new HashMap(); + ArrayList syntaxbuffer = PHPSyntaxRdr.getSyntaxData(); + PHPElement elbuffer = null; + if (syntaxbuffer != null) { + for (int i = 0; i < syntaxbuffer.size(); i++) { + elbuffer = (PHPElement) syntaxbuffer.get(i); + if (elbuffer instanceof PHPFunction) { + functionDescriptions.put( + elbuffer.getName(), elbuffer + .getHoverText()); + } else { + identDescriptions.put(elbuffer.getName(), + elbuffer.getHoverText()); + } + } + } + // + // while ((syntaxbuffer != null) + // && (!syntaxbuffer.isEmpty() && ((elbuffer = + // (PHPElement) + // syntaxbuffer.remove(0)) != null))) { + // functionDescriptions.put(elbuffer.getName(), + // elbuffer.getHoverText()); + // } + } + String hoverInfo = (String) identDescriptions.get(word); + if (hoverInfo == null & word.length() > 0) { + hoverInfo = (String) functionDescriptions.get(word + .toLowerCase()); + } + if (hoverInfo == null && fProject != null) { + // get the possible PHPDoc information from the index + // file + IdentifierIndexManager indexManager = PHPeclipsePlugin + .getDefault().getIndexManager(fProject); + List list = indexManager.getLocations(word); + if (list.size() > 0) { + try { + PHPIdentifierLocation location; + String filename; + StringBuffer hoverInfoBuffer = new StringBuffer(); + String workspaceLocation; + if (fProject != null) { + workspaceLocation = fProject.getLocation() + .toString() + '/'; + } else { + // should never happen? + workspaceLocation = PHPeclipsePlugin + .getWorkspace().getRoot() + .getLocation().toString(); + } + // boolean foundPHPdoc = false; + for (int i = 0; i < list.size(); i++) { + location = (PHPIdentifierLocation) list + .get(i); + filename = workspaceLocation + + location.getFilename(); + PHPDocUtil.appendPHPDoc(hoverInfoBuffer, + filename, location); + } + hoverInfo = hoverInfoBuffer.toString(); + } catch (Throwable e) { + // ignore exceptions + // e.printStackTrace(); + } + } + } + return hoverInfo; + } + // } catch (BadLocationException x) { + } catch (Exception x) { + } + } + return null; + // don't show this annoying text + // return "empty selection"; + } + + /* + * (non-Javadoc) Method declared on ITextHover + */ + public IRegion getHoverRegion(ITextViewer textViewer, int offset) { + Point selection = PHPWordExtractor.findWord(textViewer.getDocument(), + offset); + // show the extracted word as a tooltip + if (selection != null && selection.x <= offset + && offset < selection.x + selection.y) + return new Region(selection.x, selection.y); + return new Region(offset, 0); + } +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/ui/WebUI.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/ui/WebUI.java new file mode 100644 index 0000000..8404335 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/ui/WebUI.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2004 Christopher Lenz and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Christopher Lenz - initial implementation + * + * $Id: WebUI.java,v 1.7 2006-10-21 23:13:54 pombredanne Exp $ + */ + +package net.sourceforge.phpeclipse.ui; + +import java.io.IOException; +import java.net.URL; + +import net.sourceforge.phpeclipse.ui.templates.template.HTMLContextType; +import net.sourceforge.phpeclipse.ui.templates.template.JSContextType; +import net.sourceforge.phpeclipse.ui.templates.template.SmartyContextType; +import net.sourceforge.phpeclipse.ui.templates.template.XMLContextType; + +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.jface.text.templates.ContextTypeRegistry; +import org.eclipse.jface.text.templates.persistence.TemplateStore; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.editors.text.templates.ContributionContextTypeRegistry; +import org.eclipse.ui.editors.text.templates.ContributionTemplateStore; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +/** + * The web development tools UI plugin. + */ +public class WebUI extends AbstractUIPlugin implements IPreferenceConstants { + private static final String CUSTOM_TEMPLATES_KEY = "net.sourceforge.phpeclipse.ui.templates"; //$NON-NLS-1$ + + // Constants --------------------------------------------------------------- + + public static final String ICON_OVERLAY_ERROR = "full/ovr16/error_co.gif"; //$NON-NLS-1$ + + public static final String ICON_OVERLAY_WARNING = "full/ovr16/warning_co.gif"; //$NON-NLS-1$ + + // Instance Variables ------------------------------------------------------ + + /** The shared instance. */ + private static WebUI plugin; + + public static IWorkbenchPage getActivePage() { + return getDefault().internalGetActivePage(); + } + + private IWorkbenchPage internalGetActivePage() { + return getWorkbench().getActiveWorkbenchWindow().getActivePage(); + } + + public static Shell getActiveWorkbenchShell() { + return getActiveWorkbenchWindow().getShell(); + } + + public static IWorkbenchWindow getActiveWorkbenchWindow() { + return getDefault().getWorkbench().getActiveWorkbenchWindow(); + } + + // Public Methods ---------------------------------------------------------- + + /** + * Returns the shared instance. + */ + public static WebUI getDefault() { + return plugin; + } + + /** + * Returns the workspace instance. + */ + public static IWorkspace getWorkspace() { + return ResourcesPlugin.getWorkspace(); + } + + /** The context type registry. */ + private ContributionContextTypeRegistry fRegistry; + + /** The template store. */ + private TemplateStore fStore; + + // Constructors ------------------------------------------------------------ + + /** + * The constructor. + */ + public WebUI() { + plugin = this; + } + + /** + * Returns this plug-in's context type registry. + * + * @return the context type registry for this plug-in instance + */ + public ContextTypeRegistry getContextTypeRegistry() { + if (fRegistry == null) { + // create an configure the contexts available in the editor + fRegistry = new ContributionContextTypeRegistry(); + fRegistry.addContextType(XMLContextType.XML_CONTEXT_TYPE); + fRegistry.addContextType(HTMLContextType.HTML_CONTEXT_TYPE); + fRegistry.addContextType(SmartyContextType.SMARTY_CONTEXT_TYPE); + fRegistry.addContextType(JSContextType.JS_CONTEXT_TYPE); + } + return fRegistry; + } + + // Private Methods --------------------------------------------------------- + + /** + * Returns an image descriptor for the image corresponding to the specified + * key (which is the name of the image file). + * + * @param key + * The key of the image + * @return The descriptor for the requested image, or null if + * the image could not be found + */ + private ImageDescriptor getImageDescriptor(String key) { + try { + URL url = getBundle().getEntry("/icons/" + key); //$NON-NLS-1$ + return ImageDescriptor.createFromURL(url); + } catch (IllegalStateException e) { + return null; + } + } + + /** + * Returns this plug-in's template store. + * + * @return the template store of this plug-in instance + */ + public TemplateStore getTemplateStore() { + if (fStore == null) { + fStore = new ContributionTemplateStore(getContextTypeRegistry(), + getDefault().getPreferenceStore(), CUSTOM_TEMPLATES_KEY); + try { + fStore.load(); + } catch (IOException e) { + WebUI + .getDefault() + .getLog() + .log( + new Status( + IStatus.ERROR, + "net.sourceforge.phpeclipse.ui", IStatus.OK, "", e)); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + return fStore; + } + + protected void initializeDefaultPreferences(IPreferenceStore store) { + store.setDefault(PHP_LOCALHOST_PREF, "http://localhost"); + store.setDefault(PHP_DOCUMENTROOT_PREF, getWorkspace().getRoot() + .getLocation().toString()); + // store.setDefault(PHP_BOOKMARK_DEFAULT, ""); + + store.setDefault(PHP_AUTO_PREVIEW_DEFAULT, "true"); + store.setDefault(PHP_BRING_TO_TOP_PREVIEW_DEFAULT, "true"); + // store.setDefault(PHP_SHOW_HTML_FILES_LOCAL, "true"); + // store.setDefault(PHP_SHOW_XML_FILES_LOCAL, "false"); + } + + /* + * @see AbstractUIPlugin#initializeImageRegistry(ImageRegistry) + */ + protected void initializeImageRegistry(ImageRegistry reg) { + reg.put(ICON_OVERLAY_ERROR, getImageDescriptor(ICON_OVERLAY_ERROR)); + reg.put(ICON_OVERLAY_WARNING, getImageDescriptor(ICON_OVERLAY_WARNING)); + } + // private IWorkbenchPage internalGetActivePage() { + // IWorkbenchWindow window = getWorkbench().getActiveWorkbenchWindow(); + // if (window != null) + // return window.getActivePage(); + // return null; + // } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/ui/editor/ShowExternalPreviewAction.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/ui/editor/ShowExternalPreviewAction.java new file mode 100644 index 0000000..abe117e --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/ui/editor/ShowExternalPreviewAction.java @@ -0,0 +1,129 @@ +package net.sourceforge.phpeclipse.ui.editor; + +import net.sourceforge.phpeclipse.ui.IPreferenceConstants; +import net.sourceforge.phpeclipse.ui.WebUI; +import net.sourceforge.phpeclipse.ui.overlaypages.ProjectPrefUtil; +import net.sourceforge.phpeclipse.webbrowser.views.BrowserView; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.ui.texteditor.TextEditorAction; + +/** + * ClassDeclaration that defines the action for parsing the current PHP file + */ +public class ShowExternalPreviewAction extends TextEditorAction { + public final static int XML_TYPE = 1; + + public final static int HTML_TYPE = 2; + + public final static int SMARTY_TYPE = 3; + + public final static int PHP_TYPE = 4; + + private static ShowExternalPreviewAction instance = new ShowExternalPreviewAction(); + + /** + * Constructs and updates the action. + */ + private ShowExternalPreviewAction() { + super(EditorMessages.getResourceBundle(), "ParserAction.", null); //$NON-NLS-1$ + update(); + } + + public static ShowExternalPreviewAction getInstance() { + return instance; + } + + /** + * Code called when the action is fired. + */ + public void run() { + doRun(PHP_TYPE); + } + + public void doRun(int type) { + IFile previewFile = getFile(); + BrowserUtil.showPreview(previewFile, false, ""); + } + + public void refresh(int type) { + IFile fileToParse = getFile(); + if (fileToParse == null) { + // should never happen + return; + } + boolean autoPreview = ProjectPrefUtil.getPreviewBooleanValue( + fileToParse, IPreferenceConstants.PHP_AUTO_PREVIEW_DEFAULT); + boolean bringToTopPreview = ProjectPrefUtil.getPreviewBooleanValue( + fileToParse, + IPreferenceConstants.PHP_BRING_TO_TOP_PREVIEW_DEFAULT); + + if (autoPreview) { + IWorkbenchPage page = WebUI.getActivePage(); + try { + IViewPart part = page.findView(BrowserView.ID_BROWSER); + if (part == null) { + part = page.showView(BrowserView.ID_BROWSER); + } else { + if (bringToTopPreview) { + page.bringToTop(part); + } + } + if (part != null) { + ((BrowserView) part).refresh(); + } + } catch (Exception e) { + // PHPeclipsePlugin.log(e); + } + } + } + + /** + * Finds the file that's currently opened in the PHP Text Editor + */ + protected IFile getFile() { + ITextEditor editor = getTextEditor(); + IEditorInput editorInput = null; + if (editor != null) { + editorInput = editor.getEditorInput(); + } + if (editorInput instanceof IFileEditorInput) + return ((IFileEditorInput) editorInput).getFile(); + // if nothing was found, which should never happen + return null; + } + + public static String getLocalhostURL(IPreferenceStore store, IFile file) { + if (file != null) { + if (store == null) { + store = WebUI.getDefault().getPreferenceStore(); + } + // IPath path = file.getFullPath(); + String localhostURL = file.getLocation().toString(); + String lowerCaseFileName = localhostURL.toLowerCase(); + // String documentRoot = + // store.getString(PHPeclipsePlugin.DOCUMENTROOT_PREF); + IPath documentRootPath = ProjectPrefUtil.getDocumentRoot(file + .getProject()); + String documentRoot = documentRootPath.toString().toLowerCase(); + if (lowerCaseFileName.startsWith(documentRoot)) { + localhostURL = localhostURL.substring(documentRoot.length()); + } else { + return null; + } + // return store.getString(PHPeclipsePlugin.LOCALHOST_PREF) + + // localhostURL; + return ProjectPrefUtil.getMiscProjectsPreferenceValue(file + .getProject(), IPreferenceConstants.PHP_LOCALHOST_PREF) + + localhostURL; + } + return "http://localhost"; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/internal/OpenWithBrowserActionDelegate.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/internal/OpenWithBrowserActionDelegate.java new file mode 100644 index 0000000..18cdc65 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/internal/OpenWithBrowserActionDelegate.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2003 IBM Corporation and others. + * All rights reserved. � This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + �* + * Contributors: + * IBM - Initial API and implementation + */ +package net.sourceforge.phpeclipse.webbrowser.internal; + +import java.net.URL; +import java.util.Iterator; + +import net.sourceforge.phpeclipse.webbrowser.WebBrowser; +import net.sourceforge.phpeclipse.webbrowser.WebBrowserEditorInput; + +import org.eclipse.core.resources.IResource; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.IActionDelegate; + +/** + * Action to open the Web broswer on a resource. + */ +public class OpenWithBrowserActionDelegate implements IActionDelegate { + private IResource resource; + + /** + * OpenBrowserAction constructor comment. + */ + public OpenWithBrowserActionDelegate() { + super(); + } + + /** + * Performs this action. + *

+ * This method is called when the delegating action has been triggered. + * Implement this method to do the actual work. + *

+ * + * @param action + * the action proxy that handles the presentation portion of the + * action + */ + public void run(IAction action) { + URL url = null; + try { + url = new URL("file://" + resource.getLocation()); + WebBrowser.openURL(new WebBrowserEditorInput(url, + WebBrowserEditorInput.SHOW_ALL + | WebBrowserEditorInput.FORCE_NEW_PAGE)); + } catch (Exception e) { + Trace.trace(Trace.SEVERE, "Error opening browser on file", e); + } + } + + /** + * Notifies this action delegate that the selection in the workbench has + * changed. + *

+ * Implementers can use this opportunity to change the availability of the + * action or to modify other presentation properties. + *

+ * + * @param action + * the action proxy that handles presentation portion of the + * action + * @param selection + * the current selection in the workbench + */ + public void selectionChanged(IAction action, ISelection sel) { + if (sel.isEmpty() || !(sel instanceof IStructuredSelection)) { + action.setEnabled(false); + return; + } + + IStructuredSelection select = (IStructuredSelection) sel; + Iterator iterator = select.iterator(); + Object selection = iterator.next(); + if (iterator.hasNext()) { // more than one selection (should never + // happen) + action.setEnabled(false); + return; + } + + if (!(selection instanceof IResource)) { + action.setEnabled(false); + return; + } + + resource = (IResource) selection; + action.setEnabled(true); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/internal/WebBrowserEditor.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/internal/WebBrowserEditor.java new file mode 100644 index 0000000..f266e11 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/internal/WebBrowserEditor.java @@ -0,0 +1,404 @@ +/** + * Copyright (c) 2003 IBM Corporation and others. + * All rights reserved. � This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + �* + * Contributors: + * IBM - Initial API and implementation + */ +package net.sourceforge.phpeclipse.webbrowser.internal; + +import java.net.URL; + +import net.sourceforge.phpeclipse.webbrowser.IWebBrowserEditorInput; +import net.sourceforge.phpeclipse.webbrowser.WebBrowserEditorInput; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.part.EditorPart; + +/** + * An integrated Web browser, defined as an editor to make better use of the + * desktop. + */ +public class WebBrowserEditor extends EditorPart { + public static final String WEB_BROWSER_EDITOR_ID = "net.sourceforge.phpeclipse.webbrowser"; + + protected WebBrowser webBrowser; + + protected String initialURL; + + protected Image image; + + protected TextAction cutAction; + + protected TextAction copyAction; + + protected TextAction pasteAction; + + protected IResourceChangeListener resourceListener; + + /** + * WebBrowserEditor constructor comment. + */ + public WebBrowserEditor() { + super(); + } + + /** + * Creates the SWT controls for this workbench part. + *

+ * Clients should not call this method (the workbench calls this method at + * appropriate times). + *

+ *

+ * For implementors this is a multi-step process: + *

    + *
  1. Create one or more controls within the parent.
  2. + *
  3. Set the parent layout as needed.
  4. + *
  5. Register any global actions with the IActionService.
  6. + *
  7. Register any popup menus with the IActionService.
  8. + *
  9. Register a selection provider with the + * ISelectionService (optional).
  10. + *
+ *

+ * + * @param parent + * the parent control + */ + public void createPartControl(Composite parent) { + IWebBrowserEditorInput input = getWebBrowserEditorInput(); + + if (input == null || input.isToolbarVisible() == false) + webBrowser = new WebBrowser(parent, false, input + .isStatusbarVisible()); + else { + webBrowser = new WebBrowser(parent, true, input + .isStatusbarVisible()); + cutAction = new TextAction(webBrowser, TextAction.CUT); + copyAction = new TextAction(webBrowser, TextAction.COPY); + pasteAction = new TextAction(webBrowser, TextAction.PASTE); + } + + webBrowser.setURL(initialURL); + webBrowser.editor = this; + } + + public void dispose() { + if (image != null && !image.isDisposed()) + image.dispose(); + image = null; + + if (resourceListener != null) + ResourcesPlugin.getWorkspace().removeResourceChangeListener( + resourceListener); + } + + /* + * (non-Javadoc) Saves the contents of this editor.

Subclasses must + * override this method to implement the open-save-close lifecycle for an + * editor. For greater details, see IEditorPart

+ * + * @see IEditorPart + */ + public void doSave(IProgressMonitor monitor) { + } + + /* + * (non-Javadoc) Saves the contents of this editor to another object.

+ * Subclasses must override this method to implement the open-save-close + * lifecycle for an editor. For greater details, see IEditorPart + *

+ * + * @see IEditorPart + */ + public void doSaveAs() { + } + + /** + * Returns the copy action. + * + * @return org.eclipse.jface.action.IAction + */ + public IAction getCopyAction() { + return copyAction; + } + + /** + * Returns the cut action. + * + * @return org.eclipse.jface.action.IAction + */ + public IAction getCutAction() { + return cutAction; + } + + /** + * Returns the paste action. + * + * @return org.eclipse.jface.action.IAction + */ + public IAction getPasteAction() { + return pasteAction; + } + + /** + * Returns the web editor input, if available. + * + * @return net.sourceforge.phpeclipse.webbrowser.IWebBrowserEditorInput + */ + protected IWebBrowserEditorInput getWebBrowserEditorInput() { + IEditorInput input = getEditorInput(); + if (input instanceof IWebBrowserEditorInput) + return (IWebBrowserEditorInput) input; + return null; + } + + /* + * (non-Javadoc) Sets the cursor and selection state for this editor to the + * passage defined by the given marker.

Subclasses may override. For + * greater details, see IEditorPart

+ * + * @see IEditorPart + */ + public void gotoMarker(IMarker marker) { + } + + /* + * (non-Javadoc) Initializes the editor part with a site and input.

+ * Subclasses of EditorPart must implement this method. + * Within the implementation subclasses should verify that the input type is + * acceptable and then save the site and input. Here is sample code:

+ *
 if (!(input instanceof IFileEditorInput)) throw new
+	 * PartInitException("Invalid Input: Must be IFileEditorInput");
+	 * setSite(site); setInput(editorInput); 
+ */ + public void init(IEditorSite site, IEditorInput input) { + Trace.trace(Trace.FINEST, "Opening browser: " + input); + if (input instanceof IFileEditorInput) { + IFileEditorInput fei = (IFileEditorInput) input; + IFile file = fei.getFile(); + URL url = null; + try { + if (file != null && file.exists()) + url = file.getLocation().toFile().toURL(); + } catch (Exception e) { + Trace.trace(Trace.SEVERE, "Error getting URL to file"); + } + addResourceListener(file); + input = new WebBrowserEditorInput(url, + WebBrowserEditorInput.SHOW_ALL + | WebBrowserEditorInput.SAVE_URL); + } + if (input instanceof IWebBrowserEditorInput) { + IWebBrowserEditorInput wbei = (IWebBrowserEditorInput) input; + initialURL = null; + if (wbei.getURL() != null) + initialURL = wbei.getURL().toExternalForm(); + if (webBrowser != null) { + webBrowser.setURL(initialURL); + site.getWorkbenchWindow().getActivePage().bringToTop(this); + } + + setPartName(wbei.getName()); + setTitleToolTip(wbei.getToolTipText()); + + Image oldImage = image; + ImageDescriptor id = wbei.getImageDescriptor(); + image = id.createImage(); + + setTitleImage(image); + if (oldImage != null && !oldImage.isDisposed()) + oldImage.dispose(); + } + setSite(site); + setInput(input); + } + + /* + * (non-Javadoc) Returns whether the contents of this editor have changed + * since the last save operation.

Subclasses must override this method + * to implement the open-save-close lifecycle for an editor. For greater + * details, see IEditorPart

+ * + * @see IEditorPart + */ + public boolean isDirty() { + return false; + } + + /* + * (non-Javadoc) Returns whether the "save as" operation is supported by + * this editor.

Subclasses must override this method to implement the + * open-save-close lifecycle for an editor. For greater details, see IEditorPart + *

+ * + * @see IEditorPart + */ + public boolean isSaveAsAllowed() { + return false; + } + + /** + * Returns true if this editor has a toolbar. + * + * @return boolean + */ + public boolean isToolbarVisible() { + IWebBrowserEditorInput input = getWebBrowserEditorInput(); + if (input == null || input.isToolbarVisible()) + return true; + else + return false; + } + + /** + * Open the input in the internal Web browser. + */ + public static void open(IWebBrowserEditorInput input) { + IWorkbenchWindow workbenchWindow = WebBrowserUIPlugin.getInstance() + .getWorkbench().getActiveWorkbenchWindow(); + IWorkbenchPage page = workbenchWindow.getActivePage(); + + try { + IEditorReference[] editors = page.getEditorReferences(); + int size = editors.length; + for (int i = 0; i < size; i++) { + if (WEB_BROWSER_EDITOR_ID.equals(editors[i].getId())) { + IEditorPart editor = editors[i].getEditor(true); + if (editor != null && editor instanceof WebBrowserEditor) { + WebBrowserEditor webEditor = (WebBrowserEditor) editor; + if (input.canReplaceInput(webEditor + .getWebBrowserEditorInput())) { + editor.init(editor.getEditorSite(), input); + return; + } + } + } + } + + page.openEditor(input, WebBrowserEditor.WEB_BROWSER_EDITOR_ID); + } catch (Exception e) { + Trace.trace(Trace.SEVERE, "Error opening Web browser", e); + } + } + + /** + * Asks this part to take focus within the workbench. + *

+ * Clients should not call this method (the workbench calls this method at + * appropriate times). + *

+ */ + public void setFocus() { + if (webBrowser != null) { + if (webBrowser.combo != null) + webBrowser.combo.setFocus(); + else + webBrowser.browser.setFocus(); + webBrowser.updateHistory(); + } + } + + /** + * Update the actions. + */ + protected void updateActions() { + if (cutAction != null) + cutAction.update(); + if (copyAction != null) + copyAction.update(); + if (pasteAction != null) + pasteAction.update(); + } + + /** + * Close the editor correctly. + */ + protected void closeEditor() { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + getEditorSite().getPage().closeEditor(WebBrowserEditor.this, + false); + } + }); + } + + /** + * Adds a resource change listener to see if the file is deleted. + */ + protected void addResourceListener(final IResource resource) { + if (resource == null) + return; + + resourceListener = new IResourceChangeListener() { + public void resourceChanged(IResourceChangeEvent event) { + try { + event.getDelta().accept(new IResourceDeltaVisitor() { + public boolean visit(IResourceDelta delta) { + IResource res = delta.getResource(); + + if (res == null || !res.equals(resource)) + return true; + + if (delta.getKind() != IResourceDelta.REMOVED) + return true; + + Display.getDefault().asyncExec(new Runnable() { + public void run() { + String title = WebBrowserUIPlugin + .getResource("%dialogResourceDeletedTitle"); + String message = WebBrowserUIPlugin + .getResource( + "%dialogResourceDeletedMessage", + resource.getName()); + String[] labels = new String[] { + WebBrowserUIPlugin + .getResource("%dialogResourceDeletedIgnore"), + IDialogConstants.CLOSE_LABEL }; + MessageDialog dialog = new MessageDialog( + getEditorSite().getShell(), title, + null, message, + MessageDialog.INFORMATION, labels, + 0); + + if (dialog.open() != 0) + closeEditor(); + } + }); + return false; + } + }); + } catch (Exception e) { + Trace.trace(Trace.SEVERE, + "Error listening for resource deletion", e); + } + } + }; + ResourcesPlugin.getWorkspace().addResourceChangeListener( + resourceListener); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/views/BrowserView.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/views/BrowserView.java new file mode 100644 index 0000000..92face4 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/webbrowser/views/BrowserView.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package net.sourceforge.phpeclipse.webbrowser.views; + +import net.sourceforge.phpeclipse.webbrowser.internal.WebBrowser; +import net.sourceforge.phpeclipse.webbrowser.internal.WebBrowserUtil; + +import org.eclipse.core.resources.IFile; +import org.eclipse.swt.browser.ProgressListener; +import org.eclipse.swt.browser.StatusTextListener; +import org.eclipse.swt.browser.TitleListener; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.part.IShowInTarget; +import org.eclipse.ui.part.ShowInContext; +import org.eclipse.ui.part.ViewPart; + +/** + * BrowserView is a simple demonstration of the SWT Browser + * widget. It consists of a workbench view and tab folder where each tab in the + * folder allows the user to interact with a control. + * + * @see ViewPart + */ +public class BrowserView extends ViewPart implements IShowInTarget { + public final static String ID_BROWSER = "net.sourceforge.phpeclipse.webbrowser.views"; + + WebBrowser fInstance = null; + + String fUrl = null; + + /** + * Create the example + * + * @see ViewPart#createPartControl + */ + public void createPartControl(Composite frame) { + try { + if (WebBrowserUtil.isInternalBrowserOperational()) { + fInstance = new WebBrowser(frame, true, true); + } + } catch (Exception e) { + fInstance = null; + } + } + + /** + * Called when we must grab focus. + * + * @see org.eclipse.ui.part.ViewPart#setFocus + */ + public void setFocus() { + if (fInstance != null) { + fInstance.setFocus(); + } + } + + /** + * Called when the View is to be disposed + */ + public void dispose() { + if (fInstance != null) { + fInstance.dispose(); + fInstance = null; + } + super.dispose(); + } + + public void setUrl(final String url) { + if (fInstance != null) { + fUrl = url; + fInstance.setURL(url); + // try { + // ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { + // public void run(IProgressMonitor monitor) throws CoreException { + // instance.setURL(url); + // } + // }, null); + // } catch (CoreException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + } + } + + public void refresh() { + if (fInstance != null) { + fInstance.refresh(); + // try { + // ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { + // public void run(IProgressMonitor monitor) throws CoreException { + // instance.refresh(); + // } + // }, null); + // } catch (CoreException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + } + } + + public void refresh(String url) { + if (fInstance != null) { + if (fUrl == null || !fUrl.equals(url)) { + setUrl(url); + } else { + refresh(); + } + } + } + + public void addProgressListener(ProgressListener listener) { + if (fInstance != null) { + fInstance.addProgressListener(listener); + } + } + + public void addStatusTextListener(StatusTextListener listener) { + if (fInstance != null) { + fInstance.addStatusTextListener(listener); + } + } + + public void addTitleListener(TitleListener listener) { + if (fInstance != null) { + fInstance.addTitleListener(listener); + } + } + + public boolean show(ShowInContext context) { + if (context instanceof ShowInContextBrowser) { + ShowInContextBrowser contextBrowser = (ShowInContextBrowser) context; + String localhostURL = contextBrowser.getLocalhostUrl(); + if (localhostURL != null) { + setUrl(localhostURL); + return true; + } + } + if (context.getInput() instanceof IFile) { + IFile file = (IFile) context.getInput(); + String localhostURL; + localhostURL = "file:///" + file.getLocation().toString(); + setUrl(localhostURL); + return true; + } + return false; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/wizards/NewProjectCreationWizard.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/wizards/NewProjectCreationWizard.java new file mode 100644 index 0000000..0601e03 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/wizards/NewProjectCreationWizard.java @@ -0,0 +1,119 @@ +package net.sourceforge.phpeclipse.wizards; + +import java.lang.reflect.InvocationTargetException; + +import net.sourceforge.phpdt.core.JavaCore; +import net.sourceforge.phpdt.ui.actions.OpenPHPPerspectiveAction; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExecutableExtension; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.ui.INewWizard; +import org.eclipse.ui.actions.WorkspaceModifyDelegatingOperation; +import org.eclipse.ui.dialogs.WizardNewProjectCreationPage; +import org.eclipse.ui.wizards.newresource.BasicNewProjectResourceWizard; +import org.eclipse.ui.wizards.newresource.BasicNewResourceWizard; + +public class NewProjectCreationWizard extends BasicNewResourceWizard implements + INewWizard, IExecutableExtension { + protected WizardNewProjectCreationPage projectPage; + + protected IConfigurationElement configurationElement; + + protected IProject newProject; + + public NewProjectCreationWizard() { + setWindowTitle(PHPWizardMessages + .getString("NewProjectCreationWizard.windowTitle")); + } + + public boolean performFinish() { + IRunnableWithProgress projectCreationOperation = new WorkspaceModifyDelegatingOperation( + getProjectCreationRunnable()); + + try { + getContainer().run(false, true, projectCreationOperation); + } catch (Exception e) { + PHPeclipsePlugin.log(e); + return false; + } + + BasicNewProjectResourceWizard.updatePerspective(configurationElement); + selectAndReveal(newProject); + // open the PHP perspective + new OpenPHPPerspectiveAction().run(); + return true; + } + + protected IRunnableWithProgress getProjectCreationRunnable() { + return new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) + throws InvocationTargetException, InterruptedException { + int remainingWorkUnits = 10; + monitor + .beginTask( + PHPWizardMessages + .getString("NewProjectCreationWizard.projectCreationMessage"), + remainingWorkUnits); + + IWorkspace workspace = PHPeclipsePlugin.getWorkspace(); + newProject = projectPage.getProjectHandle(); + + IProjectDescription description = workspace + .newProjectDescription(newProject.getName()); + IPath path = Platform.getLocation(); + IPath customPath = projectPage.getLocationPath(); + if (!path.equals(customPath)) { + path = customPath; + description.setLocation(path); + } + + try { + if (!newProject.exists()) { + newProject.create(description, new SubProgressMonitor( + monitor, 1)); + remainingWorkUnits--; + } + if (!newProject.isOpen()) { + newProject.open(new SubProgressMonitor(monitor, 1)); + remainingWorkUnits--; + } + JavaCore.addPHPNature(newProject, new SubProgressMonitor( + monitor, remainingWorkUnits)); + } catch (CoreException e) { + throw new InvocationTargetException(e); + } finally { + monitor.done(); + } + } + }; + } + + public void addPages() { + super.addPages(); + + projectPage = new WizardNewProjectCreationPage(PHPWizardMessages + .getString("WizardNewProjectCreationPage.pageName")); + projectPage.setTitle(PHPWizardMessages + .getString("WizardNewProjectCreationPage.pageTitle")); + projectPage.setDescription(PHPWizardMessages + .getString("WizardNewProjectCreationPage.pageDescription")); + + addPage(projectPage); + } + + public void setInitializationData(IConfigurationElement config, + String propertyName, Object data) throws CoreException { + configurationElement = config; + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPLaunchConfigurationDelegate.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPLaunchConfigurationDelegate.java new file mode 100644 index 0000000..5880ca0 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPLaunchConfigurationDelegate.java @@ -0,0 +1,155 @@ +/********************************************************************** + Copyright (c) 2000, 2002 IBM Corp. and others. + All rights reserved. This program and the accompanying materials + are made available under the terms of the Common Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/cpl-v10.html + + Contributors: + IBM Corporation - Initial implementation + Vicente Fernando - www.alfersoft.com.ar + **********************************************************************/ +package net.sourceforge.phpeclipse.xdebug.php.launching; + +import java.io.File; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import net.sourceforge.phpeclipse.xdebug.core.IXDebugPreferenceConstants; +import net.sourceforge.phpeclipse.xdebug.core.XDebugCorePlugin; +import net.sourceforge.phpeclipse.xdebug.php.model.XDebugTarget; + +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.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.ILaunchConfigurationDelegate; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.core.model.LaunchConfigurationDelegate; + +public class PHPLaunchConfigurationDelegate extends LaunchConfigurationDelegate { + + /** + * @see ILaunchConfigurationDelegate#launch(ILaunchConfiguration, String, + * ILaunch, IProgressMonitor) + */ + public void launch(ILaunchConfiguration configuration, String mode, + ILaunch launch, IProgressMonitor monitor) throws CoreException { + List commandList = new ArrayList(); + + String phpInterpreter = configuration.getAttribute( + IXDebugConstants.ATTR_PHP_INTERPRETER, (String) null); + boolean useDefaultInterpreter = configuration.getAttribute( + IXDebugConstants.ATTR_PHP_DEFAULT_INTERPRETER, true); + + if (useDefaultInterpreter) + phpInterpreter = XDebugCorePlugin + .getDefault() + .getPreferenceStore() + .getString( + IXDebugPreferenceConstants.PHP_INTERPRETER_PREFERENCE); + + File exe = new File(phpInterpreter); + // Just to get sure that the interpreter exists + if (!exe.exists()) { + abort( + MessageFormat + .format( + "Specified PHP executable {0} does not exist. Check value of PHP-Interpreter.", + new String[] { phpInterpreter }), null); + } + commandList.add(phpInterpreter); + + // Project name + String projectName = configuration.getAttribute( + IXDebugConstants.ATTR_PHP_PROJECT, (String) null); + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject( + projectName); + // Just to get sure that the project exists + if (project == null) { + abort("Project does not exist.", null); + } + String fileName = configuration.getAttribute( + IXDebugConstants.ATTR_PHP_FILE, (String) null); + + IFile file = project.getFile(fileName); + // Just to get sure that the script exists + if (!file.exists()) { + abort(MessageFormat.format("PHP-Script {0} does not exist.", + new String[] { file.getFullPath().toString() }), null); + } + + commandList.add(file.getLocation().toOSString()); + + // Get de Debugport form the Launchconfiguration or from the preferences + int debugPort = configuration.getAttribute( + IXDebugConstants.ATTR_PHP_DEBUGPORT, -1); + boolean useDefaultPort = configuration.getAttribute( + IXDebugConstants.ATTR_PHP_DEFAULT_DEBUGPORT, true); + if (useDefaultPort) + debugPort = XDebugCorePlugin.getDefault().getPreferenceStore() + .getInt(IXDebugPreferenceConstants.DEBUGPORT_PREFERENCE); + if (debugPort < 1024) + debugPort = IXDebugPreferenceConstants.DEFAULT_DEBUGPORT; + + String[] envp = DebugPlugin.getDefault().getLaunchManager() + .getEnvironment(configuration); + // appends the environment to the native environment + if (envp == null) { + Map stringVars = DebugPlugin.getDefault().getLaunchManager() + .getNativeEnvironment(); + int idx = 0; + envp = new String[stringVars.size()]; + for (Iterator i = stringVars.keySet().iterator(); i.hasNext();) { + String key = (String) i.next(); + String value = (String) stringVars.get(key); + envp[idx++] = key + "=" + value; + } + } + if (mode.equals(ILaunchManager.DEBUG_MODE)) { + String[] env = new String[envp.length + 1]; + for (int i = 0; i < envp.length; i++) + env[i + 1] = envp[i]; + env[0] = "XDEBUG_CONFIG=idekey=xdebug_test remote_enable=1"; + envp = env; + } + + String[] commandLine = (String[]) commandList + .toArray(new String[commandList.size()]); + Process process = DebugPlugin.exec(commandLine, null, envp); + IProcess p = DebugPlugin.newProcess(launch, process, phpInterpreter); + if (mode.equals(ILaunchManager.DEBUG_MODE)) { + IDebugTarget target = new XDebugTarget(launch, p, debugPort); + launch.addDebugTarget(target); + } + } + + /** + * Throws an exception with a new status containing the given message and + * optional exception. + * + * @param message + * error message + * @param e + * underlying exception + * @throws CoreException + */ + private void abort(String message, Throwable e) throws CoreException { + // TODO: the plug-in code should be the example plug-in, not Perl debug + // model id + throw new CoreException(new Status(IStatus.ERROR, + IXDebugConstants.ID_PHP_DEBUG_MODEL, 0, message, e)); + } + +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPSourceLookupParticipant.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPSourceLookupParticipant.java new file mode 100644 index 0000000..59cdae3 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPSourceLookupParticipant.java @@ -0,0 +1,17 @@ +package net.sourceforge.phpeclipse.xdebug.php.launching; + +import net.sourceforge.phpeclipse.xdebug.php.model.XDebugStackFrame; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupParticipant; + +public class PHPSourceLookupParticipant extends AbstractSourceLookupParticipant { + + public String getSourceName(Object object) throws CoreException { + if (object instanceof XDebugStackFrame) { + return ((XDebugStackFrame) object).getSourceName(); + } + return null; + } + +} diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugTarget.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugTarget.java new file mode 100644 index 0000000..04099c4 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugTarget.java @@ -0,0 +1,638 @@ +/** + * + */ +package net.sourceforge.phpeclipse.xdebug.php.model; + +import net.sourceforge.phpeclipse.xdebug.core.Base64; +import net.sourceforge.phpeclipse.xdebug.core.DebugConnection; +import net.sourceforge.phpeclipse.xdebug.core.PHPDebugUtils; +import net.sourceforge.phpeclipse.xdebug.core.XDebugCorePlugin; +import net.sourceforge.phpeclipse.xdebug.core.DebugConnection.DebugResponse; +import net.sourceforge.phpeclipse.xdebug.php.launching.IXDebugConstants; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IMarkerDelta; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IDebugEventSetListener; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.ILineBreakpoint; +import org.eclipse.debug.core.model.IMemoryBlock; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.core.model.IStackFrame; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.debug.core.model.IValue; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * @author Christian + * + */ +public class XDebugTarget extends XDebugElement implements IDebugTarget, + IDebugEventSetListener { + // associated system process (VM) + private IProcess fProcess; + + // containing launch object + private ILaunch fLaunch; + + // debugPort + private int fDebugPort; + + // program name + // private String fName; + + // suspend state + private boolean fSuspended = true; + + // terminated state + private boolean fTerminated = false; + + // threads + private XDebugThread fThread; + + private IThread[] fThreads; + + // event dispatch job + // private EventDispatchJob fEventDispatch; + + private DebugConnection fDebugConnection; + + // private DebugResponse lastResponse; + + /** + * Constructs a new debug target in the given launch for the associated PDA + * VM process. + * + * @param launch + * containing launch + * @param debugPort + * port to read events from + * @exception CoreException + * if unable to connect to host + */ + public XDebugTarget(ILaunch launch, IProcess process, int debugPort) + throws CoreException { + super(null); + fLaunch = launch; + fProcess = process; + fTarget = this; + fDebugConnection = new DebugConnection(this, debugPort); + fThread = new XDebugThread(this); + fThreads = new IThread[] { fThread }; + DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener( + this); + DebugPlugin.getDefault().addDebugEventListener(this); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugTarget#getProcess() + */ + public IProcess getProcess() { + return fProcess; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugTarget#getThreads() + */ + public IThread[] getThreads() throws DebugException { + return fThreads; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugTarget#hasThreads() + */ + public boolean hasThreads() throws DebugException { + return (fThreads.length > 0); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugTarget#getName() + */ + public String getName() throws DebugException { + return "PHP XDebug Client at localhost:" + fDebugPort; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint) + */ + public boolean supportsBreakpoint(IBreakpoint breakpoint) { + if (breakpoint.getModelIdentifier().equals( + IXDebugConstants.ID_PHP_DEBUG_MODEL)) { + return true; + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget() + */ + public IDebugTarget getDebugTarget() { + return this; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugElement#getLaunch() + */ + public ILaunch getLaunch() { + return fLaunch; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.ITerminate#canTerminate() + */ + public boolean canTerminate() { + return getProcess().canTerminate(); + // return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.ITerminate#isTerminated() + */ + public boolean isTerminated() { + // return getProcess().isTerminated(); + return fTerminated; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.ITerminate#terminate() + */ + public void terminate() throws DebugException { + fDebugConnection.sendRequest("stop"); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.ISuspendResume#canResume() + */ + public boolean canResume() { + return !isTerminated() && isSuspended(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend() + */ + public boolean canSuspend() { + return !isTerminated() && !isSuspended(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended() + */ + public boolean isSuspended() { + return fSuspended; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.ISuspendResume#resume() + */ + public void resume() throws DebugException { + fDebugConnection.sendRequest("run"); + } + + /** + * Notification the target has resumed for the given reason + * + * @param detail + * reason for the resume + */ + private void resumed(int detail) { + fSuspended = false; + fThread.fireResumeEvent(detail); + } + + /** + * Notification the target has suspended for the given reason + * + * @param detail + * reason for the suspend + */ + public void suspended(int detail) { + fSuspended = true; + fThread.fireSuspendEvent(detail); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.ISuspendResume#suspend() + */ + public void suspend() throws DebugException { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint) + */ + public void breakpointAdded(IBreakpoint breakpoint) { + + if (supportsBreakpoint(breakpoint)) { + try { + if (breakpoint.isEnabled()) { + IMarker marker = breakpoint.getMarker(); + if (marker != null) { + try { + String fileName = PHPDebugUtils.escapeString(marker + .getResource().getLocation().toString()); + String arg = "-t line -f file:///" + + fileName + + " -n " + + ((ILineBreakpoint) breakpoint) + .getLineNumber(); + int id = fDebugConnection.sendRequest( + "breakpoint_set", arg); + // set the marker Attribute to make later + // idetification possible + // TODO: make sure that attribute is set before + // response from debugger is beeing prosessed + marker.setAttribute( + XDebugLineBreakpoint.BREAKPOINT_ID, id); + + } catch (CoreException e) { + } + } + } + } catch (CoreException e) { + + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, + * org.eclipse.core.resources.IMarkerDelta) + */ + public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { + if (supportsBreakpoint(breakpoint)) { + try { + int id = ((XDebugLineBreakpoint) breakpoint).getID(); + if (id > 0) + fDebugConnection.sendRequest("breakpoint_remove", "-d " + + id); + } catch (CoreException e) { + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, + * org.eclipse.core.resources.IMarkerDelta) + */ + public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { + // if (supportsBreakpoint(breakpoint)) { + // try { + // if (breakpoint.isEnabled()) { + // breakpointAdded(breakpoint); + // } else { + // breakpointRemoved(breakpoint, null); + // } + // } catch (CoreException e) { + // } + // } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect() + */ + public boolean canDisconnect() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDisconnect#disconnect() + */ + public void disconnect() throws DebugException { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected() + */ + public boolean isDisconnected() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval() + */ + public boolean supportsStorageRetrieval() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, + * long) + */ + public IMemoryBlock getMemoryBlock(long startAddress, long length) + throws DebugException { + return null; + } + + /** + * Notification we have connected to the PHP debugger and it has started. + * Resume the the debugger. + */ + public void started() { + + fThread.setBreakpoints(null); + fThread.setStepping(false); + + installDeferredBreakpoints(); + try { + resume(); + // step(); + } catch (DebugException e) { + } + } + + /** + * Install breakpoints that are already registered with the breakpoint + * manager. + */ + private void installDeferredBreakpoints() { + IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints(); + for (int i = 0; i < breakpoints.length; i++) { + breakpointAdded(breakpoints[i]); + } + } + + /** + * Called when this debug target terminates. + */ + public void terminated() { + fTerminated = true; + fSuspended = false; + XDebugCorePlugin.getBreakpointManager().removeBreakpointListener(this); + fireTerminateEvent(); + DebugPlugin.getDefault().removeDebugEventListener(this); + fThread.removeEventListeners(); + } + + /** + * Returns the current stack frames in the target. + * + * @return the current stack frames in the target + * @throws DebugException + * if unable to perform the request + */ + protected IStackFrame[] getStackFrames() throws DebugException { + int id = fDebugConnection.sendRequest("stack_get"); + DebugResponse lastResponse = fDebugConnection.waitforTransID(id); + if (lastResponse.isError()) + return new IStackFrame[0]; + Node response = lastResponse.getParentNode(); + NodeList frames = response.getChildNodes(); + IStackFrame[] theFrames = new IStackFrame[frames.getLength()]; + for (int i = 0; i < frames.getLength(); i++) { + Node stackNode = frames.item(i); + theFrames[i] = new XDebugStackFrame(fThread, stackNode, i); + } + return theFrames; + } + + /** + * Single step the interpreter. + * + * @throws DebugException + * if the request fails + */ + protected void step_over() throws DebugException { + fThread.setStepping(true); + resumed(DebugEvent.STEP_OVER); + fDebugConnection.sendRequest("step_over"); + } + + /** + * Single step the interpreter. + * + * @throws DebugException + * if the request fails + */ + protected void step_into() throws DebugException { + fThread.setStepping(true); + resumed(DebugEvent.STEP_INTO); + fDebugConnection.sendRequest("step_into"); + } + + /** + * Single step the interpreter. + * + * @throws DebugException + * if the request fails + */ + protected void step_out() throws DebugException { + fThread.setStepping(true); + resumed(DebugEvent.STEP_RETURN); + fDebugConnection.sendRequest("step_out"); + } + + /** + * Returns the current value of the given variable. + * + * @param variable + * @return variable value + * @throws DebugException + * if the request fails + */ + protected IValue getVariableValue(XDebugVariable variable) + throws DebugException { + // synchronized (fDebugSocket) { + // fDebugConnection.sendRequest("var","" + + // variable.getStackFrame().getIdentifier() + " " + variable.getName()); + // try { + // String value = fDebugReader.readLine(); + // //return new XDebugValue(this, value); + // + // } catch (IOException e) { + // abort(MessageFormat.format("Unable to retrieve value for variable + // {0}", new String[]{variable.getName()}), e); + // } + // } + return null; + } + + /** + * Returns the values on the data stack (top down) + * + * @return the values on the data stack (top down) + */ + public IValue[] getDataStack() throws DebugException { + // synchronized (fDebugSocket) { + // fDebugConnection.sendRequest ("data"); + // try { + // String valueString = fDebugReader.readLine(); + // if (valueString != null && valueString.length() > 0) { + // String[] values = valueString.split("\\|"); + // IValue[] theValues = new IValue[values.length]; + // for (int i = 0; i < values.length; i++) { + // String value = values[values.length - i - 1]; + // // theValues[i] = new XDebugValue(this, value); + // } + // return theValues; + // } + // } catch (IOException e) { + // abort("Unable to retrieve data stack", e); + // } + // } + return new IValue[0]; + } + + public boolean setVarValue(String name, String value) { + int id = -1; + String str = Base64.encodeBytes(value.getBytes()); + int len = str.length(); + + try { + id = fDebugConnection.sendRequest("property_set", "-n " + name + + " -l " + len + " -- " + str); + } catch (DebugException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + DebugResponse dr = getResponse(id); + if ((dr.getAttributeValue("success")).equals("1")) + return true; + + return false; + } + + public DebugResponse getResponse(int id) { + return fDebugConnection.waitforTransID(id); + } + + /** + * Sends a request to the Debugengine and waits for an OK. + * + * @param command + * debug command + * @throws DebugException + * if the request fails + */ + + public int sendRequest(String command) throws DebugException { + return fDebugConnection.sendRequest(command, ""); + } + + /** + * Sends a request to the Debugengine and waits for an OK. + * + * @param command + * debug command + * @arguments arguments for the command + * @throws DebugException + * if the request fails + */ + + public int sendRequest(String command, String arguments) + throws DebugException { + return fDebugConnection.sendRequest(command, arguments); + } + + /** + * Notification a breakpoint was encountered. Determine which breakpoint was + * hit and fire a suspend event. + * + * @param event + * debug event + */ + public void breakpointHit(Node node) { + // determine which breakpoint was hit, and set the thread's breakpoint + Node child = node.getFirstChild(); + if (child.getNodeName().equals("stack")) { + int lineNumber = Integer.parseInt(PHPDebugUtils.getAttributeValue( + child, "lineno")); + String filename = PHPDebugUtils + .getAttributeValue(child, "filename").substring(8); // remove + // file:/// + IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints(); + for (int i = 0; i < breakpoints.length; i++) { + IBreakpoint breakpoint = breakpoints[i]; + if (supportsBreakpoint(breakpoint)) { + if (breakpoint instanceof ILineBreakpoint) { + ILineBreakpoint lineBreakpoint = (ILineBreakpoint) breakpoint; + try { + if (breakpoint.isEnabled()) { + IMarker marker = breakpoint.getMarker(); + if (marker != null) { + + String name = marker.getResource() + .getLocation().toOSString(); + if (name.equals(PHPDebugUtils + .unescapeString(filename)) + && (lineBreakpoint.getLineNumber() == lineNumber)) { + fThread + .setBreakpoints(new IBreakpoint[] { breakpoint }); + break; + } + } + + } + } catch (CoreException e) { + } + } + } + } + } + suspended(DebugEvent.BREAKPOINT); + } + + public void handleDebugEvents(DebugEvent[] events) { + for (int i = 0; i < events.length; i++) { + DebugEvent event = events[i]; + if ((event.getKind() == DebugEvent.CREATE) + && (event.getSource() instanceof XDebugElement)) { + if (((XDebugElement) event.getSource()).getModelIdentifier() == IXDebugConstants.ID_PHP_DEBUG_MODEL) { + if (event.getKind() == DebugEvent.CREATE) + started(); + } + } + } + + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xml/core/internal/model/XMLDocument.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xml/core/internal/model/XMLDocument.java new file mode 100644 index 0000000..c0b5680 --- /dev/null +++ b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xml/core/internal/model/XMLDocument.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2004 Christopher Lenz and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Christopher Lenz - initial API + * + * $Id: XMLDocument.java,v 1.2 2006-10-21 23:13:43 pombredanne Exp $ + */ + +package net.sourceforge.phpeclipse.xml.core.internal.model; + +import net.sourceforge.phpeclipse.core.model.SourceReference; +import net.sourceforge.phpeclipse.xml.core.internal.parser.XMLParser; +import net.sourceforge.phpeclipse.xml.core.model.IXMLDocument; +import net.sourceforge.phpeclipse.xml.core.model.IXMLElement; +import net.sourceforge.phpeclipse.xml.core.parser.IProblemCollector; +import net.sourceforge.phpeclipse.xml.core.parser.IXMLParser; + +import org.eclipse.core.resources.IFile; +import org.eclipse.jface.text.DocumentEvent; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentListener; + +/** + * + */ +public class XMLDocument extends SourceReference implements IXMLDocument, + IDocumentListener { + // Instance Variables ------------------------------------------------------ + + private IXMLElement root; + + private String systemId; + + private Object dirtyLock = new Object(); + + private boolean dirty = true; + + // Constructors ------------------------------------------------------------ + + public XMLDocument(IDocument document, String systemId) { + super(document, 0, document.getLength()); + this.systemId = systemId; + } + + // IXMLDocument Implementation --------------------------------------------- + + /* + * @see IXMLDocument#getRoot() + */ + public IXMLElement getRoot() { + return root; + } + + /* + * @see net.sourceforge.phpeclipse.xml.core.model.IXMLDocument#getSystemId() + */ + public String getSystemId() { + return systemId; + } + + /* + * @see IStyleSheet#reconcile(IProblemCollector) + */ + public void reconcile(IProblemCollector problemCollector, IFile file) { + synchronized (dirtyLock) { + if (!dirty) { + return; + } + dirty = false; + } + + synchronized (this) { + boolean doParse = false; + root = null; + if (file != null) { + String filename = file.getLocation().toString(); + int len = filename.length(); + if (len >= 4) { + if ((filename.charAt(len - 1) != 'l' && filename + .charAt(len - 1) != 'L') + || (filename.charAt(len - 2) != 'p' && filename + .charAt(len - 2) != 'P') + || (filename.charAt(len - 3) != 't' && filename + .charAt(len - 3) != 'T') + || (filename.charAt(len - 4) != '.')) { + if ((filename.charAt(len - 1) != 'm' && filename + .charAt(len - 1) != 'M') + || (filename.charAt(len - 2) != 't' && filename + .charAt(len - 2) != 'T') + || (filename.charAt(len - 3) != 'h' && filename + .charAt(len - 3) != 'H') + || (filename.charAt(len - 4) != '.')) { + if (len >= 5) { + if ((filename.charAt(len - 1) != 'l' && filename + .charAt(len - 1) != 'L') + || (filename.charAt(len - 2) != 'm' && filename + .charAt(len - 2) != 'M') + || (filename.charAt(len - 3) != 't' && filename + .charAt(len - 3) != 'T') + || (filename.charAt(len - 4) != 'h' && filename + .charAt(len - 4) != 'H') + || (filename.charAt(len - 5) != '.')) { + doParse = true; + } + } + } + } + } else { + doParse = true; + } + } + if (doParse) { + IXMLParser parser = new XMLParser(); + parser.setProblemCollector(problemCollector); + parser.setSource(getDocument()); + parser.setSystemId(systemId); + IXMLDocument model = parser.parse(); + if (model != null) { + root = model.getRoot(); + } + } + } + } + + // IDocumentListener Implementation ---------------------------------------- + + /* + * @see IDocumentListener#documentAboutToBeChanged(DocumentEvent) + */ + public void documentAboutToBeChanged(DocumentEvent event) { + // do nothing + } + + /* + * @see IDocumentListener#documentChanged(DocumentEvent) + */ + public void documentChanged(DocumentEvent event) { + synchronized (dirtyLock) { + dirty = true; + } + } + + // Public Methods ---------------------------------------------------------- + + /** + * Sets the root element. + * + * @param root + * the root element to set + */ + public void setRoot(IXMLElement root) { + this.root = root; + } + +} \ No newline at end of file -- 1.7.1