Commit 2917e739 authored by Steven Chua's avatar Steven Chua Committed by David Hurka
Browse files

Fix Table Selection polluting clipboard history

The Table Select tool no longer automatically copies its
contents to the clipboard, but only to the selection clipboard.
(Middle-click paste clipboard.) Instead, after creating
the table, the user can right-click to bring up a popup
menu with the action "Copy Table Contents to the Clipboard".
Clicking on this will copy the table contents to the clipboard.
Ctrl+C also works.

BUG: 402110
parent 06b86531
Pipeline #45297 passed with stage
in 10 minutes and 49 seconds
......@@ -2178,8 +2178,12 @@ Context menu actions like Rename Bookmarks etc.)
</menuchoice>
</term>
<listitem>
<para>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.</para>
<para>
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.
</para>
</listitem>
</varlistentry>
<varlistentry>
......
......@@ -972,12 +972,93 @@ QString PageViewPrivate::selectedText() const
return text;
}
QMimeData *PageView::getTableContents() const
{
QString selText;
QString selHtml;
QList<double> xs = d->tableSelectionCols;
QList<double> ys = d->tableSelectionRows;
xs.prepend(0.0);
xs.append(1.0);
ys.prepend(0.0);
ys.append(1.0);
selHtml = QString::fromLatin1(
"<html><head>"
"<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">"
"</head><body><table>");
for (int r = 0; r + 1 < ys.length(); r++) {
selHtml += QLatin1String("<tr>");
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("&amp;")).replace(QLatin1Char('<'), QLatin1String("&lt;")).replace(QLatin1Char('>'), QLatin1String("&gt;"));
// Remove newlines, do not turn them into <br>, because
// Excel interprets <br> within cell as new cell...
html.replace(QLatin1Char('\n'), QLatin1String(" "));
selHtml += QStringLiteral("<td>") + html + QStringLiteral("</td>");
}
selText += QLatin1Char('\n');
selHtml += QLatin1String("</tr>\n");
}
selHtml += QLatin1String("</table></body></html>\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<double> xs = d->tableSelectionCols;
QList<double> ys = d->tableSelectionRows;
xs.prepend(0.0);
xs.append(1.0);
ys.prepend(0.0);
ys.append(1.0);
selHtml = QString::fromLatin1(
"<html><head>"
"<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">"
"</head><body><table>");
for (int r = 0; r + 1 < ys.length(); r++) {
selHtml += QLatin1String("<tr>");
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("&amp;")).replace(QLatin1Char('<'), QLatin1String("&lt;")).replace(QLatin1Char('>'), QLatin1String("&gt;"));
// Remove newlines, do not turn them into <br>, because
// Excel interprets <br> within cell as new cell...
html.replace(QLatin1Char('\n'), QLatin1String(" "));
selHtml += QStringLiteral("<td>") + html + QStringLiteral("</td>");
}
selText += QLatin1Char('\n');
selHtml += QLatin1String("</tr>\n");
}
selHtml += QLatin1String("</table></body></html>\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)) {
......
......@@ -31,6 +31,7 @@
#include <QVector>
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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment