Copying text to clipboard

This commit is contained in:
Jakub Melka 2020-01-26 17:48:38 +01:00
parent 12b2f44619
commit 0bc64494fd
4 changed files with 103 additions and 0 deletions

View File

@ -483,6 +483,33 @@ PDFTextSelection PDFTextLayout::createTextSelection(PDFInteger pageIndex, const
return selection; return selection;
} }
QString PDFTextLayout::getTextFromSelection(PDFTextSelection::iterator itBegin, PDFTextSelection::iterator itEnd, PDFInteger pageIndex) const
{
QStringList text;
if (itBegin != itEnd)
{
PDFTextFlows flows = PDFTextFlow::createTextFlows(*this, PDFTextFlow::RemoveSoftHyphen, pageIndex);
Q_ASSERT(flows.size() < 2);
if (!flows.empty())
{
const PDFTextFlow& textFlow = flows.front();
for (auto it = itBegin; it != itEnd; ++it)
{
text << textFlow.getText(it->start, it->end);
}
}
}
return text.join("\n");
}
QString PDFTextLayout::getTextFromSelection(const PDFTextSelection& selection, PDFInteger pageIndex) const
{
return getTextFromSelection(selection.begin(pageIndex), selection.end(pageIndex), pageIndex);
}
QDataStream& operator>>(QDataStream& stream, PDFTextLayout& layout) QDataStream& operator>>(QDataStream& stream, PDFTextLayout& layout)
{ {
stream >> layout.m_characters; stream >> layout.m_characters;
@ -1083,6 +1110,17 @@ PDFTextSelection::iterator PDFTextSelection::end(PDFInteger pageIndex) const
return std::upper_bound(m_items.cbegin(), m_items.end(), item); return std::upper_bound(m_items.cbegin(), m_items.end(), item);
} }
PDFTextSelection::iterator PDFTextSelection::nextPageRange(iterator currentPageRange) const
{
auto it = currentPageRange;
while (it != m_items.cend() && it->start.pageIndex == currentPageRange->start.pageIndex)
{
++it;
}
return it;
}
PDFFindResults PDFTextFlow::find(const QString& text, Qt::CaseSensitivity caseSensitivity) const PDFFindResults PDFTextFlow::find(const QString& text, Qt::CaseSensitivity caseSensitivity) const
{ {
PDFFindResults results; PDFFindResults results;
@ -1133,6 +1171,21 @@ PDFFindResults PDFTextFlow::find(const QRegularExpression& expression) const
return results; return results;
} }
QString PDFTextFlow::getText(const PDFCharacterPointer& begin, const PDFCharacterPointer& end) const
{
auto it = std::find(m_characterPointers.cbegin(), m_characterPointers.cend(), begin);
auto itEnd = std::find(m_characterPointers.cbegin(), m_characterPointers.cend(), end);
const std::size_t startIndex = std::distance(m_characterPointers.cbegin(), it);
const std::size_t endIndex = std::distance(m_characterPointers.cbegin(), itEnd);
if (startIndex <= endIndex)
{
return m_text.mid(int(startIndex), int(endIndex - startIndex + 1));
}
return QString();
}
void PDFTextFlow::merge(const PDFTextFlow& next) void PDFTextFlow::merge(const PDFTextFlow& next)
{ {
m_text += next.m_text; m_text += next.m_text;

View File

@ -238,9 +238,15 @@ public:
/// Returns iterator to end of page range /// Returns iterator to end of page range
iterator end(PDFInteger pageIndex) const; iterator end(PDFInteger pageIndex) const;
/// Returns iterator to next page range
iterator nextPageRange(iterator currentPageRange) const;
/// Returns true, if text selection is empty /// Returns true, if text selection is empty
bool isEmpty() const { return m_items.empty(); } bool isEmpty() const { return m_items.empty(); }
iterator begin() const { return m_items.cbegin(); }
iterator end() const { return m_items.cend(); }
private: private:
PDFTextSelectionColoredItems m_items; PDFTextSelectionColoredItems m_items;
}; };
@ -288,6 +294,11 @@ public:
/// \param expression Regular expression to be matched /// \param expression Regular expression to be matched
PDFFindResults find(const QRegularExpression& expression) const; PDFFindResults find(const QRegularExpression& expression) const;
/// Returns text form character pointers
/// \param begin Begin character
/// \param end End character
QString getText(const PDFCharacterPointer& begin, const PDFCharacterPointer& end) const;
/// Merge data from \p next flow (i.e. connect two consecutive flows) /// Merge data from \p next flow (i.e. connect two consecutive flows)
void merge(const PDFTextFlow& next); void merge(const PDFTextFlow& next);
@ -347,6 +358,17 @@ public:
/// \param point2 Second point /// \param point2 Second point
PDFTextSelection createTextSelection(PDFInteger pageIndex, const QPointF& point1, const QPointF& point2); PDFTextSelection createTextSelection(PDFInteger pageIndex, const QPointF& point1, const QPointF& point2);
/// Returns string from text selection
/// \param itBegin Iterator (begin range)
/// \param itEnd Iterator (end range)
/// \param pageIndex Index of the page
QString getTextFromSelection(PDFTextSelection::iterator itBegin, PDFTextSelection::iterator itEnd, PDFInteger pageIndex) const;
/// Returns string from text selection
/// \param selection Text selection
/// \param pageIndex Index of the page
QString getTextFromSelection(const PDFTextSelection& selection, PDFInteger pageIndex) const;
friend QDataStream& operator<<(QDataStream& stream, const PDFTextLayout& layout); friend QDataStream& operator<<(QDataStream& stream, const PDFTextLayout& layout);
friend QDataStream& operator>>(QDataStream& stream, PDFTextLayout& layout); friend QDataStream& operator>>(QDataStream& stream, PDFTextLayout& layout);

