Merge branch 'master' of git.labs.intellij.net:idea/community
authorAlexander Marchuk <Alexander.Marchuk@jetbrains.com>
Thu, 30 Oct 2014 12:52:23 +0000 (15:52 +0300)
committerAlexander Marchuk <Alexander.Marchuk@jetbrains.com>
Thu, 30 Oct 2014 12:52:23 +0000 (15:52 +0300)
15 files changed:
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerExpressionComboBox.java
platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerMultilineEditor.java
python/src/com/jetbrains/python/debugger/array/ArrayChunk.java
python/src/com/jetbrains/python/debugger/array/ArrayTableCellEditor.java
python/src/com/jetbrains/python/debugger/array/ArrayTableCellRenderer.java
python/src/com/jetbrains/python/debugger/array/ArrayTableComponent.java [deleted file]
python/src/com/jetbrains/python/debugger/array/ArrayTableForm.java
python/src/com/jetbrains/python/debugger/array/ArrayValueProvider.java
python/src/com/jetbrains/python/debugger/array/ComparableArrayChunk.java [deleted file]
python/src/com/jetbrains/python/debugger/array/JBTableWithRowHeaders.java [new file with mode: 0644]
python/src/com/jetbrains/python/debugger/array/NumpyArraySlice.java
python/src/com/jetbrains/python/debugger/array/NumpyArrayValueProvider.java
python/src/com/jetbrains/python/debugger/array/PagingTableModel.java
python/src/com/jetbrains/python/debugger/array/RowHeaderTable.java [deleted file]

