gprofng-gui-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Fix 66534 Copy-n-paste from the GUI loses metric percent column


From: vladimir . mezentsev
Subject: [PATCH] Fix 66534 Copy-n-paste from the GUI loses metric percent column
Date: Thu, 16 Jan 2025 20:00:09 -0800

From: Vladimir Mezentsev <vladimir.mezentsev@oracle.com>

There are several ways to copy rows from JTables to the clipboard or a file:
 - Select the rows and press Cntrl-C.
 - Right-click and select "Copy Selected" or "Copy All".
 - Go to "File" and select "Export..."
In all these cases we called printTableContents, which did not work correctly.

ChangeLog
2025-01-16  Vladimir Mezentsev  <vladimir.mezentsev@oracle.com>

        PR 66534
        * org/gprofng/mpmt/AnTable.java: Call registerKeyboardAction for 
Cntrl-C.
        Improve output in printTableHeader and printTableContents.
        * org/gprofng/mpmt/CallTreeView.java: Use AnUtility.copyToClipboard.
        * org/gprofng/mpmt/CallerCalleesView.java: Improve output in 
exportAsText.
        * org/gprofng/mpmt/DisasmDisp.java: Minor formatting.
        * org/gprofng/mpmt/FuncListDisp.java: Remove unused getCurrentTotal.
        * org/gprofng/mpmt/SourceDisp.java: Add @Override.
        * org/gprofng/mpmt/metrics/MetricLabel.java: Calculate width for column.
        * org/gprofng/mpmt/AnDisplay.java: Move copyToClipboard to AnUtility.
        * org/gprofng/mpmt/util/gui/AnUtility.java (copyToClipboard): New 
function.
---
 org/gprofng/mpmt/AnDisplay.java           |   9 -
 org/gprofng/mpmt/AnTable.java             | 492 +++++++---------------
 org/gprofng/mpmt/CallTreeView.java        |   2 +-
 org/gprofng/mpmt/CallerCalleesView.java   |  59 ++-
 org/gprofng/mpmt/DisasmDisp.java          |   4 +-
 org/gprofng/mpmt/FuncListDisp.java        |  51 +--
 org/gprofng/mpmt/SourceDisp.java          |  15 +-
 org/gprofng/mpmt/metrics/MetricLabel.java |  91 +++-
 org/gprofng/mpmt/util/gui/AnUtility.java  |  14 +
 9 files changed, 303 insertions(+), 434 deletions(-)

diff --git a/org/gprofng/mpmt/AnDisplay.java b/org/gprofng/mpmt/AnDisplay.java
index 9ba2635..aaf6193 100644
--- a/org/gprofng/mpmt/AnDisplay.java
+++ b/org/gprofng/mpmt/AnDisplay.java
@@ -29,9 +29,6 @@ import org.gprofng.mpmt.ipc.IPCContext;
 import org.gprofng.mpmt.mainview.Subview;
 import org.gprofng.mpmt.util.gui.AnUtility;
 import java.awt.Component;
-import java.awt.Toolkit;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.StringSelection;
 import java.util.ArrayList;
 import java.util.List;
 import javax.accessibility.AccessibleContext;
@@ -106,12 +103,6 @@ public abstract class AnDisplay extends JPanel {
     return null;
   }
 
-  protected void copyToClipboard(String text) {
-    StringSelection data = new StringSelection(text);
-    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
-    clipboard.setContents(data, data);
-  }
-
   //    abstract JPopupMenu getFilterPopup();
   public void showFilterPopup(Component parent) {
     JPopupMenu popup;
diff --git a/org/gprofng/mpmt/AnTable.java b/org/gprofng/mpmt/AnTable.java
index c89bb3a..a1b0b7d 100644
--- a/org/gprofng/mpmt/AnTable.java
+++ b/org/gprofng/mpmt/AnTable.java
@@ -34,6 +34,8 @@ import static 
org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED;
 import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGING;
 import static org.gprofng.mpmt.event.AnChangeEvent.Type.SOURCE_FINDING_CHANGED;
 import static 
org.gprofng.mpmt.event.AnChangeEvent.Type.SOURCE_FINDING_CHANGING;
+import static org.gprofng.mpmt.util.gui.AnUtility.SPACES_BETWEEN_COLUMNS;
+import static org.gprofng.mpmt.util.gui.AnUtility.EOL;
 
 import org.gprofng.analyzer.AnEnvironment;
 import org.gprofng.mpmt.DisasmDisp.DisRenderer;
@@ -63,11 +65,11 @@ import java.awt.event.AdjustmentEvent;
 import java.awt.event.AdjustmentListener;
 import java.awt.event.ComponentEvent;
 import java.awt.event.ComponentListener;
+import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.io.Serializable;
-import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -596,11 +598,12 @@ public final class AnTable extends AnTableScrollPane 
implements AnChangeListener
     }
 
     callHandler = new CallHandler();
