diff --git a/memory/org.eclipse.cdt.debug.ui.memory-feature/feature.properties b/memory/org.eclipse.cdt.debug.ui.memory-feature/feature.properties index 827e75627cc..58974a665b6 100644 --- a/memory/org.eclipse.cdt.debug.ui.memory-feature/feature.properties +++ b/memory/org.eclipse.cdt.debug.ui.memory-feature/feature.properties @@ -29,7 +29,7 @@ providerName=Eclipse CDT updateSiteName=Eclipse CDT Update Site # "description" property - description of the feature -description=Additional features for debug Memory View - traditional rendering, Find/Replace, Import/Export. +description=Additional features for debug Memory View - traditional rendering, floating-point rendering, Find/Replace, Import/Export. # "licenseURL" property - URL of the "Feature License" # do not translate value - just change to point to a locale-specific HTML page diff --git a/memory/org.eclipse.cdt.debug.ui.memory-feature/feature.xml b/memory/org.eclipse.cdt.debug.ui.memory-feature/feature.xml index 27fbf4a0fb8..334d34a8d3b 100644 --- a/memory/org.eclipse.cdt.debug.ui.memory-feature/feature.xml +++ b/memory/org.eclipse.cdt.debug.ui.memory-feature/feature.xml @@ -30,6 +30,13 @@ install-size="0" version="0.0.0" unpack="false"/> + + + + + + + + diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.gitignore b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.gitignore new file mode 100644 index 00000000000..ea8c4bf7f35 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.gitignore @@ -0,0 +1 @@ +/target diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.project b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.project new file mode 100644 index 00000000000..91d6dff85c8 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.project @@ -0,0 +1,28 @@ + + + org.eclipse.cdt.debug.ui.memory.floatingpoint + + + + + + 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/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.settings/org.eclipse.jdt.core.prefs b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..40227fe6c21 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,95 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.settings/org.eclipse.jdt.ui.prefs b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..56613a2a55a --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.ui.javadoc=true +org.eclipse.jdt.ui.text.custom_code_templates= diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.settings/org.eclipse.pde.prefs b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.settings/org.eclipse.pde.prefs new file mode 100644 index 00000000000..cf80c8bc5b8 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/.settings/org.eclipse.pde.prefs @@ -0,0 +1,32 @@ +compilers.f.unresolved-features=1 +compilers.f.unresolved-plugins=1 +compilers.incompatible-environment=1 +compilers.p.build=1 +compilers.p.build.bin.includes=1 +compilers.p.build.encodings=2 +compilers.p.build.java.compiler=2 +compilers.p.build.java.compliance=1 +compilers.p.build.missing.output=2 +compilers.p.build.output.library=1 +compilers.p.build.source.library=1 +compilers.p.build.src.includes=1 +compilers.p.deprecated=1 +compilers.p.discouraged-class=1 +compilers.p.internal=1 +compilers.p.missing-packages=1 +compilers.p.missing-version-export-package=2 +compilers.p.missing-version-import-package=1 +compilers.p.missing-version-require-bundle=1 +compilers.p.no-required-att=0 +compilers.p.not-externalized-att=2 +compilers.p.unknown-attribute=1 +compilers.p.unknown-class=1 +compilers.p.unknown-element=1 +compilers.p.unknown-identifier=1 +compilers.p.unknown-resource=1 +compilers.p.unresolved-ex-points=0 +compilers.p.unresolved-import=0 +compilers.s.create-docs=false +compilers.s.doc-folder=doc +compilers.s.open-tags=1 +eclipse.preferences.version=1 diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/META-INF/MANIFEST.MF b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..edfa244b84d --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/META-INF/MANIFEST.MF @@ -0,0 +1,17 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.cdt.debug.ui.memory.floatingpoint;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Localization: plugin +Require-Bundle: org.eclipse.debug.core;bundle-version="3.7.100", + org.eclipse.debug.ui;bundle-version="3.8.1", + org.eclipse.core.runtime;bundle-version="3.8.0", + org.eclipse.ui;bundle-version="3.8.0", + org.eclipse.search;bundle-version="3.8.0", + org.eclipse.cdt.debug.core;bundle-version="7.2.0" +Bundle-ActivationPolicy: lazy +Bundle-Activator: org.eclipse.cdt.debug.ui.memory.floatingpoint.FPRenderingPlugin +Bundle-Vendor: %providerName +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Export-Package: org.eclipse.cdt.debug.ui.memory.floatingpoint diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/build.properties b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/build.properties new file mode 100644 index 00000000000..a8d25594f6e --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/build.properties @@ -0,0 +1,12 @@ +source.. = src/ +bin.includes = .classpath,\ + .gitignore,\ + .project,\ + .settings/,\ + bin/,\ + build.properties,\ + META-INF/,\ + plugin.properties,\ + plugin.xml,\ + pom.xml,\ + . diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/plugin.properties b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/plugin.properties new file mode 100644 index 00000000000..fa0cd17819e --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/plugin.properties @@ -0,0 +1,22 @@ +############################################################################### +# Copyright (c) 2012 Wind River Systems and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Randy Rohrbach (Wind River) - Initial implementation +# IBM Corporation +############################################################################### +# +# Plugin information +# +pluginName = Floating Point Memory Renderer +providerName = Eclipse CDT +renderingType.name = Floating Point +page.name = Floating Point Memory Renderer +# +# Action preference text +# +FPRenderingPreferenceActionName=Floating Point Rendering Preferences ... diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/plugin.xml b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/plugin.xml new file mode 100644 index 00000000000..0f687ebde07 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/plugin.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/pom.xml b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/pom.xml new file mode 100644 index 00000000000..b6255b76271 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + + org.eclipse.cdt + cdt-parent + 8.1.0-SNAPSHOT + ../../../../pom/pom-all.xml + + + org.eclipse.cdt.debug.ui.memory.floatingpoint + 1.0.0.qualifier + eclipse-plugin + diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPAbstractPane.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPAbstractPane.java new file mode 100644 index 00000000000..c8da9cf9c48 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPAbstractPane.java @@ -0,0 +1,903 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import java.math.BigInteger; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.MemoryByte; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +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.Font; +import org.eclipse.swt.graphics.FontMetrics; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Caret; + +public abstract class FPAbstractPane extends Canvas +{ + protected Rendering fRendering; + + // Selection state + + protected boolean fSelectionStarted = false; + protected boolean fSelectionInProgress = false; + protected BigInteger fSelectionStartAddress = null; + protected int fSelectionStartAddressSubPosition; + + // Caret + + protected Caret fCaret = null; + + // Character may not fall on byte boundary + + protected int fSubCellCaretPosition = 0; + protected int fOldSubCellCaretPosition = 0; + protected boolean fCaretEnabled = false; + protected BigInteger fCaretAddress = null; + + // Storage + + protected int fRowCount = 0; + protected boolean fPaneVisible = true; + + // Mouse listener class + + class AbstractPaneMouseListener implements MouseListener + { + @Override + public void mouseUp(MouseEvent me) + { + // Move the caret + + positionCaret(me.x, me.y); + + fCaret.setVisible(true); + + if (fSelectionInProgress && me.button == 1) + endSelection(me.x, me.y); + + fSelectionInProgress = fSelectionStarted = false; + } + + // Mouse down click + + @Override + public void mouseDown(MouseEvent me) + { + // Any click, whether inside this cell or elsewhere, terminates the edit and acts the same as a carriage return would. + + handleCarriageReturn(); + + // Switch focus and check for selection + + FPAbstractPane.this.forceFocus(); + positionCaret(me.x, me.y); + fCaret.setVisible(false); + + if (me.button == 1) + { + // If shift is down and we have an existing start address, append selection + + if ((me.stateMask & SWT.SHIFT) != 0 && fRendering.getSelection().getStart() != null) + { + // If the pane doesn't have a selection start (the selection was created in a different + // pane) then initialize the pane's selection start to the rendering's selection start. + + if (FPAbstractPane.this.fSelectionStartAddress == null) + FPAbstractPane.this.fSelectionStartAddress = fRendering.getSelection().getStart(); + + FPAbstractPane.this.fSelectionStarted = true; + FPAbstractPane.this.appendSelection(me.x, me.y); + + } + else + { + // Start a new selection + + FPAbstractPane.this.startSelection(me.x, me.y); + } + } + + } + + // Double click + + @Override + public void mouseDoubleClick(MouseEvent me) + { + handleMouseDoubleClick(me); + } + } + + // Mouse move listener class + + class AbstractPaneMouseMoveListener implements MouseMoveListener + { + @Override + public void mouseMove(MouseEvent me) + { + if (fSelectionStarted) + { + fSelectionInProgress = true; + appendSelection(me.x, me.y); + } + } + } + + // Focus listener class + + class AbstractPaneFocusListener implements FocusListener + { + @Override + public void focusLost(FocusEvent fe) + { + IPreferenceStore store = FPRenderingPlugin.getDefault().getPreferenceStore(); + + if (FPRenderingPreferenceConstants.MEM_EDIT_BUFFER_SAVE_ON_ENTER_ONLY.equals(store.getString(FPRenderingPreferenceConstants.MEM_EDIT_BUFFER_SAVE))) + fRendering.getViewportCache().clearEditBuffer(); + else + fRendering.getViewportCache().writeEditBuffer(); + + // clear the pane local selection start + FPAbstractPane.this.fSelectionStartAddress = null; + } + + @Override + public void focusGained(FocusEvent fe) + { + // Set the floating point edit mode indicator if the user clicked in the Data Pane; otherwise clear it + + if (FPAbstractPane.this instanceof FPDataPane) + fRendering.displayEditModeIndicator(true); + else + fRendering.displayEditModeIndicator(false); + } + } + + // Key listener class + + class AbstractPaneKeyListener implements KeyListener + { + @Override + public void keyPressed(KeyEvent ke) + { + fOldSubCellCaretPosition = fSubCellCaretPosition; + + // Shift + + if ((ke.stateMask & SWT.SHIFT) != 0) + { + switch (ke.keyCode) + { + case SWT.ARROW_RIGHT: + case SWT.ARROW_LEFT: + case SWT.ARROW_UP: + case SWT.ARROW_DOWN: + case SWT.PAGE_DOWN: + case SWT.PAGE_UP: + { + if (fRendering.getSelection().getStart() == null) + fRendering.getSelection().setStart(fCaretAddress.add(BigInteger.valueOf(fRendering.getAddressesPerColumn())), fCaretAddress); + break; + } + } + } + + // Arrow, Page, Insert, Escape and standard characters + + if (ke.keyCode == SWT.ARROW_RIGHT) + { + handleRightArrowKey(); + } + else if (ke.keyCode == SWT.ARROW_LEFT || ke.keyCode == SWT.BS) + { + handleLeftArrowKey(); + } + else if (ke.keyCode == SWT.ARROW_DOWN) + { + handleDownArrowKey(); + } + else if (ke.keyCode == SWT.ARROW_UP) + { + handleUpArrowKey(); + } + else if (ke.keyCode == SWT.PAGE_DOWN) + { + handlePageDownKey(); + } + else if (ke.keyCode == SWT.PAGE_UP) + { + handlePageUpKey(); + } + else if (ke.keyCode == SWT.INSERT) + { + handleInsertKey(); + } + else if (ke.keyCode == SWT.ESC) + { + fRendering.getViewportCache().clearEditBuffer(); + handleCTRLZ(); + } + else if (ke.character == '\r') + { + fRendering.getViewportCache().writeEditBuffer(); + handleCarriageReturn(); + } + else if (FPutilities.validEditCharacter(ke.character)) + { + // Check for selection + + if (fRendering.getSelection().hasSelection()) + { + setCaretAddress(fRendering.getSelection().getLow()); + fSubCellCaretPosition = 0; + } + + // Add the chatacter to the cell + + editCell(fCaretAddress, fSubCellCaretPosition, ke.character); + } + + // Control + + if ((ke.stateMask & SWT.CTRL) != 0) + { + // CTRL/Z + + if (ke.keyCode == 'z' || ke.keyCode == 'Z') + handleCTRLZ(); + } + + // Alt + + if ((ke.stateMask & SWT.ALT) != 0) + { + // Future use + } + + // Shift + + if ((ke.stateMask & SWT.SHIFT) != 0) + { + switch (ke.keyCode) + { + case SWT.ARROW_RIGHT: + case SWT.ARROW_LEFT: + case SWT.ARROW_UP: + case SWT.ARROW_DOWN: + case SWT.PAGE_DOWN: + case SWT.PAGE_UP: + fRendering.getSelection().setEnd(fCaretAddress.add(BigInteger.valueOf(fRendering.getAddressesPerColumn())), fCaretAddress); + break; + } + } + else if (ke.keyCode != SWT.SHIFT) + { + // If it's a SHIFT key, keep the selection since we may add to it + fRendering.getSelection().clear(); + } + } + + @Override + public void keyReleased(KeyEvent ke) + { + // do nothing + } + } + + class AbstractPanePaintListener implements PaintListener + { + @Override + public void paintControl(PaintEvent pe) + { + FPAbstractPane.this.paint(pe); + } + } + + public FPAbstractPane(Rendering rendering) + { + super(rendering, SWT.DOUBLE_BUFFERED); + + fRendering = rendering; + + try + { + fCaretAddress = rendering.getBigBaseAddress(); + } + catch (Exception e) + { + // do nothing + } + + // pref + + this.setFont(fRendering.getFont()); + + GC gc = new GC(this); + gc.setFont(this.getFont()); + fCaret = new Caret(this, SWT.NONE); + fCaret.setSize(1, gc.stringExtent("|").y); //$NON-NLS-1$ + gc.dispose(); + + this.addPaintListener(createPaintListener()); + this.addMouseListener(createMouseListener()); + this.addMouseMoveListener(createMouseMoveListener()); + this.addKeyListener(createKeyListener()); + this.addFocusListener(createFocusListener()); + } + + // Listener methods + + protected MouseListener createMouseListener() + { + return new AbstractPaneMouseListener(); + } + + protected MouseMoveListener createMouseMoveListener() + { + return new AbstractPaneMouseMoveListener(); + } + + protected FocusListener createFocusListener() + { + return new AbstractPaneFocusListener(); + } + + protected KeyListener createKeyListener() + { + return new AbstractPaneKeyListener(); + } + + protected PaintListener createPaintListener() + { + return new AbstractPanePaintListener(); + } + + // Right arrow + + protected void handleRightArrowKey() + { + fSubCellCaretPosition++; + + if (fSubCellCaretPosition >= getCellCharacterCount()) + { + // We've moved beyond the end of the cell: End the edit to the previous cell. + + handleCarriageReturn(); + + // Move to the next cell; ensure that caret is within the addressable range + + fSubCellCaretPosition = 0; + BigInteger newCaretAddress = fCaretAddress.add(BigInteger.valueOf(fRendering.getFPDataType().getByteLength())); + + if (newCaretAddress.compareTo(fRendering.getMemoryBlockEndAddress()) > 0) + fSubCellCaretPosition = getCellCharacterCount(); + else + setCaretAddress(newCaretAddress); + } + + updateTheCaret(); + ensureCaretWithinViewport(); + } + + // Left arrow + + protected void handleLeftArrowKey() + { + fSubCellCaretPosition--; + + if (fSubCellCaretPosition < 0) + { + // We've moved beyond the beginning of the cell: This action ends the edit to the previous cell. + + handleCarriageReturn(); + + // Move to the previous cell; ensure that caret is within the addressable range + + fSubCellCaretPosition = getCellCharacterCount() - 1; + BigInteger newCaretAddress = fCaretAddress.subtract(BigInteger.valueOf(fRendering.getFPDataType().getByteLength())); + + if (newCaretAddress.compareTo(fRendering.getMemoryBlockStartAddress()) < 0) + fSubCellCaretPosition = 0; + else + setCaretAddress(newCaretAddress); + } + + updateTheCaret(); + ensureCaretWithinViewport(); + } + + // Down arrow + + protected void handleDownArrowKey() + { + // We've moved beyond the beginning of the cell: This action ends the edit to the previous cell. + + handleCarriageReturn(); + + // Ensure that caret is within the addressable range + + BigInteger newCaretAddress = fCaretAddress.add(BigInteger.valueOf(fRendering.getFPDataType().getByteLength() * fRendering.getColumnCount())); + setCaretAddress(newCaretAddress); + updateTheCaret(); + ensureCaretWithinViewport(); + } + + // Up arrow + + protected void handleUpArrowKey() + { + // We've moved beyond the beginning of the cell: This action ends the edit to the previous cell. + + handleCarriageReturn(); + + // Ensure that caret is within the addressable range + + BigInteger newCaretAddress = fCaretAddress.subtract(BigInteger.valueOf(fRendering.getFPDataType().getByteLength() * fRendering.getColumnCount())); + setCaretAddress(newCaretAddress); + updateTheCaret(); + ensureCaretWithinViewport(); + } + + // Page down + + protected void handlePageDownKey() + { + // We've moved beyond the beginning of the cell: This action ends the edit to the previous cell. + + handleCarriageReturn(); + + // Ensure that caret is within the addressable range + + BigInteger newCaretAddress = fCaretAddress.add(BigInteger.valueOf(fRendering.getAddressableCellsPerRow() * (fRendering.getRowCount() - 1))); + setCaretAddress(newCaretAddress); + updateTheCaret(); + ensureCaretWithinViewport(); + } + + // Page up + + protected void handlePageUpKey() + { + // We've moved beyond the beginning of the cell: This action ends the edit to the previous cell. + + handleCarriageReturn(); + + // Ensure that caret is within the addressable range + + BigInteger newCaretAddress = fCaretAddress.subtract(BigInteger.valueOf(fRendering.getAddressableCellsPerRow() * (fRendering.getRowCount() - 1))); + setCaretAddress(newCaretAddress); + updateTheCaret(); + ensureCaretWithinViewport(); + } + + // Insert key + + protected void handleInsertKey() + { + // If focus is in the Data Pane, toggle Insert/Overwrite mode and make sure the cell edit + // status line indicator is displayed. Otherwise, make clear the status line indicator. + + if (FPAbstractPane.this instanceof FPDataPane) + { + if (!fRendering.isEditingCell()) fRendering.setInsertMode(!fRendering.insertMode()); + fRendering.displayEditModeIndicator(true); + } + else + fRendering.displayEditModeIndicator(false); + } + + // Double-click + + protected void handleMouseDoubleClick(MouseEvent me) + { + try + { + BigInteger address = getViewportAddress(me.x / getCellWidth(), me.y / getCellHeight()); + + fRendering.getSelection().clear(); + fRendering.getSelection().setStart(address.add(BigInteger.valueOf(fRendering.getAddressesPerColumn())), address); + fRendering.getSelection().setEnd(address.add(BigInteger.valueOf(fRendering.getAddressesPerColumn())), address); + } + catch (DebugException de) + { + // do nothing + } + } + + // Carriage return + + protected void handleCarriageReturn() + { + // If we're not editing a cell or there is no string buffer to use, nothing to do: Exit edit mode and return. + + if (!fRendering.isEditingCell() || fRendering.getEditBuffer() == null) + { + fRendering.endCellEditing(); + return; + } + + // Remove all whitespace from the string buffer. + + fRendering.setEditBuffer(new StringBuffer(fRendering.getEditBuffer().toString().trim().replaceAll(" ", ""))); //$NON-NLS-1$ //$NON-NLS-2$ + + // Check the string to make sure it's in valid, acceptable form. + + if (FPutilities.isValidFormat(fRendering.getEditBuffer().toString())) + { + // Valid string: Convert it to a byte array and write the buffer back to memory; + // a subsequent re-draw/paint converts it to normalized scientific notation. + + fRendering.convertAndUpdateCell(fRendering.getCellEditAddress(), fRendering.getEditBuffer().toString()); + } + else + { + // Invalid string: Create the error text and restore the previous value + + String errorText = NLS.bind(FPRenderingMessages.getString("FPRendering.ERROR_FPENTRY_POPUP_TEXT"), fRendering.getEditBuffer().toString()); //$NON-NLS-1$ + + try + { + fRendering.setEditBuffer(new StringBuffer(fRendering.fDataPane.bytesToSciNotation(fRendering.getBytes(fCaretAddress, fRendering.getFPDataType().getByteLength())))); + } + catch (DebugException e) + { + e.printStackTrace(); + } + + // Put together the pop-up window components and show the user the error + + String statusString = FPRenderingMessages.getString("FPRendering.ERROR_FPENTRY_STATUS"); //$NON-NLS-1$ + Status status = new Status(IStatus.ERROR, FPRenderingPlugin.getUniqueIdentifier(), statusString); + FPutilities.popupMessage(FPRenderingMessages.getString("FPRendering.ERROR_FPENTRY_POPUP_TITLE"), errorText, status); //$NON-NLS-1$ + } + + // Exit cell-edit mode + + fRendering.endCellEditing(); + } + + // CTRL/Z handling + + protected void handleCTRLZ() + { + // CTRL/Z: Replace the cell contents with the original value and exit "number edit mode" + + try + { + fRendering.setEditBuffer(new StringBuffer(fRendering.fDataPane.bytesToSciNotation(fRendering.getBytes(fCaretAddress, fRendering.getFPDataType().getByteLength())))); + } + catch (DebugException e) + { + e.printStackTrace(); + } + + fRendering.endCellEditing(); + } + + // Other getter/setters + + protected boolean isPaneVisible() + { + return fPaneVisible; + } + + protected void setPaneVisible(boolean visible) + { + fPaneVisible = visible; + this.setVisible(visible); + } + + protected int getNumberOfBytesRepresentedByColumn() + { + return fRendering.getCharsPerColumn(); + } + + protected void editCell(BigInteger cellAddress, int subCellPosition, char character) + { + // Do nothing; overridden in subclass FPDataPane + } + + // Set the caret address + + protected void setCaretAddress(BigInteger caretAddress) + { + // Ensure that caret is within the addressable range + + if ((caretAddress.compareTo(fRendering.getMemoryBlockStartAddress()) >= 0) && (caretAddress.compareTo(fRendering.getMemoryBlockEndAddress()) <= 0)) + { + fCaretAddress = caretAddress; + } + else if (caretAddress.compareTo(fRendering.getMemoryBlockStartAddress()) < 0) + { + // Calculate offset from the beginning of the row + + int cellOffset = fCaretAddress.subtract(fRendering.getViewportStartAddress()).intValue(); + int row = cellOffset / (fRendering.getBytesPerRow() / fRendering.getBytesPerCharacter()); + + cellOffset -= row * fRendering.getBytesPerRow() / fRendering.getBytesPerCharacter(); + + fCaretAddress = fRendering.getMemoryBlockStartAddress().add(BigInteger.valueOf(cellOffset / fRendering.getAddressableSize())); + } + else if (caretAddress.compareTo(fRendering.getMemoryBlockEndAddress()) > 0) + { + // Calculate offset from the end of the row + + int cellOffset = fCaretAddress.subtract(fRendering.getViewportEndAddress()).intValue() + 1; + int row = cellOffset / (fRendering.getBytesPerRow() / fRendering.getBytesPerCharacter()); + + cellOffset -= row * fRendering.getBytesPerRow() / fRendering.getBytesPerCharacter(); + + fCaretAddress = fRendering.getMemoryBlockEndAddress().add(BigInteger.valueOf(cellOffset / fRendering.getAddressableSize())); + } + + fRendering.setCaretAddress(fCaretAddress); + } + + protected boolean isOdd(int value) + { + return (value / 2) * 2 == value; + } + + protected void updateTheCaret() + { + try + { + if (fCaretAddress != null) + { + Point cellPosition = getCellLocation(fCaretAddress); + + if (cellPosition != null) + fCaret.setLocation(cellPosition.x + fSubCellCaretPosition * getCellCharacterWidth(), cellPosition.y); + } + } + catch (Exception e) + { + fRendering.logError(FPRenderingMessages.getString("FPRendering.FAILURE_POSITION_CURSOR"), e); //$NON-NLS-1$ + } + } + + // This method scrolls the viewport to insure that the caret is within the viewable area + + protected void ensureCaretWithinViewport() // TODO getAddressableSize() > 1 ? + { + // If the caret is before the viewport start if so, scroll viewport up by several rows + + BigInteger rowCount = BigInteger.valueOf(getRowCount()); + BigInteger rowMemBytes = BigInteger.valueOf(fRendering.getFPDataType().getByteLength() * fRendering.getColumnCount()); + BigInteger viewableBytes = rowCount.multiply(rowMemBytes); + BigInteger viewableEnd = fRendering.getViewportStartAddress().add(viewableBytes); + + if (fCaretAddress.compareTo(fRendering.getViewportStartAddress()) < 0) + { + fRendering.setViewportStartAddress(fRendering.getViewportStartAddress().subtract(rowMemBytes)); + fRendering.ensureViewportAddressDisplayable(); + fRendering.gotoAddress(fRendering.getViewportStartAddress()); + } + + // If the caret is after the viewport end if so, scroll viewport down by appropriate rows + + else if (fCaretAddress.compareTo(viewableEnd) >= 0) + { + fRendering.setViewportStartAddress(fRendering.getViewportStartAddress().add(rowMemBytes)); + fRendering.ensureViewportAddressDisplayable(); + fRendering.gotoAddress(fRendering.getViewportStartAddress()); + } + + fRendering.setCaretAddress(fCaretAddress); + } + + protected void advanceCursor() + { + handleRightArrowKey(); + } + + protected void positionCaret(int x, int y) + { + // do nothing + } + + protected int getRowCount() + { + return fRowCount; + } + + protected void setRowCount() + { + fRowCount = getBounds().height / getCellHeight(); + } + + protected void settingsChanged() + { + fSubCellCaretPosition = 0; + } + + // Start selection + + protected void startSelection(int x, int y) + { + try + { + BigInteger address = getViewportAddress(x / getCellWidth(), y / getCellHeight()); + + if (address != null) + { + this.fSelectionStartAddress = address; + Point cellPosition = getCellLocation(address); + + if (cellPosition != null) + { + int offset = x - cellPosition.x; + fSelectionStartAddressSubPosition = offset / getCellCharacterWidth(); + } + + fRendering.getSelection().clear(); + fRendering.getSelection().setStart(address.add(BigInteger.valueOf(fRendering.getFPDataType().getByteLength())), address); + fSelectionStarted = true; + + new CopyAction(fRendering, DND.SELECTION_CLIPBOARD).run(); + } + } + catch (DebugException e) + { + fRendering.logError(FPRenderingMessages.getString("FPRendering.FAILURE_START_SELECTION"), e); //$NON-NLS-1$ + } + } + + // End selection + + protected void endSelection(int x, int y) + { + appendSelection(x, y); + fSelectionInProgress = false; + } + + protected void appendSelection(int x, int y) + { + try + { + if (this.fSelectionStartAddress == null) return; + + BigInteger address = getViewportAddress(x / getCellWidth(), y / getCellHeight()); + + if (address.compareTo(this.fSelectionStartAddress) == 0) + { + // Sub-cell selection + + Point cellPosition = getCellLocation(address); + int offset = x - cellPosition.x; + int subCellCharacterPosition = offset / getCellCharacterWidth(); + + if (Math.abs(subCellCharacterPosition - this.fSelectionStartAddressSubPosition) > this.getCellCharacterCount() / 4) + { + fRendering.getSelection().setEnd(address.add(BigInteger.valueOf((fRendering.getFPDataType().getByteLength()))), address); + } + else + { + fRendering.getSelection().setEnd(null, null); + } + } + else + { + fRendering.getSelection().setEnd(address.add(BigInteger.valueOf(fRendering.getFPDataType().getByteLength())), address); + } + + if (fRendering.getSelection().getEnd() != null) + { + this.fCaretAddress = fRendering.getSelection().getEnd(); + this.fSubCellCaretPosition = 0; + } + + updateTheCaret(); + + new CopyAction(fRendering, DND.SELECTION_CLIPBOARD).run(); + } + catch (Exception e) + { + fRendering.logError(FPRenderingMessages.getString("FPRendering.FAILURE_APPEND_SELECTION"), e); //$NON-NLS-1$ + } + } + + protected void paint(PaintEvent pe) + { + fRowCount = getBounds().height / getCellHeight(); + + if (fRendering.isDirty()) + { + fRendering.setDirty(false); + fRendering.refresh(); + } + } + + abstract protected BigInteger getViewportAddress(int col, int row) throws DebugException; + + protected Point getCellLocation(BigInteger address) + { + return null; + } + + protected String getCellText(MemoryByte bytes[]) + { + return null; + } + + abstract protected int getCellWidth(); + + abstract protected int getCellCharacterCount(); + + @Override + public void setFont(Font font) + { + super.setFont(font); + fCharacterWidth = -1; + fCellHeight = -1; + fTextHeight = -1; + } + + private int fCellHeight = -1; // called often, cache + + protected int getCellHeight() + { + if (fCellHeight == -1) + { + fCellHeight = getCellTextHeight() + (fRendering.getCellPadding() * 2); + } + + return fCellHeight; + } + + private int fCharacterWidth = -1; // called often, cache + + protected int getCellCharacterWidth() + { + if (fCharacterWidth == -1) + { + GC gc = new GC(this); + gc.setFont(fRendering.getFont()); + fCharacterWidth = gc.getAdvanceWidth('F'); + gc.dispose(); + } + + return fCharacterWidth; + } + + private int fTextHeight = -1; // called often, cache + + protected int getCellTextHeight() + { + if (fTextHeight == -1) + { + GC gc = new GC(this); + gc.setFont(fRendering.getFont()); + FontMetrics fontMetrics = gc.getFontMetrics(); + fTextHeight = fontMetrics.getHeight(); + gc.dispose(); + } + return fTextHeight; + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPAddressPane.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPAddressPane.java new file mode 100644 index 00000000000..3e7ff179772 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPAddressPane.java @@ -0,0 +1,237 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import java.math.BigInteger; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.graphics.FontMetrics; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; + +public class FPAddressPane extends FPAbstractPane +{ + final int bytesPerColumn = fRendering.getFPDataType().getByteLength(); + + public FPAddressPane(Rendering parent) + { + super(parent); + } + + @Override + protected BigInteger getViewportAddress(int col, int row) throws DebugException + { + BigInteger address = fRendering.getViewportStartAddress(); +// address = address.add(BigInteger.valueOf((row * fRendering.getColumnCount() + col) * fRendering.getAddressesPerColumn())); + address = address.add(BigInteger.valueOf((row * fRendering.getColumnCount() + col) * fRendering.getFPDataType().getByteLength())); + return address; + } + + @Override + protected void appendSelection(int x, int y) + { + try + { + if (this.fSelectionStartAddress == null) return; + + BigInteger address = getViewportAddress(x / getCellWidth(), y / getCellHeight()); + + if (address.compareTo(this.fSelectionStartAddress) == 0) + { + // The address hasn't changed + + fRendering.getSelection().setEnd(null, null); + } + else + { + // The address has changed + + fRendering.getSelection().setEnd(address.add(BigInteger.valueOf(fRendering.getFPDataType().getByteLength() * fRendering.getColumnCount())), address); + } + } + catch(Exception e) + { + fRendering.logError(FPRenderingMessages.getString("FPRendering.FAILURE_APPEND_SELECTION"), e); //$NON-NLS-1$ + } + } + + @Override + public Point computeSize(int wHint, int hHint) + { + return new Point(getCellWidth() + fRendering.getRenderSpacing(), 100); + } + + @Override + protected int getCellCharacterCount() + { + // Two characters per byte of HEX address + + return fRendering.getAddressBytes() * 2 + 2; // 0x + } + + @Override + protected int getCellWidth() + { + GC gc = new GC(this); + StringBuffer buf = new StringBuffer(); + for(int index = 0; index < getCellCharacterCount(); index++) + buf.append("0"); //$NON-NLS-1$ + int width = gc.textExtent(buf.toString()).x; + gc.dispose(); + return width; + } + + private int getColumnCount() + { + return 0; + } + + private BigInteger getCellAddressAt(int x, int y) throws DebugException + { + BigInteger address = fRendering.getViewportStartAddress(); + + int col = x / getCellWidth(); + int row = y / getCellHeight(); + + if(col > getColumnCount()) + return null; + + address = address.add(BigInteger.valueOf(row * fRendering.getColumnCount() * fRendering.getAddressesPerColumn() / fRendering.getBytesPerCharacter())); + address = address.add(BigInteger.valueOf(col * fRendering.getAddressesPerColumn())); + + return address; + } + + @Override + protected Point getCellLocation(BigInteger cellAddress) + { + try + { + BigInteger address = fRendering.getViewportStartAddress(); + + int cellOffset = cellAddress.subtract(address).intValue(); + + cellOffset *= fRendering.getAddressableSize(); + + if(fRendering.getColumnCount() == 0) // avoid divide by zero + return new Point(0,0); + + int row = cellOffset / (fRendering.getColumnCount() * fRendering.getCharsPerColumn() / fRendering.getBytesPerCharacter()); + cellOffset -= row * fRendering.getColumnCount() * fRendering.getCharsPerColumn() / fRendering.getBytesPerCharacter(); + int col = cellOffset / fRendering.getCharsPerColumn() / fRendering.getBytesPerCharacter(); + + int x = col * getCellWidth() + fRendering.getCellPadding(); + int y = row * getCellHeight() + fRendering.getCellPadding(); + + return new Point(x, y); + } + catch(Exception e) + { + fRendering.logError(FPRenderingMessages.getString("FPRendering.FAILURE_DETERMINE_CELL_LOCATION"), e); //$NON-NLS-1$ + return null; + } + } + + @Override + protected int getNumberOfBytesRepresentedByColumn() + { + return fRendering.getBytesPerRow(); + } + + @Override + protected void positionCaret(int x, int y) + { + try + { + BigInteger cellAddress = getCellAddressAt(x, y); + if(cellAddress != null) + { + Point cellPosition = getCellLocation(cellAddress); + + int offset = x - cellPosition.x; + int x2 = offset / getCellCharacterWidth(); + + if(x2 >= this.getCellCharacterCount()) + { + cellAddress = cellAddress.add(BigInteger.valueOf(this.getNumberOfBytesRepresentedByColumn())); + x2 = 0; + cellPosition = getCellLocation(cellAddress); + } + + fCaret.setLocation(cellPosition.x + x2 * getCellCharacterWidth(), cellPosition.y); + + this.fCaretAddress = cellAddress; + this.fSubCellCaretPosition = x2; + setCaretAddress(fCaretAddress); + } + } + catch(Exception e) + { + fRendering.logError(FPRenderingMessages.getString("FPRendering.FAILURE_POSITION_CURSOR"), e); //$NON-NLS-1$ + } + } + + @Override + protected void paint(PaintEvent pe) + { + super.paint(pe); + + GC gc = pe.gc; + + FontMetrics fontMetrics = gc.getFontMetrics(); + int textHeight = fontMetrics.getHeight(); + int cellHeight = textHeight + (fRendering.getCellPadding() * 2); + final int memBytesPerCol = fRendering.getFPDataType().getByteLength(); + + try + { + BigInteger start = fRendering.getViewportStartAddress(); + + for(int index = 0; index < this.getBounds().height / cellHeight; index++) + { + BigInteger memAddress = start.add(BigInteger.valueOf(index * fRendering.getColumnCount() * memBytesPerCol)); + gc.setForeground(fRendering.getFPRendering().getColorText()); + + // Highlight the selected addresses if necessary; otherwise use the standard foreground/background colors + + if (fRendering.getSelection().isSelected(memAddress)) + { + gc.setBackground(fRendering.getFPRendering().getColorSelection()); + gc.fillRectangle(fRendering.getCellPadding() * 2, cellHeight * index, getCellWidth(), cellHeight); + gc.setForeground(fRendering.getFPRendering().getColorBackground()); + } + else + { + gc.setBackground(fRendering.getFPRendering().getColorBackground()); + gc.fillRectangle(fRendering.getCellPadding() * 2, cellHeight * index, getCellWidth(), cellHeight); + // Allow subclass to override this method to do its own coloring + applyCustomColor(gc); + } + + gc.drawText(fRendering.getAddressString(memAddress), + fRendering.getCellPadding() * 2, cellHeight * index + fRendering.getCellPadding()); + } + } + catch(Exception e) + { + fRendering.logError(FPRenderingMessages.getString("FPRendering.FAILURE_PAINT"), e); //$NON-NLS-1$ + } + } + + // Allow subclass to override this method to do its own coloring + protected void applyCustomColor(GC gc) + { + gc.setForeground(fRendering.getFPRendering().getColorText()); + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPDataPane.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPDataPane.java new file mode 100644 index 00000000000..2ee7bce1ced --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPDataPane.java @@ -0,0 +1,399 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import java.math.BigInteger; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; + +public class FPDataPane extends FPAbstractPane +{ + public FPDataPane(Rendering parent) + { + super(parent); + } + + // Returns the representation of the given memory bytes as a scientific notation string + + protected String bytesToSciNotation(FPMemoryByte[] bytes) + { + return fRendering.sciNotationString(bytes, fRendering.getFPDataType(), fRendering.isDisplayLittleEndian()); + } + + // Cell editing: Accumulate text entry characters, replacing or inserting them at the current cursor position + + @Override + protected void editCell(BigInteger cellAddress, int subCellPosition, char character) + { + try + { + // Switch to cell edit mode if not we're not currently in the middle of an edit + + if (!fRendering.isEditingCell()) + { + // Calculate the memory address from the cell address + + BigInteger vpStart = fRendering.getViewportStartAddress(); + BigInteger colChars = BigInteger.valueOf(fRendering.getCharsPerColumn()); + BigInteger dtBytes = BigInteger.valueOf(fRendering.getFPDataType().getByteLength()); + BigInteger memoryAddress = vpStart.add(((cellAddress.subtract(vpStart)).divide(colChars)).multiply(dtBytes)); + + if (!fRendering.insertMode()) + { + // Overstrike/overwrite mode: Enter cell-edit mode; start with the current cell contents. + + fRendering.startCellEditing(cellAddress, memoryAddress, bytesToSciNotation(fRendering.getBytes(cellAddress, fRendering.getFPDataType().getByteLength()))); + } + else + { + // Insert/Replace mode: Clear the current cell contents; start + // with a blank string. Move the caret to the start of the cell. + + fRendering.startCellEditing(cellAddress, memoryAddress, FPutilities.fillString(fRendering.getCharsPerColumn(), ' ')); + + subCellPosition = 0; + Point cellCoordinates = getCellLocation(cellAddress); + positionCaret(cellCoordinates.x, cellCoordinates.y); + fCaret.setVisible(true); + } + } + + // Validate the current string: Only one decimal point and exponent character ('e' or 'E') is allowed. Number + // signs may be present up to two times - once for the number and once for the exponent, and may occur at the + // very beginning of a number or immediately after the exponent character. If an entry violates a rule, do not + // echo the character (implicitly, through replacement and re-paint) and do not advance the cursor. + + String cellString = fRendering.getEditBuffer().toString().toLowerCase(); + + // Check to see if a second decimal point or exponent was entered + + if ((character == '.' && FPutilities.countMatches(cellString, ".") > 0 && cellString.indexOf('.') != subCellPosition) || //$NON-NLS-1$ + (character == 'e' && FPutilities.countMatches(cellString, "e") > 0 && cellString.indexOf('e') != subCellPosition)) //$NON-NLS-1$ + return; + + // Check to see if more than two number signs have been entered + + if ((character == '+' && FPutilities.countMatches(cellString, "+") > 1) || //$NON-NLS-1$ + (character == '-' && FPutilities.countMatches(cellString, "-") > 1)) //$NON-NLS-1$ + return; + + // We've passed the previous checks: Make the character substitution, if possible. + // Advance the cursor as long as we're inside the column. Re-paint the view. + + if (subCellPosition < fRendering.getEditBuffer().length()) + fRendering.getEditBuffer().setCharAt(subCellPosition, character); + + if (subCellPosition < fRendering.getCharsPerColumn()) + advanceCursor(); + + redraw(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + // Returns cell width, in pixels + + @Override + protected int getCellWidth() + { + return getCellCharacterCount() * getCellCharacterWidth() + (fRendering.getCellPadding() * 2); + } + + @Override + protected int getCellCharacterCount() + { + return fRendering.getCharsPerColumn(); + } + + @Override + public Point computeSize(int wHint, int hHint) + { + return new Point(fRendering.getColumnCount() * getCellWidth() + fRendering.getRenderSpacing(), 100); + } + + private BigInteger getCellAddressAt(int x, int y) throws DebugException + { + BigInteger address = fRendering.getViewportStartAddress(); + + int col = x / getCellWidth(); + int row = y / getCellHeight(); + + if (col >= fRendering.getColumnCount()) + return null; + + address = address.add(BigInteger.valueOf(row * fRendering.getColumnCount() * fRendering.getFPDataType().getByteLength())); + address = address.add(BigInteger.valueOf(col * fRendering.getFPDataType().getByteLength())); + + return address; + } + + // Return a Point representing the cell address + + @Override + protected Point getCellLocation(BigInteger cellAddress) + { + try + { + BigInteger address = fRendering.getViewportStartAddress(); + + int cellOffset = cellAddress.subtract(address).intValue(); + cellOffset *= fRendering.getAddressableSize(); + + int row = cellOffset / (fRendering.getColumnCount() * fRendering.getFPDataType().getByteLength()); + cellOffset -= row * fRendering.getColumnCount() * fRendering.getFPDataType().getByteLength(); + int col = cellOffset / fRendering.getFPDataType().getByteLength(); + + int x = col * getCellWidth() + fRendering.getCellPadding(); + int y = row * getCellHeight() + fRendering.getCellPadding(); + + return new Point(x, y); + } + catch (Exception e) + { + fRendering.logError(FPRenderingMessages.getString("FPRendering.FAILURE_DETERMINE_CELL_LOCATION"), e); //$NON-NLS-1$ + return null; + } + } + + @Override + protected void positionCaret(int x, int y) + { + try + { + BigInteger cellAddress = getCellAddressAt(x, y); + + if (cellAddress != null) + { + Point cellPosition = getCellLocation(cellAddress); + int offset = x - cellPosition.x; + int subCellCharacterPosition = offset / getCellCharacterWidth(); + + if (subCellCharacterPosition == this.getCellCharacterCount()) + { + cellAddress = cellAddress.add(BigInteger.valueOf(fRendering.getFPDataType().getByteLength())); + subCellCharacterPosition = 0; + cellPosition = getCellLocation(cellAddress); + } + + fCaret.setLocation(cellPosition.x + subCellCharacterPosition * getCellCharacterWidth(), cellPosition.y); + + this.fCaretAddress = cellAddress; + this.fSubCellCaretPosition = subCellCharacterPosition; + setCaretAddress(fCaretAddress); + } + } + catch (Exception e) + { + fRendering.logError(FPRenderingMessages.getString("FPRendering.FAILURE_POSITION_CURSOR"), e); //$NON-NLS-1$ + } + } + + @Override + protected BigInteger getViewportAddress(int col, int row) throws DebugException + { + BigInteger address = fRendering.getViewportStartAddress(); + address = address.add(BigInteger.valueOf((row * fRendering.getColumnCount() + col) * fRendering.getFPDataType().getByteLength())); + + return address; + } + + @Override + protected void paint(PaintEvent pe) + { + super.paint(pe); + // Allow subclasses to override this method to do their own painting + doPaintData(pe); + } + + // Display text in the cell + + + protected void doPaintData(PaintEvent pe) + { + GC gc = pe.gc; + gc.setFont(fRendering.getFont()); + + int cellHeight = getCellHeight(); + int cellWidth = getCellWidth(); + int boundsHeight = this.getBounds().height; + int columns = fRendering.getColumnCount(); + + int cellX = 0; + int cellY = 0; + + String displayString = FPutilities.fillString(fRendering.getCharsPerColumn(), '.'); + + try + { + BigInteger vpStart = fRendering.getViewportStartAddress(); + BigInteger cellStartAddr = vpStart; + BigInteger memoryAddr = vpStart; + BigInteger cellEndAddr; + + for(int row = 0; row < boundsHeight / cellHeight; row++) + { + for (int column = 0; column < columns; column++) + { + // Set alternating colors for every other column and display the text + // FIXME: There is duplicate code in applyCustomColor() in this class + + if (isOdd(column)) + gc.setForeground(fRendering.getFPRendering().getColorText()); + else + gc.setForeground(fRendering.getFPRendering().getColorTextAlternate()); + + // Calculate the cell starting address and X/Y coordinates + + cellStartAddr = vpStart.add(BigInteger.valueOf((row * fRendering.getColumnCount() + column) * fRendering.getFPDataType().getByteLength())); + cellEndAddr = cellStartAddr.add(BigInteger.valueOf(fRendering.getFPDataType().getByteLength()).subtract(BigInteger.ONE)); + + cellX = (cellWidth * column) + fRendering.getCellPadding(); + cellY = (cellHeight * row ) + fRendering.getCellPadding(); + + // Cell editing: If we're in edit mode, change the cell color and then set the + // edit buffer as the string to display. Otherwise, just use the memory contents. + + if (fRendering.isEditingCell() && cellStartAddr.equals(fRendering.getCellEditAddress())) + { + gc.setForeground(fRendering.getFPRendering().getColorEdit()); + FPMemoryByte[] memoryBytes = fRendering.getBytes(cellStartAddr, fRendering.getFPDataType().getByteLength()); + for (FPMemoryByte memoryByte : memoryBytes) + memoryByte.setEdited(true); + applyCustomColor(gc, memoryBytes, column); + displayString = fRendering.getEditBuffer().toString(); + } + else + displayString = bytesToSciNotation(fRendering.getBytes(memoryAddr, fRendering.getFPDataType().getByteLength())); + + // Cell selection + + if (fRendering.getSelection().isSelected(cellStartAddr)) + { + gc.setBackground(fRendering.getFPRendering().getColorSelection()); + gc.fillRectangle(cellX, row * cellHeight, cellWidth, cellHeight); + gc.setForeground(fRendering.getFPRendering().getColorBackground()); + } + else + { + gc.setBackground(fRendering.getFPRendering().getColorBackground()); + gc.fillRectangle(cellX, row * cellHeight, cellWidth, cellHeight); + // Allow subclasses to override this method to do their own coloring + applyCustomColor(gc, fRendering.getBytes(cellStartAddr, fRendering.getFPDataType().getByteLength()), column); + } + + gc.drawText(displayString, cellX, cellY); + + // Move the caret if appropriate + + if (fCaretEnabled) + { + if(cellStartAddr.compareTo(fCaretAddress) <= 0 && cellEndAddr.compareTo(fCaretAddress) >= 0) + { + int x = cellWidth * column + fRendering.getCellPadding() + fSubCellCaretPosition * this.getCellCharacterWidth(); + int y = cellHeight * row + fRendering.getCellPadding(); + fCaret.setLocation(x, y); + } + } + + // For debugging + + if (fRendering.isDebug()) + gc.drawRectangle(cellX, cellY, cellWidth, cellHeight); + + // Increment the memory address by the length of the data type + + memoryAddr = memoryAddr.add(BigInteger.valueOf(fRendering.getFPDataType().getByteLength())); + } + } + } + catch(Exception e) + { + fRendering.logError(FPRenderingMessages.getString("FPRendering.FAILURE_PAINT"), e); //$NON-NLS-1$ + e.printStackTrace(); + } + } + + // Allow subclasses to override this method to do their own coloring + + protected void applyCustomColor(GC gc, FPMemoryByte bytes[], int col) + { + // Check to see if any byte has been changed and whether we're actually in edit mode + + boolean anyByteEditing = false; + + for (int n = 0; n < bytes.length && !anyByteEditing; n++) + if (bytes[n].isEdited()) anyByteEditing = true; + + anyByteEditing = anyByteEditing && fRendering.isEditingCell(); + + // Even/odd column coloring + + if (isOdd(col)) + gc.setForeground(fRendering.getFPRendering().getColorText()); + else + gc.setForeground(fRendering.getFPRendering().getColorTextAlternate()); + + // Background + + gc.setBackground(fRendering.getFPRendering().getColorBackground()); + + if (anyByteEditing) + { + gc.setForeground(fRendering.getFPRendering().getColorEdit()); + } + else + { + boolean isColored = false; + + for (int index = 0; index < fRendering.getHistoryDepth() && !isColored; index++) + { + // TODO consider adding finer granularity? + + for (int n = 0; n < bytes.length; n++) + { + if (bytes[n].isChanged(index)) + { + if (index == 0) + gc.setForeground(fRendering.getFPRendering().getColorsChanged()[index]); + else + gc.setBackground(fRendering.getFPRendering().getColorsChanged()[index]); + + isColored = true; + break; + } + } + } + } + } + + // Draw a box around the specified cell + + public void highCellBox(BigInteger memoryAddress) + { +// if (fRendering.isDebug()) +// gc.drawRectangle(cellX, cellY, cellWidth, cellHeight); + } + + // Clear the box around the specified cell + + public void clearCellBox(BigInteger memoryAddress) + { + + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPDisplayCharacteristics.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPDisplayCharacteristics.java new file mode 100644 index 00000000000..4fc155ee9a5 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPDisplayCharacteristics.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import org.eclipse.cdt.debug.ui.memory.floatingpoint.FPutilities.Endian; +import org.eclipse.cdt.debug.ui.memory.floatingpoint.FPutilities.FPDataType; +import org.eclipse.cdt.debug.ui.memory.floatingpoint.FPutilities.Justification; + +public class FPDisplayCharacteristics +{ + private FPDataType dataType; + private Endian endian; + private int displayedPrecision; + private Justification justification; + + // Constructors + + FPDisplayCharacteristics() + { + // Default values + + this.dataType = FPDataType.FLOAT; + this.endian = Endian.LITTLE; + this.displayedPrecision = FPDataType.FLOAT.getDisplayedPrecision(); + this.justification = Justification.LEFT; + } + + public FPDisplayCharacteristics(FPDataType dataType, Endian endian, Justification justification) + { + this.dataType = dataType; + this.endian = endian; + this.justification = justification; + } + + // Getters and Setters + + public FPDataType getDataType() + { + return dataType; + } + + public void setDataType(FPDataType dataType) + { + this.dataType = dataType; + } + + public Endian getEndian() + { + return endian; + } + + public void setEndian(Endian endian) + { + this.endian = endian; + } + + public int getDisplayedPrecision() + { + return displayedPrecision; + } + + public void setDisplayedPrecision(int displayedPrecision) + { + this.displayedPrecision = displayedPrecision; + } + + public Justification getJustification() + { + return justification; + } + + public void setJustification(Justification justification) + { + this.justification = justification; + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPIMemoryByte.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPIMemoryByte.java new file mode 100644 index 00000000000..7810d41023f --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPIMemoryByte.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +public interface FPIMemoryByte +{ + public boolean isEdited(); + public void setEdited(boolean edited); +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPIMemorySelection.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPIMemorySelection.java new file mode 100644 index 00000000000..aa3767917ca --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPIMemorySelection.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import java.math.BigInteger; + +public interface FPIMemorySelection +{ + public boolean hasSelection(); + public boolean isSelected(BigInteger address); + public BigInteger getStart(); + public BigInteger getEnd(); + public BigInteger getStartLow(); + public void setStart(BigInteger high, BigInteger low); + public void setEnd(BigInteger high, BigInteger low); + public BigInteger getHigh(); + public BigInteger getLow(); + public void clear(); +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPIViewportCache.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPIViewportCache.java new file mode 100644 index 00000000000..41846f275b7 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPIViewportCache.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import java.math.BigInteger; + +import org.eclipse.debug.core.DebugException; + +public interface FPIViewportCache { + + public void dispose(); + public void refresh(); + public FPMemoryByte[] getBytes(BigInteger address, int bytesRequested) throws DebugException; + public void archiveDeltas(); + public void setEditedValue(BigInteger address, FPMemoryByte[] bytes); + public void clearEditBuffer(); + public void writeEditBuffer(); + public boolean containsEditedCell(BigInteger address); + // private void queueRequest(BigInteger startAddress, BigInteger endAddress); +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPMemoryByte.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPMemoryByte.java new file mode 100644 index 00000000000..9c5a18ede5a --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPMemoryByte.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import org.eclipse.debug.core.model.MemoryByte; + +public class FPMemoryByte extends MemoryByte implements FPIMemoryByte +{ + private boolean isEdited = false; + + private boolean[] changeHistory = new boolean[0]; + + public FPMemoryByte() + { + super(); + } + + public FPMemoryByte(byte byteValue) + { + super(byteValue); + } + + public FPMemoryByte(byte byteValue, byte byteFlags) + { + super(byteValue, byteFlags); + } + + @Override + public boolean isEdited() + { + return isEdited; + } + + @Override + public void setEdited(boolean edited) + { + isEdited = edited; + } + + public boolean isChanged(int historyDepth) + { + return changeHistory.length > historyDepth && changeHistory[historyDepth]; + } + + public void setChanged(int historyDepth, boolean changed) + { + if(historyDepth >= changeHistory.length) + { + boolean newChangeHistory[] = new boolean[historyDepth + 1]; + System.arraycopy(changeHistory, 0, newChangeHistory, 0, changeHistory.length); + changeHistory = newChangeHistory; + } + + changeHistory[historyDepth] = changed; + + if(historyDepth == 0) + this.setChanged(changed); + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPPreferenceConstants.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPPreferenceConstants.java new file mode 100644 index 00000000000..661837597d5 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPPreferenceConstants.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import org.eclipse.cdt.debug.ui.memory.floatingpoint.FPutilities.FPDataType; +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.jface.preference.IPreferenceStore; + + +public class FPPreferenceConstants +{ + private FPPreferenceConstants() + { + // Prevent subclassing or instantiation + } + + /** + * Initialize preference default values. + * + * @param store + */ + public static void initializeDefaults(IPreferenceStore store) + { + // Set default values + + store.setDefault(IFPRConstants.ENDIAN_KEY, -1); // -1 = No default set + store.setDefault(IFPRConstants.DATATYPE_KEY, FPDataType.FLOAT.getValue()); + store.setDefault(IFPRConstants.FLOAT_DISP_KEY, 8); + store.setDefault(IFPRConstants.DOUBLE_DISP_KEY, 8); + store.setDefault(IFPRConstants.COLUMN_COUNT_KEY, Rendering.COLUMNS_AUTO_SIZE_TO_FIT); + store.setDefault(IFPRConstants.UPDATEMODE_KEY, Rendering.UPDATE_ALWAYS); + } + + public static class Initializer extends AbstractPreferenceInitializer + { + @Override + public void initializeDefaultPreferences() + { + IPreferenceStore store = FPRenderingPlugin.getDefault().getPreferenceStore(); + initializeDefaults(store); + } + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRendering.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRendering.java new file mode 100644 index 00000000000..cd4ebafc542 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRendering.java @@ -0,0 +1,1494 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import java.lang.reflect.Method; +import java.math.BigInteger; + +import org.eclipse.cdt.debug.core.model.provisional.IMemoryRenderingViewportProvider; +import org.eclipse.cdt.debug.ui.memory.floatingpoint.FPutilities.Endian; +import org.eclipse.cdt.debug.ui.memory.floatingpoint.FPutilities.FPDataType; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.model.IMemoryBlock; +import org.eclipse.debug.core.model.IMemoryBlockExtension; +import org.eclipse.debug.core.model.MemoryByte; +import org.eclipse.debug.internal.ui.DebugPluginImages; +import org.eclipse.debug.internal.ui.DebugUIMessages; +import org.eclipse.debug.internal.ui.DebugUIPlugin; +import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; +import org.eclipse.debug.internal.ui.memory.IMemoryBlockConnection; +import org.eclipse.debug.internal.ui.memory.provisional.MemoryViewPresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.debug.ui.memory.AbstractMemoryRendering; +import org.eclipse.debug.ui.memory.AbstractTableRendering; +import org.eclipse.debug.ui.memory.IMemoryRendering; +import org.eclipse.debug.ui.memory.IMemoryRenderingContainer; +import org.eclipse.debug.ui.memory.IMemoryRenderingSite; +import org.eclipse.debug.ui.memory.IRepositionableMemoryRendering; +import org.eclipse.debug.ui.memory.IResettableMemoryRendering; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.IInputValidator; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.viewers.IBasicPropertyConstants; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.graphics.Color; +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.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.model.IWorkbenchAdapter; +import org.eclipse.ui.progress.UIJob; + + +/** + * A memory rendering displaying memory in a floating point memory view look and + * feel, optimized for minimal IO traffic. + *

+ * requirements of the debug model implementation: - An IMemoryBlockExtension is + * required. + * + * Since it is not possible to size the memory block to match the size of the + * viewport, memory block change notification is not useful. Such events are + * ignored by this rendering. + */ + +@SuppressWarnings({ "restriction" }) +public class FPRendering extends AbstractMemoryRendering + implements IRepositionableMemoryRendering, IResettableMemoryRendering, IMemoryRenderingViewportProvider, IModelChangedListener +{ + protected Rendering fRendering; + protected Action actionDisplayBigEndian; + protected Action actionDisplayLittleEndian; + protected Action actionDisplayFloatingPoint; + + private IWorkbenchAdapter fWorkbenchAdapter; + private IMemoryBlockConnection fConnection; + + private final static int MAX_MENU_COLUMN_COUNT = 8; + + Action actionFloatingPoint32 = null; + Action actionFloatingPoint64 = null; + + Action actionDisplay4Digits = null; + Action actionDisplay8Digits = null; + Action actionDisplay16Digits = null; + + // Constructor + + public FPRendering(String id) + { + super(id); + + JFaceResources.getFontRegistry().addListener(new IPropertyChangeListener() + { + @Override + public void propertyChange(PropertyChangeEvent event) + { + if (event.getProperty().equals(IInternalDebugUIConstants.FONT_NAME)) + { + FPRendering.this.fRendering.handleFontPreferenceChange(JFaceResources.getFont(IInternalDebugUIConstants.FONT_NAME)); + } + } + }); + + this.addPropertyChangeListener(new IPropertyChangeListener() + { + @Override + public void propertyChange(PropertyChangeEvent event) + { + IMemoryRendering sourceRendering = (IMemoryRendering) event.getSource(); + if (!sourceRendering.getMemoryBlock().equals(getMemoryBlock())) + return; + + Object address = event.getNewValue(); + + if (event.getProperty().equals(AbstractTableRendering.PROPERTY_SELECTED_ADDRESS) && address instanceof BigInteger) + { + FPRendering.this.fRendering.ensureVisible((BigInteger) address); + } + } + }); + + FPRenderingPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(new IPropertyChangeListener() + { + @Override + public void propertyChange(PropertyChangeEvent event) + { + disposeColors(); + allocateColors(); + applyPreferences(); + } + }); + + DebugUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(new IPropertyChangeListener() + { + @Override + public void propertyChange(PropertyChangeEvent event) + { + if (event.getProperty().equals(IDebugUIConstants.PREF_PADDED_STR)) + { + if (FPRendering.this.fRendering != null) + { + setRenderingPadding((String) event.getNewValue()); + FPRendering.this.fRendering.redrawPanes(); + } + } + } + }); + } + + static int paddingCounter = 0; + + void setRenderingPadding(String padding) + { + if (padding == null || padding.length() == 0) padding = " "; //$NON-NLS-1$ + FPRendering.this.fRendering.setPaddingString(padding); + } + + protected void logError(String message, Exception e) + { + Status status = new Status(IStatus.ERROR, getRenderingId(), DebugException.INTERNAL_ERROR, message, e); + FPRenderingPlugin.getDefault().getLog().log(status); + } + + BigInteger fBigBaseAddress; // Memory base address + private BigInteger fStartAddress; // Starting address + private BigInteger fEndAddress; // Ending address + private int fAddressableSize; // Memory block size + private int fAddressSize; // Size of address + + /* + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener#modelChanged(org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta, org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy) + */ + @Override + public void modelChanged(IModelDelta delta, IModelProxy proxy) + { + /* + * The event model in the traditional renderer is written to expect a suspend first + * which will cause it to save its current data set away in an archive. Then when + * the state change comes through it will compare and refresh showing a difference. + */ + int flags = delta.getFlags(); + if ( ( flags & IModelDelta.STATE ) != 0 ) { + fRendering.handleSuspend(false); + } + + fRendering.handleChange(); + } + + /* + * We use the model proxy which is supplied by the TCF implementation to provide the knowledge of memory + * change notifications. The older backends ( the reference model, Wind River Systems Inc. ) are written + * to generate the Debug Model events. TCF follows the "ModelDelta/IModelProxy" implementation that the + * platform renderers use. So this implementation acts as a shim. If the older Debug Events come in then + * fine. If the newer model deltas come in fine also. + */ + IModelProxy fModel; + + @Override + public void dispose() + { + /* + * We use the UI dispatch thread to protect the proxy information. Even though I believe the + * dispose routine is always called in the UI dispatch thread. I am going to make sure. + */ + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + if ( fModel != null ) { + fModel.removeModelChangedListener(FPRendering.this); + fModel.dispose(); + } + }}); + + if(this.fRendering != null) + this.fRendering.dispose(); + disposeColors(); + super.dispose(); + } + + @Override + public void init(final IMemoryRenderingContainer container, final IMemoryBlock block) + { + super.init(container, block); + + /* + * Working with the model proxy must be done on the UI dispatch thread. + */ + final IModelProxyFactory factory = (IModelProxyFactory) DebugPlugin.getAdapter(block, IModelProxyFactory.class ); + if ( factory != null ) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + + /* + * The asynchronous model assumes we have an asynchronous viewer that has an IPresentationContext + * to represent it. The Platform memory subsystem provides a way to create one without a viewewr. + */ + IMemoryRenderingSite site = container.getMemoryRenderingSite(); + MemoryViewPresentationContext context = new MemoryViewPresentationContext(site, container, FPRendering.this); + + /* + * Get a new proxy and perform the initialization sequence so we are known the + * the model provider. + */ + fModel = factory.createModelProxy(block, context); + fModel.installed(null); + fModel.addModelChangedListener(FPRendering.this); + + }}); + } + + try + { + fBigBaseAddress = ((IMemoryBlockExtension) block).getBigBaseAddress(); + } + catch (DebugException de) + { + logError(FPRenderingMessages.getString("FPRendering.FAILURE_RETRIEVE_BASE_ADDRESS"), de); //$NON-NLS-1$ + } + + try + { + fAddressableSize = ((IMemoryBlockExtension) block).getAddressableSize(); + } + catch (DebugException de) + { + fAddressableSize = 1; + } + + try + { + fStartAddress = ((IMemoryBlockExtension) block).getMemoryBlockStartAddress(); + } + catch (DebugException de) + { + fStartAddress = null; + logError(FPRenderingMessages.getString("FPRendering.FAILURE_RETRIEVE_START_ADDRESS"), de); //$NON-NLS-1$ + } + + try + { + fAddressSize = ((IMemoryBlockExtension) block).getAddressSize(); + } + catch (DebugException e) + { + fAddressSize = 0; + } + + BigInteger endAddress; + try + { + endAddress = ((IMemoryBlockExtension) block).getMemoryBlockEndAddress(); + if (endAddress != null) + fEndAddress = endAddress; + } + catch (DebugException e) + { + fEndAddress = null; + } + + if (fEndAddress == null) + { + int addressSize; + try + { + addressSize = ((IMemoryBlockExtension) block).getAddressSize(); + } + catch (DebugException e) + { + addressSize = 4; + } + + endAddress = BigInteger.valueOf(2); + endAddress = endAddress.pow(addressSize * 8); + endAddress = endAddress.subtract(BigInteger.ONE); + fEndAddress = endAddress; + } + + // default to MAX_VALUE if we have trouble getting the end address + if (fEndAddress == null) + fEndAddress = BigInteger.valueOf(Integer.MAX_VALUE); + } + + public BigInteger getBigBaseAddress() + { + return fBigBaseAddress; + } + + public BigInteger getMemoryBlockStartAddress() + { + return fStartAddress; + } + + public BigInteger getMemoryBlockEndAddress() + { + return fEndAddress; + } + + public int getAddressableSize() + { + return fAddressableSize; + } + + public int getAddressSize() + { + return fAddressSize; + } + + @Override + public Control createControl(Composite parent) + { + allocateColors(); + + this.fRendering = new Rendering(parent, this); + + applyPreferences(); + + createMenus(); + + if (actionFloatingPoint32.isChecked()) + actionDisplay16Digits.setEnabled(false); + else + actionDisplay16Digits.setEnabled(true); + + return this.fRendering; + } + + /* + * We are duplicating the reference to the GoToAddress command because it is private in the platform. + * This is not going to change at this point so just live with it. + */ + private static final String ID_GO_TO_ADDRESS_COMMAND = "org.eclipse.debug.ui.command.gotoaddress"; //$NON-NLS-1$ + private AbstractHandler fGoToAddressHandler; + + @Override + public void activated() + { + super.activated(); + + IWorkbench workbench = PlatformUI.getWorkbench(); + ICommandService commandSupport = (ICommandService) workbench.getAdapter(ICommandService.class); + + if (commandSupport != null) + { + Command gotoCommand = commandSupport.getCommand(ID_GO_TO_ADDRESS_COMMAND); + + if (fGoToAddressHandler == null) + { + fGoToAddressHandler = new AbstractHandler() + { + @Override + public Object execute(ExecutionEvent event) throws ExecutionException + { + return null; + } + }; + } + gotoCommand.setHandler(fGoToAddressHandler); + } + } + + @Override + public void deactivated() + { + IWorkbench workbench = PlatformUI.getWorkbench(); + ICommandService commandSupport = (ICommandService) workbench.getAdapter(ICommandService.class); + + if (commandSupport != null) + { + // remove handler + Command command = commandSupport.getCommand(ID_GO_TO_ADDRESS_COMMAND); + command.setHandler(null); + } + + super.deactivated(); + } + + public void setSelection(BigInteger start, BigInteger end) + { + fRendering.getSelection().setStart(start, start); + fRendering.getSelection().setEnd(end, end); + } + + public void gotoAddress(final BigInteger address) + { + this.fRendering.gotoAddress(address); + } + + public void updateRenderingLabels() + { + UIJob job = new UIJob("updateLabels") { //$NON-NLS-1$ + @SuppressWarnings("synthetic-access") + @Override + public IStatus runInUIThread(IProgressMonitor monitor) + { + + // Update tab labels + String fLabel = getLabel(); + firePropertyChangedEvent(new PropertyChangeEvent(FPRendering.this, IBasicPropertyConstants.P_TEXT, null, fLabel)); + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.schedule(); + } + + private Color colorBackground; + private Color colorChanged; + private Color colorsChanged[] = null; + private Color colorEdit; + private Color colorSelection; + private Color colorText; + private Color colorTextAlternate; + + public void allocateColors() + { + IPreferenceStore store = FPRenderingPlugin.getDefault().getPreferenceStore(); + + colorBackground = new Color(Display.getDefault(), PreferenceConverter.getColor(store, FPRenderingPreferenceConstants.MEM_COLOR_BACKGROUND)); + colorChanged = new Color(Display.getDefault(), PreferenceConverter.getColor(store, FPRenderingPreferenceConstants.MEM_COLOR_CHANGED)); + colorEdit = new Color(Display.getDefault(), PreferenceConverter.getColor(store, FPRenderingPreferenceConstants.MEM_COLOR_EDIT)); + colorSelection = new Color(Display.getDefault(), PreferenceConverter.getColor(store, FPRenderingPreferenceConstants.MEM_COLOR_SELECTION)); + colorText = new Color(Display.getDefault(), PreferenceConverter.getColor(store, FPRenderingPreferenceConstants.MEM_COLOR_TEXT)); + + // alternate cell color + Color textColor = getColorText(); + int red = textColor.getRed(); + int green = textColor.getGreen(); + int blue = textColor.getBlue(); + + float scale = store.getInt(FPRenderingPreferenceConstants.MEM_LIGHTEN_DARKEN_ALTERNATE_CELLS); + + red = (int) Math.min(red + ((255 - red) / 10) * scale, 255); + green = (int) Math.min(green + ((255 - green) / 10) * scale, 255); + blue = (int) Math.min(blue + ((255 - blue) / 10) * scale, 255); + + colorTextAlternate = new Color(Display.getDefault(), new RGB(red, green, blue)); + } + + public void disposeColors() + { + if (colorBackground != null) colorBackground.dispose(); + colorBackground = null; + + if (colorChanged != null) colorChanged.dispose(); + colorChanged = null; + + if (colorEdit != null) colorEdit.dispose(); + colorEdit = null; + + if (colorSelection != null) colorSelection.dispose(); + colorSelection = null; + + if (colorText != null) colorText.dispose(); + colorText = null; + + if (colorTextAlternate != null) colorTextAlternate.dispose(); + colorTextAlternate = null; + + disposeChangedColors(); + } + + public void applyPreferences() + { + if (fRendering != null && !fRendering.isDisposed()) + { + IPreferenceStore store = FPRenderingPlugin.getDefault().getPreferenceStore(); + fRendering.setHistoryDepth(store.getInt(FPRenderingPreferenceConstants.MEM_HISTORY_TRAILS_COUNT)); + fRendering.setBackground(getColorBackground()); + + FPAbstractPane panes[] = fRendering.getRenderingPanes(); + for (int index = 0; index < panes.length; index++) + panes[index].setBackground(getColorBackground()); + + setRenderingPadding(FPRenderingPlugin.getDefault().getPreferenceStore().getString(IDebugUIConstants.PREF_PADDED_STR)); + + fRendering.redrawPanes(); + } + } + + public Color getColorBackground() + { + IPreferenceStore store = FPRenderingPlugin.getDefault().getPreferenceStore(); + + if (store.getBoolean(FPRenderingPreferenceConstants.MEM_USE_GLOBAL_BACKGROUND)) + return Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND); + + return colorBackground; + } + + public Color getColorChanged() + { + return colorChanged; + } + + private void disposeChangedColors() + { + if (colorsChanged != null) + for (int index = 0; index < colorsChanged.length; index++) + colorsChanged[index].dispose(); + colorsChanged = null; + } + + public Color[] getColorsChanged() + { + if (colorsChanged != null && colorsChanged.length != fRendering.getHistoryDepth()) + { + disposeChangedColors(); + } + + if (colorsChanged == null) + { + colorsChanged = new Color[fRendering.getHistoryDepth()]; + colorsChanged[0] = colorChanged; + int shades = fRendering.getHistoryDepth() + 4; + int red = (255 - colorChanged.getRed()) / shades; + int green = (255 - colorChanged.getGreen()) / shades; + int blue = (255 - colorChanged.getBlue()) / shades; + for (int index = 1; index < fRendering.getHistoryDepth(); index++) + { + colorsChanged[index] = new Color(colorChanged.getDevice(), colorChanged.getRed() + ((shades - index) * red), colorChanged.getGreen() + + ((shades - index) * green), colorChanged.getBlue() + ((shades - index) * blue)); + } + } + + return colorsChanged; + } + + public Color getColorEdit() + { + return colorEdit; + } + + public Color getColorSelection() + { + IPreferenceStore store = FPRenderingPlugin.getDefault().getPreferenceStore(); + + if (store.getBoolean(FPRenderingPreferenceConstants.MEM_USE_GLOBAL_SELECTION)) + return Display.getDefault().getSystemColor(SWT.COLOR_LIST_SELECTION); + + return colorSelection; + } + + public Color getColorText() + { + IPreferenceStore store = FPRenderingPlugin.getDefault().getPreferenceStore(); + + if (store.getBoolean(FPRenderingPreferenceConstants.MEM_USE_GLOBAL_TEXT)) + return Display.getDefault().getSystemColor(SWT.COLOR_LIST_FOREGROUND); + + return colorText; + } + + public Color getColorTextAlternate() + { + return colorTextAlternate; + } + + // Menu creation + + public void createMenus() + { + // Add the menu to each of the rendering panes + + Control[] renderingControls = this.fRendering.getRenderingPanes(); + + for (int index = 0; index < renderingControls.length; index++) + super.createPopupMenu(renderingControls[index]); + + super.createPopupMenu(this.fRendering); + + // Copy + + final Action copyAction = new CopyAction(this.fRendering); + + // Copy address + + final Action copyAddressAction = new Action(FPRenderingMessages.getString("FPRendering.COPY_ADDRESS")) //$NON-NLS-1$ + { + @Override + public void run() + { + Display.getDefault().asyncExec(new Runnable() + { + @Override + public void run() + { + FPRendering.this.fRendering.copyAddressToClipboard(); + } + }); + } + }; + + // Reset to base address + + final Action gotoBaseAddressAction = new Action(FPRenderingMessages.getString("FPRendering.RESET_TO_BASE_ADDRESS")) //$NON-NLS-1$ + { + @Override + public void run() + { + Display.getDefault().asyncExec(new Runnable() + { + @Override + public void run() + { + FPRendering.this.fRendering.gotoAddress(FPRendering.this.fRendering.fBaseAddress); + } + }); + } + }; + + // Refresh + + final Action refreshAction = new Action(FPRenderingMessages.getString("FPRendering.REFRESH")) //$NON-NLS-1$ + { + @Override + public void run() + { + Display.getDefault().asyncExec(new Runnable() + { + @Override + public void run() + { + // For compatibility with DSF update modes (hopefully this will either be replaced + // by an enhanced platform interface or the caching will move out of the data layer) + + try + { + Method m = fRendering.getMemoryBlock().getClass().getMethod("clearCache", new Class[0]); //$NON-NLS-1$ + if (m != null) + m.invoke(fRendering.getMemoryBlock(), new Object[0]); + } + catch (Exception e) + { + } + + FPRendering.this.fRendering.refresh(); + } + }); + } + }; + + // Little Endian + + actionDisplayLittleEndian = new Action(FPRenderingMessages.getString("FPRendering.ENDIAN_LITTLE"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + fRendering.setDisplayLittleEndian(true); + setRMCvalue(IFPRConstants.ENDIAN_KEY, Endian.LITTLE.getValue()); + } + }; + + // Big Endian + + actionDisplayBigEndian = new Action(FPRenderingMessages.getString("FPRendering.ENDIAN_BIG"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + fRendering.setDisplayLittleEndian(false); + setRMCvalue(IFPRConstants.ENDIAN_KEY, Endian.BIG.getValue()); + } + }; + + // Endian settings + + int endian = getRMCvalue(IFPRConstants.ENDIAN_KEY); + + endian = endian != -1 ? endian : (fRendering.isDisplayLittleEndian() ? Endian.LITTLE.getValue() : Endian.BIG.getValue()); + boolean le = (endian == Endian.LITTLE.getValue()); + + fRendering.setDisplayLittleEndian(le); + actionDisplayLittleEndian.setChecked(le); + actionDisplayBigEndian.setChecked(!le); + + // Float + + boolean dtFloat = getRMCvalue(IFPRConstants.DATATYPE_KEY) == FPDataType.FLOAT.getValue(); + this.fRendering.setFPDataType(dtFloat ? FPDataType.FLOAT : FPDataType.DOUBLE); + + actionFloatingPoint32 = new Action(FPRenderingMessages.getString("FPRendering.FLOATING_POINT_32"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + fRendering.setDisplayedPrecision(getRMCvalue(IFPRConstants.FLOAT_DISP_KEY)); + fRendering.setFPDataType(FPDataType.FLOAT); + setRMCvalue(IFPRConstants.DATATYPE_KEY, FPDataType.FLOAT.getValue()); + setSelections(); + } + }; + + // Double + + actionFloatingPoint64 = new Action(FPRenderingMessages.getString("FPRendering.FLOATING_POINT_64"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + fRendering.setDisplayedPrecision(getRMCvalue(IFPRConstants.DOUBLE_DISP_KEY)); + fRendering.setFPDataType(FPDataType.DOUBLE); + setRMCvalue(IFPRConstants.DATATYPE_KEY, FPDataType.DOUBLE.getValue()); + setSelections(); + } + }; + + // Displayed precision: 4 digits + + int savedPrecision = getDisplayedPrecision(); + + actionDisplay4Digits = new Action(FPRenderingMessages.getString("FPRendering.DISPLAYED_PRECISION_4"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + FPRendering.this.fRendering.setDisplayedPrecision(4); + setDisplayedPrecision(4); + } + }; + + if (savedPrecision == 4) + { + FPRendering.this.fRendering.setDisplayedPrecision(4); + actionDisplay4Digits.setChecked(savedPrecision == 4); + } + + // Displayed precision: 8 digits + + actionDisplay8Digits = new Action(FPRenderingMessages.getString("FPRendering.DISPLAYED_PRECISION_8"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + FPRendering.this.fRendering.setDisplayedPrecision(8); + setDisplayedPrecision(8); + } + }; + + if (savedPrecision == 8) + { + FPRendering.this.fRendering.setDisplayedPrecision(8); + actionDisplay8Digits.setChecked(savedPrecision == 8); + } + + // Displayed precision: 16 digits (doubles only) + + actionDisplay16Digits = new Action(FPRenderingMessages.getString("FPRendering.DISPLAYED_PRECISION_16"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + FPRendering.this.fRendering.setDisplayedPrecision(16); + setDisplayedPrecision(16); + } + }; + + if (savedPrecision == 16) + { + FPRendering.this.fRendering.setDisplayedPrecision(16); + actionDisplay16Digits.setChecked(savedPrecision == 16); + } + + // Set RMC selections based on datatype and displayed precision settings in effect + + setSelections(); + + // Columns + + int savedColumnCount = getRMCvalue(IFPRConstants.COLUMN_COUNT_KEY); + + final Action displayColumnCountAuto = new Action(FPRenderingMessages.getString("FPRendering.COLUMN_COUNT_AUTO"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + FPRendering.this.fRendering.setColumnsSetting(Rendering.COLUMNS_AUTO_SIZE_TO_FIT); + setRMCvalue(IFPRConstants.COLUMN_COUNT_KEY, Rendering.COLUMNS_AUTO_SIZE_TO_FIT); + } + }; + + boolean autoMode = savedColumnCount == Rendering.COLUMNS_AUTO_SIZE_TO_FIT; + displayColumnCountAuto.setChecked(autoMode); + + final Action[] displayColumnCounts = new Action[MAX_MENU_COLUMN_COUNT]; + + for (int index = 0, j = 1; index < MAX_MENU_COLUMN_COUNT; index++, j *= 2) + { + final int finali = j; + displayColumnCounts[index] = new Action(FPRenderingMessages.getString("FPRendering.COLUMN_COUNT_" + finali), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + FPRendering.this.fRendering.setColumnsSetting(finali); + setRMCvalue(IFPRConstants.COLUMN_COUNT_KEY, finali); + } + }; + displayColumnCounts[index].setChecked(fRendering.getColumnsSetting() == finali); + } + + // Set/clear column count selections as appropriate + + int countValue = getRMCvalue(IFPRConstants.COLUMN_COUNT_KEY); + + for (int index = 0; index < MAX_MENU_COLUMN_COUNT; index++) + displayColumnCounts[index].setChecked(countValue != Rendering.COLUMNS_AUTO_SIZE_TO_FIT && (countValue == (1 << index))); + + fRendering.setColumnsSetting(getRMCvalue(IFPRConstants.COLUMN_COUNT_KEY)); + + final Action displayColumnCountCustomValue = new Action("", IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + } + }; + + final Action displayColumnCountCustom = new Action(FPRenderingMessages.getString("FPRendering.COLUMN_COUNT_CUSTOM"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + InputDialog inputDialog = new InputDialog + ( + fRendering.getShell(), "Set Column Count", "Please enter column count", "", new IInputValidator() //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + { + @Override + public String isValid(String input) + { + try + { + int index = Integer.parseInt(input); + + if (index <= 0) + return "Please enter a positive integer"; //$NON-NLS-1$ + + if (index > 200) + return "Please enter a positive integer not greater than 200"; //$NON-NLS-1$ + } + catch (NumberFormatException x) + { + return "Please enter a positive integer"; //$NON-NLS-1$ + } + + return null; + } + } + ); + + if (inputDialog.open() != Window.OK) + { + this.setChecked(false); + int currentColumnSetting = FPRendering.this.fRendering.getColumnsSetting(); + + if (currentColumnSetting == Rendering.COLUMNS_AUTO_SIZE_TO_FIT) + displayColumnCountAuto.setChecked(true); + else + { + boolean currentCountIsCustom = true; + + for (int index = 0, j = 1; index < MAX_MENU_COLUMN_COUNT && currentCountIsCustom; index++, j *= 2) + { + currentCountIsCustom = (j != fRendering.getColumnsSetting()); + if (j == fRendering.getColumnsSetting()) + displayColumnCounts[index].setChecked(true); + } + + if (currentCountIsCustom) + displayColumnCountCustomValue.setChecked(true); + } + + return; + } + + int newColumnCount = -1; + + try + { + newColumnCount = Integer.parseInt(inputDialog.getValue()); + } + catch (NumberFormatException x) + { + assert false; + } + + boolean customIsOneOfStandardListChoices = false; + + for (int index = 0, j = 1; index < MAX_MENU_COLUMN_COUNT; index++, j *= 2) + { + if (newColumnCount == j) + { + customIsOneOfStandardListChoices = true; + FPRendering.this.fRendering.setColumnsSetting(newColumnCount); + setRMCvalue(IFPRConstants.COLUMN_COUNT_KEY, newColumnCount); + this.setChecked(false); + displayColumnCountCustomValue.setChecked(false); + displayColumnCounts[index].setChecked(true); + break; + } + } + + if (!customIsOneOfStandardListChoices) + { + FPRendering.this.fRendering.setColumnsSetting(newColumnCount); + setRMCvalue(IFPRConstants.COLUMN_COUNT_KEY, newColumnCount); + this.setChecked(false); + + displayColumnCountCustomValue.setChecked(true); + displayColumnCountCustomValue.setText(Integer.valueOf(fRendering.getColumnsSetting()).toString()); + } + } + }; + + // Check for a custom value: If we're not in "Auto Fill" mode, check for standard column sizes. + // If none of the standard sizes were entered, then it's a custom value; set it and display it. + + boolean customColumnCountSet = true; + countValue = getRMCvalue(IFPRConstants.COLUMN_COUNT_KEY); + + if (countValue != Rendering.COLUMNS_AUTO_SIZE_TO_FIT) + { + for (int index = 0; index < MAX_MENU_COLUMN_COUNT; index++) + { + // If the column count is one of the standard values, set flag to false and exit the loop + + if (countValue == (1 << index)) + { + customColumnCountSet = false; + break; + } + } + + if (customColumnCountSet) + { + FPRendering.this.fRendering.setColumnsSetting(countValue); + displayColumnCountCustomValue.setChecked(true); + displayColumnCountCustomValue.setText(Integer.valueOf(fRendering.getColumnsSetting()).toString()); + } + } + + // Add the right-mouse-click (RMC) context menu items + + getPopupMenuManager().addMenuListener(new IMenuListener() + { + @Override + public void menuAboutToShow(IMenuManager manager) + { + manager.add(new Separator()); + + MenuManager sub = new MenuManager(FPRenderingMessages.getString("FPRendering.PANES")); //$NON-NLS-1$ + + sub = new MenuManager(FPRenderingMessages.getString("FPRendering.ENDIAN")); //$NON-NLS-1$ + sub.add(actionDisplayBigEndian); + sub.add(actionDisplayLittleEndian); + manager.add(sub); + + sub = new MenuManager(FPRenderingMessages.getString("FPRendering.NUMBER_TYPE")); //$NON-NLS-1$ + sub.add(actionFloatingPoint32); + sub.add(actionFloatingPoint64); + manager.add(sub); + + sub = new MenuManager(FPRenderingMessages.getString("FPRendering.PRECISION")); //$NON-NLS-1$ + sub.add(actionDisplay4Digits); + sub.add(actionDisplay8Digits); + sub.add(actionDisplay16Digits); + manager.add(sub); + +// TODO: Add separator for FP group here: manager.add(new Separator()); + + sub = new MenuManager(FPRenderingMessages.getString("FPRendering.COLUMN_COUNT")); //$NON-NLS-1$ + sub.add(displayColumnCountAuto); + + for (int index = 0; index < displayColumnCounts.length; index++) + sub.add(displayColumnCounts[index]); + + boolean currentCountIsCustom = fRendering.getColumnsSetting() != 0; + + for (int index = 0, j = 1; index < MAX_MENU_COLUMN_COUNT && currentCountIsCustom; index++, j *= 2) + currentCountIsCustom = (j != fRendering.getColumnsSetting()); + + if (currentCountIsCustom) + sub.add(displayColumnCountCustomValue); + + sub.add(displayColumnCountCustom); + manager.add(sub); + + // Update modes + + int updateMode = getRMCvalue(IFPRConstants.UPDATEMODE_KEY); + + final Action updateAlwaysAction = new Action(FPRenderingMessages.getString("FPRendering.UPDATE_ALWAYS"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + fRendering.setUpdateMode(Rendering.UPDATE_ALWAYS); + setRMCvalue(IFPRConstants.UPDATEMODE_KEY, Rendering.UPDATE_ALWAYS); + } + }; + updateAlwaysAction.setChecked(updateMode == Rendering.UPDATE_ALWAYS); + + final Action updateOnBreakpointAction = new Action(FPRenderingMessages.getString("FPRendering.UPDATE_ON_BREAKPOINT"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + fRendering.setUpdateMode(Rendering.UPDATE_ON_BREAKPOINT); + setRMCvalue(IFPRConstants.UPDATEMODE_KEY, Rendering.UPDATE_ON_BREAKPOINT); + } + }; + updateOnBreakpointAction.setChecked(updateMode == Rendering.UPDATE_ON_BREAKPOINT); + + final Action updateManualAction = new Action(FPRenderingMessages.getString("FPRendering.UPDATE_MANUAL"), IAction.AS_RADIO_BUTTON) //$NON-NLS-1$ + { + @Override + public void run() + { + fRendering.setUpdateMode(Rendering.UPDATE_MANUAL); + setRMCvalue(IFPRConstants.UPDATEMODE_KEY, Rendering.UPDATE_MANUAL); + } + }; + updateManualAction.setChecked(updateMode == Rendering.UPDATE_MANUAL); + + // Add menu + + sub = new MenuManager(FPRenderingMessages.getString("FPRendering.UPDATEMODE")); //$NON-NLS-1$ + sub.add(updateAlwaysAction); + sub.add(updateOnBreakpointAction); + sub.add(updateManualAction); + manager.add(sub); + manager.add(new Separator()); + + BigInteger start = fRendering.getSelection().getStart(); + BigInteger end = fRendering.getSelection().getEnd(); + copyAction.setEnabled(start != null && end != null); + + manager.add(copyAction); + manager.add(copyAddressAction); + + manager.add(gotoBaseAddressAction); + manager.add(refreshAction); + manager.add(new Separator()); + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + } + }); + } + + // Set/clear selections as appropriate + + public void setSelections() + { + if (actionDisplay4Digits == null || actionDisplay8Digits == null || actionDisplay16Digits == null) return; + + // Enable/disable and set/clear menu RMC elements based on currently selected datatype + + boolean dtFloat = FPRendering.this.fRendering.getFPDataType() == FPDataType.FLOAT; + + actionDisplay16Digits.setEnabled(!dtFloat); + actionFloatingPoint32.setChecked(dtFloat); + actionFloatingPoint64.setChecked(!dtFloat); + + // Set/clear RMC elements based on displayed precision + + int displayedPrecision = getRMCvalue(dtFloat ? IFPRConstants.FLOAT_DISP_KEY : IFPRConstants.DOUBLE_DISP_KEY); + + actionDisplay4Digits.setChecked (displayedPrecision == 4); + actionDisplay8Digits.setChecked (displayedPrecision == 8); + actionDisplay16Digits.setChecked(displayedPrecision == 16); + } + + + @Override + public Control getControl() + { + return this.fRendering; + } + + // Selection is terminology for caret position + + @Override + public BigInteger getSelectedAddress() + { + FPIMemorySelection selection = fRendering.getSelection(); + if (selection == null || selection.getStart() == null) + return fRendering.getCaretAddress(); + + return selection.getStartLow(); + } + + @Override + public MemoryByte[] getSelectedAsBytes() + { + try + { + // default to the caret address and the cell count size + BigInteger startAddr = fRendering.getCaretAddress(); + int byteCount = fRendering.getCharsPerColumn(); + + // Now see if there's a selection + FPIMemorySelection selection = fRendering.getSelection(); + if (selection != null && selection.getStart() != null) + { + // The implementation is such that just having a caret somewhere (without multiple cells + // being selected) constitutes a selection, except for when the rendering is in its initial + // state, i.e. just because we get here doesn't mean the user has selected more than one cell. + + startAddr = getSelectedAddress(); + + if (selection.getHigh() != null) + byteCount = selection.getHigh().subtract(selection.getLow()).intValue() * fRendering.getAddressableSize(); + } + + return fRendering.getViewportCache().getBytes(startAddr, byteCount); + + } + catch (DebugException de) + { + return new MemoryByte[0]; + } + } + + @Override + public void goToAddress(final BigInteger address) throws DebugException + { + Display.getDefault().asyncExec(new Runnable() + { + @Override + public void run() + { + fRendering.gotoAddress(address); + } + }); + } + + protected void setTargetMemoryLittleEndian(boolean littleEndian) + { + // Once we actually read memory we can determine the endianess and need to set these actions accordingly. + actionDisplayBigEndian.setChecked(!littleEndian); + actionDisplayLittleEndian.setChecked(littleEndian); + + // When target endian changes, force display endian to track. User can then change display endian if desired. + fRendering.setDisplayLittleEndian(littleEndian); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) + */ + @Override + public Object getAdapter(Class adapter) + { + if (adapter == IWorkbenchAdapter.class) + { + if (this.fWorkbenchAdapter == null) + { + this.fWorkbenchAdapter = new IWorkbenchAdapter() + { + @Override + public Object[] getChildren(Object o) + { + return new Object[0]; + } + + @Override + public ImageDescriptor getImageDescriptor(Object object) + { + return null; + } + + @Override + public String getLabel(Object o) + { + return FPRenderingMessages.getString("FPRendering.RENDERING_NAME"); //$NON-NLS-1$ + } + + @Override + public Object getParent(Object o) + { + return null; + } + }; + } + return this.fWorkbenchAdapter; + } + + if (adapter == IMemoryBlockConnection.class) + { + if (fConnection == null) + { + fConnection = new IMemoryBlockConnection() + { + @Override + public void update() + { + // update UI asynchronously + Display display = FPRenderingPlugin.getDefault().getWorkbench().getDisplay(); + display.asyncExec(new Runnable() + { + @Override + public void run() + { + try + { + if (fBigBaseAddress != FPRendering.this.fRendering.getMemoryBlock().getBigBaseAddress()) + { + fBigBaseAddress = FPRendering.this.fRendering.getMemoryBlock().getBigBaseAddress(); + FPRendering.this.fRendering.gotoAddress(fBigBaseAddress); + } + FPRendering.this.fRendering.refresh(); + } + catch (DebugException e) + { + } + } + }); + } + }; + } + + return fConnection; + } + + return super.getAdapter(adapter); + } + + @Override + public void resetRendering() throws DebugException + { + fRendering.gotoAddress(fRendering.fBaseAddress); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.debug.internal.core.model.provisional. + * IMemoryRenderingViewportProvider#getViewportAddress() + */ + @Override + public BigInteger getViewportAddress() + { + return fRendering.getViewportStartAddress(); + } + + // Persistence methods + + void setDisplayedPrecision(int precision) + { + // Save the appropriate displayed precision value, based on data type, in the store + + if (FPRendering.this.fRendering.getFPDataType() == FPDataType.FLOAT) + setRMCvalue(IFPRConstants.FLOAT_DISP_KEY, precision); + else + setRMCvalue(IFPRConstants.DOUBLE_DISP_KEY, precision); + } + + private int getDisplayedPrecision() + { + // Retrieve the persisted data value from the store + + IPreferenceStore store = FPRenderingPlugin.getDefault().getPreferenceStore(); + + FPDataType dataType = FPRendering.this.fRendering.getFPDataType(); + + if (store != null) + return store.getInt(dataType == FPDataType.FLOAT ? IFPRConstants.FLOAT_DISP_KEY : IFPRConstants.DOUBLE_DISP_KEY); + + // If there's nothing persisted, return the default precision for data type + + return dataType == FPDataType.FLOAT ? FPDataType.FLOAT.getDisplayedPrecision() : FPDataType.DOUBLE.getDisplayedPrecision(); + } + + void setRMCvalue(String key, int value) + { + // Save the specified key and int value + + IPreferenceStore store = FPRenderingPlugin.getDefault().getPreferenceStore(); + if (store != null) store.setValue(key, value); + } + + int getRMCvalue(String key) + { + // Return the value for the specified key + + IPreferenceStore store = FPRenderingPlugin.getDefault().getPreferenceStore(); + return (store != null) ? store.getInt(key) : 0; + } +} + +// Copy class + +class CopyAction extends Action +{ + // TODO for the sake of large copies, this action should probably read in + // blocks on a Job. + + private Rendering fRendering; + private int fType = DND.CLIPBOARD; + + public CopyAction(Rendering rendering) + { + this(rendering, DND.CLIPBOARD); + } + + @SuppressWarnings("restriction") // using platform's labels and images; acceptable build risk + public CopyAction(Rendering rendering, int clipboardType) + { + super(); + fType = clipboardType; + fRendering = rendering; + setText(DebugUIMessages.CopyViewToClipboardAction_title); + setToolTipText(DebugUIMessages.CopyViewToClipboardAction_tooltip); + setImageDescriptor(DebugPluginImages + .getImageDescriptor(IInternalDebugUIConstants.IMG_ELCL_COPY_VIEW_TO_CLIPBOARD)); + setHoverImageDescriptor(DebugPluginImages + .getImageDescriptor(IInternalDebugUIConstants.IMG_LCL_COPY_VIEW_TO_CLIPBOARD)); + setDisabledImageDescriptor(DebugPluginImages + .getImageDescriptor(IInternalDebugUIConstants.IMG_DLCL_COPY_VIEW_TO_CLIPBOARD)); + } + + @Override + public void run() + { + Clipboard clip = null; + final String PANE_SPACING = " "; //$NON-NLS-1$ + + try + { + clip = new Clipboard(fRendering.getDisplay()); + + BigInteger start = fRendering.getSelection().getStart(); + BigInteger end = fRendering.getSelection().getEnd(); + + if (end == null) return; // End will be null when there is nothing selected + + if (start.compareTo(end) > 0) + { + // Swap start and end + + BigInteger bigI = end; + end = start; + start = bigI; + } + + final FPDataType numberType = fRendering.getFPDataType(); + final int bytesPerColumn = numberType.getByteLength(); + final boolean isLittleEndian = fRendering.isTargetLittleEndian(); + final int columns = fRendering.getColumnCount(); + BigInteger lengthToRead = end.subtract(start); + + int rows = lengthToRead.divide(BigInteger.valueOf(columns * (fRendering.getFPDataType().getByteLength()))).intValue(); + + if (rows * columns * bytesPerColumn < lengthToRead.intValue()) rows++; + + StringBuffer buffer = new StringBuffer(); + + for (int row = 0; row < rows; row++) + { + BigInteger rowAddress = start.add(BigInteger.valueOf(row * columns * bytesPerColumn)); + + if (fRendering.getPaneVisible(Rendering.PANE_ADDRESS)) + { + buffer.append(fRendering.getAddressString(rowAddress)); + buffer.append(PANE_SPACING); + } + + if (fRendering.getPaneVisible(Rendering.PANE_DATA)) + { + for(int col = 0; col < columns; col++) + { + BigInteger cellAddress = rowAddress.add(BigInteger.valueOf(col * bytesPerColumn)); + + if (cellAddress.compareTo(end) < 0) + { + try + { + FPMemoryByte bytes[] = fRendering.getBytes(cellAddress, bytesPerColumn); + buffer.append(fRendering.sciNotationString(bytes, numberType, isLittleEndian)); + } + catch(DebugException de) + { + fRendering + .logError( + FPRenderingMessages + .getString("FPRendering.FAILURE_COPY_OPERATION"), de); //$NON-NLS-1$ + return; + } + } + else + { + for(int i = fRendering.getCharsPerColumn(); i > 0; i--) + buffer.append(' '); + } + + if (col != columns - 1) + buffer.append(' '); + } + } + + if (fRendering.getPaneVisible(Rendering.PANE_DATA)) + buffer.append(PANE_SPACING); + + buffer.append("\n"); //$NON-NLS-1$ + } + + if (buffer.length() > 0) + { + TextTransfer plainTextTransfer = TextTransfer.getInstance(); + clip.setContents(new Object[] { buffer.toString() }, new Transfer[] { plainTextTransfer }, fType); + } + } + finally + { + if (clip != null) + { + clip.dispose(); + } + } + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingMessages.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingMessages.java new file mode 100644 index 00000000000..88ab53aa05b --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingMessages.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class FPRenderingMessages +{ + private static final String BUNDLE_NAME = "org.eclipse.cdt.debug.ui.memory.floatingpoint.messages"; //$NON-NLS-1$ + private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME); + + private FPRenderingMessages() + { + } + + public static String getString(String key) + { + // TODO Auto-generated method stub + try + { + return RESOURCE_BUNDLE.getString(key); + } + catch(MissingResourceException e) + { + return '!' + key + '!'; + } + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPlugin.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPlugin.java new file mode 100644 index 00000000000..54f6842d8bf --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPlugin.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +public class FPRenderingPlugin extends AbstractUIPlugin +{ + public static final String PLUGIN_ID = "org.eclipse.cdt.debug.ui.memory.floatingpoint"; //$NON-NLS-1$ + + private static FPRenderingPlugin plugin; + + public FPRenderingPlugin() + { + super(); + } + + + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + + /** + * Returns the shared instance. + */ + public static FPRenderingPlugin getDefault() + { + return plugin; + } + + /** + * Returns the unique identifier for this plugin. + */ + public static String getUniqueIdentifier() + { + return PLUGIN_ID; + } + + /** + * Returns the workbench's display. + */ + public static Display getStandardDisplay() + { + return PlatformUI.getWorkbench().getDisplay(); + } + + /** + * Returns the currently active workbench window shell or null + * if none. + * + * @return the currently active workbench window shell or null + */ + public static Shell getShell() + { + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + + if (window == null) + { + IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows(); + if (windows.length > 0) + { + return windows[0].getShell(); + } + } + else + { + return window.getShell(); + } + return null; + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferenceAction.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferenceAction.java new file mode 100644 index 00000000000..ac158b1e6d9 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferenceAction.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.preference.IPreferenceNode; +import org.eclipse.jface.preference.IPreferencePage; +import org.eclipse.jface.preference.PreferenceDialog; +import org.eclipse.jface.preference.PreferenceManager; +import org.eclipse.jface.preference.PreferenceNode; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.custom.BusyIndicator; +import org.eclipse.ui.IViewActionDelegate; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.actions.ActionDelegate; + +public class FPRenderingPreferenceAction extends ActionDelegate implements IViewActionDelegate +{ + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction) + */ + @Override + public void run(IAction action) + { + IPreferencePage page = new FPRenderingPreferencePage(); + showPreferencePage("org.eclipse.cdt.debug.ui.memory.floatingpoint.FPRenderingPreferencePage", page); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart) + */ + @Override + public void init(IViewPart view) + { + } + + protected void showPreferencePage(String id, IPreferencePage page) + { + final IPreferenceNode targetNode = new PreferenceNode(id, page); + + PreferenceManager manager = new PreferenceManager(); + manager.addToRoot(targetNode); + final PreferenceDialog dialog = new PreferenceDialog(FPRenderingPlugin.getShell(), manager); + final boolean[] result = new boolean[] { false }; + BusyIndicator.showWhile(FPRenderingPlugin.getStandardDisplay(), new Runnable() + { + @Override + public void run() + { + dialog.create(); + dialog.setMessage(targetNode.getLabelText()); + result[0] = (dialog.open() == Window.OK); + } + }); + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferenceConstants.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferenceConstants.java new file mode 100644 index 00000000000..1fc4a93670f --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferenceConstants.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +/** + * Constant definitions for plug-in preferences + */ +public class FPRenderingPreferenceConstants +{ + public static final String MEM_COLOR_CHANGED = "memoryColorChanged"; //$NON-NLS-1$ + public static final String MEM_USE_GLOBAL_BACKGROUND = "memUseGlobalBackground"; //$NON-NLS-1$ + public static final String MEM_COLOR_BACKGROUND = "memoryColorBackground"; //$NON-NLS-1$ + public static final String MEM_COLOR_EDIT = "memoryColorEdit"; //$NON-NLS-1$ + public static final String MEM_COLOR_TEXT = "memoryColorText"; //$NON-NLS-1$ + public static final String MEM_USE_GLOBAL_SELECTION = "memUseGlobalSelection"; //$NON-NLS-1$ + public static final String MEM_COLOR_SELECTION = "memoryColorSelection"; //$NON-NLS-1$ + public static final String MEM_USE_GLOBAL_TEXT = "memUseGlobalText"; //$NON-NLS-1$ + public static final String MEM_LIGHTEN_DARKEN_ALTERNATE_CELLS = "memoryColorScaleTextAlternate"; //$NON-NLS-1$ + public static final String MEM_EDIT_BUFFER_SAVE = "memoryEditBufferSave"; //$NON-NLS-1$ + public static final String MEM_EDIT_BUFFER_SAVE_ON_ENTER_ONLY = "saveOnEnterCancelOnFocusLost"; //$NON-NLS-1$ + public static final String MEM_EDIT_BUFFER_SAVE_ON_ENTER_OR_FOCUS_LOST = "saveOnEnterOrFocusLost"; //$NON-NLS-1$ + public static final String MEM_HISTORY_TRAILS_COUNT = "memoryHistoryTrailsCount"; //$NON-NLS-1$ +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferenceInitializer.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferenceInitializer.java new file mode 100644 index 00000000000..7cbcbed5e3f --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferenceInitializer.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Display; + +/** + * Class used to initialize default preference values. + */ +public class FPRenderingPreferenceInitializer extends AbstractPreferenceInitializer +{ + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer# + * initializeDefaultPreferences() + */ + @Override + public void initializeDefaultPreferences() + { + IPreferenceStore store = FPRenderingPlugin.getDefault().getPreferenceStore(); + + store.setDefault(FPRenderingPreferenceConstants.MEM_USE_GLOBAL_TEXT, true); + store.setDefault(FPRenderingPreferenceConstants.MEM_USE_GLOBAL_BACKGROUND, true); + store.setDefault(FPRenderingPreferenceConstants.MEM_USE_GLOBAL_SELECTION, true); + + store.setDefault(FPRenderingPreferenceConstants.MEM_COLOR_CHANGED, "255,0,0"); //$NON-NLS-1$ + + Color systemSelection = Display.getDefault().getSystemColor(SWT.COLOR_LIST_SELECTION); + store.setDefault(FPRenderingPreferenceConstants.MEM_COLOR_SELECTION, systemSelection.getRed() + "," + systemSelection.getGreen() + "," //$NON-NLS-1$ //$NON-NLS-2$ + + systemSelection.getBlue()); + + store.setDefault(FPRenderingPreferenceConstants.MEM_LIGHTEN_DARKEN_ALTERNATE_CELLS, "5"); //$NON-NLS-1$ + + store.setDefault(FPRenderingPreferenceConstants.MEM_COLOR_EDIT, "0,255,0"); //$NON-NLS-1$ + + Color systemText = Display.getDefault().getSystemColor(SWT.COLOR_LIST_FOREGROUND); + store.setDefault(FPRenderingPreferenceConstants.MEM_COLOR_TEXT, systemText.getRed() + "," + systemText.getGreen() + "," + systemText.getBlue()); //$NON-NLS-1$ //$NON-NLS-2$ + + Color systemBackground = Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND); + store.setDefault(FPRenderingPreferenceConstants.MEM_COLOR_BACKGROUND, systemBackground.getRed() + "," + systemBackground.getGreen() + "," //$NON-NLS-1$ //$NON-NLS-2$ + + systemBackground.getBlue()); + + store.setDefault(FPRenderingPreferenceConstants.MEM_EDIT_BUFFER_SAVE, FPRenderingPreferenceConstants.MEM_EDIT_BUFFER_SAVE_ON_ENTER_ONLY); + + store.setDefault(FPRenderingPreferenceConstants.MEM_HISTORY_TRAILS_COUNT, "1"); //$NON-NLS-1$ + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferencePage.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferencePage.java new file mode 100644 index 00000000000..716596f25a4 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingPreferencePage.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.ColorFieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.RadioGroupFieldEditor; +import org.eclipse.jface.preference.ScaleFieldEditor; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.ui.PlatformUI; + +/** + * This class represents a preference page that is contributed to the + * Preferences dialog. By subclassing FieldEditorPreferencePage, we + * can use the field support built into JFace that allows us to create a page + * that is small and knows how to save, restore and apply itself. + *

+ * This page is used to modify preferences only. They are stored in the + * preference store that belongs to the main plug-in class. That way, + * preferences can be accessed directly via the preference store. + */ + +public class FPRenderingPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage +{ + public FPRenderingPreferencePage() + { + super(GRID); + setPreferenceStore(FPRenderingPlugin.getDefault().getPreferenceStore()); + setDescription("Floating Point Memory Rendering"); //$NON-NLS-1$ + } + + @Override + public void createControl(Composite parent) + { + super.createControl(parent); + PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), FPRenderingPlugin.getUniqueIdentifier() + ".FPRenderingPreferencePage_context"); //$NON-NLS-1$ + } + + /** + * Creates the field editors. Field editors are abstractions of the common + * GUI blocks needed to manipulate various types of preferences. Each field + * editor knows how to save and restore itself. + */ + @Override + public void createFieldEditors() + { + addField(new BooleanFieldEditor(FPRenderingPreferenceConstants.MEM_USE_GLOBAL_TEXT, "Use Global Te&xt Color", getFieldEditorParent())); //$NON-NLS-1$ + addField(new ColorFieldEditor(FPRenderingPreferenceConstants.MEM_COLOR_TEXT, "&Text Color:", getFieldEditorParent())); //$NON-NLS-1$ + addField(new ScaleFieldEditor(FPRenderingPreferenceConstants.MEM_LIGHTEN_DARKEN_ALTERNATE_CELLS, "Brighten Alternate Cells", getFieldEditorParent(), 0, 8, 1, 1)); //$NON-NLS-1$ + addField(new BooleanFieldEditor(FPRenderingPreferenceConstants.MEM_USE_GLOBAL_BACKGROUND, "Use Global B&ackground Color", getFieldEditorParent())); //$NON-NLS-1$ + addField(new ColorFieldEditor(FPRenderingPreferenceConstants.MEM_COLOR_BACKGROUND, "&Background Color:", getFieldEditorParent())); //$NON-NLS-1$ + addField(new ColorFieldEditor(FPRenderingPreferenceConstants.MEM_COLOR_CHANGED, "&Changed Color:", getFieldEditorParent())); //$NON-NLS-1$ + addField(new ColorFieldEditor(FPRenderingPreferenceConstants.MEM_COLOR_EDIT, "&Edit Color:", getFieldEditorParent())); //$NON-NLS-1$ + addField(new BooleanFieldEditor(FPRenderingPreferenceConstants.MEM_USE_GLOBAL_SELECTION, "Use Global Se&lection Color", getFieldEditorParent())); //$NON-NLS-1$ + addField(new ColorFieldEditor(FPRenderingPreferenceConstants.MEM_COLOR_SELECTION, "&Selection Color:", getFieldEditorParent())); //$NON-NLS-1$ + addField(new RadioGroupFieldEditor(FPRenderingPreferenceConstants.MEM_EDIT_BUFFER_SAVE, "Edit Buffer", 1, new String[][] //$NON-NLS-1$ + { { "Save on E&nter, Cancel on Focus Lost", "saveOnEnterCancelOnFocusLost" }, //$NON-NLS-1$ //$NON-NLS-2$ + { "Save on Enter or Focus L&ost", "saveOnEnterOrFocusLost" } }, getFieldEditorParent())); //$NON-NLS-1$ //$NON-NLS-2$ + addField(new ScaleFieldEditor(FPRenderingPreferenceConstants.MEM_HISTORY_TRAILS_COUNT, "History &Trail Levels", getFieldEditorParent(), 1, 10, 1, 1)); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) + */ + @Override + public void init(IWorkbench workbench) + { + } + +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingTypeDelegate.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingTypeDelegate.java new file mode 100644 index 00000000000..8a71b83a252 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPRenderingTypeDelegate.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.ui.memory.IMemoryRendering; +import org.eclipse.debug.ui.memory.IMemoryRenderingTypeDelegate; + +public class FPRenderingTypeDelegate implements IMemoryRenderingTypeDelegate +{ + @Override + public IMemoryRendering createRendering(String id) throws CoreException + { + return new FPRendering(id); + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPutilities.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPutilities.java new file mode 100644 index 00000000000..c59bd5d5e4b --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/FPutilities.java @@ -0,0 +1,492 @@ +/******************************************************************************* + * Copyright (c) 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Arrays; +import java.util.regex.Pattern; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.progress.UIJob; + +public class FPutilities +{ + private static final int BYTE_MASK = 0xFF; + + // ANSI C "Smallest" and "largest" negative and positive float and double values + + public static final float floatNegMax = -3.40282347E+38f; // Largest negative float value; farthest from zero + public static final float floatNegMin = -1.17549435E-38f; // Smallest negative float value; closest to zero + public static final float floatPosMax = 1.17549435E+38f; // Largest positive float value; farthest from zero + public static final float floatPosMin = 3.40282347E-38f; // Smallest positive float value; closest to zero + + public static final double doubleNegMax = -1.7976931348623157E+308; // Largest positive double value + public static final double doubleNegMin = -2.2250738585072014E-308; // Smallest positive double value + public static final double doublePosMax = 1.7976931348623157E+308; // Largest positive double value + public static final double doublePosMin = 2.2250738585072014E-308; // Smallest positive double value + + public enum FPDataType + { + // Value (for persisteance), Bitsize of type, Number of internal precision decimal digits, Default displayed precision + + FLOAT ( 10, 32, 7, 8), // C/C++ single-precision "float" + DOUBLE ( 20, 64, 15, 8), // C/C++ double-precision "double" + FLOAT_80 ( 30, 80, 19, 16), // Extended precision + FLOAT_96 ( 40, 96, 0, 0), // TODO: unknown internal decimal digit precision; C/C++ extended-precision "long double" + + // Future work + + FLOAT_128 (50, 128, 33, 16), // TODO: known values, but not currently implmented + FLOAT_256 (60, 256, 0, 0), // TODO: unknown internal decimal digit precision + FLOAT_512 (70, 512, 0, 0); // TODO: unknown internal decimal digit precision + + // Member variables + + private int value; + private int bitsize; + private int decimalPrecision; + private int displayedPrecision; + + // Constructor + + private FPDataType(int value, int bitSize, int precisionDigits, int defaultDisplayPrecision) + { + this.value = value; + this.bitsize = bitSize; + this.decimalPrecision = precisionDigits; + this.displayedPrecision = defaultDisplayPrecision; + } + + // Getters + + public int getValue() { return value; } + public int getBitsize() { return bitsize; } + public int getDecimalPrecision() { return decimalPrecision; } + public int getDisplayedPrecision() { return displayedPrecision; } + public int getInternalPrecision() { return decimalPrecision; } + + public int getByteLength() + { + return bitsize/Byte.SIZE; + } + } + + // Byte ordering + + public enum Endian + { + // Value + + LITTLE (10), + BIG (20); + + // Member variables + + private int value; + + // Constructor + + private Endian(int value) + { + this.value = value; + } + + // Getters + + public int getValue() { return value; } + } + + // Justification (latent support) + + public enum Justification + { + LEFT, + RIGHT, + CENTER; + } + + // Convert raw float bits to a byte array + + public static byte[] rawFloatBitsToByteArray(int floatBits) + { + int byteCount = Integer.SIZE/Byte.SIZE; + byte[] result = new byte[byteCount]; + + for (int index = 0; index < byteCount; index++) + { + int offset = (result.length - 1 - index) * 8; + result[index] = (byte) ((floatBits >>> offset) & BYTE_MASK); + } + + return result; + } + + // Convert raw double bits to a byte array + + public static byte[] rawDoubleBitsToByteArray(long doubleBits) + { + int byteCount = Long.SIZE/Byte.SIZE; + byte[] result = new byte[byteCount]; + + for (int index = 0; index < byteCount; index++) + { + int offset = (result.length - 1 - index) * 8; + result[index] = (byte) ((doubleBits >>> offset) & BYTE_MASK); + } + + return result; + } + + // Return a byte array that is in reverse order of the passed-in array parameter + + public static byte[] reverseByteOrder(byte[] byteArray) + { + if (byteArray.length == 0) return new byte[0]; + + byte tempByte = 0; + byte[] reversedByteArray = new byte[byteArray.length]; + + // Copy the array that is passed in to the array that will be returned + + System.arraycopy(byteArray, 0, reversedByteArray, 0, byteArray.length); + + // Reverse the bytes + + for(int start = 0, end = reversedByteArray.length - 1; start < end; ++start, --end) + { + tempByte = reversedByteArray[start]; + reversedByteArray[start] = reversedByteArray[end]; + reversedByteArray[end] = tempByte; + } + + return reversedByteArray; + } + + // Convert a representation of a float or double in a byte array to a scientific notation string (Should we use BigDecimal here???) + + public static String byteArrayToSciNotation(FPDataType dt, boolean isLittleEndian, FPMemoryByte[] memByteArray, int maxDisplayDigits) throws ArithmeticException + { + int displayedDigits = 8; + + // If the byte array is not a 32-bit float or 64-bit double, throw an exception. + + if (memByteArray.length != (FPDataType.FLOAT.getByteLength()) && + memByteArray.length != (FPDataType.DOUBLE.getByteLength())) + throw new ArithmeticException("Conversion of the floating point number cannot be performed; invalid data type or byte array length."); //$NON-NLS-1$ + + // Create and initialize a DecimalFormat object for scientific notation. Specify a space + // for the preceding plus-sign, which lines up the first significant digit, decimal point + // and exponent character. Define the symbol strings for "Not a Number" and "Infinity." + + DecimalFormat df = new DecimalFormat("0.0E0"); //$NON-NLS-1$ + df.setPositivePrefix(" "); //$NON-NLS-1$ + + DecimalFormatSymbols dfSymbols = new DecimalFormatSymbols(); + dfSymbols.setNaN(" "+ FPRenderingMessages.getString("FPRendering.NAN")); //$NON-NLS-1$ //$NON-NLS-2$ + dfSymbols.setInfinity(FPRenderingMessages.getString("FPRendering.INFINITY")); //$NON-NLS-1$ + df.setDecimalFormatSymbols(dfSymbols); + + // Set the integer and fraction digits for normalized scientific notation. + + df.setMinimumIntegerDigits(1); + df.setMaximumIntegerDigits(1); + + if (dt == FPDataType.FLOAT) + displayedDigits = Math.min(maxDisplayDigits, FPDataType.FLOAT.getInternalPrecision()); + + if (dt == FPDataType.DOUBLE) + displayedDigits = Math.min(maxDisplayDigits, FPDataType.DOUBLE.getInternalPrecision()); + + df.setMinimumFractionDigits(displayedDigits - 1); + df.setMaximumFractionDigits(displayedDigits - 1); + + // Convert the byte array to a scientific notation floating point number string (only floats and doubles currently supported) + + ByteOrder byteOrder = isLittleEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN; + + return df.format(dt == FPDataType.FLOAT ? + ByteBuffer.wrap(memoryBytesToByteArray(memByteArray)).order(byteOrder).getFloat() : + ByteBuffer.wrap(memoryBytesToByteArray(memByteArray)).order(byteOrder).getDouble()); + } + + // Convert a floating point string to a byte array (*** only 'floats' and 'doubles' currently supported ***) + + public static byte[] floatingStringToByteArray(FPDataType dt, String valueString, int dataTypeBitCount) throws NumberFormatException + { + // Remove whitespace and check for non-zero length + valueString = valueString.trim().replaceAll(" ", ""); //$NON-NLS-1$ //$NON-NLS-2$ + + if (valueString.length() != 0) + { + // Float handling + + if (dt == FPDataType.FLOAT || FPDataType.FLOAT.getBitsize() == dataTypeBitCount) + { + // Convert the string to a float. Check the range. Convert to byte array. + + float floatValue = new Float(valueString).floatValue(); + floatValue = floatLimitCheck(floatValue); + return rawFloatBitsToByteArray(Float.floatToRawIntBits(floatValue)); + } + + // Double handling + + if (dt == FPDataType.DOUBLE || FPDataType.DOUBLE.getBitsize() == dataTypeBitCount) + { + // Convert the string to a double. Check the range. Convert to byte array. + + double doubleValue = new Double(valueString).doubleValue(); + doubleValue = doubleLimitCheck(doubleValue); + return rawDoubleBitsToByteArray(Double.doubleToRawLongBits(doubleValue)); + } + } + + return new byte[0]; + } + + // Convert from an FPMemoryByte array to a byte array + + public static byte[] memoryBytesToByteArray(FPMemoryByte[] memoryByteArray) + { + byte[] byteArray = new byte[memoryByteArray.length]; + + for (int index = 0; index < memoryByteArray.length; index++) + byteArray[index] = memoryByteArray[index].getValue(); + + return byteArray; + } + + // Convert from a byte array to a MemoryByte array + + public static FPMemoryByte[] byteArrayToMemoryBytes(Endian endian, byte[] byteArray) + { + FPMemoryByte[] memoryBytes = new FPMemoryByte[byteArray.length]; + + for (int index = 0; index < byteArray.length; index++) + { + memoryBytes[index] = new FPMemoryByte(); + memoryBytes[index].setBigEndian(endian == Endian.BIG); + memoryBytes[index].setValue(byteArray[index]); + } + + return memoryBytes; + } + + // Check the character for being valid for number entry, both standard and scientific notation + + public static boolean validEditCharacter(char character) + { + return (character >= '0' && character <= '9') || + character == '+' || character == '-' || + character == 'e' || character == 'E' || + character == '.' || character == ' '; + } + + // Validate floating point number string + + public static boolean isValidFormat(String string) + { + // Rules: + // - A minimum of one digit preceding the optional exponent character is required. + // - Allowable characters: 0-9, a decimal point, '+' and '-' number + // signs, exponent characters 'e' and 'E', and spaces. + // + // Strings may also have: + // - One [optional] decimal point + // - A maximum of two [optional] number signs (one before the number and one after the exponent character) + // - Only one [optional] exponent character is allowed + + boolean digit = false; + char[] charArray = string.toCharArray(); + + // Phase I check: + + String scientificNotationPattern = "^[-+]??(\\d++[.]\\d*?|[.]?\\d+?|\\d+(?=[eE]))([eE][-+]??\\d++)?$"; //$NON-NLS-1$ + + if (!Pattern.matches(scientificNotationPattern, string)) + return false; + + // Phase II check + + for (int index = 0; index < string.length(); index++) + { + // Check for a digit + + if (charArray[index] >= '0' && charArray[index] <= '9') + digit = true; + + // Make sure it's a valid/allowable character + + if (!validEditCharacter(charArray[index])) + return false; + + // Only one decimal point and exponent character is allowed + + if (FPutilities.countMatches(string.toLowerCase(), ".") > 1 || FPutilities.countMatches(string.toLowerCase(), "e") > 1) //$NON-NLS-1$ //$NON-NLS-2$ + return false; + + // Number signs are only allowed in the first position and following the exponent character. + + if (((charArray[index] == '+' || charArray[index] == '-') && index != 0) && + (charArray[index-1] != 'e' && charArray[index-1] != 'E')) + return false; + + // Decimal points are not allowed after the exponent character + + int eIndex = string.toLowerCase().indexOf('e'); + + if (charArray[index] == '.' && eIndex != -1 && eIndex < index) + return false; + } + + return digit; + } + + // Return a string of the specified length filled with the specified character + + public static String fillString(int length, char character) + { + if (length < 1) return ""; //$NON-NLS-1$ + char[] charArray = new char[length]; + Arrays.fill(charArray, character); + return new String(charArray); + } + + // Count the 'subString' matches in 'string' + + public static int countMatches(String string, String subString) + { + if (string.length() == 0 || subString.length() == 0) return 0; + + int count = 0; + int index = 0; + + while ((index = string.indexOf(subString, index)) != -1) + { + count++; + index += subString.length(); + } + + return count; + } + + // Print out a stack trace; useful for UI operations where stopping at a breakpoint causes button press context to be lost + + public static void stackTrace(int depth) + { + int offset = 3; // Ignore frames contributed to the stack based on call to this method + if (depth == 0) depth = 4; // Default depth if zero supplied + + // Get the stack frames for the current thread; start at the offset + + StackTraceElement[] seArray = Thread.currentThread().getStackTrace(); + + if (seArray.length > offset) + { + System.out.println("Displaying " + depth + " of " + seArray.length + " stack trace elements"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + for (int index = offset; index < Math.min(depth + offset, seArray.length + offset); index++) + System.out.println(" " + seArray[index].getClassName() + "." + seArray[index].getMethodName() + ": line " + seArray[index].getLineNumber()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + else + System.out.println("No stack frames to display"); //$NON-NLS-1$ + } + + // Pop up a message inside the UI thread + + public static void popupMessage(final String title, final String errorText, final Status status) + { + UIJob job = new UIJob("Floating Point Renderer") //$NON-NLS-1$ + { + // Notify the user of some condition via a pop-up box. + + @Override + public IStatus runInUIThread(IProgressMonitor monitor) + { + ErrorDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), title, errorText, status); + return Status.OK_STATUS; + } + }; + + job.setSystem(true); + job.schedule(); + } + + // Check float range. Returns -Infinity, the original value or +Infinity + + public static float floatLimitCheck(float floatValue) + { + if (floatValue != 0.0f && floatValue != Float.NEGATIVE_INFINITY && floatValue != Float.POSITIVE_INFINITY) + { + if (floatValue < 0) + { + if (Float.compare(floatValue, floatNegMax) < 0 || Float.compare(floatValue, floatNegMin) > 0) + return Float.NEGATIVE_INFINITY; + } + else + { + if (Float.compare(floatValue, floatPosMin) < 0 || Float.compare(floatValue, floatPosMax) > 0) + return Float.POSITIVE_INFINITY; + } + } + + return floatValue; + } + + // Check double range. Returns a value of RangeCheck + + public static double doubleLimitCheck(double doubleValue) + { + if (doubleValue != 0.0 && doubleValue != Double.NEGATIVE_INFINITY && doubleValue != Double.POSITIVE_INFINITY) + { + if (doubleValue < 0) + { + if (Double.compare(doubleValue, doubleNegMax) < 0 || Double.compare(doubleValue, doubleNegMin) > 0) + return Double.NEGATIVE_INFINITY; + } + else + { + if (Double.compare(doubleValue, doublePosMin) < 0 || Double.compare(doubleValue, doublePosMax) > 0) + return Double.POSITIVE_INFINITY; + } + } + + return doubleValue; + } + + // Convert a BigInteger to a hex String and return only the ending number of specified digits. + + public static String bi2HexStr(BigInteger bi, int lastDigits) + { + final int PAD_LENGTH = 12; + String base16 = bi.toString(16); + base16 = fillString(PAD_LENGTH - base16.length(), '0') + base16; + return "0x" + base16.substring(PAD_LENGTH - lastDigits).toUpperCase(); //$NON-NLS-1$ + } + + // Convert a BigInteger to a decimal String and return only the ending number of + // specified digits. For example: bi2HexStr(239248506, 5) = "48506" + + public static String bi2DecStr(BigInteger bi, int lastDigits) + { + final int PAD_LENGTH = 12; + String base10 = bi.toString(); + base10 = fillString(PAD_LENGTH - base10.length(), '0') + base10; + return base10.substring(PAD_LENGTH - lastDigits); + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/IFPRConstants.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/IFPRConstants.java new file mode 100644 index 00000000000..2d65cfead84 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/IFPRConstants.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +public interface IFPRConstants +{ + public final String ENDIAN_KEY = FPRenderingPlugin.PLUGIN_ID + ".endian"; // Endianness key //$NON-NLS-1$ + public final String DATATYPE_KEY = FPRenderingPlugin.PLUGIN_ID + ".dataType"; // Currently-selected data type //$NON-NLS-1$ + public final String FLOAT_DISP_KEY = FPRenderingPlugin.PLUGIN_ID + ".floatDispPrec"; // 32-bit floating point data type displayed precision //$NON-NLS-1$ + public final String DOUBLE_DISP_KEY = FPRenderingPlugin.PLUGIN_ID + ".doubleDispPrec"; // 64-bit floating point data type displayed precision //$NON-NLS-1$ + public final String COLUMN_COUNT_KEY = FPRenderingPlugin.PLUGIN_ID + ".columns"; // Number of columns to display //$NON-NLS-1$ + public final String UPDATEMODE_KEY = FPRenderingPlugin.PLUGIN_ID + ".updateMode"; // Renderer update mode //$NON-NLS-1$ +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/Rendering.java b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/Rendering.java new file mode 100644 index 00000000000..bf6ba9cdecd --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/Rendering.java @@ -0,0 +1,2297 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010, 2012 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ted R Williams (Wind River Systems, Inc.) - initial implementation + * Randy Rohrbach (Wind River Systems, Inc.) - Copied and modified to create the floating point plugin + *******************************************************************************/ + +package org.eclipse.cdt.debug.ui.memory.floatingpoint; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; +import java.util.Vector; + +import org.eclipse.cdt.debug.ui.memory.floatingpoint.FPutilities.FPDataType; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +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.model.IDebugElement; +import org.eclipse.debug.core.model.IMemoryBlock; +import org.eclipse.debug.core.model.IMemoryBlockExtension; +import org.eclipse.debug.core.model.MemoryByte; +import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; +import org.eclipse.debug.internal.ui.views.memory.MemoryViewUtil; +import org.eclipse.debug.internal.ui.views.memory.renderings.GoToAddressComposite; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Layout; +import org.eclipse.swt.widgets.ScrollBar; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.progress.UIJob; + + +@SuppressWarnings("restriction") +public class Rendering extends Composite implements IDebugEventSetListener +{ + // The IMemoryRendering parent + + private FPRendering fParent; + + // Controls + + protected FPAddressPane fAddressPane; + protected FPDataPane fDataPane; + private GoToAddressComposite fAddressBar; + protected Control fAddressBarControl; + private Selection fSelection = new Selection(); + + // Internal management + + BigInteger fViewportAddress = null; // Default visibility for performance + BigInteger fMemoryBlockStartAddress = null; // Starting address + BigInteger fMemoryBlockEndAddress = null; // Ending address + protected BigInteger fBaseAddress = null; // Base address + protected int fColumnCount = 0; // Auto calculate can be disabled by user, making this user settable + protected int fBytesPerRow = 0; // Number of bytes per row are displayed + int fScrollSelection = 0; // Scroll selection + private BigInteger fCaretAddress = null; // Caret/cursor position + private boolean fCellEditState = false; // Cell editing mode: 'true' = currently editing a cell; 'false' = not editing a cell + private BigInteger cellEditAddress = null; // The address of the cell currently being edited + private BigInteger memoryAddress = null; // The memory address associated with the cell that currently being edited + private StringBuffer fEditBuffer = null; // Character buffer used during editing + static boolean initialDisplayModeSet = false; // Initial display mode been set to the same endianness as the target + + // Constants used to identify the panes + + public final static int PANE_ADDRESS = 1; + public final static int PANE_DATA = 2; + + // Decimal precision used when converting between scroll units and number of memory + // rows. Calculations do not need to be exact; two decimal places is good enough. + + static private final MathContext SCROLL_CONVERSION_PRECISION = new MathContext(2); + + // Constants used to identify text, maybe java should be queried for all available sets + + public final static int TEXT_ISO_8859_1 = 1; + public final static int TEXT_USASCII = 2; + public final static int TEXT_UTF8 = 3; + protected final static int TEXT_UTF16 = 4; + + // Internal constants + + public final static int COLUMNS_AUTO_SIZE_TO_FIT = 0; + + // View internal settings + + private int fCellPadding = 2; + private int fPaneSpacing = 16; + private String fPaddingString = " "; //$NON-NLS-1$ + + // Flag whether the memory cache is dirty + + private boolean fCacheDirty = false; + + // Update modes + + public final static int UPDATE_ALWAYS = 1; + public final static int UPDATE_ON_BREAKPOINT = 2; + public final static int UPDATE_MANUAL = 3; + public int fUpdateMode = UPDATE_ALWAYS; + + // Constants for cell-width calculations + + private static final int DECIMAL_POINT_SIZE = 1; + private static final int SIGN_SIZE = 1; + private static final int EXPONENT_CHARACTER_SIZE = 1; + private static final int EXPONENT_VALUE_SIZE = 3; + + // User settings + + private FPDataType fFPDataType = FPDataType.FLOAT; // Default to float data type + private int fDisplayedPrecision = 8; // The default number of digits of displayed precision + private int fCharsPerColumn = charsPerColumn(); // Figure out the initial cell-width size + private int fColumnsSetting = COLUMNS_AUTO_SIZE_TO_FIT; // Default column setting + private boolean fIsTargetLittleEndian = true; // Default target endian setting + private boolean fIsDisplayLittleEndian = true; // Default display endian setting + private boolean fEditInserMode = false; // Insert mode: true = replace existing number, false = overstrike + + // Constructors + + public Rendering(Composite parent, FPRendering renderingParent) + { + super(parent, SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND | SWT.H_SCROLL | SWT.V_SCROLL); + this.setFont(JFaceResources.getFont(IInternalDebugUIConstants.FONT_NAME)); // TODO: internal? + this.fParent = renderingParent; + + // Initialize the viewport start + + if (fParent.getMemoryBlock() != null) + { + fViewportAddress = fParent.getMemoryBlockStartAddress(); + + // The viewport address will be null if memory may be retrieved at any + // address less than this memory block's base. If so use the base address. + + if (fViewportAddress == null) + fViewportAddress = fParent.getBigBaseAddress(); + + fBaseAddress = fViewportAddress; + } + + // Instantiate the panes, TODO default visibility from state or plugin.xml? + + this.fAddressPane = createAddressPane(); + this.fDataPane = createDataPane(); + + fAddressBar = new GoToAddressComposite(); + fAddressBarControl = fAddressBar.createControl(parent); + Button button = fAddressBar.getButton(IDialogConstants.OK_ID); + + if (button != null) + { + button.addSelectionListener(new SelectionAdapter() + { + + @Override + public void widgetSelected(SelectionEvent e) + { + doGoToAddress(); + } + }); + + button = fAddressBar.getButton(IDialogConstants.CANCEL_ID); + if (button != null) + { + button.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + setVisibleAddressBar(false); + } + }); + } + } + + fAddressBar.getExpressionWidget().addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetDefaultSelected(SelectionEvent e) + { + doGoToAddress(); + } + }); + + fAddressBar.getExpressionWidget().addKeyListener(new KeyAdapter() + { + @Override + public void keyPressed(KeyEvent e) + { + if (e.keyCode == SWT.ESC) + setVisibleAddressBar(false); + super.keyPressed(e); + } + }); + + this.fAddressBarControl.setVisible(false); + + getHorizontalBar().addSelectionListener(createHorizontalBarSelectionListener()); + getVerticalBar().addSelectionListener(createVerticalBarSelectinListener()); + + this.addPaintListener(new PaintListener() + { + @Override + public void paintControl(PaintEvent pe) + { + pe.gc.setBackground(Rendering.this.getFPRendering().getColorBackground()); + pe.gc.fillRectangle(0, 0, Rendering.this.getBounds().width, Rendering.this.getBounds().height); + } + }); + + setLayout(); + + this.addControlListener(new ControlListener() + { + @Override + public void controlMoved(ControlEvent ce) + { + } + + @Override + public void controlResized(ControlEvent ce) + { + packColumns(); + } + }); + + DebugPlugin.getDefault().addDebugEventListener(this); + } + + // Determine how many characters are allowed in the column + + private int charsPerColumn() + { + return fDisplayedPrecision + DECIMAL_POINT_SIZE + SIGN_SIZE + EXPONENT_CHARACTER_SIZE + EXPONENT_VALUE_SIZE + fCellPadding; + } + + // Establish the visible layout of the view + + protected void setLayout() + { + this.setLayout(new Layout() + { + @Override + public void layout(Composite composite, boolean changed) + { + int xOffset = 0; + + if (Rendering.this.getHorizontalBar().isVisible()) + xOffset = Rendering.this.getHorizontalBar().getSelection(); + + int x = xOffset * -1; + int y = 0; + + if (fAddressBarControl.isVisible()) + { + fAddressBarControl.setBounds(0, 0, Rendering.this.getBounds().width, fAddressBarControl.computeSize(100, 30).y); // FIXME + // y = fAddressBarControl.getBounds().height; + } + + if (fAddressPane.isPaneVisible()) + { + fAddressPane.setBounds(x, y, fAddressPane.computeSize(0, 0).x, Rendering.this.getBounds().height - y); + x = fAddressPane.getBounds().x + fAddressPane.getBounds().width; + } + + if (fDataPane.isPaneVisible()) + { + fDataPane.setBounds(x, y, fDataPane.computeSize(0, 0).x, Rendering.this.getBounds().height - y); + x = fDataPane.getBounds().x + fDataPane.getBounds().width; + } + + ScrollBar horizontal = Rendering.this.getHorizontalBar(); + + horizontal.setVisible(true); + horizontal.setMinimum(0); + horizontal.setMaximum(fDataPane.getBounds().x + fDataPane.getBounds().width + xOffset); + @SuppressWarnings("unused") + int temp = horizontal.getMaximum(); + horizontal.setThumb(getClientArea().width); + horizontal.setPageIncrement(40); // TODO ? + horizontal.setIncrement(20); // TODO ? + } + + @Override + protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) + { + return new Point(100, 100); // dummy data + } + }); + } + + // Handles for the caret/cursor movement keys + + protected void handleDownArrow() + { + fViewportAddress = fViewportAddress.add(BigInteger.valueOf(getAddressableCellsPerRow())); + ensureViewportAddressDisplayable(); + redrawPanes(); + } + + protected void handleUpArrow() + { + fViewportAddress = fViewportAddress.subtract(BigInteger.valueOf(getAddressableCellsPerRow())); + ensureViewportAddressDisplayable(); + redrawPanes(); + } + + protected void handlePageDown() + { + fViewportAddress = fViewportAddress.add(BigInteger.valueOf(getAddressableCellsPerRow() * (Rendering.this.getRowCount() - 1))); + ensureViewportAddressDisplayable(); + redrawPanes(); + } + + protected void handlePageUp() + { + fViewportAddress = fViewportAddress.subtract(BigInteger.valueOf(getAddressableCellsPerRow() * (Rendering.this.getRowCount() - 1))); + ensureViewportAddressDisplayable(); + redrawPanes(); + } + + protected SelectionListener createHorizontalBarSelectionListener() + { + return new SelectionListener() + { + @Override + public void widgetSelected(SelectionEvent se) + { + Rendering.this.layout(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent se) + { + // Do nothing + } + }; + } + + protected SelectionListener createVerticalBarSelectinListener() + { + return new SelectionListener() + { + @Override + public void widgetSelected(SelectionEvent se) + { + switch (se.detail) + { + case SWT.ARROW_DOWN: + handleDownArrow(); + break; + + case SWT.PAGE_DOWN: + handlePageDown(); + break; + + case SWT.ARROW_UP: + handleUpArrow(); + break; + + case SWT.PAGE_UP: + handlePageUp(); + break; + + case SWT.SCROLL_LINE: + // See: BUG 203068 selection event details broken on GTK < 2.6 + + default: + { + if (getVerticalBar().getSelection() == getVerticalBar().getMinimum()) + { + // Set view port start address to the start address of the Memory Block + fViewportAddress = Rendering.this.getMemoryBlockStartAddress(); + } + else if (getVerticalBar().getSelection() == getVerticalBar().getMaximum()) + { + // The view port end address should be less or equal to the the end address of the Memory Block + // Set view port address to be bigger than the end address of the Memory Block for now + // and let ensureViewportAddressDisplayable() to figure out the correct view port start address + fViewportAddress = Rendering.this.getMemoryBlockEndAddress(); + } + else + { + // Figure out the delta, ignore events with no delta + int deltaScroll = getVerticalBar().getSelection() - fScrollSelection; + if (deltaScroll == 0) break; + BigInteger deltaRows = scrollbar2rows(deltaScroll); + BigInteger newAddress = fViewportAddress.add(BigInteger.valueOf(getAddressableCellsPerRow()).multiply(deltaRows)); + fViewportAddress = newAddress; + } + + ensureViewportAddressDisplayable(); + + // Update tooltip; FIXME conversion from slider to scrollbar + // getVerticalBar().setToolTipText(Rendering.this.getAddressString(fViewportAddress)); + + // Update the addresses in the Address pane. + + if (fAddressPane.isPaneVisible()) + fAddressPane.redraw(); + + redrawPanes(); + + break; + } + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent se) + { + // do nothing + } + }; + } + + protected FPAddressPane createAddressPane() + { + return new FPAddressPane(this); + } + + protected FPDataPane createDataPane() + { + return new FPDataPane(this); + } + + public FPRendering getFPRendering() // TODO rename + { + return fParent; + } + + protected void setCaretAddress(BigInteger address) + { + fCaretAddress = address; + } + + protected BigInteger getCaretAddress() + { + // Return the caret address if it has been set. Otherwise return the viewport address. + // When the rendering is first created, the caret is unset until the user clicks somewhere + // in the rendering. It also reset (unset) when the user gives us a new viewport address + + return (fCaretAddress != null) ? fCaretAddress : fViewportAddress; + } + + void doGoToAddress() + { + try + { + BigInteger address = fAddressBar.getGoToAddress(this.getMemoryBlockStartAddress(), this.getCaretAddress()); + getFPRendering().gotoAddress(address); + setVisibleAddressBar(false); + } + catch (NumberFormatException e1) + { + // FIXME log? + } + } + + // Ensure that all addresses displayed are within the addressable range + protected void ensureViewportAddressDisplayable() + { + if (fViewportAddress.compareTo(Rendering.this.getMemoryBlockStartAddress()) < 0) + { + fViewportAddress = Rendering.this.getMemoryBlockStartAddress(); + } + else if (getViewportEndAddress().compareTo(getMemoryBlockEndAddress().add(BigInteger.ONE)) > 0) + { + fViewportAddress = getMemoryBlockEndAddress().subtract(BigInteger.valueOf(getAddressableCellsPerRow() * getRowCount() - 1)); + } + + setScrollSelection(); + } + + public FPIMemorySelection getSelection() + { + return fSelection; + } + + protected int getHistoryDepth() + { + return fViewportCache.getHistoryDepth(); + } + + protected void setHistoryDepth(int depth) + { + fViewportCache.setHistoryDepth(depth); + } + + public void logError(String message, Exception e) + { + Status status = new Status(IStatus.ERROR, fParent.getRenderingId(), DebugException.INTERNAL_ERROR, message, e); + FPRenderingPlugin.getDefault().getLog().log(status); + } + + public void handleFontPreferenceChange(Font font) + { + setFont(font); + + Control controls[] = this.getRenderingPanes(); + for (int index = 0; index < controls.length; index++) + controls[index].setFont(font); + + packColumns(); + layout(true); + } + + public void setPaddingString(String padding) + { + fPaddingString = padding; + refresh(); + } + + public char getPaddingCharacter() + { + return fPaddingString.charAt(0); // use only the first character + } + + static int suspendCount = 0; + + @Override + public void handleDebugEvents(DebugEvent[] events) + { + if (this.isDisposed()) return; + + boolean isChangeOnly = false; + boolean isSuspend = false; + boolean isBreakpointHit = false; + + for (int index = 0; index < events.length; index++) + { + if (events[0].getSource() instanceof IDebugElement) + { + final int kind = events[index].getKind(); + final int detail = events[index].getDetail(); + final IDebugElement source = (IDebugElement) events[index].getSource(); + + /* + * We have to make sure we are comparing memory blocks here. It pretty much is now the + * case that the IDebugTarget is always null. Almost no one in the Embedded Space is + * using anything but CDT/DSF or CDT/TCF at this point. The older CDI stuff will still + * be using the old Debug Model API. But this will generate the same memory block and + * a legitimate IDebugTarget which will match properly. + */ + if( source.equals( getMemoryBlock() ) && source.getDebugTarget() == getMemoryBlock().getDebugTarget() ) + { + if ((detail & DebugEvent.BREAKPOINT) != 0) isBreakpointHit = true; + + if (kind == DebugEvent.SUSPEND) + { + handleSuspendEvent(detail); + isSuspend = true; + } + else if (kind == DebugEvent.CHANGE) + { + handleChangeEvent(); + isChangeOnly = true; + } + } + } + } + + if (isSuspend) + handleSuspend(isBreakpointHit); + else if (isChangeOnly) + handleChange(); + } + + protected void handleSuspend(boolean isBreakpointHit) + { + if (getUpdateMode() == UPDATE_ALWAYS || (getUpdateMode() == UPDATE_ON_BREAKPOINT && isBreakpointHit)) + { + Display.getDefault().asyncExec(new Runnable() + { + @Override + public void run() + { + archiveDeltas(); + refresh(); + } + }); + } + } + + protected void handleChange() + { + if (getUpdateMode() == UPDATE_ALWAYS) + { + Display.getDefault().asyncExec(new Runnable() + { + @Override + public void run() + { + refresh(); + } + }); + } + } + + protected void handleSuspendEvent(int detail) + { + } + + protected void handleChangeEvent() + { + } + + // Return true to enable development debug print statements + + public boolean isDebug() + { + return false; + } + + protected IMemoryBlockExtension getMemoryBlock() + { + IMemoryBlock block = fParent.getMemoryBlock(); + if (block != null) + return (IMemoryBlockExtension) block.getAdapter(IMemoryBlockExtension.class); + + return null; + } + + public BigInteger getBigBaseAddress() + { + return fParent.getBigBaseAddress(); + } + + public int getAddressableSize() + { + return fParent.getAddressableSize(); + } + + protected FPIViewportCache getViewportCache() + { + return fViewportCache; + } + + public FPMemoryByte[] getBytes(BigInteger address, int bytes) throws DebugException + { + return getViewportCache().getBytes(address, bytes); + } + + // Default visibility for performance + + ViewportCache fViewportCache = new ViewportCache(); + + private interface Request + { + } + + class ViewportCache extends Thread implements FPIViewportCache + { + class ArchiveDeltas implements Request + { + } + + class AddressPair implements Request + { + BigInteger startAddress; + BigInteger endAddress; + + public AddressPair(BigInteger start, BigInteger end) + { + startAddress = start; + endAddress = end; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (obj instanceof AddressPair) + { + return ((AddressPair) obj).startAddress.equals(startAddress) && ((AddressPair) obj).endAddress.equals(endAddress); + } + + return false; + } + + @Override + public int hashCode() { + return super.hashCode() + startAddress.hashCode() + endAddress.hashCode(); + } + + } + + class MemoryUnit implements Cloneable + { + BigInteger start; + + BigInteger end; + + FPMemoryByte[] bytes; + + @Override + public MemoryUnit clone() + { + MemoryUnit b = new MemoryUnit(); + + b.start = this.start; + b.end = this.end; + b.bytes = new FPMemoryByte[this.bytes.length]; + for (int index = 0; index < this.bytes.length; index++) + b.bytes[index] = new FPMemoryByte(this.bytes[index].getValue()); + + return b; + } + + public boolean isValid() + { + return this.start != null && this.end != null && this.bytes != null; + } + } + + @SuppressWarnings("hiding") + private HashMap fEditBuffer = new HashMap(); + private boolean fDisposed = false; + private Object fLastQueued = null; + private Vector fQueue = new Vector(); + protected MemoryUnit fCache = null; + protected MemoryUnit fHistoryCache[] = new MemoryUnit[0]; + protected int fHistoryDepth = 0; + + public ViewportCache() + { + start(); + } + + @Override + public void dispose() + { + fDisposed = true; + synchronized (fQueue) + { + fQueue.notify(); + } + } + + public int getHistoryDepth() + { + return fHistoryDepth; + } + + public void setHistoryDepth(int depth) + { + fHistoryDepth = depth; + fHistoryCache = new MemoryUnit[fHistoryDepth]; + } + + @Override + public void refresh() + { + assert Thread.currentThread().equals(Display.getDefault().getThread()) : FPRenderingMessages.getString("CALLED_ON_NON_DISPATCH_THREAD"); //$NON-NLS-1$ + + if (fCache != null) + { + queueRequest(fViewportAddress, getViewportEndAddress()); + } + } + + @Override + public void archiveDeltas() + { + assert Thread.currentThread().equals(Display.getDefault().getThread()) : FPRenderingMessages.getString("CALLED_ON_NON_DISPATCH_THREAD"); //$NON-NLS-1$ + + if (fCache != null) + { + queueRequestArchiveDeltas(); + } + } + + private void queueRequest(BigInteger startAddress, BigInteger endAddress) + { + AddressPair pair = new AddressPair(startAddress, endAddress); + queue(pair); + } + + private void queueRequestArchiveDeltas() + { + ArchiveDeltas archive = new ArchiveDeltas(); + queue(archive); + } + + private void queue(Object element) + { + synchronized (fQueue) + { + if (!(fQueue.size() > 0 && element.equals(fLastQueued))) + { + fQueue.addElement(element); + fLastQueued = element; + } + fQueue.notify(); + } + } + + @Override + public void run() + { + while (!fDisposed) + { + AddressPair pair = null; + boolean archiveDeltas = false; + synchronized (fQueue) + { + if (fQueue.size() > 0) + { + Request request = (Request) fQueue.elementAt(0); + Class type = request.getClass(); + + while (fQueue.size() > 0 && type.isInstance(fQueue.elementAt(0))) + { + request = (Request) fQueue.elementAt(0); + fQueue.removeElementAt(0); + } + + if (request instanceof ArchiveDeltas) + archiveDeltas = true; + else if (request instanceof AddressPair) + pair = (AddressPair) request; + } + } + + if (archiveDeltas) + { + for (int i = fViewportCache.getHistoryDepth() - 1; i > 0; i--) + fHistoryCache[i] = fHistoryCache[i - 1]; + + fHistoryCache[0] = fCache.clone(); + } + else if (pair != null) + { + populateCache(pair.startAddress, pair.endAddress); + } + else + { + synchronized (fQueue) + { + try + { + if (fQueue.isEmpty()) + { + fQueue.wait(); + } + } catch (Exception e) + { + // do nothing + } + } + } + } + } + + // Cache memory necessary to paint viewport + // TODO: user setting to buffer +/- x lines + // TODO: reuse existing cache? probably only a minor performance gain + + private void populateCache(final BigInteger startAddress, final BigInteger endAddress) + { + try + { + IMemoryBlockExtension memoryBlock = getMemoryBlock(); + + BigInteger lengthInBytes = endAddress.subtract(startAddress); + BigInteger addressableSize = BigInteger.valueOf(getAddressableSize()); + + long units = lengthInBytes.divide(addressableSize) + .add(lengthInBytes.mod(addressableSize).compareTo(BigInteger.ZERO) > 0 ? BigInteger.ONE : BigInteger.ZERO).longValue(); + + // CDT (and maybe other backends) will call setValue() on these MemoryBlock objects. We + // don't want this to happen, because it interferes with this rendering's own change history. + // Ideally, we should strictly use the back end change notification and history, but it is + // only guaranteed to work for bytes within the address range of the MemoryBlock. + + MemoryByte readBytes[] = memoryBlock.getBytesFromAddress(startAddress, units); + FPMemoryByte cachedBytes[] = new FPMemoryByte[readBytes.length]; + + for (int index = 0; index < readBytes.length; index++) + cachedBytes[index] = new FPMemoryByte(readBytes[index].getValue(), readBytes[index].getFlags()); + + // Derive the target endian from the read MemoryBytes. + + if (cachedBytes.length > 0) + if (cachedBytes[0].isEndianessKnown()) + setTargetLittleEndian(!cachedBytes[0].isBigEndian()); + + // The first time we execute this method, set the display endianness to the target endianness. + + if (!initialDisplayModeSet) + { + setDisplayLittleEndian(isTargetLittleEndian()); + initialDisplayModeSet = true; + } + + // Re-order bytes within unit to be a sequential byte stream if the endian is already little + + if (isTargetLittleEndian()) + { + // There isn't an order when the unit size is one, so skip for performance + + if (addressableSize.compareTo(BigInteger.ONE) != 0) + { + int unitSize = addressableSize.intValue(); + FPMemoryByte cachedBytesAsByteSequence[] = new FPMemoryByte[cachedBytes.length]; + for (int unit = 0; unit < units; unit++) + { + for (int unitbyte = 0; unitbyte < unitSize; unitbyte++) + { + cachedBytesAsByteSequence[unit * unitSize + unitbyte] = cachedBytes[unit * unitSize + unitSize - unitbyte]; + } + } + cachedBytes = cachedBytesAsByteSequence; + } + } + + final FPMemoryByte[] cachedBytesFinal = cachedBytes; + + fCache = new MemoryUnit(); + fCache.start = startAddress; + fCache.end = endAddress; + fCache.bytes = cachedBytesFinal; + + Display.getDefault().asyncExec(new Runnable() + { + @Override + public void run() + { + // Generate deltas + + for (int historyIndex = 0; historyIndex < getHistoryDepth(); historyIndex++) + { + if (fHistoryCache[historyIndex] != null && fHistoryCache[historyIndex].isValid()) + { + BigInteger maxStart = startAddress.max(fHistoryCache[historyIndex].start); + BigInteger minEnd = endAddress.min(fHistoryCache[historyIndex].end).subtract(BigInteger.ONE); + + BigInteger overlapLength = minEnd.subtract(maxStart); + if (overlapLength.compareTo(BigInteger.valueOf(0)) > 0) + { + // there is overlap + + int offsetIntoOld = maxStart.subtract(fHistoryCache[historyIndex].start).intValue(); + int offsetIntoNew = maxStart.subtract(startAddress).intValue(); + + for (int i = overlapLength.intValue(); i >= 0; i--) + { + cachedBytesFinal[offsetIntoNew + i].setChanged(historyIndex, + cachedBytesFinal[offsetIntoNew + i].getValue() != fHistoryCache[historyIndex].bytes[offsetIntoOld + i] + .getValue()); + } + + // There are several scenarios where the history cache must be updated from the data cache, so that when a + // cell is edited the font color changes appropriately. The following code deals with the different cases. + + if (historyIndex != 0) continue; + + int dataStart = fCache.start.intValue(); + int dataEnd = fCache.end.intValue(); + int dataLength = fCache.bytes.length; + + int historyStart = fHistoryCache[0].start.intValue(); + int historyEnd = fHistoryCache[0].end.intValue(); + int historyLength = fHistoryCache[0].bytes.length; + + // Case 1: The data cache is smaller than the history cache; the data cache's + // address range is fully covered by the history cache. Do nothing. + + if ((dataStart >= historyStart) && (dataEnd <= historyEnd)) + continue; + + // Case 2: The data and history cache's do not overlap at all + + if (((dataStart < historyStart) && (dataEnd < historyStart)) || (dataStart > historyEnd)) + { + // Create a new history cache: Copy the data cache bytes to the history cache + + MemoryUnit newHistoryCache = new MemoryUnit(); + + newHistoryCache.start = fCache.start; + newHistoryCache.end = fCache.end; + int newHistoryCacheSize = fCache.bytes.length; + newHistoryCache.bytes = new FPMemoryByte[newHistoryCacheSize]; + + for (int index = 0; index < newHistoryCacheSize; index++) + newHistoryCache.bytes[index] = new FPMemoryByte(fCache.bytes[index].getValue()); + + fHistoryCache[0] = newHistoryCache; + + continue; + } + + // Case 3: The data cache starts at a lower address than the history cache, but overlaps the history cache + + if ((dataStart < historyStart) && ((dataEnd >= historyStart) && (dataEnd <= historyEnd))) + { + // Create a new history cache with the missing data from the main cache and append the old history to it. + + int missingDataByteCount = historyStart - dataStart; + int historyCacheSize = historyLength; + int newHistoryCacheSize = missingDataByteCount + historyLength; + + if (missingDataByteCount <= 0 && historyCacheSize <= 0) break; + + MemoryUnit newHistoryCache = new MemoryUnit(); + + newHistoryCache.start = fCache.start; + newHistoryCache.end = fHistoryCache[0].end; + newHistoryCache.bytes = new FPMemoryByte[newHistoryCacheSize]; + + // Copy the missing bytes from the beginning of the main cache to the history cache. + + for (int index = 0; index < missingDataByteCount; index++) + newHistoryCache.bytes[index] = new FPMemoryByte(fCache.bytes[index].getValue()); + + // Copy the remaining bytes from the old history cache to the new history cache + + for (int index = 0; index < historyCacheSize; index++) + newHistoryCache.bytes[index + missingDataByteCount] = + new FPMemoryByte(fHistoryCache[0].bytes[index].getValue()); + + fHistoryCache[0] = newHistoryCache; + + continue; + } + + // Case 4: The data cache starts at a higher address than the history cache + + if (((dataStart >= historyStart) && (dataStart <= historyEnd)) && (dataEnd > historyEnd)) + { + // Append the missing main cache bytes to the history cache. + + int missingDataByteCount = dataEnd - historyEnd; + int historyCacheSize = historyEnd - historyStart; + int newHistoryCacheSize = missingDataByteCount + historyLength; + + if (missingDataByteCount > 0 && historyCacheSize > 0) + { + MemoryUnit newHistoryCache = new MemoryUnit(); + + newHistoryCache.start = fHistoryCache[0].start; + newHistoryCache.end = fCache.end; + newHistoryCache.bytes = new FPMemoryByte[newHistoryCacheSize]; + + // Copy the old history bytes to the new history cache + + System.arraycopy(fHistoryCache[0].bytes, 0, newHistoryCache.bytes, 0, historyLength); + + // Copy the bytes from the main cache that are not in the history cache to the end of the new history cache. + + for (int index = 0; index < missingDataByteCount; index++) + { + int srcIndex = dataLength - missingDataByteCount + index; + int dstIndex = historyLength + index; + newHistoryCache.bytes[dstIndex] = new FPMemoryByte(fCache.bytes[srcIndex].getValue()); + } + + fHistoryCache[0] = newHistoryCache; + + continue; + } + } + + // Case 5 - The data cache is greater than the history cache and fully covers it + + if (dataStart < historyStart && dataEnd > historyEnd) + { + int start = 0; + int end = 0; + + // Create a new history cache to reflect the entire data cache + + MemoryUnit newHistoryCache = new MemoryUnit(); + + newHistoryCache.start = fCache.start; + newHistoryCache.end = fCache.end; + int newHistoryCacheSize = fCache.bytes.length; + newHistoryCache.bytes = new FPMemoryByte[newHistoryCacheSize]; + + int topByteCount = historyStart - dataStart; + int bottomByteCount = dataEnd - historyEnd; + + // Copy the bytes from the beginning of the data cache to the new history cache + + for (int index = 0; index < topByteCount; index++) + newHistoryCache.bytes[index] = new FPMemoryByte(fCache.bytes[index].getValue()); + + // Copy the old history cache bytes to the new history cache + + start = topByteCount; + end = topByteCount + historyLength; + + for (int index = start; index < end; index++) + newHistoryCache.bytes[index] = new FPMemoryByte(fCache.bytes[index].getValue()); + + // Copy the bytes from the end of the data cache to the new history cache + + start = topByteCount + historyLength; + end = topByteCount + historyLength + bottomByteCount; + + for (int index = start; index < end; index++) + newHistoryCache.bytes[index] = new FPMemoryByte(fCache.bytes[index].getValue()); + + fHistoryCache[0] = newHistoryCache; + + continue; + } + } + } + } + + // If the history does not exist, populate the history with the just populated + // cache. This solves the use case of (1) connect to target; (2) edit memory + // before the first suspend debug event; (3) paint differences in changed color. + + if (fHistoryCache[0] == null) + fHistoryCache[0] = fCache.clone(); + + Rendering.this.redrawPanes(); + } + }); + + } + catch (Exception e) + { + // User can scroll to any memory, whether it's valid on the target or not. It doesn't make + // much sense to fill up the Eclipse error log with such "failures." So, comment out for now. + // logError(FPRenderingMessages.getString("FAILURE_READ_MEMORY"), e); //$NON-NLS-1$ + } + } + + // Bytes will be fetched from cache + + @Override + public FPMemoryByte[] getBytes(BigInteger address, int bytesRequested) throws DebugException + { + assert Thread.currentThread().equals(Display.getDefault().getThread()) : FPRenderingMessages.getString("CALLED_ON_NON_DISPATCH_THREAD"); //$NON-NLS-1$ + + if (containsEditedCell(address)) // Cell size cannot be switched during an edit + return getEditedMemory(address); + + boolean contains = false; + if (fCache != null && fCache.start != null) + { + // See if all of the data requested is in the cache + + BigInteger dataEnd = address.add(BigInteger.valueOf(bytesRequested)); + + if (fCache.start.compareTo(address) <= 0 && fCache.end.compareTo(dataEnd) >= 0 && fCache.bytes.length > 0) + contains = true; + } + + if (contains) + { + int offset = address.subtract(fCache.start).intValue(); + FPMemoryByte bytes[] = new FPMemoryByte[bytesRequested]; + + for (int index = 0; index < bytes.length; index++) + bytes[index] = fCache.bytes[offset + index]; + + return bytes; + } + + FPMemoryByte bytes[] = new FPMemoryByte[bytesRequested]; + + for (int index = 0; index < bytes.length; index++) + { + bytes[index] = new FPMemoryByte(); + bytes[index].setReadable(false); + } + + fViewportCache.queueRequest(fViewportAddress, getViewportEndAddress()); + + return bytes; + } + + @Override + public boolean containsEditedCell(BigInteger address) + { + assert Thread.currentThread().equals(Display.getDefault().getThread()) : FPRenderingMessages.getString("CALLED_ON_NON_DISPATCH_THREAD"); //$NON-NLS-1$ + return fEditBuffer.containsKey(address); + } + + public FPMemoryByte[] getEditedMemory(BigInteger address) + { + assert Thread.currentThread().equals(Display.getDefault().getThread()) : FPRenderingMessages.getString("CALLED_ON_NON_DISPATCH_THREAD"); //$NON-NLS-1$ + return fEditBuffer.get(address); + } + + @Override + public void clearEditBuffer() + { + assert Thread.currentThread().equals(Display.getDefault().getThread()) : FPRenderingMessages.getString("CALLED_ON_NON_DISPATCH_THREAD"); //$NON-NLS-1$ + fEditBuffer.clear(); + Rendering.this.redrawPanes(); + } + + @Override + public void writeEditBuffer() + { + assert Thread.currentThread().equals(Display.getDefault().getThread()) : FPRenderingMessages.getString("CALLED_ON_NON_DISPATCH_THREAD"); //$NON-NLS-1$ + + Set keySet = fEditBuffer.keySet(); + Iterator iterator = keySet.iterator(); + + while (iterator.hasNext()) + { + BigInteger address = iterator.next(); + FPMemoryByte[] bytes = fEditBuffer.get(address); + + byte byteValue[] = new byte[bytes.length]; + + for (int index = 0; index < bytes.length; index++) + byteValue[index] = bytes[index].getValue(); + + try + { + IMemoryBlockExtension block = getMemoryBlock(); + BigInteger offset = address.subtract(block.getBigBaseAddress()); + block.setValue(offset, byteValue); + } + catch (Exception e) + { + MemoryViewUtil.openError(FPRenderingMessages.getString("FAILURE_WRITE_MEMORY"), "", e); //$NON-NLS-1$ //$NON-NLS-2$ + logError(FPRenderingMessages.getString("FAILURE_WRITE_MEMORY"), e); //$NON-NLS-1$ + } + } + + clearEditBuffer(); + } + + @Override + public void setEditedValue(BigInteger address, FPMemoryByte[] bytes) + { + assert Thread.currentThread().equals(Display.getDefault().getThread()) : FPRenderingMessages.getString("CALLED_ON_NON_DISPATCH_THREAD"); //$NON-NLS-1$ + fEditBuffer.put(address, bytes); + Rendering.this.redrawPanes(); + } + } + + public void setVisibleAddressBar(boolean visible) + { + fAddressBarControl.setVisible(visible); + if (visible) + { + String selectedStr = "0x" + getCaretAddress().toString(16); //$NON-NLS-1$ + Text text = fAddressBar.getExpressionWidget(); + text.setText(selectedStr); + text.setSelection(0, text.getCharCount()); + fAddressBar.getExpressionWidget().setFocus(); + } + + layout(true); + layoutPanes(); + } + + public void setDirty(boolean needRefresh) + { + fCacheDirty = needRefresh; + } + + public boolean isDirty() + { + return fCacheDirty; + } + + @Override + public void dispose() + { + DebugPlugin.getDefault().removeDebugEventListener(this); + if (fViewportCache != null) + { + fViewportCache.dispose(); + fViewportCache = null; + } + super.dispose(); + } + + class Selection implements FPIMemorySelection + { + private BigInteger fStartHigh = null; + private BigInteger fStartLow = null; + + private BigInteger fEndHigh = null; + private BigInteger fEndLow = null; + + @Override + public void clear() + { + fEndHigh = fEndLow = fStartHigh = fStartLow = null; + redrawPanes(); + } + + @Override + public boolean hasSelection() + { + return fStartHigh != null && fStartLow != null && fEndHigh != null && fEndLow != null; + } + + @Override + public boolean isSelected(BigInteger address) + { + // Do we have valid start and end addresses? + + if (getEnd() == null || getStart() == null) return false; + + // If end is greater than start + + if (getEnd().compareTo(getStart()) >= 0) + { + // If address is greater-than-or-equal-to start and less then end, return true + if (address.compareTo(getStart()) >= 0 && address.compareTo(getEnd()) < 0) return true; + } + + // If start is greater than end + + else if (getStart().compareTo(getEnd()) >= 0) + { + // If address is greater-than-or-equal-to zero and less than start, return true + if (address.compareTo(getEnd()) >= 0 && address.compareTo(getStart()) < 0) return true; + } + + return false; + } + + // Set selection start + + @Override + public void setStart(BigInteger high, BigInteger low) + { + if (high == null && low == null) + { + if (fStartHigh != null && fStartLow != null) + { + fStartHigh = null; + fStartLow = null; + redrawPanes(); + } + + return; + } + + boolean changed = false; + + if (fStartHigh == null || !high.equals(fStartHigh)) + { + fStartHigh = high; + changed = true; + } + + if (fStartLow == null || !low.equals(fStartLow)) + { + fStartLow = low; + changed = true; + } + + if (changed) redrawPanes(); + } + + // Set selection end + + @Override + public void setEnd(BigInteger high, BigInteger low) + { + if (high == null && low == null) + { + if (fEndHigh != null && fEndLow != null) + { + fEndHigh = null; + fEndLow = null; + redrawPanes(); + } + + return; + } + + boolean changed = false; + + if (fEndHigh == null || !high.equals(fEndHigh)) + { + fEndHigh = high; + changed = true; + } + + if (fEndLow == null || !low.equals(fEndLow)) + { + fEndLow = low; + changed = true; + } + + if (changed) redrawPanes(); + } + + @Override + public BigInteger getHigh() + { + if (!hasSelection()) return null; + return getStart().max(getEnd()); + } + + @Override + public BigInteger getLow() + { + if (!hasSelection()) return null; + return getStart().min(getEnd()); + } + + @Override + public BigInteger getStart() + { + // If there is no start, return null + if (fStartHigh == null) return null; + + // If there is no end, return the high address of the start + if (fEndHigh == null) return fStartHigh; + + // If Start High/Low equal End High/Low, return a low start and high end + if (fStartHigh.equals(fEndHigh) && fStartLow.equals(fEndLow)) return fStartLow; + + BigInteger differenceEndToStartHigh = fEndHigh.subtract(fStartHigh).abs(); + BigInteger differenceEndToStartLow = fEndHigh.subtract(fStartLow).abs(); + + // Return the start high or start low based on which creates a larger selection + if (differenceEndToStartHigh.compareTo(differenceEndToStartLow) > 0) + return fStartHigh; + + return fStartLow; + } + + @Override + public BigInteger getStartLow() + { + return fStartLow; + } + + @Override + public BigInteger getEnd() + { + // If there is no end, return null + if (fEndHigh == null) return null; + + // *** Temporary for debugging *** + + if (fStartHigh == null || fStartLow == null) + { + return null; + } + + // If Start High/Low equal End High/Low, return a low start and high end + if (fStartHigh.equals(fEndHigh) && fStartLow.equals(fEndLow)) return fStartHigh; + + BigInteger differenceStartToEndHigh = fStartHigh.subtract(fEndHigh).abs(); + BigInteger differenceStartToEndLow = fStartHigh.subtract(fEndLow).abs(); + + // Return the start high or start low based on which creates a larger selection + if (differenceStartToEndHigh.compareTo(differenceStartToEndLow) >= 0) + return fEndHigh; + + return fEndLow; + } + } + + public void setPaneVisible(int pane, boolean visible) + { + switch (pane) + { + case PANE_ADDRESS: + fAddressPane.setPaneVisible(visible); + break; + case PANE_DATA: + fDataPane.setPaneVisible(visible); + break; + } + + fireSettingsChanged(); + layoutPanes(); + } + + public boolean getPaneVisible(int pane) + { + switch (pane) + { + case PANE_ADDRESS: + return fAddressPane.isPaneVisible(); + case PANE_DATA: + return fDataPane.isPaneVisible(); + default: + return false; + } + } + + protected void packColumns() + { + int availableWidth = Rendering.this.getSize().x; + + if (fAddressPane.isPaneVisible()) + { + availableWidth -= fAddressPane.computeSize(0, 0).x; + availableWidth -= Rendering.this.getRenderSpacing() * 2; + } + + int combinedWidth = 0; + + if (fDataPane.isPaneVisible()) combinedWidth += fDataPane.getCellWidth(); + + if (getColumnsSetting() == Rendering.COLUMNS_AUTO_SIZE_TO_FIT) + { + if (combinedWidth == 0) + fColumnCount = 0; + else + { + fColumnCount = availableWidth / combinedWidth; + if (fColumnCount == 0) fColumnCount = 1; // Paint one column even if only part can show in view + } + } + else + fColumnCount = getColumnsSetting(); + + try + { + // Update the number of bytes per row; the max/min scroll range and the current thumbnail position. + + fBytesPerRow = getCharsPerColumn() * getColumnCount(); + getVerticalBar().setMinimum(1); + + // scrollbar maximum range is Integer.MAX_VALUE. + + getVerticalBar().setMaximum(getMaxScrollRange().min(BigInteger.valueOf(Integer.MAX_VALUE)).intValue()); + getVerticalBar().setIncrement(1); + getVerticalBar().setPageIncrement(this.getRowCount() - 1); + + // FIXME: conversion of slider to scrollbar + // fScrollBar.setToolTipText(Rendering.this.getAddressString(fViewportAddress)); + + setScrollSelection(); + } + catch (Exception e) + { + // FIXME precautionary + } + + Rendering.this.redraw(); + Rendering.this.redrawPanes(); + } + + public FPAbstractPane[] getRenderingPanes() + { + return new FPAbstractPane[] { fAddressPane, fDataPane }; + } + + public int getCellPadding() + { + return fCellPadding; + } + + protected int getRenderSpacing() + { + return fPaneSpacing; + } + + public void refresh() + { + if (!this.isDisposed()) + { + if (this.isVisible() && getViewportCache() != null) + { + getViewportCache().refresh(); + } + else + { + setDirty(true); + fParent.updateRenderingLabels(); + } + } + } + + protected void archiveDeltas() + { + this.getViewportCache().archiveDeltas(); + } + + public void gotoAddress(BigInteger address) + { + // Ensure that the GoTo address is within the addressable range + + if ((address.compareTo(this.getMemoryBlockStartAddress()) < 0) || (address.compareTo(this.getMemoryBlockEndAddress()) > 0)) + return; + + fViewportAddress = address; + + // Reset the caret and selection state (no caret and no selection) + + fCaretAddress = null; + fSelection = new Selection(); + + redrawPanes(); + } + + public void setViewportStartAddress(BigInteger newAddress) + { + fViewportAddress = newAddress; + } + + public BigInteger getViewportStartAddress() + { + return fViewportAddress; + } + + public BigInteger getViewportEndAddress() + { + return fViewportAddress.add(BigInteger.valueOf(this.getBytesPerRow() * getRowCount() / getAddressableSize())); + } + + public String getAddressString(BigInteger address) + { + StringBuffer addressString = new StringBuffer(address.toString(16).toUpperCase()); + + for (int chars = getAddressBytes() * 2 - addressString.length(); chars > 0; chars--) + addressString.insert(0, '0'); + + addressString.insert(0, "0x"); //$NON-NLS-1$ + + return addressString.toString(); + } + + protected int getAddressBytes() + { + return fParent.getAddressSize(); + } + + public Control getAddressBarControl() + { + return fAddressBarControl; + } + + public int getColumnCount() + { + return fColumnCount; + } + + public int getColumnsSetting() + { + return fColumnsSetting; + } + + protected void setBytesPerRow(int count) + { + fBytesPerRow = count; + } + + protected void setColumnCount(int count) + { + fColumnCount = count; + } + + public void setColumnsSetting(int columns) + { + if (fColumnsSetting != columns) + { + fColumnsSetting = columns; + fireSettingsChanged(); + layoutPanes(); + } + } + + protected void ensureVisible(BigInteger address) + { + BigInteger viewportStart = this.getViewportStartAddress(); + BigInteger viewportEnd = this.getViewportEndAddress(); + + boolean isAddressBeforeViewportStart = address.compareTo(viewportStart) < 0; + boolean isAddressAfterViewportEnd = address.compareTo(viewportEnd) > 0; + + if (isAddressBeforeViewportStart || isAddressAfterViewportEnd) gotoAddress(address); + } + + protected int getRowCount() + { + int rowCount = 0; + Control panes[] = getRenderingPanes(); + for (int i = 0; i < panes.length; i++) + if (panes[i] instanceof FPAbstractPane) + rowCount = Math.max(rowCount, ((FPAbstractPane) panes[i]).getRowCount()); + + return rowCount; + } + + protected int getBytesPerRow() + { + return fBytesPerRow; + } + + protected int getAddressableCellsPerRow() + { + return getBytesPerRow() / getAddressableSize(); + } + + public int getAddressesPerColumn() + { + return this.getCharsPerColumn() / getAddressableSize(); + } + + /** + * @return Set current scroll selection + */ + protected void setScrollSelection() + { + BigInteger selection = getViewportStartAddress().divide(BigInteger.valueOf(getAddressableCellsPerRow())); + + fScrollSelection = rows2scrollbar(selection); + getVerticalBar().setSelection(fScrollSelection); + } + + /** + * compute the maximum scrolling range. + * + * @return number of lines that rendering can display + */ + private BigInteger getMaxScrollRange() + { + BigInteger difference = getMemoryBlockEndAddress().subtract(getMemoryBlockStartAddress()).add(BigInteger.ONE); + BigInteger maxScrollRange = difference.divide(BigInteger.valueOf(getAddressableCellsPerRow())); + if (maxScrollRange.multiply(BigInteger.valueOf(getAddressableCellsPerRow())).compareTo(difference) != 0) + maxScrollRange = maxScrollRange.add(BigInteger.ONE); + + // Support targets with an addressable size greater than 1 + + maxScrollRange = maxScrollRange.divide(BigInteger.valueOf(getAddressableSize())); + return maxScrollRange; + } + + /** + * The scroll range is limited by SWT. Because it can be less than the number + * of rows (of memory) that we need to display, we need an arithmetic mapping. + * + * @return ratio this function returns how many rows a scroll bar unit + * represents. The number will be some fractional value, up to but + * not exceeding the value 1. I.e., when the scroll range exceeds + * the row range, we use a 1:1 mapping. + */ + private final BigDecimal getScrollRatio() + { + BigInteger maxRange = getMaxScrollRange(); + if (maxRange.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) + { + return new BigDecimal(maxRange).divide(BigDecimal.valueOf(Integer.MAX_VALUE), SCROLL_CONVERSION_PRECISION); + } + + return BigDecimal.ONE; + } + + /** + * Convert memory row units to scroll bar units. The scroll range is limited + * by SWT. Because it can be less than the number of rows (of memory) that + * we need to display, we need an arithmetic mapping. + * + * @param rows + * units of memory + * @return scrollbar units + */ + private int rows2scrollbar(BigInteger rows) + { + return new BigDecimal(rows).divide(getScrollRatio(), SCROLL_CONVERSION_PRECISION).intValue(); + } + + /** + * Convert scroll bar units to memory row units. The scroll range is limited + * by SWT. Because it can be less than the number of rows (of memory) that + * we need to display, we need an arithmetic mapping. + * + * @param scrollbarUnits + * scrollbar units + * @return number of rows of memory + */ + BigInteger scrollbar2rows(int scrollbarUnits) + { + return getScrollRatio().multiply(BigDecimal.valueOf(scrollbarUnits), SCROLL_CONVERSION_PRECISION).toBigInteger(); + } + + /** + * @return start address of the memory block + */ + protected BigInteger getMemoryBlockStartAddress() + { + if (fMemoryBlockStartAddress == null) + fMemoryBlockStartAddress = fParent.getMemoryBlockStartAddress(); + if (fMemoryBlockStartAddress == null) + fMemoryBlockStartAddress = BigInteger.ZERO; + + return fMemoryBlockStartAddress; + } + + /** + * @return end address of the memory block + */ + protected BigInteger getMemoryBlockEndAddress() + { + if (fMemoryBlockEndAddress == null) + fMemoryBlockEndAddress = fParent.getMemoryBlockEndAddress(); + + return fMemoryBlockEndAddress; + } + + public FPDataType getFPDataType() + { + return fFPDataType; + } + + public void setFPDataType(FPDataType numberType) + { + if (fFPDataType == numberType) return; + + fFPDataType = numberType; + fireSettingsChanged(); + layoutPanes(); + } + + public int getUpdateMode() + { + return fUpdateMode; + } + + public void setUpdateMode(int fUpdateMode) + { + this.fUpdateMode = fUpdateMode; + } + + protected String getCharacterSet(int mode) + { + switch (mode) + { + case Rendering.TEXT_UTF8: + return "UTF8"; //$NON-NLS-1$ + + case Rendering.TEXT_UTF16: + return "UTF16"; //$NON-NLS-1$ + + case Rendering.TEXT_USASCII: + return "US-ASCII"; //$NON-NLS-1$ + + case Rendering.TEXT_ISO_8859_1: + default: + return "ISO-8859-1"; //$NON-NLS-1$ + } + } + + public int getBytesPerCharacter() + { + return 1; + } + + public boolean isTargetLittleEndian() + { + return fIsTargetLittleEndian; + } + + public void setTargetLittleEndian(boolean littleEndian) + { + if (fIsTargetLittleEndian == littleEndian) return; + + fParent.setTargetMemoryLittleEndian(littleEndian); + fIsTargetLittleEndian = littleEndian; + + Display.getDefault().asyncExec(new Runnable() + { + @Override + public void run() + { + fireSettingsChanged(); + layoutPanes(); + } + }); + } + + public boolean isDisplayLittleEndian() + { + return fIsDisplayLittleEndian; + } + + public void setDisplayLittleEndian(boolean isLittleEndian) + { + if (fIsDisplayLittleEndian == isLittleEndian) return; + fIsDisplayLittleEndian = isLittleEndian; + fireSettingsChanged(); + + Display.getDefault().asyncExec(new Runnable() + { + @Override + public void run() + { + layoutPanes(); + } + }); + } + + public int getCharsPerColumn() + { + return fCharsPerColumn; + } + + public int getDisplayedPrecision() + { + return fDisplayedPrecision; + } + + // Set the number of precision digits that are displayed in the view + + public void setDisplayedPrecision(int displayedPrecision) + { + if (fDisplayedPrecision != displayedPrecision) + { + fDisplayedPrecision = displayedPrecision; + fCharsPerColumn = charsPerColumn(); + fireSettingsChanged(); + layoutPanes(); + } + } + + protected void redrawPane(int paneId) + { + if (!isDisposed() && this.isVisible()) + { + FPAbstractPane pane = null; + + if (paneId == Rendering.PANE_ADDRESS) + { + pane = fAddressPane; + } + else if (paneId == Rendering.PANE_DATA) + { + pane = fDataPane; + } + + if (pane != null && pane.isPaneVisible()) + { + pane.redraw(); + pane.setRowCount(); + if (pane.isFocusControl()) pane.updateTheCaret(); + } + } + + fParent.updateRenderingLabels(); + } + + protected void redrawPanes() + { + if (!isDisposed() && this.isVisible()) + { + if (fAddressPane.isPaneVisible()) + { + fAddressPane.redraw(); + fAddressPane.setRowCount(); + if (fAddressPane.isFocusControl()) fAddressPane.updateTheCaret(); + } + + if (fDataPane.isPaneVisible()) + { + fDataPane.redraw(); + fDataPane.setRowCount(); + if (fDataPane.isFocusControl()) fDataPane.updateTheCaret(); + } + } + + fParent.updateRenderingLabels(); + } + + void layoutPanes() + { + packColumns(); + layout(true); + + redraw(); + redrawPanes(); + } + + void fireSettingsChanged() + { + fAddressPane.settingsChanged(); + fDataPane.settingsChanged(); + } + + protected void copyAddressToClipboard() + { + Clipboard clip = null; + + try + { + clip = new Clipboard(getDisplay()); + + String addressString = "0x" + getCaretAddress().toString(16); //$NON-NLS-1$ + + TextTransfer plainTextTransfer = TextTransfer.getInstance(); + clip.setContents(new Object[] { addressString }, new Transfer[] { plainTextTransfer }); + } + finally + { + if (clip != null) + { + clip.dispose(); + } + } + } + + // Given an array of bytes, the data type and endianness, return a scientific notation string representation + + public String sciNotationString(FPMemoryByte byteArray[], FPDataType fpDataType, boolean isLittleEndian) + { + StringBuffer textString = null; + + // Check the byte array for readability + + for (int index = 0; index < byteArray.length; index++) + if (!byteArray[index].isReadable()) + return FPutilities.fillString(fCharsPerColumn, '?'); + + // Convert the byte array to a floating point value and check to see if it's within the range + // of the data type. If the valid range is exceeded, set string to "-Infinity" or "Infinity". + + ByteOrder byteOrder = isLittleEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN; + + if (fpDataType == FPDataType.FLOAT) + { + float floatValue = ByteBuffer.wrap(FPutilities.memoryBytesToByteArray(byteArray)).order(byteOrder).getFloat(); + floatValue = FPutilities.floatLimitCheck(floatValue); + + if (floatValue == Float.NEGATIVE_INFINITY) + textString = new StringBuffer("-Infinity"); //$NON-NLS-1$ + + if (floatValue == Float.POSITIVE_INFINITY) + textString = new StringBuffer(" Infinity"); //$NON-NLS-1$ + } + + if (fpDataType == FPDataType.DOUBLE) + { + double doubleValue = ByteBuffer.wrap(FPutilities.memoryBytesToByteArray(byteArray)).order(byteOrder).getDouble(); + doubleValue = FPutilities.doubleLimitCheck(doubleValue); + + if (doubleValue == Double.NEGATIVE_INFINITY) + textString = new StringBuffer("-Infinity"); //$NON-NLS-1$ + + if (doubleValue == Double.POSITIVE_INFINITY) + textString = new StringBuffer(" Infinity"); //$NON-NLS-1$ + } + + // If we do not already have a StringBuffer value, Convert the value to + // a string. In any case, pad the string with spaces to the cell width. + + if (textString == null) + textString = new StringBuffer(FPutilities.byteArrayToSciNotation(fpDataType, isLittleEndian, byteArray, fDisplayedPrecision)); + + return (textString.append(FPutilities.fillString(fCharsPerColumn - textString.length(), getPaddingCharacter()))).toString(); + } + + // Convert the floating point edit buffer string to a byte array and update memory + + public void convertAndUpdateCell(BigInteger memoryAddress, String editBuffer) + { + if (editBuffer != null && editBuffer.length() > 0) + { + // Convert the edit buffer string to byte arrays + + byte[] targetByteArray = new byte[getFPDataType().getByteLength()]; + + targetByteArray = FPutilities.floatingStringToByteArray(getFPDataType(), editBuffer, getFPDataType().getBitsize()); + + // If we're in little endian mode, reverse the bytes, which is required + // due to lower-level internal conversion when written to memory. + + if (fIsDisplayLittleEndian) + targetByteArray = FPutilities.reverseByteOrder(targetByteArray); + + FPMemoryByte[] newMemoryBytes = new FPMemoryByte[targetByteArray.length]; + + for (int index = 0; index < targetByteArray.length; index++) + { + newMemoryBytes[index] = new FPMemoryByte(targetByteArray[index]); + newMemoryBytes[index].setBigEndian(!isTargetLittleEndian()); + newMemoryBytes[index].setEdited(true); + newMemoryBytes[index].setChanged(true); + } + + // Apply the change and make it visible in the view + + getViewportCache().setEditedValue(memoryAddress, newMemoryBytes); + getViewportCache().writeEditBuffer(); + redraw(); + } + else + { + // The edit buffer string is null or has a zero length. + + final String errorText = NLS.bind(FPRenderingMessages.getString("FPRendering.ERROR_FPENTRY_POPUP_TEXT"), ""); //$NON-NLS-1$ //$NON-NLS-2$ + + try + { + // Restore the previous value + setEditBuffer(new StringBuffer(fDataPane.bytesToSciNotation(getBytes(fCaretAddress, getFPDataType().getByteLength())))); + } + catch (DebugException e) + { + e.printStackTrace(); + } + + // Put together the pop-up window components and show the user the error + + String statusString = FPRenderingMessages.getString("FPRendering.ERROR_FPENTRY_STATUS"); //$NON-NLS-1$ + Status status = new Status(IStatus.ERROR, FPRenderingPlugin.getUniqueIdentifier(), statusString); + FPutilities.popupMessage(FPRenderingMessages.getString("FPRendering.ERROR_FPENTRY_POPUP_TITLE"), errorText, status); //$NON-NLS-1$ + } + } + + // Getter/setter for Insert Mode state + + public void setInsertMode(boolean insertMode) + { + this.fEditInserMode = insertMode; + } + + public boolean insertMode() + { + return fEditInserMode; + } + + // Getter/setter for cell edit state: true = we're in cell edit mode; false = we're not in cell edit mode + + public boolean isEditingCell() + { + return fCellEditState; + } + + public void setEditingCell(boolean state) + { + this.fCellEditState = state; + } + + // Getter/setter for the address of the cell currently being edited + + public BigInteger getCellEditAddress() + { + return cellEditAddress; + } + + public void setCellEditAddress(BigInteger cellEditAddress) + { + this.cellEditAddress = cellEditAddress; + } + + // Getter/Setter for the memory address of the cell currently being edited + + public BigInteger getMemoryAddress() + { + return memoryAddress; + } + + public void setMemoryAddress(BigInteger memoryAddress) + { + this.memoryAddress = memoryAddress; + } + + // Getter/setter for storing the raw/uninterpreted/not-converted-to-scientific-notation text entry string + + public StringBuffer getEditBuffer() + { + return fEditBuffer; + } + + public void setEditBuffer(StringBuffer cellChars) + { + this.fEditBuffer = cellChars; + } + + // Enter cell-edit mode + + public void startCellEditing(BigInteger cellAddress, BigInteger memoryAddress, String editString) + { + setEditBuffer(new StringBuffer(editString)); + setCellEditAddress(cellAddress); + setMemoryAddress(memoryAddress); + setEditingCell(true); + } + + // Exit cell-edit mode + + public void endCellEditing() + { + setEditingCell(false); + setCellEditAddress(null); + setMemoryAddress(null); + setEditBuffer(null); + + } + + // Floating point number edit mode status-line display: 'true' = display edit mode, 'false' clear edit mode + + public void displayEditModeIndicator(final boolean indicatorON) + { + UIJob job = new UIJob("FP Renderer Edit Indicator") //$NON-NLS-1$ + { + @Override + public IStatus runInUIThread(IProgressMonitor monitor) + { + String statusLineMessage; + IViewPart viewInstance = null; + + if (indicatorON) + { + // Construct the edit mode message + statusLineMessage = NLS.bind(FPRenderingMessages.getString("FPRendering.EDIT_MODE"), //$NON-NLS-1$ + (insertMode() ? FPRenderingMessages.getString("FPRendering.EDIT_MODE_INSERT") : //$NON-NLS-1$ + FPRenderingMessages.getString("FPRendering.EDIT_MODE_OVERWRITE"))); //$NON-NLS-1$ + } + else + { + // 'null' = clear the message + statusLineMessage = null; + } + + // Get the window and page references + + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) return Status.OK_STATUS; + + IWorkbenchPage page = window.getActivePage(); + if (page == null) return Status.OK_STATUS; + + // Update (or clear) the Workbench status line when the Memory and Memory Browser views are in focus + + viewInstance = page.findView("org.eclipse.debug.ui.MemoryView"); // TODO: programmatically retrieve ID //$NON-NLS-1$ + + if (viewInstance != null) + viewInstance.getViewSite().getActionBars().getStatusLineManager().setMessage(statusLineMessage); + + viewInstance = page.findView("org.eclipse.cdt.debug.ui.memory.memorybrowser.MemoryBrowser"); // TODO: programmatically retrieve ID //$NON-NLS-1$ + + if (viewInstance != null) + viewInstance.getViewSite().getActionBars().getStatusLineManager().setMessage(statusLineMessage); + + return Status.OK_STATUS; + } + }; + + job.setSystem(true); + job.schedule(); + } + + // Calculate memory address from the cell address + + public BigInteger cellToMemoryAddress(BigInteger cellAddress) + { + BigInteger vpStart = getViewportStartAddress(); + BigInteger colChars = BigInteger.valueOf(getCharsPerColumn()); + BigInteger dtBytes = BigInteger.valueOf(getFPDataType().getByteLength()); + + return vpStart.add(((cellAddress.subtract(vpStart)).divide(colChars)).multiply(dtBytes)); + } +} diff --git a/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/messages.properties b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/messages.properties new file mode 100644 index 00000000000..eba849c7373 --- /dev/null +++ b/memory/org.eclipse.cdt.debug.ui.memory.floatingpoint/src/org/eclipse/cdt/debug/ui/memory/floatingpoint/messages.properties @@ -0,0 +1,68 @@ +############################################################################### +# Copyright (c) 2009, 2012 Wind River Systems and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### + +FPRendering.ADDRESS=Address +FPRendering.CALLED_ON_NON_DISPATCH_THREAD=Called on non-dispatch thread +FPRendering.COLUMN_COUNT=Columns +FPRendering.COLUMN_COUNT_AUTO=Auto Size to Fill +FPRendering.COLUMN_COUNT_1=1 +FPRendering.COLUMN_COUNT_2=2 +FPRendering.COLUMN_COUNT_4=4 +FPRendering.COLUMN_COUNT_8=8 +FPRendering.COLUMN_COUNT_16=16 +FPRendering.COLUMN_COUNT_32=32 +FPRendering.COLUMN_COUNT_64=64 +FPRendering.COLUMN_COUNT_128=128 +FPRendering.COLUMN_COUNT_CUSTOM=Custom ... +FPRendering.COPY_ADDRESS=Copy Address +FPRendering.DATA=Data +FPRendering.DISPLAYED_PRECISION_4=Four (4) significant digits +FPRendering.DISPLAYED_PRECISION_8=Eight (8) significant digits +FPRendering.DISPLAYED_PRECISION_16=Sixteen (16) significant digits +FPRendering.EDIT_MODE=Editing: {0} +FPRendering.EDIT_MODE_INSERT=Replace existing value +FPRendering.EDIT_MODE_OVERWRITE=Overwrite number (in-place) +FPRendering.ENDIAN=Endian +FPRendering.ENDIAN_BIG=Big +FPRendering.ENDIAN_LITTLE=Little +FPRendering.ERROR_FPENTRY_POPUP_TEXT="{0}" is an invalid floating point number.\rThe previous value has been restored. +FPRendering.ERROR_FPENTRY_POPUP_TITLE=Floating point number error +FPRendering.ERROR_FPENTRY_STATUS=Invalid floating point number +FPRendering.FAILURE_APPEND_SELECTION=Failed to append selection. +FPRendering.FAILURE_COPY_OPERATION=Failed copy operation. +FPRendering.FAILURE_DETERMINE_ADDRESS_SIZE=Failed to determine address size. +FPRendering.FAILURE_DETERMINE_CELL_LOCATION=Failed to determine cell location. +FPRendering.FAILURE_PAINT=Failed to paint. +FPRendering.FAILURE_POSITION_CURSOR=Failed to position cursor. +FPRendering.FAILURE_READ_MEMORY=Failed reading memory. +FPRendering.FAILURE_RETRIEVE_BASE_ADDRESS=Failure in retrieving base address. +FPRendering.FAILURE_RETRIEVE_START_ADDRESS=Failure in retrieving start address. +FPRendering.FAILURE_START_SELECTION=Failed to start selection. +FPRendering.FAILURE_WRITE_MEMORY=Error writing memory. +FPRendering.FLOATING_POINT_32=32-bit Single Precision +FPRendering.FLOATING_POINT_64=64-bit Double Precision +FPRendering.GO_TO_ADDRESS=Go To Address +FPRendering.INFINITY=Infinity +FPRendering.ISO-8859-1=ISO-8859-1 +FPRendering.NUMBER_TYPE=Floating Point Type +FPRendering.NAN=NaN +FPRendering.PANES=Panes +FPRendering.PRECISION=Displayed Precision +FPRendering.REFRESH=Refresh +FPRendering.RENDERING_NAME=Floating Point +FPRendering.RESET_TO_BASE_ADDRESS=Reset To Base Address +FPRendering.UPDATE_ALWAYS=Always +FPRendering.UPDATE_MANUAL=Manual +FPRendering.UPDATE_ON_BREAKPOINT=On Breakpoint +FPRendering.UPDATEMODE=Update Mode +FPRendering.USASCII=US-ASCII +FPRendering.UTF16=UTF-16 +FPRendering.UTF8=UTF-8l \ No newline at end of file diff --git a/memory/org.eclipse.cdt.debug.ui.memory.source-feature/feature.properties b/memory/org.eclipse.cdt.debug.ui.memory.source-feature/feature.properties index b9b90abb371..fe3740d2c43 100644 --- a/memory/org.eclipse.cdt.debug.ui.memory.source-feature/feature.properties +++ b/memory/org.eclipse.cdt.debug.ui.memory.source-feature/feature.properties @@ -24,7 +24,7 @@ providerName=Eclipse CDT updateSiteName=Eclipse CDT update site # "description" property - description of the feature -description=Additional features for debug Memory View - traditional rendering, Find/Replace, Import/Export. Source code. +description=Additional features for debug Memory View - traditional rendering, floating-point rendering, Find/Replace, Import/Export. Source code. # "licenseURL" property - URL of the "Feature License" # do not translate value - just change to point to a locale-specific HTML page diff --git a/memory/org.eclipse.cdt.debug.ui.memory.source-feature/feature.xml b/memory/org.eclipse.cdt.debug.ui.memory.source-feature/feature.xml index e23ed14c442..c64eb902375 100644 --- a/memory/org.eclipse.cdt.debug.ui.memory.source-feature/feature.xml +++ b/memory/org.eclipse.cdt.debug.ui.memory.source-feature/feature.xml @@ -31,6 +31,13 @@ version="0.0.0" unpack="false"/> + +