mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Signature plugin: Element manipulation
This commit is contained in:
@ -17,11 +17,14 @@
|
|||||||
|
|
||||||
#include "pdfpagecontentelements.h"
|
#include "pdfpagecontentelements.h"
|
||||||
#include "pdfpainterutils.h"
|
#include "pdfpainterutils.h"
|
||||||
|
#include "pdfdrawwidget.h"
|
||||||
|
#include "pdfdrawspacecontroller.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QSvgRenderer>
|
#include <QSvgRenderer>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
@ -36,6 +39,16 @@ void PDFPageContentElement::setPageIndex(PDFInteger newPageIndex)
|
|||||||
m_pageIndex = newPageIndex;
|
m_pageIndex = newPageIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFInteger PDFPageContentElement::getElementId() const
|
||||||
|
{
|
||||||
|
return m_elementId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElement::setElementId(PDFInteger newElementId)
|
||||||
|
{
|
||||||
|
m_elementId = newElementId;
|
||||||
|
}
|
||||||
|
|
||||||
const QPen& PDFPageContentStyledElement::getPen() const
|
const QPen& PDFPageContentStyledElement::getPen() const
|
||||||
{
|
{
|
||||||
return m_pen;
|
return m_pen;
|
||||||
@ -59,6 +72,7 @@ void PDFPageContentStyledElement::setBrush(const QBrush& newBrush)
|
|||||||
PDFPageContentElementRectangle* PDFPageContentElementRectangle::clone() const
|
PDFPageContentElementRectangle* PDFPageContentElementRectangle::clone() const
|
||||||
{
|
{
|
||||||
PDFPageContentElementRectangle* copy = new PDFPageContentElementRectangle();
|
PDFPageContentElementRectangle* copy = new PDFPageContentElementRectangle();
|
||||||
|
copy->setElementId(getElementId());
|
||||||
copy->setPageIndex(getPageIndex());
|
copy->setPageIndex(getPageIndex());
|
||||||
copy->setPen(getPen());
|
copy->setPen(getPen());
|
||||||
copy->setBrush(getBrush());
|
copy->setBrush(getBrush());
|
||||||
@ -123,7 +137,9 @@ void PDFPageContentElementRectangle::drawPage(QPainter* painter,
|
|||||||
|
|
||||||
PDFPageContentScene::PDFPageContentScene(QObject* parent) :
|
PDFPageContentScene::PDFPageContentScene(QObject* parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_isActive(false)
|
m_firstFreeId(1),
|
||||||
|
m_isActive(false),
|
||||||
|
m_manipulator(this, nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -135,10 +151,22 @@ PDFPageContentScene::~PDFPageContentScene()
|
|||||||
|
|
||||||
void PDFPageContentScene::addElement(PDFPageContentElement* element)
|
void PDFPageContentScene::addElement(PDFPageContentElement* element)
|
||||||
{
|
{
|
||||||
|
element->setElementId(m_firstFreeId++);
|
||||||
m_elements.emplace_back(element);
|
m_elements.emplace_back(element);
|
||||||
emit sceneChanged();
|
emit sceneChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFPageContentElement* PDFPageContentScene::getElementById(PDFInteger id) const
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_elements.cbegin(), m_elements.cend(), [id](const auto& element) { return element->getElementId() == id; });
|
||||||
|
if (it != m_elements.cend())
|
||||||
|
{
|
||||||
|
return it->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void PDFPageContentScene::clear()
|
void PDFPageContentScene::clear()
|
||||||
{
|
{
|
||||||
if (!m_elements.empty())
|
if (!m_elements.empty())
|
||||||
@ -168,32 +196,127 @@ void PDFPageContentScene::keyReleaseEvent(QWidget* widget, QKeyEvent* event)
|
|||||||
|
|
||||||
void PDFPageContentScene::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
void PDFPageContentScene::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
if (!isActive())
|
||||||
event->ignore();
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseEventInfo info = getMouseEventInfo(widget, event->pos());
|
||||||
|
if (info.isValid() || isMouseGrabbed())
|
||||||
|
{
|
||||||
|
// We to handle selecting/deselecting the active
|
||||||
|
// item. After that, accept the item.
|
||||||
|
if (info.isValid() && event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
info.widgetMouseStartPos = event->pos();
|
||||||
|
info.timer.start();
|
||||||
|
|
||||||
|
if (!m_manipulator.isManipulationInProgress())
|
||||||
|
{
|
||||||
|
Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers();
|
||||||
|
const bool isCtrl = keyboardModifiers.testFlag(Qt::CTRL);
|
||||||
|
const bool isShift = keyboardModifiers.testFlag(Qt::SHIFT);
|
||||||
|
|
||||||
|
if (isCtrl && !isShift)
|
||||||
|
{
|
||||||
|
m_manipulator.select(info.hoveredElementIds);
|
||||||
|
}
|
||||||
|
else if (!isCtrl && isShift)
|
||||||
|
{
|
||||||
|
m_manipulator.deselect(info.hoveredElementIds);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_manipulator.selectNew(info.hoveredElementIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
grabMouse(info, event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPageContentScene::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
void PDFPageContentScene::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
Q_UNUSED(widget);
|
||||||
event->ignore();
|
|
||||||
|
if (!isActive())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If mouse is grabbed, then event is accepted always (because
|
||||||
|
// we get Press event, when we grabbed the mouse, then we will
|
||||||
|
// wait for corresponding release event while all mouse move events
|
||||||
|
// will be accepted, even if editor doesn't accept them.
|
||||||
|
if (isMouseGrabbed())
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPageContentScene::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
void PDFPageContentScene::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
Q_UNUSED(widget);
|
||||||
event->ignore();
|
|
||||||
|
if (!isActive())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMouseGrabbed())
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
m_manipulator.finishManipulation();
|
||||||
|
}
|
||||||
|
|
||||||
|
ungrabMouse(info, event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPageContentScene::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
void PDFPageContentScene::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
if (!isActive())
|
||||||
event->ignore();
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseEventInfo info = getMouseEventInfo(widget, event->pos());
|
||||||
|
if (info.isValid())
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// If mouse is grabbed, then event is accepted always (because
|
||||||
|
// we get Press event, when we grabbed the mouse, then we will
|
||||||
|
// wait for corresponding release event while all mouse move events
|
||||||
|
// will be accepted, even if editor doesn't accept them.
|
||||||
|
if (isMouseGrabbed())
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPageContentScene::wheelEvent(QWidget* widget, QWheelEvent* event)
|
void PDFPageContentScene::wheelEvent(QWidget* widget, QWheelEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
Q_UNUSED(widget);
|
||||||
event->ignore();
|
|
||||||
|
if (!isActive())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will accept mouse wheel events, if we are grabbing the mouse.
|
||||||
|
// We do not want to zoom in/zoom out while grabbing.
|
||||||
|
if (isMouseGrabbed())
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PDFPageContentScene::getTooltip() const
|
QString PDFPageContentScene::getTooltip() const
|
||||||
@ -234,6 +357,80 @@ void PDFPageContentScene::drawPage(QPainter* painter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFPageContentScene::MouseEventInfo PDFPageContentScene::getMouseEventInfo(QWidget* widget, QPoint point)
|
||||||
|
{
|
||||||
|
MouseEventInfo result;
|
||||||
|
|
||||||
|
Q_ASSERT(isActive());
|
||||||
|
|
||||||
|
if (isMouseGrabbed())
|
||||||
|
{
|
||||||
|
result = m_mouseGrabInfo.info;
|
||||||
|
result.widgetMouseCurrentPos = point;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFWidgetSnapshot snapshot = m_proxy->getSnapshot();
|
||||||
|
for (const PDFWidgetSnapshot::SnapshotItem& snapshotItem : snapshot.items)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentScene::grabMouse(const MouseEventInfo& info, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
Q_ASSERT(isActive());
|
||||||
|
|
||||||
|
if (event->type() == QEvent::MouseButtonDblClick)
|
||||||
|
{
|
||||||
|
// Double clicks doesn't grab the mouse
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(event->type() == QEvent::MouseButtonPress);
|
||||||
|
|
||||||
|
if (isMouseGrabbed())
|
||||||
|
{
|
||||||
|
// If mouse is already grabbed, then when new mouse button is pressed,
|
||||||
|
// we just increase nesting level and accept the mouse event. We are
|
||||||
|
// accepting all mouse events, if mouse is grabbed.
|
||||||
|
++m_mouseGrabInfo.mouseGrabNesting;
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
else if (event->isAccepted())
|
||||||
|
{
|
||||||
|
// Event is accepted and we are not grabbing the mouse. We must start
|
||||||
|
// grabbing the mouse.
|
||||||
|
Q_ASSERT(m_mouseGrabInfo.mouseGrabNesting == 0);
|
||||||
|
++m_mouseGrabInfo.mouseGrabNesting;
|
||||||
|
m_mouseGrabInfo.info = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentScene::ungrabMouse(const MouseEventInfo& info, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(info);
|
||||||
|
Q_ASSERT(isActive());
|
||||||
|
Q_ASSERT(event->type() == QEvent::MouseButtonRelease);
|
||||||
|
|
||||||
|
if (isMouseGrabbed())
|
||||||
|
{
|
||||||
|
// Mouse is being grabbed, decrease nesting level. We must also accept
|
||||||
|
// mouse release event, because mouse is being grabbed.
|
||||||
|
--m_mouseGrabInfo.mouseGrabNesting;
|
||||||
|
event->accept();
|
||||||
|
|
||||||
|
if (!isMouseGrabbed())
|
||||||
|
{
|
||||||
|
m_mouseGrabInfo.info = MouseEventInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(m_mouseGrabInfo.mouseGrabNesting >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
bool PDFPageContentScene::isActive() const
|
bool PDFPageContentScene::isActive() const
|
||||||
{
|
{
|
||||||
return m_isActive;
|
return m_isActive;
|
||||||
@ -244,6 +441,25 @@ void PDFPageContentScene::setActive(bool newIsActive)
|
|||||||
if (m_isActive != newIsActive)
|
if (m_isActive != newIsActive)
|
||||||
{
|
{
|
||||||
m_isActive = newIsActive;
|
m_isActive = newIsActive;
|
||||||
|
|
||||||
|
if (!newIsActive)
|
||||||
|
{
|
||||||
|
m_mouseGrabInfo = MouseGrabInfo();
|
||||||
|
m_manipulator.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit sceneChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentScene::removeElementsById(const std::set<PDFInteger>& selection)
|
||||||
|
{
|
||||||
|
const size_t oldSize = m_elements.size();
|
||||||
|
m_elements.erase(std::remove_if(m_elements.begin(), m_elements.end(), [&selection](const auto& element){ return selection.count(element->getElementId()); }), m_elements.end());
|
||||||
|
const size_t newSize = m_elements.size();
|
||||||
|
|
||||||
|
if (newSize < oldSize)
|
||||||
|
{
|
||||||
emit sceneChanged();
|
emit sceneChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,6 +467,7 @@ void PDFPageContentScene::setActive(bool newIsActive)
|
|||||||
PDFPageContentElementLine* PDFPageContentElementLine::clone() const
|
PDFPageContentElementLine* PDFPageContentElementLine::clone() const
|
||||||
{
|
{
|
||||||
PDFPageContentElementLine* copy = new PDFPageContentElementLine();
|
PDFPageContentElementLine* copy = new PDFPageContentElementLine();
|
||||||
|
copy->setElementId(getElementId());
|
||||||
copy->setPageIndex(getPageIndex());
|
copy->setPageIndex(getPageIndex());
|
||||||
copy->setPen(getPen());
|
copy->setPen(getPen());
|
||||||
copy->setBrush(getBrush());
|
copy->setBrush(getBrush());
|
||||||
@ -328,6 +545,7 @@ PDFPageContentSvgElement::~PDFPageContentSvgElement()
|
|||||||
PDFPageContentSvgElement* PDFPageContentSvgElement::clone() const
|
PDFPageContentSvgElement* PDFPageContentSvgElement::clone() const
|
||||||
{
|
{
|
||||||
PDFPageContentSvgElement* copy = new PDFPageContentSvgElement();
|
PDFPageContentSvgElement* copy = new PDFPageContentSvgElement();
|
||||||
|
copy->setElementId(getElementId());
|
||||||
copy->setPageIndex(getPageIndex());
|
copy->setPageIndex(getPageIndex());
|
||||||
copy->setRectangle(getRectangle());
|
copy->setRectangle(getRectangle());
|
||||||
copy->setContent(getContent());
|
copy->setContent(getContent());
|
||||||
@ -400,6 +618,7 @@ void PDFPageContentSvgElement::setRectangle(const QRectF& newRectangle)
|
|||||||
PDFPageContentElementDot* PDFPageContentElementDot::clone() const
|
PDFPageContentElementDot* PDFPageContentElementDot::clone() const
|
||||||
{
|
{
|
||||||
PDFPageContentElementDot* copy = new PDFPageContentElementDot();
|
PDFPageContentElementDot* copy = new PDFPageContentElementDot();
|
||||||
|
copy->setElementId(getElementId());
|
||||||
copy->setPageIndex(getPageIndex());
|
copy->setPageIndex(getPageIndex());
|
||||||
copy->setPen(getPen());
|
copy->setPen(getPen());
|
||||||
copy->setBrush(getBrush());
|
copy->setBrush(getBrush());
|
||||||
@ -444,6 +663,7 @@ void PDFPageContentElementDot::setPoint(QPointF newPoint)
|
|||||||
PDFPageContentElementFreehandCurve* PDFPageContentElementFreehandCurve::clone() const
|
PDFPageContentElementFreehandCurve* PDFPageContentElementFreehandCurve::clone() const
|
||||||
{
|
{
|
||||||
PDFPageContentElementFreehandCurve* copy = new PDFPageContentElementFreehandCurve();
|
PDFPageContentElementFreehandCurve* copy = new PDFPageContentElementFreehandCurve();
|
||||||
|
copy->setElementId(getElementId());
|
||||||
copy->setPageIndex(getPageIndex());
|
copy->setPageIndex(getPageIndex());
|
||||||
copy->setPen(getPen());
|
copy->setPen(getPen());
|
||||||
copy->setBrush(getBrush());
|
copy->setBrush(getBrush());
|
||||||
@ -502,4 +722,186 @@ void PDFPageContentElementFreehandCurve::clear()
|
|||||||
m_curve = QPainterPath();
|
m_curve = QPainterPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFPageContentElementManipulator::PDFPageContentElementManipulator(PDFPageContentScene* scene, QObject* parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_scene(scene),
|
||||||
|
m_isManipulationInProgress(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::reset()
|
||||||
|
{
|
||||||
|
stopManipulation();
|
||||||
|
deselectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::update(PDFInteger id, SelectionModes modes)
|
||||||
|
{
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
if (modes.testFlag(Clear))
|
||||||
|
{
|
||||||
|
modified = !m_selection.empty();
|
||||||
|
m_selection.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is id valid?
|
||||||
|
if (id > 0)
|
||||||
|
{
|
||||||
|
if (modes.testFlag(Select))
|
||||||
|
{
|
||||||
|
if (!isSelected(id))
|
||||||
|
{
|
||||||
|
modified = true;
|
||||||
|
m_selection.insert(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modes.testFlag(Deselect))
|
||||||
|
{
|
||||||
|
if (isSelected(id))
|
||||||
|
{
|
||||||
|
modified = true;
|
||||||
|
m_selection.erase(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modes.testFlag(Toggle))
|
||||||
|
{
|
||||||
|
if (isSelected(id))
|
||||||
|
{
|
||||||
|
m_selection.erase(id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_selection.insert(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When toggle is performed, selection is always changed
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modified)
|
||||||
|
{
|
||||||
|
emit selectionChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::update(const std::set<PDFInteger>& ids, SelectionModes modes)
|
||||||
|
{
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
if (modes.testFlag(Clear))
|
||||||
|
{
|
||||||
|
modified = !m_selection.empty();
|
||||||
|
m_selection.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is id valid?
|
||||||
|
if (!ids.empty())
|
||||||
|
{
|
||||||
|
if (modes.testFlag(Select))
|
||||||
|
{
|
||||||
|
for (auto id : ids)
|
||||||
|
{
|
||||||
|
if (!isSelected(id))
|
||||||
|
{
|
||||||
|
modified = true;
|
||||||
|
m_selection.insert(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modes.testFlag(Deselect))
|
||||||
|
{
|
||||||
|
for (auto id : ids)
|
||||||
|
{
|
||||||
|
if (isSelected(id))
|
||||||
|
{
|
||||||
|
modified = true;
|
||||||
|
m_selection.erase(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modes.testFlag(Toggle))
|
||||||
|
{
|
||||||
|
for (auto id : ids)
|
||||||
|
{
|
||||||
|
if (isSelected(id))
|
||||||
|
{
|
||||||
|
m_selection.erase(id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_selection.insert(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When toggle is performed, selection is always changed
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modified)
|
||||||
|
{
|
||||||
|
emit selectionChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::select(PDFInteger id)
|
||||||
|
{
|
||||||
|
update(id, Select);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::select(const std::set<PDFInteger>& ids)
|
||||||
|
{
|
||||||
|
update(ids, Select);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::selectNew(PDFInteger id)
|
||||||
|
{
|
||||||
|
update(id, Select | Clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::selectNew(const std::set<PDFInteger>& ids)
|
||||||
|
{
|
||||||
|
update(ids, Select | Clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::deselect(PDFInteger id)
|
||||||
|
{
|
||||||
|
update(id, Deselect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::deselect(const std::set<PDFInteger>& ids)
|
||||||
|
{
|
||||||
|
update(ids, Deselect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::deselectAll()
|
||||||
|
{
|
||||||
|
update(-1, Clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::manipulateDeleteSelection()
|
||||||
|
{
|
||||||
|
stopManipulation();
|
||||||
|
m_scene->removeElementsById(m_selection);
|
||||||
|
deselectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentElementManipulator::stopManipulation()
|
||||||
|
{
|
||||||
|
if (m_isManipulationInProgress)
|
||||||
|
{
|
||||||
|
m_isManipulationInProgress = false;
|
||||||
|
m_manipulatedElements.clear();
|
||||||
|
m_manipulationModes.clear();
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -25,10 +25,13 @@
|
|||||||
#include <QCursor>
|
#include <QCursor>
|
||||||
#include <QPainterPath>
|
#include <QPainterPath>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
class QSvgRenderer;
|
class QSvgRenderer;
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
class PDFPageContentScene;
|
||||||
|
|
||||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentElement
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentElement
|
||||||
{
|
{
|
||||||
@ -48,7 +51,11 @@ public:
|
|||||||
PDFInteger getPageIndex() const;
|
PDFInteger getPageIndex() const;
|
||||||
void setPageIndex(PDFInteger newPageIndex);
|
void setPageIndex(PDFInteger newPageIndex);
|
||||||
|
|
||||||
|
PDFInteger getElementId() const;
|
||||||
|
void setElementId(PDFInteger newElementId);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
PDFInteger m_elementId = -1;
|
||||||
PDFInteger m_pageIndex = -1;
|
PDFInteger m_pageIndex = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -201,6 +208,61 @@ private:
|
|||||||
std::unique_ptr<QSvgRenderer> m_renderer;
|
std::unique_ptr<QSvgRenderer> m_renderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentElementManipulator : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
PDFPageContentElementManipulator(PDFPageContentScene* scene, QObject* parent);
|
||||||
|
|
||||||
|
enum SelectionMode
|
||||||
|
{
|
||||||
|
NoUpdate = 0x0000,
|
||||||
|
Clear = 0x0001, ///< Clears current selection
|
||||||
|
Select = 0x0002, ///< Selects item
|
||||||
|
Deselect = 0x0004, ///< Deselects item
|
||||||
|
Toggle = 0x0008, ///< Toggles selection of the item
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(SelectionModes, SelectionMode)
|
||||||
|
|
||||||
|
/// Returns true, if element with given id is selected
|
||||||
|
/// \param id Element id
|
||||||
|
bool isSelected(PDFInteger id) const { return m_selection.count(id); }
|
||||||
|
|
||||||
|
/// Returns true, if selection is empty
|
||||||
|
bool isSelectionEmpty() const { return m_selection.empty(); }
|
||||||
|
|
||||||
|
/// Clear all selection, stop manipulation
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void update(PDFInteger id, SelectionModes modes);
|
||||||
|
void update(const std::set<PDFInteger>& ids, SelectionModes modes);
|
||||||
|
void select(PDFInteger id);
|
||||||
|
void select(const std::set<PDFInteger>& ids);
|
||||||
|
void selectNew(PDFInteger id);
|
||||||
|
void selectNew(const std::set<PDFInteger>& ids);
|
||||||
|
void deselect(PDFInteger id);
|
||||||
|
void deselect(const std::set<PDFInteger>& ids);
|
||||||
|
void deselectAll();
|
||||||
|
|
||||||
|
bool isManipulationInProgress() const { return m_isManipulationInProgress; }
|
||||||
|
|
||||||
|
void manipulateDeleteSelection();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void selectionChanged();
|
||||||
|
void stateChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void stopManipulation();
|
||||||
|
|
||||||
|
PDFPageContentScene* m_scene;
|
||||||
|
std::set<PDFInteger> m_selection;
|
||||||
|
bool m_isManipulationInProgress;
|
||||||
|
std::vector<std::unique_ptr<PDFPageContentElement>> m_manipulatedElements;
|
||||||
|
std::map<PDFInteger, uint> m_manipulationModes;
|
||||||
|
};
|
||||||
|
|
||||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentScene : public QObject,
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentScene : public QObject,
|
||||||
public IDocumentDrawInterface,
|
public IDocumentDrawInterface,
|
||||||
public IDrawWidgetInputInterface
|
public IDrawWidgetInputInterface
|
||||||
@ -216,12 +278,23 @@ public:
|
|||||||
/// \param element Element
|
/// \param element Element
|
||||||
void addElement(PDFPageContentElement* element);
|
void addElement(PDFPageContentElement* element);
|
||||||
|
|
||||||
|
/// Returns element by its id (identifier number)
|
||||||
|
/// \param id Element id
|
||||||
|
PDFPageContentElement* getElementById(PDFInteger id) const;
|
||||||
|
|
||||||
/// Clear whole scene - remove all page content elements
|
/// Clear whole scene - remove all page content elements
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
/// Returns true, if scene is empty
|
/// Returns true, if scene is empty
|
||||||
bool isEmpty() const { return m_elements.empty(); }
|
bool isEmpty() const { return m_elements.empty(); }
|
||||||
|
|
||||||
|
bool isActive() const;
|
||||||
|
void setActive(bool newIsActive);
|
||||||
|
|
||||||
|
/// Removes elements specified in selection
|
||||||
|
/// \param selection Items to be removed
|
||||||
|
void removeElementsById(const std::set<PDFInteger>& selection);
|
||||||
|
|
||||||
// IDrawWidgetInputInterface interface
|
// IDrawWidgetInputInterface interface
|
||||||
public:
|
public:
|
||||||
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;
|
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;
|
||||||
@ -244,20 +317,55 @@ public:
|
|||||||
PDFTextLayoutGetter& layoutGetter,
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
const QMatrix& pagePointToDevicePointMatrix,
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
QList<PDFRenderError>& errors) const override;
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
bool isActive() const;
|
|
||||||
void setActive(bool newIsActive);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/// This signal is emitted when scene has changed (including graphics)
|
/// This signal is emitted when scene has changed (including graphics)
|
||||||
void sceneChanged();
|
void sceneChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
struct MouseEventInfo
|
||||||
|
{
|
||||||
|
std::set<PDFInteger> hoveredElementIds;
|
||||||
|
QPoint widgetMouseStartPos;
|
||||||
|
QPoint widgetMouseCurrentPos;
|
||||||
|
QElapsedTimer timer;
|
||||||
|
|
||||||
|
bool isValid() const { return !hoveredElementIds.empty(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
MouseEventInfo getMouseEventInfo(QWidget* widget, QPoint point);
|
||||||
|
|
||||||
|
struct MouseGrabInfo
|
||||||
|
{
|
||||||
|
MouseEventInfo info;
|
||||||
|
int mouseGrabNesting = 0;
|
||||||
|
|
||||||
|
bool isMouseGrabbed() const { return mouseGrabNesting > 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isMouseGrabbed() const { return m_mouseGrabInfo.isMouseGrabbed(); }
|
||||||
|
|
||||||
|
/// Grabs mouse input, if mouse is already grabbed, or if event
|
||||||
|
/// is accepted.
|
||||||
|
/// \param info Mouse event info
|
||||||
|
/// \param event Mouse event
|
||||||
|
void grabMouse(const MouseEventInfo& info, QMouseEvent* event);
|
||||||
|
|
||||||
|
/// Release mouse input
|
||||||
|
/// \param info Mouse event info
|
||||||
|
/// \param event Mouse event
|
||||||
|
void ungrabMouse(const MouseEventInfo& info, QMouseEvent* event);
|
||||||
|
|
||||||
|
PDFInteger m_firstFreeId;
|
||||||
bool m_isActive;
|
bool m_isActive;
|
||||||
std::vector<std::unique_ptr<PDFPageContentElement>> m_elements;
|
std::vector<std::unique_ptr<PDFPageContentElement>> m_elements;
|
||||||
std::optional<QCursor> m_cursor;
|
std::optional<QCursor> m_cursor;
|
||||||
|
PDFPageContentElementManipulator m_manipulator;
|
||||||
|
MouseGrabInfo m_mouseGrabInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(pdf::PDFPageContentElementManipulator::SelectionModes)
|
||||||
|
|
||||||
#endif // PDFPAGECONTENTELEMENTS_H
|
#endif // PDFPAGECONTENTELEMENTS_H
|
||||||
|
@ -104,6 +104,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
|
|||||||
|
|
||||||
// Initialize toolbar icon size
|
// Initialize toolbar icon size
|
||||||
adjustToolbar(ui->mainToolBar);
|
adjustToolbar(ui->mainToolBar);
|
||||||
|
ui->mainToolBar->setWindowTitle(tr("Standard"));
|
||||||
|
|
||||||
// Initialize task bar progress
|
// Initialize task bar progress
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
@ -102,6 +102,7 @@ PDFViewerMainWindowLite::PDFViewerMainWindowLite(QWidget* parent) :
|
|||||||
|
|
||||||
// Initialize toolbar icon size
|
// Initialize toolbar icon size
|
||||||
adjustToolbar(ui->mainToolBar);
|
adjustToolbar(ui->mainToolBar);
|
||||||
|
ui->mainToolBar->setWindowTitle(tr("Standard"));
|
||||||
|
|
||||||
// Initialize task bar progress
|
// Initialize task bar progress
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
Reference in New Issue
Block a user