KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > debug > ui > memory > AbstractTableRendering


1 /*******************************************************************************
2  * Copyright (c) 2004, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.debug.ui.memory;
13
14 import java.math.BigInteger JavaDoc;
15
16 import org.eclipse.core.runtime.CoreException;
17 import org.eclipse.core.runtime.IStatus;
18 import org.eclipse.core.runtime.Status;
19 import org.eclipse.debug.core.DebugException;
20 import org.eclipse.debug.core.model.IMemoryBlock;
21 import org.eclipse.debug.core.model.IMemoryBlockExtension;
22 import org.eclipse.debug.core.model.MemoryByte;
23 import org.eclipse.debug.internal.ui.DebugUIMessages;
24 import org.eclipse.debug.internal.ui.DebugUIPlugin;
25 import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
26 import org.eclipse.debug.internal.ui.memory.IMemoryBlockConnection;
27 import org.eclipse.debug.internal.ui.memory.IPersistableDebugElement;
28 import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
29 import org.eclipse.debug.internal.ui.views.memory.MemoryViewUtil;
30 import org.eclipse.debug.internal.ui.views.memory.renderings.AbstractBaseTableRendering;
31 import org.eclipse.debug.internal.ui.views.memory.renderings.CopyTableRenderingToClipboardAction;
32 import org.eclipse.debug.internal.ui.views.memory.renderings.FormatTableRenderingAction;
33 import org.eclipse.debug.internal.ui.views.memory.renderings.FormatTableRenderingDialog;
34 import org.eclipse.debug.internal.ui.views.memory.renderings.GoToAddressAction;
35 import org.eclipse.debug.internal.ui.views.memory.renderings.PrintTableRenderingAction;
36 import org.eclipse.debug.internal.ui.views.memory.renderings.ReformatAction;
37 import org.eclipse.debug.internal.ui.views.memory.renderings.ResetToBaseAddressAction;
38 import org.eclipse.debug.internal.ui.views.memory.renderings.TableRenderingCellModifier;
39 import org.eclipse.debug.internal.ui.views.memory.renderings.TableRenderingContentInput;
40 import org.eclipse.debug.internal.ui.views.memory.renderings.TableRenderingContentProvider;
41 import org.eclipse.debug.internal.ui.views.memory.renderings.TableRenderingLabelProvider;
42 import org.eclipse.debug.internal.ui.views.memory.renderings.TableRenderingLabelProviderEx;
43 import org.eclipse.debug.internal.ui.views.memory.renderings.TableRenderingLine;
44 import org.eclipse.debug.ui.DebugUITools;
45 import org.eclipse.debug.ui.IDebugUIConstants;
46 import org.eclipse.jface.action.Action;
47 import org.eclipse.jface.action.IMenuListener;
48 import org.eclipse.jface.action.IMenuManager;
49 import org.eclipse.jface.action.Separator;
50 import org.eclipse.jface.preference.IPreferenceStore;
51 import org.eclipse.jface.resource.ImageDescriptor;
52 import org.eclipse.jface.resource.JFaceResources;
53 import org.eclipse.jface.text.Document;
54 import org.eclipse.jface.text.TextViewer;
55 import org.eclipse.jface.util.IPropertyChangeListener;
56 import org.eclipse.jface.util.PropertyChangeEvent;
57 import org.eclipse.jface.viewers.CellEditor;
58 import org.eclipse.jface.viewers.IBasicPropertyConstants;
59 import org.eclipse.jface.viewers.ICellModifier;
60 import org.eclipse.jface.viewers.IColorProvider;
61 import org.eclipse.jface.viewers.IFontProvider;
62 import org.eclipse.jface.viewers.ILabelProvider;
63 import org.eclipse.jface.viewers.TableViewer;
64 import org.eclipse.jface.viewers.TextCellEditor;
65 import org.eclipse.swt.SWT;
66 import org.eclipse.swt.custom.StyledText;
67 import org.eclipse.swt.custom.TableCursor;
68 import org.eclipse.swt.custom.TableEditor;
69 import org.eclipse.swt.events.DisposeEvent;
70 import org.eclipse.swt.events.DisposeListener;
71 import org.eclipse.swt.events.FocusAdapter;
72 import org.eclipse.swt.events.FocusEvent;
73 import org.eclipse.swt.events.KeyAdapter;
74 import org.eclipse.swt.events.KeyEvent;
75 import org.eclipse.swt.events.MouseAdapter;
76 import org.eclipse.swt.events.MouseEvent;
77 import org.eclipse.swt.events.MouseTrackAdapter;
78 import org.eclipse.swt.events.PaintEvent;
79 import org.eclipse.swt.events.PaintListener;
80 import org.eclipse.swt.events.SelectionAdapter;
81 import org.eclipse.swt.events.SelectionEvent;
82 import org.eclipse.swt.events.TraverseEvent;
83 import org.eclipse.swt.events.TraverseListener;
84 import org.eclipse.swt.graphics.Font;
85 import org.eclipse.swt.graphics.Point;
86 import org.eclipse.swt.graphics.Rectangle;
87 import org.eclipse.swt.layout.GridData;
88 import org.eclipse.swt.layout.GridLayout;
89 import org.eclipse.swt.widgets.Composite;
90 import org.eclipse.swt.widgets.Control;
91 import org.eclipse.swt.widgets.Display;
92 import org.eclipse.swt.widgets.Label;
93 import org.eclipse.swt.widgets.ScrollBar;
94 import org.eclipse.swt.widgets.Shell;
95 import org.eclipse.swt.widgets.Table;
96 import org.eclipse.swt.widgets.TableColumn;
97 import org.eclipse.swt.widgets.TableItem;
98 import org.eclipse.swt.widgets.Text;
99 import org.eclipse.ui.IWorkbenchActionConstants;
100 import org.eclipse.ui.PlatformUI;
101 import org.eclipse.ui.dialogs.PropertyDialogAction;
102 import org.eclipse.ui.model.IWorkbenchAdapter;
103 import org.eclipse.ui.part.PageBook;
104
105 /**
106  * Abstract implementation of a table rendering.
107  * <p>
108  * Clients should subclass from this class if they wish to provide a
109  * table rendering.
110  * </p>
111  * <p>
112  *
113  * The label of the rendering is constructed by retrieving the expression from
114  * <code>IMemoryBlockExtension</code>. For IMemoryBlock, the label is constructed
115  * using the memory block's start address.
116  *
117  * This rendering manages the change states of its memory bytes if the memory
118  * block does not opt to manage the change states. For IMemoryBlockExtension, if
119  * the memory block returns false when #supportsChangeManagement() is called, this
120  * rendering will calculate the change state for each byte when its content is updated.
121  * Clients may manages the change states of its memory block by returning true when
122  * #supportsChangeManagement() is called. This will cause this rendering to stop
123  * calculating the change states of the memory block. Instead it would rely on the
124  * attributes returned in the MemoryByte array to determine if a byte has changed.
125  * For IMemoryBlock, this rendering will manage the change states its content.
126  *
127  * When firing change event, be aware of the following:
128  * - whenever a change event is fired, the content provider for Memory View
129  * view checks to see if memory has actually changed.
130  * - If memory has actually changed, a refresh will commence. Changes to the memory block
131  * will be computed and will be shown with the delta icons.
132  * - If memory has not changed, content will not be refreshed. However, previous delta information
133  * will be erased. The screen will be refreshed to show that no memory has been changed. (All
134  * delta icons will be removed.)
135  *
136  * Please note that these APIs will be called multiple times by the Memory View.
137  * To improve performance, debug adapters need to cache the content of its memory block and only
138  * retrieve updated data when necessary.
139  * </p>
140
141  * @since 3.1
142  */

143 public abstract class AbstractTableRendering extends AbstractBaseTableRendering implements IPropertyChangeListener, IResettableMemoryRendering{
144
145     /**
146      * Property identifier for the selected address in a table rendering
147      * This property is used for synchronization between renderings.
148      */

149     public static final String JavaDoc PROPERTY_SELECTED_ADDRESS = "selectedAddress"; //$NON-NLS-1$
150

151     /**
152      * Property identifier for the column size in a table rendering
153      * This property is used for synchronization between renderings.
154      */

155     public static final String JavaDoc PROPERTY_COL_SIZE = "columnSize"; //$NON-NLS-1$
156

157     /**
158      * Property identifier for the top row address in a table rendering.
159      * This property is used for synchronization between renderings.
160      */

161     public static final String JavaDoc PROPERTY_TOP_ADDRESS = "topAddress"; //$NON-NLS-1$
162

163     /**
164      * Property identifier for the row size in a table rendering
165      * This property is used for synchronization between renderings.
166      * @since 3.2
167      */

168     public static final String JavaDoc PROPERTY_ROW_SIZE = "rowSize"; //$NON-NLS-1$
169

170     private static final int BUFFER_THRESHOLD = 1; // threshold value
171
private static final int BUFFER_START = 0; // flag to indicate asking for threshold at buffer start
172
private static final int BUFFER_END = 1; // flat to indicate asking for threshold at buffer end
173

174     private PageBook fPageBook;
175     private TableViewer fTableViewer;
176     private TextViewer fTextViewer;
177     
178     private int fBytePerLine; // number of bytes per line: 16
179
private int fColumnSize; // number of bytes per column: 1,2,4,8
180
private int fAddressableSize;
181     
182     private boolean fIsShowingErrorPage;
183     
184     private TableRenderingContentProvider fContentProvider;
185     private BigInteger JavaDoc fSelectedAddress;
186     private TableRenderingContentInput fContentInput;
187     private TableRenderingCellModifier fCellModifier;
188     private boolean fIsCreated;
189     private CellEditor[] fEditors;
190     private String JavaDoc fLabel;
191     private TableCursor fTableCursor;
192     private boolean fIsDisposed;
193     private TraverseListener fCursorTraverseListener;
194     private KeyAdapter fCursorKeyAdapter;
195     private BigInteger JavaDoc fTopRowAddress;
196     
197     private CopyTableRenderingToClipboardAction fCopyToClipboardAction;
198     private GoToAddressAction fGoToAddressAction;
199     private ResetToBaseAddressAction fResetMemoryBlockAction;
200     private PrintTableRenderingAction fPrintViewTabAction;
201     private ReformatAction fReformatAction;
202     private ToggleAddressColumnAction fToggleAddressColumnAction;
203     private EventHandleLock fEvtHandleLock = new EventHandleLock();
204     private TableEditor fCursorEditor;
205     private FocusAdapter fEditorFocusListener;
206     private MouseAdapter fCursorMouseListener;
207     private KeyAdapter fEditorKeyListener;
208     private SelectionAdapter fCursorSelectionListener;
209     private IWorkbenchAdapter fWorkbenchAdapter;
210     private IMemoryBlockConnection fConnection;
211     
212     private boolean fIsShowAddressColumn = true;
213     private SelectionAdapter fScrollbarSelectionListener;
214
215     private PropertyDialogAction fPropertiesAction;
216     
217     private int fPageSize;
218     private NextPageAction fNextAction;
219     private PrevPageAction fPrevAction;
220
221     private Shell fToolTipShell;
222     private FormatTableRenderingAction fFormatRenderingAction;
223
224     private IMenuListener fMenuListener;
225     
226     private int fPreBuffer;
227     private int fPostBuffer;
228     
229     private class EventHandleLock
230     {
231         Object JavaDoc fOwner;
232         
233         public boolean acquireLock(Object JavaDoc client)
234         {
235             if (fOwner == null)
236             {
237                 fOwner = client;
238                 return true;
239             }
240             return false;
241         }
242         
243         public boolean releaseLock(Object JavaDoc client)
244         {
245             if (fOwner == client)
246             {
247                 fOwner = null;
248                 return true;
249             }
250             return false;
251         }
252         
253         public boolean isLocked()
254         {
255             return (fOwner != null);
256         }
257     }
258     
259     
260     private class ToggleAddressColumnAction extends Action {
261
262         public ToggleAddressColumnAction() {
263             super();
264             PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IDebugUIConstants.PLUGIN_ID
265                     + ".ShowAddressColumnAction_context"); //$NON-NLS-1$
266
updateActionLabel();
267         }
268
269         /*
270          * (non-Javadoc)
271          *
272          * @see org.eclipse.jface.action.IAction#run()
273          */

274         public void run() {
275             fIsShowAddressColumn = !fIsShowAddressColumn;
276             resizeColumnsToPreferredSize();
277             updateActionLabel();
278         }
279
280         /**
281          *
282          */

283         private void updateActionLabel() {
284             if (fIsShowAddressColumn) {
285                 setText(DebugUIMessages.ShowAddressColumnAction_0);
286             } else {
287                 setText(DebugUIMessages.ShowAddressColumnAction_1);
288             }
289         }
290     }
291     
292     
293     private class NextPageAction extends Action
294     {
295         private NextPageAction()
296         {
297             super();
298             setText(DebugUIMessages.AbstractTableRendering_4);
299             PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IDebugUIConstants.PLUGIN_ID + ".NextPageAction_context"); //$NON-NLS-1$
300
}
301
302         public void run() {
303             BigInteger JavaDoc address = fContentInput.getLoadAddress();
304             address = address.add(BigInteger.valueOf(getPageSizeInUnits()));
305             handlePageStartAddressChanged(address);
306         }
307     }
308     
309     private class PrevPageAction extends Action
310     {
311         private PrevPageAction()
312         {
313             super();
314             setText(DebugUIMessages.AbstractTableRendering_6);
315             PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IDebugUIConstants.PLUGIN_ID + ".PrevPageAction_context"); //$NON-NLS-1$
316
}
317
318         public void run() {
319             BigInteger JavaDoc address = fContentInput.getLoadAddress();
320             address = address.subtract(BigInteger.valueOf(getPageSizeInUnits()));
321             handlePageStartAddressChanged(address);
322         }
323     }
324     
325     /**
326      * Constructs a new table rendering of the specified type.
327      *
328      * @param renderingId memory rendering type identifier
329      */

330     public AbstractTableRendering(String JavaDoc renderingId) {
331         super(renderingId);
332     }
333     
334     /* (non-Javadoc)
335      * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
336      */

337     public void propertyChange(PropertyChangeEvent event) {
338         // if memory view table font has changed
339
if (event.getProperty().equals(IInternalDebugUIConstants.FONT_NAME))
340         {
341             if (!fIsDisposed)
342             {
343                 Font memoryViewFont = JFaceResources.getFont(IInternalDebugUIConstants.FONT_NAME);
344                 setFont(memoryViewFont);
345             }
346             return;
347         }
348         
349         if (event.getProperty().equals(IDebugUIConstants.PREF_PADDED_STR) ||
350             event.getProperty().equals(IDebugUIConstants.PREF_MEMORY_HISTORY_KNOWN_COLOR) ||
351             event.getProperty().equals(IDebugUIConstants.PREF_MEMORY_HISTORY_UNKNOWN_COLOR))
352         {
353             if (!fIsDisposed)
354             {
355                 fTableViewer.refresh();
356                 fTableCursor.redraw();
357             }
358             return;
359         }
360         
361         Object JavaDoc evtSrc = event.getSource();
362         
363         if (event.getProperty().equals(IDebugPreferenceConstants.PREF_TABLE_RENDERING_PAGE_SIZE) ||
364             event.getProperty().equals(IDebugPreferenceConstants.PREF_TABLE_RENDERING_PRE_BUFFER_SIZE) ||
365             event.getProperty().equals(IDebugPreferenceConstants.PREF_TABLE_RENDERING_POST_BUFFER_SIZE)) {
366             // always update page size, only refresh if the table is visible
367
getPageSizeFromPreference();
368         }
369         
370         // do not handle event if the rendering is displaying an error
371
if (isDisplayingError())
372             return;
373         
374         // do not handle property change event if the rendering is not visible
375
if (!isVisible())
376             return;
377         
378         if (event.getProperty().equals(IDebugPreferenceConstants.PREF_DYNAMIC_LOAD_MEM)) {
379             handleDyanicLoadChanged();
380             return;
381         }
382         
383         if (event.getProperty().equals(IDebugPreferenceConstants.PREF_TABLE_RENDERING_PAGE_SIZE)) {
384             if (!isDynamicLoad())
385             {
386                 // only refresh if in non-autoload mode
387
refresh();
388             }
389             return;
390         }
391         
392         if (event.getProperty().equals(IDebugPreferenceConstants.PREF_TABLE_RENDERING_PRE_BUFFER_SIZE) ||
393             event.getProperty().equals(IDebugPreferenceConstants.PREF_TABLE_RENDERING_POST_BUFFER_SIZE)) {
394             if (isDynamicLoad())
395             {
396                 // only refresh if in non-autoload mode
397
refresh();
398             }
399             return;
400         }
401         
402         if (evtSrc == this)
403             return;
404         
405         if (!(evtSrc instanceof IMemoryRendering))
406             return;
407         
408         IMemoryRendering rendering = (IMemoryRendering)evtSrc;
409         IMemoryBlock memoryBlock = rendering.getMemoryBlock();
410         
411         // do not handle event from renderings displaying other memory blocks
412
if (memoryBlock != getMemoryBlock())
413             return;
414     
415         String JavaDoc propertyName = event.getProperty();
416         Object JavaDoc value = event.getNewValue();
417         
418         if (propertyName.equals(AbstractTableRendering.PROPERTY_SELECTED_ADDRESS) && value instanceof BigInteger JavaDoc)
419         {
420             selectedAddressChanged((BigInteger JavaDoc)value);
421         }
422         else if (propertyName.equals(AbstractTableRendering.PROPERTY_COL_SIZE) && value instanceof Integer JavaDoc)
423         {
424             columnSizeChanged(((Integer JavaDoc)value).intValue());
425         }
426         else if (propertyName.equals(AbstractTableRendering.PROPERTY_ROW_SIZE) && value instanceof Integer JavaDoc)
427         {
428             rowSizeChanged(((Integer JavaDoc)value).intValue());
429         }
430         else if (propertyName.equals(AbstractTableRendering.PROPERTY_TOP_ADDRESS) && value instanceof BigInteger JavaDoc)
431         {
432             if (needMoreLines())
433             {
434                 if (isDynamicLoad())
435                     reloadTable(getTopVisibleAddress(), false);
436             }
437             topVisibleAddressChanged((BigInteger JavaDoc)value, false);
438         }
439         else if (propertyName.equals(IInternalDebugUIConstants.PROPERTY_PAGE_START_ADDRESS) && value instanceof BigInteger JavaDoc)
440         {
441             handlePageStartAddressChanged((BigInteger JavaDoc)value);
442         }
443     }
444
445     private void handleDyanicLoadChanged() {
446         
447         // if currently in dynamic load mode, update page
448
// start address
449
updateSyncPageStartAddress();
450         
451         updateDynamicLoadProperty();
452         if (isDynamicLoad())
453         {
454             refresh();
455         }
456         else
457         {
458             BigInteger JavaDoc pageStart = (BigInteger JavaDoc)getSynchronizedProperty(IInternalDebugUIConstants.PROPERTY_PAGE_START_ADDRESS);
459             if (pageStart == null)
460                 pageStart = fTopRowAddress;
461             handlePageStartAddressChanged(pageStart);
462         }
463     }
464
465     private void updateDynamicLoadProperty() {
466         
467         boolean value = DebugUIPlugin
468                 .getDefault()
469                 .getPreferenceStore()
470                 .getBoolean(IDebugPreferenceConstants.PREF_DYNAMIC_LOAD_MEM);
471         
472         if (value != isDynamicLoad())
473         {
474             fContentProvider.setDynamicLoad(value);
475         
476             if (!fIsDisposed) {
477                 if (isDynamicLoad()) {
478                     fContentInput.setPostBuffer(20);
479                     fContentInput.setPreBuffer(20);
480                     fContentInput.setNumLines(getNumberOfVisibleLines());
481     
482                 } else {
483                     fContentInput.setPostBuffer(0);
484                     fContentInput.setPreBuffer(0);
485                     fContentInput.setNumLines(fPageSize);
486                 }
487             }
488         }
489     }
490
491     /**
492      * Handle top visible address change event from synchronizer
493      * @param address
494      */

495     private void topVisibleAddressChanged(final BigInteger JavaDoc address, boolean force)
496     {
497         // do not handle event if rendering is not visible
498
// continue to handle event if caller decides to force the rendering
499
// to move to the top visible address even when the rendering
500
// is not visible
501
if (!isVisible() && !force)
502             return;
503         
504         // do not handle event if the base address of the memory
505
// block has changed, wait for debug event to update to
506
// new location
507
if (isBaseAddressChanged())
508             return;
509     
510         if (!address.equals(fTopRowAddress))
511         {
512             fTopRowAddress = address;
513             updateSyncTopAddress();
514             if (getMemoryBlock() instanceof IMemoryBlockExtension)
515             {
516             
517                 handleTopAddressChangedforExtended(address);
518             }
519             else
520             {
521                 handleTopAddressChangedForSimple(address);
522             }
523         }
524     }
525
526     /**
527      * @param address
528      */

529     private void handleTopAddressChangedForSimple(final BigInteger JavaDoc address) {
530         // IMemoryBlock support
531
int index = findAddressIndex(address);
532         Table table = fTableViewer.getTable();
533         if (index >= 0)
534         {
535             setTopIndex(table, index);
536         }
537         
538         if (isAddressVisible(fSelectedAddress))
539             fTableCursor.setVisible(true);
540         else
541             fTableCursor.setVisible(false);
542         
543     }
544
545     /**
546      * @param address
547      */

548     private void handleTopAddressChangedforExtended(final BigInteger JavaDoc address) {
549         
550         Object JavaDoc evtLockClient = new Object JavaDoc();
551         try
552         {
553         if (!fEvtHandleLock.acquireLock(evtLockClient))
554             return;
555         
556         if (!isAddressOutOfRange(address))
557         {
558             Table table = fTableViewer.getTable();
559             int index = findAddressIndex(address);
560             int startThreshold = getBufferThreshold(BUFFER_START);
561             int endThrreshold = getBufferThreshold(BUFFER_END);
562             if (index >= startThreshold && table.getItemCount() - (index+getNumberOfVisibleLines()) >= endThrreshold)
563             {
564                 // update cursor position
565
setTopIndex(table, index);
566             }
567             else
568             {
569                 int numInBuffer = table.getItemCount();
570                 if (index < getBufferThreshold(BUFFER_START))
571                 {
572                     if(isAtTopLimit())
573                     {
574                         setTopIndex(table, index);
575                     }
576                     else
577                     {
578                         if (isDynamicLoad() && getBufferThreshold(BUFFER_START) > 0)
579                             reloadTable(address, false);
580                         else
581                             setTopIndex(table, index);
582                     }
583                 }
584                 else if ((numInBuffer-(index+getNumberOfVisibleLines())) <= getBufferThreshold(BUFFER_END))
585                 {
586                     if (!isAtBottomLimit() && isDynamicLoad() && getBufferThreshold(BUFFER_END) > 0)
587                         reloadTable(address, false);
588                     else
589                         setTopIndex(table, index);
590                 }
591             }
592         }
593         else
594         {
595             // approaching limit, reload table
596
reloadTable(address, false);
597         }
598         
599         if (isAddressVisible(fSelectedAddress))
600             fTableCursor.setVisible(true);
601         else
602             fTableCursor.setVisible(false);
603         }
604         finally
605         {
606             fEvtHandleLock.releaseLock(evtLockClient);
607         }
608     }
609     
610     /**
611      * @param value
612      */

613     private void selectedAddressChanged(BigInteger JavaDoc value) {
614         
615         // do not handle event if the base address of the memory
616
// block has changed, wait for debug event to update to
617
// new location
618
if (isBaseAddressChanged())
619             return;
620         
621         try {
622             // do not handle event if the event is out of range and the
623
// rendering is in non-dynamic-load mode, otherwise, will
624
// cause rendering to continue to scroll when it shouldn't
625
if (isDynamicLoad())
626                 goToAddress(value);
627             else if (!isAddressOutOfRange(value))
628                 goToAddress(value);
629         } catch (DebugException e) {
630             // do nothing
631
}
632     }
633     
634     private void handlePageStartAddressChanged(BigInteger JavaDoc address)
635     {
636         // do not handle if in dynamic mode
637
if (isDynamicLoad())
638             return;
639         
640         if (fContentInput == null)
641             return;
642         
643         if (!(getMemoryBlock() instanceof IMemoryBlockExtension))
644             return;
645         
646         // do not handle event if the base address of the memory
647
// block has changed, wait for debug event to update to
648
// new location
649
if (isBaseAddressChanged())
650             return;
651         
652         if(fContentProvider.getBufferTopAddress().equals(address))
653             return;
654     
655         BigInteger JavaDoc start = fContentInput.getStartAddress();
656         BigInteger JavaDoc end = fContentInput.getEndAddress();
657         
658         // smaller than start address, load at start address
659
if (address.compareTo(start) < 0)
660         {
661             if (isAtTopLimit())
662                 return;
663             
664             address = start;
665         }
666         
667         // bigger than end address, no need to load, already at top
668
if (address.compareTo(end) > 0)
669         {
670             if (isAtBottomLimit())
671                 return;
672             
673             address = end.subtract(BigInteger.valueOf(getPageSizeInUnits()));
674         }
675         
676         fContentInput.setLoadAddress(address);
677         refresh();
678         updateSyncPageStartAddress();
679         setTopIndex(fTableViewer.getTable(), 0);
680         fTopRowAddress = address;
681         updateSyncTopAddress();
682         
683         BigInteger JavaDoc selectedAddress = (BigInteger JavaDoc)getSynchronizedProperty(AbstractTableRendering.PROPERTY_SELECTED_ADDRESS);
684         if (selectedAddress != null)
685         {
686             fSelectedAddress = selectedAddress;
687             if (!isAddressOutOfRange(fSelectedAddress))
688             {
689                 setCursorAtAddress(fSelectedAddress);
690                 fTableCursor.setVisible(true);
691             }
692             else
693             {
694                 fTableCursor.setVisible(false);
695             }
696         }
697     }
698
699     /* (non-Javadoc)
700      * @see org.eclipse.debug.ui.memory.IMemoryRendering#createControl(org.eclipse.swt.widgets.Composite)
701      */

702     public Control createControl(Composite parent) {
703         
704         fPageBook = new PageBook(parent, SWT.NONE);
705         createErrorPage(fPageBook);
706         createTableViewer(fPageBook);
707         
708         fTableViewer.getTable().redraw();
709         createToolTip();
710         
711         return fPageBook;
712     }
713
714     /**
715      * Create the table viewer and other support controls
716      * for this rendering.
717      *
718      * @param parent parent composite
719      */

720     private void createTableViewer(Composite parent) {
721         
722         fTableViewer= new TableViewer(parent, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.HIDE_SELECTION | SWT.BORDER);
723         
724         TableRenderingLabelProvider labelProvider;
725         if (hasCustomizedDecorations())
726             labelProvider = new TableRenderingLabelProviderEx(this);
727         else
728             labelProvider = new TableRenderingLabelProvider(this);
729         
730         fTableViewer.setLabelProvider(labelProvider);
731         
732         fContentProvider = new TableRenderingContentProvider();
733         fContentProvider.setDynamicLoad(DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IDebugPreferenceConstants.PREF_DYNAMIC_LOAD_MEM));
734         
735         fTableViewer.setContentProvider(fContentProvider);
736         fContentProvider.setViewer(fTableViewer);
737         
738         ScrollBar scroll = ((Table)fTableViewer.getControl()).getVerticalBar();
739         scroll.setMinimum(-100);
740         scroll.setMaximum(200);
741
742         fTableViewer.getTable().setHeaderVisible(true);
743         fTableViewer.getTable().setLinesVisible(true);
744         
745
746         // set up addressable size and figure out number of bytes required per line
747
fAddressableSize = -1;
748         try {
749             if (getMemoryBlock() instanceof IMemoryBlockExtension)
750                 fAddressableSize = ((IMemoryBlockExtension)getMemoryBlock()).getAddressableSize();
751         } catch (DebugException e1) {
752             // log error and default to 1
753
fAddressableSize = 1;
754             displayError(e1);
755             return;
756             
757         }
758         if (getAddressableSize() < 1)
759             fAddressableSize = 1;
760         
761 // set up initial format
762
setupInitialFormat();
763         
764 // set up selected address
765
setupSelectedAddress();
766         
767         // figure out top visible address
768
BigInteger JavaDoc topVisibleAddress = getInitialTopVisibleAddress();
769         
770         getPageSizeFromPreference();
771         
772         
773         if (isDynamicLoad())
774         {
775             int numLines = getNumberOfVisibleLines();
776             if (numLines <= 0)
777             {
778                 // add listener to reload when we know the number of lines to load
779
fTableViewer.getTable().addPaintListener(new PaintListener() {
780                     public void paintControl(PaintEvent e) {
781                         fTableViewer.getTable().removePaintListener(this);
782                         fContentInput.setNumLines(getNumberOfVisibleLines());
783                         reloadTable(fContentInput.getLoadAddress(), false);
784                         resizeColumnsToPreferredSize();
785                         setCursorAtAddress(fSelectedAddress);
786                         fTableCursor.setVisible(true);
787                     }});
788             }
789             fContentInput = new TableRenderingContentInput(this, fPreBuffer, fPostBuffer, topVisibleAddress, numLines, false, null);
790         }
791         else
792         {
793             BigInteger JavaDoc addressToLoad = topVisibleAddress;
794             
795             // check synchronization service to see if we need to sync with another rendering
796
Object JavaDoc obj = getSynchronizedProperty(IInternalDebugUIConstants.PROPERTY_PAGE_START_ADDRESS);
797             if (obj != null && obj instanceof BigInteger JavaDoc)
798             {
799                 addressToLoad = (BigInteger JavaDoc)obj;
800             }
801             fContentInput = new TableRenderingContentInput(this, 0, 0, addressToLoad, fPageSize, false, null);
802         }
803         
804         fTableViewer.setInput(fContentInput);
805         
806         // set up cell modifier
807
fCellModifier = new TableRenderingCellModifier(this);
808         fTableViewer.setCellModifier(fCellModifier);
809         
810         // SET UP FONT
811
// set to a non-proportional font
812
fTableViewer.getTable().setFont(JFaceResources.getFont(IInternalDebugUIConstants.FONT_NAME));
813         if (!(getMemoryBlock() instanceof IMemoryBlockExtension))
814         {
815             // If not extended memory block, do not create any buffer
816
// no scrolling
817
fContentInput.setPreBuffer(0);
818             fContentInput.setPostBuffer(0);
819         }
820         
821         // set up table cursor
822
createCursor(fTableViewer.getTable(), fSelectedAddress);
823         fTableViewer.getTable().addMouseListener(new MouseAdapter() {
824             public void mouseDown(MouseEvent e) {
825                 handleTableMouseEvent(e);
826             }});
827         
828         // create pop up menu for the rendering
829
createActions();
830         createPopupMenu(fTableViewer.getControl());
831         createPopupMenu(fTableCursor);
832         
833         fMenuListener = new IMenuListener() {
834                     public void menuAboutToShow(IMenuManager manager) {
835                         fillContextMenu(manager);
836                         manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
837                     }};
838         getPopupMenuManager().addMenuListener(fMenuListener);
839         
840         // now the rendering is successfully created
841
fIsCreated = true;
842
843         //synchronize
844
addRenderingToSyncService();
845         synchronize();
846         
847         fTopRowAddress = getTopVisibleAddress();
848         // Need to resize column after content is filled in
849
// Pack function does not work unless content is not filled in
850
// since the table is not able to compute the preferred size.
851
resizeColumnsToPreferredSize();
852         try {
853             if (getMemoryBlock() instanceof IMemoryBlockExtension)
854             {
855                 if(((IMemoryBlockExtension)getMemoryBlock()).getBigBaseAddress() == null)
856                 {
857                     DebugException e = new DebugException(DebugUIPlugin.newErrorStatus(DebugUIMessages.AbstractTableRendering_1, null));
858                     displayError(e);
859                 }
860             }
861         } catch (DebugException e1) {
862             displayError(e1);
863         }
864
865         // add font change listener and update font when the font has been changed
866
JFaceResources.getFontRegistry().addListener(this);
867         fScrollbarSelectionListener = new SelectionAdapter() {
868
869             public void widgetSelected(SelectionEvent event) {
870                 handleScrollBarSelection();
871                 
872             }};
873         scroll.addSelectionListener(fScrollbarSelectionListener);
874         DebugUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
875     }
876     
877     private boolean validateInitialFormat()
878     {
879         int rowSize = getDefaultRowSize();
880         int columnSize = getDefaultColumnSize();
881         
882         if (rowSize < columnSize || rowSize % columnSize != 0 || rowSize == 0 || columnSize == 0)
883         {
884             return false;
885         }
886         return true;
887     }
888
889     private BigInteger JavaDoc getInitialTopVisibleAddress() {
890         BigInteger JavaDoc topVisibleAddress = (BigInteger JavaDoc) getSynchronizedProperty(AbstractTableRendering.PROPERTY_TOP_ADDRESS);
891         if (topVisibleAddress == null)
892         {
893             if (getMemoryBlock() instanceof IMemoryBlockExtension)
894             {
895                 try {
896                     topVisibleAddress = ((IMemoryBlockExtension)getMemoryBlock()).getBigBaseAddress();
897                 } catch (DebugException e1) {
898                     topVisibleAddress = new BigInteger JavaDoc("0"); //$NON-NLS-1$
899
}
900             }
901             else
902             {
903                 topVisibleAddress = BigInteger.valueOf(getMemoryBlock().getStartAddress());
904             }
905         }
906         return topVisibleAddress;
907     }
908
909     private void setupSelectedAddress() {
910         // figure out selected address
911
BigInteger JavaDoc selectedAddress = (BigInteger JavaDoc) getSynchronizedProperty(AbstractTableRendering.PROPERTY_SELECTED_ADDRESS);
912         if (selectedAddress == null)
913         {
914             if (getMemoryBlock() instanceof IMemoryBlockExtension) {
915                 try {
916                     selectedAddress = ((IMemoryBlockExtension) getMemoryBlock())
917                             .getBigBaseAddress();
918                 } catch (DebugException e1) {
919                     selectedAddress = new BigInteger JavaDoc("0"); //$NON-NLS-1$
920
}
921                 if (selectedAddress == null) {
922                     selectedAddress = new BigInteger JavaDoc("0"); //$NON-NLS-1$
923
}
924
925             } else {
926                 long address = getMemoryBlock().getStartAddress();
927                 selectedAddress = BigInteger.valueOf(address);
928             }
929         }
930         setSelectedAddress(selectedAddress);
931     }
932
933     private void setupInitialFormat() {
934         
935         boolean validated = validateInitialFormat();
936         
937         if (!validated)
938         {
939             // pop up dialog to ask user for default values
940
StringBuffer JavaDoc msgBuffer = new StringBuffer JavaDoc(DebugUIMessages.AbstractTableRendering_20);
941             msgBuffer.append(" "); //$NON-NLS-1$
942
msgBuffer.append(this.getLabel());
943             msgBuffer.append("\n\n"); //$NON-NLS-1$
944
msgBuffer.append(DebugUIMessages.AbstractTableRendering_16);
945             msgBuffer.append("\n"); //$NON-NLS-1$
946
msgBuffer.append(DebugUIMessages.AbstractTableRendering_18);
947             msgBuffer.append("\n\n"); //$NON-NLS-1$
948

949             int bytePerLine = fBytePerLine;
950             int columnSize = fColumnSize;
951             
952             // initialize this value to populate the dialog properly
953
fBytePerLine = getDefaultRowSize() / getAddressableSize();
954             fColumnSize = getDefaultColumnSize() / getAddressableSize();
955
956             FormatTableRenderingDialog dialog = new FormatTableRenderingDialog(this, DebugUIPlugin.getShell());
957             dialog.openError(msgBuffer.toString());
958             
959             // restore to original value before formatting
960
fBytePerLine = bytePerLine;
961             fColumnSize = columnSize;
962             
963             bytePerLine = dialog.getRowSize() * getAddressableSize();
964             columnSize = dialog.getColumnSize() * getAddressableSize();
965             
966             format(bytePerLine, columnSize);
967         }
968         else
969         {
970             // Row size is stored as number of addressable units in preference store
971
int bytePerLine = getDefaultRowSize();
972             // column size is now stored as number of addressable units
973
int columnSize = getDefaultColumnSize();
974             
975             // format memory block with specified "bytesPerLine" and "columnSize"
976
boolean ok = format(bytePerLine, columnSize);
977             
978             if (!ok)
979             {
980                 // this is to ensure that the rest of the rendering can be created
981
// and we can recover from a format error
982
format(bytePerLine, bytePerLine);
983             }
984         }
985     }
986
987     private int getDefaultColumnSize() {
988         
989         // default to global preference store
990
IPreferenceStore prefStore = DebugUITools.getPreferenceStore();
991         int columnSize = prefStore.getInt(IDebugPreferenceConstants.PREF_COLUMN_SIZE);
992         // actual column size is number of addressable units * size of the addressable unit
993
columnSize = columnSize * getAddressableSize();
994         
995         // check synchronized column size
996
Integer JavaDoc colSize = (Integer JavaDoc)getSynchronizedProperty(AbstractTableRendering.PROPERTY_COL_SIZE);
997         if (colSize != null)
998         {
999             // column size is stored as actual number of bytes in synchronizer
1000
int syncColSize = colSize.intValue();
1001            if (syncColSize > 0)
1002            {
1003                columnSize = syncColSize;
1004            }
1005        }
1006        else
1007        {
1008            IPersistableDebugElement elmt = (IPersistableDebugElement)getMemoryBlock().getAdapter(IPersistableDebugElement.class);
1009            int defaultColSize = -1;
1010            
1011            if (elmt != null)
1012            {
1013                if (elmt.supportsProperty(this, IDebugPreferenceConstants.PREF_COL_SIZE_BY_MODEL))
1014                    defaultColSize = getDefaultFromPersistableElement(IDebugPreferenceConstants.PREF_COL_SIZE_BY_MODEL);
1015            }
1016            
1017            if (defaultColSize <= 0)
1018            {
1019                // if not provided, get default by model
1020
defaultColSize = getDefaultColumnSizeByModel(getMemoryBlock().getModelIdentifier());
1021            }
1022            
1023            if (defaultColSize > 0)
1024                columnSize = defaultColSize * getAddressableSize();
1025        }
1026        return columnSize;
1027    }
1028
1029    private int getDefaultRowSize() {
1030        
1031        int rowSize = DebugUITools.getPreferenceStore().getInt(IDebugPreferenceConstants.PREF_ROW_SIZE);
1032        int bytePerLine = rowSize * getAddressableSize();
1033        
1034        // check synchronized row size
1035
Integer JavaDoc size = (Integer JavaDoc)getSynchronizedProperty(AbstractTableRendering.PROPERTY_ROW_SIZE);
1036        if (size != null)
1037        {
1038            // row size is stored as actual number of bytes in synchronizer
1039
int syncRowSize = size.intValue();
1040            if (syncRowSize > 0)
1041            {
1042                bytePerLine = syncRowSize;
1043            }
1044        }
1045        else
1046        {
1047            int defaultRowSize = -1;
1048            IPersistableDebugElement elmt = (IPersistableDebugElement)getMemoryBlock().getAdapter(IPersistableDebugElement.class);
1049            if (elmt != null)
1050            {
1051                if (elmt.supportsProperty(this, IDebugPreferenceConstants.PREF_ROW_SIZE_BY_MODEL))
1052                {
1053                    defaultRowSize = getDefaultFromPersistableElement(IDebugPreferenceConstants.PREF_ROW_SIZE_BY_MODEL);
1054                    return defaultRowSize * getAddressableSize();
1055                }
1056            }
1057            
1058            if (defaultRowSize <= 0)
1059                // no synchronized property, ask preference store by id
1060
defaultRowSize = getDefaultRowSizeByModel(getMemoryBlock().getModelIdentifier());
1061            
1062            if (defaultRowSize > 0)
1063                bytePerLine = defaultRowSize * getAddressableSize();
1064        }
1065        return bytePerLine;
1066    }
1067
1068    private int getDefaultFromPersistableElement(String JavaDoc propertyId) {
1069        int defaultValue = -1;
1070        IPersistableDebugElement elmt = (IPersistableDebugElement)getMemoryBlock().getAdapter(IPersistableDebugElement.class);
1071        if (elmt != null)
1072        {
1073            try {
1074                Object JavaDoc valueMB = elmt.getProperty(this, propertyId);
1075                if (valueMB != null && !(valueMB instanceof Integer JavaDoc))
1076                {
1077                    IStatus status = DebugUIPlugin.newErrorStatus("Model returned invalid type on " + propertyId, null); //$NON-NLS-1$
1078
DebugUIPlugin.log(status);
1079                }
1080                
1081                if (valueMB != null)
1082                {
1083                    Integer JavaDoc value = (Integer JavaDoc)valueMB;
1084                    defaultValue = value.intValue();
1085                }
1086            } catch (CoreException e) {
1087                DebugUIPlugin.log(e);
1088            }
1089        }
1090        return defaultValue;
1091    }
1092    
1093    private void getPageSizeFromPreference()
1094    {
1095        fPageSize = DebugUIPlugin.getDefault().getPreferenceStore().getInt(IDebugPreferenceConstants.PREF_TABLE_RENDERING_PAGE_SIZE);
1096        fPreBuffer = DebugUIPlugin.getDefault().getPreferenceStore().getInt(IDebugPreferenceConstants.PREF_TABLE_RENDERING_PRE_BUFFER_SIZE);
1097        fPostBuffer = DebugUIPlugin.getDefault().getPreferenceStore().getInt(IDebugPreferenceConstants.PREF_TABLE_RENDERING_POST_BUFFER_SIZE);
1098    }
1099    
1100    private void createCursor(Table table, BigInteger JavaDoc address)
1101    {
1102        fTableCursor = new TableCursor(table, SWT.NONE);
1103        Display display = fTableCursor.getDisplay();
1104        
1105        // set up cursor color
1106
fTableCursor.setBackground(display.getSystemColor(SWT.COLOR_LIST_SELECTION));
1107        fTableCursor.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
1108        
1109        fTableCursor.setFont(JFaceResources.getFont(IInternalDebugUIConstants.FONT_NAME));
1110        fTableCursor.setVisible(true);
1111        
1112        fCursorKeyAdapter = new KeyAdapter() {
1113            public void keyPressed(KeyEvent e)
1114             {
1115                handleCursorKeyPressed(e);
1116             }
1117        };
1118        fTableCursor.addKeyListener(fCursorKeyAdapter);
1119        
1120        fCursorTraverseListener = new TraverseListener() {
1121            public void keyTraversed(TraverseEvent e) {
1122                handleCursorTraverseEvt(e);
1123            }};
1124                    
1125        fTableCursor.addTraverseListener(fCursorTraverseListener);
1126        
1127        fCursorMouseListener = new MouseAdapter() {
1128            public void mouseDown(MouseEvent e) {
1129                handleCursorMouseEvent(e);
1130            }};
1131        fTableCursor.addMouseListener(fCursorMouseListener);
1132        
1133        // cursor may be disposed before disposed is called
1134
// remove listeners whenever the cursor is disposed
1135
fTableCursor.addDisposeListener(new DisposeListener() {
1136            public void widgetDisposed(DisposeEvent e) {
1137                if (fTableCursor == null)
1138                    return;
1139                fTableCursor.removeTraverseListener(fCursorTraverseListener);
1140                fTableCursor.removeKeyListener(fCursorKeyAdapter);
1141                fTableCursor.removeMouseListener(fCursorMouseListener);
1142                fTableCursor.removeSelectionListener(fCursorSelectionListener);
1143            }});
1144        
1145        fCursorSelectionListener = new SelectionAdapter() {
1146                    public void widgetSelected(SelectionEvent e) {
1147                        
1148                        if (!fEvtHandleLock.acquireLock(this))
1149                            return;
1150    
1151                        handleCursorMoved();
1152                        
1153                        fEvtHandleLock.releaseLock(this);
1154
1155                    }
1156                };
1157        fTableCursor.addSelectionListener(fCursorSelectionListener);
1158        
1159        
1160        setCursorAtAddress(address);
1161        
1162        fCursorEditor = new TableEditor (fTableViewer.getTable());
1163    }
1164    
1165    private void handleCursorTraverseEvt(TraverseEvent e){
1166        
1167        if (fTableCursor.getRow() == null)
1168            return;
1169        
1170        Table table = (Table)fTableCursor.getParent();
1171        int row = table.indexOf(fTableCursor.getRow());
1172        int col = fTableCursor.getColumn();
1173        if (col == getNumCol() && e.keyCode == SWT.ARROW_RIGHT)
1174        {
1175            if (row + 1>= table.getItemCount())
1176            {
1177                return;
1178            }
1179            
1180            row = row +1;
1181            col = 0;
1182            fTableCursor.setSelection(row, col);
1183        }
1184        if (col <= 1 && e.keyCode == SWT.ARROW_LEFT)
1185        {
1186            if (row-1 < 0)
1187            {
1188                return;
1189            }
1190            
1191            row = row - 1;
1192            col = getNumCol()+1;
1193            fTableCursor.setSelection(row, col);
1194        }
1195        
1196        Object JavaDoc evtLockClient = new Object JavaDoc();
1197        if (!fEvtHandleLock.acquireLock(evtLockClient))
1198            return;
1199        
1200        handleCursorMoved();
1201        
1202        fEvtHandleLock.releaseLock(evtLockClient);
1203
1204    }
1205    
1206    /**
1207     * Update selected address.
1208     * Load more memory if required.
1209     */

1210    private void handleCursorMoved()
1211    {
1212        if (fIsDisposed)
1213            return;
1214        
1215        BigInteger JavaDoc selectedAddress = getSelectedAddressFromCursor(fTableCursor);
1216        
1217        // when the cursor is moved, the selected address is changed
1218
if (selectedAddress != null && !selectedAddress.equals(fSelectedAddress))
1219        {
1220            setSelectedAddress(selectedAddress);
1221            updateSyncSelectedAddress();
1222        }
1223        
1224        // now check to see if the cursor is approaching buffer limit
1225
TableItem item = fTableCursor.getRow();
1226        if (item == null)
1227            return;
1228        
1229        if (getMemoryBlock() instanceof IMemoryBlockExtension)
1230        {
1231            int row = fTableViewer.getTable().indexOf(item);
1232            
1233            if (row < getBufferThreshold(BUFFER_START))
1234            {
1235                if (!isAtTopLimit() && getBufferThreshold(BUFFER_START) > 0)
1236                {
1237                    if (isDynamicLoad())
1238                    {
1239                        refresh();
1240                        setCursorAtAddress(fSelectedAddress);
1241                    }
1242                }
1243            }
1244            else if (row >= fTableViewer.getTable().getItemCount() - getBufferThreshold(BUFFER_END))
1245            {
1246                if (!isAtBottomLimit() && getBufferThreshold(BUFFER_END) > 0)
1247                {
1248                    if (isDynamicLoad())
1249                    {
1250                        refresh();
1251                        setCursorAtAddress(fSelectedAddress);
1252                    }
1253                }
1254            }
1255        }
1256        
1257        // if the cursor has moved, the top index of the table may change
1258
// just update the synchronization service
1259
BigInteger JavaDoc address = getTopVisibleAddress();
1260        if (!address.equals(fTopRowAddress))
1261        {
1262            fTopRowAddress = address;
1263            updateSyncTopAddress();
1264        }
1265    }
1266    
1267    private void handleCursorKeyPressed(KeyEvent event)
1268    {
1269        // allow edit if user hits return
1270
if (event.character == '\r' && event.getSource() instanceof TableCursor)
1271        {
1272            activateCellEditor(null);
1273            return;
1274        }
1275        
1276        if (MemoryViewUtil.isValidEditEvent(event.keyCode))
1277        {
1278            // activate edit as soon as user types something at the cursor
1279
if (event.getSource() instanceof TableCursor)
1280            {
1281                String JavaDoc initialValue = String.valueOf(event.character);
1282                activateCellEditor(initialValue);
1283                return;
1284            }
1285        }
1286    }
1287    
1288    /**
1289     * Calculate selected address based on cursor's current position
1290     * @param cursor
1291     * @return the selected address
1292     */

1293    private BigInteger JavaDoc getSelectedAddressFromCursor(TableCursor cursor)
1294    {
1295        TableItem row = cursor.getRow();
1296        int col = cursor.getColumn();
1297        
1298        return getAddressFromTableItem(row, col);
1299    }
1300
1301    private BigInteger JavaDoc getAddressFromTableItem(TableItem row, int col) {
1302        if (row == null)
1303            return null;
1304        
1305        // get row address
1306
String JavaDoc temp = ((TableRenderingLine)row.getData()).getAddress();
1307        BigInteger JavaDoc rowAddress = new BigInteger JavaDoc(temp, 16);
1308        
1309        int offset;
1310        if (col > 0)
1311        {
1312            // get address offset
1313
int addressableUnit = getAddressableUnitPerColumn();
1314            offset = (col-1) * addressableUnit;
1315        }
1316        else
1317        {
1318            offset = 0;
1319        }
1320        
1321        return rowAddress.add(BigInteger.valueOf(offset));
1322    }
1323    
1324    
1325    /**
1326     * Sets the cursor at the specified address
1327     * @param address
1328     * @return true if successful, false otherwise
1329     */

1330    private boolean setCursorAtAddress(BigInteger JavaDoc address)
1331    {
1332        if (fContentProvider.getBufferTopAddress() == null)
1333            return false;
1334        
1335        // selected address is out of range, simply return false
1336
if (address.compareTo(fContentProvider.getBufferTopAddress()) < 0)
1337            return false;
1338        
1339        // calculate selected row address
1340
int addressableUnit = getAddressableUnitPerLine();
1341        int numOfRows = address.subtract(fContentProvider.getBufferTopAddress()).intValue()/addressableUnit;
1342        BigInteger JavaDoc rowAddress = fContentProvider.getBufferTopAddress().add(BigInteger.valueOf(numOfRows * addressableUnit));
1343
1344        // try to find the row of the selected address
1345
int row = findAddressIndex(address);
1346            
1347        if (row == -1)
1348        {
1349            return false;
1350        }
1351        
1352        // calculate offset to the row address
1353
BigInteger JavaDoc offset = address.subtract(rowAddress);
1354        
1355        // locate column
1356
int colAddressableUnit = getAddressableUnitPerColumn();
1357        int col = ((offset.intValue()/colAddressableUnit)+1);
1358        
1359        if (col == 0)
1360            col = 1;
1361        
1362        fTableCursor.setSelection(row, col);
1363        
1364        return true;
1365    }
1366    
1367    
1368    /**
1369     * Format view tab based on the bytes per line and column.
1370     *
1371     * @param bytesPerLine - number of bytes per line, possible values: (1 / 2 / 4 / 8 / 16) * addressableSize
1372     * @param columnSize - number of bytes per column, possible values: (1 / 2 / 4 / 8 / 16) * addressableSize
1373     * @return true if format is successful, false, otherwise
1374     */

