@@ -418,13 +418,13 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
418418 connect (selectColumnShortcut, &QShortcut::activated, this , [this ]() {
419419 if (!hasFocus () || selectionModel ()->selectedIndexes ().isEmpty ())
420420 return ;
421- selectionModel ()->select (QItemSelection ( selectionModel ()->selectedIndexes (). first (), selectionModel ()-> selectedIndexes (). last () ), QItemSelectionModel::Select | QItemSelectionModel::Columns);
421+ selectionModel ()->select (selectionModel ()->selection ( ), QItemSelectionModel::Select | QItemSelectionModel::Columns);
422422 });
423423 QShortcut* selectRowShortcut = new QShortcut (QKeySequence (" Shift+Space" ), this );
424424 connect (selectRowShortcut, &QShortcut::activated, this , [this ]() {
425425 if (!hasFocus () || selectionModel ()->selectedIndexes ().isEmpty ())
426426 return ;
427- selectionModel ()->select (QItemSelection ( selectionModel ()->selectedIndexes (). first (), selectionModel ()-> selectedIndexes (). last () ), QItemSelectionModel::Select | QItemSelectionModel::Rows);
427+ selectionModel ()->select (selectionModel ()->selection ( ), QItemSelectionModel::Select | QItemSelectionModel::Rows);
428428 });
429429
430430 // Set up frozen columns child widget
@@ -573,6 +573,13 @@ void ExtendedTableWidget::copyMimeData(const QModelIndexList& fromIndices, QMime
573573 htmlResult.append (" <style type=\" text/css\" >br{mso-data-placement:same-cell;}</style></head><body>"
574574 " <table border=1 cellspacing=0 cellpadding=2>" );
575575
576+ // Insert the columns in a set, since they could be non-contiguous.
577+ std::set<int > colsInIndexes, rowsInIndexes;
578+ for (const QModelIndex & idx : indices) {
579+ colsInIndexes.insert (idx.column ());
580+ rowsInIndexes.insert (idx.row ());
581+ }
582+
576583 int currentRow = indices.first ().row ();
577584
578585 const QString fieldSepText = " \t " ;
@@ -586,10 +593,11 @@ void ExtendedTableWidget::copyMimeData(const QModelIndexList& fromIndices, QMime
586593 // Table headers
587594 if (withHeaders || inSQL) {
588595 htmlResult.append (" <tr><th>" );
589- int firstColumn = indices.front ().column ();
590- for (int i = firstColumn; i <= indices.back ().column (); i++) {
591- QByteArray headerText = model ()->headerData (i, Qt::Horizontal, Qt::EditRole).toByteArray ();
592- if (i != firstColumn) {
596+ int firstColumn = *colsInIndexes.begin ();
597+
598+ for (int col : colsInIndexes) {
599+ QByteArray headerText = model ()->headerData (col, Qt::Horizontal, Qt::EditRole).toByteArray ();
600+ if (col != firstColumn) {
593601 result.append (fieldSepText);
594602 htmlResult.append (" </th><th>" );
595603 sqlInsertStatement.append (" , " );
@@ -604,79 +612,89 @@ void ExtendedTableWidget::copyMimeData(const QModelIndexList& fromIndices, QMime
604612 sqlInsertStatement.append (" ) VALUES (" );
605613 }
606614
607- // Table data rows
608- for (const QModelIndex& index : indices) {
609- QFont font;
610- font.fromString (index.data (Qt::FontRole).toString ());
611- const QString fontStyle (font.italic () ? " italic" : " normal" );
612- const QString fontWeigth (font.bold () ? " bold" : " normal" );
613- const QString fontDecoration (font.underline () ? " text-decoration: underline;" : " " );
614- const QColor bgColor (index.data (Qt::BackgroundRole).toString ());
615- const QColor fgColor (index.data (Qt::ForegroundRole).toString ());
616- const Qt::Alignment align (index.data (Qt::TextAlignmentRole).toInt ());
617- const QString textAlign (CondFormat::alignmentTexts ().at (CondFormat::fromCombinedAlignment (align)).toLower ());
618- const QString style = QString (" font-family: '%1'; font-size: %2pt; font-style: %3; font-weight: %4;%5 "
619- " background-color: %6; color: %7; text-align: %8" ).arg (
620- font.family ().toHtmlEscaped (),
621- QString::number (font.pointSize ()),
622- fontStyle,
623- fontWeigth,
624- fontDecoration,
625- bgColor.name (),
626- fgColor.name (),
627- textAlign);
628-
629- // Separators. For first cell, only opening table row tags must be added for the HTML and nothing for the text version.
630- if (indices.first () == index) {
631- htmlResult.append (QString (" <tr><td style=\" %1\" >" ).arg (style));
632- sqlResult.append (sqlInsertStatement);
633- } else if (index.row () != currentRow) {
634- result.append (rowSepText);
635- htmlResult.append (QString (" </td></tr><tr><td style=\" %1\" >" ).arg (style));
636- sqlResult.append (" );" + rowSepText + sqlInsertStatement);
637- } else {
638- result.append (fieldSepText);
639- htmlResult.append (QString (" </td><td style=\" %1\" >" ).arg (style));
640- sqlResult.append (" , " );
641- }
642- currentRow = index.row ();
615+ // Iterate over rows x cols checking if the index actually exists when needed, in order
616+ // to support non-rectangular selections.
617+ for (const int row : rowsInIndexes) {
618+ for (const int column : colsInIndexes) {
619+
620+ const QModelIndex index = indices.first ().sibling (row, column);
621+ QString style;
622+ if (indices.contains (index)) {
623+ QFont font;
624+ font.fromString (index.data (Qt::FontRole).toString ());
625+ const QString fontStyle (font.italic () ? " italic" : " normal" );
626+ const QString fontWeigth (font.bold () ? " bold" : " normal" );
627+ const QString fontDecoration (font.underline () ? " text-decoration: underline;" : " " );
628+ const QColor bgColor (index.data (Qt::BackgroundRole).toString ());
629+ const QColor fgColor (index.data (Qt::ForegroundRole).toString ());
630+ const Qt::Alignment align (index.data (Qt::TextAlignmentRole).toInt ());
631+ const QString textAlign (CondFormat::alignmentTexts ().at (CondFormat::fromCombinedAlignment (align)).toLower ());
632+ style = QString (" style=\" font-family: '%1'; font-size: %2pt; font-style: %3; font-weight: %4;%5 "
633+ " background-color: %6; color: %7; text-align: %8\" " ).arg (
634+ font.family ().toHtmlEscaped (),
635+ QString::number (font.pointSize ()),
636+ fontStyle,
637+ fontWeigth,
638+ fontDecoration,
639+ bgColor.name (),
640+ fgColor.name (),
641+ textAlign);
642+ }
643643
644- QImage img;
645- QVariant bArrdata = index.data (Qt::EditRole);
644+ // Separators. For first cell, only opening table row tags must be added for the HTML and nothing for the text version.
645+ if (index.row () == *rowsInIndexes.begin () && index.column () == *colsInIndexes.begin ()) {
646+ htmlResult.append (QString (" <tr><td %1>" ).arg (style));
647+ sqlResult.append (sqlInsertStatement);
648+ } else if (index.row () != currentRow) {
649+ result.append (rowSepText);
650+ htmlResult.append (QString (" </td></tr><tr><td %1>" ).arg (style));
651+ sqlResult.append (" );" + rowSepText + sqlInsertStatement);
652+ } else {
653+ result.append (fieldSepText);
654+ htmlResult.append (QString (" </td><td %1>" ).arg (style));
655+ sqlResult.append (" , " );
656+ }
646657
647- // Table cell data: image? Store it as an embedded image in HTML
648- if (!inSQL && img.loadFromData (bArrdata.toByteArray ()))
649- {
650- QByteArray ba;
651- QBuffer buffer (&ba);
652- buffer.open (QIODevice::WriteOnly);
653- img.save (&buffer, " PNG" );
654- buffer.close ();
655-
656- QString imageBase64 = ba.toBase64 ();
657- htmlResult.append (" <img src=\" data:image/png;base64," );
658- htmlResult.append (imageBase64);
659- result.append (QString ());
660- htmlResult.append (" \" alt=\" Image\" >" );
661- } else {
662- QByteArray text;
663- if (!m->isBinary (index)) {
664- text = bArrdata.toByteArray ();
665-
666- // Table cell data: text
667- if (text.contains (' \n ' ) || text.contains (' \t ' ))
668- htmlResult.append (" <pre>" + QString (text).toHtmlEscaped () + " </pre>" );
669- else
670- htmlResult.append (QString (text).toHtmlEscaped ());
671-
672- result.append (text);
673- sqlResult.append (sqlb::escapeString (text));
674- } else
675- // Table cell data: binary. Save as BLOB literal in SQL
676- sqlResult.append ( " X'" + bArrdata.toByteArray ().toHex () + " '" );
658+ currentRow = index.row ();
659+
660+ QImage img;
661+ QVariant bArrdata = indices.contains (index) ? index.data (Qt::EditRole) : QVariant ();
677662
663+ // Table cell data: image? Store it as an embedded image in HTML
664+ if (!inSQL && img.loadFromData (bArrdata.toByteArray ()))
665+ {
666+ QByteArray ba;
667+ QBuffer buffer (&ba);
668+ buffer.open (QIODevice::WriteOnly);
669+ img.save (&buffer, " PNG" );
670+ buffer.close ();
671+
672+ QString imageBase64 = ba.toBase64 ();
673+ htmlResult.append (" <img src=\" data:image/png;base64," );
674+ htmlResult.append (imageBase64);
675+ result.append (QString ());
676+ htmlResult.append (" \" alt=\" Image\" >" );
677+ } else {
678+ if (bArrdata.isNull ()) {
679+ sqlResult.append (" NULL" );
680+ } else if (!m->isBinary (index)) {
681+ QByteArray text = bArrdata.toByteArray ();
682+
683+ // Table cell data: text
684+ if (text.contains (' \n ' ) || text.contains (' \t ' ))
685+ htmlResult.append (" <pre>" + QString (text).toHtmlEscaped () + " </pre>" );
686+ else
687+ htmlResult.append (QString (text).toHtmlEscaped ());
688+
689+ result.append (text);
690+ sqlResult.append (sqlb::escapeString (text));
691+ } else
692+ // Table cell data: binary. Save as BLOB literal in SQL
693+ sqlResult.append ( " X'" + bArrdata.toByteArray ().toHex () + " '" );
694+ }
678695 }
679696 }
697+
680698 sqlResult.append (" );" );
681699
682700 if ( inSQL )
@@ -1022,6 +1040,14 @@ std::unordered_set<size_t> ExtendedTableWidget::colsInSelection() const
10221040 return colsInSelection;
10231041}
10241042
1043+ std::set<size_t > ExtendedTableWidget::rowsInSelection () const
1044+ {
1045+ std::set<size_t > rowsInSelection;
1046+ for (const QModelIndex & idx : selectedIndexes ())
1047+ rowsInSelection.insert (static_cast <size_t >(idx.row ()));
1048+ return rowsInSelection;
1049+ }
1050+
10251051void ExtendedTableWidget::cellClicked (const QModelIndex& index)
10261052{
10271053 // If Ctrl-Shift is pressed try to jump to the row referenced by the foreign key of the clicked cell
0 commit comments