From bf6ca1918a2cdf63e6665beb3d80306ca9b4fee6 Mon Sep 17 00:00:00 2001 From: mbowie Date: Fri, 6 Jun 2008 05:52:00 +0000 Subject: [PATCH 01/16] Removes the "Show Line Numbers" option from the PHPEclipse preferences and sets the editor to use the setting as defined in the global "Text Editors" preferences. Some legacy (commented) code related to this still exists and should be removed prior to either the 1.3.0 or 1.5.0 release. closes #653 --- .../phpdt/internal/ui/PHPUIMessages.properties | 2 - .../ui/preferences/JavaEditorPreferencePage.java | 46 +++++++++++--------- .../ui/preferences/PreferencesMessages.properties | 5 +- .../sourceforge/phpdt/ui/PreferenceConstants.java | 28 ------------ .../phpeclipse/phpeditor/PHPEditor.java | 6 --- 5 files changed, 29 insertions(+), 58 deletions(-) diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPUIMessages.properties b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPUIMessages.properties index e8bbead..e1e7d3f 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPUIMessages.properties +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPUIMessages.properties @@ -298,9 +298,7 @@ PHPEditorPreferencePage.codeAssist=Code A&ssist PHPEditorPreferencePage.change=C&hange... PHPEditorPreferencePage.empty_input=Empty input PHPEditorPreferencePage.invalid_input=''{0}'' is not a valid input. -PHPEditorPreferencePage.showLineNumbers=Show lin&e numbers PHPEditorPreferencePage.lineNumberColor=Line number foreground color: -PHPEditorPreferencePage.lineNumberForegroundColor=Line number foreground PHPEditorPreferencePage.matchingBracketsHighlightColor2=Matching brackets highlight PHPEditorPreferencePage.currentLineHighlighColor=Current line highlight PHPEditorPreferencePage.printMarginColor2=Print margin diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/JavaEditorPreferencePage.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/JavaEditorPreferencePage.java index e1700c5..7c6e28f 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/JavaEditorPreferencePage.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/JavaEditorPreferencePage.java @@ -67,21 +67,26 @@ import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.dialogs.PreferencesUtil; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; import org.eclipse.ui.texteditor.AnnotationPreference; import org.eclipse.ui.texteditor.ChainedPreferenceStore; import org.eclipse.ui.texteditor.MarkerAnnotationPreferences; + /** * The page for setting the editor options. */ @@ -185,11 +190,6 @@ public class JavaEditorPreferencePage extends PreferencePage implements private final String[][] fAppearanceColorListModel = new String[][] { { PreferencesMessages - .getString("JavaEditorPreferencePage.lineNumberForegroundColor"), - AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR }, - //$NON-NLS-1$ - { - PreferencesMessages .getString("JavaEditorPreferencePage.matchingBracketsHighlightColor2"), PreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR }, //$NON-NLS-1$ @@ -558,14 +558,6 @@ public class JavaEditorPreferencePage extends PreferencePage implements .add(new OverlayPreferenceStore.OverlayKey( OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_OVERVIEW_RULER)); - overlayKeys - .add(new OverlayPreferenceStore.OverlayKey( - OverlayPreferenceStore.STRING, - AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR)); - overlayKeys - .add(new OverlayPreferenceStore.OverlayKey( - OverlayPreferenceStore.BOOLEAN, - AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER)); overlayKeys.add(new OverlayPreferenceStore.OverlayKey( OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_SPACES_FOR_TABS)); @@ -984,7 +976,28 @@ public class JavaEditorPreferencePage extends PreferencePage implements GridLayout layout = new GridLayout(); layout.numColumns = 2; appearanceComposite.setLayout(layout); + + // Inserts a hyper-link to the General Editor preferences page + // TODO Can probably be removed post 1.5.0? String label = PreferencesMessages + .getString("JavaEditorPreferencePage.appearanceTabLink"); + Link link = new Link(appearanceComposite, SWT.NONE); + GridData gridPosition = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + gridPosition.horizontalSpan = 2; + link.setLayoutData(gridPosition); + + link.setText(label); + link.addListener(SWT.Selection, new Listener () { + public void handleEvent(Event event) { + String u = event.text; + PreferencesUtil.createPreferenceDialogOn(getShell(), u, null, null); + } + }); + String tooltip = PreferencesMessages + .getString("JavaEditorPreferencePage.appearanceTabTooltip"); + link.setToolTipText(tooltip); + + label = PreferencesMessages .getString("JavaEditorPreferencePage.displayedTabWidth"); //$NON-NLS-1$ addTextField(appearanceComposite, label, PreferenceConstants.EDITOR_TAB_WIDTH, 3, 0, true); @@ -1003,13 +1016,6 @@ public class JavaEditorPreferencePage extends PreferencePage implements AbstractDecoratedTextEditorPreferenceConstants.EDITOR_OVERVIEW_RULER, 0); label = PreferencesMessages - .getString("JavaEditorPreferencePage.showLineNumbers"); //$NON-NLS-1$ - addCheckBox( - appearanceComposite, - label, - AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER, - 0); - label = PreferencesMessages .getString("JavaEditorPreferencePage.highlightMatchingBrackets"); //$NON-NLS-1$ addCheckBox(appearanceComposite, label, PreferenceConstants.EDITOR_MATCHING_BRACKETS, 0); diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/PreferencesMessages.properties b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/PreferencesMessages.properties index 4884b64..7a0486e 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/PreferencesMessages.properties +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/PreferencesMessages.properties @@ -80,6 +80,9 @@ NewJavaProjectPreferencePage.folders.error.invalidsrcname=Invalid source folder NewJavaProjectPreferencePage.folders.error.invalidbinname=Invalid output folder name: {0} NewJavaProjectPreferencePage.folders.error.invalidcp=Settings will result in an invalid build path. Check for nested folders. +JavaEditorPreferencePage.appearanceTabLink=Some general preferences now live on the Eclipse Text Editors pages. +JavaEditorPreferencePage.appearanceTabTooltip=Jump to the Text Editors page + JavaEditorPreferencePage.annotationsTab.title= Annotation&s JavaEditorPreferencePage.showQuickFixables= Indicate annotations solvable with &Quick Fix in vertical ruler JavaEditorPreferencePage.analyseAnnotationsWhileTyping= Analyze annotations &while typing @@ -160,8 +163,6 @@ JavaEditorPreferencePage.colors=Synta&x JavaEditorPreferencePage.codeAssist= &Code Assist JavaEditorPreferencePage.empty_input=Empty input JavaEditorPreferencePage.invalid_input=''{0}'' is not a valid input. -JavaEditorPreferencePage.showLineNumbers=Show lin&e numbers -JavaEditorPreferencePage.lineNumberForegroundColor=Line number foreground JavaEditorPreferencePage.matchingBracketsHighlightColor2=Matching brackets highlight JavaEditorPreferencePage.currentLineHighlighColor=Current line highlight JavaEditorPreferencePage.printMarginColor2=Print margin diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/PreferenceConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/PreferenceConstants.java index 1dfe2cf..60f8e03 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/PreferenceConstants.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/PreferenceConstants.java @@ -1091,29 +1091,6 @@ public class PreferenceConstants { public final static String EDITOR_OVERVIEW_RULER = "overviewRuler"; //$NON-NLS-1$ /** - * A named preference that controls if the line number ruler is shown in the - * UI. - *

- * Value is of type Boolean. - *

- */ - public final static String EDITOR_LINE_NUMBER_RULER = "lineNumberRuler"; //$NON-NLS-1$ - - /** - * A named preference that holds the color used to render line numbers - * inside the line number ruler. - *

- * Value is of type String. A RGB color value encoded as a - * string using class PreferenceConverter - *

- * - * @see org.eclipse.jface.resource.StringConverter - * @see org.eclipse.jface.preference.PreferenceConverter - * @see #EDITOR_LINE_NUMBER_RULER - */ - public final static String EDITOR_LINE_NUMBER_RULER_COLOR = "lineNumberColor"; //$NON-NLS-1$ - - /** * A named preference that holds the color used to render linked positions * inside code templates. *