1375    public boolean format(int bytesPerLine, int columnSize)
1376    {
1377        
1378        // selected address gets changed as the cursor is moved
1379
// during the reformat.
1380
// Back up the address and restore it later.
1381
BigInteger JavaDoc selectedAddress = fSelectedAddress;
1382        
1383        // bytes per cell must be divisible to bytesPerLine
1384
if (bytesPerLine % columnSize != 0)
1385        {
1386            return false;
1387        }
1388        
1389        if (bytesPerLine < columnSize)
1390        {
1391            return false;
1392        }
1393        
1394        // do not format if the view tab is already in that format
1395
if(fBytePerLine == bytesPerLine && fColumnSize == columnSize){
1396            return false;
1397        }
1398        
1399        fBytePerLine = bytesPerLine;
1400        fColumnSize = columnSize;
1401        
1402        Object JavaDoc evtLockClient = new Object JavaDoc();
1403        if (!fEvtHandleLock.acquireLock(evtLockClient))
1404            return false;
1405        
1406        // if the tab is already created and is being reformatted
1407
if (fIsCreated)
1408        {
1409            if (fTableViewer == null)
1410                return false;
1411            
1412            if (fTableViewer.getTable() == null)
1413                return false;
1414            
1415            // clean up old columns
1416
TableColumn[] oldColumns = fTableViewer.getTable().getColumns();
1417            
1418            for (int i=0; i<oldColumns.length; i++)
1419            {
1420                oldColumns[i].dispose();
1421            }
1422            
1423            // clean up old cell editors
1424
CellEditor[] oldCellEditors = fTableViewer.getCellEditors();
1425            
1426            for (int i=0; i<oldCellEditors.length; i++)
1427            {
1428                oldCellEditors[i].dispose();
1429            }
1430        }
1431        
1432        TableColumn column0 = new TableColumn(fTableViewer.getTable(),SWT.LEFT,0);
1433        column0.setText(DebugUIMessages.AbstractTableRendering_2);
1434        
1435        // create new byte columns
1436
TableColumn [] byteColumns = new TableColumn[bytesPerLine/columnSize];
1437        
1438        String JavaDoc[] columnLabels = new String JavaDoc[0];
1439        IMemoryBlockTablePresentation presentation = getTablePresentationAdapter();
1440        if (presentation != null)
1441        {
1442            columnLabels = presentation.getColumnLabels(getMemoryBlock(), bytesPerLine, getNumCol());
1443        }
1444        
1445        // check that column labels are not null
1446
if (columnLabels == null)
1447            columnLabels = new String JavaDoc[0];
1448        
1449        for (int i=0;i<byteColumns.length; i++)
1450        {
1451            TableColumn column = new TableColumn(fTableViewer.getTable(), SWT.LEFT, i+1);
1452            
1453            // if the number of column labels returned is correct
1454
// use supplied column labels
1455
if (columnLabels.length == byteColumns.length)
1456            {
1457                column.setText(columnLabels[i]);
1458            }
1459            else
1460            {
1461                // otherwise, use default
1462
int addressableUnit = columnSize/getAddressableSize();
1463                if (getAddressableUnitPerColumn() >= 4)
1464                {
1465                    column.setText(Integer.toHexString(i*addressableUnit).toUpperCase() +
1466                        " - " + Integer.toHexString(i*addressableUnit+addressableUnit-1).toUpperCase()); //$NON-NLS-1$
1467
}
1468                else
1469                {
1470                    column.setText(Integer.toHexString(i*addressableUnit).toUpperCase());
1471                }
1472            }
1473        }
1474        
1475        //Empty column for cursor navigation
1476
TableColumn emptyCol = new TableColumn(fTableViewer.getTable(),SWT.LEFT,byteColumns.length+1);
1477        emptyCol.setText(" "); //$NON-NLS-1$
1478
emptyCol.setWidth(1);
1479        emptyCol.setResizable(false);
1480
1481        // +2 to include properties for address and navigation column
1482
String JavaDoc[] columnProperties = new String JavaDoc[byteColumns.length+2];
1483        columnProperties[0] = TableRenderingLine.P_ADDRESS;
1484        
1485        int addressableUnit = columnSize / getAddressableSize();
1486
1487        // use column beginning offset to the row address as properties
1488
for (int i=1; i<columnProperties.length-1; i++)
1489        {
1490            // column properties are stored as number of addressable units from the
1491
// the line address
1492
columnProperties[i] = Integer.toHexString((i-1)*addressableUnit);
1493        }
1494        
1495        // Empty column for cursor navigation
1496
columnProperties[columnProperties.length-1] = " "; //$NON-NLS-1$
1497

1498        fTableViewer.setColumnProperties(columnProperties);
1499        
1500        
1501        Table table = fTableViewer.getTable();
1502        fEditors = new CellEditor[table.getColumnCount()];
1503        for (int i=0; i<fEditors.length; i++)
1504        {
1505            fEditors[i] = new TextCellEditor(table);
1506        }
1507        
1508        // create and set cell editors
1509
fTableViewer.setCellEditors(fEditors);
1510        
1511        if (fIsCreated)
1512        {
1513            fTableViewer.refresh();
1514        }
1515        
1516        resizeColumnsToPreferredSize();
1517        updateSyncRowSize();
1518        updateSyncColSize();
1519        
1520        if (fIsCreated)
1521        {
1522            // for Linux GTK, this must happen after table viewer is refreshed
1523
int i = findAddressIndex(fTopRowAddress);
1524            
1525            if (i >= 0)
1526                setTopIndex(fTableViewer.getTable(), i);
1527            
1528            if (isAddressVisible(selectedAddress))
1529                // after refresh, make sure the cursor is at the correct position
1530
setCursorAtAddress(selectedAddress);
1531        }
1532        
1533        fEvtHandleLock.releaseLock(evtLockClient);
1534        
1535        return true;
1536    }
1537    
1538    /**
1539     * Create the error page for this rendering.
1540     * The error page is used to report any error resulted from
1541     * getting memory from a memory block.
1542     * @param parent
1543     */

1544    private void createErrorPage(Composite parent)
1545    {
1546        if (fTextViewer == null)
1547        {
1548            fTextViewer = new TextViewer(parent, SWT.WRAP);
1549            fTextViewer.setDocument(new Document());
1550            StyledText styleText = fTextViewer.getTextWidget();
1551            styleText.setEditable(false);
1552            styleText.setEnabled(false);
1553        }
1554    }
1555    
1556    /**
1557     * Displays the content of the table viewer.
1558     */

1559    public void displayTable()
1560    {
1561        fIsShowingErrorPage = false;
1562        fPageBook.showPage(fTableViewer.getControl());
1563    }
1564    
1565    /**
1566     * Displays an error message for the given exception.
1567     *
1568     * @param e exception to display
1569     */

1570    public void displayError(DebugException e)
1571    {
1572        StyledText styleText = null;
1573        fIsShowingErrorPage = true;
1574
1575        styleText = fTextViewer.getTextWidget();
1576        
1577        if (styleText != null)
1578            styleText.setText(DebugUIMessages.AbstractTableRendering_3 + e.getMessage());
1579        fPageBook.showPage(fTextViewer.getControl());
1580        
1581        // clear content cache if we need to display error
1582
fContentProvider.clearContentCache();
1583    }
1584    
1585    /**
1586     * Returns whether the error page is displayed.
1587     *
1588     * @return whether the error page is displayed
1589     */

1590    public boolean isDisplayingError()
1591    {
1592        return fIsShowingErrorPage;
1593    }
1594    
1595    /* (non-Javadoc)
1596     * @see org.eclipse.debug.ui.memory.IMemoryRendering#getControl()
1597     */

1598    public Control getControl() {
1599        return fPageBook;
1600    }
1601    
1602    /**
1603     * Returns the addressable size of this rendering's memory block in bytes.
1604     *
1605     * @return the addressable size of this rendering's memory block in bytes
1606     */

1607    public int getAddressableSize() {
1608        return fAddressableSize;
1609    }
1610    
1611    private Object JavaDoc getSynchronizedProperty(String JavaDoc propertyId)
1612    {
1613        IMemoryRenderingSynchronizationService syncService = getMemoryRenderingContainer().getMemoryRenderingSite().getSynchronizationService();
1614        
1615        if (syncService == null)
1616            return null;
1617        
1618        return syncService.getProperty(getMemoryBlock(), propertyId);
1619    }
1620    
1621    /**
1622     * This method estimates the number of visible lines in the rendering
1623     * table.
1624     * @return estimated number of visible lines in the table
1625     */

1626    private int getNumberOfVisibleLines()
1627    {
1628        if(fTableViewer == null)
1629            return -1;
1630        
1631        Table table = fTableViewer.getTable();
1632        int height = fTableViewer.getTable().getSize().y;
1633        
1634        // when table is not yet created, height is zero
1635
if (height == 0)
1636        {
1637            // make use of the table viewer to estimate table size
1638
height = fTableViewer.getTable().getParent().getSize().y;
1639        }
1640        
1641        int numberOfLines = doGetNumberOfVisibleLines(table, height);
1642        
1643        if (numberOfLines <= 0)
1644        {
1645            return 0;
1646        }
1647    
1648        return numberOfLines;
1649    }
1650
1651    /**
1652     * @param table
1653     * @param height
1654     * @return
1655     */

1656    private int doGetNumberOfVisibleLines(Table table, int height) {
1657        // height of border
1658
int border = fTableViewer.getTable().getHeaderHeight();
1659        
1660        // height of scroll bar
1661
int scroll = fTableViewer.getTable().getHorizontalBar().getSize().y;
1662
1663        // height of table is table's area minus border and scroll bar height
1664
height = height-border-scroll;
1665
1666        // calculate number of visible lines
1667
int lineHeight = getMinTableItemHeight(table);
1668        
1669        int numberOfLines = height/lineHeight;
1670        return numberOfLines;
1671    }
1672    
1673    private static void setTopIndex(Table table, int index)
1674    {
1675        table.setTopIndex(index);
1676    }
1677
1678    private void addRenderingToSyncService()
1679    {
1680        IMemoryRenderingSynchronizationService syncService = getMemoryRenderingContainer().getMemoryRenderingSite().getSynchronizationService();
1681        
1682        if (syncService == null)
1683            return;
1684        
1685        syncService.addPropertyChangeListener(this, null);
1686    
1687        // we could be in a format error even though the error is not yet displayed
1688
// do not update sync property in this case
1689
if (!isDisplayingError())
1690        {
1691            if (syncService.getSynchronizationProvider() == null)
1692                syncService.setSynchronizationProvider(this);
1693            
1694            // check if there is already synchronization info available
1695
Object JavaDoc selectedAddress =getSynchronizedProperty( AbstractTableRendering.PROPERTY_SELECTED_ADDRESS);
1696            Object JavaDoc rowSize = getSynchronizedProperty(AbstractTableRendering.PROPERTY_ROW_SIZE);
1697            Object JavaDoc colSize =getSynchronizedProperty( AbstractTableRendering.PROPERTY_COL_SIZE);
1698            Object JavaDoc topAddress =getSynchronizedProperty( AbstractTableRendering.PROPERTY_TOP_ADDRESS);
1699            
1700            if (!isDynamicLoad())
1701            {
1702                Object JavaDoc pageStartAddress = getSynchronizedProperty(IInternalDebugUIConstants.PROPERTY_PAGE_START_ADDRESS);
1703                if (pageStartAddress == null)
1704                    updateSyncPageStartAddress();
1705            }
1706            
1707            // if info is available, some other view tab has already been
1708
// created
1709
// do not overwrite info in the synchronizer if that's the case
1710
if (selectedAddress == null) {
1711                updateSyncSelectedAddress();
1712            }
1713            
1714            if (rowSize == null)
1715            {
1716                updateSyncRowSize();
1717            }
1718
1719            if (colSize == null) {
1720                updateSyncColSize();
1721            }
1722            if (topAddress == null) {
1723                updateSyncTopAddress();
1724            }
1725        }
1726    }
1727    
1728    /**
1729     * Get properties from synchronizer and synchronize settings
1730     */

1731    private void synchronize()
1732    {
1733        if (!isDynamicLoad())
1734        {
1735            BigInteger JavaDoc pageStart = (BigInteger JavaDoc)getSynchronizedProperty(IInternalDebugUIConstants.PROPERTY_PAGE_START_ADDRESS);
1736            if (pageStart != null && fContentInput != null && fContentInput.getLoadAddress() != null)
1737            {
1738                if (!fContentInput.getLoadAddress().equals(pageStart))
1739                    handlePageStartAddressChanged(pageStart);
1740            }
1741            else if (pageStart != null)
1742            {
1743                handlePageStartAddressChanged(pageStart);
1744            }
1745        }
1746        
1747        Integer JavaDoc rowSize = (Integer JavaDoc) getSynchronizedProperty(AbstractTableRendering.PROPERTY_ROW_SIZE);
1748        Integer JavaDoc columnSize = (Integer JavaDoc) getSynchronizedProperty(AbstractTableRendering.PROPERTY_COL_SIZE);
1749        BigInteger JavaDoc selectedAddress = (BigInteger JavaDoc)getSynchronizedProperty(AbstractTableRendering.PROPERTY_SELECTED_ADDRESS);
1750        BigInteger JavaDoc topAddress = (BigInteger JavaDoc)getSynchronizedProperty(AbstractTableRendering.PROPERTY_TOP_ADDRESS);
1751        
1752        if (rowSize != null)
1753        {
1754            int rSize = rowSize.intValue();
1755            if (rSize > 0 && rSize != fBytePerLine) {
1756                rowSizeChanged(rSize);
1757            }
1758        }
1759        
1760        if (columnSize != null) {
1761            int colSize = columnSize.intValue();
1762            if (colSize > 0 && colSize != fColumnSize) {
1763                columnSizeChanged(colSize);
1764            }
1765        }
1766        if (topAddress != null) {
1767            if (!topAddress.equals(getTopVisibleAddress())) {
1768                if (selectedAddress != null) {
1769                    if (!fSelectedAddress.equals(selectedAddress)) {
1770                        selectedAddressChanged(selectedAddress);
1771                    }
1772                }
1773                topVisibleAddressChanged(topAddress, false);
1774            }
1775        }
1776        if (selectedAddress != null) {
1777            if (selectedAddress.compareTo(fSelectedAddress) != 0) {
1778                selectedAddressChanged(selectedAddress);
1779            }
1780        }
1781    }
1782    
1783    /**
1784     * Resize column to the preferred size.
1785     */

1786    public void resizeColumnsToPreferredSize() {
1787        // pack columns
1788
Table table = fTableViewer.getTable();
1789        TableColumn[] columns = table.getColumns();
1790        
1791        for (int i=0 ;i<columns.length-1; i++)
1792        {
1793            columns[i].pack();
1794        }
1795        
1796        if (!fIsShowAddressColumn)
1797        {
1798            columns[0].setWidth(0);
1799        }
1800    }
1801    
1802    /**
1803     * update selected address in synchronizer if update is true.
1804     */

1805    private void updateSyncSelectedAddress() {
1806        
1807        if (!fIsCreated)
1808            return;
1809        PropertyChangeEvent event = new PropertyChangeEvent(this, AbstractTableRendering.PROPERTY_SELECTED_ADDRESS, null, fSelectedAddress);
1810        firePropertyChangedEvent(event);
1811    }
1812
1813    /**
1814     * update column size in synchronizer
1815     */

1816    private void updateSyncColSize() {
1817        
1818        if (!fIsCreated)
1819            return;
1820        
1821        PropertyChangeEvent event = new PropertyChangeEvent(this, AbstractTableRendering.PROPERTY_COL_SIZE, null, new Integer JavaDoc(fColumnSize));
1822        firePropertyChangedEvent(event);
1823    }
1824    
1825    /**
1826     * update column size in synchronizer
1827     */

1828    private void updateSyncRowSize() {
1829        
1830        if (!fIsCreated)
1831            return;
1832        
1833        PropertyChangeEvent event = new PropertyChangeEvent(this, AbstractTableRendering.PROPERTY_ROW_SIZE, null, new Integer JavaDoc(fBytePerLine));
1834        firePropertyChangedEvent(event);
1835    }
1836    
1837    /**
1838     * update top visible address in synchronizer
1839     */