index cb49212cd476dcc36e48911e02ba593e4cecc112..5928d8babf16413fc6ff7291fd7bd941de36615f 100644 (file)
@@ -142,7 +142,7 @@ public abstract class XDebuggerEditorBase {
 
   public abstract JComponent getComponent();
 
-  protected abstract void doSetText(XExpression text);
+  protected abstract void setEditorText(XExpression text);
 
   public void setExpression(@Nullable XExpression text) {
     if (text == null) {
@@ -174,7 +174,7 @@ public abstract class XDebuggerEditorBase {
       myChooseFactory.setDisabledIcon(IconLoader.getDisabledIcon(icon));
     }
 
-    doSetText(text);
+    setEditorText(text);
   }
 
   @Nullable
@@ -240,7 +240,7 @@ public abstract class XDebuggerEditorBase {
     final List<XExpression> expressions = getRecentExpressions();
     if (myHistoryIndex < expressions.size() - 1) {
       myHistoryIndex++;
-      doSetText(expressions.get(myHistoryIndex));
+      setEditorText(expressions.get(myHistoryIndex));
     }
   }
 
@@ -248,7 +248,7 @@ public abstract class XDebuggerEditorBase {
     final List<XExpression> expressions = getRecentExpressions();
     if (myHistoryIndex > 0) {
       myHistoryIndex--;
-      doSetText(expressions.get(myHistoryIndex));
+      setEditorText(expressions.get(myHistoryIndex));
     }
   }
 }
index 3039d2acda7f5d132f5348d2f393d4c75ac9dfe1..eaff436919dbd193fef4915438a073ca5354c71f 100644 (file)
@@ -128,7 +128,7 @@ public class XDebuggerExpressionComboBox extends XDebuggerEditorBase {
   }
 
   @Override
-  protected void doSetText(XExpression text) {
+  protected void setEditorText(XExpression text) {
     if (myComboBox.getItemCount() > 0) {
       myComboBox.setSelectedIndex(0);
     }
index b2222ce556c5a1a846e940fc9fd5a1c593f384af..386bca17e8567cfbfafa58917e0c23ec97c36790 100644 (file)
@@ -69,7 +69,7 @@ public class XDebuggerMultilineEditor extends XDebuggerEditorBase {
   }
 
   @Override
-  protected void doSetText(XExpression text) {
+  protected void setEditorText(XExpression text) {
     myExpression = text;
     Language language = text.getLanguage();
     FileType fileType = language != null ? language.getAssociatedFileType() : getEditorsProvider().getFileType();
index 9526e463a72e3b50cc385c6f86f9b67d7f4a1e95..12f4d9c5cd0e53e0908190d48c7117309f855e22 100644 (file)
  */
 package com.jetbrains.python.debugger.array;
 
+import org.jetbrains.annotations.NotNull;
+
 /**
  * @author amarch
  */
-public abstract class ArrayChunk {
-  protected String baseSlice;
-  protected int columns;
-  protected int rows;
-  protected int cOffset;
-  protected int rOffset;
-  protected Object[][] data;
+public abstract class ArrayChunk implements Comparable<ArrayChunk> {
+  private final String myBaseSlice;
+  private final int myColumns;
+  private final int myRows;
+  private final int myColOffset;
+  private final int myRowOffset;
+  private Object[][] myData;
 
   public ArrayChunk(String baseSlice, int rows, int columns, int rOffset, int cOffset) {
-    this.baseSlice = baseSlice;
-    this.columns = columns;
-    this.rows = rows;
-    this.rOffset = rOffset;
-    this.cOffset = cOffset;
-    data = new Object[rows][columns];
+    myBaseSlice = baseSlice;
+    myColumns = columns;
+    myRows = rows;
+    myRowOffset = rOffset;
+    myColOffset = cOffset;
   }
 
   public int getRows() {
-    return rows;
+    return myRows;
+  }
+
+  public int getColumns() {
+    return myColumns;
   }
 
-  public int getColumns(){
-    return columns;
+  public int getColOffset() {
+    return myColOffset;
+  }
+
+  public int getRowOffset() {
+    return myRowOffset;
   }
 
   public Object[][] getData() {
-    return data;
+    return myData;
+  }
+
+  public String getBaseSlice() {
+    return myBaseSlice;
   }
 
   public String getPresentation() {
@@ -54,15 +67,30 @@ public abstract class ArrayChunk {
   abstract void fillData(Runnable callback);
 
   public boolean contains(int row, int col) {
-    return rOffset <= row && row < rOffset + rows && cOffset <= col && col < cOffset + columns;
+    return myRowOffset <= row && row < myRowOffset + myRows && myColOffset <= col && col < myColOffset + myColumns;
   }
 
   public boolean equals(Object o) {
     return o instanceof ArrayChunk &&
-           baseSlice == ((ArrayChunk)o).baseSlice &&
-           columns == ((ArrayChunk)o).columns &&
-           rows == ((ArrayChunk)o).rows &&
-           cOffset == ((ArrayChunk)o).cOffset &&
-           rOffset == ((ArrayChunk)o).rOffset;
+           myBaseSlice == ((ArrayChunk)o).myBaseSlice &&
+           myColumns == ((ArrayChunk)o).myColumns &&
+           myRows == ((ArrayChunk)o).myRows &&
+           myColOffset == ((ArrayChunk)o).myColOffset &&
+           myRowOffset == ((ArrayChunk)o).myRowOffset;
+  }
+
+  @Override
+  public int compareTo(@NotNull ArrayChunk other) {
+    int compRow = myRowOffset - other.myRowOffset;
+    int compCol = myColOffset - other.myColOffset;
+    return compRow != 0 ? compRow : compCol;
+  }
+
+  public boolean isOneRow() {
+    return getRows() == 1;
+  }
+
+  public boolean isOneColumn() {
+    return getColumns() == 1;
   }
 }
index 5748fc496260f5ea95c1d5c06aef54ee22e7a4d6..6095d1d0047d9c7c576fd2c1dad869501d2e6579 100644 (file)
@@ -17,6 +17,7 @@ package com.jetbrains.python.debugger.array;
 
 import com.intellij.openapi.application.Result;
 import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.editor.ex.EditorEx;
 import com.intellij.openapi.project.Project;
@@ -36,56 +37,53 @@ import org.jetbrains.annotations.Nullable;
 import javax.swing.*;
 import javax.swing.table.TableCellEditor;
 import java.awt.*;
-import java.awt.event.ActionEvent;
+import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
 
 /**
  * @author amarch
  */
-class ArrayTableCellEditor extends AbstractCellEditor implements TableCellEditor {
-  MyTableEditor myEditor;
-  Project myProject;
-  Object lastValue;
+public class ArrayTableCellEditor extends AbstractCellEditor implements TableCellEditor {
+  private MyTableEditor myEditor;
+  private final Project myProject;
+  private Object myLastValue;
+
+  private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.debugger.array.ArrayTableCellEditor");
 
   public ArrayTableCellEditor(Project project) {
-    super();
     myProject = project;
   }
 
   public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
                                                final int rowIndex, final int vColIndex) {
     myEditor = new MyTableEditor(myProject, new PyDebuggerEditorsProvider(), "numpy.array.table.view", null,
-                                 new XExpressionImpl(value.toString(), PythonLanguage.getInstance(), "", EvaluationMode.CODE_FRAGMENT));
-    lastValue = value;
-    JComponent editorComponent = myEditor.getComponent();
-
-    editorComponent.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
-      .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "strokeEnter");
-    editorComponent.getActionMap().put("strokeEnter", new AbstractAction() {
-      @Override
-      public void actionPerformed(ActionEvent e) {
-        doOKAction(rowIndex, vColIndex);
-      }
-    });
-    editorComponent.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
-      .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escapeStroke");
-    editorComponent.getActionMap().put("escapeStroke", new AbstractAction() {
-      @Override
-      public void actionPerformed(ActionEvent e) {
-        cancelEditing();
-      }
-    });
-
-    return editorComponent;
+                                 new XExpressionImpl(value.toString(), PythonLanguage.getInstance(), "", EvaluationMode.CODE_FRAGMENT),
+                                 getActionsAdapter(rowIndex, vColIndex));
+    myLastValue = value;
+    return myEditor.getComponent();
   }
 
+  @Nullable
   public Object getCellEditorValue() {
     if (myEditor.getEditor() != null) {
       return myEditor.getEditor().getDocument().getText();
     }
-    else {
-      return null;
-    }
+    return null;
+  }
+
+  @NotNull
+  private KeyAdapter getActionsAdapter(final int rowIndex, final int vColIndex) {
+    return new KeyAdapter() {
+      @Override
+      public void keyPressed(KeyEvent e) {
+        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+          doOKAction(rowIndex, vColIndex);
+        }
+        else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
+          cancelEditing();
+        }
+      }
+    };
   }
 
   public void doOKAction(int rowIndex, int vColIndex) {
@@ -95,7 +93,7 @@ class ArrayTableCellEditor extends AbstractCellEditor implements TableCellEditor
     new WriteCommandAction(null) {
       protected void run(@NotNull Result result) throws Throwable {
         if (myEditor.getEditor() != null) {
-          myEditor.getEditor().getDocument().setText(lastValue.toString());
+          myEditor.getEditor().getDocument().setText(myLastValue.toString());
         }
       }
     }.execute();
@@ -103,14 +101,22 @@ class ArrayTableCellEditor extends AbstractCellEditor implements TableCellEditor
     stopCellEditing();
   }
 
-  public class MyTableEditor extends XDebuggerEditorBase {
+  public MyTableEditor getEditor() {
+    return myEditor;
+  }
+
+  public void setLastValue(Object lastValue) {
+    myLastValue = lastValue;
+  }
+
+  public static class MyTableEditor extends XDebuggerEditorBase {
     private final EditorTextField myEditorTextField;
-    private XExpression myExpression;
+    private final XExpression myExpression;
 
     public MyTableEditor(Project project,
                          XDebuggerEditorsProvider debuggerEditorsProvider,
                          @Nullable @NonNls String historyId,
-                         @Nullable XSourcePosition sourcePosition, @NotNull XExpression text) {
+                         @Nullable XSourcePosition sourcePosition, @NotNull XExpression text, @NotNull final KeyAdapter actionAdapter) {
       super(project, debuggerEditorsProvider, EvaluationMode.CODE_FRAGMENT, historyId, sourcePosition);
       myExpression = XExpressionImpl.changeMode(text, getMode());
       myEditorTextField = new EditorTextField(createDocument(myExpression), project, debuggerEditorsProvider.getFileType()) {
@@ -119,6 +125,7 @@ class ArrayTableCellEditor extends AbstractCellEditor implements TableCellEditor
           final EditorEx editor = super.createEditor();
           editor.setVerticalScrollbarVisible(false);
           editor.setOneLineMode(true);
+          editor.getContentComponent().addKeyListener(actionAdapter);
           return editor;
         }
 
@@ -136,7 +143,7 @@ class ArrayTableCellEditor extends AbstractCellEditor implements TableCellEditor
     }
 
     @Override
-    protected void doSetText(XExpression text) {
+    protected void setEditorText(XExpression text) {
       myEditorTextField.setText(text.getExpression());
     }
 
index 08e8d6021c41d9da53801848f06dca7d1e2d7d0e..5eebbd18ccb4111fd3c28ac549e639ce8e6b813f 100644 (file)
  */
 package com.jetbrains.python.debugger.array;
 
-import com.intellij.openapi.util.Pair;
 import com.intellij.ui.JBColor;
-import org.jetbrains.annotations.NotNull;
+import com.intellij.util.ui.UIUtil;
 
 import javax.swing.*;
 import javax.swing.border.LineBorder;
 import javax.swing.table.DefaultTableCellRenderer;
 import java.awt.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 /**
  * @author amarch
@@ -35,11 +32,9 @@ class ArrayTableCellRenderer extends DefaultTableCellRenderer {
   private double myMax = Double.MIN_VALUE;
   private String myComplexMin;
   private String myComplexMax;
-  private boolean colored = true;
+  private boolean myColored = true;
   private String myType;
 
-  private static final Pattern PY_COMPLEX_NUMBER = Pattern.compile("([+-]?[.\\d^j]*)([+-]?[e.\\d]*j)?");
-
   public ArrayTableCellRenderer(double min, double max, String type) {
     setHorizontalAlignment(CENTER);
     setHorizontalTextPosition(LEFT);
@@ -50,7 +45,7 @@ class ArrayTableCellRenderer extends DefaultTableCellRenderer {
   }
 
   public void setColored(boolean colored) {
-    this.colored = colored;
+    myColored = colored;
   }
 
   public Component getTableCellRendererComponent(JTable table, Object value,
@@ -65,75 +60,24 @@ class ArrayTableCellRenderer extends DefaultTableCellRenderer {
     }
 
     if (myMax != myMin) {
-      if (colored && value != null) {
+      if (myColored && value != null) {
         try {
-          double rangedValue = getRangedValue(value.toString());
+          double rangedValue = NumpyArrayValueProvider.getRangedValue(value.toString(), myType, myMin, myMax, myComplexMax, myComplexMin);
           this.setBackground(
             new JBColor(new Color((int)Math.round(255 * rangedValue), 0, (int)Math.round(255 * (1 - rangedValue)), 130),
-                        new Color(0, 0, 0, 0)));
+                        new Color((int)Math.round(255 * rangedValue), 0, (int)Math.round(255 * (1 - rangedValue)), 130)));
         }
         catch (NumberFormatException ignored) {
         }
       }
       else {
-        this.setBackground(new JBColor(new Color(255, 255, 255, 0), new Color(255, 255, 255, 0)));
+        this.setBackground(new JBColor(UIUtil.getBgFillColor(table), UIUtil.getBgFillColor(table)));
       }
     }
 
     return this;
   }
 
-  /**
-   * @return double presentation from [0:1] range
-   */
-  private double getRangedValue(String value) {
-    if ("iuf".contains(myType)) {
-      return (Double.parseDouble(value) - myMin) / (myMax - myMin);
-    }
-    else if ("b".equals(myType)) {
-      return value.equals("True") ? 1 : 0;
-    }
-    else if ("c".equals(myType)) {
-      return getComplexRangedValue(value);
-    }
-    return 0;
-  }
-
-  /**
-   * type complex128 in numpy is compared by next rule:
-   * A + Bj > C +Dj if A > C or A == C and B > D
-   */
-  private double getComplexRangedValue(String value) {
-    Pair<Double, Double> med = parsePyComplex(value);
-    Pair<Double, Double> max = parsePyComplex(myComplexMax);
-    Pair<Double, Double> min = parsePyComplex(myComplexMin);
-    double range = (med.first - min.first) / (max.first - min.first);
-    if (max.first.equals(min.first)) {
-      range = (med.second - min.second) / (max.second - min.second);
-    }
-    return range;
-  }
-
-  private static Pair<Double, Double> parsePyComplex(@NotNull String pyComplexValue) {
-    if (pyComplexValue.startsWith("(") && pyComplexValue.endsWith(")")) {
-      pyComplexValue = pyComplexValue.substring(1, pyComplexValue.length() - 1);
-    }
-    Matcher matcher = PY_COMPLEX_NUMBER.matcher(pyComplexValue);
-    if (matcher.matches()) {
-      String real = matcher.group(1);
-      String imag = matcher.group(2);
-      if (real.contains("j") && imag == null) {
-        return new Pair(new Double(0.0), Double.parseDouble(real.substring(0, real.length() - 1)));
-      }
-      else {
-        return new Pair(Double.parseDouble(real), Double.parseDouble(imag.substring(0, imag.length() - 1)));
-      }
-    }
-    else {
-      throw new IllegalArgumentException("Not a valid python complex value: " + pyComplexValue);
-    }
-  }
-
   public void setMin(double min) {
     myMin = min;
   }
diff --git a/python/src/com/jetbrains/python/debugger/array/ArrayTableComponent.java b/python/src/com/jetbrains/python/debugger/array/ArrayTableComponent.java
deleted file mode 100644 (file)
index b9e4b19..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.debugger.array;
-
-import com.intellij.ui.components.JBScrollPane;
-import com.intellij.ui.table.JBTable;
-import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
-
-import javax.swing.*;
-import javax.swing.table.DefaultTableModel;
-import java.awt.*;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-
-/**
- * @author amarch
- */
-class ArrayTableComponent extends JPanel {
-  private JScrollPane myScrollPane;
-  private JTextField mySliceTextField;
-  private JTextField myFormatTextField;
-  private JBTable myTable;
-  private JCheckBox myColoredCheckbox;
-
-  private static final String DATA_LOADING_IN_PROCESS = "Please wait, load array data.";
-
-  private static final String NOT_APPLICABLE = "View not applicable for ";
-
-  public ArrayTableComponent() {
-    super(new GridBagLayout());
-
-    mySliceTextField = new JTextField();
-    mySliceTextField.setToolTipText("Current slice");
-    mySliceTextField.setEditable(false);
-
-    myFormatTextField = new JTextField();
-    myFormatTextField.setToolTipText("Value format");
-    myFormatTextField.setEditable(false);
-
-    myTable = new JBTable() {
-      public boolean getScrollableTracksViewportWidth() {
-        return getPreferredSize().width < getParent().getWidth();
-      }
-    };
-    myTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
-    myTable.setRowSelectionAllowed(false);
-
-    myColoredCheckbox = new JCheckBox();
-    myColoredCheckbox.setText("Colored");
-    myColoredCheckbox.setSelected(true);
-    myColoredCheckbox.addItemListener(new ItemListener() {
-      @Override
-      public void itemStateChanged(ItemEvent e) {
-        if (e.getSource() == myColoredCheckbox) {
-          if (myTable.getColumnCount() > 0 && myTable.getCellRenderer(0, 0) instanceof ArrayTableCellRenderer) {
-            ArrayTableCellRenderer renderer = (ArrayTableCellRenderer)myTable.getCellRenderer(0, 0);
-            if (myColoredCheckbox.isSelected()) {
-              renderer.setColored(true);
-            }
-            else {
-              renderer.setColored(false);
-            }
-          }
-          myScrollPane.repaint();
-        }
-      }
-    });
-
-    myScrollPane = new JBScrollPane(myTable);
-    myScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
-    myScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
-
-    JTable rowTable = new RowHeaderTable(myTable);
-    myScrollPane.setRowHeaderView(rowTable);
-    myScrollPane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER,
-                           rowTable.getTableHeader());
-
-    add(myScrollPane,
-        new GridBagConstraints(0, 0, 4, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
-    add(mySliceTextField,
-        new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
-    add(new JLabel("Format:"),
-        new GridBagConstraints(1, 1, 1, 1, 1, 0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
-    add(myFormatTextField,
-        new GridBagConstraints(2, 1, 1, 1, 1, 0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
-    add(myColoredCheckbox,
-        new GridBagConstraints(3, 1, 1, 1, 1, 0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
-  }
-
-  public JTextField getSliceTextField() {
-    return mySliceTextField;
-  }
-
-  public JTextField getFormatTextField() {
-    return myFormatTextField;
-  }
-
-  public JBTable getTable() {
-    return myTable;
-  }
-
-  public JCheckBox getColored() {
-    return myColoredCheckbox;
-  }
-
-  private void setSpinnerText(String text) {
-    DefaultTableModel model = new DefaultTableModel(1, 1) {
-      @Override
-      public boolean isCellEditable(int row, int column) {
-        return false;
-      }
-    };
-    myTable.setModel(model);
-    myTable.setValueAt(text, 0, 0);
-  }
-
-  public void setDefaultSpinnerText() {
-    setSpinnerText(DATA_LOADING_IN_PROCESS);
-  }
-
-  public void setErrorSpinnerText(Exception e) {
-    setSpinnerText(e.getMessage());
-  }
-
-  public void setErrorSpinnerText(String message) {
-    //todo: Access to realized (ever shown) UI components
-    // should be done only from the AWT event dispatch thread,
-    // revalidate(), invalidate() & repaint() is ok from any thread
-    setSpinnerText(message);
-  }
-
-  public void setNotApplicableSpinner(XValueNodeImpl node) {
-    setSpinnerText(NOT_APPLICABLE + node.getName());
-  }
-}
index 1e99c5d8249b5b111881869b0309fc2a9e885e03..0f7c1aaab5c37244fc1cd5708240bc090c553300 100644 (file)
@@ -21,6 +21,7 @@ import com.intellij.ui.components.JBScrollPane;
 import com.intellij.ui.table.JBTable;
 import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
 import com.jetbrains.python.PythonFileType;
+import org.jetbrains.annotations.NotNull;
 
 import javax.swing.*;
 import javax.swing.event.ListSelectionEvent;
@@ -41,20 +42,22 @@ public class ArrayTableForm {
   private JLabel myFormatLabel;
   private JPanel myFormatPanel;
   private JPanel myMainPanel;
-  public JBTable myTable;
+  private JBTable myTable;
   private JBTable myBusyTable;
-  private Project myProject;
+  private final Project myProject;
 
 
   private static final String DATA_LOADING_IN_PROCESS = "Please wait, load array data.";
   private static final String NOT_APPLICABLE = "View not applicable for ";
 
-  public ArrayTableForm(Project project) {
+  public ArrayTableForm(@NotNull Project project) {
     myProject = project;
   }
 
   private void createUIComponents() {
-    myTable = new JBTableWithRows();
+    mySliceTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE);
+
+    myTable = new JBTableWithRowHeaders();
     myTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
     myTable.setRowSelectionAllowed(false);
     myTable.setTableHeader(new CustomTableHeader(myTable));
@@ -62,15 +65,12 @@ public class ArrayTableForm {
     myTable.getTableHeader().setReorderingAllowed(false);
 
     myScrollPane = PagingTableModel.LazyViewport.createLazyScrollPaneFor(myTable);
-    JTable rowTable = new RowHeaderTable(myTable);
+    JTable rowTable = new JBTableWithRowHeaders.RowHeaderTable(myTable);
     myScrollPane.setRowHeaderView(rowTable);
     myScrollPane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER,
                            rowTable.getTableHeader());
 
-    mySliceTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE);
-
-    ((JBTableWithRows)myTable).setRowHeaderTable((RowHeaderTable)rowTable);
-    ((JBTableWithRows)myTable).setSliceField(mySliceTextField);
+    ((JBTableWithRowHeaders)myTable).setRowHeaderTable((JBTableWithRowHeaders.RowHeaderTable)rowTable);
 
     myFormatTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE);
 
@@ -80,31 +80,6 @@ public class ArrayTableForm {
     myBusyTable.setBorder(BorderFactory.createEmptyBorder());
   }
 
-  public static class JBTableWithRows extends JBTable {
-    private RowHeaderTable myRowHeaderTable;
-    private EditorTextField mySliceField;
-
-    public boolean getScrollableTracksViewportWidth() {
-      return getPreferredSize().width < getParent().getWidth();
-    }
-
-    public RowHeaderTable getRowHeaderTable() {
-      return myRowHeaderTable;
-    }
-
-    public void setRowHeaderTable(RowHeaderTable rowHeaderTable) {
-      myRowHeaderTable = rowHeaderTable;
-    }
-
-    public EditorTextField getSliceField() {
-      return mySliceField;
-    }
-
-    public void setSliceField(EditorTextField sliceField) {
-      mySliceField = sliceField;
-    }
-  }
-
   public EditorTextField getSliceTextField() {
     return mySliceTextField;
   }
index d14aead4e478e860601619d4c5c8ef8020ef60a4..136544e598fe83fbe7611dc96e02423a8284e1a3 100644 (file)
@@ -18,14 +18,16 @@ package com.jetbrains.python.debugger.array;
 import com.intellij.xdebugger.frame.XValueNode;
 import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
 import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
+import org.jetbrains.annotations.NotNull;
 
 /**
-* @author amarch
-*/
+ * @author amarch
+ */
 abstract class ArrayValueProvider {
-  XValueNode myBaseNode;
 
-  public ArrayValueProvider(XValueNode node){
+  @NotNull protected final XValueNode myBaseNode;
+
+  public ArrayValueProvider(@NotNull XValueNode node) {
     myBaseNode = node;
   }
 
diff --git a/python/src/com/jetbrains/python/debugger/array/ComparableArrayChunk.java b/python/src/com/jetbrains/python/debugger/array/ComparableArrayChunk.java
deleted file mode 100644 (file)
index 60dc1be..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.debugger.array;
-
-/**
- * @author amarch
- */
-public class ComparableArrayChunk extends ArrayChunk implements Comparable<ComparableArrayChunk> {
-  public ComparableArrayChunk(String baseSlice, int rows, int columns, int rOffset, int cOffset) {
-    super(baseSlice, rows, columns, rOffset, cOffset);
-  }
-
-  @Override
-  void fillData(Runnable callback) {
-    return;
-  }
-
-  @Override
-  public int compareTo(ComparableArrayChunk other) {
-    int compRow = rOffset - other.rOffset;
-    int compCol = cOffset - other.cOffset;
-
-    if (compRow != 0) {
-      return compRow;
-    }
-    else {
-      return compCol;
-    }
-  }
-}
diff --git a/python/src/com/jetbrains/python/debugger/array/JBTableWithRowHeaders.java b/python/src/com/jetbrains/python/debugger/array/JBTableWithRowHeaders.java
new file mode 100644 (file)
index 0000000..5818460
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.debugger.array;
+
+import com.intellij.ui.table.JBTable;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableColumn;
+import java.awt.*;
+import java.awt.event.MouseListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+/**
+ * @author amarch
+ */
+public class JBTableWithRowHeaders extends JBTable {
+  private RowHeaderTable myRowHeaderTable;
+
+  public boolean getScrollableTracksViewportWidth() {
+    return getPreferredSize().width < getParent().getWidth();
+  }
+
+  public RowHeaderTable getRowHeaderTable() {
+    return myRowHeaderTable;
+  }
+
+  public void setRowHeaderTable(RowHeaderTable rowHeaderTable) {
+    myRowHeaderTable = rowHeaderTable;
+  }
+
+  public static class RowHeaderTable extends JBTable implements PropertyChangeListener, TableModelListener {
+    private JBTable myMainTable;
+    private int myRowShift = 0;
+
+    public RowHeaderTable(JBTable table) {
+      myMainTable = table;
+      myMainTable.getModel().addTableModelListener(this);
+
+      setFocusable(false);
+      setAutoCreateColumnsFromModel(false);
+      setSelectionModel(myMainTable.getSelectionModel());
+      setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+      TableColumn column = new TableColumn();
+      column.setHeaderValue(" ");
+      addColumn(column);
+      column.setCellRenderer(new RowNumberRenderer());
+
+      getColumnModel().getColumn(0).setPreferredWidth(50);
+      setPreferredScrollableViewportSize(getPreferredSize());
+      setRowHeight(myMainTable.getRowHeight());
+      MouseListener[] listeners = getMouseListeners();
+      for (MouseListener l : listeners) {
+        removeMouseListener(l);
+      }
+    }
+
+    @Override
+    protected void paintComponent(@NotNull Graphics g) {
+      getEmptyText().setText("");
+      super.paintComponent(g);
+    }
+
+    @Override
+    public int getRowCount() {
+      return myMainTable.getRowCount();
+    }
+
+    @Override
+    public int getRowHeight(int row) {
+      setRowHeight(myMainTable.getRowHeight());
+      return super.getRowHeight(row);
+    }
+
+    @Override
+    public Object getValueAt(int row, int column) {
+      return Integer.toString(row + myRowShift);
+    }
+
+    public void setRowShift(int shift) {
+      myRowShift = shift;
+    }
+
+    @Override
+    public boolean isCellEditable(int row, int column) {
+      return false;
+    }
+
+
+    @Override
+    public void setValueAt(Object value, int row, int column) {
+    }
+
+    public void propertyChange(PropertyChangeEvent e) {
+      if ("selectionModel".equals(e.getPropertyName())) {
+        setSelectionModel(myMainTable.getSelectionModel());
+      }
+
+      if ("rowHeight".equals(e.getPropertyName())) {
+        repaint();
+      }
+
+      if ("model".equals(e.getPropertyName())) {
+        myMainTable.getModel().addTableModelListener(this);
+        revalidate();
+      }
+    }
+
+    @Override
+    public void tableChanged(TableModelEvent e) {
+      revalidate();
+    }
+
+    private class RowNumberRenderer extends DefaultTableCellRenderer {
+      public RowNumberRenderer() {
+        setHorizontalAlignment(SwingConstants.CENTER);
+      }
+
+      public Component getTableCellRendererComponent(
+        JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+        if (table != null) {
+          JTableHeader header = table.getTableHeader();
+
+          if (header != null) {
+            setForeground(header.getForeground());
+            setBackground(header.getBackground());
+            setFont(header.getFont());
+          }
+        }
+
+        if (isSelected) {
+          setFont(getFont().deriveFont(Font.BOLD));
+        }
+
+        setText((value == null) ? "" : value.toString());
+        setBorder(UIManager.getBorder("TableHeader.cellBorder"));
+
+        return this;
+      }
+    }
+  }
+}
index 5158f74f59bc9841c89e05e101920b8b7b303513..be318d591b5035b52c49b7c924604e4e7aebc278 100644 (file)
@@ -1,5 +1,6 @@
 package com.jetbrains.python.debugger.array;
 
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
 import com.intellij.xdebugger.frame.XValue;
 import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
@@ -17,11 +18,13 @@ import java.util.List;
  * @author amarch
  */
 
-public class NumpyArraySlice extends ComparableArrayChunk {
+public class NumpyArraySlice extends ArrayChunk {
   private NumpyArrayValueProvider myValueProvider;
   private DataEvaluator myDataEvaluator;
   private String myFormat;
 
+  private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.debugger.array.NumpyArraySlice");
+
   public NumpyArraySlice(String baseSlice,
                          int rows,
                          int columns,
@@ -36,21 +39,22 @@ public class NumpyArraySlice extends ComparableArrayChunk {
   }
 
   public String getPresentation() {
-    String onlyChunkSlice = "[" + rOffset + ":" + (rOffset + rows) + ", " + cOffset + ":" + (cOffset + columns) + "]";
+    String onlyChunkSlice =
+      "[" + getRowOffset() + ":" + (getRowOffset() + getRows()) + ", " + getColOffset() + ":" + (getColOffset() + getColumns()) + "]";
     if (isOneColumn() && isOneRow()) {
       onlyChunkSlice = "";
     }
     else if (isOneRow()) {
-      onlyChunkSlice = "[" + cOffset + ":" + (cOffset + columns) + "]";
+      onlyChunkSlice = "[" + getColOffset() + ":" + (getColOffset() + getColumns()) + "]";
     }
     else if (isOneColumn()) {
-      onlyChunkSlice = "[" + rOffset + ":" + (rOffset + rows) + "]";
+      onlyChunkSlice = "[" + getRowOffset() + ":" + (getRowOffset() + getRows()) + "]";
     }
 
-    if (baseSlice.endsWith(onlyChunkSlice)) {
-      return baseSlice;
+    if (getBaseSlice().endsWith(onlyChunkSlice)) {
+      return getBaseSlice();
     }
-    return baseSlice + onlyChunkSlice;
+    return getBaseSlice() + onlyChunkSlice;
   }
 
   @Override
@@ -76,7 +80,7 @@ public class NumpyArraySlice extends ComparableArrayChunk {
     }
 
     public boolean dataFilled() {
-      return rows > 0 && myFilledRows == rows;
+      return getRows() > 0 && myFilledRows == getRows();
     }
 
     public void evaluateData(final Runnable callback) {
@@ -129,8 +133,9 @@ public class NumpyArraySlice extends ComparableArrayChunk {
             }
           }
 
-          if (row > rows) {
-            throw new IllegalStateException("Row " + row + " is out of range for " + getPresentation() + ".");
+          if (row > getRows()) {
+            LOG.error("Row " + row + " is out of range for " + getPresentation() + ".");
+            return;
           }
 
           if (row != -1 && myData[row][0] == null) {
@@ -157,7 +162,7 @@ public class NumpyArraySlice extends ComparableArrayChunk {
               myData[row][0] = rawValue;
             }
             myFilledRows += 1;
-            if (myFilledRows == rows) {
+            if (myFilledRows == getRows()) {
               node.getTree().removeTreeListener(this);
               callback.run();
             }
@@ -170,7 +175,7 @@ public class NumpyArraySlice extends ComparableArrayChunk {
       };
 
       myData =
-        new Object[rows][columns];
+        new Object[getRows()][getColumns()];
       myValueProvider.getTree().addTreeListener(treeListener);
       nextRow = 0;
       myFilledRows = 0;
@@ -178,13 +183,14 @@ public class NumpyArraySlice extends ComparableArrayChunk {
     }
 
     private void startEvalNextRow(XDebuggerEvaluator.XEvaluationCallback callback) {
-      if (nextRow >= rows) {
-        throw new IllegalStateException("Row " + nextRow + " is out of range for " + getPresentation() + ".");
+      if (nextRow >= getRows()) {
+        LOG.error("Row " + nextRow + " is out of range for " + getPresentation() + ".");
+        return;
       }
 
       String evalRowCommand = "map(lambda l: " + myValueProvider.evalTypeFunc(myFormat) + ", list(" + getPresentation();
       if (!isOneRow() && !isOneColumn()) {
-        evalRowCommand += "[" + nextRow + ", 0:" + columns + "]))";
+        evalRowCommand += "[" + nextRow + ", 0:" + getColumns() + "]))";
       }
 
       if (isOneRow() && isOneColumn()) {
@@ -195,20 +201,12 @@ public class NumpyArraySlice extends ComparableArrayChunk {
         evalRowCommand += "[" + nextRow + "]";
       }
       else if (isOneRow()) {
-        evalRowCommand += "[0:" + columns + "]))";
+        evalRowCommand += "[0:" + getColumns() + "]))";
       }
       myValueProvider.getEvaluator().evaluate(evalRowCommand, callback, null);
     }
   }
 
-  private boolean isOneRow() {
-    return rows == 1;
-  }
-
-  private boolean isOneColumn() {
-    return columns == 1;
-  }
-
   public Object[][] getData() {
     return myDataEvaluator.getData();
   }
index 18f23ef1c7b7f369f6315f1852d339c74f801e66..fd98c5fc7d0d2174b189f8173296d54a316788e7 100644 (file)
@@ -18,6 +18,7 @@ package com.jetbrains.python.debugger.array;
 import com.intellij.codeInsight.hint.HintManager;
 import com.intellij.openapi.application.Result;
 import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.RangeMarker;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Pair;
@@ -35,12 +36,13 @@ import com.jetbrains.python.debugger.PyDebuggerEvaluator;
 import org.jetbrains.annotations.NotNull;
 
 import javax.management.InvalidAttributeValueException;
-import javax.swing.*;
 import javax.swing.table.TableCellEditor;
 import java.awt.*;
 import java.awt.event.*;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * @author amarch
@@ -56,7 +58,7 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
   private int[] myShape;
   private ArrayTableCellRenderer myTableCellRenderer;
   private PagingTableModel myPagingModel;
-  private boolean lastFinished = false;
+  private boolean lastSuccessful = false;
 
   private final static int COLUMNS_IN_DEFAULT_SLICE = 40;
   private final static int ROWS_IN_DEFAULT_SLICE = 40;
@@ -64,11 +66,15 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
   private final static int COLUMNS_IN_DEFAULT_VIEW = 1000;
   private final static int ROWS_IN_DEFAULT_VIEW = 1000;
 
+  private static final Pattern PY_COMPLEX_NUMBER = Pattern.compile("([+-]?[.\\d^j]*)([+-]?[e.\\d]*j)?");
+
   private final static int HUGE_ARRAY_SIZE = 1000 * 1000;
   private final static String LOAD_SMALLER_SLICE = "Full slice too large and would slow down debugger, shrunk to smaller slice.";
   private final static String DISABLE_COLOR_FOR_HUGE_ARRAY =
     "Disable color because array too big and calculating min and max would slow down debugging.";
 
+  private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.debugger.array.NumpyArrayValueProvider");
+
   public NumpyArrayValueProvider(@NotNull XValueNode node, PyViewArrayAction.MyDialog dialog, @NotNull Project project) {
     super(node);
     myDialog = dialog;
@@ -90,7 +96,7 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
     return new PagingTableModel(rows, columns, rendered, this, mainSlice) {
 
       private final String myFormat = mainSlice.getFormat();
-      private final String myBaseSlice = mainSlice.baseSlice;
+      private final String myBaseSlice = mainSlice.getBaseSlice();
 
       @Override
       protected NumpyArraySlice createChunk(int rows, int columns, int rOffset, int cOffset) {
@@ -98,9 +104,10 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
       }
 
       @Override
-      protected Runnable getDataEvaluator(final ComparableArrayChunk chunk) {
-        final NumpyArraySlice arraySlice = new NumpyArraySlice(chunk.baseSlice, chunk.rows, chunk.columns, chunk.rOffset, chunk.cOffset,
-                                                               myFormat, getInstance());
+      protected Runnable getDataEvaluator(final ArrayChunk chunk) {
+        final NumpyArraySlice arraySlice =
+          new NumpyArraySlice(chunk.getBaseSlice(), chunk.getRows(), chunk.getColumns(), chunk.getRowOffset(), chunk.getColOffset(),
+                              myFormat, getInstance());
 
         if (arraySlice.getFormat().isEmpty()) {
           arraySlice.setFormat(getDefaultFormat());
@@ -113,24 +120,10 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
                 @Override
                 public void run() {
                   //check that we still running on the right model
-                  if (!myBaseSlice.equals(getModelFullChunk().baseSlice) || !myFormat.equals(getModelFullChunk().getFormat())) {
+                  if (!myBaseSlice.equals(getModelFullChunk().getBaseSlice()) || !myFormat.equals(getModelFullChunk().getFormat())) {
                     return;
                   }
-
-                  myLastPresentation = arraySlice;
-                  lastFinished = true;
-                  getPendingSet().remove(chunk);
-                  notifyNextThread();
-                  fireTableCellUpdated(chunk.rOffset, chunk.cOffset);
-                  DebuggerUIUtil.invokeLater(new Runnable() {
-                    public void run() {
-                      addDataInCache(arraySlice.rOffset, arraySlice.cOffset, arraySlice.getData());
-
-                      myTable.setDefaultEditor(myTable.getColumnClass(0), getArrayTableCellEditor());
-                      myTable.setDefaultRenderer(myTable.getColumnClass(0), myTableCellRenderer);
-                      myDialog.setTitle(getTitlePresentation(getSliceText()));
-                    }
-                  });
+                  notifyChunkLoaded(arraySlice);
                 }
               });
             }
@@ -210,23 +203,31 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
   }
 
   private void initSliceFieldActions() {
-    myComponent.getSliceTextField().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
-      .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "strokeEnter");
-    myComponent.getSliceTextField().getActionMap().put("strokeEnter", new AbstractAction() {
+    if (myComponent.getSliceTextField().getEditor() == null) {
+      LOG.error("Null editor in slice field.");
+      return;
+    }
+    myComponent.getSliceTextField().getEditor().getContentComponent().addKeyListener(new KeyAdapter() {
       @Override
-      public void actionPerformed(ActionEvent e) {
-        doReslice(getSliceText(), null);
+      public void keyPressed(KeyEvent e) {
+        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+          doReslice(getSliceText(), null);
+        }
       }
     });
   }
 
   private void initFormatFieldActions() {
-    myComponent.getFormatTextField().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
-      .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "strokeEnter");
-    myComponent.getFormatTextField().getActionMap().put("strokeEnter", new AbstractAction() {
+    if (myComponent.getFormatTextField().getEditor() == null) {
+      LOG.error("Null editor in format field.");
+      return;
+    }
+    myComponent.getFormatTextField().getEditor().getContentComponent().addKeyListener(new KeyAdapter() {
       @Override
-      public void actionPerformed(ActionEvent e) {
-        doApplyFormat();
+      public void keyPressed(KeyEvent e) {
+        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+          doApplyFormat();
+        }
       }
     });
   }
@@ -276,6 +277,9 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
         myComponent.getSliceTextField().setText(getDefaultPresentation());
         myComponent.getFormatTextField().setText(getDefaultFormat());
         myDialog.setTitle(getTitlePresentation(getDefaultPresentation()));
+        if (myTable.getColumnCount() > 0) {
+          myTable.setDefaultEditor(myTable.getColumnClass(0), getArrayTableCellEditor());
+        }
       }
     });
     startFillTable(new NumpyArraySlice(getDefaultPresentation(), Math.min(getMaxRow(myShape), ROWS_IN_DEFAULT_VIEW),
@@ -472,12 +476,12 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
 
   private void startFillTable(final NumpyArraySlice arraySlice, boolean rendered, final boolean inPlace) {
     if (myLastPresentation != null &&
-        arraySlice.baseSlice.equals(myLastPresentation.baseSlice) &&
-        arraySlice.getFormat().equals(myLastPresentation.getFormat()) && lastFinished) {
+        arraySlice.getBaseSlice().equals(myLastPresentation.getBaseSlice()) &&
+        arraySlice.getFormat().equals(myLastPresentation.getFormat()) && lastSuccessful) {
       return;
     }
 
-    lastFinished = false;
+    lastSuccessful = false;
     myPagingModel = getPagingModel(myShape, rendered, arraySlice);
 
     DebuggerUIUtil.invokeLater(new Runnable() {
@@ -486,7 +490,7 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
         myTable.setModel(myPagingModel);
         if (!inPlace) {
           myComponent.getScrollPane().getViewport().setViewPosition(new Point(0, 0));
-          RowHeaderTable rowTable = ((ArrayTableForm.JBTableWithRows)myTable).getRowHeaderTable();
+          JBTableWithRowHeaders.RowHeaderTable rowTable = ((JBTableWithRowHeaders)myTable).getRowHeaderTable();
           rowTable.setRowShift(0);
         }
         ((PagingTableModel)myTable.getModel()).fireTableDataChanged();
@@ -516,11 +520,11 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
       }
 
       private String changeValExpression() {
-        if (myEditor.getEditor() == null) {
+        if (getEditor().getEditor() == null) {
           throw new IllegalStateException("Null editor in table cell.");
         }
 
-        return getCellSlice() + " = " + myEditor.getEditor().getDocument().getText();
+        return getCellSlice() + " = " + getEditor().getEditor().getDocument().getText();
       }
 
 
@@ -533,7 +537,7 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
       @Override
       public void doOKAction(final int row, final int col) {
 
-        if (myEditor.getEditor() == null) {
+        if (getEditor().getEditor() == null) {
           return;
         }
 
@@ -571,14 +575,14 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
 
                 new WriteCommandAction(null) {
                   protected void run(@NotNull Result result) throws Throwable {
-                    if (myEditor.getEditor() != null) {
-                      myEditor.getEditor().getDocument().setText(corrected);
+                    if (getEditor().getEditor() != null) {
+                      getEditor().getEditor().getDocument().setText(corrected);
                       ((PagingTableModel)myTable.getModel()).forcedChange(row, col, corrected);
                       cancelEditing();
                     }
                   }
                 }.execute();
-                lastValue = corrected;
+                setLastValue(corrected);
               }
 
               @Override
@@ -630,7 +634,7 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
 
   public void showError(String message, NumpyArraySlice chunk) {
     if (!chunk.getFormat().equals(getModelFullChunk().getFormat()) ||
-        !chunk.baseSlice.equals(getModelFullChunk().baseSlice)) {
+        !chunk.getBaseSlice().equals(getModelFullChunk().getBaseSlice())) {
       //ignore error message from previous task
       return;
     }
@@ -711,7 +715,7 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
 
   private static String getEvalShapeCommand(@NotNull String slice) {
     //add information about memory, see #parseShape comments
-    return "str(" + slice + ".shape)+'#'+str(" + slice + ".flags['C_CONTIGUOUS'])";
+    return "repr(" + slice + ".shape)+'#'+repr(" + slice + ".flags['C_CONTIGUOUS'])";
   }
 
   private void clearErrorMessage() {
@@ -767,8 +771,22 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
     return 0;
   }
 
-  public void notifyNextThread() {
-    myPagingModel.runNextThread();
+  public void notifyChunkLoaded(final NumpyArraySlice arraySlice) {
+    myLastPresentation = arraySlice;
+    lastSuccessful = true;
+    myPagingModel.addDataInCache(arraySlice.getRowOffset(), arraySlice.getColOffset(), arraySlice.getData());
+    myPagingModel.runNextLoadingTask();
+    DebuggerUIUtil.invokeLater(new Runnable() {
+      public void run() {
+        myTable.setDefaultRenderer(myTable.getColumnClass(0), myTableCellRenderer);
+        myDialog.setTitle(getTitlePresentation(getSliceText()));
+        for (int r = 0; r < arraySlice.getRows(); r++) {
+          for (int c = 0; c < arraySlice.getColumns(); c++) {
+            myPagingModel.fireTableCellUpdated(r + arraySlice.getRowOffset(), c + arraySlice.getColOffset());
+          }
+        }
+      }
+    });
   }
 
   public void setBusy(final boolean busy) {
@@ -783,4 +801,55 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
   private NumpyArraySlice getModelFullChunk() {
     return (NumpyArraySlice)myPagingModel.getFullChunk();
   }
+
+  /**
+   * @return double presentation from [0:1] range
+   */
+  public static double getRangedValue(String value, String type, double min, double max, String complexMax, String complexMin) {
+    if ("iuf".contains(type)) {
+      return (Double.parseDouble(value) - min) / (max - min);
+    }
+    else if ("b".equals(type)) {
+      return value.equals("True") ? 1 : 0;
+    }
+    else if ("c".equals(type)) {
+      return getComplexRangedValue(value, complexMax, complexMin);
+    }
+    return 0;
+  }
+
+  /**
+   * type complex128 in numpy is compared by next rule:
+   * A + Bj > C +Dj if A > C or A == C and B > D
+   */
+  private static double getComplexRangedValue(String value, String complexMax, String complexMin) {
+    Pair<Double, Double> med = parsePyComplex(value);
+    Pair<Double, Double> max = parsePyComplex(complexMax);
+    Pair<Double, Double> min = parsePyComplex(complexMin);
+    double range = (med.first - min.first) / (max.first - min.first);
+    if (max.first.equals(min.first)) {
+      range = (med.second - min.second) / (max.second - min.second);
+    }
+    return range;
+  }
+
+  private static Pair<Double, Double> parsePyComplex(@NotNull String pyComplexValue) {
+    if (pyComplexValue.startsWith("(") && pyComplexValue.endsWith(")")) {
+      pyComplexValue = pyComplexValue.substring(1, pyComplexValue.length() - 1);
+    }
+    Matcher matcher = PY_COMPLEX_NUMBER.matcher(pyComplexValue);
+    if (matcher.matches()) {
+      String real = matcher.group(1);
+      String imag = matcher.group(2);
+      if (real.contains("j") && imag == null) {
+        return new Pair(new Double(0.0), Double.parseDouble(real.substring(0, real.length() - 1)));
+      }
+      else {
+        return new Pair(Double.parseDouble(real), Double.parseDouble(imag.substring(0, imag.length() - 1)));
+      }
+    }
+    else {
+      throw new IllegalArgumentException("Not a valid python complex value: " + pyComplexValue);
+    }
+  }
 }
index e0f70b7d6d1eb66358095054276f69ef06cd79d7..7d020568c15e1bed7dc6a55f2cb88033ab965f27 100644 (file)
@@ -15,6 +15,7 @@
  */
 package com.jetbrains.python.debugger.array;
 
+import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.ui.components.JBScrollPane;
 import com.intellij.ui.components.JBViewport;
 import com.intellij.util.containers.HashMap;
@@ -22,7 +23,6 @@ import com.intellij.util.containers.Queue;
 
 import javax.swing.table.AbstractTableModel;
 import java.awt.*;
-import java.util.LinkedList;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
@@ -33,20 +33,19 @@ public abstract class PagingTableModel extends AbstractTableModel {
   public static final String EMPTY_CELL_VALUE = "...";
 
   private HashMap<String, Object[][]> myCachedData = new HashMap<String, Object[][]>();
-  private SortedSet<ComparableArrayChunk> myPendingSet = new TreeSet<ComparableArrayChunk>();
+  private SortedSet<ArrayChunk> myPendingSet = new TreeSet<ArrayChunk>();
   private Queue<String> cachedChunkKeys = new Queue<String>(DEFAULT_MAX_CACHED_SIZE + 1);
 
-  private LinkedList<Thread> myThreadList = new LinkedList<Thread>();
-  private Thread evaluatedThread;
+  private ArrayChunk evaluatedChunk;
 
   private boolean myRendered;
   private int myRows = 0;
   private int myColumns = 0;
   private NumpyArrayValueProvider myProvider;
-  private ComparableArrayChunk myFullChunk;
+  private ArrayChunk myFullChunk;
 
 
-  public PagingTableModel(int rows, int columns, boolean rendered, NumpyArrayValueProvider provider, ComparableArrayChunk fullChunk) {
+  public PagingTableModel(int rows, int columns, boolean rendered, NumpyArrayValueProvider provider, ArrayChunk fullChunk) {
     myRows = rows;
     myColumns = columns;
     myRendered = rendered;
@@ -113,32 +112,32 @@ public abstract class PagingTableModel extends AbstractTableModel {
     if (sz == 0) return false;
     if (sz == 1) {
       // special case (for speed)
-      ComparableArrayChunk seg = myPendingSet.first();
+      ArrayChunk seg = myPendingSet.first();
       return seg.contains(rOffset, cOffset);
     }
 
-    ComparableArrayChunk lo = createChunk(0, 0, getPageRowStart(rOffset), getPageColStart(cOffset));
-    ComparableArrayChunk hi = createChunk(0, 0, getPageRowStart(rOffset + CHUNK_ROW_SIZE), getPageColStart(cOffset + CHUNK_COL_SIZE));
+    ArrayChunk lo = createChunk(0, 0, getPageRowStart(rOffset), getPageColStart(cOffset));
+    ArrayChunk hi = createChunk(0, 0, getPageRowStart(rOffset + CHUNK_ROW_SIZE), getPageColStart(cOffset + CHUNK_COL_SIZE));
 
-    for (ComparableArrayChunk seg : myPendingSet.subSet(lo, hi)) {
+    for (ArrayChunk seg : myPendingSet.subSet(lo, hi)) {
       if (seg.contains(rOffset, cOffset)) return true;
     }
     return false;
   }
 
-  protected abstract ComparableArrayChunk createChunk(int rows, int columns, int rOffset, int cOffset);
+  protected abstract ArrayChunk createChunk(int rows, int columns, int rOffset, int cOffset);
 
-  protected abstract Runnable getDataEvaluator(final ComparableArrayChunk chunk);
+  protected abstract Runnable getDataEvaluator(final ArrayChunk chunk);
 
-  public void runNextThread() {
-    if (evaluatedThread != null) {
-      myThreadList.remove(evaluatedThread);
-      evaluatedThread = null;
+  public void runNextLoadingTask() {
+    if (evaluatedChunk != null) {
+      myPendingSet.remove(evaluatedChunk);
+      evaluatedChunk = null;
     }
 
-    if (myThreadList.size() > 0) {
-      evaluatedThread = myThreadList.get(0);
-      evaluatedThread.start();
+    if (myPendingSet.size() > 0) {
+      evaluatedChunk = myPendingSet.first();
+      ApplicationManager.getApplication().executeOnPooledThread(getDataEvaluator(evaluatedChunk));
       myProvider.setBusy(true);
     }
     else {
@@ -147,14 +146,11 @@ public abstract class PagingTableModel extends AbstractTableModel {
   }
 
   private void scheduleLoadData(final int rOffset, final int rLength, final int cOffset, final int cLength) {
-    final ComparableArrayChunk segment = createChunk(rLength, cLength, rOffset, cOffset);
+    final ArrayChunk segment = createChunk(rLength, cLength, rOffset, cOffset);
     myPendingSet.add(segment);
 
-    Runnable evaluator = getDataEvaluator(segment);
-    final Thread evalThread = new Thread(evaluator);
-    myThreadList.add(evalThread);
-    if (evaluatedThread == null) {
-      runNextThread();
+    if (evaluatedChunk == null) {
+      runNextLoadingTask();
     }
   }
 
@@ -167,12 +163,6 @@ public abstract class PagingTableModel extends AbstractTableModel {
       String old = cachedChunkKeys.pullFirst();
       myCachedData.remove(old);
     }
-
-    for (int r = 0; r < newData.length; r++) {
-      for (int c = 0; c < newData[0].length; c++) {
-        fireTableCellUpdated(r + rOffset, c + cOffset);
-      }
-    }
   }
 
   public int getColumnCount() {
@@ -187,19 +177,11 @@ public abstract class PagingTableModel extends AbstractTableModel {
     return myRows;
   }
 
-  public SortedSet<ComparableArrayChunk> getPendingSet() {
-    return myPendingSet;
-  }
-
   public void clearCached() {
     myCachedData = new HashMap<String, Object[][]>();
-    myPendingSet = new TreeSet<ComparableArrayChunk>();
+    myPendingSet = new TreeSet<ArrayChunk>();
     cachedChunkKeys = new Queue<String>(DEFAULT_MAX_CACHED_SIZE + 1);
-    if (evaluatedThread != null) {
-      evaluatedThread.interrupt();
-    }
-    evaluatedThread = null;
-    myThreadList = new LinkedList<Thread>();
+    evaluatedChunk = null;
   }
 
   public static class LazyViewport extends JBViewport {
@@ -234,7 +216,7 @@ public abstract class PagingTableModel extends AbstractTableModel {
     }
   }
 
-  public ComparableArrayChunk getFullChunk() {
+  public ArrayChunk getFullChunk() {
     return myFullChunk;
   }
 }
\ No newline at end of file
diff --git a/python/src/com/jetbrains/python/debugger/array/RowHeaderTable.java b/python/src/com/jetbrains/python/debugger/array/RowHeaderTable.java
deleted file mode 100644 (file)
index 0029525..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.debugger.array;
-
-import com.intellij.ui.table.JBTable;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import javax.swing.event.TableModelEvent;
-import javax.swing.event.TableModelListener;
-import javax.swing.table.DefaultTableCellRenderer;
-import javax.swing.table.JTableHeader;
-import javax.swing.table.TableColumn;
-import java.awt.*;
-import java.awt.event.MouseListener;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-
-public class RowHeaderTable extends JBTable implements PropertyChangeListener, TableModelListener {
-  private JTable main;
-  private int rowShift = 0;
-
-  public RowHeaderTable(JTable table) {
-    main = table;
-    main.getModel().addTableModelListener(this);
-
-    setFocusable(false);
-    setAutoCreateColumnsFromModel(false);
-    setSelectionModel(main.getSelectionModel());
-    setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
-    TableColumn column = new TableColumn();
-    column.setHeaderValue(" ");
-    addColumn(column);
-    column.setCellRenderer(new RowNumberRenderer());
-
-    getColumnModel().getColumn(0).setPreferredWidth(50);
-    setPreferredScrollableViewportSize(getPreferredSize());
-    setRowHeight(main.getRowHeight());
-    MouseListener[] listeners = getMouseListeners();
-    for (MouseListener l : listeners) {
-      removeMouseListener(l);
-    }
-  }
-
-  @Override
-  protected void paintComponent(@NotNull Graphics g) {
-    getEmptyText().setText("");
-    super.paintComponent(g);
-  }
-
-  @Override
-  public int getRowCount() {
-    return main.getRowCount();
-  }
-
-  @Override
-  public int getRowHeight(int row) {
-    setRowHeight(main.getRowHeight());
-    return super.getRowHeight(row);
-  }
-
-  @Override
-  public Object getValueAt(int row, int column) {
-    return Integer.toString(row + rowShift);
-  }
-
-  public void setRowShift(int shift) {
-    rowShift = shift;
-  }
-
-  public int getRowShift() {
-    return rowShift;
-  }
-
-  @Override
-  public boolean isCellEditable(int row, int column) {
-    return false;
-  }
-
-
-  @Override
-  public void setValueAt(Object value, int row, int column) {
-  }
-
-  public void propertyChange(PropertyChangeEvent e) {
-    if ("selectionModel".equals(e.getPropertyName())) {
-      setSelectionModel(main.getSelectionModel());
-    }
-
-    if ("rowHeight".equals(e.getPropertyName())) {
-      repaint();
-    }
-
-    if ("model".equals(e.getPropertyName())) {
-      main.getModel().addTableModelListener(this);
-      revalidate();
-    }
-  }
-
-  @Override
-  public void tableChanged(TableModelEvent e) {
-    revalidate();
-  }
-
-  private class RowNumberRenderer extends DefaultTableCellRenderer {
-    public RowNumberRenderer() {
-      setHorizontalAlignment(SwingConstants.CENTER);
-    }
-
-    public Component getTableCellRendererComponent(
-      JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-      if (table != null) {
-        JTableHeader header = table.getTableHeader();
-
-        if (header != null) {
-          setForeground(header.getForeground());
-          setBackground(header.getBackground());
-          setFont(header.getFont());
-        }
-      }
-
-      if (isSelected) {
-        setFont(getFont().deriveFont(Font.BOLD));
-      }
-
-      setText((value == null) ? "" : value.toString());
-      setBorder(UIManager.getBorder("TableHeader.cellBorder"));
-
-      return this;
-    }
-  }
-}