void ExtendedTableWidget::paste() { // Get list of selected items QItemSelectionModel* selection = selectionModel(); QModelIndexList indices = selection->selectedIndexes(); // Abort if there's nowhere to paste if(indices.isEmpty()) return; SqliteTableModel* m = qobject_cast<SqliteTableModel*>(model()); // If clipboard contains image - just insert it QImage img = qApp->clipboard()->image(); if (!img.isNull()) { QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); img.save(&buffer, "PNG"); buffer.close(); m->setData(indices.first(), ba); return; } QString clipboard = qApp->clipboard()->text(); if (clipboard.isEmpty() && !m_buffer.isEmpty()) { // If buffer contains something - use it instead of clipboard int rows = m_buffer.size(); int columns = m_buffer.first().size(); int firstRow = indices.front().row(); int firstColumn = indices.front().column(); int lastRow = qMin(firstRow + rows - 1, m->rowCount() - 1); int lastColumn = qMin(firstColumn + columns - 1, m->columnCount() - 1); int row = firstRow; foreach(const QByteArrayList& lst, m_buffer) { int column = firstColumn; foreach(const QByteArray& ba, lst) { m->setData(m->index(row, column), ba); column++; if (column > lastColumn) break; }
void ExtendedTableWidget::selectTableLines(int firstLine, int count) { SqliteTableModel* m = qobject_cast<SqliteTableModel*>(model()); int lastLine = firstLine+count-1; // Are there even that many lines? if(lastLine >= m->rowCount()) return; selectTableLine(firstLine); QModelIndex topLeft = m->index(firstLine, 0); QModelIndex bottomRight = m->index(lastLine, m->columnCount()-1); selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select | QItemSelectionModel::Rows); }
void ExtendedTableWidget::paste() { // Get list of selected items QItemSelectionModel* selection = selectionModel(); QModelIndexList indices = selection->selectedIndexes(); // Abort if there's nowhere to paste if(indices.isEmpty()) return; SqliteTableModel* m = qobject_cast<SqliteTableModel*>(model()); // We're also checking for system clipboard data first. Only if the data in the system clipboard is not ours, we use the system // clipboard, otherwise we prefer the internal buffer. That's because the data in the internal buffer is easier to parse and more // accurate, too. However, if we always preferred the internal copy-paste buffer there would be no way to copy data from other // applications in here once the internal buffer has been filled. // If clipboard contains an image and no text, just insert the image const QMimeData* mimeClipboard = qApp->clipboard()->mimeData(); if (mimeClipboard->hasImage() && !mimeClipboard->hasText()) { QImage img = qApp->clipboard()->image(); QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); img.save(&buffer, "PNG"); // We're always converting the image format to PNG here. TODO: Is that correct? buffer.close(); m->setData(indices.first(), ba); return; } // Get the clipboard text QString clipboard = qApp->clipboard()->text(); // If data in system clipboard is ours and the internal copy-paste buffer is filled, use the internal buffer; otherwise parse the // system clipboard contents (case for data copied by other application). QList<QByteArrayList> clipboardTable; QList<QByteArrayList>* source; if(mimeClipboard->hasHtml() && mimeClipboard->html().contains(m_generatorStamp) && !m_buffer.isEmpty()) { source = &m_buffer; } else { clipboardTable = parseClipboard(clipboard); source = &clipboardTable; } // Stop here if there's nothing to paste if(!source->size()) return; // Starting from assumption that selection is rectangular, and then first index is upper-left corner and last is lower-right. int rows = source->size(); int columns = source->first().size(); int firstRow = indices.front().row(); int firstColumn = indices.front().column(); int selectedRows = indices.back().row() - firstRow + 1; int selectedColumns = indices.back().column() - firstColumn + 1; // If last row and column are after table size, clamp it int lastRow = qMin(firstRow + rows - 1, m->rowCount() - 1); int lastColumn = qMin(firstColumn + columns - 1, m->columnCount() - 1); // Special case: if there is only one cell of data to be pasted, paste it into all selected fields if(rows == 1 && columns == 1) { QByteArray data = source->first().first(); for(int row=firstRow;row<firstRow+selectedRows;row++) { for(int column=firstColumn;column<firstColumn+selectedColumns;column++) m->setData(m->index(row, column), data); } return; } // If more than one cell was selected, check if the selection matches the cliboard dimensions if(selectedRows != rows || selectedColumns != columns) { // Ask user if they are sure about this if(QMessageBox::question(this, QApplication::applicationName(), tr("The content of the clipboard is bigger than the range selected.\nDo you want to insert it anyway?"), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { // If the user doesn't want to paste the clipboard data anymore, stop now return; } } // If we get here, we can definitely start pasting: either the ranges match in their size or the user agreed to paste anyway // Copy the data cell by cell and as-is from the source buffer to the table int row = firstRow; for(const QByteArrayList& source_row : *source) { int column = firstColumn; for(const QByteArray& source_cell : source_row) { m->setData(m->index(row, column), source_cell); column++; if (column > lastColumn) break; } row++; if (row > lastRow) break; } }