-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improved copying and selection behaviour of array editor #2750
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,8 @@ | |
QMessageBox, QPushButton, QInputDialog, QMenu, | ||
QApplication, QKeySequence, QLabel, QComboBox, | ||
QSpinBox, QStackedWidget, QWidget, QVBoxLayout, | ||
QAbstractItemDelegate) | ||
QAbstractItemDelegate, QItemSelection, | ||
QItemSelectionRange) | ||
from spyderlib.qt.QtCore import (Qt, QModelIndex, QAbstractTableModel, Slot) | ||
|
||
from spyderlib.qt.compat import to_qvariant, from_qvariant | ||
|
@@ -403,10 +404,39 @@ def __init__(self, parent, model, dtype, shape): | |
lambda val: self.load_more_data(val, rows=True)) | ||
|
||
def load_more_data(self, value, rows=False, columns=False): | ||
old_selection = self.selectionModel().selection() | ||
old_rows_loaded = old_cols_loaded = None | ||
|
||
if rows and value == self.verticalScrollBar().maximum(): | ||
old_rows_loaded = self.model().rows_loaded | ||
self.model().fetch_more(rows=rows) | ||
|
||
if columns and value == self.horizontalScrollBar().maximum(): | ||
old_cols_loaded = self.model().cols_loaded | ||
self.model().fetch_more(columns=columns) | ||
|
||
if old_rows_loaded is not None or old_cols_loaded is not None: | ||
# if we've changed anything, update selection | ||
new_selection = QItemSelection() | ||
for part in old_selection: | ||
top = part.top() | ||
bottom = part.bottom() | ||
if (old_rows_loaded is not None and | ||
top == 0 and bottom == (old_rows_loaded-1)): | ||
# complete column selected (so expand it to match updated range) | ||
bottom = self.model().rows_loaded-1 | ||
left = part.left() | ||
right = part.right() | ||
if (old_cols_loaded is not None | ||
and left == 0 and right == (old_cols_loaded-1)): | ||
# compete row selected (so expand it to match updated range) | ||
right = self.model().cols_loaded-1 | ||
top_left = self.model().index(top, left) | ||
bottom_right = self.model().index(bottom, right) | ||
part = QItemSelectionRange(top_left, bottom_right) | ||
new_selection.append(part) | ||
self.selectionModel().select(new_selection, self.selectionModel().ClearAndSelect) | ||
|
||
|
||
def resize_to_contents(self): | ||
"""Resize cells to contents""" | ||
|
@@ -444,6 +474,14 @@ def _sel_to_text(self, cell_range): | |
if not cell_range: | ||
return | ||
row_min, row_max, col_min, col_max = get_idx_rect(cell_range) | ||
if col_min == 0 and col_max == (self.model().cols_loaded-1): | ||
# we've selected a whole column. It isn't possible to | ||
# select only the first part of a column without loading more, | ||
# so we can treat it as intentional and copy the whole thing | ||
col_max = self.model().total_cols-1 | ||
if row_min == 0 and row_max == (self.model().rows_loaded-1): | ||
row_max = self.model().total_rows-1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really like this, it's very clever and solves the select columns, rows and all content in a very elegant way! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's probably worth mentioning that it doesn't quite do the right thing if you try to select an usual shaped region (i.e. select some rows or columns, then hold down ctrl and add a few extra cells elsewhere). That's an issue with the original code (not my added code) and it would probably be quite hard to work out what to do with numpy there. |
||
|
||
_data = self.model().get_data() | ||
if PY3: | ||
output = io.BytesIO() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one question here: this is done to extend the selection when more data is loaded, right?
But what happens if nothing is selected to start with?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - this is done to extend the selection when more data is loaded. If nothing is selected to start with nothing happens. The
QItemSelection()
constructor makes an empty selection, thefor part in old_selection:
loop is skipped and so one empty selection is replaced by another. I've have checked this case works and it does what you'd expect.As a side note here - it is possible to build a selection where to whole row is selected but it doesn't get expanded (if you select a whole row, deselect a cell, reselect the cell selection ends up split into multiple parts). I don't think it's worth the effort to try to spot this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem :-) Great work!!