1840    private void updateSyncTopAddress() {
1841        
1842        if (!fIsCreated)
1843            return;
1844
1845        PropertyChangeEvent event = new PropertyChangeEvent(this, AbstractTableRendering.PROPERTY_TOP_ADDRESS, null, fTopRowAddress);
1846        firePropertyChangedEvent(event);
1847    }
1848    
1849    private void updateSyncPageStartAddress() {
1850    
1851        if (!fIsCreated)
1852            return;
1853        
1854        if (isBaseAddressChanged())
1855            return;
1856        
1857        BigInteger JavaDoc pageStart;
1858        if (isDynamicLoad())
1859        {
1860            // if dynamic loading, the page address should be the top
1861
// row address
1862
pageStart = fTopRowAddress;
1863        }
1864        else
1865        {
1866            // otherwise, the address is the buffer's start address
1867
pageStart = fContentProvider.getBufferTopAddress();
1868        }
1869        
1870        PropertyChangeEvent event = new PropertyChangeEvent(this, IInternalDebugUIConstants.PROPERTY_PAGE_START_ADDRESS, null, pageStart);
1871        firePropertyChangedEvent(event);
1872    }
1873    
1874    /**
1875     * Fills the context menu for this rendering
1876     *
1877     * @param menu menu to fill
1878     */

1879    protected void fillContextMenu(IMenuManager menu) {
1880    
1881        menu.add(new Separator("topMenu")); //$NON-NLS-1$
1882
menu.add(fResetMemoryBlockAction);
1883        menu.add(fGoToAddressAction);
1884    
1885        menu.add(new Separator());
1886        
1887        menu.add(fFormatRenderingAction);
1888
1889        if (!isDynamicLoad() && getMemoryBlock() instanceof IMemoryBlockExtension)
1890        {
1891            menu.add(new Separator());
1892            menu.add(fPrevAction);
1893            menu.add(fNextAction);
1894        }
1895        
1896        menu.add(new Separator());
1897        menu.add(fReformatAction);
1898        menu.add(fToggleAddressColumnAction);
1899        menu.add(new Separator());
1900        menu.add(fCopyToClipboardAction);
1901        menu.add(fPrintViewTabAction);
1902        if (fPropertiesAction != null)
1903        {
1904            menu.add(new Separator());
1905            menu.add(fPropertiesAction);
1906        }
1907        
1908    }
1909    
1910    /**
1911     * Returns the number of addressable units per row.
1912     *
1913     * @return number of addressable units per row
1914     */

1915    public int getAddressableUnitPerLine() {
1916        return fBytePerLine / getAddressableSize();
1917    }
1918    
1919    /**
1920     * Returns the number of addressable units per column.
1921     *
1922     * @return number of addressable units per column
1923     */

1924    public int getAddressableUnitPerColumn() {
1925        return fColumnSize / getAddressableSize();
1926    }
1927    
1928    /**
1929     * Returns the number of bytes displayed in a single column cell.
1930     *
1931     * @return the number of bytes displayed in a single column cell
1932     */

1933    public int getBytesPerColumn()
1934    {
1935        return fColumnSize;
1936    }
1937
1938    /**
1939     * Returns the number of bytes displayed in a row.
1940     *
1941     * @return the number of bytes displayed in a row
1942     */

1943    public int getBytesPerLine()
1944    {
1945        return fBytePerLine;
1946    }
1947    
1948    /**
1949     * Updates labels of this rendering.
1950     */

1951    public void updateLabels()
1952    {
1953        // update tab labels
1954
updateRenderingLabel(true);
1955        
1956        if (fTableViewer != null)
1957        {
1958            // update column labels
1959
setColumnHeadings();
1960            fTableViewer.refresh();
1961        }
1962    }
1963    
1964
1965    /* Returns the label of this rendering.
1966     *
1967     * @return label of this rendering
1968     */

1969    public String JavaDoc getLabel() {
1970        if (fLabel == null)
1971            fLabel = buildLabel(true);
1972        
1973        return fLabel;
1974    }
1975
1976    
1977    /**
1978     * Updates the label of this rendering, optionally displaying the
1979     * base address of this rendering's memory block.
1980     *
1981     * @param showAddress whether to display the base address of this
1982     * rendering's memory block in this rendering's label
1983     */

1984    protected void updateRenderingLabel(boolean showAddress)
1985    {
1986        fLabel = buildLabel(showAddress);
1987        firePropertyChangedEvent(new PropertyChangeEvent(this, IBasicPropertyConstants.P_TEXT, null, fLabel));
1988    }
1989
1990    private String JavaDoc buildLabel(boolean showAddress) {
1991        String JavaDoc label = ""; //$NON-NLS-1$
1992
if (getMemoryBlock() instanceof IMemoryBlockExtension)
1993        {
1994            label = ((IMemoryBlockExtension)getMemoryBlock()).getExpression();
1995            
1996            if (label.startsWith("&")) //$NON-NLS-1$
1997
label = "&" + label; //$NON-NLS-1$
1998

1999            if (label == null)
2000            {
2001                label = DebugUIMessages.AbstractTableRendering_8;
2002            }
2003            
2004            try {
2005                if (showAddress && ((IMemoryBlockExtension)getMemoryBlock()).getBigBaseAddress() != null)
2006                {
2007                    label += " : 0x"; //$NON-NLS-1$
2008
label += ((IMemoryBlockExtension)getMemoryBlock()).getBigBaseAddress().toString(16).toUpperCase();
2009                }
2010            } catch (DebugException e) {
2011                // do nothing, the label will not show the address
2012
}
2013        }
2014        else
2015        {
2016            long address = getMemoryBlock().getStartAddress();
2017            label = Long.toHexString(address).toUpperCase();
2018        }
2019        
2020        String JavaDoc preName = DebugUITools.getMemoryRenderingManager().getRenderingType(getRenderingId()).getLabel();
2021        
2022        if (preName != null)
2023            label += " <" + preName + ">"; //$NON-NLS-1$ //$NON-NLS-2$
2024

2025        return decorateLabel(label);
2026    }
2027    
2028    private void setColumnHeadings()
2029    {
2030        String JavaDoc[] columnLabels = new String JavaDoc[0];
2031        
2032        IMemoryBlockTablePresentation presentation = getTablePresentationAdapter();
2033        if (presentation != null)
2034        {
2035            columnLabels = presentation.getColumnLabels(getMemoryBlock(), fBytePerLine, getNumCol());
2036        }
2037        
2038        // check that column labels returned are not null
2039
if (columnLabels == null)
2040            columnLabels = new String JavaDoc[0];
2041        
2042        int numByteColumns = fBytePerLine/fColumnSize;
2043        
2044        TableColumn[] columns = fTableViewer.getTable().getColumns();
2045        
2046        int j=0;
2047        for (int i=1; i<columns.length-1; i++)
2048        {
2049            // if the number of column labels returned is correct
2050
// use supplied column labels
2051
if (columnLabels.length == numByteColumns)
2052            {
2053                columns[i].setText(columnLabels[j]);
2054                j++;
2055            }
2056            else
2057            {
2058                // otherwise, use default
2059
if (fColumnSize >= 4)
2060                {
2061                    columns[i].setText(Integer.toHexString(j*fColumnSize).toUpperCase() +
2062                            " - " + Integer.toHexString(j*fColumnSize+fColumnSize-1).toUpperCase()); //$NON-NLS-1$
2063
}
2064                else
2065                {
2066                    columns[i].setText(Integer.toHexString(j*fColumnSize).toUpperCase());
2067                }
2068                j++;
2069            }
2070        }
2071    }
2072    
2073    /**
2074     * Refresh the table viewer with the current top visible address.
2075     * Update labels in the memory rendering.
2076     */

2077    public void refresh()
2078    {
2079        // refresh at start address of this memory block
2080
// address may change if expression is evaluated to a different value
2081
IMemoryBlock mem = getMemoryBlock();
2082        BigInteger JavaDoc address;
2083        
2084        if (mem instanceof IMemoryBlockExtension)
2085        {
2086            try {
2087                address = ((IMemoryBlockExtension)mem).getBigBaseAddress();
2088                if (address == null)
2089                {
2090                    DebugException e = new DebugException(DebugUIPlugin.newErrorStatus(DebugUIMessages.AbstractTableRendering_10, null));
2091                    displayError(e);
2092                    return;
2093                }
2094                updateRenderingLabel(true);
2095                // base address has changed
2096
if (address.compareTo(fContentProvider.getContentBaseAddress()) != 0)
2097                {
2098                    // get to new address
2099
setSelectedAddress(address);
2100                    updateSyncSelectedAddress();
2101                    
2102                    reloadTable(address, true);
2103                    
2104                    if (!isDynamicLoad())
2105                    {
2106                        updateSyncPageStartAddress();
2107                        setTopIndex(fTableViewer.getTable(), 0);
2108                    }
2109                    
2110                    fTopRowAddress = getTopVisibleAddress();
2111                    updateSyncTopAddress();
2112                    
2113                    fContentInput.updateContentBaseAddress();
2114                }
2115                else
2116                {
2117                    // reload at top of table
2118
if (isDynamicLoad())
2119                        address = getTopVisibleAddress();
2120                    else
2121                        address = fContentInput.getLoadAddress();
2122                    reloadTable(address, true);
2123                }
2124            } catch (DebugException e) {
2125                displayError(e);
2126                return;
2127            }
2128        }
2129        else
2130        {
2131            address = BigInteger.valueOf(mem.getStartAddress());
2132            reloadTable(address, true);
2133        }
2134    }
2135    
2136    synchronized private void reloadTable(BigInteger JavaDoc topAddress, boolean updateDelta){
2137        
2138        if (fTableViewer == null)
2139            return;
2140        
2141        try
2142        {
2143            Table table = (Table)fTableViewer.getControl();
2144            
2145            TableRenderingContentInput input;
2146            if (isDynamicLoad())
2147                input = new TableRenderingContentInput(this, fPreBuffer, fPostBuffer, topAddress, getNumberOfVisibleLines(), updateDelta, null);
2148            else
2149                input = new TableRenderingContentInput(this, fContentInput.getPreBuffer(), fContentInput.getPostBuffer(), topAddress, fPageSize, updateDelta, null);
2150            
2151            fContentInput = input;
2152            fTableViewer.setInput(fContentInput);
2153    
2154            if (isDynamicLoad())
2155            {
2156                if (getMemoryBlock() instanceof IMemoryBlockExtension)
2157                {
2158                    int topIdx = findAddressIndex(topAddress);
2159                    
2160                    if (topIdx != -1)
2161                    {
2162                        setTopIndex(table, topIdx);
2163                    }
2164                }
2165                
2166                // cursor needs to be refreshed after reload
2167
if (isAddressVisible(fSelectedAddress))
2168                    setCursorAtAddress(fSelectedAddress);
2169            }
2170            else
2171            {
2172                if (!isAddressOutOfRange(fSelectedAddress))
2173                {
2174                    setCursorAtAddress(fSelectedAddress);
2175                    fTableCursor.setVisible(true);
2176                }
2177                else
2178                {
2179                    fTableCursor.setVisible(false);
2180                }
2181            }
2182        }
2183        finally
2184        {
2185        }
2186    }
2187    
2188    private BigInteger JavaDoc getTopVisibleAddress() {
2189        
2190        if (fTableViewer == null)
2191            return BigInteger.valueOf(0);
2192
2193        Table table = fTableViewer.getTable();
2194        int topIndex = getTopVisibleIndex(table);
2195
2196        if (topIndex < 1) { topIndex = 0; }
2197
2198        if (table.getItemCount() > topIndex)
2199        {
2200            TableRenderingLine topItem = (TableRenderingLine)table.getItem(topIndex).getData();
2201            
2202            String JavaDoc calculatedAddress = null;
2203            if (topItem == null)
2204            {
2205                calculatedAddress = table.getItem(topIndex).getText();
2206            }
2207            else
2208            {
2209                calculatedAddress = topItem.getAddress();
2210            }
2211            
2212            BigInteger JavaDoc bigInt = new BigInteger JavaDoc(calculatedAddress, 16);
2213            return bigInt;
2214        }
2215        return BigInteger.valueOf(0);
2216    }
2217    
2218    private int findAddressIndex(BigInteger JavaDoc address)
2219    {
2220        TableItem items[] = fTableViewer.getTable().getItems();
2221    
2222        for (int i=0; i<items.length; i++){
2223            
2224            // Again, when the table resizes, the table may have a null item
2225
// at then end. This is to handle that.
2226
if (items[i] != null)
2227            {
2228                TableRenderingLine line = (TableRenderingLine)items[i].getData();
2229                BigInteger JavaDoc lineAddress = new BigInteger JavaDoc(line.getAddress(), 16);
2230                int addressableUnit = getAddressableUnitPerLine();
2231                BigInteger JavaDoc endLineAddress = lineAddress.add(BigInteger.valueOf(addressableUnit));
2232                
2233                if (lineAddress.compareTo(address) <= 0 && endLineAddress.compareTo(address) > 0)
2234                {
2235                    return i;
2236                }
2237            }
2238        }
2239        
2240        return -1;
2241    }
2242    
2243    private static int getTopVisibleIndex(Table table)
2244    {
2245        int index = table.getTopIndex();
2246        
2247        TableItem item;
2248        try {
2249            item = table.getItem(index);
2250        } catch (IllegalArgumentException JavaDoc e) {
2251            return 0;
2252        }
2253        int cnt = table.getItemCount();
2254        
2255        while (item.getBounds(0).y < 0)
2256        {
2257            index++;
2258            if (index >= cnt)
2259            {
2260                index--;
2261                break;
2262            }
2263            item = table.getItem(index);
2264        }
2265        
2266        return index;
2267    }
2268    
2269    /**
2270     * Returns this rendering's table viewer.
2271     */

2272    public TableViewer getTableViewer()
2273    {
2274        return fTableViewer;
2275    }
2276    
2277    /* (non-Javadoc)
2278     * @see org.eclipse.debug.ui.memory.IMemoryRendering#dispose()
2279     */

2280    public void dispose() {
2281        try {
2282            // prevent rendering from being disposed again
2283
if (fIsDisposed)
2284                return;
2285            
2286            fIsDisposed = true;
2287            
2288            if (fContentProvider != null)
2289                fContentProvider.dispose();
2290            
2291            ScrollBar scroll = ((Table)fTableViewer.getControl()).getVerticalBar();
2292            if (scroll != null && !scroll.isDisposed())
2293                scroll.removeSelectionListener(fScrollbarSelectionListener);
2294            
2295            if (!fTableCursor.isDisposed())
2296            {
2297                fTableCursor.removeTraverseListener(fCursorTraverseListener);
2298                fTableCursor.removeKeyListener(fCursorKeyAdapter);
2299                fTableCursor.removeMouseListener(fCursorMouseListener);
2300            }
2301            
2302            fCursorEditor.dispose();
2303            
2304            fTextViewer = null;
2305            fTableViewer = null;
2306            fTableCursor = null;
2307            
2308            // clean up cell editors
2309
for (int i=0; i<fEditors.length; i++)
2310            {
2311                fEditors[i].dispose();
2312            }
2313            
2314            // remove font change listener when the view tab is disposed
2315
JFaceResources.getFontRegistry().removeListener(this);
2316            
2317            // remove the view tab from the synchronizer
2318
IMemoryRenderingSynchronizationService syncService = getMemoryRenderingContainer().getMemoryRenderingSite().getSynchronizationService();
2319            if (syncService != null)
2320                syncService.removePropertyChangeListener(this);
2321            
2322            DebugUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
2323            
2324            fToolTipShell.dispose();
2325            
2326            if (getPopupMenuManager() != null)
2327            {
2328                getPopupMenuManager().removeMenuListener(fMenuListener);
2329            }
2330            
2331            super.dispose();
2332
2333        } catch (Exception JavaDoc e) {}
2334    }
2335    
2336    private int getNumCol() {
2337        
2338        int bytesPerLine = getBytesPerLine();
2339        int columnSize = getBytesPerColumn();
2340        
2341        return bytesPerLine/columnSize;
2342    }
2343    
2344    /* (non-Javadoc)
2345     * @see org.eclipse.debug.ui.IMemoryViewTab#setFont(org.eclipse.swt.graphics.Font)
2346     */

2347    private void setFont(Font font)
2348    {
2349        int oldIdx = getTopVisibleIndex(fTableViewer.getTable());
2350        
2351        // BUG in table, if font is changed when table is not starting
2352
// from the top, causes table grid-line to be misaligned.
2353
setTopIndex(fTableViewer.getTable(), 0);
2354        
2355        // set font
2356
fTableViewer.getTable().setFont(font);
2357        fTableCursor.setFont(font);
2358        
2359        setTopIndex(fTableViewer.getTable(), oldIdx);
2360        
2361        resizeColumnsToPreferredSize();
2362        
2363        // update table cursor and force redraw
2364
setCursorAtAddress(fSelectedAddress);
2365    }
2366    
2367    
2368    /**
2369     * Moves the cursor to the specified address.
2370     * Will load more memory if the address is not currently visible.
2371     *
2372     * @param address address to position cursor at
2373     * @throws DebugException if an exception occurs
2374     */

