mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Text selection tool - finishing (without copying text)
This commit is contained in:
@ -355,6 +355,58 @@ PDFTextLayoutGetter PDFAsynchronousTextLayoutCompiler::getTextLayoutLazy(PDFInte
|
|||||||
return PDFTextLayoutGetter(nullptr, pageIndex);
|
return PDFTextLayoutGetter(nullptr, pageIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFTextSelection PDFAsynchronousTextLayoutCompiler::getTextSelectionAll(QColor color) const
|
||||||
|
{
|
||||||
|
PDFTextSelection result;
|
||||||
|
|
||||||
|
if (m_textLayouts)
|
||||||
|
{
|
||||||
|
const PDFTextLayoutStorage& textLayouts = *m_textLayouts;
|
||||||
|
|
||||||
|
QMutex mutex;
|
||||||
|
PDFIntegerRange<size_t> pageRange(0, textLayouts.getCount());
|
||||||
|
auto selectPageText = [this, &mutex, &textLayouts, &result, color](PDFInteger pageIndex)
|
||||||
|
{
|
||||||
|
PDFTextLayout textLayout = textLayouts.getTextLayout(pageIndex);
|
||||||
|
PDFTextSelectionItems items;
|
||||||
|
|
||||||
|
const PDFTextBlocks& blocks = textLayout.getTextBlocks();
|
||||||
|
for (size_t blockId = 0, blockCount = blocks.size(); blockId < blockCount; ++blockId)
|
||||||
|
{
|
||||||
|
const PDFTextBlock& block = blocks[blockId];
|
||||||
|
const PDFTextLines& lines = block.getLines();
|
||||||
|
|
||||||
|
if (!lines.empty())
|
||||||
|
{
|
||||||
|
const PDFTextLine& lastLine = lines.back();
|
||||||
|
Q_ASSERT(!lastLine.getCharacters().empty());
|
||||||
|
|
||||||
|
PDFCharacterPointer ptrStart;
|
||||||
|
ptrStart.pageIndex = pageIndex;
|
||||||
|
ptrStart.blockIndex = blockId;
|
||||||
|
ptrStart.lineIndex = 0;
|
||||||
|
ptrStart.characterIndex = 0;
|
||||||
|
|
||||||
|
PDFCharacterPointer ptrEnd;
|
||||||
|
ptrEnd.pageIndex = pageIndex;
|
||||||
|
ptrEnd.blockIndex = blockId;
|
||||||
|
ptrEnd.lineIndex = lines.size() - 1;
|
||||||
|
ptrEnd.characterIndex = lastLine.getCharacters().size() - 1;
|
||||||
|
|
||||||
|
items.emplace_back(ptrStart, ptrEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QMutexLocker lock(&mutex);
|
||||||
|
result.addItems(qMove(items), color);
|
||||||
|
};
|
||||||
|
PDFExecutionPolicy::execute(PDFExecutionPolicy::Scope::Page, pageRange.begin(), pageRange.end(), selectPageText);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.build();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void PDFAsynchronousTextLayoutCompiler::makeTextLayout()
|
void PDFAsynchronousTextLayoutCompiler::makeTextLayout()
|
||||||
{
|
{
|
||||||
if (m_state != State::Active || !m_proxy->getDocument())
|
if (m_state != State::Active || !m_proxy->getDocument())
|
||||||
|
@ -130,6 +130,10 @@ public:
|
|||||||
/// \param pageIndex Page index
|
/// \param pageIndex Page index
|
||||||
PDFTextLayoutGetter getTextLayoutLazy(PDFInteger pageIndex);
|
PDFTextLayoutGetter getTextLayoutLazy(PDFInteger pageIndex);
|
||||||
|
|
||||||
|
/// Select all texts on all pages using \p color color.
|
||||||
|
/// \param color Color to be used for text selection
|
||||||
|
PDFTextSelection getTextSelectionAll(QColor color) const;
|
||||||
|
|
||||||
/// Create text layout for the document. Function is asynchronous,
|
/// Create text layout for the document. Function is asynchronous,
|
||||||
/// it returns immediately. After text layout is created, signal
|
/// it returns immediately. After text layout is created, signal
|
||||||
/// \p textLayoutChanged is emitted.
|
/// \p textLayoutChanged is emitted.
|
||||||
|
@ -362,6 +362,127 @@ bool PDFTextLayout::isHoveringOverTextBlock(const QPointF& point) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFTextSelection PDFTextLayout::createTextSelection(PDFInteger pageIndex, const QPointF& point1, const QPointF& point2)
|
||||||
|
{
|
||||||
|
PDFTextSelection selection;
|
||||||
|
|
||||||
|
// Jakub Melka: We must treat each block in its own coordinate system. Because texts can
|
||||||
|
// have different angles, we will treat each block separately.
|
||||||
|
|
||||||
|
size_t blockId = 0;
|
||||||
|
for (PDFTextBlock& block : m_blocks)
|
||||||
|
{
|
||||||
|
QMatrix angleMatrix;
|
||||||
|
angleMatrix.rotate(block.getAngle());
|
||||||
|
block.applyTransform(angleMatrix);
|
||||||
|
|
||||||
|
QPointF pointA = angleMatrix.map(point1);
|
||||||
|
QPointF pointB = angleMatrix.map(point2);
|
||||||
|
|
||||||
|
const qreal xMin = qMin(pointA.x(), pointB.x());
|
||||||
|
const qreal yMin = qMin(pointA.y(), pointB.y());
|
||||||
|
const qreal xMax = qMax(pointA.x(), pointB.x());
|
||||||
|
const qreal yMax = qMax(pointA.y(), pointB.y());
|
||||||
|
|
||||||
|
QRectF rect(xMin, yMin, xMax - xMin, yMax - yMin);
|
||||||
|
QPainterPath rectPath;
|
||||||
|
rectPath.addRect(rect);
|
||||||
|
QPainterPath intersectionPath = block.getBoundingBox().intersected(rectPath);
|
||||||
|
if (!intersectionPath.isEmpty())
|
||||||
|
{
|
||||||
|
QRectF intersectionRect = intersectionPath.boundingRect();
|
||||||
|
Q_ASSERT(intersectionRect.isValid());
|
||||||
|
|
||||||
|
const PDFTextLines& lines = block.getLines();
|
||||||
|
auto itLineA = std::find_if(lines.cbegin(), lines.cend(), [pointA](const PDFTextLine& line) { return line.getBoundingBox().contains(pointA); });
|
||||||
|
auto itLineB = std::find_if(lines.cbegin(), lines.cend(), [pointB](const PDFTextLine& line) { return line.getBoundingBox().contains(pointB); });
|
||||||
|
if (itLineA == itLineB && itLineA != lines.cend())
|
||||||
|
{
|
||||||
|
// Both points are in the same line. We consider point with lesser
|
||||||
|
// horizontal coordinate as start selection point, and point with greater
|
||||||
|
// horizontal coordinate as end selection point.
|
||||||
|
if (pointA.x() > pointB.x())
|
||||||
|
{
|
||||||
|
std::swap(pointA, pointB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Otherwise points are not in the same line. Then start point will be
|
||||||
|
// point top of the second point. Bottom point will mark end of selection.
|
||||||
|
if (pointA.y() > pointB.y())
|
||||||
|
{
|
||||||
|
std::swap(pointA, pointB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, we have pointA as start point and pointB as end point. We must found
|
||||||
|
// nearest character to the right of point A, and nearest character to the
|
||||||
|
// left of point B (with respect to point A/B).
|
||||||
|
|
||||||
|
qreal maxDistanceA = std::numeric_limits<qreal>::infinity();
|
||||||
|
qreal maxDistanceB = std::numeric_limits<qreal>::infinity();
|
||||||
|
|
||||||
|
PDFCharacterPointer ptrA;
|
||||||
|
PDFCharacterPointer ptrB;
|
||||||
|
|
||||||
|
for (size_t lineId = 0, linesCount = lines.size(); lineId < linesCount; ++lineId)
|
||||||
|
{
|
||||||
|
const PDFTextLine& line = lines[lineId];
|
||||||
|
const TextCharacters& characters = line.getCharacters();
|
||||||
|
for (size_t characterId = 0, characterCount = characters.size(); characterId < characterCount; ++characterId)
|
||||||
|
{
|
||||||
|
const TextCharacter& character = characters[characterId];
|
||||||
|
QPointF characterCenter = character.boundingBox.boundingRect().center();
|
||||||
|
|
||||||
|
qreal distanceA = QLineF(pointA, characterCenter).length();
|
||||||
|
qreal distanceB = QLineF(pointB, characterCenter).length();
|
||||||
|
|
||||||
|
if (distanceA < maxDistanceA && characterCenter.x() > pointA.x())
|
||||||
|
{
|
||||||
|
maxDistanceA = distanceA;
|
||||||
|
ptrA.pageIndex = pageIndex;
|
||||||
|
ptrA.blockIndex = blockId;
|
||||||
|
ptrA.lineIndex = lineId;
|
||||||
|
ptrA.characterIndex = characterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distanceB < maxDistanceB && characterCenter.x() < pointB.x())
|
||||||
|
{
|
||||||
|
maxDistanceB = distanceB;
|
||||||
|
ptrB.pageIndex = pageIndex;
|
||||||
|
ptrB.blockIndex = blockId;
|
||||||
|
ptrB.lineIndex = lineId;
|
||||||
|
ptrB.characterIndex = characterId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have filled the pointers, add them to the selection
|
||||||
|
if (ptrA.isValid() && ptrB.isValid())
|
||||||
|
{
|
||||||
|
if (ptrA < ptrB)
|
||||||
|
{
|
||||||
|
selection.addItems({ PDFTextSelectionItem(ptrA, ptrB) }, Qt::yellow);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
selection.addItems({ PDFTextSelectionItem(ptrB, ptrA) }, Qt::yellow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment block index
|
||||||
|
++blockId;
|
||||||
|
|
||||||
|
// Apply backward transformation to restore original coordinate system
|
||||||
|
block.applyTransform(angleMatrix.inverted());
|
||||||
|
}
|
||||||
|
|
||||||
|
selection.build();
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
|
||||||
QDataStream& operator>>(QDataStream& stream, PDFTextLayout& layout)
|
QDataStream& operator>>(QDataStream& stream, PDFTextLayout& layout)
|
||||||
{
|
{
|
||||||
stream >> layout.m_characters;
|
stream >> layout.m_characters;
|
||||||
|
@ -180,7 +180,7 @@ struct PDFCharacterPointer
|
|||||||
/// Returns true, if character belongs to same line
|
/// Returns true, if character belongs to same line
|
||||||
bool hasSameLine(const PDFCharacterPointer& other) const;
|
bool hasSameLine(const PDFCharacterPointer& other) const;
|
||||||
|
|
||||||
int pageIndex = -1;
|
PDFInteger pageIndex = -1;
|
||||||
size_t blockIndex = 0;
|
size_t blockIndex = 0;
|
||||||
size_t lineIndex = 0;
|
size_t lineIndex = 0;
|
||||||
size_t characterIndex = 0;
|
size_t characterIndex = 0;
|
||||||
@ -324,7 +324,7 @@ public:
|
|||||||
/// Adds character to the layout
|
/// Adds character to the layout
|
||||||
void addCharacter(const PDFTextCharacterInfo& info);
|
void addCharacter(const PDFTextCharacterInfo& info);
|
||||||
|
|
||||||
/// Perorms text layout algorithm
|
/// Performs text layout algorithm
|
||||||
void perform();
|
void perform();
|
||||||
|
|
||||||
/// Optimizes layout memory allocation to contain less space
|
/// Optimizes layout memory allocation to contain less space
|
||||||
@ -339,6 +339,14 @@ public:
|
|||||||
/// Returns true, if given point is pointing to some text block
|
/// Returns true, if given point is pointing to some text block
|
||||||
bool isHoveringOverTextBlock(const QPointF& point) const;
|
bool isHoveringOverTextBlock(const QPointF& point) const;
|
||||||
|
|
||||||
|
/// Creates text selection. This function needs to modify the layout contents,
|
||||||
|
/// so do not use this function from multiple threads (it is not thread-safe).
|
||||||
|
/// Text selection is created from rectangle using two points.
|
||||||
|
/// \param pageIndex Page index
|
||||||
|
/// \param point1 First point
|
||||||
|
/// \param point2 Second point
|
||||||
|
PDFTextSelection createTextSelection(PDFInteger pageIndex, const QPointF& point1, const QPointF& point2);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@ -354,7 +362,7 @@ private:
|
|||||||
/// Applies transform to text characters (positions and bounding boxes)
|
/// Applies transform to text characters (positions and bounding boxes)
|
||||||
/// \param characters Characters
|
/// \param characters Characters
|
||||||
/// \param matrix Transform matrix
|
/// \param matrix Transform matrix
|
||||||
void applyTransform(TextCharacters& characters, const QMatrix& matrix);
|
static void applyTransform(TextCharacters& characters, const QMatrix& matrix);
|
||||||
|
|
||||||
TextCharacters m_characters;
|
TextCharacters m_characters;
|
||||||
std::set<PDFReal> m_angles;
|
std::set<PDFReal> m_angles;
|
||||||
@ -458,6 +466,9 @@ public:
|
|||||||
/// \param flowFlags Text flow flags
|
/// \param flowFlags Text flow flags
|
||||||
PDFFindResults find(const QRegularExpression& expression, PDFTextFlow::FlowFlags flowFlags) const;
|
PDFFindResults find(const QRegularExpression& expression, PDFTextFlow::FlowFlags flowFlags) const;
|
||||||
|
|
||||||
|
/// Returns number of pages
|
||||||
|
size_t getCount() const { return m_offsets.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<int> m_offsets;
|
std::vector<int> m_offsets;
|
||||||
QByteArray m_textLayouts;
|
QByteArray m_textLayouts;
|
||||||
|
@ -446,15 +446,32 @@ PDFTextSelection PDFFindTextTool::getTextSelectionImpl() const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFSelectTextTool::PDFSelectTextTool(PDFDrawWidgetProxy* proxy, QAction* action, QAction* selectAllAction, QAction* deselectAction, QObject* parent) :
|
PDFSelectTextTool::PDFSelectTextTool(PDFDrawWidgetProxy* proxy, QAction* action, QAction* copyTextAction, QAction* selectAllAction, QAction* deselectAction, QObject* parent) :
|
||||||
BaseClass(proxy, action, parent),
|
BaseClass(proxy, action, parent),
|
||||||
|
m_copyTextAction(copyTextAction),
|
||||||
m_selectAllAction(selectAllAction),
|
m_selectAllAction(selectAllAction),
|
||||||
m_deselectAction(deselectAction),
|
m_deselectAction(deselectAction),
|
||||||
m_isCursorOverText(false)
|
m_isCursorOverText(false)
|
||||||
{
|
{
|
||||||
|
connect(copyTextAction, &QAction::triggered, this, &PDFSelectTextTool::onActionCopyText);
|
||||||
|
connect(selectAllAction, &QAction::triggered, this, &PDFSelectTextTool::onActionSelectAll);
|
||||||
|
connect(deselectAction, &QAction::triggered, this, &PDFSelectTextTool::onActionDeselect);
|
||||||
|
|
||||||
updateActions();
|
updateActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFSelectTextTool::drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(compiledPage);
|
||||||
|
|
||||||
|
pdf::PDFTextSelectionPainter textSelectionPainter(&m_textSelection);
|
||||||
|
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
void PDFSelectTextTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
void PDFSelectTextTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
Q_UNUSED(widget);
|
||||||
@ -493,6 +510,8 @@ void PDFSelectTextTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
|||||||
if (m_selectionInfo.pageIndex == pageIndex)
|
if (m_selectionInfo.pageIndex == pageIndex)
|
||||||
{
|
{
|
||||||
// Jakub Melka: handle the selection
|
// Jakub Melka: handle the selection
|
||||||
|
PDFTextLayout textLayout = getProxy()->getTextLayoutCompiler()->getTextLayoutLazy(pageIndex);
|
||||||
|
setSelection(textLayout.createTextSelection(pageIndex, m_selectionInfo.selectionStartPoint, pagePoint));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -510,26 +529,29 @@ void PDFSelectTextTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
|||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
Q_UNUSED(widget);
|
||||||
|
|
||||||
|
// We must make text layout. This is fast, because text layout is being
|
||||||
|
// created only, if it doesn't exist. This function is also called only,
|
||||||
|
// if tool is active.
|
||||||
|
getProxy()->getTextLayoutCompiler()->makeTextLayout();
|
||||||
|
|
||||||
QPointF pagePoint;
|
QPointF pagePoint;
|
||||||
const PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
const PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||||
PDFTextLayout textLayout = getProxy()->getTextLayoutCompiler()->getTextLayoutLazy(pageIndex);
|
PDFTextLayout textLayout = getProxy()->getTextLayoutCompiler()->getTextLayoutLazy(pageIndex);
|
||||||
m_isCursorOverText = textLayout.isHoveringOverTextBlock(pagePoint);
|
m_isCursorOverText = textLayout.isHoveringOverTextBlock(pagePoint);
|
||||||
|
|
||||||
if (event->button() == Qt::LeftButton)
|
if (m_selectionInfo.pageIndex != -1)
|
||||||
{
|
{
|
||||||
if (m_selectionInfo.pageIndex != -1)
|
if (m_selectionInfo.pageIndex == pageIndex)
|
||||||
{
|
{
|
||||||
if (m_selectionInfo.pageIndex == pageIndex)
|
// Jakub Melka: handle the selection
|
||||||
{
|
setSelection(textLayout.createTextSelection(pageIndex, m_selectionInfo.selectionStartPoint, pagePoint));
|
||||||
// Jakub Melka: handle the selection
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setSelection(pdf::PDFTextSelection());
|
|
||||||
}
|
|
||||||
|
|
||||||
event->accept();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setSelection(pdf::PDFTextSelection());
|
||||||
|
}
|
||||||
|
|
||||||
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCursor();
|
updateCursor();
|
||||||
@ -556,8 +578,11 @@ void PDFSelectTextTool::updateActions()
|
|||||||
{
|
{
|
||||||
BaseClass::updateActions();
|
BaseClass::updateActions();
|
||||||
|
|
||||||
m_selectAllAction->setEnabled(isActive());
|
const bool isActive = this->isActive();
|
||||||
m_deselectAction->setEnabled(isActive() && !m_textSelection.isEmpty());
|
const bool hasSelection = !m_textSelection.isEmpty();
|
||||||
|
m_selectAllAction->setEnabled(isActive);
|
||||||
|
m_deselectAction->setEnabled(isActive && hasSelection);
|
||||||
|
m_copyTextAction->setEnabled(isActive && hasSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFSelectTextTool::updateCursor()
|
void PDFSelectTextTool::updateCursor()
|
||||||
@ -575,6 +600,27 @@ void PDFSelectTextTool::updateCursor()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFSelectTextTool::onActionCopyText()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSelectTextTool::onActionSelectAll()
|
||||||
|
{
|
||||||
|
if (isActive())
|
||||||
|
{
|
||||||
|
setSelection(getProxy()->getTextLayoutCompiler()->getTextSelectionAll(Qt::yellow));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSelectTextTool::onActionDeselect()
|
||||||
|
{
|
||||||
|
if (isActive())
|
||||||
|
{
|
||||||
|
setSelection(pdf::PDFTextSelection());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PDFSelectTextTool::setSelection(PDFTextSelection&& textSelection)
|
void PDFSelectTextTool::setSelection(PDFTextSelection&& textSelection)
|
||||||
{
|
{
|
||||||
if (m_textSelection != textSelection)
|
if (m_textSelection != textSelection)
|
||||||
@ -590,7 +636,7 @@ PDFToolManager::PDFToolManager(PDFDrawWidgetProxy* proxy, Actions actions, QObje
|
|||||||
m_predefinedTools()
|
m_predefinedTools()
|
||||||
{
|
{
|
||||||
m_predefinedTools[FindTextTool] = new PDFFindTextTool(proxy, actions.findPrevAction, actions.findNextAction, this, parentDialog);
|
m_predefinedTools[FindTextTool] = new PDFFindTextTool(proxy, actions.findPrevAction, actions.findNextAction, this, parentDialog);
|
||||||
m_predefinedTools[SelectTextTool] = new PDFSelectTextTool(proxy, actions.selectTextToolAction, actions.selectAllAction, actions.deselectAction, this);
|
m_predefinedTools[SelectTextTool] = new PDFSelectTextTool(proxy, actions.selectTextToolAction, actions.copyTextAction, actions.selectAllAction, actions.deselectAction, this);
|
||||||
|
|
||||||
for (PDFWidgetTool* tool : m_predefinedTools)
|
for (PDFWidgetTool* tool : m_predefinedTools)
|
||||||
{
|
{
|
||||||
|
@ -193,8 +193,18 @@ private:
|
|||||||
public:
|
public:
|
||||||
/// Construct new text selection tool
|
/// Construct new text selection tool
|
||||||
/// \param proxy Draw widget proxy
|
/// \param proxy Draw widget proxy
|
||||||
|
/// \param action Tool activation action
|
||||||
|
/// \param copyTextAction Copy text action
|
||||||
|
/// \param selectAllAction Select all text action
|
||||||
|
/// \param deselectAction Deselect text action
|
||||||
/// \param parent Parent object
|
/// \param parent Parent object
|
||||||
explicit PDFSelectTextTool(PDFDrawWidgetProxy* proxy, QAction* action, QAction* selectAllAction,QAction* deselectAction, QObject* parent);
|
explicit PDFSelectTextTool(PDFDrawWidgetProxy* proxy, QAction* action, QAction* copyTextAction, QAction* selectAllAction, QAction* deselectAction, QObject* parent);
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix) const override;
|
||||||
|
|
||||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
@ -206,6 +216,9 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void updateCursor();
|
void updateCursor();
|
||||||
|
void onActionCopyText();
|
||||||
|
void onActionSelectAll();
|
||||||
|
void onActionDeselect();
|
||||||
void setSelection(pdf::PDFTextSelection&& textSelection);
|
void setSelection(pdf::PDFTextSelection&& textSelection);
|
||||||
|
|
||||||
struct SelectionInfo
|
struct SelectionInfo
|
||||||
@ -214,6 +227,7 @@ private:
|
|||||||
QPointF selectionStartPoint;
|
QPointF selectionStartPoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QAction* m_copyTextAction;
|
||||||
QAction* m_selectAllAction;
|
QAction* m_selectAllAction;
|
||||||
QAction* m_deselectAction;
|
QAction* m_deselectAction;
|
||||||
pdf::PDFTextSelection m_textSelection;
|
pdf::PDFTextSelection m_textSelection;
|
||||||
@ -239,6 +253,7 @@ public:
|
|||||||
QAction* selectTextToolAction = nullptr;
|
QAction* selectTextToolAction = nullptr;
|
||||||
QAction* selectAllAction = nullptr;
|
QAction* selectAllAction = nullptr;
|
||||||
QAction* deselectAction = nullptr;
|
QAction* deselectAction = nullptr;
|
||||||
|
QAction* copyTextAction = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Construct new text search tool
|
/// Construct new text search tool
|
||||||
|
@ -82,6 +82,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
|
|||||||
m_progressTaskbarIndicator(nullptr),
|
m_progressTaskbarIndicator(nullptr),
|
||||||
m_progressDialog(nullptr),
|
m_progressDialog(nullptr),
|
||||||
m_isBusy(false),
|
m_isBusy(false),
|
||||||
|
m_isChangingProgressStep(false),
|
||||||
m_toolManager(nullptr)
|
m_toolManager(nullptr)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
@ -104,6 +105,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
|
|||||||
ui->actionFindNext->setShortcut(QKeySequence::FindNext);
|
ui->actionFindNext->setShortcut(QKeySequence::FindNext);
|
||||||
ui->actionSelectTextAll->setShortcut(QKeySequence::SelectAll);
|
ui->actionSelectTextAll->setShortcut(QKeySequence::SelectAll);
|
||||||
ui->actionDeselectText->setShortcut(QKeySequence::Deselect);
|
ui->actionDeselectText->setShortcut(QKeySequence::Deselect);
|
||||||
|
ui->actionCopyText->setShortcut(QKeySequence::Copy);
|
||||||
|
|
||||||
connect(ui->actionOpen, &QAction::triggered, this, &PDFViewerMainWindow::onActionOpenTriggered);
|
connect(ui->actionOpen, &QAction::triggered, this, &PDFViewerMainWindow::onActionOpenTriggered);
|
||||||
connect(ui->actionClose, &QAction::triggered, this, &PDFViewerMainWindow::onActionCloseTriggered);
|
connect(ui->actionClose, &QAction::triggered, this, &PDFViewerMainWindow::onActionCloseTriggered);
|
||||||
@ -229,6 +231,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
|
|||||||
actions.selectTextToolAction = ui->actionSelectText;
|
actions.selectTextToolAction = ui->actionSelectText;
|
||||||
actions.selectAllAction = ui->actionSelectTextAll;
|
actions.selectAllAction = ui->actionSelectTextAll;
|
||||||
actions.deselectAction = ui->actionDeselectText;
|
actions.deselectAction = ui->actionDeselectText;
|
||||||
|
actions.copyTextAction = ui->actionCopyText;
|
||||||
m_toolManager = new pdf::PDFToolManager(m_pdfWidget->getDrawWidgetProxy(), actions, this, this);
|
m_toolManager = new pdf::PDFToolManager(m_pdfWidget->getDrawWidgetProxy(), actions, this, this);
|
||||||
m_pdfWidget->setToolManager(m_toolManager);
|
m_pdfWidget->setToolManager(m_toolManager);
|
||||||
|
|
||||||
@ -575,6 +578,13 @@ void PDFViewerMainWindow::onProgressStarted(pdf::ProgressStartupInfo info)
|
|||||||
|
|
||||||
void PDFViewerMainWindow::onProgressStep(int percentage)
|
void PDFViewerMainWindow::onProgressStep(int percentage)
|
||||||
{
|
{
|
||||||
|
if (m_isChangingProgressStep)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdf::PDFTemporaryValueChange guard(&m_isChangingProgressStep, true);
|
||||||
|
|
||||||
if (m_progressDialog)
|
if (m_progressDialog)
|
||||||
{
|
{
|
||||||
m_progressDialog->setValue(percentage);
|
m_progressDialog->setValue(percentage);
|
||||||
|
@ -164,6 +164,7 @@ private:
|
|||||||
|
|
||||||
QProgressDialog* m_progressDialog;
|
QProgressDialog* m_progressDialog;
|
||||||
bool m_isBusy;
|
bool m_isBusy;
|
||||||
|
bool m_isChangingProgressStep;
|
||||||
|
|
||||||
pdf::PDFToolManager* m_toolManager;
|
pdf::PDFToolManager* m_toolManager;
|
||||||
};
|
};
|
||||||
|
@ -105,6 +105,7 @@
|
|||||||
<addaction name="actionFindNext"/>
|
<addaction name="actionFindNext"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionSelectText"/>
|
<addaction name="actionSelectText"/>
|
||||||
|
<addaction name="actionCopyText"/>
|
||||||
<addaction name="actionSelectTextAll"/>
|
<addaction name="actionSelectTextAll"/>
|
||||||
<addaction name="actionDeselectText"/>
|
<addaction name="actionDeselectText"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
@ -403,6 +404,11 @@
|
|||||||
<string>Deselect</string>
|
<string>Deselect</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionCopyText">
|
||||||
|
<property name="text">
|
||||||
|
<string>Copy text</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources>
|
<resources>
|
||||||
|
Reference in New Issue
Block a user