mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -59,6 +59,7 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component
|
||||
private AsyncProcessIcon myBusyIcon;
|
||||
private boolean myBusy;
|
||||
|
||||
private int myMaxItemsForSizeCalculation = Integer.MAX_VALUE;
|
||||
|
||||
public JBTable() {
|
||||
this(new DefaultTableModel());
|
||||
@@ -153,8 +154,8 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component
|
||||
if (myRowHeight < 0) {
|
||||
try {
|
||||
myRowHeightIsComputing = true;
|
||||
for (int row = 0; row < getRowCount(); row++) {
|
||||
for (int column = 0; column < getColumnCount(); column++) {
|
||||
for (int row = 0; row < Math.min(getRowCount(), myMaxItemsForSizeCalculation); row++) {
|
||||
for (int column = 0; column < Math.min(getColumnCount(), myMaxItemsForSizeCalculation); column++) {
|
||||
final TableCellRenderer renderer = getCellRenderer(row, column);
|
||||
if (renderer != null) {
|
||||
final Object value = getValueAt(row, column);
|
||||
@@ -818,4 +819,15 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component
|
||||
return resizingAllowed && columnModel.getColumn(columnIdx).getResizable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JTable gets table data from model lazily - only for a table part to be shown.
|
||||
* JBTable loads <i>all</i> the data on initialization to calculate cell size.
|
||||
* This methods provides possibility to calculate size without loading all the table data.
|
||||
*
|
||||
* @param maxItemsForSizeCalculation maximum number ot items in table to be loaded for size calculation
|
||||
*/
|
||||
public void setMaxItemsForSizeCalculation(int maxItemsForSizeCalculation) {
|
||||
myMaxItemsForSizeCalculation = maxItemsForSizeCalculation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,6 @@ public interface PyFrameAccessor {
|
||||
|
||||
@Nullable
|
||||
PyReferrersLoader getReferrersLoader();
|
||||
|
||||
Object[][] getArrayItems(PyDebugValue var, int colOffset, int rowOffset, int cols, int rows, String format);
|
||||
}
|
||||
|
||||
@@ -531,6 +531,11 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[][] getArrayItems(PyDebugValue var, int colOffset, int rowOffset, int cols, int rows, String format) {
|
||||
return new Object[][]{new Object[]{1, 2}, new Object[]{3, 4}};
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that pydevconsole connect (with pydevd) to the specified port
|
||||
*
|
||||
|
||||
@@ -571,6 +571,11 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
|
||||
return myReferrersProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[][] getArrayItems(PyDebugValue var, int colOffset, int rowOffset, int cols, int rows, String format) {
|
||||
return new Object[][]{new Object[]{1, 2}, new Object[]{3, 4}};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String loadSource(String path) {
|
||||
return myDebugger.loadSource(path);
|
||||
|
||||
@@ -1,96 +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 org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author amarch
|
||||
*/
|
||||
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) {
|
||||
myBaseSlice = baseSlice;
|
||||
myColumns = columns;
|
||||
myRows = rows;
|
||||
myRowOffset = rOffset;
|
||||
myColOffset = cOffset;
|
||||
}
|
||||
|
||||
public int getRows() {
|
||||
return myRows;
|
||||
}
|
||||
|
||||
public int getColumns() {
|
||||
return myColumns;
|
||||
}
|
||||
|
||||
public int getColOffset() {
|
||||
return myColOffset;
|
||||
}
|
||||
|
||||
public int getRowOffset() {
|
||||
return myRowOffset;
|
||||
}
|
||||
|
||||
public Object[][] getData() {
|
||||
return myData;
|
||||
}
|
||||
|
||||
public String getBaseSlice() {
|
||||
return myBaseSlice;
|
||||
}
|
||||
|
||||
public String getPresentation() {
|
||||
return "";
|
||||
}
|
||||
|
||||
abstract void fillData(Runnable callback);
|
||||
|
||||
public boolean contains(int row, int col) {
|
||||
return myRowOffset <= row && row < myRowOffset + myRows && myColOffset <= col && col < myColOffset + myColumns;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof ArrayChunk &&
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ class ArrayTableCellRenderer extends DefaultTableCellRenderer {
|
||||
if (myMax != myMin) {
|
||||
if (myColored && value != null) {
|
||||
try {
|
||||
double rangedValue = NumpyArrayValueProvider.getRangedValue(value.toString(), myType, myMin, myMax, myComplexMax, myComplexMin);
|
||||
double rangedValue = NumpyArrayTable.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((int)Math.round(255 * rangedValue), 0, (int)Math.round(255 * (1 - rangedValue)), 130)));
|
||||
|
||||
@@ -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 com.jetbrains.python.debugger.PyDebugValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -42,7 +43,7 @@ public class ArrayTableForm {
|
||||
private JLabel myFormatLabel;
|
||||
private JPanel myFormatPanel;
|
||||
private JPanel myMainPanel;
|
||||
private JBTable myTable;
|
||||
private JTable myTable;
|
||||
private JBTable myBusyTable;
|
||||
private final Project myProject;
|
||||
|
||||
@@ -58,19 +59,8 @@ public class ArrayTableForm {
|
||||
mySliceTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE);
|
||||
|
||||
myTable = new JBTableWithRowHeaders();
|
||||
myTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
|
||||
myTable.setRowSelectionAllowed(false);
|
||||
myTable.setTableHeader(new CustomTableHeader(myTable));
|
||||
myTable.getTableHeader().setDefaultRenderer(new ColumnHeaderRenderer());
|
||||
myTable.getTableHeader().setReorderingAllowed(false);
|
||||
|
||||
myScrollPane = PagingTableModel.LazyViewport.createLazyScrollPaneFor(myTable);
|
||||
JTable rowTable = new JBTableWithRowHeaders.RowHeaderTable(myTable);
|
||||
myScrollPane.setRowHeaderView(rowTable);
|
||||
myScrollPane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER,
|
||||
rowTable.getTableHeader());
|
||||
|
||||
((JBTableWithRowHeaders)myTable).setRowHeaderTable((JBTableWithRowHeaders.RowHeaderTable)rowTable);
|
||||
myScrollPane = ((JBTableWithRowHeaders)myTable).getScrollPane();
|
||||
|
||||
myFormatTextField = new EditorTextField("", myProject, PythonFileType.INSTANCE);
|
||||
|
||||
@@ -88,7 +78,7 @@ public class ArrayTableForm {
|
||||
return myFormatTextField;
|
||||
}
|
||||
|
||||
public JBTable getTable() {
|
||||
public JTable getTable() {
|
||||
return myTable;
|
||||
}
|
||||
|
||||
@@ -96,15 +86,15 @@ public class ArrayTableForm {
|
||||
return myColoredCheckbox;
|
||||
}
|
||||
|
||||
public void setDefaultStatus() {
|
||||
if (myTable != null) {
|
||||
myTable.getEmptyText().setText(DATA_LOADING_IN_PROCESS);
|
||||
}
|
||||
}
|
||||
//public void setDefaultStatus() {
|
||||
// if (myTable != null) {
|
||||
//myTable.getEmptyText().setText(DATA_LOADING_IN_PROCESS);
|
||||
//}
|
||||
//}
|
||||
|
||||
public void setNotApplicableStatus(XValueNodeImpl node) {
|
||||
myTable.getEmptyText().setText(NOT_APPLICABLE + node.getName());
|
||||
}
|
||||
//public void setNotApplicableStatus(PyDebugValue node) {
|
||||
// myTable.getEmptyText().setText(NOT_APPLICABLE + node.getName());
|
||||
//}
|
||||
|
||||
public JComponent getMainPanel() {
|
||||
return myMainPanel;
|
||||
@@ -118,25 +108,6 @@ public class ArrayTableForm {
|
||||
myBusyTable.setPaintBusy(busy);
|
||||
}
|
||||
|
||||
public static class CustomTableHeader extends JTableHeader {
|
||||
|
||||
public CustomTableHeader(JTable table) {
|
||||
super();
|
||||
setColumnModel(table.getColumnModel());
|
||||
table.getColumnModel().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void columnSelectionChanged(ListSelectionEvent e) {
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ColumnHeaderRenderer extends DefaultTableHeaderCellRenderer {
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int column) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
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
|
||||
*/
|
||||
abstract class ArrayValueProvider {
|
||||
|
||||
@NotNull protected final XValueNode myBaseNode;
|
||||
|
||||
public ArrayValueProvider(@NotNull XValueNode node) {
|
||||
myBaseNode = node;
|
||||
}
|
||||
|
||||
public abstract boolean isNumeric();
|
||||
|
||||
public String getNodeName() {
|
||||
return ((XValueNodeImpl)myBaseNode).getName();
|
||||
}
|
||||
|
||||
public XDebuggerTree getTree() {
|
||||
return ((XValueNodeImpl)myBaseNode).getTree();
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,13 @@
|
||||
*/
|
||||
package com.jetbrains.python.debugger.array;
|
||||
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.event.TableModelEvent;
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
@@ -33,8 +36,30 @@ import java.beans.PropertyChangeListener;
|
||||
* @author amarch
|
||||
*/
|
||||
public class JBTableWithRowHeaders extends JBTable {
|
||||
private final JBScrollPane myScrollPane;
|
||||
private RowHeaderTable myRowHeaderTable;
|
||||
|
||||
public JBScrollPane getScrollPane() {
|
||||
return myScrollPane;
|
||||
}
|
||||
|
||||
public JBTableWithRowHeaders() {
|
||||
setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
|
||||
setRowSelectionAllowed(false);
|
||||
setMaxItemsForSizeCalculation(50);
|
||||
setTableHeader(new CustomTableHeader(this));
|
||||
getTableHeader().setDefaultRenderer(new ArrayTableForm.ColumnHeaderRenderer());
|
||||
getTableHeader().setReorderingAllowed(false);
|
||||
|
||||
myScrollPane = new JBScrollPane(this);
|
||||
JBTableWithRowHeaders.RowHeaderTable rowTable = new JBTableWithRowHeaders.RowHeaderTable(this);
|
||||
myScrollPane.setRowHeaderView(rowTable);
|
||||
myScrollPane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER,
|
||||
rowTable.getTableHeader());
|
||||
|
||||
setRowHeaderTable(rowTable);
|
||||
}
|
||||
|
||||
public boolean getScrollableTracksViewportWidth() {
|
||||
return getPreferredSize().width < getParent().getWidth();
|
||||
}
|
||||
@@ -48,10 +73,10 @@ public class JBTableWithRowHeaders extends JBTable {
|
||||
}
|
||||
|
||||
public static class RowHeaderTable extends JBTable implements PropertyChangeListener, TableModelListener {
|
||||
private JBTable myMainTable;
|
||||
private JTable myMainTable;
|
||||
private int myRowShift = 0;
|
||||
|
||||
public RowHeaderTable(JBTable table) {
|
||||
public RowHeaderTable(JTable table) {
|
||||
myMainTable = table;
|
||||
myMainTable.getModel().addTableModelListener(this);
|
||||
|
||||
@@ -158,4 +183,23 @@ public class JBTableWithRowHeaders extends JBTable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomTableHeader extends JTableHeader {
|
||||
|
||||
public CustomTableHeader(JTable table) {
|
||||
super();
|
||||
setColumnModel(table.getColumnModel());
|
||||
table.getColumnModel().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void columnSelectionChanged(ListSelectionEvent e) {
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
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;
|
||||
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeListener;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.RestorableStateNode;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueContainerNode;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
|
||||
import com.jetbrains.python.debugger.PyDebugValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author amarch
|
||||
*/
|
||||
|
||||
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,
|
||||
int rOffset,
|
||||
int cOffset,
|
||||
String format,
|
||||
@NotNull NumpyArrayValueProvider valueProvider) {
|
||||
super(baseSlice, rows, columns, rOffset, cOffset);
|
||||
myValueProvider = valueProvider;
|
||||
myDataEvaluator = new DataEvaluator();
|
||||
myFormat = format;
|
||||
}
|
||||
|
||||
public String getPresentation() {
|
||||
String onlyChunkSlice =
|
||||
"[" + getRowOffset() + ":" + (getRowOffset() + getRows()) + ", " + getColOffset() + ":" + (getColOffset() + getColumns()) + "]";
|
||||
if (isOneColumn() && isOneRow()) {
|
||||
onlyChunkSlice = "";
|
||||
}
|
||||
else if (isOneRow()) {
|
||||
onlyChunkSlice = "[" + getColOffset() + ":" + (getColOffset() + getColumns()) + "]";
|
||||
}
|
||||
else if (isOneColumn()) {
|
||||
onlyChunkSlice = "[" + getRowOffset() + ":" + (getRowOffset() + getRows()) + "]";
|
||||
}
|
||||
|
||||
if (getBaseSlice().endsWith(onlyChunkSlice)) {
|
||||
return getBaseSlice();
|
||||
}
|
||||
return getBaseSlice() + onlyChunkSlice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillData(Runnable callback) {
|
||||
myDataEvaluator.evaluateData(callback);
|
||||
}
|
||||
|
||||
public NumpyArraySlice getInstance() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean dataFilled() {
|
||||
return myDataEvaluator.dataFilled();
|
||||
}
|
||||
|
||||
private class DataEvaluator {
|
||||
private Object[][] myData;
|
||||
private int myFilledRows = 0;
|
||||
private int nextRow = 0;
|
||||
|
||||
public Object[][] getData() {
|
||||
return myData;
|
||||
}
|
||||
|
||||
public boolean dataFilled() {
|
||||
return getRows() > 0 && myFilledRows == getRows();
|
||||
}
|
||||
|
||||
public void evaluateData(final Runnable callback) {
|
||||
final XDebuggerEvaluator.XEvaluationCallback computeChildrenCallback = new XDebuggerEvaluator.XEvaluationCallback() {
|
||||
@Override
|
||||
public void evaluated(@NotNull final XValue result) {
|
||||
final String name = ((PyDebugValue)result).getName();
|
||||
DebuggerUIUtil.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
XValueNodeImpl node = new XValueNodeImpl(myValueProvider.getTree(), null, name, result);
|
||||
node.startComputingChildren();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void errorOccurred(@NotNull String errorMessage) {
|
||||
myValueProvider.showError(errorMessage, getInstance());
|
||||
}
|
||||
};
|
||||
|
||||
XDebuggerTreeListener treeListener = new XDebuggerTreeListener() {
|
||||
@Override
|
||||
public void nodeLoaded(@NotNull RestorableStateNode node, String name) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenLoaded(@NotNull XDebuggerTreeNode node, @NotNull List<XValueContainerNode<?>> children, boolean last) {
|
||||
if (!(node instanceof XValueNodeImpl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fullName = ((XValueNodeImpl)node).getName();
|
||||
if (fullName == null || !fullName.contains(getPresentation())) {
|
||||
return;
|
||||
}
|
||||
|
||||
int row;
|
||||
if (isOneRow()) {
|
||||
row = 0;
|
||||
}
|
||||
else {
|
||||
if (isOneColumn()) {
|
||||
row = Integer.parseInt(fullName.substring(fullName.lastIndexOf('[') + 1, fullName.length() - 1));
|
||||
}
|
||||
else {
|
||||
fullName = fullName.substring(0, fullName.lastIndexOf(","));
|
||||
row = Integer.parseInt(fullName.substring(fullName.lastIndexOf('[') + 1, fullName.length()));
|
||||
}
|
||||
}
|
||||
|
||||
if (row > getRows()) {
|
||||
LOG.error("Row " + row + " is out of range for " + getPresentation() + ".");
|
||||
return;
|
||||
}
|
||||
|
||||
if (row != -1 && myData[row][0] == null) {
|
||||
for (int i = 0; i < node.getChildCount() - 1; i++) {
|
||||
String rawValue = ((XValueNodeImpl)node.getChildAt(i + 1)).getRawValue();
|
||||
if (rawValue == null) {
|
||||
return;
|
||||
}
|
||||
if (myValueProvider.isNumeric()) {
|
||||
//remove str quotes in case of numeric
|
||||
rawValue = rawValue.substring(1, rawValue.length() - 1);
|
||||
}
|
||||
myData[row][i] = rawValue;
|
||||
}
|
||||
if (node.getChildCount() == 0) {
|
||||
String rawValue = ((XValueNodeImpl)node).getRawValue();
|
||||
if (rawValue == null) {
|
||||
return;
|
||||
}
|
||||
if (myValueProvider.isNumeric()) {
|
||||
//remove str quotes in case of numeric
|
||||
rawValue = rawValue.substring(1, rawValue.length() - 1);
|
||||
}
|
||||
myData[row][0] = rawValue;
|
||||
}
|
||||
myFilledRows += 1;
|
||||
if (myFilledRows == getRows()) {
|
||||
node.getTree().removeTreeListener(this);
|
||||
callback.run();
|
||||
}
|
||||
else {
|
||||
nextRow += 1;
|
||||
startEvalNextRow(computeChildrenCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
myData =
|
||||
new Object[getRows()][getColumns()];
|
||||
myValueProvider.getTree().addTreeListener(treeListener);
|
||||
nextRow = 0;
|
||||
myFilledRows = 0;
|
||||
startEvalNextRow(computeChildrenCallback);
|
||||
}
|
||||
|
||||
private void startEvalNextRow(XDebuggerEvaluator.XEvaluationCallback callback) {
|
||||
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:" + getColumns() + "]))";
|
||||
}
|
||||
|
||||
if (isOneRow() && isOneColumn()) {
|
||||
evalRowCommand = "\'" + myFormat + "\'" + " % " + getPresentation();
|
||||
}
|
||||
else if (isOneColumn()) {
|
||||
evalRowCommand = "\'" + myFormat + "\'" + " % " + getPresentation();
|
||||
evalRowCommand += "[" + nextRow + "]";
|
||||
}
|
||||
else if (isOneRow()) {
|
||||
evalRowCommand += "[0:" + getColumns() + "]))";
|
||||
}
|
||||
myValueProvider.getEvaluator().evaluate(evalRowCommand, callback, null);
|
||||
}
|
||||
}
|
||||
|
||||
public Object[][] getData() {
|
||||
return myDataEvaluator.getData();
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return myFormat;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
myFormat = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " : " + getPresentation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+33
-142
@@ -22,20 +22,15 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.ui.AppUIUtil;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
|
||||
import com.intellij.xdebugger.frame.XValue;
|
||||
import com.intellij.xdebugger.frame.XValueNode;
|
||||
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
|
||||
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
|
||||
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeState;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
|
||||
import com.jetbrains.python.debugger.PyDebugValue;
|
||||
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.*;
|
||||
@@ -47,18 +42,17 @@ import java.util.regex.Pattern;
|
||||
/**
|
||||
* @author amarch
|
||||
*/
|
||||
public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
private PyViewArrayAction.MyDialog myDialog;
|
||||
private ArrayTableForm myComponent;
|
||||
private JBTable myTable;
|
||||
public class NumpyArrayTable {
|
||||
private final PyDebugValue myValue;
|
||||
private final PyViewArrayAction.ViewArrayDialog myDialog;
|
||||
private final ArrayTableForm myComponent;
|
||||
private final JTable myTable;
|
||||
private Project myProject;
|
||||
private PyDebuggerEvaluator myEvaluator;
|
||||
private NumpyArraySlice myLastPresentation;
|
||||
private String myDtypeKind;
|
||||
private int[] myShape;
|
||||
private ArrayTableCellRenderer myTableCellRenderer;
|
||||
private PagingTableModel myPagingModel;
|
||||
private boolean lastSuccessful = false;
|
||||
|
||||
private final static int COLUMNS_IN_DEFAULT_SLICE = 40;
|
||||
private final static int ROWS_IN_DEFAULT_SLICE = 40;
|
||||
@@ -75,62 +69,28 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
|
||||
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);
|
||||
public NumpyArrayTable(@NotNull Project project,
|
||||
@NotNull PyViewArrayAction.ViewArrayDialog dialog, @NotNull PyDebugValue value) {
|
||||
myValue = value;
|
||||
myDialog = dialog;
|
||||
if (dialog != null) {
|
||||
myComponent = dialog.getComponent();
|
||||
myTable = myComponent.getTable();
|
||||
}
|
||||
myComponent = new ArrayTableForm(project);
|
||||
myTable = myComponent.getTable();
|
||||
myProject = project;
|
||||
myEvaluator = new PyDebuggerEvaluator(project, getValueContainer().getFrameAccessor());
|
||||
myEvaluator = new PyDebuggerEvaluator(project, getDebugValue().getFrameAccessor());
|
||||
}
|
||||
|
||||
private PagingTableModel getPagingModel(@NotNull int[] shape, boolean rendered, final NumpyArraySlice mainSlice) {
|
||||
public ArrayTableForm getComponent() {
|
||||
return myComponent;
|
||||
}
|
||||
|
||||
private PagingTableModel createTableModel(@NotNull int[] shape) {
|
||||
final int columns = Math.min(getMaxColumn(shape), COLUMNS_IN_DEFAULT_VIEW);
|
||||
int rows = Math.min(getMaxRow(shape), ROWS_IN_DEFAULT_VIEW);
|
||||
if (columns == 0 || rows == 0) {
|
||||
showError("Slice with zero axis shape.");
|
||||
}
|
||||
|
||||
return new PagingTableModel(rows, columns, rendered, this, mainSlice) {
|
||||
|
||||
private final String myFormat = mainSlice.getFormat();
|
||||
private final String myBaseSlice = mainSlice.getBaseSlice();
|
||||
|
||||
@Override
|
||||
protected NumpyArraySlice createChunk(int rows, int columns, int rOffset, int cOffset) {
|
||||
return new NumpyArraySlice(myBaseSlice, rows, columns, rOffset, cOffset, myFormat, getInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
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());
|
||||
}
|
||||
|
||||
return new Runnable() {
|
||||
public void run() {
|
||||
if (!arraySlice.dataFilled()) {
|
||||
arraySlice.fillData(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//check that we still running on the right model
|
||||
if (!myBaseSlice.equals(getModelFullChunk().getBaseSlice()) || !myFormat.equals(getModelFullChunk().getFormat())) {
|
||||
return;
|
||||
}
|
||||
notifyChunkLoaded(arraySlice);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
return new PagingTableModel(rows, columns, this);
|
||||
}
|
||||
|
||||
private void initComponent() {
|
||||
@@ -232,23 +192,19 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
});
|
||||
}
|
||||
|
||||
public NumpyArrayValueProvider getInstance() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public PyDebugValue getValueContainer() {
|
||||
return (PyDebugValue)((XValueNodeImpl)myBaseNode).getValueContainer();
|
||||
public PyDebugValue getDebugValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
public PyDebuggerEvaluator getEvaluator() {
|
||||
return myEvaluator;
|
||||
}
|
||||
|
||||
public void startFillTable() {
|
||||
public void init() {
|
||||
Runnable returnToFillTable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startFillTable();
|
||||
init();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -282,9 +238,7 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
}
|
||||
}
|
||||
});
|
||||
startFillTable(new NumpyArraySlice(getDefaultPresentation(), Math.min(getMaxRow(myShape), ROWS_IN_DEFAULT_VIEW),
|
||||
Math.min(getMaxColumn(myShape), COLUMNS_IN_DEFAULT_VIEW), 0, 0, getDefaultFormat(), getInstance()),
|
||||
false, false);
|
||||
initTableModel(false);
|
||||
}
|
||||
|
||||
private static String getTitlePresentation(String slice) {
|
||||
@@ -466,7 +420,6 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNumeric() {
|
||||
if (myDtypeKind != null) {
|
||||
return "biufc".contains(myDtypeKind.substring(0, 1));
|
||||
@@ -474,15 +427,8 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void startFillTable(final NumpyArraySlice arraySlice, boolean rendered, final boolean inPlace) {
|
||||
if (myLastPresentation != null &&
|
||||
arraySlice.getBaseSlice().equals(myLastPresentation.getBaseSlice()) &&
|
||||
arraySlice.getFormat().equals(myLastPresentation.getFormat()) && lastSuccessful) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastSuccessful = false;
|
||||
myPagingModel = getPagingModel(myShape, rendered, arraySlice);
|
||||
private void initTableModel(final boolean inPlace) {
|
||||
myPagingModel = createTableModel(myShape);
|
||||
|
||||
DebuggerUIUtil.invokeLater(new Runnable() {
|
||||
@Override
|
||||
@@ -544,15 +490,6 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
myEvaluator.evaluate(changeValExpression(), new XDebuggerEvaluator.XEvaluationCallback() {
|
||||
@Override
|
||||
public void evaluated(@NotNull XValue result) {
|
||||
AppUIUtil.invokeOnEdt(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
XDebuggerTree tree = ((XValueNodeImpl)myBaseNode).getTree();
|
||||
final XDebuggerTreeState treeState = XDebuggerTreeState.saveState(tree);
|
||||
tree.rebuildAndRestore(treeState);
|
||||
}
|
||||
});
|
||||
|
||||
XDebuggerEvaluator.XEvaluationCallback callback = new XDebuggerEvaluator.XEvaluationCallback() {
|
||||
@Override
|
||||
public void evaluated(@NotNull XValue value) {
|
||||
@@ -616,31 +553,11 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
this.myShape = shape;
|
||||
}
|
||||
|
||||
public void completeCurrentLoad() {
|
||||
setBusy(false);
|
||||
if (myPagingModel.getColumnCount() < getMaxColumn(myShape) || myPagingModel.getRowCount() < getMaxRow(myShape)) {
|
||||
String hintMessage = LOAD_SMALLER_SLICE;
|
||||
if (isNumeric()) {
|
||||
hintMessage += "\n" + DISABLE_COLOR_FOR_HUGE_ARRAY;
|
||||
}
|
||||
showInfoHint(hintMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public void showError(String message) {
|
||||
myDialog.setError(message);
|
||||
setBusy(false);
|
||||
}
|
||||
|
||||
public void showError(String message, NumpyArraySlice chunk) {
|
||||
if (!chunk.getFormat().equals(getModelFullChunk().getFormat()) ||
|
||||
!chunk.getBaseSlice().equals(getModelFullChunk().getBaseSlice())) {
|
||||
//ignore error message from previous task
|
||||
return;
|
||||
}
|
||||
showError(message);
|
||||
}
|
||||
|
||||
public void showInfoHint(final String message) {
|
||||
DebuggerUIUtil.invokeLater(new Runnable() {
|
||||
@Override
|
||||
@@ -710,7 +627,7 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
}
|
||||
|
||||
myShape = shape;
|
||||
startRefillTable(false);
|
||||
reset();
|
||||
}
|
||||
|
||||
private static String getEvalShapeCommand(@NotNull String slice) {
|
||||
@@ -737,20 +654,12 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
}
|
||||
|
||||
private void doApplyFormat() {
|
||||
startRefillTable(true);
|
||||
reset();
|
||||
}
|
||||
|
||||
private void startRefillTable(boolean inPlace) {
|
||||
clearTableData();
|
||||
Rectangle vr = myTable.getVisibleRect();
|
||||
int rOffset = myTable.rowAtPoint(vr.getLocation());
|
||||
int cOffset = myTable.columnAtPoint(vr.getLocation());
|
||||
startFillTable(new NumpyArraySlice(getSliceText(), 0, 0, rOffset, cOffset, getFormat(), this), true, inPlace);
|
||||
}
|
||||
|
||||
private void clearTableData() {
|
||||
private void reset() {
|
||||
clearErrorMessage();
|
||||
((PagingTableModel)myTable.getModel()).clearCached();
|
||||
initTableModel(true);
|
||||
}
|
||||
|
||||
public String evalTypeFunc(String format) {
|
||||
@@ -771,24 +680,6 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
DebuggerUIUtil.invokeLater(new Runnable() {
|
||||
@Override
|
||||
@@ -798,10 +689,6 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
});
|
||||
}
|
||||
|
||||
private NumpyArraySlice getModelFullChunk() {
|
||||
return (NumpyArraySlice)myPagingModel.getFullChunk();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return double presentation from [0:1] range
|
||||
*/
|
||||
@@ -852,4 +739,8 @@ public class NumpyArrayValueProvider extends ArrayValueProvider {
|
||||
throw new IllegalArgumentException("Not a valid python complex value: " + pyComplexValue);
|
||||
}
|
||||
}
|
||||
|
||||
public String getNodeName() {
|
||||
return (myValue).getName();
|
||||
}
|
||||
}
|
||||
@@ -15,74 +15,86 @@
|
||||
*/
|
||||
package com.jetbrains.python.debugger.array;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.ui.components.JBViewport;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.containers.Queue;
|
||||
import com.jetbrains.python.debugger.PyDebugValue;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import java.awt.*;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public abstract class PagingTableModel extends AbstractTableModel {
|
||||
private static final int CHUNK_COL_SIZE = 50;
|
||||
private static final int CHUNK_ROW_SIZE = 50;
|
||||
/**
|
||||
* @author traff
|
||||
*/
|
||||
public class PagingTableModel extends AbstractTableModel {
|
||||
private static final int CHUNK_COL_SIZE = 2; //TODO set to 100
|
||||
private static final int CHUNK_ROW_SIZE = 2;
|
||||
private static final int DEFAULT_MAX_CACHED_SIZE = 100;
|
||||
public static final String EMPTY_CELL_VALUE = "...";
|
||||
|
||||
private HashMap<String, Object[][]> myCachedData = new HashMap<String, Object[][]>();
|
||||
private SortedSet<ArrayChunk> myPendingSet = new TreeSet<ArrayChunk>();
|
||||
private Queue<String> cachedChunkKeys = new Queue<String>(DEFAULT_MAX_CACHED_SIZE + 1);
|
||||
private LoadingCache<Pair<Integer, Integer>, Object[][]> myChunkCache = CacheBuilder.newBuilder().build(
|
||||
new CacheLoader<Pair<Integer, Integer>, Object[][]>() {
|
||||
@Override
|
||||
public Object[][] load(Pair<Integer, Integer> key) throws Exception {
|
||||
PyDebugValue value = myProvider.getDebugValue();
|
||||
value = new PyDebugValue(myProvider.getSliceText(), value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(),
|
||||
value.getFrameAccessor());
|
||||
return value.getFrameAccessor().getArrayItems(value, key.first, key.second, CHUNK_COL_SIZE, CHUNK_ROW_SIZE, myProvider.getFormat());
|
||||
}
|
||||
});
|
||||
|
||||
private ArrayChunk evaluatedChunk;
|
||||
|
||||
private boolean myRendered;
|
||||
private int myRows = 0;
|
||||
private int myColumns = 0;
|
||||
private NumpyArrayValueProvider myProvider;
|
||||
private ArrayChunk myFullChunk;
|
||||
private NumpyArrayTable myProvider;
|
||||
|
||||
|
||||
public PagingTableModel(int rows, int columns, boolean rendered, NumpyArrayValueProvider provider, ArrayChunk fullChunk) {
|
||||
public PagingTableModel(int rows, int columns, NumpyArrayTable provider) {
|
||||
myRows = rows;
|
||||
myColumns = columns;
|
||||
myRendered = rendered;
|
||||
myProvider = provider;
|
||||
myFullChunk = fullChunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int column) {
|
||||
if (getValueAt(row, column).equals(EMPTY_CELL_VALUE)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !getValueAt(row, column).equals(EMPTY_CELL_VALUE);
|
||||
}
|
||||
|
||||
public Object getValueAt(int row, int col) {
|
||||
//prevent data evaluation for full table
|
||||
if (row == (getRowCount() - 1) && col == (getColumnCount() - 1) && !myRendered) {
|
||||
myRendered = true;
|
||||
return EMPTY_CELL_VALUE;
|
||||
}
|
||||
Pair<Integer, Integer> key = itemToChunkKey(row, col);
|
||||
|
||||
if (!myRendered) {
|
||||
return EMPTY_CELL_VALUE;
|
||||
}
|
||||
try {
|
||||
Object[][] chunk = myChunkCache.get(key);
|
||||
|
||||
String key = formMapKey(row, col);
|
||||
if (!myCachedData.containsKey(key)) {
|
||||
scheduleChunkAt(row, col);
|
||||
return EMPTY_CELL_VALUE;
|
||||
}
|
||||
int r = row % CHUNK_ROW_SIZE;
|
||||
int c = col % CHUNK_COL_SIZE;
|
||||
|
||||
return myCachedData.get(key)[row % CHUNK_ROW_SIZE][col % CHUNK_COL_SIZE];
|
||||
if (r < chunk.length) {
|
||||
if (c < chunk[r].length) {
|
||||
return chunk[r][c];
|
||||
}
|
||||
else {
|
||||
return EMPTY_CELL_VALUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return EMPTY_CELL_VALUE;
|
||||
}
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
return EMPTY_CELL_VALUE; //TODO: handle it
|
||||
}
|
||||
}
|
||||
|
||||
private static String formMapKey(int row, int col) {
|
||||
return "[" + getPageRowStart(row) + "," + getPageColStart(col) + "]";
|
||||
private static Pair<Integer, Integer> itemToChunkKey(int row, int col) {
|
||||
return Pair.create(getPageRowStart(row), getPageColStart(col));
|
||||
}
|
||||
|
||||
private static int getPageRowStart(int rowOffset) {
|
||||
@@ -93,78 +105,6 @@ public abstract class PagingTableModel extends AbstractTableModel {
|
||||
return colOffset - (colOffset % CHUNK_COL_SIZE);
|
||||
}
|
||||
|
||||
private void scheduleChunkAt(int rOffset, int cOffset) {
|
||||
if (isPending(rOffset, cOffset)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int startROffset = getPageRowStart(rOffset);
|
||||
int rLength = Math.min(CHUNK_ROW_SIZE, myRows - startROffset);
|
||||
|
||||
int startCOffset = getPageColStart(cOffset);
|
||||
int cLength = Math.min(CHUNK_COL_SIZE, myColumns - startCOffset);
|
||||
|
||||
scheduleLoadData(startROffset, rLength, startCOffset, cLength);
|
||||
}
|
||||
|
||||
private boolean isPending(int rOffset, int cOffset) {
|
||||
int sz = myPendingSet.size();
|
||||
if (sz == 0) return false;
|
||||
if (sz == 1) {
|
||||
// special case (for speed)
|
||||
ArrayChunk seg = myPendingSet.first();
|
||||
return seg.contains(rOffset, cOffset);
|
||||
}
|
||||
|
||||
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 (ArrayChunk seg : myPendingSet.subSet(lo, hi)) {
|
||||
if (seg.contains(rOffset, cOffset)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected abstract ArrayChunk createChunk(int rows, int columns, int rOffset, int cOffset);
|
||||
|
||||
protected abstract Runnable getDataEvaluator(final ArrayChunk chunk);
|
||||
|
||||
public void runNextLoadingTask() {
|
||||
if (evaluatedChunk != null) {
|
||||
myPendingSet.remove(evaluatedChunk);
|
||||
evaluatedChunk = null;
|
||||
}
|
||||
|
||||
if (myPendingSet.size() > 0) {
|
||||
evaluatedChunk = myPendingSet.first();
|
||||
ApplicationManager.getApplication().executeOnPooledThread(getDataEvaluator(evaluatedChunk));
|
||||
myProvider.setBusy(true);
|
||||
}
|
||||
else {
|
||||
myProvider.completeCurrentLoad();
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleLoadData(final int rOffset, final int rLength, final int cOffset, final int cLength) {
|
||||
final ArrayChunk segment = createChunk(rLength, cLength, rOffset, cOffset);
|
||||
myPendingSet.add(segment);
|
||||
|
||||
if (evaluatedChunk == null) {
|
||||
runNextLoadingTask();
|
||||
}
|
||||
}
|
||||
|
||||
protected void addDataInCache(int rOffset, int cOffset, Object[][] newData) {
|
||||
String key = formMapKey(rOffset, cOffset);
|
||||
myCachedData.put(key, newData);
|
||||
cachedChunkKeys.addLast(key);
|
||||
|
||||
if (myCachedData.size() == DEFAULT_MAX_CACHED_SIZE) {
|
||||
String old = cachedChunkKeys.pullFirst();
|
||||
myCachedData.remove(old);
|
||||
}
|
||||
}
|
||||
|
||||
public int getColumnCount() {
|
||||
return myColumns;
|
||||
}
|
||||
@@ -177,46 +117,13 @@ public abstract class PagingTableModel extends AbstractTableModel {
|
||||
return myRows;
|
||||
}
|
||||
|
||||
public void clearCached() {
|
||||
myCachedData = new HashMap<String, Object[][]>();
|
||||
myPendingSet = new TreeSet<ArrayChunk>();
|
||||
cachedChunkKeys = new Queue<String>(DEFAULT_MAX_CACHED_SIZE + 1);
|
||||
evaluatedChunk = null;
|
||||
}
|
||||
|
||||
public static class LazyViewport extends JBViewport {
|
||||
public static JBScrollPane createLazyScrollPaneFor(Component view) {
|
||||
LazyViewport vp = new LazyViewport();
|
||||
vp.setView(view);
|
||||
JBScrollPane scrollpane = new JBScrollPane();
|
||||
scrollpane.setViewport(vp);
|
||||
return scrollpane;
|
||||
}
|
||||
|
||||
public void setViewPosition(Point p) {
|
||||
Component parent = getParent();
|
||||
if (parent instanceof JBScrollPane &&
|
||||
(((JBScrollPane)parent).getVerticalScrollBar().getValueIsAdjusting() ||
|
||||
((JBScrollPane)parent).getHorizontalScrollBar().getValueIsAdjusting())) {
|
||||
return;
|
||||
}
|
||||
super.setViewPosition(p);
|
||||
}
|
||||
}
|
||||
|
||||
public void forcedChange(int row, int col, Object value) {
|
||||
String key = formMapKey(row, col);
|
||||
if (myCachedData.containsKey(key)) {
|
||||
Object[][] cachedData = myCachedData.get(key);
|
||||
cachedData[row - getPageRowStart(row)][col - getPageColStart(col)] = value;
|
||||
myCachedData.put(key, cachedData);
|
||||
Object[][] chunk = myChunkCache.getIfPresent(itemToChunkKey(row, col));
|
||||
if (chunk != null) {
|
||||
chunk[row - getPageRowStart(row)][col - getPageColStart(col)] = value;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Forced to change empty cell in " + row + " row and " + col + "column.");
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayChunk getFullChunk() {
|
||||
return myFullChunk;
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
|
||||
import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
|
||||
import com.jetbrains.python.console.PydevConsoleCommunication;
|
||||
import com.jetbrains.python.debugger.PyDebugValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -38,9 +37,11 @@ public class PyViewArrayAction extends XDebuggerTreeActionBase {
|
||||
|
||||
@Override
|
||||
protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e) {
|
||||
final MyDialog dialog = new MyDialog(e.getProject());
|
||||
dialog.setValue(node);
|
||||
dialog.show();
|
||||
Project p = e.getProject();
|
||||
if (p != null && node != null && node.getValueContainer() instanceof PyDebugValue && node.isComputed()) {
|
||||
final ViewArrayDialog dialog = new ViewArrayDialog(p, (PyDebugValue)(node.getValueContainer()));
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -53,18 +54,14 @@ public class PyViewArrayAction extends XDebuggerTreeActionBase {
|
||||
public void update(AnActionEvent e) {
|
||||
TreePath[] paths = getSelectedNodes(e.getDataContext());
|
||||
if (paths != null) {
|
||||
if(paths.length > 1) {
|
||||
if (paths.length > 1) {
|
||||
e.getPresentation().setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
XValueNodeImpl node = getSelectedNode(e.getDataContext());
|
||||
XValueNodeImpl node = getSelectedNode(e.getDataContext());
|
||||
if (node != null && node.getValueContainer() instanceof PyDebugValue && node.isComputed()) {
|
||||
PyDebugValue debugValue = (PyDebugValue) node.getValueContainer();
|
||||
if (debugValue.getFrameAccessor() instanceof PydevConsoleCommunication) {
|
||||
e.getPresentation().setVisible(false);
|
||||
return;
|
||||
}
|
||||
PyDebugValue debugValue = (PyDebugValue)node.getValueContainer();
|
||||
|
||||
String nodeType = debugValue.getType();
|
||||
if ("ndarray".equals(nodeType)) {
|
||||
@@ -76,43 +73,23 @@ public class PyViewArrayAction extends XDebuggerTreeActionBase {
|
||||
e.getPresentation().setVisible(false);
|
||||
}
|
||||
|
||||
protected class MyDialog extends DialogWrapper {
|
||||
protected static class ViewArrayDialog extends DialogWrapper {
|
||||
private Project myProject;
|
||||
private ArrayTableForm myComponent;
|
||||
private NumpyArrayTable myNumpyArrayTable;
|
||||
|
||||
private MyDialog(Project project) {
|
||||
private ViewArrayDialog(@NotNull Project project, PyDebugValue debugValue) {
|
||||
super(project, false);
|
||||
setModal(false);
|
||||
setCancelButtonText("Close");
|
||||
setCrossClosesWindow(true);
|
||||
|
||||
myProject = project;
|
||||
myComponent = new ArrayTableForm(project);
|
||||
myNumpyArrayTable = new NumpyArrayTable(myProject, this, debugValue);
|
||||
|
||||
myNumpyArrayTable.init();
|
||||
init();
|
||||
}
|
||||
|
||||
public void setValue(XValueNodeImpl node) {
|
||||
|
||||
if (node.getValueContainer() instanceof PyDebugValue) {
|
||||
PyDebugValue debugValue = (PyDebugValue)node.getValueContainer();
|
||||
|
||||
if ("ndarray".equals(debugValue.getType())) {
|
||||
myComponent.setDefaultStatus();
|
||||
final NumpyArrayValueProvider valueProvider = new NumpyArrayValueProvider(node, this, myProject);
|
||||
try {
|
||||
valueProvider.startFillTable();
|
||||
}
|
||||
catch (Exception e) {
|
||||
setErrorText(e.getMessage());
|
||||
}
|
||||
}
|
||||
else {
|
||||
myComponent.setNotApplicableStatus(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setError(String text) {
|
||||
//todo: think about this usage
|
||||
setErrorText(text);
|
||||
@@ -131,11 +108,11 @@ public class PyViewArrayAction extends XDebuggerTreeActionBase {
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return myComponent.getMainPanel();
|
||||
return myNumpyArrayTable.getComponent().getMainPanel();
|
||||
}
|
||||
|
||||
public ArrayTableForm getComponent() {
|
||||
return myComponent;
|
||||
return myNumpyArrayTable.getComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user