2375    public void goToAddress(BigInteger JavaDoc address) throws DebugException {
2376        Object JavaDoc evtLockClient = new Object JavaDoc();
2377        try
2378        {
2379            if (!fEvtHandleLock.acquireLock(evtLockClient))
2380                return;
2381
2382            // if address is within the range, highlight
2383
if (!isAddressOutOfRange(address))
2384            {
2385                setSelectedAddress(address);
2386                updateSyncSelectedAddress();
2387                setCursorAtAddress(fSelectedAddress);
2388                
2389                // force the cursor to be shown
2390
if (!isAddressVisible(fSelectedAddress))
2391                {
2392                    int i = findAddressIndex(fSelectedAddress);
2393                    fTableViewer.getTable().showItem(fTableViewer.getTable().getItem(i));
2394                }
2395            }
2396            else
2397            {
2398                // if not extended memory block
2399
// do not allow user to go to an address that's out of range
2400
if (!(getMemoryBlock() instanceof IMemoryBlockExtension))
2401                {
2402                    Status stat = new Status(
2403                     IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(),
2404                     DebugException.NOT_SUPPORTED, DebugUIMessages.AbstractTableRendering_11, null
2405                    );
2406                    DebugException e = new DebugException(stat);
2407                    throw e;
2408                }
2409
2410                BigInteger JavaDoc startAdd = fContentInput.getStartAddress();
2411                BigInteger JavaDoc endAdd = fContentInput.getEndAddress();
2412                
2413                if (address.compareTo(startAdd) < 0 ||
2414                    address.compareTo(endAdd) > 0)
2415                {
2416                    Status stat = new Status(
2417                     IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(),
2418                     DebugException.NOT_SUPPORTED, DebugUIMessages.AbstractTableRendering_11, null
2419                    );
2420                    DebugException e = new DebugException(stat);
2421                    throw e;
2422                }
2423                
2424                setSelectedAddress(address);
2425                updateSyncSelectedAddress();
2426                
2427                reloadTable(address, false);
2428                
2429                if (!isDynamicLoad())
2430                {
2431                    updateSyncPageStartAddress();
2432                }
2433                
2434                // if the table is reloaded, the top address is changed in this case
2435
fTopRowAddress = address;
2436                updateSyncTopAddress();
2437                
2438                // set the cursor at the selected address after reload
2439
setCursorAtAddress(address);
2440            }
2441            fTableCursor.setVisible(true);
2442        }
2443        catch (DebugException e)
2444        {
2445            throw e;
2446        }
2447        finally
2448        {
2449            fEvtHandleLock.releaseLock(evtLockClient);
2450        }
2451    }
2452    
2453    /**
2454     * Check if address provided is out of buffered range
2455     * @param address
2456     * @return if address is out of buffered range
2457     */

2458    private boolean isAddressOutOfRange(BigInteger JavaDoc address)
2459    {
2460        return fContentProvider.isAddressOutOfRange(address);
2461    }
2462    
2463    /**
2464     * Check if address is visible
2465     * @param address
2466     * @return if the given address is visible
2467     */

2468    private boolean isAddressVisible(BigInteger JavaDoc address)
2469    {
2470        // if view tab is not yet created
2471
// cursor should always be visible
2472
if (!fIsCreated)
2473            return true;
2474        
2475        BigInteger JavaDoc topVisible = getTopVisibleAddress();
2476        int addressableUnit = getAddressableUnitPerLine();
2477        BigInteger JavaDoc lastVisible = getTopVisibleAddress().add(BigInteger.valueOf((getNumberOfVisibleLines() * addressableUnit) + addressableUnit));
2478        
2479        if (topVisible.compareTo(address) <= 0 && lastVisible.compareTo(address) > 0)
2480        {
2481            return true;
2482        }
2483        return false;
2484    }
2485    
2486    /**
2487     * Create actions for this rendering
2488     */

2489    protected void createActions() {
2490        fCopyToClipboardAction = new CopyTableRenderingToClipboardAction(this, fTableViewer);
2491        fGoToAddressAction = new GoToAddressAction(this);
2492        fResetMemoryBlockAction = new ResetToBaseAddressAction(this);
2493        fPrintViewTabAction = new PrintTableRenderingAction(this, fTableViewer);
2494        
2495        fFormatRenderingAction = new FormatTableRenderingAction(this);
2496        fReformatAction = new ReformatAction(this);
2497        fToggleAddressColumnAction = new ToggleAddressColumnAction();
2498        
2499        IMemoryRenderingSite site = getMemoryRenderingContainer().getMemoryRenderingSite();
2500        if (site.getSite().getSelectionProvider() != null)
2501        {
2502            fPropertiesAction = new PropertyDialogAction(site.getSite(),site.getSite().getSelectionProvider());
2503        }
2504        
2505        fNextAction = new NextPageAction();
2506        fPrevAction = new PrevPageAction();
2507    }
2508    
2509    /**
2510     * Handle scrolling and reload table if necessary
2511     * @param event
2512     */

2513    private synchronized void handleScrollBarSelection()
2514    {
2515        Object JavaDoc evtLockClient = new Object JavaDoc();
2516        try
2517        {
2518            if (fIsDisposed)
2519                return;
2520            
2521            BigInteger JavaDoc address = getTopVisibleAddress();
2522    
2523            if (!fTopRowAddress.equals(address))
2524            {
2525                fTopRowAddress = address;
2526                updateSyncTopAddress();
2527            }
2528            
2529            if (!fEvtHandleLock.acquireLock(evtLockClient))
2530                return;
2531            
2532            if (getMemoryBlock() instanceof IMemoryBlockExtension)
2533            {
2534
2535                if (isDynamicLoad())
2536                {
2537                    if (!isAddressOutOfRange(address))
2538                    {
2539                        Table table = fTableViewer.getTable();
2540                        int numInBuffer = table.getItemCount();
2541                        int index = findAddressIndex(address);
2542                        if (index < getBufferThreshold(BUFFER_START))
2543                        {
2544                            if (isAtTopLimit())
2545                            {
2546                                setTopIndex(table, index);
2547                            }
2548                            else if (getBufferThreshold(BUFFER_START) > 0)
2549                            {
2550                                reloadTable(address, false);
2551                            }
2552                        }
2553                        else if (getBufferThreshold(BUFFER_END) != 0 &&
2554                            (numInBuffer-(index+getNumberOfVisibleLines())) <= getBufferThreshold(BUFFER_END))
2555                        {
2556                            if (!isAtBottomLimit() && getBufferThreshold(BUFFER_END) > 0)
2557                                reloadTable(address, false);
2558                        }
2559                    }
2560                    else
2561                    {
2562                        // approaching limit, reload table
2563
reloadTable(address, false);
2564                    }
2565                }
2566                
2567                if (isAddressVisible(fSelectedAddress))
2568                    fTableCursor.setVisible(true);
2569                else
2570                    fTableCursor.setVisible(false);
2571            }
2572        }
2573        finally
2574        {
2575            fEvtHandleLock.releaseLock(evtLockClient);
2576        }
2577    }
2578    
2579    
2580    private boolean isAtTopLimit()
2581    {
2582        BigInteger JavaDoc startAddress = fContentInput.getStartAddress();
2583        startAddress = MemoryViewUtil.alignToBoundary(startAddress, getAddressableUnitPerLine() );
2584        
2585        BigInteger JavaDoc startBufferAddress = fContentProvider.getBufferTopAddress();
2586        startBufferAddress = MemoryViewUtil.alignToBoundary(startBufferAddress, getAddressableUnitPerLine());
2587        
2588        if (startAddress.compareTo(startBufferAddress) == 0)
2589            return true;
2590        
2591        return false;
2592    }
2593    
2594    private boolean isAtBottomLimit()
2595    {
2596        BigInteger JavaDoc endAddress = fContentInput.getEndAddress();
2597        endAddress = MemoryViewUtil.alignToBoundary(endAddress, getAddressableUnitPerLine());
2598        
2599        BigInteger JavaDoc endBufferAddress = fContentProvider.getBufferEndAddress();
2600        endBufferAddress = MemoryViewUtil.alignToBoundary(endBufferAddress, getAddressableUnitPerLine());
2601        
2602        if (endAddress.compareTo(endBufferAddress) == 0)
2603            return true;
2604        
2605        return false;
2606    }
2607    
2608    private boolean needMoreLines()
2609    {
2610        if (getMemoryBlock() instanceof IMemoryBlockExtension)
2611        {
2612            Table table = fTableViewer.getTable();
2613            TableItem firstItem = table.getItem(0);
2614            TableItem lastItem = table.getItem(table.getItemCount()-1);
2615            
2616            if (firstItem == null || lastItem == null)
2617                return true;
2618            
2619            TableRenderingLine first = (TableRenderingLine)firstItem.getData();
2620            TableRenderingLine last = (TableRenderingLine) lastItem.getData();
2621            
2622            if (first == null ||last == null)
2623            {
2624                // For some reason, the table does not return the correct number
2625
// of table items in table.getItemCount(), causing last to be null.
2626
// This check is to ensure that we don't get a null pointer exception.
2627
return true;
2628            }
2629            
2630            BigInteger JavaDoc startAddress = new BigInteger JavaDoc(first.getAddress(), 16);
2631            BigInteger JavaDoc lastAddress = new BigInteger JavaDoc(last.getAddress(), 16);
2632            int addressableUnit = getAddressableUnitPerLine();
2633            lastAddress = lastAddress.add(BigInteger.valueOf(addressableUnit));
2634            
2635            BigInteger JavaDoc topVisibleAddress = getTopVisibleAddress();
2636            long numVisibleLines = getNumberOfVisibleLines();
2637            long numOfBytes = numVisibleLines * addressableUnit;
2638            
2639            BigInteger JavaDoc lastVisibleAddrss = topVisibleAddress.add(BigInteger.valueOf(numOfBytes));
2640            
2641            // if there are only 3 lines left at the top, refresh
2642
BigInteger JavaDoc numTopLine = topVisibleAddress.subtract(startAddress).divide(BigInteger.valueOf(addressableUnit));
2643            if (numTopLine.compareTo(BigInteger.valueOf(getBufferThreshold(BUFFER_START))) <= 0 && (startAddress.compareTo(BigInteger.valueOf(0)) != 0))
2644            {
2645                if (!isAtTopLimit() && getBufferThreshold(BUFFER_START) > 0)
2646                    return true;
2647            }
2648            
2649            // if there are only 3 lines left at the bottom, refresh
2650
BigInteger JavaDoc numBottomLine = lastAddress.subtract(lastVisibleAddrss).divide(BigInteger.valueOf(addressableUnit));
2651            if (numBottomLine.compareTo(BigInteger.valueOf(getBufferThreshold(BUFFER_END))) <= 0)
2652            {
2653                if (!isAtBottomLimit() && getBufferThreshold(BUFFER_END) > 0)
2654                    return true;
2655            }
2656            
2657            return false;
2658        }
2659        
2660        return false;
2661    }
2662
2663    private void handleTableMouseEvent(MouseEvent e) {
2664        // figure out new cursor position based on here the mouse is pointing
2665
TableItem[] tableItems = fTableViewer.getTable().getItems();
2666        TableItem selectedRow = null;
2667        int colNum = -1;
2668        int numCol = fTableViewer.getColumnProperties().length;
2669        
2670        for (int j=0; j<tableItems.length; j++)
2671        {
2672            TableItem item = tableItems[j];
2673            for (int i=0; i<numCol; i++)
2674            {
2675                Rectangle bound = item.getBounds(i);
2676                if (bound.contains(e.x, e.y))
2677                {
2678                    colNum = i;
2679                    selectedRow = item;
2680                    break;
2681                }
2682            }
2683        }
2684        
2685        // if column position cannot be determined, return
2686
if (colNum < 1)
2687            return;
2688        
2689        // handle user mouse click onto table
2690
// move cursor to new position
2691
if (selectedRow != null)
2692        {
2693            int row = fTableViewer.getTable().indexOf(selectedRow);
2694            fTableCursor.setVisible(true);
2695            fTableCursor.setSelection(row, colNum);
2696            
2697            // manually call this since we don't get an event when
2698
// the table cursor changes selection.
2699
handleCursorMoved();
2700            
2701            fTableCursor.setFocus();
2702        }
2703    }
2704    
2705    /**
2706     * Handle column size changed event from synchronizer
2707     * @param newColumnSize
2708     */

2709    private void columnSizeChanged(final int newColumnSize) {
2710        // ignore event if view tab is disabled
2711
if (!isVisible())
2712            return;
2713
2714        Display.getDefault().asyncExec(new Runnable JavaDoc() {
2715            public void run() {
2716                format(getBytesPerLine(), newColumnSize);
2717            }
2718        });
2719    }
2720    
2721    /**
2722     * @param newRowSize - new row size in number of bytes
2723     */

2724    private void rowSizeChanged(final int newRowSize)
2725    {
2726        // ignore event if view tab is disabled
2727
if (!isVisible())
2728            return;
2729        
2730        int bytesPerLine = newRowSize;
2731        int col = getBytesPerColumn();
2732        if (bytesPerLine < getBytesPerColumn())
2733            col = bytesPerLine;
2734
2735        final int columnSize = col;
2736        final int rowSize = bytesPerLine;
2737        Display.getDefault().asyncExec(new Runnable JavaDoc() {
2738            public void run() {
2739                format(rowSize, columnSize);
2740            }
2741        });
2742    }
2743    
2744    private void handleCursorMouseEvent(MouseEvent e){
2745        if (e.button == 1)
2746        {
2747            int col = fTableCursor.getColumn();
2748            if (col > 0 && col <= (getNumCol()))
2749                activateCellEditor(null);
2750        }
2751    }
2752    
2753    /**
2754     * Activate cell editor and pre-fill it with initial value.
2755     * If initialValue is null, use cell content as initial value
2756     * @param initialValue
2757     */

2758    private void activateCellEditor(String JavaDoc initialValue) {
2759        
2760        int col = fTableCursor.getColumn();
2761        int row = findAddressIndex(fSelectedAddress);
2762        
2763        if (row < 0)
2764            return;
2765        // do not allow user to edit address column
2766
if (col == 0 || col > getNumCol())
2767        {
2768            return;
2769        }
2770        
2771        ICellModifier cellModifier = null;
2772        
2773        if (fTableViewer == null)
2774        {
2775            return;
2776        }
2777        cellModifier = fTableViewer.getCellModifier();
2778        
2779        TableItem tableItem = fTableViewer.getTable().getItem(row);
2780        
2781        Object JavaDoc element = tableItem.getData();
2782        Object JavaDoc property = fTableViewer.getColumnProperties()[col];
2783        Object JavaDoc value = cellModifier.getValue(element, (String JavaDoc)property);
2784        
2785        // The cell modifier canModify function always returns false if the edit action
2786
// is not invoked from here. This is to prevent data to be modified when
2787
// the table cursor loses focus from a cell. By default, data will
2788
// be changed in a table when the cell loses focus. This is to workaround
2789
// this default behavior and only change data when the cell editor
2790
// is activated.
2791
((TableRenderingCellModifier)cellModifier).setEditActionInvoked(true);
2792        boolean canEdit = cellModifier.canModify(element, (String JavaDoc)property);
2793        ((TableRenderingCellModifier)cellModifier).setEditActionInvoked(false);
2794        
2795        if (!canEdit)
2796            return;
2797        
2798        // activate based on current cursor position
2799
TextCellEditor selectedEditor = (TextCellEditor)fTableViewer.getCellEditors()[col];
2800
2801        
2802        if (fTableViewer != null && selectedEditor != null)
2803        {
2804            // The control that will be the editor must be a child of the Table
2805
Text text = (Text)selectedEditor.getControl();
2806            
2807            String JavaDoc cellValue = null;
2808            
2809            if (initialValue != null)
2810            {
2811                cellValue = initialValue;
2812            }
2813            else
2814            {
2815                cellValue = ((String JavaDoc)value);
2816            }
2817            
2818            text.setText(cellValue);
2819    
2820            fCursorEditor.horizontalAlignment = SWT.LEFT;
2821            fCursorEditor.grabHorizontal = true;
2822    
2823            // Open the text editor in selected column of the selected row.
2824
fCursorEditor.setEditor (text, tableItem, col);
2825    
2826            // Assign focus to the text control
2827
selectedEditor.setFocus();
2828            
2829            if (initialValue != null)
2830            {
2831                text.clearSelection();
2832            }
2833            
2834            text.setFont(JFaceResources.getFont(IInternalDebugUIConstants.FONT_NAME));
2835
2836            // add listeners for the text control
2837
addListeners(text);
2838            
2839            // move cursor below text control
2840
fTableCursor.moveBelow(text);
2841        }
2842    }
2843    
2844    /**
2845     * @param text
2846     */

