diff --git a/doc/index.docbook b/doc/index.docbook index dbb6078d2..5dacec5b3 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -2178,8 +2178,12 @@ Context menu actions like Rename Bookmarks etc.) - Draw a rectangle around the text for the table, then use the click with the &LMB; - to divide the text block into rows and columns. A &LMB; click on a existing line removes it and merges the adjacent rows or columns. + + Draw a rectangle around the text for the table, + then click with the &LMB; to divide the text block into rows and columns. + A &LMB; click on an existing line removes it and merges the adjacent rows or columns. + Finally, just click with the &RMB; to copy the table to the clipboard. + diff --git a/part/pageview.cpp b/part/pageview.cpp index a12472dd3..5ff49b25f 100644 --- a/part/pageview.cpp +++ b/part/pageview.cpp @@ -972,12 +972,93 @@ QString PageViewPrivate::selectedText() const return text; } +QMimeData *PageView::getTableContents() const +{ + QString selText; + QString selHtml; + QList xs = d->tableSelectionCols; + QList ys = d->tableSelectionRows; + xs.prepend(0.0); + xs.append(1.0); + ys.prepend(0.0); + ys.append(1.0); + selHtml = QString::fromLatin1( + "" + "" + ""); + for (int r = 0; r + 1 < ys.length(); r++) { + selHtml += QLatin1String(""); + for (int c = 0; c + 1 < xs.length(); c++) { + Okular::NormalizedRect cell(xs[c], ys[r], xs[c + 1], ys[r + 1]); + if (c) + selText += QLatin1Char('\t'); + QString txt; + for (const TableSelectionPart &tsp : qAsConst(d->tableSelectionParts)) { + // first, crop the cell to this part + if (!tsp.rectInSelection.intersects(cell)) + continue; + Okular::NormalizedRect cellPart = tsp.rectInSelection & cell; // intersection + + // second, convert it from table coordinates to part coordinates + cellPart.left -= tsp.rectInSelection.left; + cellPart.left /= (tsp.rectInSelection.right - tsp.rectInSelection.left); + cellPart.right -= tsp.rectInSelection.left; + cellPart.right /= (tsp.rectInSelection.right - tsp.rectInSelection.left); + cellPart.top -= tsp.rectInSelection.top; + cellPart.top /= (tsp.rectInSelection.bottom - tsp.rectInSelection.top); + cellPart.bottom -= tsp.rectInSelection.top; + cellPart.bottom /= (tsp.rectInSelection.bottom - tsp.rectInSelection.top); + + // third, convert from part coordinates to item coordinates + cellPart.left *= (tsp.rectInItem.right - tsp.rectInItem.left); + cellPart.left += tsp.rectInItem.left; + cellPart.right *= (tsp.rectInItem.right - tsp.rectInItem.left); + cellPart.right += tsp.rectInItem.left; + cellPart.top *= (tsp.rectInItem.bottom - tsp.rectInItem.top); + cellPart.top += tsp.rectInItem.top; + cellPart.bottom *= (tsp.rectInItem.bottom - tsp.rectInItem.top); + cellPart.bottom += tsp.rectInItem.top; + + // now get the text + Okular::RegularAreaRect rects; + rects.append(cellPart); + txt += tsp.item->page()->text(&rects, Okular::TextPage::CentralPixelTextAreaInclusionBehaviour); + } + QString html = txt; + selText += txt.replace(QLatin1Char('\n'), QLatin1Char(' ')); + html.replace(QLatin1Char('&'), QLatin1String("&")).replace(QLatin1Char('<'), QLatin1String("<")).replace(QLatin1Char('>'), QLatin1String(">")); + // Remove newlines, do not turn them into
, because + // Excel interprets
within cell as new cell... + html.replace(QLatin1Char('\n'), QLatin1String(" ")); + selHtml += QStringLiteral(""); + } + selText += QLatin1Char('\n'); + selHtml += QLatin1String("\n"); + } + selHtml += QLatin1String("
") + html + QStringLiteral("
\n"); + + QMimeData *md = new QMimeData(); + md->setText(selText); + md->setHtml(selHtml); + + return md; +} + void PageView::copyTextSelection() const { - const QString text = d->selectedText(); - if (!text.isEmpty()) { + switch (d->mouseMode) { + case Okular::Settings::EnumMouseMode::TableSelect: { QClipboard *cb = QApplication::clipboard(); - cb->setText(text, QClipboard::Clipboard); + cb->setMimeData(getTableContents(), QClipboard::Clipboard); + } break; + + case Okular::Settings::EnumMouseMode::TextSelect: { + const QString text = d->selectedText(); + if (!text.isEmpty()) { + QClipboard *cb = QApplication::clipboard(); + cb->setText(text, QClipboard::Clipboard); + } + } break; } } @@ -2344,6 +2425,19 @@ void PageView::mousePressEvent(QMouseEvent *e) updatedRect.translate(-contentAreaPosition()); viewport()->update(updatedRect); } + } else if (rightButton && !d->tableSelectionParts.isEmpty()) { + QMenu menu(this); + QAction *copyToClipboard = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy Table Contents to Clipboard")); + const bool copyAllowed = d->document->isAllowed(Okular::AllowCopy); + + if (!copyAllowed) { + copyToClipboard->setEnabled(false); + copyToClipboard->setText(i18n("Copy forbidden by DRM")); + } + + QAction *choice = menu.exec(e->globalPos()); + if (choice == copyToClipboard) + copyTextSelection(); } break; case Okular::Settings::EnumMouseMode::TextSelect: @@ -2792,78 +2886,12 @@ void PageView::mouseReleaseEvent(QMouseEvent *e) break; } - QString selText; - QString selHtml; - QList xs = d->tableSelectionCols; - QList ys = d->tableSelectionRows; - xs.prepend(0.0); - xs.append(1.0); - ys.prepend(0.0); - ys.append(1.0); - selHtml = QString::fromLatin1( - "" - "" - ""); - for (int r = 0; r + 1 < ys.length(); r++) { - selHtml += QLatin1String(""); - for (int c = 0; c + 1 < xs.length(); c++) { - Okular::NormalizedRect cell(xs[c], ys[r], xs[c + 1], ys[r + 1]); - if (c) - selText += QLatin1Char('\t'); - QString txt; - for (const TableSelectionPart &tsp : qAsConst(d->tableSelectionParts)) { - // first, crop the cell to this part - if (!tsp.rectInSelection.intersects(cell)) - continue; - Okular::NormalizedRect cellPart = tsp.rectInSelection & cell; // intersection - - // second, convert it from table coordinates to part coordinates - cellPart.left -= tsp.rectInSelection.left; - cellPart.left /= (tsp.rectInSelection.right - tsp.rectInSelection.left); - cellPart.right -= tsp.rectInSelection.left; - cellPart.right /= (tsp.rectInSelection.right - tsp.rectInSelection.left); - cellPart.top -= tsp.rectInSelection.top; - cellPart.top /= (tsp.rectInSelection.bottom - tsp.rectInSelection.top); - cellPart.bottom -= tsp.rectInSelection.top; - cellPart.bottom /= (tsp.rectInSelection.bottom - tsp.rectInSelection.top); - - // third, convert from part coordinates to item coordinates - cellPart.left *= (tsp.rectInItem.right - tsp.rectInItem.left); - cellPart.left += tsp.rectInItem.left; - cellPart.right *= (tsp.rectInItem.right - tsp.rectInItem.left); - cellPart.right += tsp.rectInItem.left; - cellPart.top *= (tsp.rectInItem.bottom - tsp.rectInItem.top); - cellPart.top += tsp.rectInItem.top; - cellPart.bottom *= (tsp.rectInItem.bottom - tsp.rectInItem.top); - cellPart.bottom += tsp.rectInItem.top; - - // now get the text - Okular::RegularAreaRect rects; - rects.append(cellPart); - txt += tsp.item->page()->text(&rects, Okular::TextPage::CentralPixelTextAreaInclusionBehaviour); - } - QString html = txt; - selText += txt.replace(QLatin1Char('\n'), QLatin1Char(' ')); - html.replace(QLatin1Char('&'), QLatin1String("&")).replace(QLatin1Char('<'), QLatin1String("<")).replace(QLatin1Char('>'), QLatin1String(">")); - // Remove newlines, do not turn them into
, because - // Excel interprets
within cell as new cell... - html.replace(QLatin1Char('\n'), QLatin1String(" ")); - selHtml += QStringLiteral(""); - } - selText += QLatin1Char('\n'); - selHtml += QLatin1String("\n"); - } - selHtml += QLatin1String("
") + html + QStringLiteral("
\n"); - QClipboard *cb = QApplication::clipboard(); - QMimeData *md = new QMimeData(); - md->setText(selText); - md->setHtml(selHtml); - cb->setMimeData(md, QClipboard::Clipboard); if (cb->supportsSelection()) - cb->setMimeData(md, QClipboard::Selection); + cb->setMimeData(getTableContents(), QClipboard::Selection); } break; + case Okular::Settings::EnumMouseMode::TextSelect: // if it is a left release checks if is over a previous link press if (leftButton && mouseReleaseOverLink(d->mouseOverLinkObject)) { diff --git a/part/pageview.h b/part/pageview.h index eee98959a..29faa26a1 100644 --- a/part/pageview.h +++ b/part/pageview.h @@ -31,6 +31,7 @@ #include class QMenu; +class QMimeData; class KActionCollection; namespace Okular @@ -177,6 +178,7 @@ private: // start / modify / clear selection rectangle void selectionStart(const QPoint pos, const QColor &color, bool aboveAll = false); void selectionClear(const ClearMode mode = ClearAllSelection); + QMimeData *getTableContents() const; void drawTableDividers(QPainter *screenPainter); void guessTableDividers(); // update either text or rectangle selection