void QmitkDataNodeSelectionProvider::SetSelection(berry::ISelection::ConstPointer selection,
        QItemSelectionModel::SelectionFlags flags)
{
    if (!qSelectionModel) return;

    mitk::DataNodeSelection::ConstPointer dataNodeSelection = selection.Cast<const mitk::DataNodeSelection>();
    if (dataNodeSelection)
    {
        const QAbstractItemModel* model = qSelectionModel->model();

        QItemSelection newSelection;
        const std::list<mitk::DataNode::Pointer> selectedNodes = dataNodeSelection->GetSelectedDataNodes();
        for (auto i = selectedNodes.begin();
                i != selectedNodes.end(); ++i)
        {
            QModelIndexList matched = model->match(model->index(0, 0), QmitkDataNodeRawPointerRole,
                                                   QVariant::fromValue<mitk::DataNode*>(i->GetPointer()), 1, Qt::MatchRecursive);
            if (!matched.empty())
            {
                newSelection.select(matched.front(), matched.front());
            }
        }
        qSelectionModel->select(newSelection, flags);
    }
    else
    {
        QtSelectionProvider::SetSelection(selection, flags);
    }
}
void DialogSpectraTemplates::toggle_push() {
  if (selection_model_.selectedIndexes().empty()) {
    ui->pushEdit->setEnabled(false);
    ui->pushDelete->setEnabled(false);
    ui->pushUp->setEnabled(false);
    ui->pushDown->setEnabled(false);
  } else {
    ui->pushDelete->setEnabled(true);
  }

  if (selection_model_.selectedRows().size() == 1) {
    ui->pushEdit->setEnabled(true);
    QModelIndexList ixl = selection_model_.selectedRows();
    if (ixl.front().row() > 0)
      ui->pushUp->setEnabled(true);
    else
      ui->pushUp->setEnabled(false);
    if ((ixl.front().row() + 1) < templates_.size())
      ui->pushDown->setEnabled(true);
    else
      ui->pushDown->setEnabled(false);
  }

  if (templates_.empty())
    ui->pushExport->setEnabled(false);
  else
    ui->pushExport->setEnabled(true);

}
void ExtendedTableWidget::copy()
{
    // Get list of selected items
    QItemSelectionModel* selection = selectionModel();
    QModelIndexList indices = selection->selectedIndexes();

    // Abort if there's nothing to copy
    if(indices.size() == 0)
    {
        return;
    } else if(indices.size() == 1) {
        qApp->clipboard()->setText(indices.front().data().toString());
        return;
    }

    // Sort the items by row, then by column
    qSort(indices);

    // Go through all the items...
    QString result;
    QModelIndex prev = indices.front();
    indices.removeFirst();
    foreach(QModelIndex index, indices)
    {
        // Add the content of this cell to the clipboard string
        result.append(QString("\"%1\"").arg(prev.data().toString()));

        // If this is a new row add a line break, if not add a tab for cell separation
        if(index.row() != prev.row())
            result.append("\r\n");
        else
            result.append("\t");

        prev = index;
    }
void DialogSpectraTemplates::on_pushDown_clicked()
{
  QModelIndexList ixl = ui->spectraSetupView->selectionModel()->selectedRows();
  if (ixl.empty())
    return;
  templates_.down(ixl.front().row());
  selection_model_.setCurrentIndex(ixl.front().sibling(ixl.front().row()+1, ixl.front().column()),
                                   QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
  table_model_.update();
  toggle_push();
}
Beispiel #5
0
void MainWindow::startMRFRegistration()
{
	///////////////////////////////////////////////
	// First we must check that we are dealing with
	// an image series
	///////////////////////////////////////////////
	QModelIndexList selectedIndices = this->treeView->selectionModel()->selectedIndexes();

	// do some sanity checks
	if(selectedIndices.empty())
	{
		QMessageBox msgBox;
		msgBox.setText(tr("Please select a time series to register"));
		msgBox.exec();
		return;
	}

	if(selectedIndices.size() > 1)
	{
		QMessageBox msgBox;
		msgBox.setText(tr("Easy now, only one selected series at a time please..."));
		msgBox.exec();
		return;
	}

	// get the selected node out of the data tree
	if(!selectedIndices.front().isValid())
	{
		QMessageBox msgBox;
		msgBox.setText(tr("Invalid model index, not sure what's going on here..."));
		msgBox.exec();
		return;
	}

	mitk::DataNode::Pointer node = dataTree->GetNode(selectedIndices.front());

	if(node->GetData()->GetTimeSteps() <= 1)
	{
		QMessageBox msgBox;
		msgBox.setText(tr("The series you have selected has only one time step, this wont work..."));
		msgBox.exec();
		return;
	}

	/////////////////////////////////////////////////////////////////
	// Create a new MRF registration thingy
	/////////////////////////////////////////////////////////////////
	MRFRegistration * registration = new MRFRegistration(this);
	if(registration->initialise(node))
	{
		registration->exec();
	}
}
void SignaturePanel::slotRemove()
{
    const QModelIndexList selectedIndexes = m_listView->selectionModel()->selectedIndexes ();
    if (selectedIndexes.empty())
        return;

    closeEditor();
    // scroll to previous
    if (const int row = selectedIndexes.front().row())
        m_listView->setCurrentIndex (selectedIndexes.front().sibling(row - 1, 0));

    for (int  i = selectedIndexes.size() - 1; i >= 0; i--)
        qDeleteAll(m_model->takeRow(selectedIndexes[i].row()));
}
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;
            }
Beispiel #8
0
void KMyMoneyAccountCombo::setSelected(const QString& id)
{
  // make sure, we have all items available for search
  if(isEditable()) {
    lineEdit()->clear();
  }
  // find which item has this id and set is as the current item
  QModelIndexList list = model()->match(model()->index(0, 0), AccountsModel::AccountIdRole,
                                        QVariant(id),
                                        1,
                                        Qt::MatchFlags(Qt::MatchExactly | Qt::MatchCaseSensitive | Qt::MatchRecursive));
  if (list.count() > 0) {
    d->m_lastSelectedAccount = id;
    QModelIndex index = list.front();
    QString accountName = d->fullAccountName(model(), index);

    // set the current index, for this we must set the parent item as the root item
    QModelIndex oldRootModelIndex = rootModelIndex();
    setRootModelIndex(index.parent());
    setCurrentIndex(index.row());
    if(isEditable()) {
      d->m_popupView->collapseAll();
      d->m_popupView->expand(index);
    }
    // restore the old root item
    setRootModelIndex(oldRootModelIndex);
    if(isEditable()) {
      lineEdit()->setText(accountName);
    }
    emit accountSelected(id);
  }
}
void QmitkCorrespondingPointSetsView::OnPointSelectionChanged(const QItemSelection& selected, const QItemSelection&  /*deselected*/)
{
  if(m_SelfCall)
    return;

  std::vector<mitk::DataNode*> pointSetNodes = this->GetPointSetNodes();

  QModelIndexList selectedIndexes = selected.indexes();
  m_CorrespondingPointSetsModel->SetSelectedPointSetIndex(-1);
  if (selectedIndexes.size() > 0)
  {
    QModelIndex index = selectedIndexes.front();
    mitk::DataNode* pointSetNode = NULL;
    mitk::PointSet* pointSet = NULL;

    if (index.column() == 0)
    {
      pointSetNode = pointSetNodes.front();
    }
    else
    {
      pointSetNode = pointSetNodes.back();
    }

    if (pointSetNode)
    {
      this->m_CorrespondingPointSetsModel->UpdateSelection(pointSetNode);
      pointSet = dynamic_cast<mitk::PointSet*>(pointSetNode->GetData());

      if( pointSet->GetPointSet(m_CorrespondingPointSetsModel->GetTimeStep()))
      for (mitk::PointSet::PointsContainer::Iterator it = pointSet->GetPointSet(m_CorrespondingPointSetsModel->GetTimeStep())->GetPoints()->Begin();
        it != pointSet->GetPointSet(m_CorrespondingPointSetsModel->GetTimeStep())->GetPoints()->End(); ++it)
        {
          QModelIndex tempIndex;
          if (m_CorrespondingPointSetsModel->GetModelIndexForPointID(it->Index(), tempIndex, index.column()))
          {
            if (tempIndex == index)
            {
              pointSet->SetSelectInfo(it->Index(), true, m_CorrespondingPointSetsModel->GetTimeStep());

              m_CorrespondingPointSetsModel->SetSelectedPointSetIndex(index.column());
              if ( this->GetMultiWidget() != NULL)
              {
                this->GetMultiWidget()->MoveCrossToPosition(pointSet->GetPoint(it->Index(), m_CorrespondingPointSetsModel->GetTimeStep()));
              }
            }
            else
            {
              pointSet->SetSelectInfo(it->Index(), false, m_CorrespondingPointSetsModel->GetTimeStep());
            }
          }
        }
    }
  }
  emit(SignalPointSelectionChanged());
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
  this->UpdateSelectionHighlighting();
  m_SelfCall = false;
}
Beispiel #10
0
/**
  * Get the index of the selected parent account.
  *
  * @return The model index of the selected parent account.
  */
QModelIndex HierarchyFilterProxyModel::getSelectedParentAccountIndex() const
{
  QModelIndexList list = match(index(0, 0), AccountsModel::AccountIdRole, m_currentAccountId, -1, Qt::MatchFlags(Qt::MatchExactly | Qt::MatchCaseSensitive | Qt::MatchRecursive));
  if (!list.empty()) {
    return list.front().parent();
  }
  return QModelIndex();
}
/******************************************************************************
* Returns the currently selected item in the modification list.
******************************************************************************/
ModificationListItem* ModificationListModel::selectedItem() const
{
	QModelIndexList selection = _selectionModel->selectedRows();
	if(selection.empty())
		return nullptr;
	else
		return item(selection.front().row());
}
	QModelIndex PlayListWidget::selectedItem() const
	{
		QModelIndexList rows = view->selectionModel()->selectedRows();
		if (rows.count() > 0)
			return proxy_model->mapToSource(rows.front());
		else
			return QModelIndex();
	}
	void PlayListWidget::onSelectionChanged(const QItemSelection & s, const QItemSelection & d)
	{
		Q_UNUSED(d);
		QModelIndexList idx = s.indexes();
		if (idx.count() > 0)
			fileSelected(fileForIndex(idx.front()));
		else
			fileSelected(MediaFileRef());
	}
int
StageListView::selectedRow() const
{
	QModelIndexList const selection(selectionModel()->selectedRows(0));
	if (selection.empty()) {
		return - 1;
	}
	return selection.front().row();
}
void DialogSpectraTemplates::on_pushEdit_clicked()
{
  QModelIndexList ixl = ui->spectraSetupView->selectionModel()->selectedRows();
  if (ixl.empty())
    return;
  int i = ixl.front().row();
  DialogSpectrumTemplate* newDialog = new DialogSpectrumTemplate(templates_.get(i), current_dets_, true, this);
  connect(newDialog, SIGNAL(templateReady(Qpx::Spectrum::Template)), this, SLOT(change_template(Qpx::Spectrum::Template)));
  newDialog->exec();
}
    void QueueManagerWidget::updateButtons()
    {
        QModelIndexList idx = view->selectionModel()->selectedRows();
        if (idx.count() == 0)
        {
            move_top->setEnabled(false);
            move_up->setEnabled(false);
            move_down->setEnabled(false);
            move_bottom->setEnabled(false);
        }
        else
        {
            move_top->setEnabled(idx.front().row() != 0);
            move_up->setEnabled(idx.front().row() != 0);

            int rows = model->rowCount(QModelIndex());
            move_down->setEnabled(idx.back().row() != rows - 1);
            move_bottom->setEnabled(idx.back().row() != rows - 1);
        }
    }
Beispiel #17
0
void ObjectInspector::ObjectInspectorPrivate::setFormWindowBlocked(QDesignerFormWindowInterface *fwi)
{
    FormWindowBase *fw = qobject_cast<FormWindowBase *>(fwi);
    const bool formWindowChanged = m_formWindow != fw;

    m_formWindow = fw;

    const int oldWidth = m_treeView->columnWidth(0);
    const int xoffset = m_treeView->horizontalScrollBar()->value();
    const int yoffset = m_treeView->verticalScrollBar()->value();

    if (formWindowChanged)
        m_formFakeDropTarget = 0;

    switch (m_model->update(m_formWindow)) {
    case ObjectInspectorModel::NoForm:
        clear();
        return;
    case ObjectInspectorModel::Rebuilt: // Complete rebuild: Just apply cursor selection
        applyCursorSelection();
        m_treeView->expandAll();
        if (formWindowChanged) {
            m_treeView->resizeColumnToContents(0);
        } else {
            m_treeView->setColumnWidth(0, oldWidth);
            m_treeView->horizontalScrollBar()->setValue(xoffset);
            m_treeView->verticalScrollBar()->setValue(yoffset);
        }
        break;
    case ObjectInspectorModel::Updated: {
        // Same structure (property changed or click on the form)
        // We maintain a selection of unmanaged objects
        // only if the cursor is in state "mainContainer() == current".
        // and we have a non-managed selection.
        // Else we take over the cursor selection.
        bool applySelection = !mainContainerIsCurrent(m_formWindow);
        if (!applySelection) {
            const QModelIndexList currentIndexes = m_treeView->selectionModel()->selectedRows(0);
            if (currentIndexes.empty()) {
                applySelection = true;
            } else {
                applySelection = selectionType(m_formWindow, m_model->objectAt(currentIndexes.front())) == ManagedWidgetSelection;
            }
        }
        if (applySelection)
            applyCursorSelection();
    }
        break;
    }
}
Beispiel #18
0
void TrainingWidget::playSelectedWord()
{
    QModelIndexList indexList = treeViewResults->selectionModel()->selectedIndexes();
    if (indexList.empty())
        return;

    const QModelIndex &selIndex = indexList.front();
    if (!selIndex.isValid())
        return;

    m_game->removeTestRound();
    // Use the hidden column to get the result number
    const QModelIndex &index = m_model->index(selIndex.row(), HIDDEN_COLUMN);
    m_game->trainingPlayResult(m_model->data(index).toUInt());
    emit gameUpdated();
    lineEditRack->setFocus();
}
    QDesignerWidgetDataBaseItemInterface *QDesignerPromotionDialog::databaseItemAt(const QItemSelection &selected, unsigned &flags) const {
        flags = 0;
        const QModelIndexList indexes = selected.indexes();
        if (indexes.empty())
            return 0;

        bool referenced;
        QDesignerWidgetDataBaseItemInterface *dbItem = m_model->databaseItemAt(indexes.front(), &referenced);

        if (dbItem) {
            if (referenced)
                flags |= Referenced;
            // In choose mode, can we promote to the class?
            if (m_mode == ModeEditChooseClass &&  dbItem && dbItem->isPromoted() && dbItem->extends() ==  m_promotableWidgetClassName)
                flags |= CanPromote;

        }
        return dbItem;
    }
Beispiel #20
0
void ObjectInspector::ObjectInspectorPrivate::selectIndexRange(const QModelIndexList &indexes, unsigned flags)
{
    if (indexes.empty())
        return;

    QItemSelectionModel::SelectionFlags selectFlags = QItemSelectionModel::Select|QItemSelectionModel::Rows;
    if (!(flags & AddToSelection))
        selectFlags |= QItemSelectionModel::Clear;
    if (flags & MakeCurrent)
        selectFlags |= QItemSelectionModel::Current;

    QItemSelectionModel *selectionModel = m_treeView->selectionModel();
    const QModelIndexList::const_iterator cend = indexes.constEnd();
    for (QModelIndexList::const_iterator it = indexes.constBegin(); it != cend; ++it)
        if (it->column() == 0) {
            selectionModel->select(*it, selectFlags);
            selectFlags &= ~(QItemSelectionModel::Clear|QItemSelectionModel::Current);
        }
    if (flags & MakeCurrent)
        m_treeView->scrollTo(indexes.front(), QAbstractItemView::EnsureVisible);
}
void KMyMoneyAccountTreeView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
  QTreeView::selectionChanged(selected, deselected);
  if (!selected.empty()) {
    QModelIndexList indexes = selected.front().indexes();
    if (!indexes.empty()) {
      QVariant data = model()->data(model()->index(indexes.front().row(), AccountsModel::Account, indexes.front().parent()), AccountsModel::AccountRole);
      if (data.isValid()) {
        if (data.canConvert<MyMoneyAccount>()) {
          emit selectObject(data.value<MyMoneyAccount>());
        }
        if (data.canConvert<MyMoneyInstitution>()) {
          emit selectObject(data.value<MyMoneyInstitution>());
        }
        // an object was successfully selected
        return;
      }
    }
  }
  // since no object was selected reset the object selection
  emit selectObject(MyMoneyAccount());
  emit selectObject(MyMoneyInstitution());
}
Beispiel #22
0
int MainWnd::GetSelectedRow()
{
    QModelIndexList lst = ui->tableWidget->selectionModel()->selection().indexes();
    return (lst.isEmpty() ? -1 : lst.front().row());
}
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;
    }
}
Beispiel #24
0
void GuiBibtex::setFileEncodings(vector<docstring> const m)
{
	for (docstring const & s: m) {
		docstring key;
		QString enc = toqstr(split(s, key, ' '));
		QModelIndexList qmil =
				selected_model_.match(selected_model_.index(0, 0),
						     Qt::DisplayRole, toqstr(key), 1,
						     Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap));
		if (!qmil.empty()) {
			QComboBox * cb = qobject_cast<QComboBox*>(selectedLV->indexWidget(selected_model_.index(qmil.front().row(), 1)));
			cb->setCurrentIndex(cb->findData(enc));
		}
	}
}
void ExtendedTableWidget::copy(const bool withHeaders)
{
    QModelIndexList indices = selectionModel()->selectedIndexes();

    // Remove all indices from hidden columns, because if we don't we might copy data from hidden columns as well which is very
    // unintuitive; especially copying the rowid column when selecting all columns of a table is a problem because pasting the data
    // won't work as expected.
    QMutableListIterator<QModelIndex> i(indices);
    while (i.hasNext()) {
        if (isColumnHidden(i.next().column()))
            i.remove();
    }

    // Abort if there's nothing to copy
    if (indices.isEmpty())
        return;

    SqliteTableModel* m = qobject_cast<SqliteTableModel*>(model());

    // Clear internal copy-paste buffer
    m_buffer.clear();

    // If a single cell is selected, copy it to clipboard
    if (!withHeaders && indices.size() == 1) {
        QImage img;
        QVariant data = m->data(indices.first(), Qt::EditRole);

        if (img.loadFromData(data.toByteArray()))
        {
            // If it's an image, copy the image data to the clipboard
            qApp->clipboard()->setImage(img);
            return;
        } else {
            // It it's not an image, check if it's an empty field
            if (data.toByteArray().isEmpty())
            {
                // The field is either NULL or empty. Those are are handled via the internal copy-paste buffer
                qApp->clipboard()->setText(QString());      // Calling clear() alone doesn't seem to work on all systems
                qApp->clipboard()->clear();
                m_buffer.push_back(QByteArrayList{data.toByteArray()});
                return;
            }

            // The field isn't empty. Copy the text to the clipboard without quoting (for general plain text clipboard)
            qApp->clipboard()->setText(data.toByteArray());
            return;
        }
    }

    // If we got here, there are multiple selected cells, or copy with headers was requested.
    // In this case, we copy selected data into internal copy-paste buffer and then
    // we write a table both in HTML and text formats to the system clipboard.

    // Copy selected data into internal copy-paste buffer
    int last_row = indices.first().row();
    QByteArrayList lst;
    for(int i=0;i<indices.size();i++)
    {
        if(indices.at(i).row() != last_row)
        {
            m_buffer.push_back(lst);
            lst.clear();
        }
        lst << indices.at(i).data(Qt::EditRole).toByteArray();
        last_row = indices.at(i).row();
    }
    m_buffer.push_back(lst);

    QString result;
    QString htmlResult = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">";
    htmlResult.append("<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">");
    htmlResult.append("<title></title>");

    // The generator-stamp is later used to know whether the data in the system clipboard is still ours.
    // In that case we will give precedence to our internal copy buffer.
    QString now = QDateTime::currentDateTime().toString("YYYY-MM-DDTHH:mm:ss.zzz");
    m_generatorStamp = QString("<meta name=\"generator\" content=\"%1\"><meta name=\"date\" content=\"%2\">").arg(QApplication::applicationName().toHtmlEscaped(), now);
    htmlResult.append(m_generatorStamp);
    // TODO: is this really needed by Excel, since we use <pre> for multi-line cells?
    htmlResult.append("<style type=\"text/css\">br{mso-data-placement:same-cell;}</style></head><body><table>");

    int currentRow = indices.first().row();

    const QString fieldSepHtml = "</td><td>";
    const QString rowSepHtml = "</td></tr><tr><td>";
    const QString fieldSepText = "\t";
    const QString rowSepText = "\r\n";

    // Table headers
    if (withHeaders) {
        htmlResult.append("<tr><th>");
        int firstColumn = indices.front().column();
        for(int i = firstColumn; i <= indices.back().column(); i++) {
            QByteArray headerText = model()->headerData(i, Qt::Horizontal, Qt::DisplayRole).toByteArray();
            if (i != firstColumn) {
                result.append(fieldSepText);
                htmlResult.append("</th><th>");
            }

            result.append(escapeCopiedData(headerText));
            htmlResult.append(headerText);
        }
        result.append(rowSepText);
        htmlResult.append("</th></tr>");
    }

    // Table data rows
    for(const QModelIndex& index : indices) {
        // Separators. For first cell, only opening table row tags must be added for the HTML and nothing for the text version.
        if (indices.first() == index)
            htmlResult.append("<tr><td>");
        else if (index.row() != currentRow) {
            result.append(rowSepText);
            htmlResult.append(rowSepHtml);
        } else {
            result.append(fieldSepText);
            htmlResult.append(fieldSepHtml);
        }
        currentRow = index.row();

        QImage img;
        QVariant data = index.data(Qt::EditRole);

        // Table cell data: image? Store it as an embedded image in HTML and as base 64 in text version
        if (img.loadFromData(data.toByteArray()))
        {
            QByteArray ba;
            QBuffer buffer(&ba);
            buffer.open(QIODevice::WriteOnly);
            img.save(&buffer, "PNG");
            buffer.close();

            QString imageBase64 = ba.toBase64();
            htmlResult.append("<img src=\"data:image/png;base64,");
            htmlResult.append(imageBase64);
            result.append(QString());
            htmlResult.append("\" alt=\"Image\">");
        } else {
            QByteArray text;
            if (!m->isBinary(index))
                text = data.toByteArray();

            // Table cell data: text
            if (text.contains('\n') || text.contains('\t'))
                htmlResult.append("<pre>" + QString(text).toHtmlEscaped() + "</pre>");
            else
                htmlResult.append(QString(text).toHtmlEscaped());

            result.append(escapeCopiedData(text));
        }
    }

    QMimeData *mimeData = new QMimeData;
    mimeData->setHtml(htmlResult + "</td></tr></table></body></html>");
    mimeData->setText(result);
    qApp->clipboard()->setMimeData(mimeData);
}