2847    private void addListeners(Text text) {
2848        fEditorFocusListener = new FocusAdapter() {
2849            public void focusLost(FocusEvent e)
2850            {
2851                handleTableEditorFocusLost(e);
2852            }
2853        };
2854        text.addFocusListener(fEditorFocusListener);
2855        
2856        fEditorKeyListener = new KeyAdapter() {
2857            public void keyPressed(KeyEvent e) {
2858                handleKeyEventInEditor(e);
2859            }
2860        };
2861
2862        text.addKeyListener(fEditorKeyListener);
2863    }
2864    
2865    /**
2866     * @param text
2867     */

2868    private void removeListeners(Text text) {
2869        
2870        text.removeFocusListener(fEditorFocusListener);
2871        text.removeKeyListener(fEditorKeyListener);
2872    }
2873    
2874    private void handleTableEditorFocusLost(FocusEvent event)
2875    {
2876        final FocusEvent e = event;
2877
2878        Display.getDefault().syncExec(new Runnable JavaDoc() {
2879
2880            public void run()
2881            {
2882                try
2883                {
2884                    int row = findAddressIndex(fSelectedAddress);
2885                    int col = fTableCursor.getColumn();
2886                    
2887                    Text text = (Text)e.getSource();
2888                    removeListeners(text);
2889
2890                    // get new value
2891
String JavaDoc newValue = text.getText();
2892                    
2893                    // modify memory at fRow and fCol
2894
modifyValue(row, col, newValue);
2895                            
2896                    // show cursor after modification is completed
2897
setCursorAtAddress(fSelectedAddress);
2898                    fTableCursor.moveAbove(text);
2899                    fTableCursor.setVisible(false);
2900                    fTableCursor.setVisible(true);
2901                }
2902                catch (NumberFormatException JavaDoc e1)
2903                {
2904                    MemoryViewUtil.openError(DebugUIMessages.MemoryViewCellModifier_failure_title,
2905                        DebugUIMessages.MemoryViewCellModifier_data_is_invalid, null);
2906                }
2907            }
2908        });
2909    }
2910    
2911    /**
2912     * @param event
2913     */

2914    private void handleKeyEventInEditor(KeyEvent event) {
2915        final KeyEvent e = event;
2916        Display.getDefault().asyncExec(new Runnable JavaDoc()
2917        {
2918            public void run()
2919            {
2920                Text text = (Text)e.getSource();
2921                int row = findAddressIndex(fSelectedAddress);
2922                int col = fTableCursor.getColumn();
2923                
2924                try
2925                {
2926                    switch (e.keyCode)
2927                    {
2928                        case SWT.ARROW_UP :
2929                            
2930                            // move text editor box up one row
2931
if (row-1 < 0)
2932                                return;
2933                        
2934                            // modify value for current cell
2935
modifyValue(row, col, text.getText());
2936                                                    
2937                            row--;
2938
2939                            // update cursor location and selection in table
2940
fTableCursor.setSelection(row, col);
2941                            handleCursorMoved();
2942                            
2943                            // remove listeners when focus is lost
2944
removeListeners(text);
2945                            activateCellEditor(null);
2946                            break;
2947                        case SWT.ARROW_DOWN :
2948                            
2949                            // move text editor box down one row
2950

2951                            if (row+1 >= fTableViewer.getTable().getItemCount())
2952                                return;
2953                            
2954                            // modify value for current cell
2955
modifyValue(row, col, text.getText());
2956                        
2957                            row++;
2958                            
2959                            // update cursor location and selection in table
2960
fTableCursor.setSelection(row, col);
2961                            handleCursorMoved();
2962                                                
2963                            // remove traverse listener when focus is lost
2964
removeListeners(text);
2965                            activateCellEditor(null);
2966                            break;
2967                        case 0:
2968                            
2969                        // if user has entered the max number of characters allowed in a cell, move to next cell
2970
// Extra changes will be used as initial value for the next cell
2971
int numCharsPerByte = getNumCharsPerByte();
2972                            if (numCharsPerByte > 0)
2973                            {
2974                                if (text.getText().length() > getBytesPerColumn()*numCharsPerByte)
2975                                {
2976                                    String JavaDoc newValue = text.getText();
2977                                    text.setText(newValue.substring(0, getBytesPerColumn()*numCharsPerByte));
2978                                    
2979                                    modifyValue(row, col, text.getText());
2980                                    
2981                                    // if cursor is at the end of a line, move to next line
2982
if (col >= getNumCol())
2983                                    {
2984                                        col = 1;
2985                                        row++;
2986                                    }
2987                                    else
2988                                    {
2989                                        // move to next column
2990
row++;
2991                                    }
2992                                    
2993                                    // update cursor position and selected address
2994
fTableCursor.setSelection(row, col);
2995                                    handleCursorMoved();
2996                                    
2997                                    removeListeners(text);
2998                        
2999                                    // activate text editor at next cell
3000
activateCellEditor(newValue.substring(getBytesPerColumn()*numCharsPerByte));
3001                                }
3002                            }
3003                            break;
3004                        case SWT.ESC:
3005
3006                            // if user has pressed escape, do not commit the changes
3007
// that's why "modifyValue" is not called
3008
fTableCursor.setSelection(row, col);
3009                            handleCursorMoved();
3010                    
3011                            removeListeners(text);
3012                            
3013                            // cursor needs to have focus to remove focus from cell editor
3014
fTableCursor.setFocus();
3015                            break;
3016                        default :
3017                            numCharsPerByte = getNumCharsPerByte();
3018                            if (numCharsPerByte > 0)
3019                            {
3020                                if (text.getText().length()> getBytesPerColumn()* numCharsPerByte)
3021                                {
3022                                    String JavaDoc newValue = text.getText();
3023                                    text.setText(newValue.substring(0,getBytesPerColumn()* numCharsPerByte));
3024                                    modifyValue(row, col, text.getText());
3025                                    // if cursor is at the end of a line, move to next line
3026
if (col >= getNumCol())
3027                                    {
3028                                        col = 1;
3029                                        row++;
3030                                    }
3031                                    else
3032                                    {
3033                                        col++;
3034                                    }
3035                                    
3036                                    fTableCursor.setSelection(row, col);
3037                                    handleCursorMoved();
3038                                    
3039                                    removeListeners(text);
3040                                    
3041                                    activateCellEditor(newValue.substring(getBytesPerColumn()*numCharsPerByte));
3042                                }
3043                            }
3044                        break;
3045                    }
3046                }
3047                catch (NumberFormatException JavaDoc e1)
3048                {
3049                    MemoryViewUtil.openError(DebugUIMessages.MemoryViewCellModifier_failure_title,
3050                        DebugUIMessages.MemoryViewCellModifier_data_is_invalid, null);
3051                    
3052                    fTableCursor.setSelection(row, col);
3053                    handleCursorMoved();
3054            
3055                    removeListeners(text);
3056                }
3057            }
3058        });
3059    }
3060
3061    
3062    /**
3063     * Modify value and send new value to debug adapter
3064     * @param row
3065     * @param col
3066     * @param newValue
3067     * @throws NumberFormatException
3068     */

3069    private void modifyValue(int row, int col, String JavaDoc newValue) throws NumberFormatException JavaDoc
3070    {
3071        if (newValue.length() == 0)
3072        {
3073            // do not do anything if user has not entered anything
3074
return;
3075        }
3076        
3077        TableItem tableItem = fTableViewer.getTable().getItem(row);
3078
3079        Object JavaDoc property = fTableViewer.getColumnProperties()[col];
3080        fTableViewer.getCellModifier().modify(tableItem, (String JavaDoc)property, newValue);
3081    }
3082    
3083    /* (non-Javadoc)
3084     * @see org.eclipse.debug.ui.memory.IMemoryRendering#becomesHidden()
3085     */

3086    public void becomesHidden() {
3087        
3088        if (isVisible() == false)
3089        {
3090            // super should always be called
3091
super.becomesHidden();
3092            return;
3093        }
3094
3095        super.becomesHidden();
3096        
3097        if (getMemoryBlock() instanceof IMemoryBlockExtension)
3098        {
3099            updateRenderingLabel(false);
3100        }
3101            
3102        // once the view tab is disabled, all deltas information becomes invalid.
3103
// reset changed information and recompute if data has really changed when
3104
// user revisits the same tab.
3105
fContentProvider.resetDeltas();
3106        
3107    }
3108    
3109    /* (non-Javadoc)
3110     * @see org.eclipse.debug.ui.memory.IMemoryRendering#becomesVisible()
3111     */

3112    public void becomesVisible() {
3113        
3114        // do not do anything if already visible
3115
if (isVisible() == true)
3116        {
3117            // super should always be called
3118
super.becomesVisible();
3119            return;
3120        }
3121        
3122        super.becomesVisible();
3123        
3124        boolean value = DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IDebugPreferenceConstants.PREF_DYNAMIC_LOAD_MEM);
3125        if (value != isDynamicLoad())
3126            // this call will cause a reload
3127
handleDyanicLoadChanged();
3128        else
3129            refresh();
3130        
3131        synchronize();
3132        updateRenderingLabel(true);
3133    }
3134    
3135    /**
3136     * Resets this memory rendering.
3137     * The cursor will be moved to the base address of the memory block.
3138     * The table will be positioned to have the base address
3139     * at the top.
3140     *
3141     * @deprecated use <code>resetRendering</code> to reset this rendering.
3142     */

3143    public void reset()
3144    {
3145        try {
3146            resetToBaseAddress();
3147        } catch (DebugException e) {
3148            MemoryViewUtil.openError(DebugUIMessages.AbstractTableRendering_12, DebugUIMessages.AbstractTableRendering_13, e); //
3149
}
3150    }
3151    
3152    /**
3153     * Reset this rendering to the base address.
3154     * The cursor will be moved to the base address of the memory block.
3155     * The table will be positioned to have the base address
3156     * at the top.
3157     * @throws DebugException
3158     */

3159    private void resetToBaseAddress() throws DebugException
3160    {
3161        BigInteger JavaDoc baseAddress;
3162
3163        if (getMemoryBlock() instanceof IMemoryBlockExtension)
3164        {
3165            baseAddress = ((IMemoryBlockExtension)getMemoryBlock()).getBigBaseAddress();
3166        }
3167        else
3168        {
3169            baseAddress = BigInteger.valueOf(getMemoryBlock().getStartAddress());
3170        }
3171
3172        goToAddress(baseAddress);
3173        topVisibleAddressChanged(baseAddress, true);
3174    }
3175    
3176    /**
3177     * Returns the currently selected address in this rendering.
3178     *
3179     * @return the currently selected address in this rendering
3180     */

3181    public BigInteger JavaDoc getSelectedAddress() {
3182        return fSelectedAddress;
3183    }
3184
3185    /**
3186     * Returns the currently selected content in this rendering as a String.
3187     *
3188     * @return the currently selected content in this rendering
3189     */

3190    public String JavaDoc getSelectedAsString() {
3191
3192        if (isAddressOutOfRange(fSelectedAddress))
3193            return ""; //$NON-NLS-1$
3194

3195        int col = fTableCursor.getColumn();
3196        TableItem rowItem = fTableCursor.getRow();
3197        int row = fTableViewer.getTable().indexOf(rowItem);
3198        
3199        if (col == 0)
3200        {
3201            return rowItem.getText(0);
3202        }
3203        
3204        // check precondition
3205
if (col > getBytesPerLine()/getBytesPerColumn())
3206        {
3207            return ""; //$NON-NLS-1$
3208
}
3209                
3210        TableItem tableItem = getTableViewer().getTable().getItem(row);
3211        
3212        return tableItem.getText(col);
3213    }
3214    
3215    /**
3216     * Returns the currently selected content in this rendering as MemoryByte.
3217     *
3218     * @return the currently selected content in array of MemoryByte.
3219     * Returns an empty array if the selected address is out of buffered range.
3220     */

3221    public MemoryByte[] getSelectedAsBytes()
3222    {
3223        if (isAddressOutOfRange(fSelectedAddress))
3224            return new MemoryByte[0];
3225        
3226        int col = fTableCursor.getColumn();
3227        TableItem rowItem = fTableCursor.getRow();
3228        
3229        // check precondition
3230
if (col == 0 || col > getBytesPerLine()/getBytesPerColumn())
3231        {
3232            return new MemoryByte[0];
3233        }
3234        
3235        Object JavaDoc data = rowItem.getData();
3236        if (data == null || !(data instanceof TableRenderingLine))
3237            return new MemoryByte[0];
3238        
3239        TableRenderingLine line = (TableRenderingLine)data;
3240        int offset = (col-1)*(getAddressableUnitPerColumn()*getAddressableSize());
3241        int end = offset + (getAddressableUnitPerColumn()*getAddressableSize());
3242        
3243        // make a copy of the bytes to ensure that data cannot be changed
3244
// by caller
3245
MemoryByte[] bytes = line.getBytes(offset, end);
3246        MemoryByte[] retBytes = new MemoryByte[bytes.length];
3247        
3248        System.arraycopy(bytes, 0, retBytes, 0, bytes.length);
3249        
3250        return retBytes;
3251    }
3252    
3253    /**
3254     * Returns the number of characters a byte will convert to
3255     * or -1 if unknown.
3256     *
3257     * @return the number of characters a byte will convert to
3258     * or -1 if unknown
3259     */

3260    public int getNumCharsPerByte()
3261    {
3262        return -1;
3263    }
3264    
3265    private int getMinTableItemHeight(Table table){
3266        
3267        // Hack to get around Linux GTK problem.
3268
// On Linux GTK, table items have variable item height as
3269
// carriage returns are actually shown in a cell. Some rows will be
3270
// taller than others. When calculating number of visible lines, we
3271
// need to find the smallest table item height. Otherwise, the rendering
3272
// underestimates the number of visible lines. As a result the rendering
3273
// will not be able to get more memory as needed.
3274
if (MemoryViewUtil.isLinuxGTK())
3275        {
3276            // check each of the items and find the minimum
3277
TableItem[] items = table.getItems();
3278            int minHeight = table.getItemHeight();
3279            for (int i=0; i<items.length; i++)
3280            {
3281                minHeight = Math.min(items[i].getBounds(0).height, minHeight);
3282            }
3283            
3284            return minHeight;
3285                
3286        }
3287        return table.getItemHeight();
3288    }
3289    
3290    /* (non-Javadoc)
3291     * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
3292     */

3293    public Object JavaDoc getAdapter(Class JavaDoc adapter) {
3294        
3295        if (adapter == IColorProvider.class)
3296            return getColorProviderAdapter();
3297        
3298        if (adapter == ILabelProvider.class)
3299            return getLabelProviderAdapter();
3300        
3301        if (adapter == IFontProvider.class)
3302            return getFontProviderAdapter();
3303        
3304        if (adapter == IMemoryBlockTablePresentation.class)
3305            return getTablePresentationAdapter();
3306        
3307        if (adapter == IWorkbenchAdapter.class)
3308        {
3309            // needed workbench adapter to fill the title of property page
3310
if (fWorkbenchAdapter == null) {
3311                fWorkbenchAdapter = new IWorkbenchAdapter() {
3312                    public Object JavaDoc[] getChildren(Object JavaDoc o) {
3313                        return new Object JavaDoc[0];
3314                    }
3315    
3316                    public ImageDescriptor getImageDescriptor(Object JavaDoc object) {
3317                        return null;
3318                    }
3319    
3320                    public String JavaDoc getLabel(Object JavaDoc o) {
3321                        return AbstractTableRendering.this.getLabel();
3322                    }
3323    
3324                    public Object JavaDoc getParent(Object JavaDoc o) {
3325                        return null;
3326                    }
3327                };
3328            }
3329            return fWorkbenchAdapter;
3330        }
3331        
3332        if (adapter == IMemoryBlockConnection.class) {
3333            if (fConnection == null) {
3334                fConnection = new IMemoryBlockConnection() {
3335                    public void update() {
3336                        try {
3337                            fContentProvider.takeContentSnapshot();
3338                            if (getMemoryBlock() instanceof IMemoryBlockExtension)
3339                            {
3340                                BigInteger JavaDoc address = ((IMemoryBlockExtension)getMemoryBlock()).getBigBaseAddress();
3341                                if (address.compareTo(fContentProvider.getContentBaseAddress()) != 0)
3342                                {
3343                                    // get to new address
3344
setSelectedAddress(address);
3345                                    updateSyncSelectedAddress();
3346                                    fTopRowAddress = address;
3347                                    fContentInput.updateContentBaseAddress();
3348                                    fContentInput.setLoadAddress(address);
3349                                }
3350                                fContentProvider.loadContentForExtendedMemoryBlock();
3351                            }
3352                            else
3353                                fContentProvider.loadContentForSimpleMemoryBlock();
3354    
3355                            // update UI asynchronously
3356
Display display = DebugUIPlugin.getDefault().getWorkbench().getDisplay();
3357                            display.asyncExec(new Runnable JavaDoc() {
3358                                public void run() {
3359                                    updateLabels();
3360                                    
3361                                    if (getMemoryBlock() instanceof IMemoryBlockExtension) {
3362                                        int topIdx = findAddressIndex(fTopRowAddress);
3363                                        if (topIdx != -1) {
3364                                            setTopIndex(fTableViewer.getTable(),topIdx);
3365                                        }
3366                                    }
3367                                    
3368                                    // cursor needs to be refreshed after reload
3369
if (isAddressVisible(fSelectedAddress))
3370                                    {
3371                                        setCursorAtAddress(fSelectedAddress);
3372                                        fTableCursor.setVisible(true);
3373                                        fTableCursor.redraw();
3374                                    }
3375                                    else
3376                                    {
3377                                        fTableCursor.setVisible(false);
3378                                    }
3379                                    
3380                                    if (!isDynamicLoad())
3381                                        updateSyncPageStartAddress();
3382                                    
3383                                    updateSyncTopAddress();
3384                                }
3385                            });
3386                        } catch (DebugException e) {
3387                            displayError(e);
3388                        }
3389                    }
3390                };
3391            }
3392            return fConnection;
3393        }
3394        
3395        return super.getAdapter(adapter);
3396    }
3397    
3398    private boolean hasCustomizedDecorations()
3399    {
3400        if (getFontProviderAdapter() == null &&
3401            getColorProviderAdapter() == null &&
3402            getLabelProviderAdapter() == null)
3403            return false;
3404        return true;
3405    }
3406    
3407    private boolean isBaseAddressChanged()
3408    {
3409        try {
3410            IMemoryBlock mb = getMemoryBlock();
3411            if (mb instanceof IMemoryBlockExtension)
3412            {
3413                BigInteger JavaDoc baseAddress = ((IMemoryBlockExtension)mb).getBigBaseAddress();
3414                if (baseAddress != null)
3415                {
3416                    if (!baseAddress.equals(fContentInput.getContentBaseAddress()))
3417                        return true;
3418                }
3419            }
3420        } catch (DebugException e1) {
3421            return false;
3422        }
3423        return false;
3424    }
3425    
3426    /**
3427     * Returns the color provider for this rendering's memory block or
3428     * <code>null</code> if none.
3429     * <p>
3430     * By default a color provider is obtained by asking this rendering's
3431     * memory block for its {@link IColorProvider} adapter. When the color
3432     * provider is queried for color information, it is provided with a
3433     * {@link MemoryRenderingElement} as an argument.
3434     * </p>
3435     * @return the color provider for this rendering's memory block,
3436     * or <code>null</code>
3437     */

3438    protected IColorProvider getColorProviderAdapter()
3439    {
3440        return (IColorProvider)getMemoryBlock().getAdapter(IColorProvider.class);
3441    }
3442    
3443    /**
3444     * Returns the label provider for this rendering's memory block or
3445     * <code>null</code> if none.
3446     * <p>
3447     * By default a label provider is obtained by asking this rendering's
3448     * memory block for its {@link ILabelProvider} adapter. When the label
3449     * provider is queried for label information, it is provided with a
3450     * {@link MemoryRenderingElement} as an argument.
3451     * </p>
3452     * @return the label provider for this rendering's memory block,
3453     * or <code>null</code>
3454     */

3455    protected ILabelProvider getLabelProviderAdapter()
3456    {
3457        return (ILabelProvider)getMemoryBlock().getAdapter(ILabelProvider.class);
3458    }
3459    
3460    /**
3461     * Returns the font provider for this rendering's memory block or
3462     * <code>null</code> if none.
3463     * <p>
3464     * By default a font provider is obtained by asking this rendering's
3465     * memory block for its {@link IFontProvider} adapter. When the font
3466     * provider is queried for font information, it is provided with a
3467     * {@link MemoryRenderingElement} as an argument.
3468     * </p>
3469     * @return the font provider for this rendering's memory block,
3470     * or <code>null</code>
3471     */

3472    protected IFontProvider getFontProviderAdapter()
3473    {
3474        return (IFontProvider)getMemoryBlock().getAdapter(IFontProvider.class);
3475    }
3476    
3477    /**
3478     * Returns the table presentation for this rendering's memory block or
3479     * <code>null</code> if none.
3480     * <p>
3481     * By default a table presentation is obtained by asking this rendering's
3482     * memory block for its {@link IMemoryBlockTablePresentation} adapter.
3483     * </p>
3484     * @return the table presentation for this rendering's memory block,
3485     * or <code>null</code>
3486     */

3487    protected IMemoryBlockTablePresentation getTablePresentationAdapter()
3488    {
3489        return (IMemoryBlockTablePresentation)getMemoryBlock().getAdapter(IMemoryBlockTablePresentation.class);
3490    }
3491    
3492    private boolean isDynamicLoad()
3493    {
3494        return fContentProvider.isDynamicLoad();
3495    }
3496    
3497    private int getPageSizeInUnits()
3498    {
3499        return fPageSize * getAddressableUnitPerLine();
3500    }
3501    
3502    private void setSelectedAddress(BigInteger JavaDoc address)
3503    {
3504        fSelectedAddress = address;
3505    }
3506        
3507    /**
3508     * Setup the viewer so it supports hovers to show the offset of each field
3509     */

3510    private void createToolTip() {
3511        
3512        fToolTipShell = new Shell(DebugUIPlugin.getShell(), SWT.ON_TOP | SWT.RESIZE );
3513        GridLayout gridLayout = new GridLayout();
3514        gridLayout.numColumns = 1;
3515        gridLayout.marginWidth = 2;
3516        gridLayout.marginHeight = 0;
3517        fToolTipShell.setLayout(gridLayout);
3518        fToolTipShell.setBackground(fTableViewer.getTable().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
3519        
3520        final Control toolTipControl = createToolTipControl(fToolTipShell);
3521        
3522        if (toolTipControl == null)
3523        {
3524            // if client decide not to use tooltip support
3525
fToolTipShell.dispose();
3526            return;
3527        }
3528        
3529        MouseTrackAdapter listener = new MouseTrackAdapter(){
3530            
3531            private TableItem fTooltipItem = null;
3532            private int fCol = -1;
3533            
3534            public void mouseExit(MouseEvent e){
3535                
3536                if (!fToolTipShell.isDisposed())
3537                    fToolTipShell.setVisible(false);
3538                fTooltipItem = null;
3539            }
3540            
3541            public void mouseHover(MouseEvent e){
3542                
3543                Point hoverPoint = new Point(e.x, e.y);
3544                Control control = null;
3545                
3546                if (e.widget instanceof Control)
3547                    control = (Control)e.widget;
3548                
3549                if (control == null)
3550                    return;
3551                
3552                hoverPoint = control.toDisplay(hoverPoint);
3553                TableItem item = getItem(hoverPoint);
3554                int column = getColumn(hoverPoint);
3555                
3556                //Only if there is a change in hover
3557
if(this.fTooltipItem != item || fCol != column){
3558                    
3559                    //Keep Track of the latest hover
3560
fTooltipItem = item;
3561                    fCol = column;
3562                    
3563                    if(item != null){
3564                        toolTipAboutToShow(toolTipControl, fTooltipItem, column);
3565                        
3566                        //Setting location of the tooltip
3567
Rectangle shellBounds = fToolTipShell.getBounds();
3568                        shellBounds.x = hoverPoint.x;
3569                        shellBounds.y = hoverPoint.y + item.getBounds(0).height;
3570                        
3571                        fToolTipShell.setBounds(shellBounds);
3572                        fToolTipShell.pack();
3573                        
3574                        fToolTipShell.setVisible(true);
3575                    }
3576                    else {
3577                        fToolTipShell.setVisible(false);
3578                    }
3579                }
3580            }
3581        };
3582        
3583        fTableViewer.getTable().addMouseTrackListener(listener);
3584        fTableCursor.addMouseTrackListener(listener);
3585    }
3586    
3587    /**
3588     * Bug with table widget,BUG 113015, the widget is not able to return the correct
3589     * table item if SWT.FULL_SELECTION is not on when the table is created.
3590     * Created the following function to work around the problem.
3591     * We can remove this method when the bug is fixed.
3592     * @param point
3593     * @return the table item where the point is located, return null if the item cannot be located.
3594     */

3595    private TableItem getItem(Point point)
3596    {
3597        TableItem[] items = fTableViewer.getTable().getItems();
3598        for (int i=0; i<items.length; i++)
3599        {
3600            Point start = new Point(items[i].getBounds(0).x, items[i].getBounds(0).y);
3601            start = fTableViewer.getTable().toDisplay(start);
3602            Point end = new Point(start.x + items[i].getBounds(0).width, start.y + items[i].getBounds(0).height);
3603            
3604            if (start.y < point.y && point.y < end.y)
3605                return items[i];
3606        }
3607        return null;
3608    }
3609    
3610    /**
3611     * Method for figuring out which column the point is located.
3612     * @param point
3613     * @return the column index where the point is located, return -1 if column is not found.
3614     */

3615    private int getColumn(Point point) {
3616        int colCnt = fTableViewer.getTable().getColumnCount();
3617        if(fTableViewer.getTable().getItemCount() > 0) {
3618            TableItem item = fTableViewer.getTable().getItem(0);
3619            Point start, end;
3620            for (int i=0; i<colCnt; i++) {
3621                start = new Point(item.getBounds(i).x, item.getBounds(i).y);
3622                start = fTableViewer.getTable().toDisplay(start);
3623                end = new Point(start.x + item.getBounds(i).width, start.y + item.getBounds(i).height);
3624                if (start.x < point.x && end.x > point.x) {
3625                    return i;
3626                }
3627            }
3628        }
3629        return -1;
3630    }
3631
3632    /**
3633     * Creates the control used to display tool tips for cells in this table. By default
3634     * a label is used to display the address of the cell. Clients may override this
3635     * method to create custom tooltip controls.
3636     * <p>
3637     * Also see the methods <code>getToolTipText(...)</code> and
3638     * <code>toolTipAboutToShow(...)</code>.
3639     * </p>
3640     * @param composite parent for the tooltip control
3641     * @return the tooltip control to be displayed
3642     * @since 3.2
3643     */

3644    protected Control createToolTipControl(Composite composite) {
3645        Control fToolTipLabel = new Label(composite, SWT.NONE);
3646        fToolTipLabel.setForeground(fTableViewer.getTable().getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND));
3647        fToolTipLabel.setBackground(fTableViewer.getTable().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
3648        fToolTipLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL |
3649                GridData.VERTICAL_ALIGN_CENTER));
3650        return fToolTipLabel;
3651    }
3652    
3653    
3654    /* (non-Javadoc)
3655     * @see org.eclipse.debug.ui.memory.IResettableMemoryRendering#resetRendering()
3656     */

3657    public void resetRendering() throws DebugException {
3658        resetToBaseAddress();
3659    }
3660
3661    /**
3662     * Called when the tool tip is about to show in this rendering.
3663     * Clients who overrides <code>createTooltipControl</code> may need to
3664     * also override this method to ensure that the tooltip shows up properly
3665     * in their customized control.
3666     * <p>
3667     * By default a text tooltip is displayed, and the contents for the tooltip
3668     * are generated by the <code>getToolTipText(...)</code> method.
3669     * </p>
3670     * @param toolTipControl - the control for displaying the tooltip
3671     * @param item - the table item where the mouse is pointing.
3672     * @param col - the column at which the mouse is pointing.
3673     * @since 3.2
3674     */

3675    protected void toolTipAboutToShow(Control toolTipControl, TableItem item,
3676            int col) {
3677        if (toolTipControl instanceof Label) {
3678            BigInteger JavaDoc address = getAddressFromTableItem(item, col);
3679            if (address != null) {
3680                Object JavaDoc data = item.getData();
3681                if (data instanceof TableRenderingLine) {
3682                    TableRenderingLine line = (TableRenderingLine) data;
3683
3684                    if (col > 0) {
3685                        int start = (col - 1) * getBytesPerColumn();
3686                        int end = start + getBytesPerColumn();
3687                        MemoryByte[] bytes = line.getBytes(start, end);
3688
3689                        String JavaDoc str = getToolTipText(address, bytes);
3690
3691                        if (str != null)
3692                            ((Label) toolTipControl).setText(str);
3693                    } else {
3694                        String JavaDoc str = getToolTipText(address,
3695                                new MemoryByte[] {});
3696
3697                        if (str != null)
3698                            ((Label) toolTipControl).setText(str);
3699                    }
3700                }
3701            }
3702        }
3703    }
3704    
3705    /**
3706     * Returns the text to display in a tool tip at the specified address
3707     * for the specified bytes. By default the address of the bytes is displayed.
3708     * Subclasses may override.
3709     *
3710     * @param address address of cell that tool tip is displayed for
3711     * @param bytes the bytes in the cell
3712     * @return the tooltip text for the memory bytes located at the specified
3713     * address
3714     * @since 3.2
3715     */

3716    protected String JavaDoc getToolTipText(BigInteger JavaDoc address, MemoryByte[] bytes)
3717    {
3718        StringBuffer JavaDoc buf = new StringBuffer JavaDoc("0x"); //$NON-NLS-1$
3719
buf.append(address.toString(16).toUpperCase());
3720        
3721        return buf.toString();
3722    }
3723    
3724    
3725    private String JavaDoc getRowPrefId(String JavaDoc modelId) {
3726        String JavaDoc rowPrefId = IDebugPreferenceConstants.PREF_ROW_SIZE + ":" + modelId; //$NON-NLS-1$
3727
return rowPrefId;
3728    }
3729
3730    private String JavaDoc getColumnPrefId(String JavaDoc modelId) {
3731        String JavaDoc colPrefId = IDebugPreferenceConstants.PREF_COLUMN_SIZE + ":" + modelId; //$NON-NLS-1$
3732
return colPrefId;
3733    }
3734    
3735    /**
3736     * @param modelId
3737     * @return default number of addressable units per line for the model
3738     */

3739    private int getDefaultRowSizeByModel(String JavaDoc modelId)
3740    {
3741        int row = DebugUITools.getPreferenceStore().getInt(getRowPrefId(modelId));
3742        if (row == 0)
3743        {
3744            DebugUITools.getPreferenceStore().setValue(getRowPrefId(modelId), IDebugPreferenceConstants.PREF_ROW_SIZE_DEFAULT);
3745        }
3746        
3747        row = DebugUITools.getPreferenceStore().getInt(getRowPrefId(modelId));
3748        return row;
3749        
3750    }
3751    
3752    /**
3753     * @param modelId
3754     * @return default number of addressable units per column for the model
3755     */

3756    private int getDefaultColumnSizeByModel(String JavaDoc modelId)
3757    {
3758        int col = DebugUITools.getPreferenceStore().getInt(getColumnPrefId(modelId));
3759        if (col == 0)
3760        {
3761            DebugUITools.getPreferenceStore().setValue(getColumnPrefId(modelId), IDebugPreferenceConstants.PREF_COLUMN_SIZE_DEFAULT);
3762        }
3763        
3764        col = DebugUITools.getPreferenceStore().getInt(getColumnPrefId(modelId));
3765        return col;
3766    }
3767    
3768    private int getBufferThreshold(int startOrEnd)
3769    {
3770        if (startOrEnd == BUFFER_START)
3771        {
3772            if (BUFFER_THRESHOLD > fPreBuffer)
3773                return fPreBuffer;
3774            return BUFFER_THRESHOLD;
3775        }
3776        
3777        if (BUFFER_THRESHOLD > fPostBuffer)
3778            return fPostBuffer;
3779        
3780        return BUFFER_THRESHOLD;
3781    }
3782
3783    
3784    /**
3785     * Returns text for the given memory bytes at the specified address for the specified
3786     * rendering type. This is called by the label provider for.
3787     * Subclasses must override.
3788     *
3789     * @param renderingTypeId rendering type identifier
3790     * @param address address where the bytes belong to
3791     * @param data the bytes
3792     * @return a string to represent the memory. Cannot not return <code>null</code>.
3793     * Returns a string to pad the cell if the memory cannot be converted
3794     * successfully.
3795     */

3796    abstract public String JavaDoc getString(String JavaDoc renderingTypeId, BigInteger JavaDoc address, MemoryByte[] data);
3797    
3798    /**
3799     * Returns bytes for the given text corresponding to bytes at the given
3800     * address for the specified rendering type. This is called by the cell modifier
3801     * when modifying bytes in a memory block.
3802     * Subclasses must convert the string value to an array of bytes. The bytes will
3803     * be passed to the debug adapter for memory block modification.
3804     * Returns <code>null</code> if the bytes cannot be formatted properly.
3805     *
3806     * @param renderingTypeId rendering type identifier
3807     * @param address address the bytes begin at
3808     * @param currentValues current values of the data in bytes format
3809     * @param newValue the string to be converted to bytes
3810     * @return the bytes converted from a string
3811     */

3812    abstract public byte[] getBytes(String JavaDoc renderingTypeId, BigInteger JavaDoc address, MemoryByte[] currentValues, String JavaDoc newValue);
3813
3814
3815}
3816
3817
Popular Tags