View File

@ -28,6 +28,8 @@
#include <QKeyEvent> #include <QKeyEvent>
#include <QMouseEvent> #include <QMouseEvent>
#include <QWheelEvent> #include <QWheelEvent>
#include <QClipboard>
#include <QApplication>
namespace pdf namespace pdf
{ {
@ -602,7 +604,32 @@ void PDFSelectTextTool::updateCursor()
void PDFSelectTextTool::onActionCopyText() void PDFSelectTextTool::onActionCopyText()
{ {
if (isActive())
{
// Jakub Melka: we must obey document permissions
if (getDocument()->getStorage().getSecurityHandler()->isAllowed(PDFSecurityHandler::Permission::CopyContent))
{
QStringList result;
auto it = m_textSelection.begin();
auto itEnd = m_textSelection.nextPageRange(it);
while (it != m_textSelection.end())
{
const PDFInteger pageIndex = it->start.pageIndex;
PDFTextLayout textLayout = getProxy()->getTextLayoutCompiler()->getTextLayoutLazy(pageIndex);
result << textLayout.getTextFromSelection(it, itEnd, pageIndex);
it = itEnd;
itEnd = m_textSelection.nextPageRange(it);
}
QString text = result.join("\n\n");
if (!text.isEmpty())
{
QApplication::clipboard()->setText(text, QClipboard::Clipboard);
}
}
}
} }
void PDFSelectTextTool::onActionSelectAll() void PDFSelectTextTool::onActionSelectAll()

View File

@ -102,6 +102,7 @@ protected:
virtual void setActiveImpl(bool active); virtual void setActiveImpl(bool active);
virtual void updateActions(); virtual void updateActions();
const PDFDocument* getDocument() const { return m_document; }
PDFDrawWidgetProxy* getProxy() const { return m_proxy; } PDFDrawWidgetProxy* getProxy() const { return m_proxy; }
inline void setCursor(QCursor cursor) { m_cursor = qMove(cursor); } inline void setCursor(QCursor cursor) { m_cursor = qMove(cursor); }