gt:             this.rowToElementIndex = new int[arrayLength];
context: /*
   * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  package com.sun.max.ins.object;
  
  import java.awt.*;
  import java.awt.event.*;
  import java.util.*;
  import java.util.List;
  
  import javax.swing.*;
  import javax.swing.event.*;
  import javax.swing.table.*;
  
  import com.sun.max.ins.*;
  import com.sun.max.ins.debug.*;
  import com.sun.max.ins.gui.*;
  import com.sun.max.ins.memory.*;
  import com.sun.max.ins.type.*;
  import com.sun.max.ins.value.*;
  import com.sun.max.program.*;
  import com.sun.max.tele.*;
  import com.sun.max.tele.object.*;
  import com.sun.max.unsafe.*;
  import com.sun.max.vm.type.*;
  import com.sun.max.vm.value.*;
  
  /**
   * A table that displays VM array elements; for use in an instance of {@link ObjectView}. This is used to
   * display the elements of any {@link TeleArrayObject}, but is also use to display elements in hub instances
   * of {@link TeleHybridObject}.
   * <p>
   * Null array elements can be hidden from the display.
   * <p>
   * This table is somewhat complex so that it can serve for both ordinary array elements
   * as well as the various array subsets (tables) in hybrid objects (hubs).  They are distinguished
   * by a string prefix appearing before any mention of elements, e.g. [3] for an ordinary
   * array element and M[3] for an element of the MTable in a hub.
   */
  public final class ArrayElementsTable extends InspectorTable {
  
      private static final int TRACE_LEVEL = 1;
  
      private final ObjectView objectView;
      private final Kind elementKind;
      private final TypeDescriptor elementTypeDescriptor;
      private final int startOffset;
      private final int startIndex;
      private final int arrayLength;
      private final String indexPrefix;
      private final WordValueLabel.ValueMode wordValueMode;
  
      private final ArrayElementsTableModel tableModel;
  
      private final List<InspectorAction> extraViewMenuActions = new ArrayList<InspectorAction>();
  
      /**
       * A table specialized for the display VM array elements.
       * This table is somewhat complex so that it can serve for both ordinary array elements
       * as well as the various array subsets (tables) in hybrid objects (hubs).
       *
       * @param elementKind the VM value "kind" of the array elements.
       * @param startOffset memory position relative to the object origin where the displayed array starts
       * @param startIndex index into the array where the display starts
       * @param length number of elements to display
       * @param indexPrefix text to prepend to the displayed name(index) of each element.
       * @param wordValueMode how to display word values, based on their presumed use in the VM.
       */
      ArrayElementsTable(Inspection inspection,
                      ObjectView objectView, final Kind elementKind, final TypeDescriptor elementTypeDescriptor, final int startOffset,
                      int startIndex, int length, final String indexPrefix, WordValueLabel.ValueMode wordValueMode) {
          super(inspection);
          this.objectView = objectView;
          this.elementKind = elementKind;
          this.elementTypeDescriptor = elementTypeDescriptor;
          this.startOffset = startOffset;
          this.startIndex = startIndex;
          this.arrayLength = length;
          this.indexPrefix = indexPrefix;
          this.wordValueMode = wordValueMode;
  
          this.tableModel = new ArrayElementsTableModel(inspection, objectView.object().origin());
          ArrayElementsTableColumnModel columnModel = new ArrayElementsTableColumnModel(this, this.tableModel, objectView.viewPreferences());
          configureMemoryTable(tableModel, columnModel);
  
          this.extraViewMenuActions.add(scrollToBeginningAction());
          this.extraViewMenuActions.add(new ScrollToIndexAction(inspection));
          this.extraViewMenuActions.add(scrollToEndAction());
  
          setFillsViewportHeight(true);
          updateFocusSelection();
      }
  
      @Override
      protected void mouseButton1Clicked(final int row, int col, MouseEvent mouseEvent) {
          if (mouseEvent.getClickCount() > 1 && vm().watchpointManager() != null) {
              final InspectorAction toggleAction = new Watchpoints.ToggleWatchpointRowAction(inspection(), tableModel, row, "Toggle watchpoint") {
  
                  @Override
                  public MaxWatchpoint setWatchpoint() {
                      actions().setArrayElementWatchpoint(objectView.object(), elementKind, startOffset, tableModel.rowToElementIndex(row), indexPrefix, null).perform();
                      final List<MaxWatchpoint> watchpoints = tableModel.getWatchpoints(row);
                      if (!watchpoints.isEmpty()) {
                          return watchpoints.get(0);
                      }
                      return null;
                  }
              };
              toggleAction.perform();
          }
      }
  
      @Override
      protected InspectorPopupMenu getPopupMenu(final int row, int col, MouseEvent mouseEvent) {
          if (vm().watchpointManager() != null) {
              final MaxObject object = objectView.object();
              final InspectorPopupMenu menu = new InspectorPopupMenu();
              menu.add(new Watchpoints.ToggleWatchpointRowAction(inspection(), tableModel, row, "Toggle watchpoint (double-click)") {
  
                  @Override
                  public MaxWatchpoint setWatchpoint() {
                      actions().setArrayElementWatchpoint(object, elementKind, startOffset, tableModel.rowToElementIndex(row), indexPrefix, null).perform();
                      final List<MaxWatchpoint> watchpoints = tableModel.getWatchpoints(row);
                      if (!watchpoints.isEmpty()) {
                          return watchpoints.get(0);
                      }
                      return null;
                  }
              });
              menu.add(actions().setArrayElementWatchpoint(object, elementKind, startOffset, tableModel.rowToElementIndex(row), indexPrefix, "Watch this array element"));
              menu.add(actions().setObjectWatchpoint(object, "Watch this array's memory"));
              menu.add(Watchpoints.createEditMenu(inspection(), tableModel.getWatchpoints(row)));
              menu.add(Watchpoints.createRemoveActionOrMenu(inspection(), tableModel.getWatchpoints(row)));
              return menu;
          }
          return null;
      }
  
      @Override
      public void updateFocusSelection() {
          // Sets table selection to the memory word, if any, that is the current user focus.
          final Address address = focus().address();
          updateSelection(tableModel.findRow(address));
      }
  
      @Override
      public void valueChanged(ListSelectionEvent e) {
          // The selection in the table has changed; might have happened via user action (click, arrow) or
          // as a side effect of a focus change.
          super.valueChanged(e);
          if (!e.getValueIsAdjusting()) {
              final int row = getSelectedRow();
              if (row >= 0 && row < tableModel.getRowCount()) {
                  focus().setAddress(tableModel.getAddress(row));
              }
          }
      }
  
      /**
       * @return color the text specially in the row where a watchpoint is triggered
       */
      @Override
      public Color cellForegroundColor(int row, int column) {
          final MaxWatchpointEvent watchpointEvent = vm().state().watchpointEvent();
          if (watchpointEvent != null && tableModel.getMemoryRegion(row).contains(watchpointEvent.address())) {
              return preference().style().debugIPTagColor();
          }
          return null;
      }
  
  
      @Override
      public Color cellBackgroundColor() {
          return objectView == null ? null : objectView.viewBackgroundColor();
      }
  
      @Override
      public Color headerBackgroundColor() {
          return cellBackgroundColor();
      }
  
      @Override
      public List<InspectorAction> extraViewMenuActions() {
          return extraViewMenuActions;
      }
  
      @Override
      public boolean isElided() {
          return objectView.viewPreferences().elideNullArrayElements();
      }
  
      public ObjectView getView() {
          return objectView;
      }
  
      /**
       * A column model for array elements, to be used in an {@link ObjectView}.
       * Column selection is driven by choices in the parent {@link ObjectView}.
       * This implementation cannot update column choices dynamically.
       */
      private final class ArrayElementsTableColumnModel extends InspectorTableColumnModel<ObjectColumnKind> {
  
          ArrayElementsTableColumnModel(InspectorTable table, InspectorMemoryTableModel tableModel, ObjectViewPreferences viewPreferences) {
              super(inspection(), ObjectColumnKind.values().length, viewPreferences);
              addColumnIfSupported(ObjectColumnKind.TAG, new MemoryTagTableCellRenderer(inspection(), table, tableModel), null);
              addColumnIfSupported(ObjectColumnKind.ADDRESS, new MemoryAddressLocationTableCellRenderer(inspection(), table, tableModel), null);
              addColumnIfSupported(ObjectColumnKind.OFFSET, new MemoryOffsetLocationTableCellRenderer(inspection(), table, tableModel), null);
              addColumnIfSupported(ObjectColumnKind.TYPE,  new MemoryContentsTypeTableCellRenderer(inspection(), table, tableModel), null);
              addColumnIfSupported(ObjectColumnKind.NAME, new NameRenderer(inspection()), null);
              addColumnIfSupported(ObjectColumnKind.VALUE, new ValueRenderer(inspection()), null);
              addColumnIfSupported(ObjectColumnKind.BYTES,  new MemoryBytesTableCellRenderer(inspection(), table, tableModel), null);
              addColumnIfSupported(ObjectColumnKind.REGION, new MemoryRegionPointerTableCellRenderer(inspection(), table, tableModel), null);
          }
      }
  
      /**
       * Models (a possible subset of) words/rows in a sequence of array elements;
       * the value of each cell is simply the index into the array
       * elements being displayed.
       * <br>
       * The origin of the model is the current origin of the object in memory that includes these elements,
       * which may change after GC.
       */
      private final class ArrayElementsTableModel extends InspectorMemoryTableModel {
  
          private final int nBytesInElement;
  
          /**
           * Map: display {@code row --> element index}.
           * <p>
           * When null elements are not being hidden then {@code row == elementIndex}
           */
          private final int[] rowToElementIndex;
  
  
          private int visibleElementCount = 0;  // number of array elements being displayed
  
          public ArrayElementsTableModel(Inspection inspection, Address origin) {
              super(inspection, origin);
              this.nBytesInElement = elementKind.width.numberOfBytes;
  