-    table.registerKeyboardAction(
-        new CallHandler(),
-        "ENTER",
+    table.registerKeyboardAction(callHandler, "ENTER",
         KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
         JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+    table.registerKeyboardAction(callHandler, "CNTRL_C",
+        KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK),
+        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 
     // Popup menu
     menuListener = new AnMenuListener(this);
@@ -740,9 +743,7 @@ public final class AnTable extends AnTableScrollPane 
implements AnChangeListener
 
     if (!hasSelect) {
       table.addMouseListener(callHandler);
-      table.registerKeyboardAction(
-          callHandler,
-          "SPACE",
+      table.registerKeyboardAction(callHandler, "SPACE",
           KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0),
           JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
     } else {
@@ -914,214 +915,170 @@ public final class AnTable extends AnTableScrollPane 
implements AnChangeListener
     return printTableHeader(tname, sortedby, MaximumValues);
   }
 
-  private int spacesBetweenColumns = 3;
-  private int spacesForPercentage = 10;
+  private static void append_blanks(StringBuilder sb, int n) {
+    for (int i = 0; i < n; i++) {
+      sb.append(' ');
+    }
+  }
+
+  private static void stripTrailing(StringBuilder sb) {
+    int length = sb.length();
+    while (length > 0 && Character.isWhitespace(sb.charAt(length - 1))) {
+        length--;
+    }
+    sb.setLength(length);
+  }
 
   /** Create text presentation of the table header. */
   protected synchronized String printTableHeader(
       String tname, String sortedby, Object[][] MaximumValues) {
     // Prepare text presentation of the table
-    String space = " ";
-    String eol = "\n";
-    String empty = "";
-    String text = tname;
+    StringBuilder sb = new StringBuilder();
     if (canSort) {
       // text = "Functions sorted by metric: Exclusive Total CPU Time\n"
       int sc = getSortColumn();
       if (sc >= 0) {
         MetricLabel m = getTableModel().getLabel(sc);
         String ltext = m.getAnMetric().getName();
-        text += space + sortedby + space + ltext + eol;
+        if (tname != null && tname.length() > 0) {
+          sb.append(tname);
+          sb.append(" ");
+        }
+        sb.append(sortedby);
+        sb.append(" ");
+        sb.append(ltext);
+        sb.append(EOL);
       }
-    }
-    if ((type == AnDisplay.DSP_Source) || (type == AnDisplay.DSP_SourceV2)) {
+    } else if (type == AnDisplay.DSP_Source || type == AnDisplay.DSP_SourceV2) 
{
       // Print Source File name
-      if (this.names != null && this.names.length > 0) {
-        text = this.names[0]; // Source File: ...
-        text += eol;
+      if (names != null && names.length > 0) {
+        sb.append(names[0]); // Source File: ...
       }
-    }
-    if ((type == AnDisplay.DSP_Disassembly) || (type == 
AnDisplay.DSP_DisassemblyV2)) {
+    } else if (type == AnDisplay.DSP_Disassembly || type == 
AnDisplay.DSP_DisassemblyV2) {
       // Print Load Object name
-      if (this.names != null && this.names.length > 2) {
-        text = this.names[2]; // Load Object: ...
-        text += eol;
+      if (names != null && names.length > 2) {
+        sb.append(names[2]); // Load Object: ...
       }
     }
-    text += eol;
-    MetricLabel[] labels = tableModel.metricLabels;
-    String[][] s = new String[labels.length][];
-    show_percentage = new boolean[labels.length];
-    for (int j = 0; j < labels.length; j++) {
-      s[j] = labels[j].getLegendAndTitleLines();
-      if (labels[j].getAnMetric().isPVisible()) { // Show percentage
-        show_percentage[j] = true;
-      } else {
-        show_percentage[j] = false;
-      }
+    if (sb.length() > 0) {
+      sb.append(EOL);
+    } else if (tname != null && tname.length() > 0) {
+      sb.append(tname);
+      sb.append(EOL);
     }
-    if (null != s) {
-      int maxh[] = new int[s.length];
-      int maxv = 0;
-      for (int i = 0; i < s.length; i++) {
-        if (s[i].length > maxv) {
-          maxv = s[i].length;
+
+    StringBuilder line = new StringBuilder();
+    StringBuilder column = new StringBuilder();
+    MetricLabel[] labels = tableModel.metricLabels;
+    for (int lineN = 0;; lineN++) {
+      line.setLength(0);
+      for (int i = 0; i < labels.length; i++) {
+        MetricLabel ml = labels[i];
+        String[] titles = ml.getLegendAndTitleLines();
+        String s = "";
+        if (lineN < titles.length && titles[lineN] != null) {
+          s = titles[lineN];
         }
-        maxh[i] = 0;
-        for (int j = 0; j < s[i].length; j++) {
-          if (s[i][j].length() > maxh[i]) {
-            maxh[i] = s[i][j].length();
-          }
+        line.append(s);
+        if (i + 1 < labels.length) {
+          append_blanks(line, ml.getColumnWidth() + SPACES_BETWEEN_COLUMNS
+              - s.length());
         }
       }
-      for (int i = 0; i < maxh.length; i++) {
-        // choose max width between the label length and max value length
-        int maxvalen = 0;
-        if (null != MaximumValues) {
-          if (labels[i].getAnMetric().isVVisible()) { // Show Value
-            maxvalen = MaximumValues[1][i].toString().length();
-          }
-          String value = empty;
-          if (labels[i].getAnMetric().isTVisible()) { // Show Time
-            if (labels[i].getClock() != -1.0) { // Can convert cycles to time
-              value = ((AnObject) 
MaximumValues[1][i]).toFormTime(labels[i].getClock());
-            } else {
-              value = MaximumValues[1][i].toString();
-            }
-          }
-          maxvalen += value.length();
-          if (labels[i].getAnMetric().isVVisible()
-              && labels[i].getAnMetric().isTVisible()) { // Show Value and Time
-            maxvalen += 1; // space between them
-          }
-        }
-        if (labels[i].getAnMetric().isPVisible()) { // Show percentage
-          maxvalen += spacesForPercentage;
-        }
-        if (maxvalen > maxh[i]) {
-          maxh[i] = maxvalen;
-        }
-        // add spaces to separate header labels
-        maxh[i] += spacesBetweenColumns;
-      }
-      for (int i = 0; i < maxv; i++) {
-        for (int j = 0; j < s.length; j++) {
-          int k = 0;
-          if (s[j].length > i) {
-            text += s[j][i]; // Print header label
-            k = s[j][i].length();
-          }
-          if (j + 1 < s.length) { // do not add spaces to the end
-            // print formatting spaces
-            for (; k < maxh[j]; k++) {
-              text += space;
-            }
-          }
-        }
-        text += eol;
+      stripTrailing(line);
+      if (line.length() == 0) {
+        break;
       }
-      boolean needeol = false;
-      String units = empty;
-      for (int i = 0; i < labels.length; i++) {
-        String un = labels[i].getUnit();
-        if (null == un) {
-          un = empty;
-        }
-        if (un.length() > 0) {
-          needeol = true;
+      sb.append(line);
+      sb.append(EOL);
+    }
+
+    line.setLength(0);
+    for (int i = 0; i < labels.length; i++) {
+      MetricLabel ml = labels[i];
+      AnMetric m = ml.getAnMetric();
+      column.setLength(0);
+      String s = ml.getUnit();
+      if (s == null || s.length() == 0) {
+        if (!m.isNameMetric() && (m.isTVisible() || m.isVVisible())) {
+          column.append("#");
         }
-        units += un;
-        if (i + 1 < labels.length) { // do not add spaces to the end
-          for (int k = un.length(); k < maxh[i]; k++) {
-            // print formatting spaces
-            units += space;
-          }
+      } else {
+        column.append(s);
+      }
+      if (m.isPVisible()) {
+        append_blanks(column, ml.getValWidth() - column.length());
+        if (ml.getValWidth() > 0) {
+          append_blanks(column, SPACES_BETWEEN_COLUMNS);
         }
+        append_blanks(column, ml.getPercentWidth() - 3);
+        column.append("%");
       }
-      if (needeol) {
-        text += units;
-        text += eol;
+      if (i + 1 < labels.length) {
+        append_blanks(column, ml.getColumnWidth() + SPACES_BETWEEN_COLUMNS
+            - column.length());
       }
-      header_widths = maxh;
+      line.append(column);
     }
-    return text;
-  }
-
-  // Temporary solution. This array should be local variable of function, that 
includes function
-  // above and below
-  private int[] header_widths = null;
-  private boolean[] show_percentage = null;
-
-  /** Create text presentation of the table. */
-  protected int[] getTableHeaderWidths() {
-    return header_widths;
-  }
-
-  /** Create text presentation of the table. */
-  protected boolean[] getPercentageArray() {
-    return show_percentage;
+    stripTrailing(line);
+    if (line.length() != 0) {
+      sb.append(line);
+      sb.append(EOL);
+    }
+    return sb.toString();
   }
 
   /** Create text presentation of the table. */
   protected String printTableContents(Object[][] MaximumValues, int 
printLimit) {
     boolean last_only = false;
     boolean selected_only = false;
-    return printTableContents(
-        MaximumValues, header_widths, printLimit, show_percentage, last_only, 
selected_only);
+    return printTableContents(printLimit, last_only, selected_only);
   }
 
   /** Create text presentation of the selected rows of the table. */
   protected String printSelectedTableContents(Object[][] MaximumValues, int 
printLimit) {
     boolean last_only = false;
     boolean selected_only = true;
-    return printTableContents(
-        MaximumValues, header_widths, printLimit, show_percentage, last_only, 
selected_only);
+    return printTableContents(printLimit, last_only, selected_only);
   }
 
-  /** Create text presentation of the table. */
-  protected synchronized String printTableContents(
-      Object[][] MaximumValues,
-      int[] header_widths,
-      int printLimit,
-      boolean[] show_percentage,
-      boolean last_only,
-      boolean selected_only) {
-    // Prepare text presentation of the table
-    JTable t = table;
-    String space = " ";
-    String empty = "";
-    String eol = "\n";
-    StringBuilder fileContent = new StringBuilder();
-    TableModel tModel = t.getModel();
-    int namecol = getNameCol();
+  /** Create text presentation of the table.
+   * @param printLimit
+   * @param last_only
+   * @param selected_only
+   * @return  */
+  public synchronized String printTableContents(int printLimit,
+      boolean last_only, boolean selected_only) {
+    if (printLimit < 0) {
+      return "";
+    }
+    TableModel tModel = table.getModel();
     int rows = tModel.getRowCount();
     if (columnWidth.length <= 1) {
-      return "\n" + AnLocale.getString("No metrics selected for this view") + 
"\n";
+      return EOL + AnLocale.getString("No metrics selected for this view") + 
EOL;
     }
-    if (printLimit > 0) {
-      // print max printLimit
-      if (printLimit < rows) {
-        rows = printLimit;
-      }
-    } else if (printLimit < 0) {
-      // print headers only
-      rows = 0;
+    if (printLimit > 0 && rows < printLimit) {
+      rows = printLimit;  // print max printLimit
     }
 
+    MetricLabel[] labels = tableModel.metricLabels;
     int sz = rows;
+    int[] selected_ind = null;
     if (selected_only) {
-      if (null == selected_indices) {
-        selected_indices = table.getSelectedRows();
-      }
-      if (null == selected_indices) {
-        return empty;
+      selected_ind = table.getSelectedRows();
+      if (null == selected_ind) {
+        return "";
       }
-      sz = selected_indices.length;
+      sz = selected_ind.length;
     }
+    StringBuilder sb = new StringBuilder();
+    StringBuilder line = new StringBuilder();
+    StringBuilder column = new StringBuilder();
+
     for (int index = 0; index < sz; index++) {
       int i = index;
       if (selected_only) {
-        i = selected_indices[index];
+        i = selected_ind[index];
       }
 
       // Check if all values are empty
@@ -1137,173 +1094,44 @@ public final class AnTable extends AnTableScrollPane 
implements AnChangeListener
           || (src_type == AT_DIS_ONLY)) {
         emptyValues = true;
       }
-      for (int j = 0; j < tModel.getColumnCount(); j++) {
-        // get the cell value
+
+      line.setLength(0);
+      for (int j = 0; j < labels.length; j++) {
+        MetricLabel ml = labels[j];
+        AnMetric m = ml.getAnMetric();
         Object cellValue = tModel.getValueAt(i, j);
-        MetricLabel label = tableModel.getLabel(j);
-        boolean showPercentage = false;
-        String value = empty; // Used for empty values
-        if (j == namecol) { // Name
-          value = cellValue.toString();
-        } else {
-          if (!emptyValues) {
-            if (label.getAnMetric().isTVisible()) { // Show time
-              value = cellValue.toString();
-              if (label.getClock() != -1.0) { // Can convert cycles to time
-                value = ((AnObject) cellValue).toFormTime(label.getClock());
-              }
-            }
-            String value1 = empty;
-            if (label.getAnMetric().isVVisible()) { // Show value
-              value1 = cellValue.toString(); // number of cycles
-            }
-            if (label.getAnMetric().isPVisible()) { // Show percentage
-              showPercentage = true;
-            }
-            if ((label.getClock() != -1.0) /* || (label.unit != null) */) { // 
CPU cycles
-              String value2 = empty;
-              if (showPercentage) {
-                // calculate the weight of one percent
-                double onepercent = 0.0;
-                double total = 0.0;
-                if (MaximumValues != null) {
-                  total = ((AnObject) MaximumValues[0][j]).doubleValue();
-                }
-                if (total > 0.0) {
-                  onepercent = 100.0 / total;
-                }
-                // calculate the percentage
-                value2 = ((AnObject) cellValue).toPercent(onepercent);
-                value2 = "(" + value2 + "%)";
-              }
-              // Insert formatting spaces
-              int k = value.length() + value1.length() + value2.length() + 4; 
// 4 spaces
-              if (k < header_widths[j]) {
-                int len2 = 9 - value2.length(); // 9 - max percent length 
"(100.00%)"
-                String maxvalue = ((AnObject) 
MaximumValues[1][j]).toFormTime(label.getClock());
-                int len = maxvalue.length() - value.length();
-                String spaces = empty;
-                while (k++ < header_widths[j]) {
-                  spaces += space;
-                  if (showPercentage) {
-                    if (len2 > 0) { // percentage
-                      len2--;
-                      if (len2 == 0) { // add spaces to percentage
-                        value2 = spaces + value2;
-                        spaces = empty;
-                      }
-                      continue;
-                    }
-                  }
-                  if (len > 0) { // value
-                    len--;
-                    if (len == 0) { // add spaces to the left
-                      value = spaces + value;
-                      spaces = empty;
-                    }
-                    continue;
-                  }
-                }
-                value1 = spaces + value1; // add spaces to the middle
-              } else {
-                if (k > header_widths[j]) {
-                  String spaces = empty; // Is it a bug that we are here?
-                  while (k++ < header_widths[j]) {
-                    spaces += space;
-                  }
-                  value1 = spaces + value1; // add spaces to the middle
-                }
-              }
-              value += space + value1 + space + value2 + space + space;
-            } else { // Not CPU cycles
-              if (showPercentage) { // Show pecentage
-                double total = 0.0;
-                if (MaximumValues != null) {
-                  total = ((AnObject) MaximumValues[0][j]).doubleValue();
-                }
-                double percent = 0.0;
-                if (total > 0.0) {
-                  percent = (((AnObject) cellValue).doubleValue() / total) * 
100;
-                }
-                if (label.getAnMetric().isVVisible()
-                    || label.getAnMetric().isTVisible()) { // Show value and 
percentage
-                  value = ((AnObject) cellValue).toPercentQuote(percent);
-                } else { // Show only percentage
-                  DecimalFormat format_percent = new DecimalFormat("0.00");
-                  value = format_percent.format(percent);
-                  // Add formatting spaces
-                  int k = 6 - value.length();
-                  String spaces = empty;
-                  while (k-- > 0) {
-                    spaces += space;
-                  }
-                  value = spaces + value; // add spaces to the left
-                  value = "(" + value + "%)";
-                  k = 9;
-                  spaces = empty;
-                  while (k++ < header_widths[j]) {
-                    spaces += space;
-                  }
-                  value += spaces; // add spaces to the right
-                }
-              } else { // Show value
-                value = cellValue.toString();
-              }
-            }
-          } else { // Do not show empty values
-            // value = empty;
-          }
-        }
-        // calculate formatting spaces
-        int needspaces = 0;
-        if (label.getAnMetric().isVVisible() || 
label.getAnMetric().isTVisible()) { // Show value
-          if (MaximumValues != null) {
-            needspaces = MaximumValues[1][j].toString().length();
+        column.setLength(0);
+        if (m.isNameMetric()) {
+          column.append(cellValue.toString());
+        } else if (!emptyValues && !(last_only && (i + 1 != rows))) {
+          if (m.isTVisible() || m.isVVisible()) {
+            String s = cellValue.toString();
+            append_blanks(column, ml.getValWidth() - s.length());
+            column.append(s);
+          } else if (ml.getValWidth() > 0) {
+            append_blanks(column, ml.getValWidth());
           }
-        }
-        if (showPercentage) {
-          needspaces += spacesForPercentage;
-        }
-        int maxvalen = needspaces;
-        if ((null != header_widths) && (needspaces < header_widths[j])) {
-          needspaces = header_widths[j];
-        }
-        if (j != namecol) {
-          int k = maxvalen - value.length();
-          if (k > 0) {
-            // insert formatting spaces
-            needspaces -= k;
-            while (k > 0) {
-              fileContent.append(space);
-              k--;
+          if (m.isPVisible()) {
+            if (ml.getValWidth() > 0) {
+              append_blanks(column, SPACES_BETWEEN_COLUMNS);
             }
+            String s = ((AnObject) cellValue).toPercent(ml.getTotal());
+            append_blanks(column, ml.getPercentWidth() - s.length());
+            column.append(s);
           }
         }
-        needspaces -= value.length();
-        if ((last_only) && (j != namecol) && (i + 1 != rows)) {
-          // print spaces instead of values
-          for (int k = 0; k < value.length(); k++) {
-            fileContent.append(space);
-          }
-        } else {
-          // append the cell value
-          fileContent.append(value);
-        }
-        // append formatting spaces
-        if (needspaces < 1) {
-          needspaces = 1;
-        }
-        if ((j + 1) < tModel.getColumnCount()) {
-          for (int k = 0; k < needspaces; k++) {
-            fileContent.append(space);
-          }
+        if (j + 1 < labels.length) {
+          append_blanks(column, ml.getColumnWidth() + SPACES_BETWEEN_COLUMNS
+              - column.length());
         }
+        line.append(column);
       }
-      fileContent.append(eol);
+      stripTrailing(line);
+      sb.append(line);
+      sb.append(EOL);
     }
-    fileContent.append(eol);
-    String text = fileContent.toString();
-    return text;
+    sb.append(EOL);
+    return sb.toString();
   }
 
   // Listener for resize
@@ -2267,7 +2095,6 @@ public final class AnTable extends AnTableScrollPane 
implements AnChangeListener
       if (cmd.equals("SPACE")) {
         setSelectedRow(table.getSelectedRow());
       } else if (cmd.equals("ENTER")) {
-        //                System.out.println("ENTER" + event.getSource());
         int table_row = table.getSelectedRow();
         if (table_row == -1) {
           return;
@@ -2277,6 +2104,10 @@ public final class AnTable extends AnTableScrollPane 
implements AnChangeListener
           return;
         }
         performDefaultAction();
+      } else if (cmd.equals("CNTRL_C")) {
+        int printLimit = 0;
+        String text = anTable.printSelectedTableContents(null, printLimit);
+        AnUtility.copyToClipboard(text);
       }
     }
 
@@ -2306,12 +2137,7 @@ public final class AnTable extends AnTableScrollPane 
implements AnChangeListener
       System.out.println("AnTable.CallHandler.updateSelectedRow() org_row=" + 
orgRow);
       return;
     }
-    fireAnEvent(
-        new AnEvent(
-            anTable,
-            AnEvent.EVT_COMPUTE, // AnEvent.EVT_UPDATE,
-            orgRow,
-            null));
+    fireAnEvent(new AnEvent(anTable, AnEvent.EVT_COMPUTE, orgRow, null));
   }
 
   private final class TableAdapter extends MouseAdapter {
@@ -2440,7 +2266,7 @@ public final class AnTable extends AnTableScrollPane 
implements AnChangeListener
   // Table Model for Function List
   public final class FListTableModel extends AbstractTableModel { // public 
for memobj/indexobj
 
-    private MetricLabel[] metricLabels;
+    public MetricLabel[] metricLabels;
     private Object[][] data;
     private int[] src_type;
     private Row[] rows;
@@ -2519,9 +2345,8 @@ public final class AnTable extends AnTableScrollPane 
implements AnChangeListener
       this.src_type = src_type;
 
       // Get numbers of rows/columns
-      columnCount =
-          metricLabels
-              .length; // FIXUP: sometimes label == null if you quickly 
select/deselect metrics in
+      columnCount = metricLabels.length;
+      // FIXUP: sometimes label == null if you quickly select/deselect metrics 
in
       // overview
       rowCount = data[0].length;
 
@@ -2531,9 +2356,6 @@ public final class AnTable extends AnTableScrollPane 
implements AnChangeListener
         rows[i] = new Row(i);
       }
 
-      // for (int i=0; i< label.length; i  ++) {
-      // System.err.println("XXX Metric Label[" + i + "] = " + 
label[i].getText());
-      // }
       setLabel(metricLabels);
       if (marks != null && marks_inc != null) {
         for (int i = 0; i < marks[0].length; i++) {
diff --git a/org/gprofng/mpmt/CallTreeView.java 
b/org/gprofng/mpmt/CallTreeView.java
index bfcc8dd..9f75795 100644
--- a/org/gprofng/mpmt/CallTreeView.java
+++ b/org/gprofng/mpmt/CallTreeView.java
@@ -397,7 +397,7 @@ public final class CallTreeView extends AnDisplay 
implements ExportSupport, AnCh
   /** Copy all lines to the system clipboard */
   protected void copyAll() {
     String text = exportAsText(null, ExportFormat.TEXT, null);
-    copyToClipboard(text);
+    AnUtility.copyToClipboard(text);
   }
 
   @Override
diff --git a/org/gprofng/mpmt/CallerCalleesView.java 
b/org/gprofng/mpmt/CallerCalleesView.java
index fdde73f..b9071d1 100644
--- a/org/gprofng/mpmt/CallerCalleesView.java
+++ b/org/gprofng/mpmt/CallerCalleesView.java
@@ -19,6 +19,8 @@ import static org.gprofng.mpmt.AnDisplay.DSP_Callees;
 import static org.gprofng.mpmt.AnDisplay.DSP_CallerCalleeSelf;
 import static org.gprofng.mpmt.AnDisplay.DSP_Callers;
 import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED;
+import static org.gprofng.mpmt.util.gui.AnUtility.EOL;
+import static org.gprofng.mpmt.util.gui.AnUtility.SPACES_BETWEEN_COLUMNS;
 
 import org.gprofng.analyzer.AnEnvironment;
 import org.gprofng.mpmt.event.AnChangeEvent;
@@ -406,62 +408,53 @@ public final class CallerCalleesView extends FuncListDisp
   private String exportAsText(Integer limit) {
     // Prepare text presentation of the table
     String sortedby = AnLocale.getString("sorted by metric:");
-    String eol = "\n";
-    String empty = "";
-    String space = " ";
-    String textImage = null;
-    String separator = empty;
     String No = AnLocale.getString("No ");
+
+    MetricLabel[] labels = func_item.getTableModel().metricLabels;
+    MetricLabel[] labels1 = caller.getTableModel().metricLabels;
+    MetricLabel[] labels2 = callee.getTableModel().metricLabels;
+    int width = -1;
+    for (int i = 0; i < labels.length; i++) {
+      labels[i].updateWidth(labels1[i], labels2[i]);
+      if (i + 1 < labels.length) {
+        width += labels[i].getColumnWidth() + SPACES_BETWEEN_COLUMNS;
+      }
+    }
+    String separator = "";
+    for (int i = 0; i < width; i++) {
+      separator += "=";
+    }
+    separator += " ";
+
     String title1 = caller.getAccessibleContext().getAccessibleName();
     String title2 = func_item.getAccessibleContext().getAccessibleName();
     String title3 = callee.getAccessibleContext().getAccessibleName();
     AnTable tbl = func_item;
     Object[][] total_max = getCurrentTotalMax();
-    textImage = tbl.printTableHeader(title2, sortedby, total_max);
-    boolean[] show_percentage = tbl.getPercentageArray();
-    int[] maxh = tbl.getTableHeaderWidths();
-    if (null == MaximumValues) {
-      return textImage; // empty report
-    }
-    for (int i = 0; i < maxh.length - 1; i++) {
-      int j = 0;
-      if (i + 2 == maxh.length) {
-        j = 1; // Cosmetic
-      }
-      for (; j < maxh[i]; j++) {
-        separator += "=";
-      }
-    }
-    separator += space; // Cosmetic
+    String textImage = tbl.printTableHeader(title2, sortedby, total_max);
     int printLimit = limit != null ? limit : 0;
     tbl = caller;
     textImage += separator;
     if (tbl.getRowCount() == 0) {
       textImage += No;
     }
-    textImage += title1 + eol;
+    textImage += title1 + EOL;
     boolean last_only = false;
     boolean selected_only = false;
-    textImage +=
-        tbl.printTableContents(
-            total_max, maxh, printLimit, show_percentage, last_only, 
selected_only);
+    textImage += tbl.printTableContents(printLimit, last_only, selected_only);
     tbl = func_item;
     textImage += separator;
-    textImage += title2 + eol;
+    textImage += title2 + EOL;
     last_only = true;
-    textImage +=
-        tbl.printTableContents(
-            total_max, maxh, printLimit, show_percentage, last_only, 
selected_only);
+    textImage += tbl.printTableContents(printLimit, last_only, selected_only);
     tbl = callee;
     textImage += separator;
     if (tbl.getRowCount() == 0) {
       textImage += No;
     }
-    textImage += title3 + eol;
+    textImage += title3 + EOL;
     last_only = false;
-    textImage +=
-        tbl.printTableContents(
-            total_max, maxh, printLimit, show_percentage, last_only, 
selected_only);
+    textImage += tbl.printTableContents(printLimit, last_only, selected_only);
     return textImage;
   }
 
diff --git a/org/gprofng/mpmt/DisasmDisp.java b/org/gprofng/mpmt/DisasmDisp.java
index 2460be1..955b423 100644
--- a/org/gprofng/mpmt/DisasmDisp.java
+++ b/org/gprofng/mpmt/DisasmDisp.java
@@ -168,9 +168,7 @@ public class DisasmDisp extends SourceDisp {
         marks_inc[0] = (int[]) raw_marks_inc[0];
         marks_inc[1] = (int[]) raw_marks_inc[1];
         final AnMetric[] mlist = 
getSettings().getMetricsSetting().getMetricListByDType(type);
-        table_data =
-            localProcessData(
-                mlist, raw_data); // first index is for column, second index 
is for rows
+        table_data = localProcessData(mlist, raw_data);
         src_type = (int[]) raw_data[raw_data.length - 1]; // AnTable.AT_SRC, 
DIS, QUOTE, etc.
         String[] hdrContent = getNames(type, 0); // name column table header 
contents (?)
         label = getSettings().getMetricsSetting().getLabel(table_data, null, 
type, table);
diff --git a/org/gprofng/mpmt/FuncListDisp.java 
b/org/gprofng/mpmt/FuncListDisp.java
index 235ab01..1d88515 100644
--- a/org/gprofng/mpmt/FuncListDisp.java
+++ b/org/gprofng/mpmt/FuncListDisp.java
@@ -357,51 +357,19 @@ public class FuncListDisp extends AnDisplay implements 
ExportSupport {
     }
   }
 
-  /*
-   * Returns Total values for MET_CALL metric list (Temporary solution)
-   */
-  public Object[] getCurrentTotal() {
-    final String mlistStr = "MET_CALL";
-    final String typeStrFunc = "FUNCTION";
-    final String subtypeStr = "0"; // + DSP_SOURCE;
-    // final String stab_callers = "CALLERS";
-    final String stab_callees = "CALLEES";
-    // final String stab_self = "SELF";
-    Object[] total = null;
-    Object[] raw_data_with_ids =
-        window.getTableDataV2(mlistStr, stab_callees, typeStrFunc, subtypeStr, 
null /*cstack*/);
-    if (null == raw_data_with_ids) {
-      return total;
-    }
-    final AnMetric[] mlist = 
getSettings().getMetricsSetting().getMetricListByDType(type);
-    Object[][] processed_data = localProcessData(mlist, raw_data_with_ids);
-    int len = processed_data.length;
-    if (len > 0) {
-      total = new Object[len];
-      for (int i = 0; i < len; i++) {
-        total[i] = processed_data[i][0];
-      }
-    }
-    return total;
-  }
-
   /** Copy all lines to the system clipboard */
   protected void copyAll() {
     String text = exportAsText(null, ExportFormat.TEXT, null);
-    copyToClipboard(text);
+    AnUtility.copyToClipboard(text);
   }
 
   /** Copy selected lines to the system clipboard */
   protected void copySelected() {
     String sortedby = AnLocale.getString("sorted by metric:");
-    String textImage = "";
-    textImage = table.printTableHeader(sortedby, MaximumValues);
-    if (null == MaximumValues) {
-      return; // empty report
-    }
+    String textImage = table.printTableHeader(sortedby, MaximumValues);
     int printLimit = 0;
     textImage += table.printSelectedTableContents(MaximumValues, printLimit);
-    copyToClipboard(textImage);
+    AnUtility.copyToClipboard(textImage);
   }
 
   @Override
@@ -586,12 +554,9 @@ public class FuncListDisp extends AnDisplay implements 
ExportSupport {
           raw_data = getFuncList(type, subtype);
           if (raw_data != null && raw_data.length > 0) {
             raw_data_length = raw_data.length;
-            table_data =
-                localProcessData(
-                    mlist, raw_data); // first index is for column, second 
index is for rows
-            // System.err.println("XXX after processData table_data.length = " 
+ table_data.length +
-            // "; row_length " + table_data[0].length );
-            src_type = (int[]) raw_data[raw_data.length - 1]; // 
AnTable.AT_SRC, DIS, QUOTE, etc.
+            table_data = localProcessData(mlist, raw_data);
+            // first index is for column, second index is for rows:
+            src_type = (int[]) raw_data[raw_data.length - 1]; // AT_SRC, DIS, 
QUOTE, etc.
           } else {
             // Should never happen but it does sometimes if you quickly 
select/deselect metrics in
             // overview // Changdao?
@@ -610,9 +575,7 @@ public class FuncListDisp extends AnDisplay implements 
ExportSupport {
         // String[] hdrContent = getNames(typeForPresentation, 0); // name 
column table header
         // contents (?) // SYNC IPC
         String[] hdrContent = ipcr_getNames.getStrings();
-        label =
-            getSettings()
-                .getMetricsSetting()
+        label = getSettings().getMetricsSetting()
                 .getLabel(table_data, null, typeForPresentation, table);
         name_col = 
getSettings().getMetricsSetting().getNameColumnIndexByDType(getMetricMType());
         sort_ind = 
getSettings().getMetricsSetting().getSortColumnByDType(typeForPresentation);
diff --git a/org/gprofng/mpmt/SourceDisp.java b/org/gprofng/mpmt/SourceDisp.java
index 523b9d0..ebd4ead 100644
--- a/org/gprofng/mpmt/SourceDisp.java
+++ b/org/gprofng/mpmt/SourceDisp.java
@@ -247,11 +247,9 @@ public class SourceDisp extends FuncListDisp {
         marks_inc[0] = (int[]) raw_marks_inc[0];
         marks_inc[1] = (int[]) raw_marks_inc[1];
         final AnMetric[] mlist = 
getSettings().getMetricsSetting().getMetricListByDType(type);
-        table_data =
-            localProcessData(
-                mlist, raw_data); // first index is for column, second index 
is for rows
-        src_type =
-            (int[]) raw_data[raw_data.length - 1]; // AnTable.AnTable.AT_SRC, 
DIS, QUOTE, etc.
+        table_data = localProcessData(mlist, raw_data);
+        // first index is for column, second index is for rows
+        src_type = (int[]) raw_data[raw_data.length - 1]; // AT_SRC, DIS, 
QUOTE, etc.
         String[] hdrContent = getNames(type, 0); // name column table header 
contents (?)
         label = getSettings().getMetricsSetting().getLabel(table_data, null, 
type, table);
         name_col = 
getSettings().getMetricsSetting().getNameColumnIndexByDType(type);
@@ -267,8 +265,8 @@ public class SourceDisp extends FuncListDisp {
           sel_func = getFuncObj(); // inside doCompute, on worker thread and 
synchronized
           // (AnVariable.mainFlowLock)
         }
-        table.setData(
-            label, table_data, hdrContent, src_type, new_ind, name_col, 
sort_ind, marks, marks_inc);
+        table.setData(label, table_data, hdrContent, src_type, new_ind,
+            name_col, sort_ind, marks, marks_inc);
 
         if (sel_func == 0) {
           // XXX we should not call setSelObj when we go to the Source tab
@@ -1666,14 +1664,17 @@ public class SourceDisp extends FuncListDisp {
         parentComponent.dispatchEvent(e);
       }
 
+      @Override
       public void keyTyped(KeyEvent e) {
         propagateToTable(e);
       }
 
+      @Override
       public void keyPressed(KeyEvent e) {
         propagateToTable(e);
       }
 
+      @Override
       public void keyReleased(KeyEvent e) {
         propagateToTable(e);
       }
diff --git a/org/gprofng/mpmt/metrics/MetricLabel.java 
b/org/gprofng/mpmt/metrics/MetricLabel.java
index 1802fd8..cf78a7f 100644
--- a/org/gprofng/mpmt/metrics/MetricLabel.java
+++ b/org/gprofng/mpmt/metrics/MetricLabel.java
@@ -21,6 +21,7 @@ import org.gprofng.mpmt.AnObject;
 import org.gprofng.mpmt.settings.CompareModeSetting.CompareMode;
 import org.gprofng.mpmt.util.gui.AnUtility;
 import javax.swing.ImageIcon;
+import static org.gprofng.mpmt.util.gui.AnUtility.SPACES_BETWEEN_COLUMNS;
 
 public class MetricLabel {
 
@@ -71,8 +72,6 @@ public class MetricLabel {
       titleLines[0] = "";
       icon = null;
     }
-
-    //        }
   }
 
   public String getText() {
@@ -136,6 +135,94 @@ public class MetricLabel {
     this.maxAnObject = maxAnObject;
   }
 
+  private int columnWidth = 0;
+  private int headerWidth = 0;
+  private int valWidth = 0;
+  private int percentWidth = 0;
+
+  public void init_width() {
+    if (columnWidth > 0) {
+      return;
+    }
+    AnMetric m = getAnMetric();
+    AnObject obj = getMaxAnObject();
+    if (m.isTVisible() || m.isVVisible()) {
+      valWidth = obj.toString().length();
+      if (unit != null && valWidth < unit.length()) {
+        valWidth = unit.length();
+      }
+    }
+    if (m.isPVisible()) {
+      if (valWidth > 0) {
+        columnWidth += SPACES_BETWEEN_COLUMNS;
+      }
+      percentWidth = obj.toPercent(getTotal()).length();
+    }
+    columnWidth += valWidth + percentWidth;
+
+    if (unit != null) {
+      headerWidth = unit.length();
+    }
+    String[] titles = getLegendAndTitleLines();
+    for (int i = 0; i < titles.length; i++) {
+      if (headerWidth < titles[i].length()) {
+        headerWidth = titles[i].length();
+      }
+    }
+    if (columnWidth < headerWidth) {
+      columnWidth = headerWidth;
+    }
+  }
+  
+  private int max_val(int i1, int i2, int i3) {
+    int cnt = i1;
+    if (cnt < i2) {
+      cnt = i2;
+    }
+    return i3 > cnt ? i3 : cnt;
+  }
+
+  // Make the caller and callee views the same width
+  public void updateWidth(MetricLabel m1, MetricLabel m2) {
+    init_width();
+    m1.init_width();
+    m2.init_width();
+    valWidth = max_val(valWidth, m1.valWidth, m2.valWidth);
+    percentWidth = max_val(percentWidth, m1.percentWidth, m2.percentWidth);
+    headerWidth = max_val(headerWidth, m1.headerWidth, m2.headerWidth);
+    columnWidth = valWidth + percentWidth;
+    if (valWidth > 0) {
+      columnWidth += SPACES_BETWEEN_COLUMNS;
+    }
+    if (columnWidth < headerWidth) {
+      columnWidth = headerWidth;
+    }
+    m1.valWidth = m2.valWidth = valWidth;
+    m1.percentWidth = m2.percentWidth = percentWidth;
+    m1.headerWidth = m2.headerWidth = headerWidth;
+    m1.columnWidth = m2.columnWidth = columnWidth;
+  }
+
+  public int getValWidth() {
+    init_width();
+    return valWidth;
+  }
+
+  public int getPercentWidth() {
+    init_width();
+    return percentWidth;
+  }
+
+  public int getHeaderWidth() {
+    init_width();
+    return headerWidth;
+  }
+
+  public int getColumnWidth() {
+    init_width();
+    return columnWidth;
+  }
+
   public void dump() {
     System.out.print("MetricLabel: ");
     for (int i = 0; i < titleLines.length; i++) {
diff --git a/org/gprofng/mpmt/util/gui/AnUtility.java 
b/org/gprofng/mpmt/util/gui/AnUtility.java
index f7ae52b..f1670b8 100644
--- a/org/gprofng/mpmt/util/gui/AnUtility.java
+++ b/org/gprofng/mpmt/util/gui/AnUtility.java
@@ -33,6 +33,9 @@ import java.awt.Font;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
 import java.awt.event.InputEvent;
@@ -86,6 +89,9 @@ public final class AnUtility {
   public static final int WARNING_MSG = 2;
   public static final int PSTAT_MSG = 3;
   public static final int PWARN_MSG = 4;
+  public static final int SPACES_BETWEEN_COLUMNS = 3;
+  public static final String SPACE = " ";
+  public static final String EOL = "\n";
   // mime types for files
   public static final int MIME_ELF_EXECUTABLE = 0x7f454c46;
   public static final int MIME_JAVA_CLASS_FILE = 0xcafebabe;
@@ -1177,6 +1183,14 @@ public final class AnUtility {
     }
   }
 
+  public static void copyToClipboard(String text) {
+    if (text != null && text.length() > 0) {
+      StringSelection data = new StringSelection(text);
+      Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+      clipboard.setContents(data, data);
+    }
+  }
+
   public static String keyStrokeToStringFormatted(KeyStroke keyStroke) {
     return "  (" + keyStrokeToString(keyStroke) + ")"; // NOI18N
   }
-- 
2.43.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]