@@ -2760,11 +2737,6 @@ public class PreferenceConstants { store.setDefault(PreferenceConstants.EDITOR_OVERVIEW_RULER, true); - store.setDefault(PreferenceConstants.EDITOR_LINE_NUMBER_RULER, false); - PreferenceConverter.setDefault(store, - PreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR, new RGB(0, - 0, 0)); - // WorkbenchChainedTextFontFieldEditor.startPropagate(store, // JFaceResources.TEXT_FONT); diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java index 0a09a2e..e8de8e0 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java @@ -3063,12 +3063,6 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements */ 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; -- 1.7.1 From 415d47ac4187d3d76b1680bf1c1962e19d5ffc55 Mon Sep 17 00:00:00 2001 From: Edward Mann Date: Fri, 27 Jun 2008 05:09:05 +0000 Subject: [PATCH 03/16] 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: + *

+ *

+ * 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: + *

+ *

+ * 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 From 3f9ac3776fd6d895c951d52b5bf77ca482ad31d4 Mon Sep 17 00:00:00 2001 From: Edward Mann Date: Tue, 1 Jul 2008 02:34:59 +0000 Subject: [PATCH 04/16] adding entry to runtime to put compatibility.jar in the class path. This will support the fragment to allow PHPEclipse to run on Eclipse 3.2 --- net.sourceforge.phpeclipse/META-INF/MANIFEST.MF | 3 ++- net.sourceforge.phpeclipse/build.properties | 1 + 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/net.sourceforge.phpeclipse/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse/META-INF/MANIFEST.MF index facece9..3f494ca 100644 --- a/net.sourceforge.phpeclipse/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse/META-INF/MANIFEST.MF @@ -3,7 +3,8 @@ Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: net.sourceforge.phpeclipse; singleton:=true Bundle-Version: 0.0.0 -Bundle-ClassPath: phpeclipse.jar +Bundle-ClassPath: compatibility.jar, + phpeclipse.jar Bundle-Activator: net.sourceforge.phpeclipse.PHPeclipsePlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/net.sourceforge.phpeclipse/build.properties b/net.sourceforge.phpeclipse/build.properties index bf86075..2874055 100644 --- a/net.sourceforge.phpeclipse/build.properties +++ b/net.sourceforge.phpeclipse/build.properties @@ -33,3 +33,4 @@ src.includes = src/,\ templates/,\ test/ output.phpeclipse.jar = bin/ +jars.compile.order = phpeclipse.jar -- 1.7.1 From 034404a8380c404d33efa8fbb393475310e4964d Mon Sep 17 00:00:00 2001 From: Edward Mann Date: Sat, 12 Jul 2008 15:21:24 +0000 Subject: [PATCH 05/16] Code needed for final 1.1.9 build. --- .../.classpath | 2 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- .../META-INF/MANIFEST.MF | 28 +- .../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 ------ .../launching/PHPLaunchConfigurationDelegate.java | 155 ---- .../php/launching/PHPSourceLookupParticipant.java | 17 - .../phpeclipse/xdebug/php/model/XDebugTarget.java | 638 ---------------- .../xml/core/internal/model/XMLDocument.java | 160 ---- 13 files changed, 29 insertions(+), 3091 deletions(-) delete mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/core/PHPDBGProxy.java delete mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/LoadPathEntryLabelProvider.java delete mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/PHPEnvironmentTab.java delete mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunner.java delete mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunnerConfiguration.java delete mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/PHPSourceLocator.java delete mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPLaunchConfigurationDelegate.java delete mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPSourceLookupParticipant.java delete mode 100644 net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugTarget.java delete 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 index ce73933..304e861 100644 --- a/net.sourceforge.phpeclipse.32.compatibility/.classpath +++ b/net.sourceforge.phpeclipse.32.compatibility/.classpath @@ -1,7 +1,7 @@ - + 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 index 8ba6423..44acd00 100644 --- a/net.sourceforge.phpeclipse.32.compatibility/.settings/org.eclipse.jdt.core.prefs +++ b/net.sourceforge.phpeclipse.32.compatibility/.settings/org.eclipse.jdt.core.prefs @@ -1,7 +1,7 @@ -#Thu Jun 26 21:18:27 CDT 2008 +#Fri Jul 11 22:55:41 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 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/net.sourceforge.phpeclipse.32.compatibility/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.32.compatibility/META-INF/MANIFEST.MF index 848862d..3f08029 100644 --- a/net.sourceforge.phpeclipse.32.compatibility/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.32.compatibility/META-INF/MANIFEST.MF @@ -2,11 +2,27 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Compatability Fragment Bundle-SymbolicName: net.sourceforge.phpeclipse.32.compatibility -Bundle-Version: 1.0.0 +Bundle-Version: 0.0.0 Fragment-Host: net.sourceforge.phpeclipse;bundle-version="0.0.0" -Bundle-RequiredExecutionEnvironment: J2SE-1.4 -Bundle-ClassPath: compatability.jar, - . +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-ClassPath: compatability.jar Eclipse-PatchFragment: true -Require-Bundle: net.sourceforge.phpeclipse.launching, - net.sourceforge.phpeclipse.core;bundle-version="0.0.0" +Export-Package: net.sourceforge.phpdt.externaltools.actions, + net.sourceforge.phpdt.internal.compiler.lookup;x-internal:=true, + net.sourceforge.phpdt.internal.compiler.parser;x-internal:=true, + net.sourceforge.phpdt.internal.core;x-internal:=true, + net.sourceforge.phpdt.internal.corext.phpdoc;x-internal:=true, + net.sourceforge.phpdt.internal.corext.util;x-internal:=true, + net.sourceforge.phpdt.internal.ui.text.template;x-internal:=true, + net.sourceforge.phpdt.internal.ui.util;x-internal:=true, + net.sourceforge.phpdt.ltk.core, + net.sourceforge.phpeclipse.actions, + net.sourceforge.phpeclipse.obfuscator, + net.sourceforge.phpeclipse.obfuscator.export, + net.sourceforge.phpeclipse.phpeditor, + net.sourceforge.phpeclipse.ui, + net.sourceforge.phpeclipse.ui.editor, + net.sourceforge.phpeclipse.webbrowser.internal;x-internal:=true, + net.sourceforge.phpeclipse.webbrowser.views, + net.sourceforge.phpeclipse.wizards +Bundle-Vendor: PHPEclipse Development Team 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 deleted file mode 100644 index 5c5b26b..0000000 --- a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/core/PHPDBGProxy.java +++ /dev/null @@ -1,703 +0,0 @@ -/*********************************************************************************************************************************** - * 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 deleted file mode 100644 index 7831922..0000000 --- a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/LoadPathEntryLabelProvider.java +++ /dev/null @@ -1,64 +0,0 @@ -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 deleted file mode 100644 index 0257ce1..0000000 --- a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/debug/ui/launcher/PHPEnvironmentTab.java +++ /dev/null @@ -1,775 +0,0 @@ -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 deleted file mode 100644 index 6aa5738..0000000 --- a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunner.java +++ /dev/null @@ -1,140 +0,0 @@ -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 deleted file mode 100644 index 52fa78a..0000000 --- a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/InterpreterRunnerConfiguration.java +++ /dev/null @@ -1,207 +0,0 @@ -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 deleted file mode 100644 index 652a6c7..0000000 --- a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/internal/launching/PHPSourceLocator.java +++ /dev/null @@ -1,219 +0,0 @@ -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/phpeclipse/xdebug/php/launching/PHPLaunchConfigurationDelegate.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPLaunchConfigurationDelegate.java deleted file mode 100644 index 5880ca0..0000000 --- a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPLaunchConfigurationDelegate.java +++ /dev/null @@ -1,155 +0,0 @@ -/********************************************************************** - 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 deleted file mode 100644 index 59cdae3..0000000 --- a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/launching/PHPSourceLookupParticipant.java +++ /dev/null @@ -1,17 +0,0 @@ -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 deleted file mode 100644 index 04099c4..0000000 --- a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugTarget.java +++ /dev/null @@ -1,638 +0,0 @@ -/** - * - */ -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 deleted file mode 100644 index c0b5680..0000000 --- a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpeclipse/xml/core/internal/model/XMLDocument.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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 From 6a1e17d61b98d2f5831b07d89500df9fbc0e311c Mon Sep 17 00:00:00 2001 From: Edward Mann Date: Sat, 12 Jul 2008 15:22:43 +0000 Subject: [PATCH 06/16] cleanup version entries for 1.1.9 release. --- .../META-INF/MANIFEST.MF | 2 +- .../feature.xml | 4 ++-- .../META-INF/MANIFEST.MF | 2 +- net.sourceforge.phpeclipse.feature/feature.xml | 11 +++++++++-- .../META-INF/MANIFEST.MF | 2 +- .../META-INF/MANIFEST.MF | 2 +- .../META-INF/MANIFEST.MF | 4 ++-- .../META-INF/MANIFEST.MF | 3 ++- .../META-INF/MANIFEST.MF | 4 ++-- net.sourceforge.phpeclipse.ui/META-INF/MANIFEST.MF | 4 ++-- .../META-INF/MANIFEST.MF | 7 +++---- .../feature.xml | 2 +- .../META-INF/MANIFEST.MF | 4 ++-- .../META-INF/MANIFEST.MF | 4 ++-- 14 files changed, 31 insertions(+), 24 deletions(-) diff --git a/net.sourceforge.phpeclipse.debug.core/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.debug.core/META-INF/MANIFEST.MF index 3b0f6a9..e1ef72a 100644 --- a/net.sourceforge.phpeclipse.debug.core/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.debug.core/META-INF/MANIFEST.MF @@ -1,6 +1,6 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: %Plugin.name +Bundle-Name: PHPEclipse DBG Core Bundle-SymbolicName: net.sourceforge.phpeclipse.debug.core; singleton:=true Bundle-Version: 0.0.0 Bundle-ClassPath: core.jar diff --git a/net.sourceforge.phpeclipse.debug.feature/feature.xml b/net.sourceforge.phpeclipse.debug.feature/feature.xml index 94963be..6cff413 100644 --- a/net.sourceforge.phpeclipse.debug.feature/feature.xml +++ b/net.sourceforge.phpeclipse.debug.feature/feature.xml @@ -1,8 +1,8 @@ diff --git a/net.sourceforge.phpeclipse.debug.ui/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.debug.ui/META-INF/MANIFEST.MF index 5d9821a..de060f4 100644 --- a/net.sourceforge.phpeclipse.debug.ui/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.debug.ui/META-INF/MANIFEST.MF @@ -1,6 +1,6 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: %Plugin.name +Bundle-Name: PHPEclipse DBG Debug Bundle-SymbolicName: net.sourceforge.phpeclipse.debug.ui; singleton:=true Bundle-Version: 0.0.0 Bundle-ClassPath: debug.jar diff --git a/net.sourceforge.phpeclipse.feature/feature.xml b/net.sourceforge.phpeclipse.feature/feature.xml index dabcdfa..973fd9d 100644 --- a/net.sourceforge.phpeclipse.feature/feature.xml +++ b/net.sourceforge.phpeclipse.feature/feature.xml @@ -2,7 +2,7 @@ @@ -245,7 +245,7 @@ litigation. - + + + diff --git a/net.sourceforge.phpeclipse.help/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.help/META-INF/MANIFEST.MF index a648269..981e9fb 100644 --- a/net.sourceforge.phpeclipse.help/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.help/META-INF/MANIFEST.MF @@ -1,6 +1,6 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: PHpEclipse Help Plug-in +Bundle-Name: PHPEclipse Help Plug-in Bundle-SymbolicName: net.sourceforge.phpeclipse.help; singleton:=true Bundle-Version: 0.0.0 Bundle-Vendor: PHPEclipse Team diff --git a/net.sourceforge.phpeclipse.launching/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.launching/META-INF/MANIFEST.MF index f2db42a..217fec4 100644 --- a/net.sourceforge.phpeclipse.launching/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.launching/META-INF/MANIFEST.MF @@ -1,6 +1,6 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: %Plugin.name +Bundle-Name: PHPEclipse launching Bundle-SymbolicName: net.sourceforge.phpeclipse.launching; singleton:=true Bundle-Version: 0.0.0 Bundle-ClassPath: launch.jar diff --git a/net.sourceforge.phpeclipse.phphelp/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.phphelp/META-INF/MANIFEST.MF index a1378dc..41888d1 100644 --- a/net.sourceforge.phpeclipse.phphelp/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.phphelp/META-INF/MANIFEST.MF @@ -1,11 +1,11 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: %pluginName +Bundle-Name: PHPEclipse Help Manual Bundle-SymbolicName: net.sourceforge.phpeclipse.phphelp; singleton:=true Bundle-Version: 0.0.0 Bundle-ClassPath: phphelp.jar Bundle-Activator: net.sourceforge.phpdt.phphelp.PHPHelpPlugin -Bundle-Vendor: %providerName +Bundle-Vendor: PHPEclipse Development Team Bundle-Localization: plugin Export-Package: net.sourceforge.phpdt.httpquery, net.sourceforge.phpdt.httpquery.config, diff --git a/net.sourceforge.phpeclipse.phpmanual.htmlparser/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.phpmanual.htmlparser/META-INF/MANIFEST.MF index b568868..33a8834 100644 --- a/net.sourceforge.phpeclipse.phpmanual.htmlparser/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.phpmanual.htmlparser/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Htmlparser Plug-in Bundle-SymbolicName: net.sourceforge.phpeclipse.phpmanual.htmlparser -Bundle-Version: 1.6.0 +Bundle-Version: 0.0.0 Bundle-ClassPath: filterbuilder.jar, htmllexer.jar, htmlparser.jar, @@ -42,3 +42,4 @@ Export-Package: ., org.xml.sax.ext, org.xml.sax.helpers Bundle-RequiredExecutionEnvironment: J2SE-1.4 +Bundle-Vendor: PHPEclipse project Team diff --git a/net.sourceforge.phpeclipse.phpmanual/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.phpmanual/META-INF/MANIFEST.MF index 8c995f0..2749643 100644 --- a/net.sourceforge.phpeclipse.phpmanual/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.phpmanual/META-INF/MANIFEST.MF @@ -1,11 +1,11 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: %pluginName +Bundle-Name: PHPEclipse Manual Bundle-SymbolicName: net.sourceforge.phpeclipse.phpmanual; singleton:=true Bundle-Version: 0.0.0 Bundle-ClassPath: phpmanual.jar Bundle-Activator: net.sourceforge.phpeclipse.phpmanual.PHPManualUIPlugin -Bundle-Vendor: %providerName +Bundle-Vendor: PHPEclipse Development Team Bundle-Localization: plugin Require-Bundle: org.eclipse.core.runtime, org.eclipse.jface.text, diff --git a/net.sourceforge.phpeclipse.ui/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.ui/META-INF/MANIFEST.MF index 2dd512c..4fa50ab 100644 --- a/net.sourceforge.phpeclipse.ui/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.ui/META-INF/MANIFEST.MF @@ -1,12 +1,12 @@ Manifest-Version: 1.0 Generated-from: 1150021273000;type=2 Bundle-ManifestVersion: 2 -Bundle-Name: %pluginName +Bundle-Name: PHPEclipse UI Bundle-SymbolicName: net.sourceforge.phpeclipse.ui; singleton:=true Bundle-Version: 0.0.0 Bundle-ClassPath: ui.jar Bundle-Activator: net.sourceforge.phpeclipse.ui.WebUI -Bundle-Vendor: %providerName +Bundle-Vendor: PHPEclipse Development Team Bundle-Localization: plugin Export-Package: net.sourceforge.phpeclipse.ui, net.sourceforge.phpeclipse.ui.editor, diff --git a/net.sourceforge.phpeclipse.webbrowser/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.webbrowser/META-INF/MANIFEST.MF index f48d6ca..efe5bdf 100644 --- a/net.sourceforge.phpeclipse.webbrowser/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.webbrowser/META-INF/MANIFEST.MF @@ -1,11 +1,11 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: %pluginName +Bundle-Name: PHPEclipse WebBrowser Bundle-SymbolicName: net.sourceforge.phpeclipse.webbrowser; singleton:=true Bundle-Version: 0.0.0 Bundle-ClassPath: webbrowser.jar Bundle-Activator: net.sourceforge.phpeclipse.webbrowser.internal.WebBrowserUIPlugin -Bundle-Vendor: %providerName +Bundle-Vendor: PHPEclipse Development Team Bundle-Localization: plugin Export-Package: net.sourceforge.phpeclipse.webbrowser, net.sourceforge.phpeclipse.webbrowser.internal;x-internal:=true, @@ -14,6 +14,5 @@ Require-Bundle: org.eclipse.core.resources;bundle-version="3.0.0", org.eclipse.core.runtime;bundle-version="3.0.0", org.eclipse.ui;bundle-version="3.0.0", org.eclipse.ui.ide;bundle-version="3.0.0" -Bundle-RequiredExecutionEnvironment: J2SE-1.4, - J2SE-1.5 +Bundle-RequiredExecutionEnvironment: J2SE-1.4 Eclipse-LazyStart: true diff --git a/net.sourceforge.phpeclipse.xdebug.feature/feature.xml b/net.sourceforge.phpeclipse.xdebug.feature/feature.xml index 9141e74..dea7a8e 100644 --- a/net.sourceforge.phpeclipse.xdebug.feature/feature.xml +++ b/net.sourceforge.phpeclipse.xdebug.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/net.sourceforge.phpeclipse.xml.core/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.xml.core/META-INF/MANIFEST.MF index 45d0c0b..9dc1383 100644 --- a/net.sourceforge.phpeclipse.xml.core/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.xml.core/META-INF/MANIFEST.MF @@ -1,10 +1,10 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: %pluginName +Bundle-Name: PHPEclipse XML Core Bundle-SymbolicName: net.sourceforge.phpeclipse.xml.core;singleton:=true Bundle-Version: 0.0.0 Bundle-ClassPath: xmlcore.jar -Bundle-Vendor: %providerName +Bundle-Vendor: PHPEclipse project team Bundle-Localization: plugin Export-Package: net.sourceforge.phpeclipse.xml.core.internal.model;x-internal:=true, net.sourceforge.phpeclipse.xml.core.internal.parser;x-internal:=true, diff --git a/net.sourceforge.phpeclipse.xml.ui/META-INF/MANIFEST.MF b/net.sourceforge.phpeclipse.xml.ui/META-INF/MANIFEST.MF index 2eefcf8..022be47 100644 --- a/net.sourceforge.phpeclipse.xml.ui/META-INF/MANIFEST.MF +++ b/net.sourceforge.phpeclipse.xml.ui/META-INF/MANIFEST.MF @@ -1,11 +1,11 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: %pluginName +Bundle-Name: PHPEclipse XML UI Bundle-SymbolicName: net.sourceforge.phpeclipse.xml.ui; singleton:=true Bundle-Version: 0.0.0 Bundle-ClassPath: xmlui.jar Bundle-Activator: net.sourceforge.phpeclipse.xml.ui.XMLPlugin -Bundle-Vendor: %providerName +Bundle-Vendor: PHPEclipse project team Bundle-Localization: plugin Export-Package: net.sourceforge.phpeclipse.xml.ui, net.sourceforge.phpeclipse.xml.ui.internal.compare;x-internal:=true, -- 1.7.1 From 9a7e6fb2a17a5348f4d5210151860cf3853df7d8 Mon Sep 17 00:00:00 2001 From: Edward Mann Date: Sat, 12 Jul 2008 19:24:32 +0000 Subject: [PATCH 07/16] Committing changes needed for the 1.2.0 release build. Removed addition of compat fragment in phpeclipse.feature.build. Also changed the features version to 1.2.0 --- .../feature.xml | 2 +- net.sourceforge.phpeclipse.feature/feature.xml | 9 +-------- .../feature.xml | 2 +- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/net.sourceforge.phpeclipse.debug.feature/feature.xml b/net.sourceforge.phpeclipse.debug.feature/feature.xml index 6cff413..89b7783 100644 --- a/net.sourceforge.phpeclipse.debug.feature/feature.xml +++ b/net.sourceforge.phpeclipse.debug.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/net.sourceforge.phpeclipse.feature/feature.xml b/net.sourceforge.phpeclipse.feature/feature.xml index 973fd9d..932286f 100644 --- a/net.sourceforge.phpeclipse.feature/feature.xml +++ b/net.sourceforge.phpeclipse.feature/feature.xml @@ -2,7 +2,7 @@ @@ -320,11 +320,4 @@ litigation. install-size="0" version="0.0.0"/> - - diff --git a/net.sourceforge.phpeclipse.xdebug.feature/feature.xml b/net.sourceforge.phpeclipse.xdebug.feature/feature.xml index dea7a8e..9141e74 100644 --- a/net.sourceforge.phpeclipse.xdebug.feature/feature.xml +++ b/net.sourceforge.phpeclipse.xdebug.feature/feature.xml @@ -2,7 +2,7 @@ -- 1.7.1 From 86d52686a0beaaa21a9b4dd3d14e029e9f0ec10c Mon Sep 17 00:00:00 2001 From: Edward Mann Date: Sun, 13 Jul 2008 14:07:45 +0000 Subject: [PATCH 08/16] Changing update site url to the correct site for stable builds. Seeing if this will fix an error in Ganymede. But then needed to be fixed anyway. --- .../feature.xml | 2 +- net.sourceforge.phpeclipse.feature/feature.xml | 2 +- .../feature.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net.sourceforge.phpeclipse.debug.feature/feature.xml b/net.sourceforge.phpeclipse.debug.feature/feature.xml index 89b7783..9020031 100644 --- a/net.sourceforge.phpeclipse.debug.feature/feature.xml +++ b/net.sourceforge.phpeclipse.debug.feature/feature.xml @@ -216,7 +216,7 @@ litigation. - + diff --git a/net.sourceforge.phpeclipse.feature/feature.xml b/net.sourceforge.phpeclipse.feature/feature.xml index 932286f..2ff836d 100644 --- a/net.sourceforge.phpeclipse.feature/feature.xml +++ b/net.sourceforge.phpeclipse.feature/feature.xml @@ -218,7 +218,7 @@ litigation. - + diff --git a/net.sourceforge.phpeclipse.xdebug.feature/feature.xml b/net.sourceforge.phpeclipse.xdebug.feature/feature.xml index 9141e74..1fe6b6e 100644 --- a/net.sourceforge.phpeclipse.xdebug.feature/feature.xml +++ b/net.sourceforge.phpeclipse.xdebug.feature/feature.xml @@ -216,7 +216,7 @@ litigation. - + -- 1.7.1 From e582855b00b5fe2be41f53715f00a5d83084bea4 Mon Sep 17 00:00:00 2001 From: Edward Mann Date: Sun, 13 Jul 2008 14:16:32 +0000 Subject: [PATCH 09/16] adding direct path to Update Site URL for 1.2.x directory. --- .../feature.xml | 2 +- net.sourceforge.phpeclipse.feature/feature.xml | 2 +- .../feature.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net.sourceforge.phpeclipse.debug.feature/feature.xml b/net.sourceforge.phpeclipse.debug.feature/feature.xml index 9020031..35fbced 100644 --- a/net.sourceforge.phpeclipse.debug.feature/feature.xml +++ b/net.sourceforge.phpeclipse.debug.feature/feature.xml @@ -216,7 +216,7 @@ litigation. - + diff --git a/net.sourceforge.phpeclipse.feature/feature.xml b/net.sourceforge.phpeclipse.feature/feature.xml index 2ff836d..6a013eb 100644 --- a/net.sourceforge.phpeclipse.feature/feature.xml +++ b/net.sourceforge.phpeclipse.feature/feature.xml @@ -218,7 +218,7 @@ litigation. - + diff --git a/net.sourceforge.phpeclipse.xdebug.feature/feature.xml b/net.sourceforge.phpeclipse.xdebug.feature/feature.xml index 1fe6b6e..2910077 100644 --- a/net.sourceforge.phpeclipse.xdebug.feature/feature.xml +++ b/net.sourceforge.phpeclipse.xdebug.feature/feature.xml @@ -216,7 +216,7 @@ litigation. - + -- 1.7.1 From ad1d4948d059ee9ff5615efa9de65ee1cbd805b7 Mon Sep 17 00:00:00 2001 From: Edward Mann Date: Fri, 29 Aug 2008 02:36:59 +0000 Subject: [PATCH 10/16] Documentation update from hudson build on Thu 28 Aug 2008 09:25:08 PM CDT --- net.sourceforge.phpeclipse.phphelp/doc.zip | Bin 10113397 -> 10113453 bytes 1 files changed, 0 insertions(+), 0 deletions(-) diff --git a/net.sourceforge.phpeclipse.phphelp/doc.zip b/net.sourceforge.phpeclipse.phphelp/doc.zip index 7cd926f599d72332eeaf69c34d3b3d251fdd8722..7ce8d72caaa4ad9f48aa6f4fceb8500a1f40a3e7 100644 GIT binary patch delta 634796 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 A)b0q|~cbc(`k~g9KG-KmPF%7onp_@x%0GNmi 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�n1C06MsnL-HZ>O_xpOa@28#WN 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�BZ{b}2HWJXIQ%1+qJ)&Xme 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 z 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 VXNF{c&rP1A6K(VP9Zkcp{|7w%5;p(< delta 633992 zcmZ5}bzD@-`@ef)_iUWA!0r;F0yY8?Dk6e{?X|F5!EV9sZc#wgu@$=&QOC|}TobO> zyyi8obrrky_dI8ov!Cy8U$6H+GiUmlXP%nbZEKzhA67pTl!OMnU@C+^-;raZG8CU; zSF>K#y$fhLLMYU&Q1?Rkg&p#xLQh7(7qx?=fsl*H9`TD8RzYIsXdz5`vFcS_L{5&d zo)gYtaz{f|sVaPk$XR9h#tU;Xd8N6cbRND$!AqY<~xwc!FG#I`_a#Ir|;SoZto( zWQKTGl#W6=f`tED&z3XB+eZ{WV!6ddiADEeL;LPd zPdiaQXXrDHy{yu5_zaQb-|H|Z9KaeL^ofxCAPGU@S`D%1g!b(w3R5wUB$ty8K;IA~ zd8Wycb2s^bC``e;Wy2yQ3h9WPYs2z+;X5Xu8&zIf22~+;jUFKi*q_WX6Uw;S-ZH_$ zv)&(^9Odf$x5*nMVK{!hJ~cwhf@%>Yt7WWr&gawxBHJDr^QvgugS_b)Zp(Q*uLQ?h zu`HP_STm3lOh^@l*H@KxLsf{Jj_Ygi%1x*#q)=dy7_m^H1;t3fc!MqT*d~9e z9ejbvdAg~wC=|lN(L3r&s~`zM+*3O_a#rkE!wZ?%m)bc&(lzJ@B4-P#SM&vm4ixb9TCEjN%NZX-J1PK`KXV2+*cDkrw-sA^89ozMV3VjJs zDU>7+ZfwZ(yrj6kZ#pc_krRJui(a^jb>;sRAvJ@}AV|~FdRtEH)j0y&AeU}d(>6$s z{Z==D@uV?#BQ>6sbKve;PJRwG-P!bu)`7iojs!I0>}0~y5Rq8E&M;-pec&byhuRUi zklr~*9>fX4PHdff5-eFD9g!3H#9L6ZA=x@|=%XOmBq4f|RLbs2hW?#qN4}!KSBRX9 z=dqkH11tFRWr%bPrU8*-_;0OFP;fDKyo!_#!Iy}f|6Un+VF`Zy^-X2zA$*A-4>lKf zeZECV_{313%xk~Aq%ZIpBIm=e(V~LX zzGrIbJAN?Y3VM>4CfZ2#yJ_w?;?wXIf^HLa;hb^-K3z#?)qM*qe8!vT=J&KOlyrrq zI2a~^7MFB_K@edINI9!6PTB;C2$IrZv?rZm)m;>Y|DY1m)}afM#zGE)6aqyMG^LEL9j}rzxm-?HMWavZ7Nir5!fhI`2a zNM7kg8%?UHTPFxxFxON?7bS6!gP^}v(J2OX*N_fzI@h+LBu+O~6rN!T|2ojnF!&ll zlj`Vhh$>qnu?=a$Hq#2I@p! z!4>zK+`RG_=+iwDd2pq8;f0UW3L^<^hEEYBU`2gT+H|mP1h4Kra&Z_eqZx7#)G}Q6 zA1Ca^R(_1sMM~a~h#>Aac`w>*l&&YQN-N~>SeTMykb|IK#_9+!T*hMaCqhOYNJLN| zsRyFE>&Twzxq3z(7ULw`-zg>b@gEEYCP7b2B|A_$UFypElYoTV$usfP+#k_seH zAav2(RNYRqG7F0R-S2zyd6==LCs%xY9t90L)gh2Aw>Ox(DQT89cg~@~t9WAucI^7nXun{Zxz8=W;8x%&+ zxDC2;3R{!`dvrCVp3r#&Nf~6c(erzBAWMG6V(0ejqNVwegCK4tlYD8J1G+>ebCKDH zfmHuj=<=p_59{7=$_*$xci+UuSAlhGvyu2)?w%z1PNqmcAJf^THc%IW+K=o06$L$# z>aWwVYFi)?L1WM8bWA8BHO}dRHQAF6JExO);W2h?(nT0_fA|_f_g~bt6lAO_V#d$} z1qi7SXf=pQ{=|CJg&%uWS4~@Zk~KlL)9Y7twU}5y{Qid3 z*H$p$Z=GEfP?jRS?gO`oho%v9^?luXfz5Qo$GULWOiz8R8!4&+5#e6I5)?>8w9X6N zRmOjb-)mq6Z(v;zM3Pm%yt68CfE5;hIE7uLztw&sf+~16R?-!b(b9lqld?N)lzRvNQs!K@k5Lah`OK z%=O@f518xc4h_wP90cv@&K=}sB$z8tc6VD13%8Plmu+Py`Nwo3>HmhEB(3371c{Gp zZll8;Toy0ZZ0p(!(3xguB!AG%qoI5EXth_WfX}P$ZhWi zK~sH+d(kil2`j;QX%Z4`Qi6-+)kBk{mxiGioSJ0&FR#M%VQJ2t6YwY_pUZO5Qgvt- zL3AlK?6h$pG@(p@+$`Iq3C)1~OFBq+NDm)UIh3G138I3>ciyq~ zd#1ptxT*-rD=OPa*u=UD;omd4;U*M7?5)Ht)C*s+fuKq~PH$odi+3|F#&xiCXvQV+f&q#3cuTH^v<<#SP;)D;Jg*9yB(^OVAzg=2 zAjrfKsWv*REw_UguHblLJ8~gXBPfEPgF12^dUmwU=*opktDy*j9_`8naqJX-)g5Rr z1HML(ydI$rTD=FikZH!`W-l&Cih&#iwe;qu@(LdQ9n5=5E(bwHG9usgBKM~!izMN5 zni&ULP#ewb$L-)0RHViqN=kVObh6MwvM6sOiQh^IWKK$16WKA4lci74DFoU1e1a#v zHIRG6E2!YTI~!PGrLIt+y#k3VHpt=VJ)n2_UPJo#YuN&tIRRZl(2s+;Y@L8o7TGcs zX6Fmkgdi!_!8ZDNC^wrEhGFjX5kP0FAO}JJ7{M9zf+x=QU*ova(gmmsLAmjq#UQ_j z5>5T%zchkwpC$24`V=LdzNRTSz*P7OL7PtFIyxeowPv9lPK&1UuFB)eN(Bwk+&o}+st7e9yG@tRuqvG-;=Z}N?*i|12TrIaLgig3 z>qU=T<=%1fW@x$2nyCx_1S&a0l0LPulicg!`UNA?)io#tT|toJ*JpT9<4x`&&p61f z+rZfmLJoq2hqv&i;di(TysGpP-2>>cHs2K=aF=-*mpa@do-}}#!pNK2?SZ}I)|Sak zUAjt?+H(K)m;=)W+Ih&9r@(d#Odj;nQ*OPE$y0Nm!-5u^#^m@egPlHk&J7hA^XZ(= zRo9pg39iuEkDkisDmgjO&v#roP2VLT$9a<1RVSNi)AyXj39qo-jvwKZ2{1AQajVzD zLDzod5)G_z=_ge0Y8-TW+T|zrhL_PsXX&->%^(B=a6FAtJmAZ=;oDew|Z_y6eWrYPKa>!kw?DXPkGS7qrtD z+CY$iN1hIP(2ECI22BK{dl9~pi)#a4a!^`?2MZ4xEXW8y$VF=fg6Jj<_NEv8_-UeS zhTOFQ-zuE|VoW93{p@I16v-`px~dlLh0hUmK`H((PI!SW^)JhpmPSG%f-Wt~S2d`{ z5^^h)FQZvYs46d$AMBowBtG_%o>_Az{*bR0T^ps6wZRh^6y#{<1rj|DLIJxSKX zx(*U#O!vf176xA-$b*NSY?M~x=ktPulhmXJUt8Jr%Z) zll?RGbVh4lah|P9+VT}Oy9&M5mVd!1D3lDlea3to=KYF+$uPMsiVNh&Coh@!TiCiU zf*C-Ngo+J3X{nAtNUBxwKwRfFIZ*P6foVglk_!uDv?X1&#;$+@2wFUmKjjo*Uvz;* zD-dBx_R97)TB9p(7Z`JI*AsFzrWYSw$wsq#@-}8(Bxn2aRW)f=Eeof*B+%mh`D?st z0VCg&`AC-uEURL18*P-rf8v>bS#Kyzkr(s`L9!AJHo9Oa?>@r`nh7}w`h5|<_pawddDVNdB`BZG~<=fwmANZ+&AgdVec_fEm}wik&dgk01v@Z|~&cFj6^0 z>~0{K0;>g`u$#9ruM8m+CiNwJjUc%{+B@h=%KsrUv1k8bs4o-xfgp`n#duQr2tR`p zc4J=_AA_FSAqPQFt)%yk@eKsk5kShHf^9qzau6iGq{*93KE>}AnBrUY91viC$U)Gd z=XeiZ@In%seGypJB}hcjLl^noyn<5FrhnT}H?TH*@g*tGJUmHRPjG!h3^XB;j!%fqc3F$4dcYpkP%Q$FqYf^EMwOjfPqf^z?1q zCusjC$M3^*`#~aN?*o2_lShqs45Y5{sO-o5ekaEr@Qjbv+#+=6Gd@=*UxS)zR6S(w zk5o>YP6yXT+}4VEvf%}9lbS=t2(%5^>9rSpUtXRF1uj+`IQKQsT?ToO+tE%Id#9`R z*Ilqo2s-gKuVXqdnf4y|uV$+{_@2+_7~9_Q2|822w&|NsKo07TxiX`X90{FiOY;1R z6d^mG6qU&MZ@krIyIA;*ugA+LpdWv1T()8sd^?7?|LJ32c)OB`7=Q5&DH!^UK;x8+ zR{6!xP89sxebGsb&yrYWfVx>l0|F%MHQ=o{8!KW+6}$)oC-c zkSM4Mb^WHF>WzYV7);)rhj~yH>e0UGs#(? zHXk8MTYQqpF%dyC{Dk3p0X>ey zQd+3u+NDY5``T$zX(5bP7kiAkaS1$Lw=~iRPC6`x*nl6yMgWh)HpDN0vSS3NxnD9bVD?6=MNdN&6E#zcklo0At z_K(aQ8$fSH2_}xoA^%1TWnFTJS5@IM$E+aFW1)S`kn2-TFo`UqOidx&m62FeFc{bd z?)w`|=Kz=$1l{tR@KO+TI5SI|2-T!4NJP*FO@y|R>a!r#+6XSE1sdr*>AW^VV_sPd z9beB4zWW&l8fqrlpKBH;ZXE<4=^vmV1P$*Xm;_-R4zPNn5G{R#Lb z@dvW#Nz(Sm`jWB5(`_gxX$Gq!m<!}H8(owp#7RuPzfE9&Y4ZKC3w69`;3C1x zAfplFfLwpxU6{t}Br(eZ>X5gmo-8lPq&ptg13?lZ$J^<$mBMXa7>ZLmW{nUcEr;nu z(CjsWzePcV`HhSv71n}9rBZpK3odIT4NI|Yw;w)3P-&;I*C?-sPe;yPRT=7ltDuG(Rtf^-Se5G3WrSQ||}EUe)Kv^bFp$AsYjF)`H* zv(Zt@v3I743fkQaN1>AYzzMt z{9HnAnSX`)POW3eGohT64DBM&Pi&_Lo(ccx1l);a)eE4t2e38>^1wLRL4UjufW51p zr&+II{}ou7NPd6OPVc`Kt}!PwIq(*8mqV=x5+B^%PTk%KnVgK~=7`yg5AKEOol3I3 zsyc|8B6EPM+C~wtN9x zrP>w`IBf)TY$Z<;f6CuZLdOp?5^E^il_@ZL2%?LrW~X&Zhz6&TziC-9&=n%#_PfPS z7nT*lVTdF{8U=|i4>QdS5;FuN>TOj=&VQJ;AR)F0DK;?EKoY`4t0oE3o?#+b;?>=3 zsQ}BM?Pk@))~Q& zFr$-T5D1zb1D#QpLp>Gh7yWbw25$5s?pa;zBw4N~lHT#6kMtZC6+vgki{Jy8i9_mH zS1d0bheQO)epJ*(ch(he>x4&`n_eH*r7zTvAP-K3+vu(OVhMqLOy1sb0uE^waxx4Ho>E0B#~a#^|VVvJLL>eCBmWgO%nNM4x=Hk#8*# zB@J>A6t?wc&WLXOoa*!Ad6FAd%YUIbNFW0$vF&;YzCuu4is*3al!b?g5iXx4L>bs= zuOVV(K}Nx3>D@P{gMl>#k(2{{y-DFnCeCWTeQ>^;5B)wuEXCqFNU7042?c>27z$;h z6Gn^2I0e1P_u~HX$%iSm_%mrOeTdmWdX0naGYtBKpcBT4oI!Qr6|c2+Kq!2iTbKm= zRm+=Hsr-M1M>Xh${y9|)(JLr&1qSRH*cE7YGWc-M)+tPOdWaHOz}xD{%F65%$bkkB zv~j99)H(PwX=1oG_`T`k2Z8CEU*^NIY5HdL0w|!&g(3VkCc4Wtpy*?6B8_i!NJ{1|uy}bfxVjeVzpv6{-TR6t4FJ_7H{~xCgT8#^?8X)_w6N5B|DqXQo zT;$|i(VN5&sS4DEpaVCFpaZKyt@{?SvL@8hge@XC$Pb7Hm?jjg+9^KdRSSOmW--%H=NU-ys)m5*e$U-Rw(l0*rBrAaLC@?K$2%>F zzwHAqRlpeN=zSuDCOp8lZytovcZaVL)c24W%z~*%gQH@Yv=kB%sy;#Pm#ZVtrANiL zPHimXq*%_Sjh#Fxf{}M0R+@PR=EfJwA?WEdVs)q4#CRUMp&iSr6Qj|2aT<%=BiAp& zNHv?T=OwYClUy6;LSHm;1tGvrm*k2^I5m=ubhsi$X`yU%*%k4;)5_EL22h7)<$+?J z^u!GjG${1jkkr3nLw$xBN6^!Mi}8A995Vm&KgDRnf5gp#8U#bWJ`p1|`zek3SDeHP ze`8fgo{KS3M;I%DaxcWKqKppc5r@QO?_r6eNs#J)46XaK&4i0)iufNL)r?9nU zMtztR4qZSH5b{0gbEE!0fmy`u-a; zOoh4-biGagUSJOE72Z%)DM&;Br}cKwr{4ONI%fHpU05HaSw85I!ukX~3%~IQfciq9 z2!dokZ)&HV1N7N~YJBfMV$1LpP;@tufRa@Tlc?HE`7F>`CY-tA;jCyAy%4GgPZY{<3oGiQT>K=iq8@oHos8Dc(KA<5i+Ftvm#b+-y#9-GS1hds6I-w==&f4%C!B&N z`S;uR2R;VoH`JHtb``aegh56F+2$1_k^H)PhgO2<>K3t4|9bjIB9jHB#`;LjhsgY| zZ5!*&EGCZhY6in9IKoKY-H|qWu$g`@C)iMw8`@GIAf1MJN6-~5^~s#7cs`9R_Hj0l zbT1Rh%Z~6`I5|xZB0{UjnFCyDofjwH9y&vI_3pY8Q!q)t!~f`)X^FW?k(W`6H5 zX|4x^O5c4$0;ct`k(l3@{r3WVhM+$?=}VgAzhDkh-6+X}<^D(lD(dW{W^cVK-iVQX za&P@*fo-Fj1N3FJZG>*0qBMPg-kp>2h;Co%-r;UAf}SM2LbW0!v3Lvc*fwB$vf!L% zM%Pct`mQ{)rFR;lub|n|>Ea=Jh?!OWv^_^ch9+;X9;ts~V79>2iTWxo3Gm`XeGy)` zk5u#D6n#yp8;lM?;<`@tp-rdi19`TG#?1g)od!7wnlnS++rap`f4V+S>H&!e+ACdu zh+`&0qwE_5p3s-lLZ9jO6Z$vK*t<37^p!L=?{YLy{dqk&yFHMc4qkv^{SF;O z(EJPf%SQEFZ+`ankiM`O{{T7dmTctyHNA%xKT5w|(~ot=e2l&YyD1C`BWTVoJ;ZRK z-H$ZBtFJ0$1II_ujJx`O^~`uP<}vK1X!sgI4?fn%ifsRVe-8X601^>2^o9O{z`U}* zUc)#{kcc2}7B{iegna!r1B-vqeTI424><@XVm1D(|DA=y63=h?Q0-7xbwqOTiBg!3 z{-&R7`$HeY%NPN@VDjnR zQ=rT^@}P?m^`D}OHAK2%c2FLtvwaPHcoqrvrI?|b%LxIpa8cU9&)_An zXv^Ux4B^r?SY8B4I^5Ate=lJmA~W!G4m6Z?8F-Saw6f9Ffd)?tJNpk+GDNvV1~}s! z)IHKLP!w`;d{e3#%1HH~s|cD?)lk{U;+0<2f_oNoAQ3^sYa2TA%5y03`6k}F`?cL-y-Pk{)Sfuc3xi^YKYd(Yw9-45F|1ZtUlUM z#U)ox7;OOVq`H^9#v5Waai1KgwQY3Zc*8A@?YKshVBHTuBM3Tel3^Ps^s@A4kmsHBqCJf*xvPqPP~wTnO!!){>X!!gCK9NH?fn> zlV(YD`z8apchT%Xj%_i7xs-{|TMRm9@Gu$ zi;+TP#xFs=GC+Q(hSIK%zNLmXA~QNSK5Phf8J&}Q4)vx>4jW$Rn7ef5QA31gsVBM@ zEo}7KQA4aj#t9lQjjQns7JWE*@Q<4vVsOV9N$eSehilG~E`d&*e8%vZV?untb1*7R z>R5Zu&`4BJZfo|(+G{mIl=$inLGwlJq)C@_HCnVl7NU{4hL!?T8PonUG<)J|3%YAO)JE!e6@V4@Jz@0J1NY&CKZB6_R1BKLaD_9{X< z-7$=IhFRaa52G%)7(=}t7!FCQpL6GzEho^=xf7yShxw4|Gh;;Z^BD}7V)eKlpyoSh z$aBMMr*Yi>KiDstaU2}}l8z+30-m4}N!V*x%K~zy$*&D5yo>>pBgZ~kJRB7MTV&#| z2)p;t0liatcXKiGf=Ei{0xJK`FjUV@jtyT7bzCQhZWI_uq_2kK9E+g7_#OJ9U0iVM zZgEiG9|nm1!wtOPl2l3CtkkT7C>sIoRzw!0aLq6VhxHO_bkx^a2l z>03*Q+_kVbxnHM)p3LpdtT{>0EP}k2i+RzzWh6MuCt$Zn1W7^C4%n^;x+O@mNitdw zC+yoaZzxdiYVx2u1f$&pgRXQDK0(m$6{P8cOt5^?+A3+l1vQ zO@U-m;*}@~g2*s@dUWISL+YY+#ZI#BI($ifpL8!2=(j@W5JU~AI2t3>5t$X!2&~Fw z#Z;w+4mG5W&NwEiwp3P|*UW_04%(=;G?Y^gL*G{4e*M-0O}&TsfX_AUg(iz|ve8eR?e{wv}h3FE%s+{c6L-9F7K?S&EulD*K~lV&uM zz+Ir)G}99#mrawNPLRGfQP525eY*C;ZBSEt1Cuv%>y8s0y#@|<(R(IThoIk9Nk=(m zCpfZ3D($ipyj&yg5*54~HL8ha(_N^|7lQ8+JwT@0B-y3uP#8hN*Fi|<>rK)fr|CF% zD@;oab^%B<-E(1wjah&9$H4w!~3ODqKq+B>nDbX7J}`c zni+7`zF>k43>pL35kC+~pDXsoPV_M+ECBOE;{ zpJ-(?mePg_v4+O49J_il(P9j8T|EJ5-A>P1j0<^%hoQ!uSy7@m^!cJfCia>DT1m5( zqHTn02d#&7LeNES#){6M!d$yCRy!=H!(jwZ`Ya@%$-pRdbtP6A(*S`QYqs+7HX_)E1dff_U0am*`@FA zPnXa;=_O@DT?mpg41yX?1{xnY-TfPbjWL>`7f)9oDux(8aVl{y3^PVav!ED)1e~4Y zpe@6U$9ds2cBODdV>zh;w>YZ0Xe5)BN zxVTHJYR3A`eX%Cq80Oj+%Rf!^qHp7k;5$@flrGeQDeVQ#A*g$8V=S-W9?iY-#QGMN zXTLj(z#3T3Xp_#t3?Yy(9duR(8jU##a15~voe7vD3v^#)I%r0RkiS3Pk+Kms4CAZV1?TrPoi3d8v z!WJ+X65gV_jam|oXF0a)H@ZOE+On(nlgf5AHsDpa=p+(QyaBZ1PErm|bh<^0jAbfx zJWK^bjjAMmU;PdATn{4zUZUZLxc7x+I0)GYros2aK{My#sJu3t(Jd z`|r7UA6U#P3`K%_BVTML5<8BycN3-*L7|UeM8^|`^c-gVpCB-}rQk&m4Kwa`?!_S^ zjb*gGNSdAp7wO)S#szw2scbR<_HhLC4ne0(Fivu+jHYR@OqxUxH_b@REEMBghOwf{ zH(z<4v8TwEX*Gd{T0u1k3L&ulIrrhvzo)G(4_X5UaIeyZ3Kb{EI?i>FSrgJd@C?p^ zks#>ACB{7>^LIwCf;~|cszA_jtBjtKFcOEkXd@8kdiWYab2l2hx-*wtK72*S#=K7X=J*CaL+xa82@nXmjHtj+y9^-T?*mfPNr|8f zS~P^f*r{xVw7W!LoU&2JH{$@kybvlcZoU*h2`WE9lIj(MI2Nvxk!;hM6zOkR90bX3 z>A?kRoml#Ztp~dr8Gnt+;D>&TFHC1#8?LDlfb{tdt ze|I-kb*cRZ57VDc{qT;%6z7V<2KCHFqdZM|UO@%gy?FbpXQ9inHj9GLNUD5jlkPMcDgsxw3L_eocnk2vbzsqwBS_5tLC|{TUyD;U-MMQ zk#_pwU3R)P+Vqd0UPQV&bN<{bP^L5JsU8DMl4I3P7MFkPuj;190<*0hu4SsAnf@?@ z*G?_9O%N%FbVt(bnZh(L06kmJwA3VLL56?+uEK7>*J7AGGWV22Pkzj1Zq@%_2nYhl z3b+NDo2*WQ)1_9XD9znOmDZ*WA~Trn?_i42*ggHx!2~f17{o%t5~2A5zD#>1nl=gw zUK_JTkG)YBn%@tW-=eZF@vqxfB4g$-I^PBx2tib}GNrqz4$n+N2YZ?7xQwvso!BD1 zO_h0eZnW-aiq*~yHPmlsKT{H~YW;=G&Hfn<@_=k0NgV8}xFT$;cyyL%$LXeAoq)k&Bz&f+ zvh*6313}^Gj3a`KF6&yWyL~JMy}Lwofk0GE=9-FX42wB~rbCi}1qyFm0PS3YHW2jg z0+S>;V;PqN^>C1gAP@rSMG{8#m1wOMrk^?)rPp>|>*fuFrTT+WN_t+Pf%I8ra%ciA zyT7`0m8n0^tge=|uv0ceeFzq|(rc}0g){8hv=K<6z&1c@Y&5w!qd8h_2NqLsbf`}| z&~@8Q%LHcVt({{Eav6Fdmas6Lmt$(8XFBua{id>-QI$Fln8JC+u75jhigdB-8HY_* zIVL_P9fMA4;$udCh;%x9%w#vHp*R^ue)aAIWBy8XV@iR62d^h=n9o*!1q=$oM9$J@ zO%OJYM=P0r9-1mRMKM;!PH&z!ZE*&b&$tYHQWMzDUpAHD)i-HcFW-FOIyCi{g}kvq zu=9l63_U4)#bkBe_X@vadd4$uTkJZFQ`6%bUpLt~W(4VR6Bu`a5d_1l9CX)B({zDt zoY=cSLj|@}c8P2LT@!?1AIFY2{Rg@h2tz{9`Tv+sI4ybY{)HWd=0*fv`L78s7pZs4 z>%D;bz5_iX$eX`rfq3`A)L+kTWm(>us=01u<@bv5rhVR;s34;`B>7>7e;&bj-w^k9 zH63K>B6el1Ac}x?{bc&+jB@Ds4LJC6Xc~cx+D3PMGl9I0F*1bw1Ugb62SG3YGzByH zaltQhl*R_w9js>O<@Mn?XK3gQIO$!W<$+LJop?4VIQLgA<)a ziIy@$1SG758YQZ({;X1Foq@S8(}K;xnoXLX3^s$Q<_A_fFw_jf8dRv#Geq5a(vzWP zcy9rfQ&PQx*%hTjz+7vmsTIumI_3|YPzeU38HZPnZ01dGRWd71WA)1@sJVc0NK$yP z7mcrC{_G6!jg2)&NCga+{G6WbMd!wv!LhCe*|mu?m(wgI1Y}oFx+>1x)p@7GP}5vm zdJIEF&`LGU@lFrjsNc+$G#aP$H*>PU46s2>U}cFqsZgRv6Eo}zRr`6<90pjR{h+3*LOERl$dFK&H!^|O?09c2AJWA zDb<$TDFrgLp)5}^|H)#!LKbfiX%AxKSuggA4#aplT;W~YhL~Y%s-B@@qk)Vx&rtKx zW-G5g!!vBx{qJ``#41({xe%O>d%8(v_BgZa9UhuB&iq&%|g5~)z3IetujOZy9q*_BhF@~iM6f;LJu zZZtW-l^lb22`xGGox%V#|S})F)XYxJg%K z_=qHV?R>DbE;UHi;UB~f8^G{Cx6N$LCkQ6ThGm<_iR!~4&maH%ttO1_f{BHHfbb}g zS{u@fqRv(zJkoD_%`JHupD6lz&o_2D$c-Fn+H9_U;nGlnq)%BSlARlvOUnXnAV~a! zo_4zafO)F(x^n1Ib1Cik+R))B1craY=}0^cG?xJ-5EQhi{hT|7xL6EsH-aC&P<&?f6Rgoqov&H<|3KJFMql8BVkDXo%=P%zkiXhzdQHUfTYjQzJBcJ zcWB}3UxRLb`fZX%v+d>Cwbu7u-+t7J=GJo?R!ra7DzkhoW5%rKcQ@oU z+2$A1;$-Lt>2&cG)8jAnSoMBc^E20qFKd(&G{fSypyT<8<4a~VZSdhxhd&p$&TF#I z|Eno#d9Rw@-d9U5U)Ai=!jJR&^ffHWt26Y_&d#qoc3gbX_x8*7zV*F7*SRol_l2^% z0~_t?{b$*^vuEVDYfFc1sGpFrgZro5Xx%~O+LZJe^S3AN3|`-))QkN8++Njd<#y!6 z%W3`@_YZpS+;@6#V9Qwz!*@3xKkIm8O2)g3I~RROUHjM85s^*jT{_)(`Mu!56wdZSbk)eAZF}e17;f4NeYFOjb%Z^O2PnNox zia#7&Q}}V&?=oNAN|NhLKa{?I)0&Qbj#VH3L*BDs$e=MPU%Jxu%iiWoTaML9IzM~X z_&Nvp@Rk|fs`Tmj_1&)3*{7aPom^__o8KQFC^M+|%*T_h5ARw0r9XBq>q5@eo89i% zlH}%p&zx~J#~Vw^?@gIp+GGY1pXNcZ>BHI%j-jRo_$P0$Uup*Uzuj?ka}& zo9{K-Ix_Tou{RB`Tz~NM(vc0PC7Je^XbW#KmR=R;d3d@OEqbgHQfe&1C7QoV!Q z%in(aKWWu-*|R}=-8+}d`y+Vk@YAzGy+1bmH{GMm+%3Jg<%hH#)@I=8_Zy$TZta2eo2mJeB1gWvJMUP}207=mg8CbN7gGCg&zV`a z+}eur>D_Nt{Sp% zU#Sj0yZp~Q4+)=Jb!X1}%a^j#gQj+9N+xc}$SrqoZo->Am6wz}Gx&JP0Hyn3vSWOa zI(vIBOCFQ-D?PjSr?0onP4>My5}AD5+d8!UnKC!qJiZfgzVM>Xhig2&TWxLQOD9TX ztgUrrZ0_YFbE|nr`8L^K?M~_@i^b{8MPhg(fR~ z-+Zch`(?e+hxtFd)!4V%F#Ge#Q&(d9jlWXX{Z~M4rSWI--%bCXzxBrz`CGjaVeYx}Pt6^8 zro421X%2EJFY{iSpEz}fG5K)fX*$EcO=h0fvBPNtmJ3&Jdr7&2Y$dn3lvcL>W6s-CrpPX7L2k~kdDC7 zj6ikLzUL3i-+C7Pu+d9W=&&5W^8y=3{<>3M%+vP8MUXThj{U$0){c=&?$5S?@X#sUMGUBu$;a>_OR%fn8O7O{Y<7ZrRW6t|RgX#-)! zEe#|l-HtD3iO{0mNPN96HhQ6)CEh8CxR(mR+j1j%>? zQI%2Q76{8xy&Z-~D5kyjRVUJttY=hpAjT4==^pI%i$2zpn%pDsWUg=$gis zYXZB;JGMFWwBRN$J=EM1$lgCB&stlewFeMsP#eoYXPEqo_Ap^pU>y-`2rt`PIy<$O zCY>$8QYFYi(8--Gtwd(>zS9jROfz|d5jNJ@@us~jp;80*8bN3DvVcPnZ;6v5{h-8X zNJP*#{Vec&%^#StV8H+OK(#miGr*G0$*4coom6?3J4jJWn2Z>fCY#90Jxn6fw5m&` z`vlNyDHhK8&fo1JK!)33B@wjnP|F?teVSqUpNKcyd$iU}3l$k_`Zd>5 zNqY~J#-v%gFoWTp@?+de!}e;SS08R9p8HswK|xGBhGyF6r%Vgn8d2j6{1?I~G_OME zg%-Gsbp>Z~;u0XoM$mZ#-M_?g%xP*IyAp^d3=$DEXC=%#|>y`ZFKFLD}asdwyKv+Jo^nE+QsEaYy(vxNPOd#Hrjua zWw|rnN!e~G?Fs~m*=~UdYSqJ2B^!9wAt-`in*a1{3p^5ncSs^Uj(cT6V>{e3A0*gG z^@Hht$bK%s(jsWg9!rkXUHNW5)T2dmls{m3<=kfehascD9YVk{?x4wsEp7EI>fqu@ zOI7VA6@{x~a1jE7=*W`OFwt7b+|ARLE>4em^$W1jGoiBxI^u$*k09eSj;*75FF~8o zSLag*$#AL0oM&pjdWvcsf_{2sS&5Z8&V6k%Q3oUD7zkk7~Ngp!tC`6Uq`(!DjooVb*i-6CT zHqPT?>^B%%OK2BCbG}*N4Lj8A7QB{2HN}qg7`81?xN4NR$H}gnf9jK|G>Vr!1$T@G zEA;Yh-IMV8*JGeBKXQB~T=wWOl()M~M6mS=lex{hdedVDc@4WiyYu|$e$%1T^+`CEiL6JEnJ(vXer+lSmfxXc5)fl1B>z25C~swFE@0GrHLJ7 zSIiYn?Ecv*7^ff$47riK z(i`^25i<#&?FGj4QngIv@&y*rR2e#eAZn;+|1{a1SFnq-`&TWu0}jq|1~T5KXkk+B zA`2cWu%^?4^JEBYRNr=*umFgECscxfBPPWT&J;OLQ2j+2XJ1?&3v^Mv6!RCwEs-5s zus-d$L{8H)gM0oeIYu+M6Lo{t%aU)33f`93-!bIRdoYHFM)fH{5_Ybm;I6$T_&c0AIyah-q6mk&w!n&Pq*dp(6?u>Rj<^M6ItHRNaoibRg)t8A^K;7xeKKX?n06d*`H6F0=myLlp?>wNC~; zMm5#z4gn3wkcgnw4#|BDEJ%0TNvOXQBqEUK+UUEJ@;e>7gZBIs3<*Od5$eO_wAN{P zgEK_s^&h~m@$n=CEqzW76&Y!_z5KtVz3Q^uKwwt#*H?f>3#{bS|1TLHOS%dK01x2- zr)dV&AgJkvT+XQrD=46!RE}i@R{c+HVu92pNTiMCV&%mh~ zLt_XQrk3|vJ|?QKn4g*_y?+YzUYE$5Dm6UGo}aQ!bFh#%9|qa!qo48ll3k!a>$9OT z%ECX1u6s!^P`fF1S6>JA0mF6g8VyTOUw7q;j%n!LHYHATEz?As0?x5(NE=1HU?eS| zGYHzkOF61%A%9-Qlwd97k2WZ#EO+X^Fa4Epji_m<0OhE26Fx1axc<9tk63?k%GwfJ6pEV+EQ79T=>P zb;_3c;V>XAVoiM=ut9_ZFZ}+E#a32=&Ub_nA?TG#${I7~{5vu_uecLFHMH$~(__Lk)%x|!o|B&!iz;^ro%~X#;P&tCa1411{_Qqv?SEY(8 zPCmSwaztRd_`6<8h-KF$^{*L7;%FekcJLvB&KRvgu$dZMba_0CvN|LpsM`c(p;LO= zJVkN6dQISE6g&MsMe%g!r#z0{N-lDS6eVNJ|=WWn!i=bDUJpN*l0%1#N z{C}L1H*Y5FBe-yvG7R36@PEL3;05jg_6+air3$DzYRJ{V6;M&Z5ly$PPXN)Iry2W@B|J!gY z`sQZEUFr%$LD09Gl^4#y-Ur(i*FRHGuN}%|r$OQQE+7XqCLn0>90hI(sP~{Z?p4Za zCI~eIgTC0S4Cj>V(DtCmuNQ=a>*`Pu;y$X5r(;O>{w@twQzDk`S87TsZ*I_T$e{T! zVG$&6!bEtv48u$kKaUbg`A6({oCmEVXz>%udgo2-3%|pj3x`AmHJnn?oL3T;`~l=( zfxW^oL__Z*nvU?_s1#a}3J*;cg{%zUL(*TS5M zF1@5Deez0a!VA-|Se3UxF4`kT_$M=T!dvB#$SfCepMe=@=NtT?gPqR!tXvc1+fdfs zVd*gdHm?tQ=p1Ci55?QH*H-;dCI||0l-27K2kZbT?pqP|0yNySFpwtC*kddOjD|f4 zGMuw+*E6js&}fa(;zx=9zEDqysJ5PSZr`RBYelIx3>1NHXgKI?p3cbQb0d0TbP7us9 z&~;U#&-1tb&oYG<8|F!i1Xy)?_GU#u8EcsKW(93q#tJr-^*Gzphnr#a6&WIySnnt~FRM*6Plina^5U z%ewsUKCP@^3R2(vAKxA(;0SaUK~J`~me8|j2A(HbYq?l+WEX2UUJ!6YuIO$pBW-}M z5%gkrYhe>ptX>SXR@NfUXt`u-CB6DgZsvKuJ86SQSs_YyJI?Bs@h~h2nnTdrDDOiFC>T> zHszO}Dt0vxVZrf;EY3#fuC`WlUi`{k3-euIF2twY;gzv< z*3(X-lciQy;~W((F$)PsMhTBTdd_>)@iiqnwJWP@ z04Y3RSE|yFTLUzfOZOkQ0&jneGw*&12Hqd$6@iu5Y1dQM*LoJ*+3Et!d=1D!(6kHI zaXfQ_xaV3cXl@YNFxT428Gf?;n)QDk5Cdm5a|fAtvALb3 z?N}_4CAY1fu6ONf-XiGumsSWh+l?hg<^yHhArV10=UX%NEF=CCEUpa_5p=>Q>m8@Qo%9VD zZ5SjX=+bXi`0p+Cpseu=wv~2J4*X?pY-X(NxXG=G>%8X7Zp{oVMzM{DTdXS*Wx0pj zZ_c;ZUpU-c25nl}(+y-64BjPMeW1jDAn+pS8y`1s=igt*McvA~9`yWK+E1q=wTihN zHKBq0?1pZueRz0>1|+%r$)b@cKbd8ufIMj(Ker(EH&EWKbNjV{=L{Y2tm_1Lk7#Fg zlSmd7cXQVQ*l2cfw?0N@&+-d)3v@kWnGo#O)SzHw`jw?k-t2{=ZJ94g^3&N^X!`jI zP|I!TI098X2mMmPEysDqYG)O<5G{_CKCa^SOQ-&&A9-5Ut*rK+e$+e0t&K&&JygX$ zW9AbO(KZK=iPyrs7RVXuEAyI*XnQ@k&k{Q>HaB&P)Xd%N3dpynZoE^F;aa*yxc&|$ zrls2~kp<75Yv)!@x(LgRpx@iM{V*^$*^e$zpC2S5;O~*#Mmzt8;6N|8N?I5_3uQI+ zc01sV#yr~}mQ|C~2Ttozp2S7f5NM?VZtHX`H0*7)knVs*Q#vyZz)83>EBA zB67MFcJDAVzIX0T!hX8R9xi#Iz^X?ETzB)Lvj)4F`2WY&SH?$mZExRXW|E0bGVUG- z5<-H8AR)L*p|}Khceg@uNRW-S5ZXdeJ^>|v(#)d$fBVM737=%dUa^RN_E^n_~G){u47i?Oqomud=_CRi&QzBxKlpx zCj8#fws87HHN8G60Y)xQ6c{%)Az6DE6Uc;a8=C;GSDtj6G8wB}_CWWWoPhg^u_2L* zQ}IJj3=|V;o0f1`tz(yX?CB#{E8+48#xBSKdHbhX2{vVpkausRWoIX(OH9ava#7Q= zFJ8ceuFFlh7tTp~U009fG{BI|Ct0sLy2yrC3!^Mud-Tp%reQrEU?OU#JYJAcUjlSh zTAZNx{ppa!3BSgQJm7k(Fo}23JtlP8s)VLm(ZyRE6EbA0k1_RIXt_-Z2PBB@$E^uP zm4t}2Z3#dev-6Ea@4#v?qX|rCtsM#DBYCwxa`MN7Qc5uz?N13KBGe<<6O(^QD5(7& zUuQzM{gQA&;zpQpBq3AwRuBZ>?eyW11g*$6Anm^DJ|1I%8v@QbQEBSz&!g1DdjcCT z6n`dgC>d$p6A9y_<$wA#_E#e`jS2mDI^lA-NW8v!4r9I;|H*`!&L`MJDMpfd5giJ- zuP9dAqi{hx+wL+JxJ)~{_;Nydt#F_I@n=H1>^`No+X=v1a3gHMT|7|&?`I;^y#03* z=4f=gFb-=Mt-Q(%z^Xd3|9pmpct?zmAR`_nI21CZ5Cp>zy- zdG$eNk?Pg&*9fof---Hs?8)xMMi;GFKtC-kjzJvH{8fJESj^cF@;ox!L=v8w zG-OkJ4zD#b1#`@VCM4Ea>AyHRs9{NK~J)j{R9{O(` zeHl6A!>UJGX#KkSB@(RYVFS#Xd^i?psDB+PoL|1?Xv0#xkV)<+6Ybwz-$29bRQ~si zA2S#+;5ET&z1ioCBI5^da;zWUON%f9hD&_aau(?b_#jvR7gfIdm_+Pod0&x#gKpv=+wg7QM6 zeMak@k>bppIZ0nqRshM|?5SpYb&}p6A+D6L>H2EQl~RAY9=nt4tt)0>6NdCwHk_|# z>8nWLfr|6=C~k&9W3qbaJiX+58@Uk6IUE1Sgo084uCx8D)khZVizw8P|1Q@5pcZz? zmanlKTi~ymh?E=6a{W1p=5EI$?)BH|E6J`nR+y8nUaN1W5~^$1 zMm!~}u2~!Pv(!AlwpH2RTfV}%FpX?U2FMxtwNWI)E-va>_y7}X*``NDFm6Bicjz-@ z`++R^H{C-g?9d~TiaP^N?9x}1eKs^!(PDaK^9b=ObKeOho4Q ztY7u3BKXeB=zJrxKbHJ2BDlu0;?8#jR7(?kU6!dy$1+C5vtU=i`;Jv8_r4K(i7Tw00k$nkQZtD-JIR9R~ zj^(=%9HxI6iT<`9Ltkl0JlX6PM^h+7Oz+*(uTkrmVIIsYrC~sTR~*%1AwN9Ah6&l} z#QWQ1Grjdl|ECo2J@Oo@@c;&!i6GcDzR=&2uEjU6^vUwINR$83ua#)zF8_<+ll`BL zw|elw5w=(_zt^WKN&SWo`mLgLF*zD$C?XTPiNK03-0(K$YG`y!7s$@O74;Tp*FC?;7VvotM%linyon0Qge@J2$sJ*jC(Q+xzTwG3^e#9U8pj0RuF{$WCYY;341I1YcV zT%|Fqq%wfL{r&v zN^XrY-iOyS5iA;`TN{u-vx5B^nT=Hw+Qby}YDXlmOKexHixv116I#Bjp|u3QS<(ZY zY=-}2LNE3(z;DTS-__oREcx0NC`U_y`=2N z*I!~XL)nicYwHML`=%P8JU(RuI%@_t#smxv6M}5_;)M3i{)3#DX*e#1eDN%dL@0qr zI9VUhGC;pzj5K6M4p#nDJj;Zh$T3V($1%r8$qgNQ6h|xj@zPwR-$H|3?u_8;{AQsc zMWy=%e|!4Y9~~^%fA`I#@!s;#9zRTrCvS=h)vY+*%Y?d?7z$~`tzK(6=AbkFlL?)^ z+~AW=uZ=6QKIK8Uz0%M}%}M7A&mU8I7EZ`D@nk{+6zUkb+F(*h=W*v5Y2IqXOtqTv zjgYkUSY#o$GVQhAFgrrHO+IWzXLsP6OlZYzhTc+I+lK8}v?04hZ1a!X4Xvd-{kA)? z;Je}xCUoUa1F&aYJE^k=YctdjaV0I;W5|%`RR7qIsgbEZ;|~~qRq57ZxFY@~=`6GV zcpN$K*<`b*ofCD)pi`L6c)6+)hYWg&5Vz(re5fG4&V+t(%+NQI`}PiGFDQ8&cl`ZG zhF-Cd)YKeaX>1YxjEN}!Q0JWCm{h&adI3WdI)5nKX}u(8|Ncw(0<+_o&<~dk)=2e4 zwm@vRaAIx4US`5hEHmwO%Yf3ieEDs=i#|@oBTN{Lo{@gIYv?MS+THHsYqF0l@4f-S z2=4KE{=`sHxx+ZCedbfcQH=;S$GpNP;Ha8+BnkMSd9uxP6Urii&4d^|}~$ZzC3N1FNth z8mWyYg-o@#+6cpid*@T5jhRX+{jg}`Dvdbk{RzfWG7w)-nGT-V%0wq87*SQ3$0JG^ zj0z5mb}|@ozjC|JZZ&4fAUC2bTHi)TT8&3kx@qWZhsm4 z{c~hx^>!L{3TAYo)A&4=$2`YOiah@gOQA0-X^aQjC#gyDZoiH^EuF(@148SR{#3{q zr&62PPB~N5SXz4o!^eciCL4#va5!mdt+Nk4!{{{uXb2&U>|Lef$@((lI@*OlWkOGv zHFg%Hk16|pF1raU+9omN&D~okjwF;73QuVMg^fO=ym5nCsPGjk8;i^Npmb1WW3pPL z!+ulESVwyk%Z&+rRn53uDs8f;ma)7Xxfh%dPih&jY6SZ4bOU1r8U4p0(&W+0aj~>a zL*qS(v&G*8^C`==O(sYG%2 z^3#oF6i(X_(~YQ&&R5c@9Ah~J(Z>xqf36W1B}Z9~Ux4Mb4im$K9$R2^N;l|#7a8+a zd4|=!TB^x*bO{<6N(oUWXAd-yPtD6l5ZghcO>-(vb)hwAZ(;)I{$1g3WAu}tBP7Fr}n24=#=Zq1Vl-v~QbHP|q zIp4QlFjkkqHSca*a zB~79C1I)I3RP!Q5yB-+JYs8{^^AtPd1m4AjWmQ!g>wAv!1;{ zw|H1R3mvUTo^OS_1~AwdlJT$6pp`j}n*M8SBH`ZFeK6)@y}tXwm?ssjnh{|tDaXm^ z;Rw@j5(~-lXp_Q4POn9qHfaRJZ*GFAgyJti9V$D$onRWH(y^HFfK64F&A=geGJ<67 z#T8Mqy0{M$G3ZR_Hzw0p;X1})p!%`ZUoElFj=BY(%$({u9tQ6(j6Y){Oq#E(rWR8E z%fD_@s^W}I^OypW-2YbN?EE=HaaNWT;oi9bjSx^k7-aY&IS>VIm$d~CR20*}lqvg4$(FP_M%tx=>69qZJmuk?5A3#TEApTgo3)yz{(5(i`S-1tu>j0w(22MsnIj1cth8Kbc1 zrr;MQWWrjMv6?)}bTd-ics(YWD(1WKEGTe(aFQuaE&OwDzBDDv{y9+B#@Wb+C5<1E z)M=(o!hXFy%~VK1S{tXcesL#E;aPZbWqgu}P^~7+GC>>Vme;}@Y(d%YaW==)Rx0R_ zHXlDs#v@E^F>@al+7vZ}RJ24$Tyq*c& zveT3)#diPRV=63TscC_|ro$>x7vbqXtn$P7YbLbNep9h1!IjbS7*0ML{*wuvf6UY< zN_^wL=P`((Z;%c(!hk~j)ihTv{BXxE;zP2Y{`R5?JX~Bk=y%1GuEdHrT``?f3xj<8 zO$@Od*w}j0lo`!Q5b`z;%4CJSz7i!f6%vG$rb2NGN5h!Vk`GOLg~Hsb#hcm&+bDr|lR7)#Z*hjuLWyra3;xs+;+B7vnByzO=i1}rerI?5ky9pax zXz13Drrv^j{H(Hu|j#G1j(!R?d%@#Y$emr9plt|hsA zTN%xz6_+nDno}eM%rT2OSw_GJW)QvAjN+KwDWZ3o3n_Du9&CPi8B22_ z$?jjnobeDgAp~(Tp@^ z-h-8u&Bf#%Fxp6+iLJ8s-KPUhH}; zb6LfbC%jWq9QPLTbov|mRvm=*b%T&TObyzCekjLc)Zo1y(Pp8~no z%bcnB55PrgqZN9a?J9v4YuV3SQO1gqvpbz8y0xEqakxO`G#rQ?Wuehb2uHIm9cUgc z<(4{!nNzeIu^O4s#>32~BI5qVC%b;UoPHPMJ(@i40B>dHShGvMi)g2@X5jJoZP9*$ zxr%aIteIf;s{}Ue^cNTwh6`gtQj0V&QO9I6Y<*_V9EVo1tvc?XSYUoCF5Gz17 za)!+`Bhivyqdn$e;fAhJx^|8^DpJHJ=tBGuicgTVd$o)-hM2!m>;6O^S{ZEx?AScT zqeMOO{Y|P_N%4;2Gu_ZECiMMMb5SW&UvxQEaWVWS6WVUM`C5d?iqBky*$Mf&1VQP7 zRc5VJZ8UEUR+JpbzqZEwSp?^7FID)!SPQ;CTh!}lwApM^yv;mFKW(!)UV=j`+h#5< z$F774ac`UXttRdXdh*|@;nP3IGO9$1kM8CsF}uxivY&?xs5{C+%j`BcmVBTy_MthU z!+{>zXD%caDR}ua_C;@WjR_4LG|vj>#git-*GM>yx1S*^sLD^S9Wv__FYe1j=BuLI zm1?hR!&!9au7v74VRpzdH5S=KDb( zD$%87UBnNvy*loq*%T>EUveFbKeQ@{-%;I2>Yg1RL*HL#>w}YUKDmV*AiMrb{%NkP z;+~GKMbt$Ppvgw2y}QVnZsO#Wu{NA};n-j1{SqjA)_v?1*|a=--@GzH91Fdl;YgJY zs1?u5zew?#?ys;ie#Uq*q3d3mW~*_Ivq7Trm}e==d|aVC29tr_teo*+H;Bj#ug zeqq9IDT-U_w{RWvyUiS0qVy%q$CC2G%B;L4DUv+wA=d2#JivtB46{6x;6-O5EeiOC z9p5ErX{}{km~e0HjIv}XNATMy%OI^lM-MPqQslgD5w6%{u>7sjtw$sBu5=mu4vm=3 z%VpX~&0fMmq{g?Ih%!rRy9G5CkFySkdC`ap_=O4a?}Aod%WG+?794PEf|hDB2ONDB zv}CAw?dYd}cp`h?GkcLiaiN-pwCOF3>2L57CbUz$DZG#gEmG0~Gz-5hwPh@ol*f+w{eh2%@cKG0F>&H11Fo6+Ww3fVn@-hWJ!Xbg?Qrz(k~L zIcr%KOO=dv*0^5^hL>(0d2Lw+T2Tey zv8f3FkTxEzA=wMQ)S%?FMK9apw0R3lJyqNeJTd>L7YFsg%nT>D4$nq7Y2LI*;u#?9 zOIhXpv$Z7{DZ=7Woh&uwJCCtInQ5O+7I4Ua#riaG}xlV z&lu6Ki547UxgaINejIM8ET7V}#t2J6DI(Q>G}d>>E@B(nO81PmAX;Z;zShy>@zP_M z7AAE2cni{G*WfQ?XeN^z3h= zMW|#L-u##t6PoSFBF9Lqrq_TgtHtHX0G5yFWbu?X#! zqm>zpEVgJ-&7|2%tjiGcht6GT$<_0n-{PykPS1nyLk{qZTA$u{bC>cmhAj20u1Bhza%IvAmP$fqeIIeucap zwD)}rV#q8yMp{0yWGbowz~~mbc~NEEoC zwk9dgH=V}XU81}kskN4su|;&3)(T!o=D8w2#aqkBUMli+pH^0COt2PLaqsG-iQVe# z#(=#c6DFbR1}|8);(5tPYsY~@26b10ocqyYCUlz7dQz(9+|p((Cx!ct0V|Q#LS#S!Z>1#}9;->w1?HM?mh|#ilT-rEz0hwh zro=I!iaY6Dzjb<86jKsPe!6_RHW@IZiw&i{)nv|hb3yqMwB{=tqQ9gv(-T2!4OJXN zsMcuH^ebk2O(%_GhNH*#YJ;UP$*R}(K=+u?MoHE=DxOR9?4L`;qVTuxIVfvkQL9t2 zvx4}SDB!l44E=_Y$8TT|04upaPTX}%@h&EGWQz5LR93!!32O<(r?R$$6$cHY0wKN1 zVD@AM26hsm$i{`EfwhT796bY?;ElJi#hB3DO|07_K-_@l){^p}A;Jp#np=;B2`hPKOKTOy zO8&j26%e<$p zlE0@yXS^p*>~Bq!0;0~L)(k~S zY&+D7Wa9H|$2mq?3(D6$tu@m6N;)30#$fY?jt6GKI_UHU)MEx$m+yJIOapln^~{X5)wG~`x+gS?>t*|Oa6dBOIjFApoVU3Fre)6fStPPYbfa|NQN2GM$ zHEXPyO3=_h%xk8awbqszZh#$H`g46|02UIZk6?gB|Nn6DsSk%)=$1`Zvr1swj&H>* z|BIE$gle`~;h1E+1#Nr%GO#GF>>zVBTFFIfwJEmeUUS!E8r*5shYMdz`fePi?J+h? z=+NEP7_HE2CjV?rQ6_KC&(^~lUR&?H`q-#@*hqH~TVjRC;${jDhY8O!5xfwWk6Qnd zYC0S|jnl3feqpk31IUNs&R9L+A`iUyIh?HWP1*gN^+JU3$yWZuT1oNAPWi(MeU~G} zHeEptSs6X_=N0Q6iAd}CH4KNW_=Gen8!dU=iXy<=<8tE$ni5*B)O6E|r1+O?RxjSg zOQ)fIOlb5yYr2M;IGR6WZWl*qZz9LBrPoZ3%@)?pMEn^O(b+kVti_~+!2Qp$pw{CT zCWP;B;|uF!Nj*}(LT^Lr5v};jx>O>_z4{sl%_2O)gcf*X?JEq!D|d#r9EFwfrC!D#&q-vD&%h~iYIGAoIXKSYw;pq4(w$gGq znxNJr>hV;uA-|U$!UZBCwzfdKrbdZ$+pb-E|Bpgb4_{^?Xv~sp+L{aX;87oEi#d3% zIyvyoR1V2VAV1WxS!DHqjQgsKnck~oo2iOp{Lb$ZZhXP=jW3Wq2kfS^_6d<>X#<;1 z&g-FIQ5dfl3Am-3*iyA;asDtNd7oD_(Fsj#9W`-mTYWqKPlyrQb2K20HkOJYeHMu+ z?u6Gdp)oydU8V5Jklxq|p*2LpZj}P7VsBfsaLy`yXy^FJZD3{|4w9_NNCet{pq+-) z>Sr^^Bo4G=KU?2O9m|)sEWT25ImWhW0?Da6#6(6d77H|#LCa!HCh8w%`${mXE&Qq8 zp|9P)#7^!iz4Nh)>#v6w@k^L`+#@V7G_;if@PtkX?@iH*y zGxnPWeLS^cknvR;c2bSF+LXFD+~E*LTFx!<~{3r`Zy;A&(@1XTwCT(`~C& zJiW`@tV8%loIBr2Rq7h8QAL<~4^lKN%7&HA7E14#XxwbudI?7G<6K)M8AiZJ7>(4D zW6P5c{5|t+8QM@VLSV@f7TDH>iyL zAkMuu6uRI#%*=f__$`L0dZiq}Pd$@YW9+<5FVI=B{(Frmn1=^*KQeXrwdjqsmL=(_8+ z3tHh`oOBPbdW}Na1Dk^8_}fKHnW68sQeC13(?6lEK%9I zJbkte6I_twgjbNNcVwTNqb6%K_INqK&ngQTiFdFYq#7FgGD*LjrnP6t5FG+=orT`g z+TnLz!v^`+7<-cT1NzN`hR51f2FWYpv8OAnG00l9(rk|%t}PzUS>v~t)qcVwOayh> zN5B1oDsB;8YPhj3ZW;Dg7E4{ky;9AnB^AHU(UMcEgpW!^i>gq%_sr0>Yk%U%=V77Q)#(q1T-zpXBCM-@z z+5x!YvF90WF&_u;3ln;%t=%2Lk#SAC(|f1kbQ@GyWJdS5W<`?N_2R$_^@MR9SZMjq z_Tv$fYqb}?)f{hPLb5bHt+Ycg`#1?KcBe1K_e=c3gc|$VkuJ)~B_0m27ncKuG%(OU zLB)&G?~N(f@Hs}IqA&#K&TOtGM~B#LvL(k-OD*){5IYoauJ}J4ZckA{tvqI1ZiM}? zN-4(C;SO?Lvv)z4Jyz6Bb)ffh7WtHI@|HloQF6_z;ejz__zf^EA6oC1|>m zX5wWl@FFI(^-MchDS1wTel|v{7XFh7tvuVFsnRhvyi)Vsjbkw=5kQ?C@&PVeETATy z&0=Q4@wZIq{v5j}Jnnn8GDa?NG92?C+^s+F?5Bu@>TC@ew^`^x@37^WP~Uv}L6xw{ z?h$)FGNi;s_DPYVgwVR>nBSH7YbNy3a(fq{zARgH@>O$uqisGy*pc7b^AW-h_`5Tz zIecsXT+&@Wt+uBs3%~65_9fzM{BE-GF)M)^o9}GQ+$uW9U{6e_euEwEZ0=>gunFsz z`S+Lz&a%YKZ0(<6T_3j<`>qClVIr!fp5JPptJbmjO_>Kr>-~jBmq+FmMNN@Lu3#jY zPVFWoe*x*IMiOgi8BGsT`(-J-owvuXP@xFZ@68_j94P=j<0l*h+irxdsWG8rah0A&Bu3{5S;Q(+U>mkol18Q4OsJM{l1f+z^p<^yE--_nR}~C0`bnw zjUqR;iv(j9WoANQkt|S)W2MfOe8-ANaGZAql}Ck7y}>Pec{$UZf;4Bg$k?A%V8B=w zOn}|YvH?LeK2v?tAV`95+FQcu5PcmUd)h62Wz8$C?9!34T#D)0K=t#~ND$79eypkpd(rJEW&z`e7Qe-+Q8fkL?^3B!4Y?ng;5{ol`tIIK2 za@m&mIV#E7`E-KMfs=*h3SId3>jV$RCQmCe+inFNMkPPyebAArQh&j|o0^2q>_kVH z(C$eN(64hv0%L_NX>^?lX>=vbME@x2SScw?V^baF6orX1d;OZ~_*NqC8CAxSrj5jN zOz00~9IaxweNuYOh;`9u)oj5-j8ua-GV4cS8p*E3&#O4V#xsmHZb)@UG3AU}Tiww) zLR`XzdX9V~AXV!*nyQ7jVQC{rMcLaxQ8s#_hO>x%-lO{dC-`zQ*%Fm$BB?`W#oPOJ z8q%jr-@%HplZ@6fVLS^qda#+}zY=(3Q!9)`XiKqtEerj-l>^v5t`W3ti)jztqm;CD z^pVm6w4EGES^%rPZlT$o9H_7MBkNrKZjO9eq#{f+sk>t%&%wQ%n|`k{+PhC;Y-TyQ zt$R3>oH9DRhvPGqV4ynP8%ty+8qP%2iu3hxv{!K=(6tK&cnJ3I^+>X%O=SzoJ|KKG zp%a)qUpW%h^s7#%vs0dEw;xRT$-JBt4gVYiWbCpi8H6Yhz36CD*4 zez43*j`JD;IyFyo6p@oA8Lyy;ww~r#rV;D)-E8db(0Zk1<~Vw5bSLq(0|Rzfn-A@0 zb73-IWjZpQe#zm*ATlvlO!z+CvA~fV!5u#-HO35Hjz9m!%UlD1rw{0-C3}}TbP5XR z{8Go32!XZua;2k|eA>{9D;;gb)iI!3 zw30IV@2*3yRrV|qcC^3V~Sot%UmZN3bc&2Kk3Mc~}OW}Li^MHE8r(XbniZIbJF=S?gk*>${SNS2v= zXqobaytw7qA`aZuf8x=77)d7d>Yone$?)W*=64+hWt;IWSkB)ueW#E4+sqgC&O@4fa!!-{LXF~sY<^Z7@H`+h_gHe^y zTj{SIlO*P$eeW@DN%(6f!uM$Y;HWPFf4YV_Ysz{t-5%z=8!mM6y zSfGr2&^l9P$Sf@#<=hpeWB%1X=c7CQUv^88xB8_x9i)!y+0GTi>xS2L|I+ulsoROz4XKC3CAP90=Xce~;lxGjns&C5A zp2X7-hCFN_APDpeDRK}C%HY7O<%jQ45p5**9 zf`eb{Uq0UNHaPH~l1({7%w+dzp;Lwe3`9_t7kBRGKxZ3igES}VpK~{7p;Bm{;v5JEHObIY=%her94YH8sGu`mm37`N zAP%G(ZJk-lfmEoSGhI~STypwdmp+)2)(Ir*vK~ zG7H_hI)NDBszy!^XTA!6M|(KiL<&8k&;VyKS&tA|NdpHsPpdin;_9`GcDt~88#(g9 zFYcccw!aE9&xDR0>O3LUNv%Hyo%;$i&xDQ|?_()kxWI#4^a@f6J@HRo*r?hE$&F)G6qWW>cMr7IEu*+ze-$ z9Q+`twpobYoZ*a?5>cPba#oN5inPRR=RN5ja?i(D$^J7Azw0;OIZ-&stKO+MZZaBi zpLDoZ!Ai0(h@=8lQLN2xYDH)%K**M^Kn)2Cw+fnZG4*vN|4a9ds3?ldUs{j2THWg^f2 zVqX8vL5yE-(tmEUncN&@izJmV3bQlhkf4AEmzG?5QG2mxLM}a#2-tkD6D$X-*>QDg zAC8Ss6jao7EwbPFI6^S0IFDfd`(Q|z5D*brX|E&B7|CKEiA;4R9*Dg4vtc?$#1h{9 zPR3-c?YYP>*x|O3)hC>K`7Lz+2`7mV`3|kmJBui2>sjZWB{iH&_CgpO;#0IN{jg`fS*r z*qkyBwalN++-PCvoP6X|BD!RAP2k2nkDbYpBH^jQ-#DB@^dBVCJi|u6{@eMlWTh^B zjb_MJ>haf3gz#RlQMSLsI8H^QnXnXNUKhkj$GvkRk&}CJi+sSFL!R8#9X|j}!tAd2 z%409Dz;fD4^vwp_$kMCggpds}#(cSbo9inLPfJgp@uJRWh^Bn-kO^Z(*vYU6mq|JJ z=0&(VOD>0Zajv3D_fvGP(*gj$(BM+iQz?pPqM|rIk zx@nTDgp4$$vy)tHBpAq(!mfNtvSo|7a6xi*u8PH6N*IxjDdsAp5qbnI;YwEY2;eMy zG^V60He7fMoux4r6VL=E9F4-NaYxf$rCq1O#6GA{)>TMZ!M)468cBEZ{tQSpOv}osK55fVE+pcym>AJ?ch!-BE3A~RnfC7P+9B}Jb6YGw`W@Da z7CwX@v_?|3m&>3`3rgac>A+sDl~TCL)(=yfiY72YEDd3i?0&8xQq6};gE0E1anLd$ zVGo-cX`#Wc*;)~T-#yxussyq??3zK7$GApHiqzV%cvjx4VG}{@`gW`fdF}667m7^6 zJ_sE_BKS0PlB&_G-tXC?kSE4D>fU=l7p7~P8~hlbx{@f6fYayyvQ%BaDQ}X zG;{C_F(~<{TvwbtespfGYo|maS8o9pONhUP_}9-i)1?bsyETGAw&hX`&K?XK6PmNs z^(-Qe^<00UUKxt^5)$^Yu!-!+L`Cd%D_yZN#!yfq{s(Ewtl`-kT_qJ07xXeldUd1A6d?kMfB%5ZdIOIzp-J0a zho$7E=M)PpDrXk92 z&)w(JN|)oZpIzmZ%MshdNMHQy>aG!nTDzmJ4A~VyR~&VXknCUgY3%M#Xde^W_O$D% zgi~pB4rgTury>^5>T|ANq{4Ike#5+Mz#~k=&f5E%D^1$s&o5(V$!2C&!>Oj#6|T4< z1S-GsEi|P9mJJi~^eO7VlUuH0QrPI|9aljmZ1m3^SE(40hn?~a?dga|n9zaGT#-`A ztuZfM#bmAxvZ4m|z~Ps!`zjraCmq@2n307`#^WGi$%R1g`r4(FN1on&?P?M!T2=9r ztBTSpUes#oC)c+sPCD3loNLrH-0^_~4$aM0xotA8nT}Vvm#T%k(yMhBR@{}1v~HZC z964So)}1CJtQb9miOz_1?@)2i@9%-!EJmF60~xTmnwj*!kz>k-2@9o}&}j+oNR^IR zIQGx~Q*PAI7o#@dRj&o&qTk;Fxx5g4V!}WVW^!d(r6~GyZ8snaJd3=gv8tvgYD^ETW1!a;u*S2j5ro;CFr{d@`Yp zMvpdguTpbBTHjiUrSIbJ8yf{6?cpn-H%~;{n23z5J+0k$)KSbXsI+razrRTPI*n{( zf41ALxX}K}cE6VVH8(rCQ`>DH-qXYjf!XGT65iUk^JCk;n*bdaRJZsY$H z7ckLgecgj4lGf9M+)7eAk9kwXyuXvOVU7-Urz_bo+F@=K?)eVi_`TbR$^!r<+li8J zH)om1(Kk6J=6aXiM7g8flVSuI*Z!sZ|Kw}YL0`IK#S*lg`a7F}S^gzCf1?1=is|Us z*XR@za`s_s6FooO4g3nHw4XT3U0k8cW9}n*dX{@dSloUzY3e^C);`9YUJ4GYIdj~0 z*;_+5&vAbWS3BAE*_P`LYJbD)nb7OG?$J@=?d_JiQ{}hQh0EOOQkKE_?z8J=AF%ygIk*`~j$c5jy@|+Z?;$s!zdxW8B<%>!F(dwy3Cu|M6Dhvd_LRG#ytByM z?I||8`;;3bDYMvPv(DmuGIzNXJP43A0?T{pK!jH~-9Jir=Qm$4q-Plq)ji z4o;xZ5ka@yasMvCXlC4X*N}bAgx6Plbl3e)xZudVdmkry5j24bH9l|`P>YhG6`o)K z4`3NFq2r&p=fnsd&-m6|R5^3?J%Gk)`PMx`tb*Q_mX%aE01A_=XGtc~P?h^XTqo4^ z$!*rev2@)DeYVDhW4)Xdd24ga*N7wgRk=LNU$#z1t34)(XK#L_r>qha|25KcSt^9K zCC*buR(2_(CJwbY+TskJa`Mq8fb|^=p5|&{?e4XBl4MsTeQ5F2)Wk8vW zkX1(8l<)v(vV?u|QE9wSrtjmGAWE0<*rocgpQU?>%4!asobDMSl{NjCf%k_^8I76%re) zw;5h4XIq~s+{I1@H}fDXfjdrSwZN~k| ztehP%NFj@iHt661NeCa?=x%r{$k&z+W>Fd9&w6d%$(ckELZ3Jr%Ua&{HNN>ho%%XR<~(MaE9`WGYS(FhC%z zH`Q|~Tz3bve5=ZkjCI(a0Ua4|yB568I!vKHjpQ}T%NBHau$(KiJ)WF&Gmo>Ig;Il9p-r|%3r6e=6NnktYi}i*0G!!M2QDH zKI|+dj-{RwO2*6MmX#c|?@|xEYuxv9eK}T26k5ham@S1?cuq-r_`ly^m3#3E6Po_5 zXSYgso3%aS@!xx~m=_rY1urtIV05JpFp#3(d*YRut@6DGKJowJiDJ!PFD!~DF6cy| z#O``AFoW=7CbZ!O4-kiMS&Qdx!T1yWClh*Mi^nMC;yt9EYRYw7cBcmsY%3d;=6gJa zw5RdcOz4+;JP4^Vhb=kq6IMVd)FM74HwE)i?IFG$w9gi@f@6UVs>jgnw|2ue} ztZ8k!<5@1^Tn#o{?Y|PEQUV+rm-SYX+F*DL8T-%^rv$p^J@kN`nny_LK0{|@vwG?? z4>GWs?`3V!mbVxy>5FJGp^y=U6i34E|Kg>`DEnh*+~1yc5{JOv*BC^3J!;>0o~lKm zuy^mVDfMVM6Xq^9(uN;AZ6)Jov&x&U7;(>3-WF<+eqB%NEiWsa45e+PE4AJ?lK%g7 ztT$D5(hBg|qgd~wa1o-u8joj(;&V(GR2^WA1g}>UcLCjM^JBSY8rY(xi2rV?n~XMl z<7HnrooDuf0rNbYtc@;jvbG*xz(kbhc;)i;ljgX)-dy#O=yglSmvNuhJ1ryXi zvXG5q8$2e3QoLJ*F@8P8TShU)UB$hJ)M~~GLH;U<;Tey1GaY$i=&`7# z_oYS@Cz(^Mu=s7zX@ik2EN3ECO7pClh{R9xAf+_ZLhZU&X-Kc z!EMouGdMk&(2Z@q!zBXQA|1R%6@X0J4&J^J*~ppBm<=u7&xB;H>WS)GUA(s=xL0ps zZ#3@|Ud4o#@9n)V)%bMx#Q^=U;|wL#zfKw=m!s!?8ik(iLmQb$bS0y`5gLy3 ze_w6de~eIq!Yv#QG%wo_Maoa`Mk|IN_o-%2@ESB6VOI80<-Jk3(bn39Qn1>W%Z)My z4`3oVYY$EFYNc8%=Vp49S}cOHt-vfV!a?iVYHBwZ%S?smn9yZ&y`=?dW8_YC%17wa zc~!(Qv)`X#QKmJ*j&dP~b0NwnKaFQQ3=z5M=n`1Cc58WUP%l~*0X zBWTW1QOkeF$kj5iG!zH98W4R5=|IBnp0?h5K`qv3hb`Ez4e(heWXqu1Ho9SpccNOy zK69n?)0k7R(1t~_N;rTR?(n+guL?ZHmpi;C!{ZoH=it^wy$!KdqsW0hV^Qk+X{45n z+vU~C5C<_r-|zA^P>Jb#yBEt$p1v%G4y*Q~_cw`oz(gg#HMoDJ)DWH@CXxn`=0leRH*yvV{bJX&rJ(G z@xqNWl09+iIoc)Ht%-c$?NMAe13&bCU8+TOG$~G?#mVYIqD_aeMwrlbeqVEydNg}S zL;+th?Rxwt6I#B2Pb0an7H>*fYJsETi6 z80U^#XKVk%Lo63UvgQ^+1;|2kjpklmhAAN^85q^8n(u?8yZ5f?E2`Kq%WL||g$ta~ z)!IHKb%Kn4Th>HV>-gZTVqGQv`gn{LM`A*o*7x~UA}wV^BVRuL>7Vc~3HA4>iLbbV z`YY4a2hKMRJ&$bZOI4ufnJs;=Zn%2)pp`FQqITFwRNJW0ntf<5YeBDezCudHMV`^K zv7Ha}Ud*>~xk2fqrnoLQ6%$~fvmJeQ*}+Ypcl33Q6tt|Zdty{OVMLkG`8|CN1sK~n z>13O}n9F(jAjz?Pefc2CY<-iDZ<|EW%)Y)Zk~Z}H01Qh=#iCaR_%??Lp36Cde3fJh zR`Og6!~5|d-(TU}(OiA+!iQ>{d?p*&(hz(1^-y1&j3VL%1Xc%z`67fjwBQ(D3B?&1{rVrW6Om!d=bFkJLqJK;%&G7-x#G|!+=jEUKym`Jz>527= zFe;%ZnCWSzZx{LC;9!Y=5GnP7Jw=01c7XBC)GEMui_y^2%G zfBxs%qAhSVf>YpaTN_!Qmdnc$mB2fg2&8~+l@B0P-nedSeT8LvMVMLZ*ZOva30-S3_|*sfAhVTsuuiq1si4so?}8a zSADtC5wP^SuZVI4oVxCdR*R$Y%Ae?VNV6g-gIwe?9`1Uz7Z`6GRl>m+n^p znI!CsN+voi-M>#G)Ub?7ekF5Xkit%>Ge+jvrtv&oDWR;yh>fyf^#(6S5qY=5n zv`iprB`di|cA%+xVQ;@qfts<*5?Z*ozo&}x>Hl|6y_y~H_i0kt*IhS`jIW%_sq{Oc zSxo4qe*Qs{qqor@e?i4FIChZ#bB&1UT^x=dSUisj)r|1NmCNTNWsJY9Y;X$4@#Hc1 zyZ{=!9FKm;Hc7Dw{z@8&^?ZuIvf@Gq5W-4NPw|7fl#v#ZwbT5CWXp&h@fP}Qnm-{t z?iyQ~Yes0t!+uyrZk=t5h!@MgzFbB4w>qMAOlakqe&~a*@aKlJTRJty5IhjnqP&9C z`y9Vfu82adx&BU4ruNtc{^ANIb^8K8R8AIqB2O0k%PH1f@g@ErHG;D7*>Zmog|acQ z!hcR=-t>4A{hqN1Rv{B^wL*-GvHG~a^PA-K8=C%||4)g~$Fl~DL3Z-AS>vy%ieg<| zHFW6F8YFu)fK1Q2+cf0spDRR@Hq~=^oyt&O8A2Mtiw*v&Qtn-Y%~*IpV-%Q>v){L{ z(C;_<=Y|OwXN9f)Dl&|d9b87bc&mS>NZNi@;QbO-*5#>Gf1ydWSTc5p-y-`+$bpNf zMYd&!znK&ZiP??Ug<>J}^WA7HMjv0Hr&Iaj_IPw!NdMm2@eBXh?@{N(Sc z7S5@`Kl@V^=hXV2{mnH(y^TDIDJh7aFd=$#c_VFn)c-}eNGZE?9J}uq9QsVC^MpT3 z!ZT){@#h2lFF4~j#|nVX#w$2?WaR=3d5JXUsvmh@^VvL~zK&+dY0;<<20G6hexylo zpIhW@oM<7R8#82VwBv36Q{nEr_H^-(!RT>^c#<~*`CZ5;NgxI5iX#B}e9sr}*GTbesucnl7rImQ>Sn&-|!1!=vqOUt$9? zw>T5J?4`epTK6xy;(XYDU;?IcaYW6`JC@HIEETzRn>qP~sg~vTYKmL0A!u%5b7(||* zz;-`cKbIFo8;!RyK?-Lf6TKM|c&>_LR%lAC2JyG?=QT*$?l7$L#f8_KVKo)ek^|FhMaX4$Kp`)nFWiBjB@UXM zzCecJP(;L@4vWZyv&BqsvS`Tr zM#7uC3&X~Q!Zz9@D6va+)*3Fx1GUhKL(d$81`q5yxJRFSb!4aD0VZ@tdfW!Lr(UBDwr$&%Dov}7T5g7s(gPHE_901abc_hdm-Lb-$^MMIPRI{?0 z6Vkpv>gq5EHyN%b2b`#&*Nh}rnu^;w1W%(meF6xoaM!kD5av4M+9v*2V*_-+pa2f` zW$Y`OA%SF>0+3`?!#1opBmg8iUvl?`W3EC=j@*o&XrdKH1WK#p*eO)HRQ=q^7_lKN z!^=$OjS0B(K?`rUGm;xm21L+vV*>DVapy>r3HX@o9QkrWz#~;{TQfP3B`1+GM4X96 zObINM>Ts->7APvmvKP+PnCQJ}0r2ayi<SfE zks)5->8Ix`LbY9R;`MDQuG|BdKPD8ZvmmPDe(jYT1E~tnHg|_S*%)Xi0ZkfhLDOgB z5hlC_0ePIzTT3@>3Baj)leOQ!9U~^+pgp$-l0+%;&&pmO5f4|z7bUr?g5xkAwGw;c zfAQ+~b_U`ig;DutANGW7R3_~YApM7@ZZRqfH8~cjsDz8I9t*&F z;1xK0rvgmmxE^7d=fDKMHIV$pCd9 z2Nb*`o&7klL*mk}^$b6Rrk_9wH`1@41%44}jia`-s(v4Cny-?DgPNz<70(t^B`4Sc z_HUv){tn!e(vb7sVSIO>B~0kUcL9(=amPTbPnars4#}s$8o?!h?eW4O;}FKRcCLD9 zJMo(4Mv}ha!C1w#hpWa&7la3a&}7&l5~dBNC}^Rw+TfoOU#L4KSV}%DXv>)3b&bfu zEw2wMIk<#F7QfU7b5w#)#bpi_QTS9En1cpUJnu^051S@pzr2YiSsezL$iE$hJ|4m+ z)1|iHd{x|6Xj6|p_ewBCd@GiYi0qBJ<_OZ<71YbGCH}8#o9Gv=;1&t^Th52J%JGY| z?*$sfzLkIkoKL$ z5xWZG&V;5U1&>L%>32oZLB(K64uW5b@1Op~ga0S>nZ!1mYNWpv57v_M=lvyv1?8iU zHY^z&7|yd^ryZ}@;#=J6DO!@X+F>P|x(Jh9UK!vWC`b#H3C@+MHTI?lOUipylxvAD z7c3%iYNuBSR+KR}{0z;h5NxmJpK8$8RbnLu_iL1XYz_L-XPIs_Inq^3hWtHn%9v=? ztRR@0R$xXJ6ee@r7^I*eJm-7`G1Y@cIn`0P?8{dV0{ya^EvuHbgG$X#^44D0OSjh! z!X)4v!SVHjN!sHWSSBJk)3|m0-Cv@Gc`;;9_A*7lca24cMX+^SzmNpBVgI!>|4>v87Md#``ko9jI+0?Wbbei{sl&=*X!-WMuGz zrEV-w=%FDt@LqNIPUntul zpFdLyP4wEqV1LO#ZG04`+C03637vH`2rfr%5hkAq{x8$AiGFz^h!PF_7VUl>O$gnh zbjkT3$cO)CgV6J0u#Dn|`u<|@bhxmtMqb8tWKQoo5XP};q5Cceqa>n}lUK2pLwX^N zxE3Um$0zSktbW<9y!mHvqgq%sx%V)!vQ=~DUJ%CWP}Tz5LtHj1V23lI4IT#j>V<~0 z|2^&$+1>Q!eXwpMhqf+E@7=!|)?Qmt;vLY|Skhme7%wk0(xJ{|6J4rKtfCTr-dmB0 zsj{D!+O>(5rOULfF0q1gnZgFexjl?E>W)4!MOmK?Ln1Q!cs_KDJ+Xuwb|lcU&9s$0 zaeahfyo&ZEmePJiKbX)OzQoaL&Khy7`Q8P$uzJ^udLdx7izQDJ6B85%$ya3xS*fQ$ z;#G+l{bN#MAq85IQYdj?6kjvzEIIXAQ0}>S)6Ke5<4ESPTwcB`v}ovGX^9_%g>>kT z%;9Q`)h7X_1$k{0i7lOIQrr=FwOc@^FP#{!;wgk@50?MDBGkv9fP#OeHj?(~iAFh9 zg^o;5Y#1r5lT(?A|I5;4rNPRHCsqHCtM3e~qWIqaCAZ`zB$tF#Lg>luy@n7Vq4y?& zNJo&~oAe?`hd>}hFVdx}F!X?k0#a2(sR0oXsiIVY_nDc!yZOH#&WB|0?#|AfnK^UL zbDpDT=3$fFj#{jSro9BoCH{C4TRYvXSc^DhV9sz%#in}c#p2cH-T*QCcfIueQX1vX zrWm(S8YTU+Y5K0n77Mk5L{U3?O&(|g0D60+qs7pF5mdR}VUvx`%E73)F_w;h%kvy|^V(s@cNQDC< zQpms_>B;hPPUrSW4~C1Rx0Ain{kr~`HB5xxAhmaTiiitzn|CN?A;#}U1nCkEnjetS zs7dEvx<-=D{h<$`nN7}r3@=e$|Ma=xF_+Px8&kV~!HhU?TJEoqNb-^vs*`$l>or(e z!b83i+HO!fN<#3gvP;9$y-HRYxAIIQ(wnK(YuPuB9*uVX14U&*_l!j1H#>qxY_CMRtd53HX?RWvGJCA(_euCI6MA=g`cE2h7ATyX zo~0P|VR`9orKPfCKBkw9YFvpy`U);28r#UO8!8%wuSI=#WM0KTb!mgfr-6 zKTU5aBQ6BYeD%|Go8%ri|17mI3^=r!?Ug`yxUXw z42yz6&`g{&jEW;Cr;32~X1t$?X#cBH8BpTwY?PlSW(0LnxWa^bk}^t0>Zjns;W_7~ zzXKp?yi34jKba;>ihbyECUipijJPPyN9Z_PpwGfjPaEMYKpId{;G+`ckU2vyXH&2o z&;)wdoRJwRw$gNOhDF&*TYEDQx8e!$n*$kc1rl*9kb$~L%=9qq{&fcPiPR@?AEm-u z#fWsTO&7*>RkWOmAPy*9E#nJS%q`qgBy6uj6?-rsn5-D zNU3@`wKHnV)G!4<&rG1JYGiFy0V(0d&->Z|pPQsU^p*RRdOFfNH;EFEy=zgN3t z>1G3m_8QQ?7)i&+_+Tb<^hX&h!bR-6?8i{5P+AFX@^Qw97~uv#J_Li@0l#KKus^0C zA1MPtadrYDy+>x4<>MAzIx?eexWGid7@eVDB3YS`MA~Rf2IlQScH5Zo8A?TUg4)L* z79OARVT>4I%WPcT4n<+YSkMybnAsWSC5O<;d|cg+#xS8*@-wEWIOi?>cIX{u%We?` zFlx-5&nb#R<}kUg0bBS%k^$%_FY)ABmXWO-!-g))m?Q;8U#-L!&%(o*&?>7k;4k0E zTK(>GTnM2-X!SK2KS%}rVm4sx=it{&Xxj}LW29`%-@eFj$=R3`DfY?I%Wc~;>L@QC zxjkct#FAzI3bWLK$1oA#y3zQTR;(vG_hwX)*Ax2p-i(+?0liQi%`ob|#Vt&z=V-T; zu^&Z0gRaO)8aOe{kn z?LE-`o)L(6HvvmmR0|E6yHG4XmC!Lv=pB{eq%djR`Ez!rqYq~BBjlZhVo8wAm600}d6l~#Fw|@B7O+5V>akp#F=&4JPatVe~GF!Otz8)A^N=M&IFd!3! zyFXnihHA2%LK?R=r_k9c1|-#Sq*-1WL#DEAqQjHvoiYX>&G?}>y1c=uR5h+u-cVhm zXU6c13OiHEVzkfJAQO8zlgavYLrJ*+89kV8a7KuiKeieS^2=#Co8c?r>2qhs)Hw); zqP844zoktodFenWg(3o^V(H98YH=F&X+^5bT|XKb8W({ruNp91k^IwTvJ7s;Kg|oY z^~^G0l5z{V_%d!UJ+L2UkNL5R$tsE}kam8fr_f{!VoacE#Vd zppF6fJnpZrQP1E~He}RlPow$u3@8;j44sqpc|wQk7}$N$q|jS7nM_zJd8e>QF=ii< zQ@d{h9o)c>t>LxpO1-ib^u@3e26{;&SEQfI{y@$Es%~Zg;(>X8s$HHs?mH}BYO;Db za!cp7G?bU~+UV|LhHq5;>h-25lvSisZ(F*za`ePeIzsSf5`02YB zj~-Se_Sz#+$GwXoN!~L>*_ruW3_#+u9FkvZuDr{DLfy!qqOerbY`Hkg5&d_G#C=$crxcWyS2G&6)BrRwcQaI9iKmCgNen{% zN<)@LWXqplYfu~kj0Fr+Wt|~UCCE|_ZA72{3@u|qpKdhZV97&trMF=!{|^mf!l)-V|amLUu3VMeQ3OHXzZ5VL-_2Z!v+pqFGEt=;60- z4W}h#`QkXPF2fZjtUP5BeR-U#ka36w2+kCoj3#_uMofSlVfpH~5q6Og|D*Dz6vuQYxM1)Pi9 znb7es4PcPt=4JWU7>8Q;ClmVNYXkhhcGe*lN*C(CX*gp zM2~ewW0{bh1#yY=lGg}Qi7Tu%Cjv&J;`w;2eb zR?wxb|DP3fyN>ahl>SiEz*t2|f2i2d_*5-?i7CyD9@&@3R3Vx6YG!;Zk;L?Q4+9;J zPi8{keM+W>-!sBJdyjqH>GzG*WiKpCbx5Gb*2b%9v8?FY8J#-H+Rc<~VDo_q^u2b* z#%i8^xO4OP!)!f;Uoq^XDWyr#;ru9au9GoA0W>naD?koLP&cxjj+na{t10^%XEmMF z%?M%~4k5_tjh;S?Rx+WV_BNK%36J&S!O)aYs83YBxINg|MLN+n8g8^G6uM<GfU75TKt*`;I88mXqlzPRpFv*3zr-1 z%3#x5VP5M5`r+rsrs2Yb z+p-o5g6wV#)vZdP`gKMaWDE*M_O6GH6`)y6L^LmYgYlM%`(Vi*t@pDsydRQ@%}kOH zwy+Wo>S>$N%ONi;i{mBG`kRdxHJos%_t_pPt)X32NN#FHPPmjTBWML5?vS0vR%+pE z|6vz8Gqh+kPgx>O-)-!y5xMl!_T%%)pk++xp8dvDHE&q>?G6c_pkb|;K_xY;Jr!0} zs97}juyKY)oGVux!&u1Y%G<|`DH>jpY534t$F0zymZbBt&nlBVbEKA-_Xw}sPP~!{ z;mEr#KNt~Zp?g!!t+6(%(Cve6<%VQO79qI50($*0!1t41IWxv|sd21ZWyi*CAM zoT(QET;^je46ASl6LLO%XcArU*!ZioFbw<`&DeuQfeBsruQ4M+kb#`}4~n({w=f}# zVk67aif@bnD)H2~YGI~KnGuAz%Yl0|FU&+Egcdc5G*$aQT2zK^jx>d-MWAIzj44M6 zw7iHhrRX?q*57{=9A#+twE_rRqgp^qmi@C(M`|RQ^xSe;%9_Hk)wE}l35N@QF58i6 zaw~y`KT}QJRWU5ibts|1l^PgK(&XlZp8kUzcwNUYDNgGS{t6K;K zsu(A78&@4@p(ei^6j+`^cq_VnYiOsK_X@~e0X*4oAUqo-iI^OHd> zwJD_Nkl5}*)0VDrnuxR(RQH&Q)kNgE0~0)^9|fShW4WitS?P*g$)VQCs3tLyOY~%M zp#U|=KqADU5c}ol)U{Pi1|>N1V--^miMgd(Haa<^t#o*{DKT8EICHB*5m@pk6MD9~ zJS@qzO!bsu`M8$ptrURiS=UqyX|kfO>5WRv?v)KqHI>=@XG7CWDJ$@kW_ZVbbQ2T0 zrDzb67vqQ;9sd?;w+3ArIa($TUGRk?g~9$0zt2 zCbZ{pQ)@v;mEd@9IrEz?EkWW|qBe2SNK>i|fuZ4}OmLTSB!+LSsTlXbkg+D%;@`5i zRGx_O2pRaa?L^atF#XTC5Svw@T{TR{9k2@ahl6{eX)hfq{7#rP&Cv=bwBDyC1ebQR z2Q8V3(MZ8RnFtHy{#27k!|55up5CL|40VL7h!=CrnQbbgnARW7HXW33)#-U?=S3(J z6Z%n}>9=rEA~h%9R9z`1`dPlIU5wCzKUSH{iWVfTHq{9iv8YaKa7Sp}rt8+2UWN0j zF3XK!)#u>L`mrEYo3BCBp)LNoL zaQ}_fY#9E@gm(Jdv|p`e;Sy5rIfiU6280Q1`P_6y7qbHw?)0kilttS6u=H01F2F;z zu&y~x$=iEZw|(NS@#eb{cBhZZTt$IcY*CrPl*04*{)jaD6h5PhQRc={p`k(1W{d71 zn!|*yi8ik;DWFjG)65Qqkb7L3IU-yfq^Fm|9UlCe3Ef}L++Qs&*el}>H~z^)q-PAT zY>tuAP^KEq3OvF9N#wMlE^YVJh^ z^~Q@9+(u6^p-!Lqu|`-vm9ua`&ZUDEl_jRzA0*T1S>_jEF-KX48k+a$jDa)?Cd>*i zhHA)$Y;&yaaHoaY=D{jGTR&Q=$e&vHooAWEvb>|dIf4}aB%IH3WN~9#rMvQnVu>^yTd1?inI-)t9W zy>TU{Tzi3Dg|4vlw%!ZPrR3B$I(eZvN)V{$(+P)H!#%#AyveShJ&4_XF^LT?J&?FhU_305a&aON| z+VQ>FrR42?{Jq&HIgnSJGzXPv=+%>E01|mDe8d@ZF}TFGGv*`V`aS593pED(*&Mnx zrxc0%9mhP^R1DC}Mo_yg9^NmUhwXRT9ubWZw@-r(eydg=V;ZGY1sS z=>MDfrDQ4fxe5hkbfZk@_N(SY;lj5#s0hyt`4;JxBJ($4dIl#>8}AA4iS=T644Idy zOC+7!S~X-~kqEip!$X)bzMCX^|A`ChdTrNlg%9st^7G^Sq0tLT+*??i*S)$3vczF2Bf~3sRF0l=SoTToqB$OXdqp&e2|e$zxHWpF z)%8BFx#kfD`e{75kyt%}q-R><6eX{gX$g~P*lJd@SQST-U`P9;x@DWN9xXL2jb$Vg ztM>{>XblTcOZ@xp)hhOV!q=Wz+X7>o`-gkiL;u!BvzX8?>REQF;#f_+1&a^uS&#lL zSq*1RvO1z%3b}Mg#FOgdmrUsDMwUGh!i?zfo~4OwMhM){vG*+Hw8A32(-wW-3AZqz z6+g5TXvOJbe`iaMa=K7;v8#>WkUBX zw;&M8Ax70#Tk6P=000J9g2!sh%WyFvm#($=;_;!0b8KiVLBq^9q;IHh#e1BWcN4xIbOlaK;mdOz!;CJQ%M{sp4 zvScU-u9-!a;}U^Ln?EdWW#!2G!_q=ZYxv_&%HI`+>)n)lx?2<$uwI@)(wWW{H=! z7uQS7VVO3k`%BAwogh(o9cB&4^q`D%ERi-1x9*idJS8HnRTK-Uaild)GQGM)TXU5S z_KRpM0#yufJNI(eb!DJ>1Bly)Ox%mH)>tK@@JJ2<{NZudR0%pzA;GFpw$Zi;R%je^ zwUFt_)@<3WB8b|HlC7g8@`8?Kt(o%qkD%;fJl$E=s#o!PNxwa6dZis2u$kmWA|a=! zg0+;Ag$JV+e(Q=>pi6m{VV`tsHN{@pk#2=|mN(#<(OOgPM@Ek+lUOO>Oz5eA z6?Hw>mRj)g=Got({`bEP9&xOR&9atJl-!$T{VPg1Xe!mQ){u2d>^I};Sno@R-2M%$ zE=76QH?Ve=(CJaltzHG4esxn~GHu`7I!z<&$Gh*N|78cJtu-5VZdT;BwH7lg&hKfG zK+wCKA%~Q@-dn`S==mvZu`vIM#7jz&Oyh@UL+Pn zrHG;K3lphLsd*T!dFT%&WMa~XrD?xBYhTICyE@<6Qa1Al#xkBZ%(uc&KxEp6=F*8AFIc_^_9U=X2tg5Jduzj;>_dXsPvMl_-_EYX!!o8s5)@ zK3HKL9VNQ3?4D~?K>FZIK%=-`^Tg$bRz)w)aaf!5!NA?b#HGGVd6 zB)Vy*b(oYQS7{gK*%(}5!ZR=_GBC%42~1`*g|>yrcxW?fO;E>7$2a|0x!j}}ocAu1 zK@(yUNMW4?8d6r1&r>Ci;PaW#Rr{@gHu99*qerY6GUSOqK4R@B(Rz0|X00oS+&64L zW>s-sow42Z`U3Qsid2l(!$EZ1T3Lylzdml=sN$6m-7}kMQla#AQZaoB>eoF&^2MoB z){?R>n1CuTk-j)(O%^z?l!&jspAVCDJLp_*rUGXFBUancv0QL)w)@cvw=$2nKmG+B z&ae?osO_TFtP*~$wwKV?4Dic@@HO)DOIBntac^6>YgnN|PI21)niaJ+enqE|W;d`# zw!yQQ2>sb|!8dN@;NRv$9+shd7cN)t*r#&bmseQ z{Q2mni{wa>20Q(t_Bt{kDxW(sLYpq(PKVX6(Odd&@OAsXDl>^C`SsPadb{xjSNyT$ zYE*tH=J>GT9ZWdtg3~z>&^blyT4@9S!X4H%*VMM43`3`7H8voZ=CcbebT+Gk51OpA zjn|0?W<;E=SoOr5INNIpFI6MiW>;8#&XdS^IyKoALXo#jwJCMj$%wE~W$Bt!Tm5hm zNO+WHbI27OgO4HcC`5voBviv+hdiOA-{ID`IQ-hYHGlWePr9I78C1w4|G9jVhIi} zdrzA|&;af}@%6-H^h0g#VC3`~IoGUeGPaK`UbzXJv#4*-$CjjuVP~Z3DDCY~5#Wg@puNb%P8X9*Io3RI$R!UhbP` zY@5ObwaeV|_^^1~&O~Gz+&FI=EU`GW`4v}Xm00kr4e>v=j*~%`Z8`rR-t_Ec+jEJc z|KxR>L7CWmI+ZB0)luo0_y2X3f(d7!k2wfsepxo26jiMrK_+~*P(#N4ZcCBF0t^%h zMxx(sfJ`oAubg-XGvznvEED?O9b2sk;RA?ygbQDz`AnGiCxL$a$hK4!!@^5_dkxvj zs!v!**j$8{JCqgn$6h>xiQrsp{L~gM@G)9#6HR?Iu8pX=Jm3XdG!c(w!f4Ve(VZ`t zroLh=dhi+xx9mp7aR%x6|Je{)Kgq7vc?TuS#(hla_;)s>hw-H~NoBXo!FXjyCM9zd ze;`fO_8oD|L@l`?as7TQA}xI^%+TT+c+BUP(P>Dz^7))-Q;q>u)7Vc(3bsXkNxM}! z&Y*^^ODq@JUwb^2@Ktlk`SNM$?v+WMG@NYEBu~(H< ziq6lmgF|x>)0c{M?JoJ?K-<=}ch|?TRGq$ezJhhc0C)4kvtehI4Mvi?t?YW4OoF~` zWe1@LL;7Cb+$SpzZT(BHa8&m1UM$4oMuV9MGq%GA_E_n}JgB|B%Ku$S30Bf*dcM7V zNw{!W4d{dsk{wptI@vc!)ZA@9!UwDHR3>!sM|L=QxTaU^gHNi0e=;G1ItAis-#+#^ zQmXpffp&+2q5w&KSQzmSwigO6&KH9*;{RfbGNGO!_81+{nftrl^2<(i2ME&6UoH_( zI*+zjQl{CA(e_-)4RUrICd2!9F%v2r%9;uGZ84kCQSsxq+-C{WsPDPVheA*DO6$m# z2~g*7{Fn*JOF#khsEKyK``Hbo-DG>Ve3c?yv7<&<&tWt0k)hp@R+(Y{JWL?Kug}DV zu6Py`krQv7Wv{Lh@!EcK?M?+*$WNeq=Gwgx;_Dw3*o!fdazH{Zv6oZxaw{+5D(@%* z?IrP~#VKz>{)8K9^4u)e_z`#)6Eg1xn6P#&wPS1J=aipTVWNb#X*N+(X{FWn#bIg| z<0plm+x<#Ve^3P!;w-twj-uf_W%lJdT$NLlc;UDP>+MC-Vc)(9<9Gz`WI{jMWIv`A zPB7aJyHCNR_uOH3N;72X*Y;xR=%>E6BLv1HG9&h(Q*?L?6UM!eLciN*Z!XpING*f{ zhB7Y2p}k+BJy(=U{G~=W2ZIYtBdh1u1d{xiy{zK;{r8w1l%gC}_3XI4iHxcu&L`E9 zXqOZA4@4(tJk24!Bg7poi! zj>AMc@v42BTI4}{Z=&b=qt}?w-Z$-lS8#Bk`3~9~nw%_yF_DhFWB*DR3M>0&Z}Y6G_yi_ALblx}g)7FS&_s=+q?8L{igIKrsCJGh9~> zlyhXtD5wpW%Hc(voa9E$Mg5f=V^w;VX>uvAa}UOrm{n4+KCDci6G^UQI8a@I zt$xf=wX<2WjLaM#py z1Z961nYaY!@PBJMMrg%c9oWE8Q<uguLF$ze8ny|08Kvy&0s>` zAK*AzLXaP)jYgOD#$%Y!cB38tNpX^P6VMA4@J}Xm;RL3woH42JQ-?!=!1Jvra8KE>vt;W8qscAf)iB%D?L@&Ytt4c^3r?9A50Q~N^4 z9m(8CS>gyNP?FY592F$j`l#g&i|ktG3n49B?)Wi`C&9E|FmT8$cog5HFrY<6a(Ja9 zR$eXWuPYrZB;t}$>m4q6HDpv=r~|v+u}gB`jNjz&$=<&L71sD4H#rcz;GN;zid(g4 zGZVH2CDE~49miBL`_UQokN&=U3uc{0l)zkCBfl(jT~)+SnGnuJwPL3Oh*YlpO?F}S z$ccOihTfD82gCPZ^g@RNg3^5P^za@>QCJKM%r@ze;SGakHzPM{fDH^9q#=8A@;Uvp z9BjI_&k-;9C?Dp}>u1K#e-IgXIWHzglX8WQ7&-NndJ7#@)jXs5z_R}hJBtt46wRyG z@`UDoxx$m)2VcO1Za?a{q0%$gN4>i}qS@)`y;xRUr7Ss}E39~Vhvan{?tbqGmzY8y zo^p7V9TK%2Q)upK2NLqQ&fYnPj+g6rRX*=%p%sClPcCAn{R%~9LXTW@tP2;>?%tOi z#egN-E;%kpWj>}}brdV}aptN6z%_O;=Zacn^tlv|29ai}&eRtOpCa88=rS_Oz125dEC+>+( zn3BnhqloRkqm;Z;(Yp5?h*dKEAxj_QLuGZrfijuCe(X4+6298Q|2Pz1E&cZ&$GLE^ zPMvs;rp2IHObF^-fZzCq!zF2Z)3=yR{c(i}cb`)1$uA_MWofw6E3eF?d=c!1zrvjt zrR2Zwv`(80&|!**NM3{!6(u-x)-j#aszj__=$v&T1?gvQDQ7X#&ncyxgCt1Ot3+op zND>e-^Hnit@a0#+=8t3<_d7`LzX+ZqeJz4G&W(sDJ*4}PAs}c_P++0mpO#2N^7pqWDF9=a3R2ZGJ#24C*%gnhA-#oKlXSZ{@5kx$|DMaVp+4PI5;ZeBex%aH)ej zKvQJj_v&&WgWl7@c||7zl8Ziex|M(=xRrqT;QUh~dZAaE;B`#s_Fm3-Dcb*CKj`H& z{F4cN)z69i>k+IU2M%^-$rc0sa>)i+p~{)3Pf!*deo*on?hwPI0I zPeV)PjW~0fbB2mn-Kz7;XV%u(tnMe1i62LnCaEp*d74QsTERpx;+C4_1ji9~z4V!n z*My8Vx^=#DvWnw&=Y0Fq&&{C0o5|zphH@mYX%8(~b)&nQTyG)v1UsI_gpMn4c2VmY zDDtTKVVAAI?@n^@bkTyP&I&TyCN(W}7V3ma{nr}we-`d#!mAL`;9BR!FwR9b_v}wE z^jQ7fNo3G|WbL@tJLBb~W!h-Hvw}v=Jj`UkW~W_oDX-n^M6EP#?`ChuO!^X!W+H%D zbGJLcSBZGZhhISvLw+ogVY&S)r&&t0y+Waln{gi#T49g#Ubr|`>i6S94g8Y{d7=eS zq5FR4H&X1|T8QN?A6J;rj|-jHF}S@};~VJ50sNB*9rukB+4lUxsbjc9_S=G`5F9Vx zIpGy&$wg$s322Y(hoC2%D`EwXv+X53?=YUlgf6<|T(8!T#T~iO1hTUxly( zWal2_c%8fBEU$`WC!;p=JGzi2H?VFBiTw-OC=V##VA}oVgcE~hk&rD9ofbKuN3T6} zS|$H>%oBW!?B8zu#Mw&6&3tXbytpI4^Y~D_gwdrPdFd=GZzlBiOXp7!BGPs+%;lAH z1?h`0S3ix|@p?tLvSgYIx;esiEL{IR+OqMgaUUa;jg986s?r|{3|g zR{Ea(|Gn)C{XZbGwDa_?WMwbJ2{eHo)w@uTfYDSCcf1QuD)cWCIxya~T#7fum3CE^ z!y`Q0MO>xb8akk~YoSDBr7P?5E6Y0vlYLOubyaeCSE=B#$u4i&uY#+knwR1`^s{kf zbu8ImX-UP?S&3xT9h-(^x6kK^?95lqghpn#noAyt4n~(nKI_xDM%N+<=YjyCMXs4Z zJJ?)}b>gG8`p_`>qwe`!$&q@7@UEOx`05;68IV7~MrZr7l-R`oQQ|q;puJA(M%`+`iQPE+mj5d=TZ=}6xfFg(otkV8DB{nR3 zWAuB-H$(e2c5ROoey8%ST`t-0MBB7>WyTBBF29${qW~FC_j19}f04CdML(BWcH9xr zb;i@1{am@>0>WS%=yJ#q2Ba?mSzym>`3 z)KyhR%aX@;CnwW(LtS5mb8_9YdmFzPg`UkWxKqCjnchV#-3s#ePW>D@YlN$@MD}oH zG@jK3J;{WYALA;m5pJ36i7u1OpqSsh4SY5eUGu^Ph$CsT%c`r6JDAW0lU+}>!raT5 ziO!6{KbbK4sAO6&(^X0(j-^}XK$92a3KM}|*UohT^v2=kljpk{D$CL@^IZ$I0@glY zF_fqPw=m(^#AN&S(OUZbV%HoA;NNyRK4T6pGoj0tyY@=yPvuW~(= z>W(e{9GW5T)z?3FfuWeKtOK{5+!=`}p36{cu#DHcl9Y88u&@OB<9b(wgloOJ$yG&G z2U4+6mq0yVxNd0$LMnA98c@9ZGw8^jt{!S$H~fQ$Mky@2(njI}I4@23sb5JFyW3UF z0=MjTA*+&O(A;}nnaWWEwKR}Ac8lr5_yewh%hE8VLR$;bElgpji{Nf5a{3HC62|2UUlR{fub%9@=18X}Jxtc1w5z_T4(F;W`u%q&C z+x0utI@BACoVF|tzvU_wE_Rue+t9S;cq$Xp;sf)w7 zbOB+{ho|*Z=u!x3DTpJtJaqxk%W-9!o}tZ0a32$T@0qJWEig!vUt?55c91a9etqrw zK+6O8YvvrNcNBV9nsk1dS(Y^GCtT$_@C+uR#M|s}ccFyMX|8o=%V+?)KGcpy6dVr=j!~}6@NFulF>beoS&-!=c?YFAO}CFP4DicR^McbHn)_! zs!Tjfe=OyOABMyB{!4WG71O0kk{ebsKj2(XaTg<-;I2*VT^l9)-r>`XmVc- zk7420Sxt9#U}X)4k&1to2G}aRVejtJ~bUy#cfeVG95UXbLmu&RBRDQA&0Zw zsfsq-%yu`BHgacr)#^LNU8qi>fw`QYp-)X_bn+GxPD`d4U4!ip`SH&H&VxZg$^6h{K1-BeCr>G`m=msK=r`5dq)Ll;rWp~iZ@4(B~JKz1cv;uZ6K!>|96igVGNdnzo;GU@BZ29evoIm~!k6W%IH;&g$ zE!em?nsi&@j+gVFc}*xfe~J5Tc+8)8e^|n+!!L1W7%581aA^O^QQ~wLS}N(e622%r{a+Dd$LgjbJ3d2d#n_+SdfgR#8WWoTvpY?t z{{lDc&G_TqPgv}Ki6J+3RZS$njT6h~|ImR<=);TdKh(mazIerLkm1e(){=77Z4|{J zS1dd+@HxB$&&ZQI6Hyr8b}tR-eFLiU0iMEyPPyTZj1V-X^Y6M%x^eg?6Z*|vcWJ2@ z*7d*KKBX8|nfvY<8j&H`@d>&!gk+`*p12RG^(+^789nrdovF&lktfp)m5H;UN(6Z{ zK|o97eH8qv$#nNKcMmB#SMfD=nvj2v@CxjMUb~YuJRyDIEKfi#?6T{mr@jD#99;8b zpZCzUUkjHxuc-HSVm`0Yy#=4agtk+AKor7YGe;JDr|ZLZQIeZonbXxqlGvuhwd8Sx zCr+ltrI9)hA`mPPMP@{M?8=d}Fxs=K1jkJzbg%hOd%U<0nOInh?{Y>3GO<0y(_baF zXQD$MLrf?PDm?1_}>R5r1B>J)QB_8u5dx7s}U;dvT8gaQq87_Mzlo(n9%V~&uFz+K;L>j78y}MT|Uo0lFQ6g#Z!z-zhf28uM)5< ztA@v=6nTsD_!8)6H9UW*^~>1zCtg0gCK>~m%_}}E`z*f#i*?9ZQwM8%c13firRtyT ziwv3Hg5=glwji(7xU7XIQ3>$uZQ+5Jl5e4B6VUzBQre>4$?j$br9LbIxCD>ccQDOQ)&=oBXO)43k66bRWj&*N6uC7;gogpP@k3!!z3@oOfc zjz#;09<>BR>bBTplwnB1@4sQO=i4yhv>C9}Q%?y~;53m$e_rZ2sL~ffG3uR+s?0#N zDGaZqmOrwj13*+SR%;vOb6b^}%kL9jIP3yf=sO_J{Z!n0Qu^BisaG~=fGKlEN* z0gTPt<|(UGq1m;~gLEbawu;i8ysF0B>M7`m4zsdw)mF?aL9Wgbv9KZx854oXHGGL= zI^oW+?e-Ld`}f@KLDnA6;aR#DEt1JzdD)Qrdp%%0-h=m%h(nm0W$+P9ScoEtHap}& zHVRv5NWa4#n=Z7j(A9@M+to45CEVl9%(-vyH5WOFT7flLPsSfZ7k9=(n9zC0JSA0P zZ&-WWlcnTN-ahUbB<;8DPGfy+j$bpOd8a)eX*t=#=_|VyU&6!9tgk!q z6DG9E&z}3?!n0?-=kXOom_bsk^oJwBAj(Q*(TXxlRNh<9z>K62JH=f0W zes#+O_btC|^&Na{Q~Z+&i&`Yodv`n+HC+1_&(po#g+S&r

#eDV(cxedC(gl>K3StgapZldw} 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

7#kef2&q{J4;4?whdIb0E!`kz1!+t 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

Z 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
NO(>k_`5^;-`+rEL`^f+R

-- 
1.7.1


From cc4307a86daa7502107ea27128485cdc132bb545 Mon Sep 17 00:00:00 2001
From: Edward Mann 
Date: Fri, 29 Aug 2008 02:37:11 +0000
Subject: [PATCH 11/16] syntax.xml update from hudson build on Thu 28 Aug 2008 09:25:08 PM CDT

---
 .../sourceforge/phpeclipse/phpeditor/syntax.xml    |  207 +++++++++++++-------
 1 files changed, 137 insertions(+), 70 deletions(-)

diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/syntax.xml b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/syntax.xml
index 35c78f0..fc39beb 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/syntax.xml
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/syntax.xml
@@ -2855,77 +2855,53 @@
 Obtain the backtrace for the exception as a string (instead of an array)
 Exception constructor
 ErrorException constructor
-PHP 5 allows developers to declare constructor methods for classes. Classes which have a constructor method call this method on each newly-created object, so it is suitable for any initialization that the object may need before it is used.PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as C++. The destructor method will be called as soon as all references to a particular object are removed or when the object is explicitly destroyed or in any order in shutdown sequence.
-
-
-
-
-
+PHP 5 allows developers to declare constructor methods for classes. Classes which have a constructor method call this method on each newly-created object, so it is suitable for any initialization that the object may need before it is used.PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as C++. The destructor method will be called as soon as all references to a particular object are removed or when the object is explicitly destroyed or in any order in shutdown sequence.
+
 
 
 
 
+
 
+
 
 
 
 
-
 
-
 
 
-
 
 
 
 
 
 
-
-
 
+
 
 
 
 
 
-
-
-
-
+
+
+
+
 
-
-
-
-
+
+
+
+
 
 
-
+
+
+
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
 
 
 
@@ -2957,6 +2933,7 @@
 
 
 
+
 
 
 
@@ -3102,6 +3079,17 @@
 
 
 
+
+
+
+
+
+
+
+
+
+
+
 
 
 
@@ -3538,10 +3526,10 @@
 
 
 
+
 
 
 
-
 
 
 
@@ -3668,6 +3656,8 @@
 
 
 
+Phar::SHA512 ( integer )
+Phar::PHPS ( integer )
 
 
 
@@ -3979,20 +3969,60 @@
 
 
 
-
-
-
-
-
-
-
+
+
+
 
-
-
+
+
 
+
+
+
+
+
+
 
+
+
+
+
+
+
+
+
+
+
+
+
+
 
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 
@@ -4564,24 +4594,24 @@
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 
@@ -4726,6 +4756,7 @@
 
 
 
+
 
 
 
@@ -6115,6 +6146,42 @@
 End Element
 End Entity
 XML Declaration node
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
  
 1
 2
-- 
1.7.1


From 4b7be67afac4e0634146e46431e34bad35403547 Mon Sep 17 00:00:00 2001
From: incastrix 
Date: Fri, 29 Aug 2008 03:02:34 +0000
Subject: [PATCH 12/16] Enable class members visibility icon in variable view.

---
 .../phpeclipse/xdebug/ui/XDebugUIPluginImages.java |    7 +++++++
 .../php/launching/PHPDebugModelPresentation.java   |   16 +++++++++++++---
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/net.sourceforge.phpeclipse.xdebug.ui/src/net/sourceforge/phpeclipse/xdebug/ui/XDebugUIPluginImages.java b/net.sourceforge.phpeclipse.xdebug.ui/src/net/sourceforge/phpeclipse/xdebug/ui/XDebugUIPluginImages.java
index 69e49cc..c689c49 100644
--- a/net.sourceforge.phpeclipse.xdebug.ui/src/net/sourceforge/phpeclipse/xdebug/ui/XDebugUIPluginImages.java
+++ b/net.sourceforge.phpeclipse.xdebug.ui/src/net/sourceforge/phpeclipse/xdebug/ui/XDebugUIPluginImages.java
@@ -51,6 +51,9 @@ public class XDebugUIPluginImages {
 	public static final String IMG_INFO_ST_OBJ="IMG_INFO_ST_OBJ";
 	public static final String IMG_ERROR_STACK_OBJ="IMG_ERROR_STACK_OBJ";
 
+	public static final String IMG_FIELD_PUBLIC = "IMG_FIELD_PUBLIC";
+	public static final String IMG_FIELD_PROTECTED = "IMG_FIELD_PROTECTED";
+	public static final String IMG_FIELD_PRIVATE = "IMG_FIELD_PRIVATE";
 
 	public static final String IMG_PROPERTIES          = "IMG_PROPERTIES";
 //	public static final String IMG_PROPERTIES_DISABLED = "IMG_PROPERTIES_DISABLED";
@@ -106,6 +109,10 @@ public class XDebugUIPluginImages {
 	}
 	
 	private static void declareImages() {
+		declareRegistryImage(IMG_FIELD_PUBLIC, T_OBJ + "methpub_obj.gif");
+		declareRegistryImage(IMG_FIELD_PROTECTED, T_OBJ + "methpro_obj.gif");
+		declareRegistryImage(IMG_FIELD_PRIVATE, T_OBJ + "methpri_obj.gif");
+
 		declareRegistryImage(IMG_EVIEW_ARGUMENTS_TAB, T_EVIEW + "arguments_tab.gif"); //$NON-NLS-1$
 		declareRegistryImage(IMG_EVIEW_ENVIROMENT_TAB, T_EVIEW + "environment_tab.gif"); //$NON-NLS-1$
 
diff --git a/net.sourceforge.phpeclipse.xdebug.ui/src/net/sourceforge/phpeclipse/xdebug/ui/php/launching/PHPDebugModelPresentation.java b/net.sourceforge.phpeclipse.xdebug.ui/src/net/sourceforge/phpeclipse/xdebug/ui/php/launching/PHPDebugModelPresentation.java
index 8ef0577..028eb2c 100644
--- a/net.sourceforge.phpeclipse.xdebug.ui/src/net/sourceforge/phpeclipse/xdebug/ui/php/launching/PHPDebugModelPresentation.java
+++ b/net.sourceforge.phpeclipse.xdebug.ui/src/net/sourceforge/phpeclipse/xdebug/ui/php/launching/PHPDebugModelPresentation.java
@@ -21,6 +21,7 @@ import net.sourceforge.phpeclipse.xdebug.php.model.XDebugThread;
 import net.sourceforge.phpeclipse.xdebug.php.model.XDebugStackFrame;
 import net.sourceforge.phpeclipse.xdebug.php.model.XDebugVariable;
 import net.sourceforge.phpeclipse.xdebug.php.model.XDebugValue;
+import net.sourceforge.phpeclipse.xdebug.ui.XDebugUIPluginImages;
 //import net.sourceforge.phpeclipse.xdebug.ui.XDebugUIPlugin;
 //import net.sourceforge.phpeclipse.xdebug.ui.php.launching.CopyOfPHPDebugModelPresentation.StorageEditorInput;
 
@@ -129,16 +130,25 @@ public class PHPDebugModelPresentation extends LabelProvider implements
 		return DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_BREAKPOINT);
 	}
 
-	private Image getVariableImage(XDebugVariable phpVar) {
+//	private Image getVariableImage(XDebugVariable phpVar) {
 		/*
 		 * if (phpVar != null) { if (phpVar.isLocal()) return
 		 * DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_VARIABLE); if
 		 * (phpVar.isHashValue()) return
 		 * DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_VARIABLE); }
 		 */
-		return DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_VARIABLE);
-	}
+	//	return DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_VARIABLE);
+	//}
+	
+	private Image getVariableImage(XDebugVariable phpVar) {
+		if (phpVar.getVisibility().equals("protected")) {
+			return XDebugUIPluginImages.get(XDebugUIPluginImages.IMG_FIELD_PROTECTED);			
+		}  else if (phpVar.getVisibility().equals("private")) {
+			return (XDebugUIPluginImages.get(XDebugUIPluginImages.IMG_FIELD_PRIVATE));			
+		}
 
+		return XDebugUIPluginImages.get(XDebugUIPluginImages.IMG_FIELD_PUBLIC);			
+	}
 	private Image getValueImage(XDebugValue phpVar) {
 		if (phpVar != null) {
 			return DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_VARIABLE);
-- 
1.7.1


From c1bb7c074e0b90ef5016ca846a1ebdb0c0ec4af1 Mon Sep 17 00:00:00 2001
From: incastrix 
Date: Sat, 30 Aug 2008 04:57:11 +0000
Subject: [PATCH 13/16] fix bug #675.

---
 .../xdebug/core/xdebug/XDebugConnection.java       |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/core/xdebug/XDebugConnection.java b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/core/xdebug/XDebugConnection.java
index 24fedd1..aa5793d 100644
--- a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/core/xdebug/XDebugConnection.java
+++ b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/core/xdebug/XDebugConnection.java
@@ -99,6 +99,9 @@ public class XDebugConnection {
 				else
 					attempts++;
 			}
+			
+			fDebugReader.readFully(byteBuffer,readCount,count);
+			
 			if((b= fDebugReader.readByte())!=0) // reads the NULL Byte at the end;
 				System.out.println("NULL-Byte missing!!"); 
 		} catch (IOException e) {
-- 
1.7.1


From 114b0e55a3a546458cafb2ef6f64dccc313c6ba2 Mon Sep 17 00:00:00 2001
From: incastrix 
Date: Sat, 30 Aug 2008 04:58:25 +0000
Subject: [PATCH 14/16] Change variable view behaviour.

---
 .../xdebug/php/model/XDebugArrayValue.java         |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugArrayValue.java b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugArrayValue.java
index a140ffb..3745a14 100644
--- a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugArrayValue.java
+++ b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugArrayValue.java
@@ -22,9 +22,13 @@ public class XDebugArrayValue extends XDebugAbstractValue {
 
 	public void renderValueString(String data) {
 		if (data.equals("")) {
-			fValueString = /*"Array */"empty";
+			fValueString = "empty";
 		} else {
-			fValueString = /*"Array " + */data + " element(s)";			
+			if ("array".equals(fTypeName)) {
+				fValueString = "array";
+			} else {
+				fValueString = data;
+			}
 		}
 	}
 
-- 
1.7.1


From 2b181b2bfa96140da49ef65e603e077b876779b2 Mon Sep 17 00:00:00 2001
From: incastrix 
Date: Sat, 13 Sep 2008 18:57:56 +0000
Subject: [PATCH 15/16] Remove unnecessary explicit cast.

---
 .../phpeclipse/xdebug/php/model/XDebugThread.java  |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugThread.java b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugThread.java
index 505b5a6..fa29d34 100644
--- a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugThread.java
+++ b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugThread.java
@@ -10,7 +10,6 @@ import java.net.MalformedURLException;
 import java.net.URL;
 
 import net.sourceforge.phpeclipse.xdebug.core.PHPDebugUtils;
-//import net.sourceforge.phpeclipse.xdebug.core.xdebug.ResponseListener.DebugResponse;
 import net.sourceforge.phpeclipse.xdebug.core.xdebug.ResponseListener.XDebugResponse;
 
 import org.eclipse.debug.core.DebugEvent;
@@ -30,7 +29,7 @@ import org.w3c.dom.NodeList;
  * Window - Preferences - Java - Code Style - Code Templates
  */
 public class XDebugThread extends XDebugElement implements IThread, IDebugEventSetListener {
-	private IStackFrame[]  fStackFrames;
+	private XDebugStackFrame[]  fStackFrames;
 	
 	private IBreakpoint[] fBreakpoints;
 	
@@ -57,7 +56,7 @@ public class XDebugThread extends XDebugElement implements IThread, IDebugEventS
 	}
 	
 	public IStackFrame[] getStackFrames() throws DebugException {
-		IStackFrame[] newStackFrames = null;
+		XDebugStackFrame[] newStackFrames = null;
 		
 		if (isSuspended()) {	
 			if (fStepCount > fCurrentStepCount) {
@@ -67,7 +66,7 @@ public class XDebugThread extends XDebugElement implements IThread, IDebugEventS
 				newStackFrames = _getStackFrames(dr);
 
 				for (int i = 0; i < newStackFrames.length; i++) {
-					((XDebugStackFrame)newStackFrames[i]).getVariables();
+					newStackFrames[i].getVariables();
 				}
 				
 				if (fStackFrames != null) {
@@ -75,10 +74,11 @@ public class XDebugThread extends XDebugElement implements IThread, IDebugEventS
 						int delta = newStackFrames.length - fStackFrames.length + 1;
 						
 						for (int i = fStackFrames.length - 1; i >= 0; i--) {
-							if (((XDebugStackFrame) fStackFrames[i]).equals(((XDebugStackFrame) newStackFrames[newStackFrames.length  - delta]))) {
+							if (fStackFrames[i].equals(newStackFrames[newStackFrames.length - delta])) {
 								int b = 2; b++;
 								//((XDebugStackFrame) newStackFrames[newStackFrames.length - delta]).evaluateChange((XDebugStackFrame) fStackFrames[i]);								
-							} else if (((XDebugStackFrame) fStackFrames[i]).isSameStackFrame(newStackFrames[newStackFrames.length  - delta])) {
+							} else if (fStackFrames[i].isSameStackFrame(newStackFrames[newStackFrames.length - delta])) {
+								int b = 2; b++;
 								//((XDebugStackFrame) newStackFrames[newStackFrames.length - delta]).evaluateChange((XDebugStackFrame) fStackFrames[i]);								
 							}
 							
@@ -98,14 +98,14 @@ public class XDebugThread extends XDebugElement implements IThread, IDebugEventS
 		}
 	}
 	
-	private IStackFrame[] _getStackFrames(XDebugResponse lastResponse) {
+	private XDebugStackFrame[] _getStackFrames(XDebugResponse lastResponse) {
 		//IStackFrame[] newStackFrames = null;
 
 	if (lastResponse.isError())
-		return new IStackFrame[0];
+		return new XDebugStackFrame[0];
 	Node response = lastResponse.getParentNode();
 	NodeList frames = response.getChildNodes();
-	IStackFrame[] theFrames = new IStackFrame[frames.getLength()];
+	XDebugStackFrame[] theFrames = new XDebugStackFrame[frames.getLength()];
 	for (int i = 0; i < frames.getLength(); i++) {
 		Node stackNode = frames.item(i);
 		XDebugStackFrame frame = new XDebugStackFrame(this/*fThread*/, i);
-- 
1.7.1


From ac9aaac9b65a6cd001e0683004de718eb615cd05 Mon Sep 17 00:00:00 2001
From: incastrix 
Date: Sun, 14 Sep 2008 04:46:14 +0000
Subject: [PATCH 16/16] Remove XDebugConnection dependence from XDebugWatchExpressionDelegate and add XdebugTarget#eval(String).

---
 .../phpeclipse/xdebug/php/model/XDebugTarget.java  |   16 ++++++-
 .../php/model/XDebugWatchExpressionDelegate.java   |   49 ++++++--------------
 2 files changed, 30 insertions(+), 35 deletions(-)

diff --git a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugTarget.java b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugTarget.java
index be31843..9b7b206 100644
--- a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugTarget.java
+++ b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugTarget.java
@@ -489,6 +489,16 @@ public class XDebugTarget extends XDebugElement implements IDebugTarget, IDebugE
 		}
 	}
 	
+	public Node eval(String expression) {
+		int id = fDebugConnection.eval(expression);
+		XDebugResponse response = getResponse(id);
+
+		Node evalResponse = response.getParentNode();
+		Node evalProperty = evalResponse.getFirstChild();
+		
+		return evalProperty;
+	}
+	
 	public void handleDebugEvents(DebugEvent[] events) {
 		for (int i = 0; i < events.length; i++) {
 			DebugEvent event = events[i];
@@ -620,11 +630,15 @@ public class XDebugTarget extends XDebugElement implements IDebugTarget, IDebugE
 		return response.getParentNode();
 	}
 	
+	public void stop() {
+		fDebugConnection.stop();
+	}
+	
 	protected IBreakpoint breakpointHit(Node node) {
 		Node child = node.getFirstChild();
 		if (child.getNodeName().equals("stack")) {
 			int lineNumber = Integer.parseInt(PHPDebugUtils.getAttributeValue(child, "lineno"));
-			String filename=PHPDebugUtils.getAttributeValue(child, "filename");  
+			String filename = PHPDebugUtils.getAttributeValue(child, "filename");  
 			IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
 			for (int i = 0; i < breakpoints.length; i++) {
 				IBreakpoint breakpoint = breakpoints[i];
diff --git a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugWatchExpressionDelegate.java b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugWatchExpressionDelegate.java
index a14bc08..9fbfdc2 100644
--- a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugWatchExpressionDelegate.java
+++ b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/php/model/XDebugWatchExpressionDelegate.java
@@ -1,8 +1,6 @@
 package net.sourceforge.phpeclipse.xdebug.php.model;
 
 
-import net.sourceforge.phpeclipse.xdebug.core.xdebug.XDebugConnection;
-import net.sourceforge.phpeclipse.xdebug.core.xdebug.ResponseListener.XDebugResponse;
 import net.sourceforge.phpeclipse.xdebug.php.model.XDebugVariable;
 import net.sourceforge.phpeclipse.xdebug.php.model.XDebugTarget;
 
@@ -15,40 +13,23 @@ import org.w3c.dom.Node;
 public class XDebugWatchExpressionDelegate implements IWatchExpressionDelegate {
 	public void evaluateExpression(String expression, IDebugElement context, IWatchExpressionListener listener) {
 		IWatchExpressionResult x;
-		XDebugConnection connection;
-		XDebugTarget s;
 
-		x = new XDebugWatchExpressionResult(expression, null, null);
-		
-		s = (XDebugTarget) context.getDebugTarget();
-		connection = (XDebugConnection) s.getDebugConnection();
-
-		if( connection != null ) {
-			try {
-				if( ! connection.isClosed() ) {
-					/*XDebugResponse*/ int evalCommand = connection.eval(expression);
-					
-					XDebugResponse response = s.getResponse(evalCommand);
-
-					
-					Node evalResponse = response.getParentNode();
-					Node evalProperty = evalResponse.getFirstChild();
-					XDebugVariable variable = new XDebugVariable(null, evalProperty);
-					XDebugVariable result[] = {variable};
-					
-					if (result.length == 0) {
-						x = new XDebugWatchExpressionResult(expression, null, null);
-					} else {
-						x = new XDebugWatchExpressionResult(expression, result[0].getValue(), null);
-					}
+		try {
+				Node evalProperty = ((XDebugTarget) context.getDebugTarget()).eval(expression);
+				XDebugVariable variable = new XDebugVariable(null, evalProperty);
+				XDebugVariable result[] = {variable};
+				
+				if (result.length == 0) {
+					x = new XDebugWatchExpressionResult(expression, null, null);
+				} else {
+					x = new XDebugWatchExpressionResult(expression, result[0].getValue(), null);
 				}
-			} catch (Exception e) {
-				String[] s1;
-	
-				s1 = new String[1];
-				s1[0] = e.toString();
-				x = new XDebugWatchExpressionResult(expression, null, s1);
-			}
+		} catch (Exception e) {
+			String[] s1;
+
+			s1 = new String[1];
+			s1[0] = e.toString();
+			x = new XDebugWatchExpressionResult(expression, null, s1);
 		}
 
 		listener.watchEvaluationFinished(x);
-- 
1.7.1