Merge remote-tracking branch 'remotes/origin/signdoc'
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 3.7 KiB |
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="256px" height="256px" viewBox="0 0 256 256" enable-background="new 0 0 256 256" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<polygon fill="#C53620" points="146.424,82.456 146.424,0.012 41.555,0.012 41.555,132.479 41.555,134.878 41.555,136.484
|
||||||
|
41.555,149.736 41.555,164.563 41.555,210.882 41.555,222.341 41.555,232.551 41.555,238.803 41.555,249.243 41.555,255.993
|
||||||
|
214.445,255.993 214.445,82.456 "/>
|
||||||
|
<polygon fill="#6CBD45" points="155.248,0.055 155.248,73.621 214.445,73.621 "/>
|
||||||
|
</g>
|
||||||
|
<path fill="#FFFFFF" d="M172.148,135.116c-7.619,0-15.232,0.008-22.668,0.03c0.023-3.642,0.023-7.27,0.017-10.908l-0.009-11.133
|
||||||
|
l-31.014,30.836l31.006,30.727v-22.006h44.615v-17.538L172.148,135.116z"/>
|
||||||
|
<path fill="#FFFFFF" d="M137.501,195.057l-30.951-30.662v21.92l-44.649-0.022v17.405l2.818,0.129
|
||||||
|
c0.396,0.027,0.799,0.048,1.19,0.048l40.688,0.008v21.894L137.501,195.057z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -15,7 +15,7 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
# along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
QT += gui widgets xml
|
QT += gui widgets xml svg
|
||||||
|
|
||||||
TARGET = Pdf4QtLib
|
TARGET = Pdf4QtLib
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
|
@ -72,6 +72,10 @@ SOURCES += \
|
||||||
sources/pdfoptimizer.cpp \
|
sources/pdfoptimizer.cpp \
|
||||||
sources/pdfoptionalcontent.cpp \
|
sources/pdfoptionalcontent.cpp \
|
||||||
sources/pdfoutline.cpp \
|
sources/pdfoutline.cpp \
|
||||||
|
sources/pdfpagecontenteditorstylesettings.cpp \
|
||||||
|
sources/pdfpagecontenteditortools.cpp \
|
||||||
|
sources/pdfpagecontenteditorwidget.cpp \
|
||||||
|
sources/pdfpagecontentelements.cpp \
|
||||||
sources/pdfpagenavigation.cpp \
|
sources/pdfpagenavigation.cpp \
|
||||||
sources/pdfpagetransition.cpp \
|
sources/pdfpagetransition.cpp \
|
||||||
sources/pdfpainterutils.cpp \
|
sources/pdfpainterutils.cpp \
|
||||||
|
@ -87,6 +91,7 @@ SOURCES += \
|
||||||
sources/pdfsignaturehandler.cpp \
|
sources/pdfsignaturehandler.cpp \
|
||||||
sources/pdfsnapper.cpp \
|
sources/pdfsnapper.cpp \
|
||||||
sources/pdfstructuretree.cpp \
|
sources/pdfstructuretree.cpp \
|
||||||
|
sources/pdftexteditpseudowidget.cpp \
|
||||||
sources/pdftextlayout.cpp \
|
sources/pdftextlayout.cpp \
|
||||||
sources/pdftransparencyrenderer.cpp \
|
sources/pdftransparencyrenderer.cpp \
|
||||||
sources/pdfutils.cpp \
|
sources/pdfutils.cpp \
|
||||||
|
@ -147,6 +152,10 @@ HEADERS += \
|
||||||
sources/pdfoptimizer.h \
|
sources/pdfoptimizer.h \
|
||||||
sources/pdfoptionalcontent.h \
|
sources/pdfoptionalcontent.h \
|
||||||
sources/pdfoutline.h \
|
sources/pdfoutline.h \
|
||||||
|
sources/pdfpagecontenteditorstylesettings.h \
|
||||||
|
sources/pdfpagecontenteditortools.h \
|
||||||
|
sources/pdfpagecontenteditorwidget.h \
|
||||||
|
sources/pdfpagecontentelements.h \
|
||||||
sources/pdfpagenavigation.h \
|
sources/pdfpagenavigation.h \
|
||||||
sources/pdfpagetransition.h \
|
sources/pdfpagetransition.h \
|
||||||
sources/pdfpainterutils.h \
|
sources/pdfpainterutils.h \
|
||||||
|
@ -165,6 +174,7 @@ HEADERS += \
|
||||||
sources/pdfsignaturehandler_impl.h \
|
sources/pdfsignaturehandler_impl.h \
|
||||||
sources/pdfsnapper.h \
|
sources/pdfsnapper.h \
|
||||||
sources/pdfstructuretree.h \
|
sources/pdfstructuretree.h \
|
||||||
|
sources/pdftexteditpseudowidget.h \
|
||||||
sources/pdftextlayout.h \
|
sources/pdftextlayout.h \
|
||||||
sources/pdftransparencyrenderer.h \
|
sources/pdftransparencyrenderer.h \
|
||||||
sources/pdfwidgettool.h \
|
sources/pdfwidgettool.h \
|
||||||
|
@ -194,6 +204,8 @@ HEADERS += \
|
||||||
sources/pdfimage.h
|
sources/pdfimage.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
|
sources/pdfpagecontenteditorstylesettings.ui \
|
||||||
|
sources/pdfpagecontenteditorwidget.ui \
|
||||||
sources/pdfrenderingerrorswidget.ui \
|
sources/pdfrenderingerrorswidget.ui \
|
||||||
sources/pdfselectpagesdialog.ui
|
sources/pdfselectpagesdialog.ui
|
||||||
|
|
||||||
|
|
|
@ -659,7 +659,7 @@ void PDFCreateFreehandCurveTool::mousePressEvent(QWidget* widget, QMouseEvent* e
|
||||||
resetTool();
|
resetTool();
|
||||||
}
|
}
|
||||||
|
|
||||||
getProxy()->repaintNeeded();
|
emit getProxy()->repaintNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFCreateFreehandCurveTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
void PDFCreateFreehandCurveTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||||
|
@ -1063,7 +1063,7 @@ void PDFCreateHighlightTextTool::setSelection(PDFTextSelection&& textSelection)
|
||||||
if (m_textSelection != textSelection)
|
if (m_textSelection != textSelection)
|
||||||
{
|
{
|
||||||
m_textSelection = qMove(textSelection);
|
m_textSelection = qMove(textSelection);
|
||||||
getProxy()->repaintNeeded();
|
emit getProxy()->repaintNeeded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,8 @@ private:
|
||||||
public:
|
public:
|
||||||
explicit PDFCreateEllipseTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QAction* action, QObject* parent);
|
explicit PDFCreateEllipseTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QAction* action, QObject* parent);
|
||||||
|
|
||||||
virtual void drawPage(QPainter* painter, PDFInteger pageIndex,
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
const PDFPrecompiledPage* compiledPage,
|
const PDFPrecompiledPage* compiledPage,
|
||||||
PDFTextLayoutGetter& layoutGetter,
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
const QMatrix& pagePointToDevicePointMatrix,
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
|
|
@ -501,10 +501,11 @@ public:
|
||||||
{
|
{
|
||||||
None = 0x0000, ///< No flag
|
None = 0x0000, ///< No flag
|
||||||
Reset = 0x0001, ///< Whole document content is changed (for example, new document is being set)
|
Reset = 0x0001, ///< Whole document content is changed (for example, new document is being set)
|
||||||
Annotation = 0x0002, ///< Annotations changed
|
PageContents = 0x0002, ///< Page contents changed (page graphics, not annotations)
|
||||||
FormField = 0x0004, ///< Form field content changed
|
Annotation = 0x0004, ///< Annotations changed
|
||||||
Authorization = 0x0008, ///< Authorization has changed (for example, old document is granted user access, but for new, owner access)
|
FormField = 0x0008, ///< Form field content changed
|
||||||
XFA_Pagination = 0x0010, ///< XFA pagination has been performed (this flag can be set only when Reset flag has been set and not any other flag)
|
Authorization = 0x0010, ///< Authorization has changed (for example, old document is granted user access, but for new, owner access)
|
||||||
|
XFA_Pagination = 0x0020, ///< XFA pagination has been performed (this flag can be set only when Reset flag has been set and not any other flag)
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_FLAGS(ModificationFlags, ModificationFlag)
|
Q_DECLARE_FLAGS(ModificationFlags, ModificationFlag)
|
||||||
|
@ -550,6 +551,7 @@ public:
|
||||||
ModificationFlags getFlags() const { return m_flags; }
|
ModificationFlags getFlags() const { return m_flags; }
|
||||||
|
|
||||||
bool hasReset() const { return m_flags.testFlag(Reset); }
|
bool hasReset() const { return m_flags.testFlag(Reset); }
|
||||||
|
bool hasPageContentsChanged() const { return m_flags.testFlag(PageContents); }
|
||||||
bool hasFlag(ModificationFlag flag) const { return m_flags.testFlag(flag); }
|
bool hasFlag(ModificationFlag flag) const { return m_flags.testFlag(flag); }
|
||||||
|
|
||||||
operator PDFDocument*() const { return m_document; }
|
operator PDFDocument*() const { return m_document; }
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include "pdfobjectutils.h"
|
#include "pdfobjectutils.h"
|
||||||
#include "pdfnametreeloader.h"
|
#include "pdfnametreeloader.h"
|
||||||
#include "pdfdbgheap.h"
|
#include "pdfdbgheap.h"
|
||||||
|
#include "pdfparser.h"
|
||||||
|
#include "pdfstreamfilters.h"
|
||||||
|
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
@ -698,14 +700,23 @@ PDFDocument PDFDocumentBuilder::build()
|
||||||
return PDFDocument(PDFObjectStorage(m_storage), m_version);
|
return PDFDocument(PDFObjectStorage(m_storage), m_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray PDFDocumentBuilder::getDecodedStream(const PDFStream* stream) const
|
||||||
|
{
|
||||||
|
return m_storage.getDecodedStream(stream);
|
||||||
|
}
|
||||||
|
|
||||||
std::array<PDFReal, 4> PDFDocumentBuilder::getAnnotationReductionRectangle(const QRectF& boundingRect, const QRectF& innerRect) const
|
std::array<PDFReal, 4> PDFDocumentBuilder::getAnnotationReductionRectangle(const QRectF& boundingRect, const QRectF& innerRect) const
|
||||||
{
|
{
|
||||||
return { qAbs(innerRect.left() - boundingRect.left()), qAbs(boundingRect.bottom() - innerRect.bottom()), qAbs(boundingRect.right() - innerRect.right()), qAbs(boundingRect.top() - innerRect.top()) };
|
return { qAbs(innerRect.left() - boundingRect.left()), qAbs(boundingRect.bottom() - innerRect.bottom()), qAbs(boundingRect.right() - innerRect.right()), qAbs(boundingRect.top() - innerRect.top()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFPageContentStreamBuilder::PDFPageContentStreamBuilder(PDFDocumentBuilder* builder) :
|
PDFPageContentStreamBuilder::PDFPageContentStreamBuilder(PDFDocumentBuilder* builder,
|
||||||
|
PDFContentStreamBuilder::CoordinateSystem coordinateSystem,
|
||||||
|
Mode mode) :
|
||||||
m_documentBuilder(builder),
|
m_documentBuilder(builder),
|
||||||
m_contentStreamBuilder(nullptr)
|
m_contentStreamBuilder(nullptr),
|
||||||
|
m_coordinateSystem(coordinateSystem),
|
||||||
|
m_mode(mode)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -733,7 +744,7 @@ QPainter* PDFPageContentStreamBuilder::begin(PDFObjectReference page)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pageReference = page;
|
m_pageReference = page;
|
||||||
m_contentStreamBuilder = new PDFContentStreamBuilder(mediaBox.size(), PDFContentStreamBuilder::CoordinateSystem::Qt);
|
m_contentStreamBuilder = new PDFContentStreamBuilder(mediaBox.size(), m_coordinateSystem);
|
||||||
return m_contentStreamBuilder->begin();
|
return m_contentStreamBuilder->begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,21 +773,223 @@ void PDFPageContentStreamBuilder::end(QPainter* painter)
|
||||||
PDFObjectReference resourcesReference = copiedObjects[0].getReference();
|
PDFObjectReference resourcesReference = copiedObjects[0].getReference();
|
||||||
PDFObjectReference contentsReference = copiedObjects[1].getReference();
|
PDFObjectReference contentsReference = copiedObjects[1].getReference();
|
||||||
|
|
||||||
PDFObjectFactory pageUpdateFactory;
|
if (m_mode == Mode::Replace)
|
||||||
|
{
|
||||||
|
PDFObjectFactory pageUpdateFactory;
|
||||||
|
|
||||||
pageUpdateFactory.beginDictionary();
|
pageUpdateFactory.beginDictionary();
|
||||||
|
|
||||||
pageUpdateFactory.beginDictionaryItem("Contents");
|
pageUpdateFactory.beginDictionaryItem("Contents");
|
||||||
pageUpdateFactory << contentsReference;
|
pageUpdateFactory << contentsReference;
|
||||||
pageUpdateFactory.endDictionaryItem();
|
pageUpdateFactory.endDictionaryItem();
|
||||||
|
|
||||||
pageUpdateFactory.beginDictionaryItem("Resources");
|
pageUpdateFactory.beginDictionaryItem("Resources");
|
||||||
pageUpdateFactory << resourcesReference;
|
pageUpdateFactory << resourcesReference;
|
||||||
pageUpdateFactory.endDictionaryItem();
|
pageUpdateFactory.endDictionaryItem();
|
||||||
|
|
||||||
pageUpdateFactory.endDictionary();
|
pageUpdateFactory.endDictionary();
|
||||||
|
|
||||||
m_documentBuilder->mergeTo(m_pageReference, pageUpdateFactory.takeObject());
|
m_documentBuilder->mergeTo(m_pageReference, pageUpdateFactory.takeObject());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<PDFObjectReference> contentReferences;
|
||||||
|
PDFObject pageObject = m_documentBuilder->getObjectByReference(m_pageReference);
|
||||||
|
|
||||||
|
if (pageObject.isDictionary())
|
||||||
|
{
|
||||||
|
const PDFDictionary* pageDictionary = pageObject.getDictionary();
|
||||||
|
const PDFObject& oldContents = pageDictionary->get("Contents");
|
||||||
|
const PDFObject& oldContentsObject = m_documentBuilder->getObject(oldContents);
|
||||||
|
|
||||||
|
if (oldContentsObject.isStream())
|
||||||
|
{
|
||||||
|
if (oldContents.isReference())
|
||||||
|
{
|
||||||
|
contentReferences.push_back(oldContents.getReference());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (oldContentsObject.isArray())
|
||||||
|
{
|
||||||
|
const PDFArray* contentsArray = oldContentsObject.getArray();
|
||||||
|
for (const PDFObject& object : *contentsArray)
|
||||||
|
{
|
||||||
|
if (object.isReference())
|
||||||
|
{
|
||||||
|
contentReferences.push_back(object.getReference());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFObject oldResourcesObject = pageDictionary->get("Resources");
|
||||||
|
replaceResources(contentsReference, resourcesReference, oldResourcesObject);
|
||||||
|
m_documentBuilder->mergeTo(resourcesReference, m_documentBuilder->getObject(oldResourcesObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_mode)
|
||||||
|
{
|
||||||
|
case Mode::PlaceBefore:
|
||||||
|
contentReferences.insert(contentReferences.begin(), contentsReference);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Mode::PlaceAfter:
|
||||||
|
contentReferences.push_back(contentsReference);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFObjectFactory pageUpdateFactory;
|
||||||
|
|
||||||
|
pageUpdateFactory.beginDictionary();
|
||||||
|
|
||||||
|
pageUpdateFactory.beginDictionaryItem("Contents");
|
||||||
|
pageUpdateFactory << contentReferences;
|
||||||
|
pageUpdateFactory.endDictionaryItem();
|
||||||
|
|
||||||
|
pageUpdateFactory.beginDictionaryItem("Resources");
|
||||||
|
pageUpdateFactory << resourcesReference;
|
||||||
|
pageUpdateFactory.endDictionaryItem();
|
||||||
|
|
||||||
|
pageUpdateFactory.endDictionary();
|
||||||
|
|
||||||
|
m_documentBuilder->mergeTo(m_pageReference, pageUpdateFactory.takeObject());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentStreamBuilder::replaceResources(PDFObjectReference contentStreamReference,
|
||||||
|
PDFObjectReference resourcesReference,
|
||||||
|
PDFObject oldResources)
|
||||||
|
{
|
||||||
|
PDFObject newResources = m_documentBuilder->getObjectByReference(resourcesReference);
|
||||||
|
oldResources = m_documentBuilder->getObject(oldResources);
|
||||||
|
PDFObject contentStreamObject = m_documentBuilder->getObjectByReference(contentStreamReference);
|
||||||
|
|
||||||
|
std::vector<std::pair<QByteArray, QByteArray>> renamings;
|
||||||
|
|
||||||
|
if (oldResources.isDictionary() && newResources.isDictionary())
|
||||||
|
{
|
||||||
|
PDFObjectFactory renamedResourcesDictionary;
|
||||||
|
|
||||||
|
renamedResourcesDictionary.beginDictionary();
|
||||||
|
|
||||||
|
const PDFDictionary* oldResourcesDictionary = oldResources.getDictionary();
|
||||||
|
const PDFDictionary* newResourcesDictionary = newResources.getDictionary();
|
||||||
|
const size_t count = newResourcesDictionary->getCount();
|
||||||
|
for (size_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
const PDFInplaceOrMemoryString& key = newResourcesDictionary->getKey(i);
|
||||||
|
QByteArray keyString = key.getString();
|
||||||
|
|
||||||
|
// Process current resource key
|
||||||
|
renamedResourcesDictionary.beginDictionaryItem(keyString);
|
||||||
|
|
||||||
|
if (oldResourcesDictionary->hasKey(keyString))
|
||||||
|
{
|
||||||
|
const PDFObject& newResourcesSubdictionaryObject = m_documentBuilder->getObject(newResourcesDictionary->getValue(i));
|
||||||
|
const PDFObject& oldResourcesSubdictionaryObject = m_documentBuilder->getObject(oldResourcesDictionary->get(keyString));
|
||||||
|
if (oldResourcesSubdictionaryObject.isDictionary() && newResourcesSubdictionaryObject.isDictionary())
|
||||||
|
{
|
||||||
|
// Jakub Melka: Rename items, which are in both dictionaries
|
||||||
|
const PDFDictionary* oldSd = oldResourcesSubdictionaryObject.getDictionary();
|
||||||
|
const PDFDictionary* newSd = newResourcesSubdictionaryObject.getDictionary();
|
||||||
|
|
||||||
|
renamedResourcesDictionary.beginDictionary();
|
||||||
|
|
||||||
|
const size_t subcount = newSd->getCount();
|
||||||
|
for (size_t j = 0; j < subcount; ++j)
|
||||||
|
{
|
||||||
|
const PDFInplaceOrMemoryString& subkey = newSd->getKey(j);
|
||||||
|
QByteArray subkeyString = subkey.getString();
|
||||||
|
if (oldSd->hasKey(subkeyString))
|
||||||
|
{
|
||||||
|
// Jakub Melka: we must rename the item
|
||||||
|
QByteArray newSubkeyString = subkeyString;
|
||||||
|
PDFInteger k = 0;
|
||||||
|
while (oldSd->hasKey(newSubkeyString))
|
||||||
|
{
|
||||||
|
newSubkeyString = subkeyString + "_" + QByteArray::number(++k);
|
||||||
|
}
|
||||||
|
renamings.emplace_back(std::make_pair(subkeyString, newSubkeyString));
|
||||||
|
subkeyString = newSubkeyString;
|
||||||
|
}
|
||||||
|
|
||||||
|
renamedResourcesDictionary.beginDictionaryItem(subkeyString);
|
||||||
|
renamedResourcesDictionary << newSd->getValue(j);
|
||||||
|
renamedResourcesDictionary.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
renamedResourcesDictionary.endDictionary();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
renamedResourcesDictionary << newResourcesDictionary->getValue(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
renamedResourcesDictionary << newResourcesDictionary->getValue(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
renamedResourcesDictionary.endDictionaryItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
renamedResourcesDictionary.endDictionary();
|
||||||
|
m_documentBuilder->setObject(resourcesReference, renamedResourcesDictionary.takeObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentStreamObject.isStream())
|
||||||
|
{
|
||||||
|
QByteArray decodedStream = m_documentBuilder->getDecodedStream(contentStreamObject.getStream());
|
||||||
|
decodedStream = decodedStream.trimmed();
|
||||||
|
|
||||||
|
// Append save/restore state
|
||||||
|
if (!decodedStream.startsWith("q "))
|
||||||
|
{
|
||||||
|
decodedStream.prepend("q ");
|
||||||
|
decodedStream.append(" Q");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace all occurences in the stream
|
||||||
|
for (const auto& item : renamings)
|
||||||
|
{
|
||||||
|
QByteArray oldName = item.first;
|
||||||
|
QByteArray newName = item.second;
|
||||||
|
|
||||||
|
oldName.prepend('/');
|
||||||
|
newName.prepend('/');
|
||||||
|
|
||||||
|
int currentPos = 0;
|
||||||
|
int oldNameIndex = decodedStream.indexOf(oldName, currentPos);
|
||||||
|
while (oldNameIndex != -1)
|
||||||
|
{
|
||||||
|
const int whiteSpacePosition = oldNameIndex + oldName.size();
|
||||||
|
if (whiteSpacePosition < decodedStream.size() && !PDFLexicalAnalyzer::isWhitespace(decodedStream[whiteSpacePosition]))
|
||||||
|
{
|
||||||
|
currentPos = oldNameIndex + 1;
|
||||||
|
oldNameIndex = decodedStream.indexOf(oldName, currentPos);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
decodedStream.replace(oldNameIndex, oldName.length(), newName);
|
||||||
|
currentPos = oldNameIndex + 1;
|
||||||
|
oldNameIndex = decodedStream.indexOf(oldName, currentPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFArray array;
|
||||||
|
array.appendItem(PDFObject::createName("FlateDecode"));
|
||||||
|
|
||||||
|
// Compress the content stream
|
||||||
|
QByteArray compressedData = PDFFlateDecodeFilter::compress(decodedStream);
|
||||||
|
PDFDictionary updatedDictionary = *contentStreamObject.getStream()->getDictionary();
|
||||||
|
updatedDictionary.setEntry(PDFInplaceOrMemoryString("Length"), PDFObject::createInteger(compressedData.size()));
|
||||||
|
updatedDictionary.setEntry(PDFInplaceOrMemoryString("Filters"), PDFObject::createArray(std::make_shared<PDFArray>(qMove(array))));
|
||||||
|
PDFObject newContentStream = PDFObject::createStream(std::make_shared<PDFStream>(qMove(updatedDictionary), qMove(compressedData)));
|
||||||
|
m_documentBuilder->setObject(contentStreamReference, std::move(newContentStream));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFDocumentBuilder::updateAnnotationAppearanceStreams(PDFObjectReference annotationReference)
|
void PDFDocumentBuilder::updateAnnotationAppearanceStreams(PDFObjectReference annotationReference)
|
||||||
|
@ -1715,6 +1928,30 @@ PDFObjectReference PDFDocumentBuilder::appendPage(QRectF mediaBox)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PDFObjectReference PDFDocumentBuilder::createAcroForm(PDFObjectReferenceVector fields)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Fields");
|
||||||
|
objectBuilder << fields;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("NeedAppearances");
|
||||||
|
objectBuilder << false;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("SigFlags");
|
||||||
|
objectBuilder << 0;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("XFA");
|
||||||
|
objectBuilder << PDFObject();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObjectReference acroForm = addObject(objectBuilder.takeObject());
|
||||||
|
setCatalogAcroForm(acroForm);
|
||||||
|
return acroForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PDFObjectReference PDFDocumentBuilder::createActionGoTo(PDFDestination destination)
|
PDFObjectReference PDFDocumentBuilder::createActionGoTo(PDFDestination destination)
|
||||||
{
|
{
|
||||||
PDFObjectFactory objectBuilder;
|
PDFObjectFactory objectBuilder;
|
||||||
|
@ -2479,88 +2716,6 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationFileAttachment(PDFObjectR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PDFObjectReference PDFDocumentBuilder::createAnnotationFreeText(PDFObjectReference page,
|
|
||||||
QRectF boundingRectangle,
|
|
||||||
QRectF textRectangle,
|
|
||||||
QString title,
|
|
||||||
QString subject,
|
|
||||||
QString contents,
|
|
||||||
TextAlignment textAlignment,
|
|
||||||
QPointF startPoint,
|
|
||||||
QPointF endPoint,
|
|
||||||
AnnotationLineEnding startLineType,
|
|
||||||
AnnotationLineEnding endLineType)
|
|
||||||
{
|
|
||||||
PDFObjectFactory objectBuilder;
|
|
||||||
|
|
||||||
objectBuilder.beginDictionary();
|
|
||||||
objectBuilder.beginDictionaryItem("Type");
|
|
||||||
objectBuilder << WrapName("Annot");
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("Subtype");
|
|
||||||
objectBuilder << WrapName("FreeText");
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("Rect");
|
|
||||||
objectBuilder << boundingRectangle;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("F");
|
|
||||||
objectBuilder << 4;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("P");
|
|
||||||
objectBuilder << page;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("M");
|
|
||||||
objectBuilder << WrapCurrentDateTime();
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("CreationDate");
|
|
||||||
objectBuilder << WrapCurrentDateTime();
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("T");
|
|
||||||
objectBuilder << title;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("Contents");
|
|
||||||
objectBuilder << contents;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("Subj");
|
|
||||||
objectBuilder << subject;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("Q");
|
|
||||||
objectBuilder << WrapFreeTextAlignment(textAlignment);
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("DA");
|
|
||||||
objectBuilder << WrapString("/Arial 10 Tf");
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("RD");
|
|
||||||
objectBuilder << getAnnotationReductionRectangle(boundingRectangle, textRectangle);
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("CL");
|
|
||||||
objectBuilder.beginArray();
|
|
||||||
objectBuilder << startPoint;
|
|
||||||
objectBuilder << endPoint;
|
|
||||||
objectBuilder.endArray();
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("LE");
|
|
||||||
objectBuilder.beginArray();
|
|
||||||
objectBuilder << startLineType;
|
|
||||||
objectBuilder << endLineType;
|
|
||||||
objectBuilder.endArray();
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.endDictionary();
|
|
||||||
PDFObjectReference annotationObject = addObject(objectBuilder.takeObject());
|
|
||||||
objectBuilder.beginDictionary();
|
|
||||||
objectBuilder.beginDictionaryItem("Annots");
|
|
||||||
objectBuilder.beginArray();
|
|
||||||
objectBuilder << annotationObject;
|
|
||||||
objectBuilder.endArray();
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.endDictionary();
|
|
||||||
PDFObject pageAnnots = objectBuilder.takeObject();
|
|
||||||
appendTo(page, pageAnnots);
|
|
||||||
updateAnnotationAppearanceStreams(annotationObject);
|
|
||||||
return annotationObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PDFObjectReference PDFDocumentBuilder::createAnnotationFreeText(PDFObjectReference page,
|
PDFObjectReference PDFDocumentBuilder::createAnnotationFreeText(PDFObjectReference page,
|
||||||
QRectF boundingRectangle,
|
QRectF boundingRectangle,
|
||||||
QRectF textRectangle,
|
QRectF textRectangle,
|
||||||
|
@ -2707,6 +2862,88 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationFreeText(PDFObjectReferen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PDFObjectReference PDFDocumentBuilder::createAnnotationFreeText(PDFObjectReference page,
|
||||||
|
QRectF boundingRectangle,
|
||||||
|
QRectF textRectangle,
|
||||||
|
QString title,
|
||||||
|
QString subject,
|
||||||
|
QString contents,
|
||||||
|
TextAlignment textAlignment,
|
||||||
|
QPointF startPoint,
|
||||||
|
QPointF endPoint,
|
||||||
|
AnnotationLineEnding startLineType,
|
||||||
|
AnnotationLineEnding endLineType)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Type");
|
||||||
|
objectBuilder << WrapName("Annot");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Subtype");
|
||||||
|
objectBuilder << WrapName("FreeText");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Rect");
|
||||||
|
objectBuilder << boundingRectangle;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("F");
|
||||||
|
objectBuilder << 4;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("P");
|
||||||
|
objectBuilder << page;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("M");
|
||||||
|
objectBuilder << WrapCurrentDateTime();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("CreationDate");
|
||||||
|
objectBuilder << WrapCurrentDateTime();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("T");
|
||||||
|
objectBuilder << title;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Contents");
|
||||||
|
objectBuilder << contents;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Subj");
|
||||||
|
objectBuilder << subject;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Q");
|
||||||
|
objectBuilder << WrapFreeTextAlignment(textAlignment);
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("DA");
|
||||||
|
objectBuilder << WrapString("/Arial 10 Tf");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("RD");
|
||||||
|
objectBuilder << getAnnotationReductionRectangle(boundingRectangle, textRectangle);
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("CL");
|
||||||
|
objectBuilder.beginArray();
|
||||||
|
objectBuilder << startPoint;
|
||||||
|
objectBuilder << endPoint;
|
||||||
|
objectBuilder.endArray();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("LE");
|
||||||
|
objectBuilder.beginArray();
|
||||||
|
objectBuilder << startLineType;
|
||||||
|
objectBuilder << endLineType;
|
||||||
|
objectBuilder.endArray();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObjectReference annotationObject = addObject(objectBuilder.takeObject());
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Annots");
|
||||||
|
objectBuilder.beginArray();
|
||||||
|
objectBuilder << annotationObject;
|
||||||
|
objectBuilder.endArray();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObject pageAnnots = objectBuilder.takeObject();
|
||||||
|
appendTo(page, pageAnnots);
|
||||||
|
updateAnnotationAppearanceStreams(annotationObject);
|
||||||
|
return annotationObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PDFObjectReference PDFDocumentBuilder::createAnnotationHighlight(PDFObjectReference page,
|
PDFObjectReference PDFDocumentBuilder::createAnnotationHighlight(PDFObjectReference page,
|
||||||
QRectF rectangle,
|
QRectF rectangle,
|
||||||
QColor color,
|
QColor color,
|
||||||
|
@ -3632,6 +3869,47 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationSquiggly(PDFObjectReferen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PDFObjectReference PDFDocumentBuilder::createAnnotationSquiggly(PDFObjectReference page,
|
||||||
|
QPolygonF quadrilaterals,
|
||||||
|
QColor color)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Type");
|
||||||
|
objectBuilder << WrapName("Annot");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Subtype");
|
||||||
|
objectBuilder << WrapName("Squiggly");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("P");
|
||||||
|
objectBuilder << page;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("CreationDate");
|
||||||
|
objectBuilder << WrapCurrentDateTime();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("C");
|
||||||
|
objectBuilder << color;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("QuadPoints");
|
||||||
|
objectBuilder << quadrilaterals;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObjectReference annotationObject = addObject(objectBuilder.takeObject());
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Annots");
|
||||||
|
objectBuilder.beginArray();
|
||||||
|
objectBuilder << annotationObject;
|
||||||
|
objectBuilder.endArray();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObject pageAnnots = objectBuilder.takeObject();
|
||||||
|
appendTo(page, pageAnnots);
|
||||||
|
updateAnnotationAppearanceStreams(annotationObject);
|
||||||
|
return annotationObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PDFObjectReference PDFDocumentBuilder::createAnnotationSquiggly(PDFObjectReference page,
|
PDFObjectReference PDFDocumentBuilder::createAnnotationSquiggly(PDFObjectReference page,
|
||||||
QRectF rectangle,
|
QRectF rectangle,
|
||||||
QColor color,
|
QColor color,
|
||||||
|
@ -3696,47 +3974,6 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationSquiggly(PDFObjectReferen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PDFObjectReference PDFDocumentBuilder::createAnnotationSquiggly(PDFObjectReference page,
|
|
||||||
QPolygonF quadrilaterals,
|
|
||||||
QColor color)
|
|
||||||
{
|
|
||||||
PDFObjectFactory objectBuilder;
|
|
||||||
|
|
||||||
objectBuilder.beginDictionary();
|
|
||||||
objectBuilder.beginDictionaryItem("Type");
|
|
||||||
objectBuilder << WrapName("Annot");
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("Subtype");
|
|
||||||
objectBuilder << WrapName("Squiggly");
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("P");
|
|
||||||
objectBuilder << page;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("CreationDate");
|
|
||||||
objectBuilder << WrapCurrentDateTime();
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("C");
|
|
||||||
objectBuilder << color;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("QuadPoints");
|
|
||||||
objectBuilder << quadrilaterals;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.endDictionary();
|
|
||||||
PDFObjectReference annotationObject = addObject(objectBuilder.takeObject());
|
|
||||||
objectBuilder.beginDictionary();
|
|
||||||
objectBuilder.beginDictionaryItem("Annots");
|
|
||||||
objectBuilder.beginArray();
|
|
||||||
objectBuilder << annotationObject;
|
|
||||||
objectBuilder.endArray();
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.endDictionary();
|
|
||||||
PDFObject pageAnnots = objectBuilder.takeObject();
|
|
||||||
appendTo(page, pageAnnots);
|
|
||||||
updateAnnotationAppearanceStreams(annotationObject);
|
|
||||||
return annotationObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PDFObjectReference PDFDocumentBuilder::createAnnotationStamp(PDFObjectReference page,
|
PDFObjectReference PDFDocumentBuilder::createAnnotationStamp(PDFObjectReference page,
|
||||||
QRectF rectangle,
|
QRectF rectangle,
|
||||||
Stamp stampType,
|
Stamp stampType,
|
||||||
|
@ -4020,70 +4257,6 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationText(PDFObjectReference p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectReference page,
|
|
||||||
QRectF rectangle,
|
|
||||||
QColor color,
|
|
||||||
QString title,
|
|
||||||
QString subject,
|
|
||||||
QString contents)
|
|
||||||
{
|
|
||||||
PDFObjectFactory objectBuilder;
|
|
||||||
|
|
||||||
objectBuilder.beginDictionary();
|
|
||||||
objectBuilder.beginDictionaryItem("Type");
|
|
||||||
objectBuilder << WrapName("Annot");
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("Subtype");
|
|
||||||
objectBuilder << WrapName("Underline");
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("Rect");
|
|
||||||
objectBuilder << rectangle;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("P");
|
|
||||||
objectBuilder << page;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("M");
|
|
||||||
objectBuilder << WrapCurrentDateTime();
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("CreationDate");
|
|
||||||
objectBuilder << WrapCurrentDateTime();
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("C");
|
|
||||||
objectBuilder << color;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("T");
|
|
||||||
objectBuilder << title;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("Contents");
|
|
||||||
objectBuilder << contents;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("Subj");
|
|
||||||
objectBuilder << subject;
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.beginDictionaryItem("QuadPoints");
|
|
||||||
objectBuilder.beginArray();
|
|
||||||
objectBuilder << rectangle.bottomLeft();
|
|
||||||
objectBuilder << rectangle.bottomRight();
|
|
||||||
objectBuilder << rectangle.topLeft();
|
|
||||||
objectBuilder << rectangle.topRight();
|
|
||||||
objectBuilder.endArray();
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.endDictionary();
|
|
||||||
PDFObjectReference annotationObject = addObject(objectBuilder.takeObject());
|
|
||||||
objectBuilder.beginDictionary();
|
|
||||||
objectBuilder.beginDictionaryItem("Annots");
|
|
||||||
objectBuilder.beginArray();
|
|
||||||
objectBuilder << annotationObject;
|
|
||||||
objectBuilder.endArray();
|
|
||||||
objectBuilder.endDictionaryItem();
|
|
||||||
objectBuilder.endDictionary();
|
|
||||||
PDFObject pageAnnots = objectBuilder.takeObject();
|
|
||||||
appendTo(page, pageAnnots);
|
|
||||||
updateAnnotationAppearanceStreams(annotationObject);
|
|
||||||
return annotationObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectReference page,
|
PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectReference page,
|
||||||
QRectF rectangle,
|
QRectF rectangle,
|
||||||
QColor color)
|
QColor color)
|
||||||
|
@ -4174,6 +4347,70 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectRefere
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectReference page,
|
||||||
|
QRectF rectangle,
|
||||||
|
QColor color,
|
||||||
|
QString title,
|
||||||
|
QString subject,
|
||||||
|
QString contents)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Type");
|
||||||
|
objectBuilder << WrapName("Annot");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Subtype");
|
||||||
|
objectBuilder << WrapName("Underline");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Rect");
|
||||||
|
objectBuilder << rectangle;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("P");
|
||||||
|
objectBuilder << page;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("M");
|
||||||
|
objectBuilder << WrapCurrentDateTime();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("CreationDate");
|
||||||
|
objectBuilder << WrapCurrentDateTime();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("C");
|
||||||
|
objectBuilder << color;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("T");
|
||||||
|
objectBuilder << title;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Contents");
|
||||||
|
objectBuilder << contents;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Subj");
|
||||||
|
objectBuilder << subject;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("QuadPoints");
|
||||||
|
objectBuilder.beginArray();
|
||||||
|
objectBuilder << rectangle.bottomLeft();
|
||||||
|
objectBuilder << rectangle.bottomRight();
|
||||||
|
objectBuilder << rectangle.topLeft();
|
||||||
|
objectBuilder << rectangle.topRight();
|
||||||
|
objectBuilder.endArray();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObjectReference annotationObject = addObject(objectBuilder.takeObject());
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Annots");
|
||||||
|
objectBuilder.beginArray();
|
||||||
|
objectBuilder << annotationObject;
|
||||||
|
objectBuilder.endArray();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObject pageAnnots = objectBuilder.takeObject();
|
||||||
|
appendTo(page, pageAnnots);
|
||||||
|
updateAnnotationAppearanceStreams(annotationObject);
|
||||||
|
return annotationObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PDFObjectReference PDFDocumentBuilder::createCatalog()
|
PDFObjectReference PDFDocumentBuilder::createCatalog()
|
||||||
{
|
{
|
||||||
PDFObjectFactory objectBuilder;
|
PDFObjectFactory objectBuilder;
|
||||||
|
@ -4305,6 +4542,135 @@ PDFObjectReference PDFDocumentBuilder::createFileSpecification(QString fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PDFObjectReference PDFDocumentBuilder::createFormFieldSignature(QString fieldName,
|
||||||
|
PDFObjectReferenceVector kids,
|
||||||
|
PDFObjectReference signatureValue)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("FT");
|
||||||
|
objectBuilder << WrapName("Sig");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Kids");
|
||||||
|
objectBuilder << kids;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("T");
|
||||||
|
objectBuilder << fieldName;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("V");
|
||||||
|
objectBuilder << signatureValue;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObjectReference formFieldSignature = addObject(objectBuilder.takeObject());
|
||||||
|
return formFieldSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PDFDocumentBuilder::createFormFieldWidget(PDFObjectReference formField,
|
||||||
|
PDFObjectReference page,
|
||||||
|
PDFObjectReference appearanceStream,
|
||||||
|
QRectF rect)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Type");
|
||||||
|
objectBuilder << WrapName("Annot");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Subtype");
|
||||||
|
objectBuilder << WrapName("Widget");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("P");
|
||||||
|
objectBuilder << page;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Rect");
|
||||||
|
objectBuilder << rect;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("AP");
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("N");
|
||||||
|
objectBuilder << appearanceStream;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObject widgetObject = objectBuilder.takeObject();
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Annots");
|
||||||
|
objectBuilder << std::array{ formField };
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObject pageObject = objectBuilder.takeObject();
|
||||||
|
mergeTo(formField, widgetObject);
|
||||||
|
appendTo(page, pageObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PDFDocumentBuilder::createInvisibleFormFieldWidget(PDFObjectReference formField,
|
||||||
|
PDFObjectReference page)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("P");
|
||||||
|
objectBuilder << page;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Rect");
|
||||||
|
objectBuilder << std::array{ 0.0, 0.0, 0.0, 0.0 };
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Subtype");
|
||||||
|
objectBuilder << WrapName("Widget");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Type");
|
||||||
|
objectBuilder << WrapName("Annot");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObject widgetObject = objectBuilder.takeObject();
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Annots");
|
||||||
|
objectBuilder << std::array{ formField };
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObject pageObject = objectBuilder.takeObject();
|
||||||
|
mergeTo(formField, widgetObject);
|
||||||
|
appendTo(page, pageObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PDFObjectReference PDFDocumentBuilder::createSignatureDictionary(QByteArray filter,
|
||||||
|
QByteArray subfilter,
|
||||||
|
QByteArray contents,
|
||||||
|
QDateTime signingTime,
|
||||||
|
PDFInteger byteRangeItem)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Type");
|
||||||
|
objectBuilder << WrapName("Sig");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Filter");
|
||||||
|
objectBuilder << WrapName(filter);
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("SubFilter");
|
||||||
|
objectBuilder << WrapName(subfilter);
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("ByteRange");
|
||||||
|
objectBuilder << std::array{ byteRangeItem, byteRangeItem, byteRangeItem, byteRangeItem };
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Contents");
|
||||||
|
objectBuilder << WrapString(contents);
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("M");
|
||||||
|
objectBuilder << signingTime;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObjectReference signatureDictionary = addObject(objectBuilder.takeObject());
|
||||||
|
return signatureDictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PDFObject PDFDocumentBuilder::createTrailerDictionary(PDFObjectReference catalog)
|
PDFObject PDFDocumentBuilder::createTrailerDictionary(PDFObjectReference catalog)
|
||||||
{
|
{
|
||||||
PDFObjectFactory objectBuilder;
|
PDFObjectFactory objectBuilder;
|
||||||
|
@ -4805,6 +5171,14 @@ void PDFDocumentBuilder::setFormFieldValue(PDFObjectReference formField,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PDFDocumentBuilder::setLanguage(QLocale locale)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
setLanguage(locale.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PDFDocumentBuilder::setLanguage(QString language)
|
void PDFDocumentBuilder::setLanguage(QString language)
|
||||||
{
|
{
|
||||||
PDFObjectFactory objectBuilder;
|
PDFObjectFactory objectBuilder;
|
||||||
|
@ -4819,14 +5193,6 @@ void PDFDocumentBuilder::setLanguage(QString language)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PDFDocumentBuilder::setLanguage(QLocale locale)
|
|
||||||
{
|
|
||||||
PDFObjectFactory objectBuilder;
|
|
||||||
|
|
||||||
setLanguage(locale.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PDFDocumentBuilder::setOutline(PDFObjectReference outline)
|
void PDFDocumentBuilder::setOutline(PDFObjectReference outline)
|
||||||
{
|
{
|
||||||
PDFObjectFactory objectBuilder;
|
PDFObjectFactory objectBuilder;
|
||||||
|
@ -4961,6 +5327,36 @@ void PDFDocumentBuilder::setPageUserUnit(PDFObjectReference page,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PDFDocumentBuilder::setSignatureContactInfo(PDFObjectReference signatureDictionary,
|
||||||
|
QString contactInfoText)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("ContactInfo");
|
||||||
|
objectBuilder << contactInfoText;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObject updatedSignatureDictionary = objectBuilder.takeObject();
|
||||||
|
mergeTo(signatureDictionary, updatedSignatureDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PDFDocumentBuilder::setSignatureReason(PDFObjectReference signatureDictionary,
|
||||||
|
QString reasonText)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Reason");
|
||||||
|
objectBuilder << reasonText;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObject updatedSignatureDictionary = objectBuilder.takeObject();
|
||||||
|
mergeTo(signatureDictionary, updatedSignatureDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PDFDocumentBuilder::updateTrailerDictionary(PDFInteger objectCount)
|
void PDFDocumentBuilder::updateTrailerDictionary(PDFInteger objectCount)
|
||||||
{
|
{
|
||||||
PDFObjectFactory objectBuilder;
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
|
@ -39,6 +39,12 @@ struct WrapName
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WrapName(QByteArray name) :
|
||||||
|
name(std::move(name))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray name;
|
QByteArray name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,7 +92,7 @@ struct WrapEmptyArray { };
|
||||||
|
|
||||||
/// Factory for creating various PDF objects, such as simple objects,
|
/// Factory for creating various PDF objects, such as simple objects,
|
||||||
/// dictionaries, arrays etc.
|
/// dictionaries, arrays etc.
|
||||||
class PDFObjectFactory
|
class PDF4QTLIBSHARED_EXPORT PDFObjectFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline explicit PDFObjectFactory() = default;
|
inline explicit PDFObjectFactory() = default;
|
||||||
|
@ -261,9 +267,20 @@ private:
|
||||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentStreamBuilder
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentStreamBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PDFPageContentStreamBuilder(PDFDocumentBuilder* builder);
|
|
||||||
|
|
||||||
/// Starts painting onto the page. Old page content is erased. This
|
enum class Mode
|
||||||
|
{
|
||||||
|
Replace,
|
||||||
|
PlaceBefore,
|
||||||
|
PlaceAfter
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Vytvoří nový builder, který vytváří obsah stránek.
|
||||||
|
PDFPageContentStreamBuilder(PDFDocumentBuilder* builder,
|
||||||
|
PDFContentStreamBuilder::CoordinateSystem coordinateSystem = PDFContentStreamBuilder::CoordinateSystem::Qt,
|
||||||
|
Mode mode = Mode::Replace);
|
||||||
|
|
||||||
|
/// Starts painting onto the page. Old page content is erased (in Replace mode). This
|
||||||
/// function returns painter, onto which can be graphics drawn. Painter
|
/// function returns painter, onto which can be graphics drawn. Painter
|
||||||
/// uses Qt's coordinate system. Calling begin multiple times, without
|
/// uses Qt's coordinate system. Calling begin multiple times, without
|
||||||
/// subsequent calls to end function, is invalid and can result
|
/// subsequent calls to end function, is invalid and can result
|
||||||
|
@ -284,9 +301,15 @@ public:
|
||||||
void end(QPainter* painter);
|
void end(QPainter* painter);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void replaceResources(PDFObjectReference contentStreamReference,
|
||||||
|
PDFObjectReference resourcesReference,
|
||||||
|
PDFObject oldResources);
|
||||||
|
|
||||||
PDFDocumentBuilder* m_documentBuilder;
|
PDFDocumentBuilder* m_documentBuilder;
|
||||||
PDFContentStreamBuilder* m_contentStreamBuilder;
|
PDFContentStreamBuilder* m_contentStreamBuilder;
|
||||||
PDFObjectReference m_pageReference;
|
PDFObjectReference m_pageReference;
|
||||||
|
PDFContentStreamBuilder::CoordinateSystem m_coordinateSystem;
|
||||||
|
Mode m_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PDF4QTLIBSHARED_EXPORT PDFDocumentBuilder
|
class PDF4QTLIBSHARED_EXPORT PDFDocumentBuilder
|
||||||
|
@ -328,6 +351,11 @@ public:
|
||||||
/// is returned (no exception is thrown).
|
/// is returned (no exception is thrown).
|
||||||
const PDFObject& getObjectByReference(PDFObjectReference reference) const;
|
const PDFObject& getObjectByReference(PDFObjectReference reference) const;
|
||||||
|
|
||||||
|
/// Returns the decoded stream. If stream data cannot be decoded,
|
||||||
|
/// then empty byte array is returned.
|
||||||
|
/// \param stream Stream to be decoded
|
||||||
|
QByteArray getDecodedStream(const PDFStream* stream) const;
|
||||||
|
|
||||||
/// Returns annotation bounding rectangle
|
/// Returns annotation bounding rectangle
|
||||||
std::array<PDFReal, 4> getAnnotationReductionRectangle(const QRectF& boundingRect, const QRectF& innerRect) const;
|
std::array<PDFReal, 4> getAnnotationReductionRectangle(const QRectF& boundingRect, const QRectF& innerRect) const;
|
||||||
|
|
||||||
|
@ -446,6 +474,11 @@ public:
|
||||||
PDFObjectReference appendPage(QRectF mediaBox);
|
PDFObjectReference appendPage(QRectF mediaBox);
|
||||||
|
|
||||||
|
|
||||||
|
/// Creates AcroForm dictionary. Erases XFA form if present.
|
||||||
|
/// \param fields Fields
|
||||||
|
PDFObjectReference createAcroForm(PDFObjectReferenceVector fields);
|
||||||
|
|
||||||
|
|
||||||
/// Creates GoTo action. This action changes view to a specific destination in the same document.
|
/// Creates GoTo action. This action changes view to a specific destination in the same document.
|
||||||
/// \param destination Destination
|
/// \param destination Destination
|
||||||
PDFObjectReference createActionGoTo(PDFDestination destination);
|
PDFObjectReference createActionGoTo(PDFDestination destination);
|
||||||
|
@ -662,36 +695,6 @@ public:
|
||||||
QString description);
|
QString description);
|
||||||
|
|
||||||
|
|
||||||
/// Free text annotation displays text directly on a page. Text appears directly on the page, in the
|
|
||||||
/// same way, as standard text in PDF document. Free text annotations are usually used to comment
|
|
||||||
/// the document. Free text annotation can also have callout line, with, or without a knee. Specify
|
|
||||||
/// start/end point parameters of this function to get callout line.
|
|
||||||
/// \param page Page to which is annotation added
|
|
||||||
/// \param boundingRectangle Bounding rectangle of free text annotation. It must contain both
|
|
||||||
/// callout line and text rectangle.
|
|
||||||
/// \param textRectangle Rectangle with text, in absolute coordinates. They are then recomputed to
|
|
||||||
/// match bounding rectangle.
|
|
||||||
/// \param title Title
|
|
||||||
/// \param subject Subject
|
|
||||||
/// \param contents Contents (text displayed)
|
|
||||||
/// \param textAlignment Text alignment. Only horizontal alignment flags are valid.
|
|
||||||
/// \param startPoint Start point of callout line
|
|
||||||
/// \param endPoint End point of callout line
|
|
||||||
/// \param startLineType Line ending at the start point
|
|
||||||
/// \param endLineType Line ending at the end point
|
|
||||||
PDFObjectReference createAnnotationFreeText(PDFObjectReference page,
|
|
||||||
QRectF boundingRectangle,
|
|
||||||
QRectF textRectangle,
|
|
||||||
QString title,
|
|
||||||
QString subject,
|
|
||||||
QString contents,
|
|
||||||
TextAlignment textAlignment,
|
|
||||||
QPointF startPoint,
|
|
||||||
QPointF endPoint,
|
|
||||||
AnnotationLineEnding startLineType,
|
|
||||||
AnnotationLineEnding endLineType);
|
|
||||||
|
|
||||||
|
|
||||||
/// Free text annotation displays text directly on a page. Text appears directly on the page, in the
|
/// Free text annotation displays text directly on a page. Text appears directly on the page, in the
|
||||||
/// same way, as standard text in PDF document. Free text annotations are usually used to comment
|
/// same way, as standard text in PDF document. Free text annotations are usually used to comment
|
||||||
/// the document. Free text annotation can also have callout line, with, or without a knee. Specify
|
/// the document. Free text annotation can also have callout line, with, or without a knee. Specify
|
||||||
|
@ -741,6 +744,36 @@ public:
|
||||||
TextAlignment textAlignment);
|
TextAlignment textAlignment);
|
||||||
|
|
||||||
|
|
||||||
|
/// Free text annotation displays text directly on a page. Text appears directly on the page, in the
|
||||||
|
/// same way, as standard text in PDF document. Free text annotations are usually used to comment
|
||||||
|
/// the document. Free text annotation can also have callout line, with, or without a knee. Specify
|
||||||
|
/// start/end point parameters of this function to get callout line.
|
||||||
|
/// \param page Page to which is annotation added
|
||||||
|
/// \param boundingRectangle Bounding rectangle of free text annotation. It must contain both
|
||||||
|
/// callout line and text rectangle.
|
||||||
|
/// \param textRectangle Rectangle with text, in absolute coordinates. They are then recomputed to
|
||||||
|
/// match bounding rectangle.
|
||||||
|
/// \param title Title
|
||||||
|
/// \param subject Subject
|
||||||
|
/// \param contents Contents (text displayed)
|
||||||
|
/// \param textAlignment Text alignment. Only horizontal alignment flags are valid.
|
||||||
|
/// \param startPoint Start point of callout line
|
||||||
|
/// \param endPoint End point of callout line
|
||||||
|
/// \param startLineType Line ending at the start point
|
||||||
|
/// \param endLineType Line ending at the end point
|
||||||
|
PDFObjectReference createAnnotationFreeText(PDFObjectReference page,
|
||||||
|
QRectF boundingRectangle,
|
||||||
|
QRectF textRectangle,
|
||||||
|
QString title,
|
||||||
|
QString subject,
|
||||||
|
QString contents,
|
||||||
|
TextAlignment textAlignment,
|
||||||
|
QPointF startPoint,
|
||||||
|
QPointF endPoint,
|
||||||
|
AnnotationLineEnding startLineType,
|
||||||
|
AnnotationLineEnding endLineType);
|
||||||
|
|
||||||
|
|
||||||
/// Text markup annotation is used to highlight text. It is a markup annotation, so it can contain
|
/// Text markup annotation is used to highlight text. It is a markup annotation, so it can contain
|
||||||
/// window to be opened (and commented). This annotation is usually used to highlight text, but can
|
/// window to be opened (and commented). This annotation is usually used to highlight text, but can
|
||||||
/// also highlight other things, such as images, or other graphics.
|
/// also highlight other things, such as images, or other graphics.
|
||||||
|
@ -1024,6 +1057,16 @@ public:
|
||||||
QColor color);
|
QColor color);
|
||||||
|
|
||||||
|
|
||||||
|
/// Text markup annotation is used to squiggly underline text. It is a markup annotation, so it can
|
||||||
|
/// contain window to be opened (and commented).
|
||||||
|
/// \param page Page to which is annotation added
|
||||||
|
/// \param quadrilaterals Area in which is markup displayed
|
||||||
|
/// \param color Color
|
||||||
|
PDFObjectReference createAnnotationSquiggly(PDFObjectReference page,
|
||||||
|
QPolygonF quadrilaterals,
|
||||||
|
QColor color);
|
||||||
|
|
||||||
|
|
||||||
/// Text markup annotation is used to squiggly underline text. It is a markup annotation, so it can
|
/// Text markup annotation is used to squiggly underline text. It is a markup annotation, so it can
|
||||||
/// contain window to be opened (and commented).
|
/// contain window to be opened (and commented).
|
||||||
/// \param page Page to which is annotation added
|
/// \param page Page to which is annotation added
|
||||||
|
@ -1040,16 +1083,6 @@ public:
|
||||||
QString contents);
|
QString contents);
|
||||||
|
|
||||||
|
|
||||||
/// Text markup annotation is used to squiggly underline text. It is a markup annotation, so it can
|
|
||||||
/// contain window to be opened (and commented).
|
|
||||||
/// \param page Page to which is annotation added
|
|
||||||
/// \param quadrilaterals Area in which is markup displayed
|
|
||||||
/// \param color Color
|
|
||||||
PDFObjectReference createAnnotationSquiggly(PDFObjectReference page,
|
|
||||||
QPolygonF quadrilaterals,
|
|
||||||
QColor color);
|
|
||||||
|
|
||||||
|
|
||||||
/// Stamp annotation
|
/// Stamp annotation
|
||||||
/// \param page Page to which is annotation added
|
/// \param page Page to which is annotation added
|
||||||
/// \param rectangle Stamp area
|
/// \param rectangle Stamp area
|
||||||
|
@ -1122,22 +1155,6 @@ public:
|
||||||
bool open);
|
bool open);
|
||||||
|
|
||||||
|
|
||||||
/// Text markup annotation is used to underline text. It is a markup annotation, so it can contain
|
|
||||||
/// window to be opened (and commented).
|
|
||||||
/// \param page Page to which is annotation added
|
|
||||||
/// \param rectangle Area in which is markup displayed
|
|
||||||
/// \param color Color
|
|
||||||
/// \param title Title
|
|
||||||
/// \param subject Subject
|
|
||||||
/// \param contents Contents
|
|
||||||
PDFObjectReference createAnnotationUnderline(PDFObjectReference page,
|
|
||||||
QRectF rectangle,
|
|
||||||
QColor color,
|
|
||||||
QString title,
|
|
||||||
QString subject,
|
|
||||||
QString contents);
|
|
||||||
|
|
||||||
|
|
||||||
/// Text markup annotation is used to underline text. It is a markup annotation, so it can contain
|
/// Text markup annotation is used to underline text. It is a markup annotation, so it can contain
|
||||||
/// window to be opened (and commented).
|
/// window to be opened (and commented).
|
||||||
/// \param page Page to which is annotation added
|
/// \param page Page to which is annotation added
|
||||||
|
@ -1158,6 +1175,22 @@ public:
|
||||||
QColor color);
|
QColor color);
|
||||||
|
|
||||||
|
|
||||||
|
/// Text markup annotation is used to underline text. It is a markup annotation, so it can contain
|
||||||
|
/// window to be opened (and commented).
|
||||||
|
/// \param page Page to which is annotation added
|
||||||
|
/// \param rectangle Area in which is markup displayed
|
||||||
|
/// \param color Color
|
||||||
|
/// \param title Title
|
||||||
|
/// \param subject Subject
|
||||||
|
/// \param contents Contents
|
||||||
|
PDFObjectReference createAnnotationUnderline(PDFObjectReference page,
|
||||||
|
QRectF rectangle,
|
||||||
|
QColor color,
|
||||||
|
QString title,
|
||||||
|
QString subject,
|
||||||
|
QString contents);
|
||||||
|
|
||||||
|
|
||||||
/// Creates empty catalog. This function is used, when a new document is being created. Do not call
|
/// Creates empty catalog. This function is used, when a new document is being created. Do not call
|
||||||
/// this function manually.
|
/// this function manually.
|
||||||
PDFObjectReference createCatalog();
|
PDFObjectReference createCatalog();
|
||||||
|
@ -1193,6 +1226,48 @@ public:
|
||||||
PDFObjectReference createFileSpecification(QString fileName);
|
PDFObjectReference createFileSpecification(QString fileName);
|
||||||
|
|
||||||
|
|
||||||
|
/// Creates form field of type signature.
|
||||||
|
/// \param fieldName Field name
|
||||||
|
/// \param kids Kids of the signature field.
|
||||||
|
/// \param signatureValue Signature value
|
||||||
|
PDFObjectReference createFormFieldSignature(QString fieldName,
|
||||||
|
PDFObjectReferenceVector kids,
|
||||||
|
PDFObjectReference signatureValue);
|
||||||
|
|
||||||
|
|
||||||
|
/// Creates visible form field widget without contents.
|
||||||
|
/// \param formField Form field reference
|
||||||
|
/// \param page Page reference
|
||||||
|
/// \param appearanceStream Appearance stream
|
||||||
|
/// \param rect Widget rectangle
|
||||||
|
void createFormFieldWidget(PDFObjectReference formField,
|
||||||
|
PDFObjectReference page,
|
||||||
|
PDFObjectReference appearanceStream,
|
||||||
|
QRectF rect);
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param formField Form field reference
|
||||||
|
/// \param page Page reference
|
||||||
|
void createInvisibleFormFieldWidget(PDFObjectReference formField,
|
||||||
|
PDFObjectReference page);
|
||||||
|
|
||||||
|
|
||||||
|
/// Creates signature dictionary used for preparation in signing process. Can define parameters of the
|
||||||
|
/// signature.
|
||||||
|
/// \param filter Filter (for example, Adobe.PPKLite, Entrust.PPKEF, CiCi.SignIt, ...)
|
||||||
|
/// \param subfilter Subfilter (for example, adbe.pkcs7.detached, adbe.pkcs7.sha1,
|
||||||
|
/// ETSI.CAdES.detached, ...)
|
||||||
|
/// \param contents Contents (reserved data for signature).
|
||||||
|
/// \param signingTime Signing date/time
|
||||||
|
/// \param byteRangeItem Item which will fill byte range array.
|
||||||
|
PDFObjectReference createSignatureDictionary(QByteArray filter,
|
||||||
|
QByteArray subfilter,
|
||||||
|
QByteArray contents,
|
||||||
|
QDateTime signingTime,
|
||||||
|
PDFInteger byteRangeItem);
|
||||||
|
|
||||||
|
|
||||||
/// This function is used to create a new trailer dictionary, when blank document is created. Do not
|
/// This function is used to create a new trailer dictionary, when blank document is created. Do not
|
||||||
/// call this function manually.
|
/// call this function manually.
|
||||||
/// \param catalog Reference to document catalog
|
/// \param catalog Reference to document catalog
|
||||||
|
@ -1393,6 +1468,11 @@ public:
|
||||||
PDFObject value);
|
PDFObject value);
|
||||||
|
|
||||||
|
|
||||||
|
/// Set document language.
|
||||||
|
/// \param locale Locale, from which is language determined
|
||||||
|
void setLanguage(QLocale locale);
|
||||||
|
|
||||||
|
|
||||||
/// Set document language.
|
/// Set document language.
|
||||||
/// \param language Document language. It should be a language identifier, as defined in ISO 639
|
/// \param language Document language. It should be a language identifier, as defined in ISO 639
|
||||||
/// and ISO 3166. For example, "en-US", where first two letter means language code (en =
|
/// and ISO 3166. For example, "en-US", where first two letter means language code (en =
|
||||||
|
@ -1400,11 +1480,6 @@ public:
|
||||||
void setLanguage(QString language);
|
void setLanguage(QString language);
|
||||||
|
|
||||||
|
|
||||||
/// Set document language.
|
|
||||||
/// \param locale Locale, from which is language determined
|
|
||||||
void setLanguage(QLocale locale);
|
|
||||||
|
|
||||||
|
|
||||||
/// Set document outline.
|
/// Set document outline.
|
||||||
/// \param outline Document outline root
|
/// \param outline Document outline root
|
||||||
void setOutline(PDFObjectReference outline);
|
void setOutline(PDFObjectReference outline);
|
||||||
|
@ -1470,6 +1545,20 @@ public:
|
||||||
PDFReal unit);
|
PDFReal unit);
|
||||||
|
|
||||||
|
|
||||||
|
/// Sets signature contact info field.
|
||||||
|
/// \param signatureDictionary Signature dictionary reference
|
||||||
|
/// \param contactInfoText Contact info text
|
||||||
|
void setSignatureContactInfo(PDFObjectReference signatureDictionary,
|
||||||
|
QString contactInfoText);
|
||||||
|
|
||||||
|
|
||||||
|
/// Sets signature reason field.
|
||||||
|
/// \param signatureDictionary Signature dictionary reference
|
||||||
|
/// \param reasonText Reason text
|
||||||
|
void setSignatureReason(PDFObjectReference signatureDictionary,
|
||||||
|
QString reasonText);
|
||||||
|
|
||||||
|
|
||||||
/// This function is used to update trailer dictionary. Must be called each time the final document is
|
/// This function is used to update trailer dictionary. Must be called each time the final document is
|
||||||
/// being built.
|
/// being built.
|
||||||
/// \param objectCount Number of objects (including empty ones)
|
/// \param objectCount Number of objects (including empty ones)
|
||||||
|
@ -1513,6 +1602,7 @@ public:
|
||||||
PDFModifiedDocument::ModificationFlags getFlags() const { return m_modificationFlags; }
|
PDFModifiedDocument::ModificationFlags getFlags() const { return m_modificationFlags; }
|
||||||
|
|
||||||
void markReset() { m_modificationFlags.setFlag(PDFModifiedDocument::Reset); }
|
void markReset() { m_modificationFlags.setFlag(PDFModifiedDocument::Reset); }
|
||||||
|
void markPageContentsChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::PageContents); }
|
||||||
void markAnnotationsChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::Annotation); }
|
void markAnnotationsChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::Annotation); }
|
||||||
void markFormFieldChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::FormField); }
|
void markFormFieldChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::FormField); }
|
||||||
void markXFAPagination() { m_modificationFlags.setFlag(PDFModifiedDocument::XFA_Pagination); }
|
void markXFAPagination() { m_modificationFlags.setFlag(PDFModifiedDocument::XFA_Pagination); }
|
||||||
|
|
|
@ -192,7 +192,10 @@ PDFOperationResult PDFDocumentWriter::write(const QString& fileName, const PDFDo
|
||||||
PDFOperationResult result = write(&file, document);
|
PDFOperationResult result = write(&file, document);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
file.commit();
|
if (!file.commit())
|
||||||
|
{
|
||||||
|
return tr("File '%1' can't be opened for writing. %2").arg(fileName, file.errorString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -488,8 +488,8 @@ void PDFDrawWidgetProxy::setDocument(const PDFModifiedDocument& document)
|
||||||
if (getDocument() != document)
|
if (getDocument() != document)
|
||||||
{
|
{
|
||||||
m_cacheClearTimer->stop();
|
m_cacheClearTimer->stop();
|
||||||
m_compiler->stop(document.hasReset());
|
m_compiler->stop(document.hasReset() || document.hasPageContentsChanged());
|
||||||
m_textLayoutCompiler->stop(document.hasReset());
|
m_textLayoutCompiler->stop(document.hasReset() || document.hasPageContentsChanged());
|
||||||
m_controller->setDocument(document);
|
m_controller->setDocument(document);
|
||||||
|
|
||||||
if (PDFOptionalContentActivity* optionalContentActivity = document.getOptionalContentActivity())
|
if (PDFOptionalContentActivity* optionalContentActivity = document.getOptionalContentActivity())
|
||||||
|
|
|
@ -1836,7 +1836,7 @@ void PDFFontCache::setDocument(const PDFModifiedDocument& document)
|
||||||
|
|
||||||
// Jakub Melka: If document has not reset flag, then fonts of the
|
// Jakub Melka: If document has not reset flag, then fonts of the
|
||||||
// document remains the same. So it is not needed to clear font cache.
|
// document remains the same. So it is not needed to clear font cache.
|
||||||
if (document.hasReset())
|
if (document.hasReset() || document.hasPageContentsChanged())
|
||||||
{
|
{
|
||||||
m_fontCache.clear();
|
m_fontCache.clear();
|
||||||
m_realizedFontCache.clear();
|
m_realizedFontCache.clear();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2020-2021 Jakub Melka
|
// Copyright (C) 2020-2022 Jakub Melka
|
||||||
//
|
//
|
||||||
// This file is part of PDF4QT.
|
// This file is part of PDF4QT.
|
||||||
//
|
//
|
||||||
|
|
|
@ -738,7 +738,7 @@ void PDFThumbnailsItemModel::setDocument(const PDFModifiedDocument& document)
|
||||||
{
|
{
|
||||||
if (m_document != document)
|
if (m_document != document)
|
||||||
{
|
{
|
||||||
if (document.hasReset() || document.hasFlag(PDFModifiedDocument::Annotation))
|
if (document.hasReset() || document.hasPageContentsChanged() || document.hasFlag(PDFModifiedDocument::Annotation))
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_thumbnailCache.clear();
|
m_thumbnailCache.clear();
|
||||||
|
|
|
@ -0,0 +1,548 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "pdfpagecontenteditorstylesettings.h"
|
||||||
|
#include "ui_pdfpagecontenteditorstylesettings.h"
|
||||||
|
|
||||||
|
#include "pdfwidgetutils.h"
|
||||||
|
#include "pdfpagecontentelements.h"
|
||||||
|
|
||||||
|
#include <QFontDialog>
|
||||||
|
#include <QColorDialog>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QTextEdit>
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
PDFPageContentEditorStyleSettings::PDFPageContentEditorStyleSettings(QWidget* parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
ui(new Ui::PDFPageContentEditorStyleSettings)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
for (QString colorName : QColor::colorNames())
|
||||||
|
{
|
||||||
|
QColor color(colorName);
|
||||||
|
QIcon icon = getIconForColor(color);
|
||||||
|
|
||||||
|
ui->penColorCombo->addItem(icon, colorName, color);
|
||||||
|
ui->brushColorCombo->addItem(icon, colorName, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->penStyleCombo->addItem(tr("None"), int(Qt::NoPen));
|
||||||
|
ui->penStyleCombo->addItem(tr("Solid"), int(Qt::SolidLine));
|
||||||
|
ui->penStyleCombo->addItem(tr("Dashed"), int(Qt::DashLine));
|
||||||
|
ui->penStyleCombo->addItem(tr("Dotted"), int(Qt::DotLine));
|
||||||
|
ui->penStyleCombo->addItem(tr("Dash-dot"), int(Qt::DashDotLine));
|
||||||
|
ui->penStyleCombo->addItem(tr("Dash-dot-dot"), int(Qt::DashDotDotLine));
|
||||||
|
|
||||||
|
ui->brushStyleCombo->addItem(tr("None"), int(Qt::NoBrush));
|
||||||
|
ui->brushStyleCombo->addItem(tr("Solid"), int(Qt::SolidPattern));
|
||||||
|
ui->brushStyleCombo->addItem(tr("Horizontal"), int(Qt::HorPattern));
|
||||||
|
ui->brushStyleCombo->addItem(tr("Vertical"), int(Qt::VerPattern));
|
||||||
|
ui->brushStyleCombo->addItem(tr("B-Diagonal"), int(Qt::BDiagPattern));
|
||||||
|
ui->brushStyleCombo->addItem(tr("F-Diagonal"), int(Qt::FDiagPattern));
|
||||||
|
ui->brushStyleCombo->addItem(tr("Cross"), int(Qt::CrossPattern));
|
||||||
|
|
||||||
|
connect(ui->fontComboBox, &QFontComboBox::currentFontChanged, this, &PDFPageContentEditorStyleSettings::onFontChanged);
|
||||||
|
connect(ui->selectPenColorButton, &QToolButton::clicked, this, &PDFPageContentEditorStyleSettings::onSelectPenColorButtonClicked);
|
||||||
|
connect(ui->selectBrushColorButton, &QToolButton::clicked, this, &PDFPageContentEditorStyleSettings::onSelectBrushColorButtonClicked);
|
||||||
|
connect(ui->selectFontButton, &QToolButton::clicked, this, &PDFPageContentEditorStyleSettings::onSelectFontButtonClicked);
|
||||||
|
connect(ui->penWidthEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &PDFPageContentEditorStyleSettings::onPenWidthChanged);
|
||||||
|
connect(ui->penStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorStyleSettings::onPenStyleChanged);
|
||||||
|
connect(ui->brushStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorStyleSettings::onBrushStyleChanged);
|
||||||
|
connect(ui->textAngleEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &PDFPageContentEditorStyleSettings::onTextAngleChanged);
|
||||||
|
connect(ui->penColorCombo->lineEdit(), &QLineEdit::editingFinished, this, &PDFPageContentEditorStyleSettings::onPenColorComboTextChanged);
|
||||||
|
connect(ui->penColorCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorStyleSettings::onPenColorComboIndexChanged);
|
||||||
|
connect(ui->brushColorCombo->lineEdit(), &QLineEdit::editingFinished, this, &PDFPageContentEditorStyleSettings::onBrushColorComboTextChanged);
|
||||||
|
connect(ui->brushColorCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorStyleSettings::onBrushColorComboIndexChanged);
|
||||||
|
|
||||||
|
m_alignmentMapper.setMapping(ui->al11Button, int(Qt::AlignLeft | Qt::AlignTop));
|
||||||
|
m_alignmentMapper.setMapping(ui->al12Button, int(Qt::AlignHCenter | Qt::AlignTop));
|
||||||
|
m_alignmentMapper.setMapping(ui->al13Button, int(Qt::AlignRight | Qt::AlignTop));
|
||||||
|
m_alignmentMapper.setMapping(ui->al21Button, int(Qt::AlignLeft | Qt::AlignVCenter));
|
||||||
|
m_alignmentMapper.setMapping(ui->al22Button, int(Qt::AlignCenter));
|
||||||
|
m_alignmentMapper.setMapping(ui->al23Button, int(Qt::AlignRight | Qt::AlignVCenter));
|
||||||
|
m_alignmentMapper.setMapping(ui->al31Button, int(Qt::AlignLeft | Qt::AlignBottom));
|
||||||
|
m_alignmentMapper.setMapping(ui->al32Button, int(Qt::AlignHCenter | Qt::AlignBottom));
|
||||||
|
m_alignmentMapper.setMapping(ui->al33Button, int(Qt::AlignRight | Qt::AlignBottom));
|
||||||
|
|
||||||
|
for (QRadioButton* radioButton : findChildren<QRadioButton*>())
|
||||||
|
{
|
||||||
|
connect(radioButton, &QRadioButton::clicked, &m_alignmentMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
}
|
||||||
|
connect(&m_alignmentMapper, &QSignalMapper::mappedInt, this, &PDFPageContentEditorStyleSettings::onAlignmentRadioButtonClicked);
|
||||||
|
|
||||||
|
loadFromElement(nullptr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFPageContentEditorStyleSettings::~PDFPageContentEditorStyleSettings()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::loadFromElement(const PDFPageContentElement* element, bool forceUpdate)
|
||||||
|
{
|
||||||
|
const PDFPageContentStyledElement* styledElement = dynamic_cast<const PDFPageContentStyledElement*>(element);
|
||||||
|
const PDFPageContentElementTextBox* textElement = dynamic_cast<const PDFPageContentElementTextBox*>(element);
|
||||||
|
|
||||||
|
StyleFeatures features = None;
|
||||||
|
|
||||||
|
if (styledElement)
|
||||||
|
{
|
||||||
|
features.setFlag(Pen);
|
||||||
|
features.setFlag(PenColor);
|
||||||
|
features.setFlag(Brush);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textElement)
|
||||||
|
{
|
||||||
|
features.setFlag(PenColor);
|
||||||
|
features.setFlag(Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool hasPen = features.testFlag(Pen);
|
||||||
|
const bool hasPenColor = features.testFlag(PenColor);
|
||||||
|
const bool hasBrush = features.testFlag(Brush);
|
||||||
|
const bool hasText = features.testFlag(Text);
|
||||||
|
|
||||||
|
ui->penWidthEdit->setEnabled(hasPen);
|
||||||
|
ui->penWidthLabel->setEnabled(hasPen);
|
||||||
|
|
||||||
|
ui->penStyleCombo->setEnabled(hasPen);
|
||||||
|
ui->penStyleLabel->setEnabled(hasPen);
|
||||||
|
|
||||||
|
ui->penColorCombo->setEnabled(hasPenColor);
|
||||||
|
ui->penColorLabel->setEnabled(hasPenColor);
|
||||||
|
ui->selectPenColorButton->setEnabled(hasPenColor);
|
||||||
|
|
||||||
|
ui->brushStyleLabel->setEnabled(hasBrush);
|
||||||
|
ui->brushStyleCombo->setEnabled(hasBrush);
|
||||||
|
|
||||||
|
ui->brushColorCombo->setEnabled(hasBrush);
|
||||||
|
ui->brushColorLabel->setEnabled(hasBrush);
|
||||||
|
ui->selectBrushColorButton->setEnabled(hasBrush);
|
||||||
|
|
||||||
|
ui->fontComboBox->setEnabled(hasText);
|
||||||
|
ui->fontLabel->setEnabled(hasText);
|
||||||
|
ui->selectFontButton->setEnabled(hasText);
|
||||||
|
|
||||||
|
for (QRadioButton* radioButton : findChildren<QRadioButton*>())
|
||||||
|
{
|
||||||
|
radioButton->setEnabled(hasText);
|
||||||
|
}
|
||||||
|
ui->textAlignmentLabel->setEnabled(hasText);
|
||||||
|
|
||||||
|
ui->textAngleLabel->setEnabled(hasText);
|
||||||
|
ui->textAngleEdit->setEnabled(hasText);
|
||||||
|
|
||||||
|
QPen pen(Qt::SolidLine);
|
||||||
|
QBrush brush(Qt::transparent);
|
||||||
|
QFont font = QGuiApplication::font();
|
||||||
|
Qt::Alignment alignment = Qt::AlignCenter;
|
||||||
|
PDFReal textAngle = 0.0;
|
||||||
|
|
||||||
|
if (styledElement)
|
||||||
|
{
|
||||||
|
pen = styledElement->getPen();
|
||||||
|
brush = styledElement->getBrush();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textElement)
|
||||||
|
{
|
||||||
|
font = textElement->getFont();
|
||||||
|
alignment = textElement->getAlignment();
|
||||||
|
textAngle = textElement->getAngle();
|
||||||
|
}
|
||||||
|
|
||||||
|
setPen(pen, forceUpdate);
|
||||||
|
setBrush(brush, forceUpdate);
|
||||||
|
setFont(font, forceUpdate);
|
||||||
|
setFontAlignment(alignment, forceUpdate);
|
||||||
|
setTextAngle(textAngle, forceUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::setPen(const QPen& pen, bool forceUpdate)
|
||||||
|
{
|
||||||
|
if (m_pen != pen || forceUpdate)
|
||||||
|
{
|
||||||
|
const bool oldBlockSignals = blockSignals(true);
|
||||||
|
|
||||||
|
m_pen = pen;
|
||||||
|
ui->penWidthEdit->setValue(pen.widthF());
|
||||||
|
ui->penStyleCombo->setCurrentIndex(ui->penStyleCombo->findData(int(pen.style())));
|
||||||
|
setColorToComboBox(ui->penColorCombo, pen.color());
|
||||||
|
|
||||||
|
blockSignals(oldBlockSignals);
|
||||||
|
emit penChanged(m_pen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::setBrush(const QBrush& brush, bool forceUpdate)
|
||||||
|
{
|
||||||
|
if (m_brush != brush || forceUpdate)
|
||||||
|
{
|
||||||
|
const bool oldBlockSignals = blockSignals(true);
|
||||||
|
|
||||||
|
m_brush = brush;
|
||||||
|
ui->brushStyleCombo->setCurrentIndex(ui->brushStyleCombo->findData(int(brush.style())));
|
||||||
|
setColorToComboBox(ui->brushColorCombo, brush.color());
|
||||||
|
|
||||||
|
blockSignals(oldBlockSignals);
|
||||||
|
emit brushChanged(m_brush);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::setFont(const QFont& font, bool forceUpdate)
|
||||||
|
{
|
||||||
|
if (m_font != font || forceUpdate)
|
||||||
|
{
|
||||||
|
const bool oldBlockSignals = blockSignals(true);
|
||||||
|
|
||||||
|
m_font = font;
|
||||||
|
ui->fontComboBox->setCurrentFont(m_font);
|
||||||
|
|
||||||
|
blockSignals(oldBlockSignals);
|
||||||
|
emit fontChanged(m_font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::setFontAlignment(Qt::Alignment alignment, bool forceUpdate)
|
||||||
|
{
|
||||||
|
if (m_alignment != alignment || forceUpdate)
|
||||||
|
{
|
||||||
|
const bool oldBlockSignals = blockSignals(true);
|
||||||
|
|
||||||
|
for (QRadioButton* radioButton : findChildren<QRadioButton*>())
|
||||||
|
{
|
||||||
|
radioButton->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_alignment = alignment;
|
||||||
|
QRadioButton* radioButton = qobject_cast<QRadioButton*>(m_alignmentMapper.mapping(int(alignment)));
|
||||||
|
radioButton->setChecked(true);
|
||||||
|
|
||||||
|
blockSignals(oldBlockSignals);
|
||||||
|
emit alignmentChanged(m_alignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::setTextAngle(PDFReal angle, bool forceUpdate)
|
||||||
|
{
|
||||||
|
if (ui->textAngleEdit->value() != angle || forceUpdate)
|
||||||
|
{
|
||||||
|
const bool oldBlockSignals = blockSignals(true);
|
||||||
|
ui->textAngleEdit->setValue(angle);
|
||||||
|
blockSignals(oldBlockSignals);
|
||||||
|
emit textAngleChanged(ui->textAngleEdit->value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PDFPageContentEditorStyleSettings::showEditElementStyleDialog(QWidget* parent,
|
||||||
|
PDFPageContentElement* element)
|
||||||
|
{
|
||||||
|
QDialog dialog(parent);
|
||||||
|
dialog.setWindowTitle(tr("Edit Item"));
|
||||||
|
dialog.setLayout(new QVBoxLayout());
|
||||||
|
|
||||||
|
QTextEdit* textEdit = nullptr;
|
||||||
|
PDFPageContentStyledElement* styledElement = dynamic_cast<PDFPageContentStyledElement*>(element);
|
||||||
|
PDFPageContentElementTextBox* textElement = dynamic_cast<PDFPageContentElementTextBox*>(element);
|
||||||
|
if (textElement)
|
||||||
|
{
|
||||||
|
QGroupBox* contentGroupBox = new QGroupBox(&dialog);
|
||||||
|
textEdit = new QTextEdit(textElement->getText(), contentGroupBox);
|
||||||
|
textEdit->setFont(textElement->getFont());
|
||||||
|
textEdit->setAlignment(textElement->getAlignment());
|
||||||
|
textEdit->setTextColor(textElement->getPen().color());
|
||||||
|
contentGroupBox->setTitle(tr("Content"));
|
||||||
|
contentGroupBox->setLayout(new QVBoxLayout());
|
||||||
|
contentGroupBox->layout()->addWidget(textEdit);
|
||||||
|
dialog.layout()->addWidget(contentGroupBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFPageContentEditorStyleSettings* appearanceWidget = new PDFPageContentEditorStyleSettings(&dialog);
|
||||||
|
appearanceWidget->loadFromElement(element, true);
|
||||||
|
if (textEdit)
|
||||||
|
{
|
||||||
|
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::alignmentChanged, textEdit, &QTextEdit::setAlignment);
|
||||||
|
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::fontChanged, textEdit, &QTextEdit::setFont);
|
||||||
|
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::penChanged, textEdit, [textEdit](const QPen& pen) { textEdit->setTextColor(pen.color()); });
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox* appearanceGroupBox = new QGroupBox(&dialog);
|
||||||
|
appearanceGroupBox->setTitle(tr("Appearance"));
|
||||||
|
appearanceGroupBox->setLayout(new QVBoxLayout());
|
||||||
|
appearanceGroupBox->layout()->addWidget(appearanceWidget);
|
||||||
|
dialog.layout()->addWidget(appearanceGroupBox);
|
||||||
|
|
||||||
|
QDialogButtonBox* dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
|
||||||
|
connect(dialogButtonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||||
|
connect(dialogButtonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||||
|
dialog.layout()->addWidget(dialogButtonBox);
|
||||||
|
|
||||||
|
if (dialog.exec() == QDialog::Accepted)
|
||||||
|
{
|
||||||
|
if (styledElement)
|
||||||
|
{
|
||||||
|
styledElement->setPen(appearanceWidget->getPen());
|
||||||
|
styledElement->setBrush(appearanceWidget->getBrush());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textElement)
|
||||||
|
{
|
||||||
|
textElement->setText(textEdit->toPlainText());
|
||||||
|
textElement->setFont(appearanceWidget->getFont());
|
||||||
|
textElement->setAlignment(appearanceWidget->getAlignment());
|
||||||
|
textElement->setAngle(appearanceWidget->getTextAngle());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon PDFPageContentEditorStyleSettings::getIconForColor(QColor color) const
|
||||||
|
{
|
||||||
|
QIcon icon;
|
||||||
|
|
||||||
|
QSize iconSize = PDFWidgetUtils::scaleDPI(this, QSize(16, 16));
|
||||||
|
|
||||||
|
QPixmap pixmap(iconSize.width(), iconSize.height());
|
||||||
|
pixmap.fill(color);
|
||||||
|
icon.addPixmap(pixmap);
|
||||||
|
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::setColorToComboBox(QComboBox* comboBox, QColor color)
|
||||||
|
{
|
||||||
|
if (!color.isValid())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString name = color.name(QColor::HexArgb);
|
||||||
|
|
||||||
|
int index = comboBox->findData(color, Qt::UserRole, Qt::MatchExactly);
|
||||||
|
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
// Jakub Melka: try to find text (color name)
|
||||||
|
index = comboBox->findText(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
comboBox->setCurrentIndex(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
comboBox->addItem(getIconForColor(color), name, color);
|
||||||
|
comboBox->setCurrentIndex(comboBox->count() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onSelectFontButtonClicked()
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
QFont font = QFontDialog::getFont(&ok, m_font, this, tr("Select Font"));
|
||||||
|
|
||||||
|
if (ok && m_font != font)
|
||||||
|
{
|
||||||
|
m_font = font;
|
||||||
|
ui->fontComboBox->setCurrentFont(m_font);
|
||||||
|
emit fontChanged(m_font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::setPenColor(QColor color)
|
||||||
|
{
|
||||||
|
if (color.isValid() && m_pen.color() != color)
|
||||||
|
{
|
||||||
|
m_pen.setColor(color);
|
||||||
|
setColorToComboBox(ui->penColorCombo, color);
|
||||||
|
emit penChanged(m_pen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onSelectPenColorButtonClicked()
|
||||||
|
{
|
||||||
|
QColor color = QColorDialog::getColor(m_pen.color(), this, tr("Select Color for Pen"), QColorDialog::ShowAlphaChannel);
|
||||||
|
setPenColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::setBrushColor(QColor color)
|
||||||
|
{
|
||||||
|
if (color.isValid() && m_brush.color() != color)
|
||||||
|
{
|
||||||
|
m_brush.setColor(color);
|
||||||
|
setColorToComboBox(ui->brushColorCombo, color);
|
||||||
|
emit brushChanged(m_brush);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::Alignment PDFPageContentEditorStyleSettings::getAlignment() const
|
||||||
|
{
|
||||||
|
return m_alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFReal PDFPageContentEditorStyleSettings::getTextAngle() const
|
||||||
|
{
|
||||||
|
return ui->textAngleEdit->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QFont& PDFPageContentEditorStyleSettings::getFont() const
|
||||||
|
{
|
||||||
|
return m_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QBrush& PDFPageContentEditorStyleSettings::getBrush() const
|
||||||
|
{
|
||||||
|
return m_brush;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPen& PDFPageContentEditorStyleSettings::getPen() const
|
||||||
|
{
|
||||||
|
return m_pen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onSelectBrushColorButtonClicked()
|
||||||
|
{
|
||||||
|
QColor color = QColorDialog::getColor(m_pen.color(), this, tr("Select Color for Brush"), QColorDialog::ShowAlphaChannel);
|
||||||
|
setBrushColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onPenWidthChanged(double value)
|
||||||
|
{
|
||||||
|
if (m_pen.widthF() != value)
|
||||||
|
{
|
||||||
|
m_pen.setWidthF(value);
|
||||||
|
emit penChanged(m_pen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onTextAngleChanged(double value)
|
||||||
|
{
|
||||||
|
emit textAngleChanged(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onAlignmentRadioButtonClicked(int alignment)
|
||||||
|
{
|
||||||
|
Qt::Alignment alignmentValue = static_cast<Qt::Alignment>(alignment);
|
||||||
|
if (m_alignment != alignmentValue)
|
||||||
|
{
|
||||||
|
m_alignment = alignmentValue;
|
||||||
|
emit alignmentChanged(m_alignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onPenStyleChanged()
|
||||||
|
{
|
||||||
|
Qt::PenStyle penStyle = static_cast<Qt::PenStyle>(ui->penStyleCombo->currentData().toInt());
|
||||||
|
if (m_pen.style() != penStyle)
|
||||||
|
{
|
||||||
|
m_pen.setStyle(penStyle);
|
||||||
|
emit penChanged(m_pen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onBrushStyleChanged()
|
||||||
|
{
|
||||||
|
Qt::BrushStyle brushStyle = static_cast<Qt::BrushStyle>(ui->brushStyleCombo->currentData().toInt());
|
||||||
|
if (m_brush.style() != brushStyle)
|
||||||
|
{
|
||||||
|
m_brush.setStyle(brushStyle);
|
||||||
|
emit brushChanged(m_brush);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onPenColorComboTextChanged()
|
||||||
|
{
|
||||||
|
QColor color(ui->penColorCombo->currentText());
|
||||||
|
if (color.isValid())
|
||||||
|
{
|
||||||
|
setColorToComboBox(ui->penColorCombo, color);
|
||||||
|
|
||||||
|
if (m_pen.color() != color)
|
||||||
|
{
|
||||||
|
m_pen.setColor(color);
|
||||||
|
emit penChanged(m_pen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ui->penColorCombo->currentIndex() != -1)
|
||||||
|
{
|
||||||
|
ui->penColorCombo->setEditText(ui->penColorCombo->itemText(ui->penColorCombo->currentIndex()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onPenColorComboIndexChanged()
|
||||||
|
{
|
||||||
|
const int index = ui->penColorCombo->currentIndex();
|
||||||
|
QColor color = ui->penColorCombo->itemData(index, Qt::UserRole).value<QColor>();
|
||||||
|
if (color.isValid() && m_pen.color() != color)
|
||||||
|
{
|
||||||
|
m_pen.setColor(color);
|
||||||
|
emit penChanged(m_pen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onBrushColorComboTextChanged()
|
||||||
|
{
|
||||||
|
QColor color(ui->brushColorCombo->currentText());
|
||||||
|
if (color.isValid())
|
||||||
|
{
|
||||||
|
setColorToComboBox(ui->brushColorCombo, color);
|
||||||
|
|
||||||
|
if (m_brush.color() != color)
|
||||||
|
{
|
||||||
|
m_brush.setColor(color);
|
||||||
|
emit brushChanged(m_brush);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ui->brushColorCombo->currentIndex() != -1)
|
||||||
|
{
|
||||||
|
ui->brushColorCombo->setEditText(ui->brushColorCombo->itemText(ui->brushColorCombo->currentIndex()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onBrushColorComboIndexChanged()
|
||||||
|
{
|
||||||
|
const int index = ui->brushColorCombo->currentIndex();
|
||||||
|
QColor color = ui->brushColorCombo->itemData(index, Qt::UserRole).value<QColor>();
|
||||||
|
if (color.isValid() && m_brush.color() != color)
|
||||||
|
{
|
||||||
|
m_brush.setColor(color);
|
||||||
|
emit brushChanged(m_brush);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorStyleSettings::onFontChanged(const QFont& font)
|
||||||
|
{
|
||||||
|
if (m_font != font)
|
||||||
|
{
|
||||||
|
m_font = font;
|
||||||
|
emit fontChanged(m_font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdf
|
|
@ -0,0 +1,118 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef PDFPAGECONTENTEDITORSTYLESETTINGS_H
|
||||||
|
#define PDFPAGECONTENTEDITORSTYLESETTINGS_H
|
||||||
|
|
||||||
|
#include "pdfglobal.h"
|
||||||
|
|
||||||
|
#include <QPen>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QBrush>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QSignalMapper>
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class PDFPageContentEditorStyleSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QComboBox;
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
class PDFPageContentElement;
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentEditorStyleSettings : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum StyleFeature
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Pen = 1 << 0,
|
||||||
|
PenColor = 1 << 1,
|
||||||
|
Brush = 1 << 2,
|
||||||
|
Text = 1 << 3
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(StyleFeatures, StyleFeature)
|
||||||
|
|
||||||
|
explicit PDFPageContentEditorStyleSettings(QWidget* parent);
|
||||||
|
virtual ~PDFPageContentEditorStyleSettings() override;
|
||||||
|
|
||||||
|
/// Loads data from element, element can be nullptr
|
||||||
|
/// \param element Element
|
||||||
|
void loadFromElement(const PDFPageContentElement* element, bool forceUpdate);
|
||||||
|
|
||||||
|
void setPen(const QPen& pen, bool forceUpdate);
|
||||||
|
void setBrush(const QBrush& brush, bool forceUpdate);
|
||||||
|
void setFont(const QFont& font, bool forceUpdate);
|
||||||
|
void setFontAlignment(Qt::Alignment alignment, bool forceUpdate);
|
||||||
|
void setTextAngle(PDFReal angle, bool forceUpdate);
|
||||||
|
|
||||||
|
static bool showEditElementStyleDialog(QWidget* parent, PDFPageContentElement* element);
|
||||||
|
|
||||||
|
const QPen& getPen() const;
|
||||||
|
const QBrush& getBrush() const;
|
||||||
|
const QFont& getFont() const;
|
||||||
|
Qt::Alignment getAlignment() const;
|
||||||
|
PDFReal getTextAngle() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void penChanged(const QPen& pen);
|
||||||
|
void brushChanged(const QBrush& brush);
|
||||||
|
void fontChanged(const QFont& font);
|
||||||
|
void alignmentChanged(Qt::Alignment alignment);
|
||||||
|
void textAngleChanged(pdf::PDFReal angle);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onSelectFontButtonClicked();
|
||||||
|
void onSelectPenColorButtonClicked();
|
||||||
|
void onSelectBrushColorButtonClicked();
|
||||||
|
void onPenWidthChanged(double value);
|
||||||
|
void onTextAngleChanged(double value);
|
||||||
|
void onAlignmentRadioButtonClicked(int alignment);
|
||||||
|
void onPenStyleChanged();
|
||||||
|
void onBrushStyleChanged();
|
||||||
|
void onPenColorComboTextChanged();
|
||||||
|
void onPenColorComboIndexChanged();
|
||||||
|
void onBrushColorComboTextChanged();
|
||||||
|
void onBrushColorComboIndexChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::PDFPageContentEditorStyleSettings* ui;
|
||||||
|
|
||||||
|
void onFontChanged(const QFont& font);
|
||||||
|
void setColorToComboBox(QComboBox* comboBox, QColor color);
|
||||||
|
QIcon getIconForColor(QColor color) const;
|
||||||
|
|
||||||
|
void setPenColor(QColor color);
|
||||||
|
void setBrushColor(QColor color);
|
||||||
|
|
||||||
|
QPen m_pen;
|
||||||
|
QBrush m_brush;
|
||||||
|
QFont m_font;
|
||||||
|
Qt::Alignment m_alignment = Qt::AlignCenter;
|
||||||
|
QSignalMapper m_alignmentMapper;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdf
|
||||||
|
|
||||||
|
#endif // PDFPAGECONTENTEDITORSTYLESETTINGS_H
|
|
@ -0,0 +1,230 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>PDFPageContentEditorStyleSettings</class>
|
||||||
|
<widget class="QWidget" name="PDFPageContentEditorStyleSettings">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>344</width>
|
||||||
|
<height>310</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Style Settings</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="textAlignmentLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Text Alignment</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="penStyleLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pen Style</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QComboBox" name="brushColorCombo">
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1" colspan="2">
|
||||||
|
<widget class="QComboBox" name="penStyleCombo"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1" colspan="2">
|
||||||
|
<widget class="QDoubleSpinBox" name="penWidthEdit"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="penColorCombo">
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="penWidthLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pen Width</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="brushColorLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Brush Color</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1" colspan="2">
|
||||||
|
<layout class="QGridLayout" name="textAlignmentLayout">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QRadioButton" name="al21Button">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QRadioButton" name="al13Button">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QRadioButton" name="al32Button">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QRadioButton" name="al22Button">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QRadioButton" name="al33Button">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QRadioButton" name="al31Button">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QRadioButton" name="al23Button">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QRadioButton" name="al11Button">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QRadioButton" name="al12Button">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="3">
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1" colspan="2">
|
||||||
|
<widget class="QDoubleSpinBox" name="textAngleEdit">
|
||||||
|
<property name="minimum">
|
||||||
|
<double>-90.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>90.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="2">
|
||||||
|
<widget class="QToolButton" name="selectBrushColorButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="penColorLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pen Color</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="fontLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Font</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QFontComboBox" name="fontComboBox"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="textAngleLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Text Angle</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QToolButton" name="selectPenColorButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="2">
|
||||||
|
<widget class="QToolButton" name="selectFontButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="brushStyleLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Brush Style</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1" colspan="2">
|
||||||
|
<widget class="QComboBox" name="brushStyleCombo"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -0,0 +1,968 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "pdfpagecontenteditortools.h"
|
||||||
|
#include "pdfpagecontentelements.h"
|
||||||
|
#include "pdfpainterutils.h"
|
||||||
|
#include "pdftexteditpseudowidget.h"
|
||||||
|
#include "pdfdrawwidget.h"
|
||||||
|
|
||||||
|
#include <QPen>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QImageReader>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
PDFCreatePCElementTool::PDFCreatePCElementTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
QObject* parent) :
|
||||||
|
PDFWidgetTool(proxy, action, parent),
|
||||||
|
m_scene(scene)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTool::setPen(const QPen& pen)
|
||||||
|
{
|
||||||
|
if (PDFPageContentStyledElement* styledElement = dynamic_cast<PDFPageContentStyledElement*>(getElement()))
|
||||||
|
{
|
||||||
|
styledElement->setPen(pen);
|
||||||
|
emit getProxy()->repaintNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTool::setBrush(const QBrush& brush)
|
||||||
|
{
|
||||||
|
if (PDFPageContentStyledElement* styledElement = dynamic_cast<PDFPageContentStyledElement*>(getElement()))
|
||||||
|
{
|
||||||
|
styledElement->setBrush(brush);
|
||||||
|
emit getProxy()->repaintNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTool::setFont(const QFont& font)
|
||||||
|
{
|
||||||
|
if (PDFPageContentElementTextBox* textBoxElement = dynamic_cast<PDFPageContentElementTextBox*>(getElement()))
|
||||||
|
{
|
||||||
|
textBoxElement->setFont(font);
|
||||||
|
emit getProxy()->repaintNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTool::setAlignment(Qt::Alignment alignment)
|
||||||
|
{
|
||||||
|
if (PDFPageContentElementTextBox* textBoxElement = dynamic_cast<PDFPageContentElementTextBox*>(getElement()))
|
||||||
|
{
|
||||||
|
textBoxElement->setAlignment(alignment);
|
||||||
|
emit getProxy()->repaintNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTool::setTextAngle(PDFReal angle)
|
||||||
|
{
|
||||||
|
if (PDFPageContentElementTextBox* textBoxElement = dynamic_cast<PDFPageContentElementTextBox*>(getElement()))
|
||||||
|
{
|
||||||
|
textBoxElement->setAngle(angle);
|
||||||
|
emit getProxy()->repaintNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF PDFCreatePCElementTool::getRectangleFromPickTool(PDFPickTool* pickTool,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix)
|
||||||
|
{
|
||||||
|
const std::vector<QPointF>& points = pickTool->getPickedPoints();
|
||||||
|
if (points.empty())
|
||||||
|
{
|
||||||
|
return QRectF();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF mousePoint = pagePointToDevicePointMatrix.inverted().map(pickTool->getSnappedPoint());
|
||||||
|
QPointF point = points.front();
|
||||||
|
qreal xMin = qMin(point.x(), mousePoint.x());
|
||||||
|
qreal xMax = qMax(point.x(), mousePoint.x());
|
||||||
|
qreal yMin = qMin(point.y(), mousePoint.y());
|
||||||
|
qreal yMax = qMax(point.y(), mousePoint.y());
|
||||||
|
qreal width = xMax - xMin;
|
||||||
|
qreal height = yMax - yMin;
|
||||||
|
|
||||||
|
if (!qFuzzyIsNull(width) && !qFuzzyIsNull(height))
|
||||||
|
{
|
||||||
|
return QRectF(xMin, yMin, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QRectF();
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementRectangleTool::PDFCreatePCElementRectangleTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
bool isRounded,
|
||||||
|
QObject* parent) :
|
||||||
|
BaseClass(proxy, scene, action, parent),
|
||||||
|
m_pickTool(nullptr),
|
||||||
|
m_element(nullptr)
|
||||||
|
{
|
||||||
|
m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Rectangles, this);
|
||||||
|
m_pickTool->setDrawSelectionRectangle(false);
|
||||||
|
addTool(m_pickTool);
|
||||||
|
connect(m_pickTool, &PDFPickTool::rectanglePicked, this, &PDFCreatePCElementRectangleTool::onRectanglePicked);
|
||||||
|
|
||||||
|
QPen pen(Qt::SolidLine);
|
||||||
|
pen.setWidthF(1.0);
|
||||||
|
|
||||||
|
m_element = new PDFPageContentElementRectangle();
|
||||||
|
m_element->setBrush(Qt::NoBrush);
|
||||||
|
m_element->setPen(std::move(pen));
|
||||||
|
m_element->setRounded(isRounded);
|
||||||
|
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementRectangleTool::~PDFCreatePCElementRectangleTool()
|
||||||
|
{
|
||||||
|
delete m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementRectangleTool::drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const
|
||||||
|
{
|
||||||
|
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||||
|
|
||||||
|
if (pageIndex != m_pickTool->getPageIndex())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF rectangle = getRectangleFromPickTool(m_pickTool, pagePointToDevicePointMatrix);
|
||||||
|
if (!rectangle.isValid())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_element->setPageIndex(pageIndex);
|
||||||
|
m_element->setRectangle(rectangle);
|
||||||
|
|
||||||
|
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFPageContentElement* PDFCreatePCElementRectangleTool::getElement() const
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFPageContentElement* PDFCreatePCElementRectangleTool::getElement()
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementRectangleTool::onRectanglePicked(PDFInteger pageIndex, QRectF pageRectangle)
|
||||||
|
{
|
||||||
|
if (pageRectangle.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_element->setPageIndex(pageIndex);
|
||||||
|
m_element->setRectangle(pageRectangle);
|
||||||
|
m_scene->addElement(m_element->clone());
|
||||||
|
|
||||||
|
setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementLineTool::PDFCreatePCElementLineTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
bool isHorizontal,
|
||||||
|
bool isVertical,
|
||||||
|
QObject* parent) :
|
||||||
|
BaseClass(proxy, scene, action, parent),
|
||||||
|
m_pickTool(nullptr),
|
||||||
|
m_element(nullptr)
|
||||||
|
{
|
||||||
|
m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Points, this);
|
||||||
|
m_pickTool->setDrawSelectionRectangle(false);
|
||||||
|
addTool(m_pickTool);
|
||||||
|
connect(m_pickTool, &PDFPickTool::pointPicked, this, &PDFCreatePCElementLineTool::onPointPicked);
|
||||||
|
|
||||||
|
QPen pen(Qt::SolidLine);
|
||||||
|
pen.setWidthF(2.0);
|
||||||
|
pen.setCapStyle(Qt::RoundCap);
|
||||||
|
|
||||||
|
PDFPageContentElementLine::LineGeometry geometry = PDFPageContentElementLine::LineGeometry::General;
|
||||||
|
|
||||||
|
if (isHorizontal)
|
||||||
|
{
|
||||||
|
geometry = PDFPageContentElementLine::LineGeometry::Horizontal;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVertical)
|
||||||
|
{
|
||||||
|
geometry = PDFPageContentElementLine::LineGeometry::Vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_element = new PDFPageContentElementLine();
|
||||||
|
m_element->setBrush(Qt::NoBrush);
|
||||||
|
m_element->setPen(std::move(pen));
|
||||||
|
m_element->setGeometry(geometry);
|
||||||
|
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementLineTool::~PDFCreatePCElementLineTool()
|
||||||
|
{
|
||||||
|
delete m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementLineTool::drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const
|
||||||
|
{
|
||||||
|
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||||
|
|
||||||
|
if (pageIndex != m_pickTool->getPageIndex() || !m_startPoint)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_element->setPageIndex(pageIndex);
|
||||||
|
|
||||||
|
QPointF startPoint = *m_startPoint;
|
||||||
|
QPointF endPoint = pagePointToDevicePointMatrix.inverted().map(m_pickTool->getSnappedPoint());
|
||||||
|
QLineF line(startPoint, endPoint);
|
||||||
|
|
||||||
|
if (!qFuzzyIsNull(line.length()))
|
||||||
|
{
|
||||||
|
m_element->setLine(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFPageContentElement* PDFCreatePCElementLineTool::getElement() const
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFPageContentElement* PDFCreatePCElementLineTool::getElement()
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementLineTool::clear()
|
||||||
|
{
|
||||||
|
m_startPoint = std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementLineTool::onPointPicked(PDFInteger pageIndex, QPointF pagePoint)
|
||||||
|
{
|
||||||
|
if (!m_startPoint || m_element->getPageIndex() != pageIndex)
|
||||||
|
{
|
||||||
|
m_startPoint = pagePoint;
|
||||||
|
m_element->setPageIndex(pageIndex);
|
||||||
|
m_element->setLine(QLineF(pagePoint, pagePoint));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qFuzzyCompare(m_startPoint.value().x(), pagePoint.x()) &&
|
||||||
|
qFuzzyCompare(m_startPoint.value().y(), pagePoint.y()))
|
||||||
|
{
|
||||||
|
// Jakub Melka: Point is same as the start point
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLineF line = m_element->getLine();
|
||||||
|
line.setP2(pagePoint);
|
||||||
|
m_element->setLine(line);
|
||||||
|
m_scene->addElement(m_element->clone());
|
||||||
|
clear();
|
||||||
|
|
||||||
|
setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementImageTool::PDFCreatePCElementImageTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
QByteArray content,
|
||||||
|
bool askSelectImage,
|
||||||
|
QObject* parent) :
|
||||||
|
BaseClass(proxy, scene, action, parent),
|
||||||
|
m_pickTool(nullptr),
|
||||||
|
m_element(nullptr),
|
||||||
|
m_askSelectImage(askSelectImage)
|
||||||
|
{
|
||||||
|
m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Rectangles, this);
|
||||||
|
m_pickTool->setDrawSelectionRectangle(false);
|
||||||
|
addTool(m_pickTool);
|
||||||
|
connect(m_pickTool, &PDFPickTool::rectanglePicked, this, &PDFCreatePCElementImageTool::onRectanglePicked);
|
||||||
|
|
||||||
|
m_element = new PDFPageContentImageElement();
|
||||||
|
m_element->setContent(content);
|
||||||
|
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementImageTool::~PDFCreatePCElementImageTool()
|
||||||
|
{
|
||||||
|
delete m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementImageTool::drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const
|
||||||
|
{
|
||||||
|
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||||
|
|
||||||
|
if (pageIndex != m_pickTool->getPageIndex())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF rectangle = getRectangleFromPickTool(m_pickTool, pagePointToDevicePointMatrix);
|
||||||
|
if (!rectangle.isValid())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_element->setPageIndex(pageIndex);
|
||||||
|
m_element->setRectangle(rectangle);
|
||||||
|
|
||||||
|
{
|
||||||
|
PDFPainterStateGuard guard(painter);
|
||||||
|
painter->setWorldMatrix(pagePointToDevicePointMatrix, true);
|
||||||
|
painter->setRenderHint(QPainter::Antialiasing);
|
||||||
|
painter->setPen(Qt::DotLine);
|
||||||
|
painter->setBrush(Qt::NoBrush);
|
||||||
|
painter->drawRect(rectangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFPageContentElement* PDFCreatePCElementImageTool::getElement() const
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFPageContentElement* PDFCreatePCElementImageTool::getElement()
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementImageTool::setActiveImpl(bool active)
|
||||||
|
{
|
||||||
|
BaseClass::setActiveImpl(active);
|
||||||
|
|
||||||
|
if (active && m_askSelectImage)
|
||||||
|
{
|
||||||
|
QTimer::singleShot(0, this, &PDFCreatePCElementImageTool::selectImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementImageTool::selectImage()
|
||||||
|
{
|
||||||
|
if (m_imageDirectory.isEmpty())
|
||||||
|
{
|
||||||
|
QStringList pictureDirectiories = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
|
||||||
|
if (!pictureDirectiories.isEmpty())
|
||||||
|
{
|
||||||
|
m_imageDirectory = pictureDirectiories.last();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_imageDirectory = QDir::currentPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QByteArray> mimeTypes = QImageReader::supportedMimeTypes();
|
||||||
|
QStringList mimeTypeFilters;
|
||||||
|
for (const QByteArray& mimeType : mimeTypes)
|
||||||
|
{
|
||||||
|
mimeTypeFilters.append(mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileDialog dialog(getProxy()->getWidget(), tr("Select Image"));
|
||||||
|
dialog.setDirectory(m_imageDirectory);
|
||||||
|
dialog.setMimeTypeFilters(mimeTypeFilters);
|
||||||
|
dialog.selectMimeTypeFilter("image/svg+xml");
|
||||||
|
dialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||||
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||||
|
|
||||||
|
if (dialog.exec() == QFileDialog::Accepted)
|
||||||
|
{
|
||||||
|
QString fileName = dialog.selectedFiles().constFirst();
|
||||||
|
QFile file(fileName);
|
||||||
|
if (file.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
m_element->setContent(file.readAll());
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementImageTool::onRectanglePicked(PDFInteger pageIndex, QRectF pageRectangle)
|
||||||
|
{
|
||||||
|
if (pageRectangle.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_element->setPageIndex(pageIndex);
|
||||||
|
m_element->setRectangle(pageRectangle);
|
||||||
|
m_scene->addElement(m_element->clone());
|
||||||
|
|
||||||
|
setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementDotTool::PDFCreatePCElementDotTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
QObject* parent) :
|
||||||
|
BaseClass(proxy, scene, action, parent),
|
||||||
|
m_pickTool(nullptr),
|
||||||
|
m_element(nullptr)
|
||||||
|
{
|
||||||
|
m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Points, this);
|
||||||
|
m_pickTool->setDrawSelectionRectangle(false);
|
||||||
|
addTool(m_pickTool);
|
||||||
|
connect(m_pickTool, &PDFPickTool::pointPicked, this, &PDFCreatePCElementDotTool::onPointPicked);
|
||||||
|
|
||||||
|
QPen pen(Qt::SolidLine);
|
||||||
|
pen.setWidthF(5.0);
|
||||||
|
pen.setCapStyle(Qt::RoundCap);
|
||||||
|
|
||||||
|
m_element = new PDFPageContentElementDot();
|
||||||
|
m_element->setBrush(Qt::NoBrush);
|
||||||
|
m_element->setPen(std::move(pen));
|
||||||
|
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementDotTool::~PDFCreatePCElementDotTool()
|
||||||
|
{
|
||||||
|
delete m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementDotTool::drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const
|
||||||
|
{
|
||||||
|
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||||
|
|
||||||
|
QPointF point = pagePointToDevicePointMatrix.inverted().map(m_pickTool->getSnappedPoint());
|
||||||
|
|
||||||
|
PDFPainterStateGuard guard(painter);
|
||||||
|
painter->setWorldMatrix(pagePointToDevicePointMatrix, true);
|
||||||
|
painter->setRenderHint(QPainter::Antialiasing);
|
||||||
|
painter->setPen(m_element->getPen());
|
||||||
|
painter->setBrush(m_element->getBrush());
|
||||||
|
painter->drawPoint(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFPageContentElement* PDFCreatePCElementDotTool::getElement() const
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFPageContentElement* PDFCreatePCElementDotTool::getElement()
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementDotTool::onPointPicked(PDFInteger pageIndex, QPointF pagePoint)
|
||||||
|
{
|
||||||
|
m_element->setPageIndex(pageIndex);
|
||||||
|
m_element->setPoint(pagePoint);
|
||||||
|
|
||||||
|
m_scene->addElement(m_element->clone());
|
||||||
|
m_element->setPageIndex(-1);
|
||||||
|
|
||||||
|
setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementFreehandCurveTool::PDFCreatePCElementFreehandCurveTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
QObject* parent) :
|
||||||
|
BaseClass(proxy, scene, action, parent),
|
||||||
|
m_element(nullptr)
|
||||||
|
{
|
||||||
|
QPen pen(Qt::SolidLine);
|
||||||
|
pen.setWidthF(2.0);
|
||||||
|
pen.setCapStyle(Qt::RoundCap);
|
||||||
|
|
||||||
|
m_element = new PDFPageContentElementFreehandCurve();
|
||||||
|
m_element->setBrush(Qt::NoBrush);
|
||||||
|
m_element->setPen(std::move(pen));
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementFreehandCurveTool::~PDFCreatePCElementFreehandCurveTool()
|
||||||
|
{
|
||||||
|
delete m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementFreehandCurveTool::drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const
|
||||||
|
{
|
||||||
|
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||||
|
|
||||||
|
if (pageIndex != m_element->getPageIndex() || m_element->isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFPageContentElement* PDFCreatePCElementFreehandCurveTool::getElement() const
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFPageContentElement* PDFCreatePCElementFreehandCurveTool::getElement()
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementFreehandCurveTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(widget);
|
||||||
|
event->accept();
|
||||||
|
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
// Try to perform pick point
|
||||||
|
QPointF pagePoint;
|
||||||
|
PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||||
|
if (pageIndex != -1 && // We have picked some point on page
|
||||||
|
(m_element->getPageIndex() == -1 || m_element->getPageIndex() == pageIndex)) // We are under current page
|
||||||
|
{
|
||||||
|
m_element->setPageIndex(pageIndex);
|
||||||
|
m_element->addStartPoint(pagePoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event->button() == Qt::RightButton)
|
||||||
|
{
|
||||||
|
resetTool();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit getProxy()->repaintNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementFreehandCurveTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(widget);
|
||||||
|
event->accept();
|
||||||
|
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
// Try to perform pick point
|
||||||
|
QPointF pagePoint;
|
||||||
|
PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||||
|
if (pageIndex != -1 && // We have picked some point on page
|
||||||
|
(m_element->getPageIndex() == pageIndex)) // We are under current page
|
||||||
|
{
|
||||||
|
m_element->setPageIndex(pageIndex);
|
||||||
|
m_element->addPoint(pagePoint);
|
||||||
|
|
||||||
|
if (!m_element->isEmpty())
|
||||||
|
{
|
||||||
|
m_scene->addElement(m_element->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resetTool();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit getProxy()->repaintNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementFreehandCurveTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(widget);
|
||||||
|
event->accept();
|
||||||
|
|
||||||
|
if (event->buttons() & Qt::LeftButton && m_element->getPageIndex() != -1)
|
||||||
|
{
|
||||||
|
// Try to add point to the path
|
||||||
|
QPointF pagePoint;
|
||||||
|
PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||||
|
if (pageIndex == m_element->getPageIndex())
|
||||||
|
{
|
||||||
|
m_element->addPoint(pagePoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit getProxy()->repaintNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementFreehandCurveTool::setActiveImpl(bool active)
|
||||||
|
{
|
||||||
|
BaseClass::setActiveImpl(active);
|
||||||
|
|
||||||
|
if (!active)
|
||||||
|
{
|
||||||
|
resetTool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementFreehandCurveTool::resetTool()
|
||||||
|
{
|
||||||
|
m_element->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementTextTool::PDFCreatePCElementTextTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
QObject* parent) :
|
||||||
|
BaseClass(proxy, scene, action, parent),
|
||||||
|
m_pickTool(nullptr),
|
||||||
|
m_element(nullptr),
|
||||||
|
m_textEditWidget(nullptr)
|
||||||
|
{
|
||||||
|
m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Rectangles, this);
|
||||||
|
m_pickTool->setDrawSelectionRectangle(true);
|
||||||
|
connect(m_pickTool, &PDFPickTool::rectanglePicked, this, &PDFCreatePCElementTextTool::onRectanglePicked);
|
||||||
|
|
||||||
|
QFont font = QGuiApplication::font();
|
||||||
|
font.setPixelSize(16.0);
|
||||||
|
|
||||||
|
m_element = new PDFPageContentElementTextBox();
|
||||||
|
m_element->setBrush(Qt::NoBrush);
|
||||||
|
m_element->setPen(QPen(Qt::SolidLine));
|
||||||
|
m_element->setFont(font);
|
||||||
|
|
||||||
|
m_textEditWidget = new PDFTextEditPseudowidget(PDFFormField::Multiline);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFCreatePCElementTextTool::~PDFCreatePCElementTextTool()
|
||||||
|
{
|
||||||
|
delete m_textEditWidget;
|
||||||
|
delete m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const
|
||||||
|
{
|
||||||
|
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||||
|
|
||||||
|
if (pageIndex != m_element->getPageIndex())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEditing())
|
||||||
|
{
|
||||||
|
PDFPainterStateGuard guard(painter);
|
||||||
|
AnnotationDrawParameters parameters;
|
||||||
|
parameters.painter = painter;
|
||||||
|
parameters.boundingRectangle = m_element->getRectangle();
|
||||||
|
parameters.key.first = PDFAppeareanceStreams::Appearance::Normal;
|
||||||
|
parameters.invertColors = getProxy()->getFeatures().testFlag(PDFRenderer::InvertColors);
|
||||||
|
|
||||||
|
painter->setWorldMatrix(pagePointToDevicePointMatrix, true);
|
||||||
|
m_textEditWidget->draw(parameters, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFPageContentElement* PDFCreatePCElementTextTool::getElement() const
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFPageContentElement* PDFCreatePCElementTextTool::getElement()
|
||||||
|
{
|
||||||
|
return m_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::resetTool()
|
||||||
|
{
|
||||||
|
m_textEditWidget->setText(QString());
|
||||||
|
m_element->setText(QString());
|
||||||
|
m_element->setPageIndex(-1);
|
||||||
|
|
||||||
|
if (getTopToolstackTool())
|
||||||
|
{
|
||||||
|
removeTool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::setActiveImpl(bool active)
|
||||||
|
{
|
||||||
|
BaseClass::setActiveImpl(active);
|
||||||
|
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!getTopToolstackTool());
|
||||||
|
addTool(m_pickTool);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resetTool();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pickTool->setActive(active);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::onRectanglePicked(PDFInteger pageIndex, QRectF pageRectangle)
|
||||||
|
{
|
||||||
|
if (pageRectangle.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_element->setPageIndex(pageIndex);
|
||||||
|
m_element->setRectangle(pageRectangle);
|
||||||
|
|
||||||
|
m_textEditWidget->setAppearance(m_element->getFont(),
|
||||||
|
m_element->getAlignment(),
|
||||||
|
m_element->getRectangle(),
|
||||||
|
std::numeric_limits<int>::max(),
|
||||||
|
m_element->getPen().color());
|
||||||
|
|
||||||
|
removeTool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::finishEditing()
|
||||||
|
{
|
||||||
|
m_element->setText(m_textEditWidget->getText());
|
||||||
|
|
||||||
|
if (!m_element->getText().isEmpty())
|
||||||
|
{
|
||||||
|
m_scene->addElement(m_element->clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
resetTool();
|
||||||
|
setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<QPointF> PDFCreatePCElementTextTool::getPagePointUnderMouse(QMouseEvent* event) const
|
||||||
|
{
|
||||||
|
QPointF pagePoint;
|
||||||
|
PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||||
|
if (pageIndex == m_element->getPageIndex() &&
|
||||||
|
m_element->getRectangle().contains(pagePoint))
|
||||||
|
{
|
||||||
|
return pagePoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PDFCreatePCElementTextTool::isEditing() const
|
||||||
|
{
|
||||||
|
return isActive() && !getTopToolstackTool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(widget);
|
||||||
|
|
||||||
|
if (isEditing())
|
||||||
|
{
|
||||||
|
m_textEditWidget->shortcutOverrideEvent(widget, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
|
||||||
|
if (!isEditing())
|
||||||
|
{
|
||||||
|
BaseClass::keyPressEvent(widget, event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->key() == Qt::Key_Escape)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_textEditWidget->isMultiline() && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return))
|
||||||
|
{
|
||||||
|
// Commit the editor and create element
|
||||||
|
finishEditing();
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_textEditWidget->keyPressEvent(widget, event);
|
||||||
|
|
||||||
|
if (event->isAccepted())
|
||||||
|
{
|
||||||
|
widget->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
if (isEditing())
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
std::optional<QPointF> pagePoint = getPagePointUnderMouse(event);
|
||||||
|
if (pagePoint)
|
||||||
|
{
|
||||||
|
const int cursorPosition = m_textEditWidget->getCursorPositionFromWidgetPosition(pagePoint.value(), true);
|
||||||
|
m_textEditWidget->setCursorPosition(cursorPosition, event->modifiers() & Qt::ShiftModifier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
finishEditing();
|
||||||
|
}
|
||||||
|
|
||||||
|
event->accept();
|
||||||
|
widget->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BaseClass::mousePressEvent(widget, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
if (isEditing())
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
std::optional<QPointF> pagePoint = getPagePointUnderMouse(event);
|
||||||
|
if (pagePoint)
|
||||||
|
{
|
||||||
|
const int cursorPosition = m_textEditWidget->getCursorPositionFromWidgetPosition(pagePoint.value(), true);
|
||||||
|
m_textEditWidget->setCursorPosition(cursorPosition, false);
|
||||||
|
m_textEditWidget->setCursorPosition(m_textEditWidget->getCursorWordBackward(), false);
|
||||||
|
m_textEditWidget->setCursorPosition(m_textEditWidget->getCursorWordForward(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
finishEditing();
|
||||||
|
}
|
||||||
|
|
||||||
|
event->accept();
|
||||||
|
widget->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BaseClass::mousePressEvent(widget, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
if (isEditing())
|
||||||
|
{
|
||||||
|
std::optional<QPointF> pagePoint = getPagePointUnderMouse(event);
|
||||||
|
if (pagePoint)
|
||||||
|
{
|
||||||
|
// We must test, if left mouse button is pressed while
|
||||||
|
// we are moving the mouse - if yes, then select the text.
|
||||||
|
if (event->buttons() & Qt::LeftButton)
|
||||||
|
{
|
||||||
|
const int cursorPosition = m_textEditWidget->getCursorPositionFromWidgetPosition(pagePoint.value(), true);
|
||||||
|
m_textEditWidget->setCursorPosition(cursorPosition, true);
|
||||||
|
|
||||||
|
event->accept();
|
||||||
|
widget->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BaseClass::mouseMoveEvent(widget, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::wheelEvent(QWidget* widget, QWheelEvent* event)
|
||||||
|
{
|
||||||
|
if (isEditing())
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BaseClass::wheelEvent(widget, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::setFont(const QFont& font)
|
||||||
|
{
|
||||||
|
BaseClass::setFont(font);
|
||||||
|
m_textEditWidget->setAppearance(font, m_element->getAlignment(), m_element->getRectangle(), std::numeric_limits<int>::max(), m_element->getPen().color());
|
||||||
|
emit getProxy()->repaintNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::setAlignment(Qt::Alignment alignment)
|
||||||
|
{
|
||||||
|
BaseClass::setAlignment(alignment);
|
||||||
|
m_textEditWidget->setAppearance(m_element->getFont(), alignment, m_element->getRectangle(), std::numeric_limits<int>::max(), m_element->getPen().color());
|
||||||
|
emit getProxy()->repaintNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFCreatePCElementTextTool::setPen(const QPen& pen)
|
||||||
|
{
|
||||||
|
BaseClass::setPen(pen);
|
||||||
|
|
||||||
|
QFont font = m_element->getFont();
|
||||||
|
font.setHintingPreference(QFont::PreferNoHinting);
|
||||||
|
if (font.pointSizeF() > 0.0)
|
||||||
|
{
|
||||||
|
font.setPixelSize(qRound(font.pointSizeF()));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_textEditWidget->setAppearance(font, m_element->getAlignment(), m_element->getRectangle(), std::numeric_limits<int>::max(), pen.color());
|
||||||
|
emit getProxy()->repaintNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdf
|
|
@ -0,0 +1,292 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef PDFPAGECONTENTEDITORTOOLS_H
|
||||||
|
#define PDFPAGECONTENTEDITORTOOLS_H
|
||||||
|
|
||||||
|
#include "pdfwidgettool.h"
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
class PDFPageContentScene;
|
||||||
|
class PDFPageContentElement;
|
||||||
|
class PDFPageContentImageElement;
|
||||||
|
class PDFPageContentElementDot;
|
||||||
|
class PDFPageContentElementLine;
|
||||||
|
class PDFPageContentElementTextBox;
|
||||||
|
class PDFPageContentElementRectangle;
|
||||||
|
class PDFPageContentElementFreehandCurve;
|
||||||
|
class PDFTextEditPseudowidget;
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementTool : public PDFWidgetTool
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
PDFCreatePCElementTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
QObject* parent);
|
||||||
|
|
||||||
|
virtual const PDFPageContentElement* getElement() const = 0;
|
||||||
|
virtual PDFPageContentElement* getElement() = 0;
|
||||||
|
|
||||||
|
virtual void setPen(const QPen& pen);
|
||||||
|
virtual void setBrush(const QBrush& brush);
|
||||||
|
virtual void setFont(const QFont& font);
|
||||||
|
virtual void setAlignment(Qt::Alignment alignment);
|
||||||
|
virtual void setTextAngle(pdf::PDFReal angle);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static QRectF getRectangleFromPickTool(PDFPickTool* pickTool, const QMatrix& pagePointToDevicePointMatrix);
|
||||||
|
|
||||||
|
PDFPageContentScene* m_scene;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Tool that creates rectangle element.
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementRectangleTool : public PDFCreatePCElementTool
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
using BaseClass = PDFCreatePCElementTool;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PDFCreatePCElementRectangleTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
bool isRounded,
|
||||||
|
QObject* parent);
|
||||||
|
virtual ~PDFCreatePCElementRectangleTool() override;
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual const PDFPageContentElement* getElement() const override;
|
||||||
|
virtual PDFPageContentElement* getElement() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||||
|
|
||||||
|
PDFPickTool* m_pickTool;
|
||||||
|
PDFPageContentElementRectangle* m_element;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Tool that displays SVG image (or raster image)
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementImageTool : public PDFCreatePCElementTool
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
using BaseClass = PDFCreatePCElementTool;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PDFCreatePCElementImageTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
QByteArray content,
|
||||||
|
bool askSelectImage,
|
||||||
|
QObject* parent);
|
||||||
|
virtual ~PDFCreatePCElementImageTool() override;
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual const PDFPageContentElement* getElement() const override;
|
||||||
|
virtual PDFPageContentElement* getElement() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void setActiveImpl(bool active) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void selectImage();
|
||||||
|
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||||
|
|
||||||
|
PDFPickTool* m_pickTool;
|
||||||
|
PDFPageContentImageElement* m_element;
|
||||||
|
bool m_askSelectImage;
|
||||||
|
QString m_imageDirectory;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Tool that creates line element.
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementLineTool : public PDFCreatePCElementTool
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
using BaseClass = PDFCreatePCElementTool;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PDFCreatePCElementLineTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
bool isHorizontal,
|
||||||
|
bool isVertical,
|
||||||
|
QObject* parent);
|
||||||
|
virtual ~PDFCreatePCElementLineTool() override;
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual const PDFPageContentElement* getElement() const override;
|
||||||
|
virtual PDFPageContentElement* getElement() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void clear();
|
||||||
|
void onPointPicked(pdf::PDFInteger pageIndex, QPointF pagePoint);
|
||||||
|
|
||||||
|
PDFPickTool* m_pickTool;
|
||||||
|
PDFPageContentElementLine* m_element;
|
||||||
|
std::optional<QPointF> m_startPoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Tool that creates dot element.
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementDotTool : public PDFCreatePCElementTool
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
using BaseClass = PDFCreatePCElementTool;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PDFCreatePCElementDotTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
QObject* parent);
|
||||||
|
virtual ~PDFCreatePCElementDotTool() override;
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual const PDFPageContentElement* getElement() const override;
|
||||||
|
virtual PDFPageContentElement* getElement() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onPointPicked(pdf::PDFInteger pageIndex, QPointF pagePoint);
|
||||||
|
|
||||||
|
PDFPickTool* m_pickTool;
|
||||||
|
PDFPageContentElementDot* m_element;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Tool that creates freehand curve element.
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementFreehandCurveTool : public PDFCreatePCElementTool
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
using BaseClass = PDFCreatePCElementTool;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PDFCreatePCElementFreehandCurveTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
QObject* parent);
|
||||||
|
virtual ~PDFCreatePCElementFreehandCurveTool() override;
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual const PDFPageContentElement* getElement() const override;
|
||||||
|
virtual PDFPageContentElement* getElement() override;
|
||||||
|
|
||||||
|
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void setActiveImpl(bool active);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void resetTool();
|
||||||
|
|
||||||
|
PDFPageContentElementFreehandCurve* m_element;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Tool that displays SVG image
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementTextTool : public PDFCreatePCElementTool
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
using BaseClass = PDFCreatePCElementTool;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PDFCreatePCElementTextTool(PDFDrawWidgetProxy* proxy,
|
||||||
|
PDFPageContentScene* scene,
|
||||||
|
QAction* action,
|
||||||
|
QObject* parent);
|
||||||
|
virtual ~PDFCreatePCElementTextTool() override;
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual const PDFPageContentElement* getElement() const override;
|
||||||
|
virtual PDFPageContentElement* getElement() override;
|
||||||
|
|
||||||
|
virtual void setPen(const QPen& pen);
|
||||||
|
virtual void setFont(const QFont& font) override;
|
||||||
|
virtual void setAlignment(Qt::Alignment alignment) override;
|
||||||
|
|
||||||
|
virtual void setActiveImpl(bool active) override;
|
||||||
|
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;
|
||||||
|
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
|
||||||
|
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
virtual void wheelEvent(QWidget* widget, QWheelEvent* event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||||
|
|
||||||
|
void finishEditing();
|
||||||
|
void resetTool();
|
||||||
|
std::optional<QPointF> getPagePointUnderMouse(QMouseEvent* event) const;
|
||||||
|
|
||||||
|
bool isEditing() const;
|
||||||
|
|
||||||
|
PDFPickTool* m_pickTool;
|
||||||
|
PDFPageContentElementTextBox* m_element;
|
||||||
|
PDFTextEditPseudowidget* m_textEditWidget;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdf
|
||||||
|
|
||||||
|
#endif // PDFPAGECONTENTEDITORTOOLS_H
|
|
@ -0,0 +1,273 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "pdfpagecontenteditorwidget.h"
|
||||||
|
#include "pdfpagecontenteditorstylesettings.h"
|
||||||
|
#include "ui_pdfpagecontenteditorwidget.h"
|
||||||
|
#include "pdfwidgetutils.h"
|
||||||
|
#include "pdfpagecontentelements.h"
|
||||||
|
#include "pdfutils.h"
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QToolButton>
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
PDFPageContentEditorWidget::PDFPageContentEditorWidget(QWidget* parent) :
|
||||||
|
QDockWidget(parent),
|
||||||
|
ui(new Ui::PDFPageContentEditorWidget),
|
||||||
|
m_toolBoxColumnCount(6),
|
||||||
|
m_scene(nullptr),
|
||||||
|
m_selectionChangeEnabled(true),
|
||||||
|
m_updatesEnabled(true)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
m_toolButtonIconSize = PDFWidgetUtils::scaleDPI(this, QSize(32, 32));
|
||||||
|
|
||||||
|
for (QToolButton* button : findChildren<QToolButton*>())
|
||||||
|
{
|
||||||
|
button->setIconSize(m_toolButtonIconSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_operationMapper.setMapping(ui->alignVertTopButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignTop));
|
||||||
|
m_operationMapper.setMapping(ui->alignVertMiddleButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignCenterVertically));
|
||||||
|
m_operationMapper.setMapping(ui->alignVertBottomButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignBottom));
|
||||||
|
m_operationMapper.setMapping(ui->alignHorLeftButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignLeft));
|
||||||
|
m_operationMapper.setMapping(ui->alignHorMiddleButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignCenterHorizontally));
|
||||||
|
m_operationMapper.setMapping(ui->alignHorRightButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignRight));
|
||||||
|
m_operationMapper.setMapping(ui->setSameWidthButton, static_cast<int>(PDFPageContentElementManipulator::Operation::SetSameWidth));
|
||||||
|
m_operationMapper.setMapping(ui->setSameHeightButton, static_cast<int>(PDFPageContentElementManipulator::Operation::SetSameHeight));
|
||||||
|
m_operationMapper.setMapping(ui->setSameSizeButton, static_cast<int>(PDFPageContentElementManipulator::Operation::SetSameSize));
|
||||||
|
m_operationMapper.setMapping(ui->centerHorizontallyButton, static_cast<int>(PDFPageContentElementManipulator::Operation::CenterHorizontally));
|
||||||
|
m_operationMapper.setMapping(ui->centerVerticallyButton, static_cast<int>(PDFPageContentElementManipulator::Operation::CenterVertically));
|
||||||
|
m_operationMapper.setMapping(ui->centerRectButton, static_cast<int>(PDFPageContentElementManipulator::Operation::CenterHorAndVert));
|
||||||
|
m_operationMapper.setMapping(ui->layoutHorizontallyButton, static_cast<int>(PDFPageContentElementManipulator::Operation::LayoutHorizontally));
|
||||||
|
m_operationMapper.setMapping(ui->layoutVerticallyButton, static_cast<int>(PDFPageContentElementManipulator::Operation::LayoutVertically));
|
||||||
|
m_operationMapper.setMapping(ui->layoutFormButton, static_cast<int>(PDFPageContentElementManipulator::Operation::LayoutForm));
|
||||||
|
m_operationMapper.setMapping(ui->layoutGridButton, static_cast<int>(PDFPageContentElementManipulator::Operation::LayoutGrid));
|
||||||
|
|
||||||
|
connect(ui->alignVertTopButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->alignVertMiddleButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->alignVertBottomButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->alignHorLeftButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->alignHorMiddleButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->alignHorRightButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->setSameWidthButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->setSameHeightButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->setSameSizeButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->centerHorizontallyButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->centerVerticallyButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->centerRectButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->layoutHorizontallyButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->layoutVerticallyButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->layoutFormButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(ui->layoutGridButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
|
||||||
|
connect(&m_actionMapper, &QSignalMapper::mappedObject, this, &PDFPageContentEditorWidget::onActionTriggerRequest);
|
||||||
|
connect(&m_operationMapper, &QSignalMapper::mappedInt, this, &PDFPageContentEditorWidget::operationTriggered);
|
||||||
|
connect(ui->itemsListWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &PDFPageContentEditorWidget::onItemSelectionChanged);
|
||||||
|
|
||||||
|
connect(ui->appearanceSettingsWidget, &PDFPageContentEditorStyleSettings::penChanged, this, &PDFPageContentEditorWidget::penChanged);
|
||||||
|
connect(ui->appearanceSettingsWidget, &PDFPageContentEditorStyleSettings::brushChanged, this, &PDFPageContentEditorWidget::brushChanged);
|
||||||
|
connect(ui->appearanceSettingsWidget, &PDFPageContentEditorStyleSettings::fontChanged, this, &PDFPageContentEditorWidget::fontChanged);
|
||||||
|
connect(ui->appearanceSettingsWidget, &PDFPageContentEditorStyleSettings::alignmentChanged, this, &PDFPageContentEditorWidget::alignmentChanged);
|
||||||
|
connect(ui->appearanceSettingsWidget, &PDFPageContentEditorStyleSettings::textAngleChanged, this, &PDFPageContentEditorWidget::textAngleChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFPageContentEditorWidget::~PDFPageContentEditorWidget()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorWidget::addAction(QAction* action)
|
||||||
|
{
|
||||||
|
// First, find position for our action
|
||||||
|
int row = 0;
|
||||||
|
int column = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (!ui->toolGroupBoxLayout->itemAtPosition(row, column))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++column;
|
||||||
|
|
||||||
|
if (column == m_toolBoxColumnCount)
|
||||||
|
{
|
||||||
|
column = 0;
|
||||||
|
++row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QToolButton* button = new QToolButton(this);
|
||||||
|
button->setIcon(action->icon());
|
||||||
|
button->setText(action->text());
|
||||||
|
button->setToolTip(action->toolTip());
|
||||||
|
button->setCheckable(action->isCheckable());
|
||||||
|
button->setChecked(action->isChecked());
|
||||||
|
button->setEnabled(action->isEnabled());
|
||||||
|
button->setShortcut(action->shortcut());
|
||||||
|
button->setIconSize(m_toolButtonIconSize);
|
||||||
|
m_actionMapper.setMapping(button, action);
|
||||||
|
connect(button, &QToolButton::clicked, &m_actionMapper, QOverload<>::of(&QSignalMapper::map));
|
||||||
|
connect(action, &QAction::changed, this, &PDFPageContentEditorWidget::onActionChanged);
|
||||||
|
|
||||||
|
ui->toolGroupBoxLayout->addWidget(button, row, column, Qt::AlignCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
QToolButton* PDFPageContentEditorWidget::getToolButtonForOperation(int operation) const
|
||||||
|
{
|
||||||
|
return qobject_cast<QToolButton*>(m_operationMapper.mapping(operation));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorWidget::updateItemsInListWidget()
|
||||||
|
{
|
||||||
|
if (!m_updatesEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdf::PDFTemporaryValueChange guard(&m_updatesEnabled, false);
|
||||||
|
ui->itemsListWidget->setUpdatesEnabled(false);
|
||||||
|
|
||||||
|
if (m_scene)
|
||||||
|
{
|
||||||
|
std::set<PDFInteger> presentElementIds;
|
||||||
|
std::set<PDFInteger> elementIds = m_scene->getElementIds();
|
||||||
|
|
||||||
|
// Remove items which are not here
|
||||||
|
for (int i = 0; i < ui->itemsListWidget->count();)
|
||||||
|
{
|
||||||
|
QListWidgetItem* item = ui->itemsListWidget->item(i);
|
||||||
|
const PDFInteger elementId = item->data(Qt::UserRole).toLongLong();
|
||||||
|
if (!elementIds.count(elementId))
|
||||||
|
{
|
||||||
|
delete ui->itemsListWidget->takeItem(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
presentElementIds.insert(elementId);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add items which are here
|
||||||
|
for (PDFInteger elementId : elementIds)
|
||||||
|
{
|
||||||
|
if (presentElementIds.count(elementId))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFPageContentElement* element = m_scene->getElementById(elementId);
|
||||||
|
Q_ASSERT(element);
|
||||||
|
|
||||||
|
QListWidgetItem* item = new QListWidgetItem(element->getDescription());
|
||||||
|
item->setData(Qt::UserRole, elementId);
|
||||||
|
|
||||||
|
ui->itemsListWidget->addItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->itemsListWidget->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->itemsListWidget->setUpdatesEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorWidget::onActionTriggerRequest(QObject* actionObject)
|
||||||
|
{
|
||||||
|
QAction* action = qobject_cast<QAction*>(actionObject);
|
||||||
|
Q_ASSERT(action);
|
||||||
|
|
||||||
|
action->trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorWidget::onActionChanged()
|
||||||
|
{
|
||||||
|
QAction* action = qobject_cast<QAction*>(sender());
|
||||||
|
QToolButton* button = qobject_cast<QToolButton*>(m_actionMapper.mapping(action));
|
||||||
|
|
||||||
|
Q_ASSERT(action);
|
||||||
|
Q_ASSERT(button);
|
||||||
|
|
||||||
|
button->setChecked(action->isChecked());
|
||||||
|
button->setEnabled(action->isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorWidget::onItemSelectionChanged()
|
||||||
|
{
|
||||||
|
if (m_selectionChangeEnabled)
|
||||||
|
{
|
||||||
|
emit itemSelectionChangedByUser();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFPageContentScene* PDFPageContentEditorWidget::scene() const
|
||||||
|
{
|
||||||
|
return m_scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorWidget::setScene(PDFPageContentScene* newScene)
|
||||||
|
{
|
||||||
|
if (m_scene != newScene)
|
||||||
|
{
|
||||||
|
m_scene = newScene;
|
||||||
|
updateItemsInListWidget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<PDFInteger> PDFPageContentEditorWidget::getSelection() const
|
||||||
|
{
|
||||||
|
std::set<PDFInteger> result;
|
||||||
|
|
||||||
|
for (int i = 0; i < ui->itemsListWidget->count(); ++i)
|
||||||
|
{
|
||||||
|
QListWidgetItem* item = ui->itemsListWidget->item(i);
|
||||||
|
if (item->isSelected())
|
||||||
|
{
|
||||||
|
const PDFInteger elementId = item->data(Qt::UserRole).toLongLong();
|
||||||
|
result.insert(elementId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorWidget::setSelection(const std::set<PDFInteger>& selection)
|
||||||
|
{
|
||||||
|
pdf::PDFTemporaryValueChange guard(&m_selectionChangeEnabled, false);
|
||||||
|
|
||||||
|
for (int i = 0; i < ui->itemsListWidget->count(); ++i)
|
||||||
|
{
|
||||||
|
QListWidgetItem* item = ui->itemsListWidget->item(i);
|
||||||
|
const PDFInteger elementId = item->data(Qt::UserRole).toLongLong();
|
||||||
|
item->setSelected(selection.count(elementId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPageContentEditorWidget::loadStyleFromElement(const PDFPageContentElement* element)
|
||||||
|
{
|
||||||
|
ui->appearanceSettingsWidget->loadFromElement(element, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdf
|
|
@ -0,0 +1,93 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef PDFPAGECONTENTEDITORWIDGET_H
|
||||||
|
#define PDFPAGECONTENTEDITORWIDGET_H
|
||||||
|
|
||||||
|
#include "pdfglobal.h"
|
||||||
|
|
||||||
|
#include <QDockWidget>
|
||||||
|
#include <QSignalMapper>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
class QToolButton;
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class PDFPageContentEditorWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
class PDFPageContentScene;
|
||||||
|
class PDFPageContentElement;
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentEditorWidget : public QDockWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PDFPageContentEditorWidget(QWidget* parent);
|
||||||
|
virtual ~PDFPageContentEditorWidget() override;
|
||||||
|
|
||||||
|
/// Adds external action to the tool box
|
||||||
|
void addAction(QAction* action);
|
||||||
|
|
||||||
|
QToolButton* getToolButtonForOperation(int operation) const;
|
||||||
|
|
||||||
|
/// Update items in list widget
|
||||||
|
void updateItemsInListWidget();
|
||||||
|
|
||||||
|
PDFPageContentScene* scene() const;
|
||||||
|
void setScene(PDFPageContentScene* newScene);
|
||||||
|
|
||||||
|
std::set<PDFInteger> getSelection() const;
|
||||||
|
void setSelection(const std::set<PDFInteger>& selection);
|
||||||
|
|
||||||
|
/// Loads style from element, element can be nullptr
|
||||||
|
/// \param element Element
|
||||||
|
void loadStyleFromElement(const PDFPageContentElement* element);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void operationTriggered(int operation);
|
||||||
|
void itemSelectionChangedByUser();
|
||||||
|
|
||||||
|
void penChanged(const QPen& pen);
|
||||||
|
void brushChanged(const QBrush& brush);
|
||||||
|
void fontChanged(const QFont& font);
|
||||||
|
void alignmentChanged(Qt::Alignment alignment);
|
||||||
|
void textAngleChanged(pdf::PDFReal angle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onActionTriggerRequest(QObject* actionObject);
|
||||||
|
void onActionChanged();
|
||||||
|
void onItemSelectionChanged();
|
||||||
|
|
||||||
|
Ui::PDFPageContentEditorWidget* ui;
|
||||||
|
QSignalMapper m_actionMapper;
|
||||||
|
QSignalMapper m_operationMapper;
|
||||||
|
int m_toolBoxColumnCount;
|
||||||
|
QSize m_toolButtonIconSize;
|
||||||
|
PDFPageContentScene* m_scene;
|
||||||
|
bool m_selectionChangeEnabled;
|
||||||
|
bool m_updatesEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdf
|
||||||
|
|
||||||
|
#endif // PDFPAGECONTENTEDITORWIDGET_H
|
|
@ -0,0 +1,215 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>PDFPageContentEditorWidget</class>
|
||||||
|
<widget class="QDockWidget" name="PDFPageContentEditorWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>333</width>
|
||||||
|
<height>607</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="allowedAreas">
|
||||||
|
<set>Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea</set>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Content editor</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="dockWidgetContents">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0,1">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="toolGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Toolbox</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="toolGroupBoxLayout"/>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="adjustBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Geometry Tools</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="geometryToolsGroupBoxLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QToolButton" name="alignVertTopButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Align to Top</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QToolButton" name="alignVertMiddleButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Align to Vertical Center</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QToolButton" name="alignVertBottomButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Align to Bottom</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
|
<widget class="QToolButton" name="setSameWidthButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set Same Width</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="4">
|
||||||
|
<widget class="QToolButton" name="setSameHeightButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set Same Height</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="5">
|
||||||
|
<widget class="QToolButton" name="setSameSizeButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set Same Size</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QToolButton" name="alignHorLeftButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Align to Left</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QToolButton" name="alignHorMiddleButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Align to Horizontal Center</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QToolButton" name="alignHorRightButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Align to Right</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="3">
|
||||||
|
<widget class="QToolButton" name="centerHorizontallyButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Center Horizontally</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="4">
|
||||||
|
<widget class="QToolButton" name="centerVerticallyButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Center Vertically</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="5">
|
||||||
|
<widget class="QToolButton" name="centerRectButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Center to Page Media Box</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="layoutGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Layout Tools</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="layoutToolBoxLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="layoutHorizontallyButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Make Horizontal Layout</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="layoutVerticallyButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Make Vertical Layout</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="layoutFormButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Make Form Layout</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="layoutGridButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Make Grid Layout</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="appearanceGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Appearance</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="appearanceLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="pdf::PDFPageContentEditorStyleSettings" name="appearanceSettingsWidget" native="true"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="contentGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Content</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="itemsListWidget">
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>pdf::PDFPageContentEditorStyleSettings</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>pdfpagecontenteditorstylesettings.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -0,0 +1,626 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef PDFPAGECONTENTELEMENTS_H
|
||||||
|
#define PDFPAGECONTENTELEMENTS_H
|
||||||
|
|
||||||
|
#include "pdfdocumentdrawinterface.h"
|
||||||
|
|
||||||
|
#include <QPen>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QBrush>
|
||||||
|
#include <QCursor>
|
||||||
|
#include <QPainterPath>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
class QSvgRenderer;
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
class PDFWidget;
|
||||||
|
class PDFDocument;
|
||||||
|
class PDFPageContentScene;
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFPageContentElement() = default;
|
||||||
|
virtual ~PDFPageContentElement() = default;
|
||||||
|
|
||||||
|
virtual PDFPageContentElement* clone() const = 0;
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const = 0;
|
||||||
|
|
||||||
|
/// Returns manipulation mode. If manipulation mode is zero, then element
|
||||||
|
/// cannot be manipulated. If it is nonzero, then element can be manipulated
|
||||||
|
/// in some way.
|
||||||
|
/// \param point Point on page
|
||||||
|
/// \param snapPointDistanceTreshold Snap point threshold
|
||||||
|
virtual uint getManipulationMode(const QPointF& point, PDFReal snapPointDistanceThreshold) const = 0;
|
||||||
|
|
||||||
|
/// Performs manipulation of given mode. Mode must be the one returned
|
||||||
|
/// from function getManipulationMode. \sa getManipulationMode
|
||||||
|
/// \param mode Mode
|
||||||
|
/// \param offset Offset
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) = 0;
|
||||||
|
|
||||||
|
/// Returns bounding box of the element
|
||||||
|
virtual QRectF getBoundingBox() const = 0;
|
||||||
|
|
||||||
|
/// Sets size to the elements that supports it. Does
|
||||||
|
/// nothing for elements, which does not support it.
|
||||||
|
virtual void setSize(QSizeF size) = 0;
|
||||||
|
|
||||||
|
/// Returns description of the element
|
||||||
|
virtual QString getDescription() const = 0;
|
||||||
|
|
||||||
|
PDFInteger getPageIndex() const;
|
||||||
|
void setPageIndex(PDFInteger newPageIndex);
|
||||||
|
|
||||||
|
PDFInteger getElementId() const;
|
||||||
|
void setElementId(PDFInteger newElementId);
|
||||||
|
|
||||||
|
/// Returns cursor shape for manipulation mode
|
||||||
|
/// \param mode Manipulation mode
|
||||||
|
static Qt::CursorShape getCursorShapeForManipulationMode(uint mode);
|
||||||
|
|
||||||
|
enum ManipulationModes : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Translate,
|
||||||
|
Top,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Bottom,
|
||||||
|
TopLeft,
|
||||||
|
TopRight,
|
||||||
|
BottomLeft,
|
||||||
|
BottomRight,
|
||||||
|
Pt1,
|
||||||
|
Pt2
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint getRectangleManipulationMode(const QRectF& rectangle,
|
||||||
|
const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const;
|
||||||
|
|
||||||
|
void performRectangleManipulation(QRectF& rectangle,
|
||||||
|
uint mode,
|
||||||
|
const QPointF& offset);
|
||||||
|
|
||||||
|
void performRectangleSetSize(QRectF& rectangle, QSizeF size);
|
||||||
|
|
||||||
|
QString formatDescription(const QString& description) const;
|
||||||
|
|
||||||
|
PDFInteger m_elementId = -1;
|
||||||
|
PDFInteger m_pageIndex = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentStyledElement : public PDFPageContentElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFPageContentStyledElement() = default;
|
||||||
|
virtual ~PDFPageContentStyledElement() = default;
|
||||||
|
|
||||||
|
const QPen& getPen() const;
|
||||||
|
void setPen(const QPen& newPen);
|
||||||
|
|
||||||
|
const QBrush& getBrush() const;
|
||||||
|
void setBrush(const QBrush& newBrush);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QPen m_pen;
|
||||||
|
QBrush m_brush;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentElementRectangle : public PDFPageContentStyledElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~PDFPageContentElementRectangle() = default;
|
||||||
|
|
||||||
|
virtual PDFPageContentElementRectangle* clone() const override;
|
||||||
|
|
||||||
|
bool isRounded() const;
|
||||||
|
void setRounded(bool newRounded);
|
||||||
|
|
||||||
|
const QRectF& getRectangle() const;
|
||||||
|
void setRectangle(const QRectF& newRectangle);
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual uint getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const override;
|
||||||
|
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||||
|
virtual QRectF getBoundingBox() const override;
|
||||||
|
virtual void setSize(QSizeF size);
|
||||||
|
virtual QString getDescription() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_rounded = false;
|
||||||
|
QRectF m_rectangle;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentElementLine : public PDFPageContentStyledElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~PDFPageContentElementLine() = default;
|
||||||
|
|
||||||
|
virtual PDFPageContentElementLine* clone() const override;
|
||||||
|
|
||||||
|
enum class LineGeometry
|
||||||
|
{
|
||||||
|
General,
|
||||||
|
Horizontal,
|
||||||
|
Vertical
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual uint getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const override;
|
||||||
|
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||||
|
virtual QRectF getBoundingBox() const override;
|
||||||
|
virtual void setSize(QSizeF size);
|
||||||
|
virtual QString getDescription() const override;
|
||||||
|
|
||||||
|
LineGeometry getGeometry() const;
|
||||||
|
void setGeometry(LineGeometry newGeometry);
|
||||||
|
|
||||||
|
const QLineF& getLine() const;
|
||||||
|
void setLine(const QLineF& newLine);
|
||||||
|
|
||||||
|
private:
|
||||||
|
LineGeometry m_geometry = LineGeometry::General;
|
||||||
|
QLineF m_line;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentElementDot : public PDFPageContentStyledElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~PDFPageContentElementDot() = default;
|
||||||
|
|
||||||
|
virtual PDFPageContentElementDot* clone() const override;
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual uint getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const override;
|
||||||
|
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||||
|
virtual QRectF getBoundingBox() const override;
|
||||||
|
virtual void setSize(QSizeF size);
|
||||||
|
virtual QString getDescription() const override;
|
||||||
|
|
||||||
|
QPointF getPoint() const;
|
||||||
|
void setPoint(QPointF newPoint);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointF m_point;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentElementFreehandCurve : public PDFPageContentStyledElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~PDFPageContentElementFreehandCurve() = default;
|
||||||
|
|
||||||
|
virtual PDFPageContentElementFreehandCurve* clone() const override;
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual uint getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const override;
|
||||||
|
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||||
|
virtual QRectF getBoundingBox() const override;
|
||||||
|
virtual void setSize(QSizeF size);
|
||||||
|
virtual QString getDescription() const override;
|
||||||
|
|
||||||
|
QPainterPath getCurve() const;
|
||||||
|
void setCurve(QPainterPath newCurve);
|
||||||
|
|
||||||
|
bool isEmpty() const { return m_curve.isEmpty(); }
|
||||||
|
void addStartPoint(const QPointF& point);
|
||||||
|
void addPoint(const QPointF& point);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPainterPath m_curve;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentImageElement : public PDFPageContentElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PDFPageContentImageElement();
|
||||||
|
virtual ~PDFPageContentImageElement();
|
||||||
|
|
||||||
|
virtual PDFPageContentImageElement* clone() const override;
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual uint getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const override;
|
||||||
|
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||||
|
virtual QRectF getBoundingBox() const override;
|
||||||
|
virtual void setSize(QSizeF size);
|
||||||
|
virtual QString getDescription() const override;
|
||||||
|
|
||||||
|
const QByteArray& getContent() const;
|
||||||
|
void setContent(const QByteArray& newContent);
|
||||||
|
|
||||||
|
const QRectF& getRectangle() const;
|
||||||
|
void setRectangle(const QRectF& newRectangle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QRectF m_rectangle;
|
||||||
|
QByteArray m_content;
|
||||||
|
QImage m_image;
|
||||||
|
std::unique_ptr<QSvgRenderer> m_renderer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentElementTextBox : public PDFPageContentStyledElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~PDFPageContentElementTextBox() = default;
|
||||||
|
|
||||||
|
virtual PDFPageContentElementTextBox* clone() const override;
|
||||||
|
|
||||||
|
const QRectF& getRectangle() const { return m_rectangle; }
|
||||||
|
void setRectangle(const QRectF& newRectangle) { m_rectangle = newRectangle; }
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
virtual uint getManipulationMode(const QPointF& point,
|
||||||
|
PDFReal snapPointDistanceThreshold) const override;
|
||||||
|
|
||||||
|
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||||
|
virtual QRectF getBoundingBox() const override;
|
||||||
|
virtual void setSize(QSizeF size);
|
||||||
|
virtual QString getDescription() const override;
|
||||||
|
|
||||||
|
const QString& getText() const;
|
||||||
|
void setText(const QString& newText);
|
||||||
|
|
||||||
|
const QFont& getFont() const;
|
||||||
|
void setFont(const QFont& newFont);
|
||||||
|
|
||||||
|
PDFReal getAngle() const;
|
||||||
|
void setAngle(PDFReal newAngle);
|
||||||
|
|
||||||
|
const Qt::Alignment& getAlignment() const;
|
||||||
|
void setAlignment(const Qt::Alignment& newAlignment);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_text;
|
||||||
|
QRectF m_rectangle;
|
||||||
|
QFont m_font;
|
||||||
|
PDFReal m_angle = 0.0;
|
||||||
|
Qt::Alignment m_alignment = Qt::AlignCenter;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentElementManipulator : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
PDFPageContentElementManipulator(PDFPageContentScene* scene, QObject* parent);
|
||||||
|
|
||||||
|
enum class Operation
|
||||||
|
{
|
||||||
|
AlignTop,
|
||||||
|
AlignCenterVertically,
|
||||||
|
AlignBottom,
|
||||||
|
AlignLeft,
|
||||||
|
AlignCenterHorizontally,
|
||||||
|
AlignRight,
|
||||||
|
SetSameHeight,
|
||||||
|
SetSameWidth,
|
||||||
|
SetSameSize,
|
||||||
|
CenterHorizontally,
|
||||||
|
CenterVertically,
|
||||||
|
CenterHorAndVert,
|
||||||
|
LayoutVertically,
|
||||||
|
LayoutHorizontally,
|
||||||
|
LayoutForm,
|
||||||
|
LayoutGrid
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/// Returns true, if all elements are selected
|
||||||
|
/// \param ids Element ids
|
||||||
|
bool isAllSelected(const std::set<PDFInteger>& elementIds) const;
|
||||||
|
|
||||||
|
/// 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 selectAll();
|
||||||
|
void deselectAll();
|
||||||
|
|
||||||
|
bool isManipulationAllowed(PDFInteger pageIndex) const;
|
||||||
|
bool isManipulationInProgress() const { return m_isManipulationInProgress; }
|
||||||
|
|
||||||
|
void performOperation(Operation operation);
|
||||||
|
void performDeleteSelection();
|
||||||
|
|
||||||
|
void startManipulation(PDFInteger pageIndex,
|
||||||
|
const QPointF& startPoint,
|
||||||
|
const QPointF& currentPoint,
|
||||||
|
PDFReal snapPointDistanceThreshold);
|
||||||
|
|
||||||
|
void updateManipulation(PDFInteger pageIndex,
|
||||||
|
const QPointF& startPoint,
|
||||||
|
const QPointF& currentPoint);
|
||||||
|
|
||||||
|
void finishManipulation(PDFInteger pageIndex,
|
||||||
|
const QPointF& startPoint,
|
||||||
|
const QPointF& currentPoint,
|
||||||
|
bool createCopy);
|
||||||
|
|
||||||
|
void cancelManipulation();
|
||||||
|
|
||||||
|
void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const;
|
||||||
|
|
||||||
|
/// Returns bounding box of whole selection
|
||||||
|
QRectF getSelectionBoundingRect() const;
|
||||||
|
|
||||||
|
/// Returns page rectangle for the page
|
||||||
|
QRectF getPageMediaBox(PDFInteger pageIndex) const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void selectionChanged();
|
||||||
|
void stateChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void eraseSelectedElementById(PDFInteger id);
|
||||||
|
|
||||||
|
PDFPageContentScene* m_scene;
|
||||||
|
std::vector<PDFInteger> m_selection;
|
||||||
|
bool m_isManipulationInProgress;
|
||||||
|
std::vector<std::unique_ptr<PDFPageContentElement>> m_manipulatedElements;
|
||||||
|
std::map<PDFInteger, uint> m_manipulationModes;
|
||||||
|
QPointF m_lastUpdatedPoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDF4QTLIBSHARED_EXPORT PDFPageContentScene : public QObject,
|
||||||
|
public IDocumentDrawInterface,
|
||||||
|
public IDrawWidgetInputInterface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PDFPageContentScene(QObject* parent);
|
||||||
|
virtual ~PDFPageContentScene();
|
||||||
|
|
||||||
|
static constexpr PDFInteger INVALID_ELEMENT_ID = 0;
|
||||||
|
|
||||||
|
/// Add new element to page content scene, scene
|
||||||
|
/// takes ownership over the element.
|
||||||
|
/// \param element Element
|
||||||
|
void addElement(PDFPageContentElement* element);
|
||||||
|
|
||||||
|
/// Replaces element in the page content scene, scene
|
||||||
|
/// takes ownership over the element.
|
||||||
|
/// \param element Element
|
||||||
|
void replaceElement(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
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/// Returns true, if scene is empty
|
||||||
|
bool isEmpty() const { return m_elements.empty(); }
|
||||||
|
|
||||||
|
bool isActive() const;
|
||||||
|
void setActive(bool newIsActive);
|
||||||
|
|
||||||
|
/// Returns set of all element ids
|
||||||
|
std::set<PDFInteger> getElementIds() const;
|
||||||
|
|
||||||
|
/// Returns set of selected element ids
|
||||||
|
std::set<PDFInteger> getSelectedElementIds() const;
|
||||||
|
|
||||||
|
/// Returns set of involved pages
|
||||||
|
std::set<PDFInteger> getPageIndices() const;
|
||||||
|
|
||||||
|
/// Returns bounding box of elements on page
|
||||||
|
QRectF getBoundingBox(PDFInteger pageIndex) const;
|
||||||
|
|
||||||
|
/// Set selected items
|
||||||
|
void setSelectedElementIds(const std::set<PDFInteger>& selectedElementIds);
|
||||||
|
|
||||||
|
/// Removes elements specified in selection
|
||||||
|
/// \param selection Items to be removed
|
||||||
|
void removeElementsById(const std::vector<PDFInteger>& selection);
|
||||||
|
|
||||||
|
/// Performs manipulation of selected elements with manipulator
|
||||||
|
void performOperation(int operation);
|
||||||
|
|
||||||
|
/// Returns document (or nullptr)
|
||||||
|
const PDFDocument* getDocument() const;
|
||||||
|
|
||||||
|
// IDrawWidgetInputInterface interface
|
||||||
|
public:
|
||||||
|
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;
|
||||||
|
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
|
||||||
|
virtual void keyReleaseEvent(QWidget* widget, QKeyEvent* event) override;
|
||||||
|
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||||
|
virtual void wheelEvent(QWidget* widget, QWheelEvent* event) override;
|
||||||
|
virtual QString getTooltip() const override;
|
||||||
|
virtual const std::optional<QCursor>& getCursor() const override;
|
||||||
|
virtual int getInputPriority() const override;
|
||||||
|
|
||||||
|
virtual void drawPage(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
|
PDFWidget* widget() const;
|
||||||
|
void setWidget(PDFWidget* newWidget);
|
||||||
|
|
||||||
|
void drawElements(QPainter* painter,
|
||||||
|
PDFInteger pageIndex,
|
||||||
|
PDFTextLayoutGetter& layoutGetter,
|
||||||
|
const QMatrix& pagePointToDevicePointMatrix,
|
||||||
|
const PDFPrecompiledPage* compiledPage,
|
||||||
|
QList<PDFRenderError>& errors) const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/// This signal is emitted when scene has changed (including graphics)
|
||||||
|
void sceneChanged(bool graphicsOnly);
|
||||||
|
|
||||||
|
void selectionChanged();
|
||||||
|
|
||||||
|
/// Request to edit the elements
|
||||||
|
void editElementRequest(const std::set<PDFInteger>& elements);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct MouseEventInfo
|
||||||
|
{
|
||||||
|
std::set<PDFInteger> hoveredElementIds;
|
||||||
|
QPoint widgetMouseStartPos;
|
||||||
|
QPoint widgetMouseCurrentPos;
|
||||||
|
QElapsedTimer timer;
|
||||||
|
PDFInteger pageIndex = -1;
|
||||||
|
QPointF pagePos;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
};
|
||||||
|
|
||||||
|
PDFReal getSnapPointDistanceThreshold() const;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/// Updates mouse cursor
|
||||||
|
/// \param info Mouse event info
|
||||||
|
/// \param snapPointDistanceTreshold Snap point threshold
|
||||||
|
void updateMouseCursor(const MouseEventInfo& info, PDFReal snapPointDistanceThreshold);
|
||||||
|
|
||||||
|
/// Reaction on selection changed
|
||||||
|
void onSelectionChanged();
|
||||||
|
|
||||||
|
PDFInteger m_firstFreeId;
|
||||||
|
bool m_isActive;
|
||||||
|
PDFWidget* m_widget;
|
||||||
|
std::vector<std::unique_ptr<PDFPageContentElement>> m_elements;
|
||||||
|
std::optional<QCursor> m_cursor;
|
||||||
|
PDFPageContentElementManipulator m_manipulator;
|
||||||
|
MouseGrabInfo m_mouseGrabInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdf
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(pdf::PDFPageContentElementManipulator::SelectionModes)
|
||||||
|
|
||||||
|
#endif // PDFPAGECONTENTELEMENTS_H
|
|
@ -348,6 +348,15 @@ void PDFSignatureVerificationResult::addCertificateQualifiedStatementNotVerified
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addCertificateUnableToGetCRLWarning()
|
||||||
|
{
|
||||||
|
if (!m_flags.testFlag(Warning_Certificate_UnableToGetCRL))
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Warning_Certificate_UnableToGetCRL);
|
||||||
|
m_warnings << PDFTranslationContext::tr("Unable to get CRL.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PDFSignatureVerificationResult::setSignatureFieldQualifiedName(const QString& signatureFieldQualifiedName)
|
void PDFSignatureVerificationResult::setSignatureFieldQualifiedName(const QString& signatureFieldQualifiedName)
|
||||||
{
|
{
|
||||||
m_signatureFieldQualifiedName = signatureFieldQualifiedName;
|
m_signatureFieldQualifiedName = signatureFieldQualifiedName;
|
||||||
|
@ -977,6 +986,15 @@ int PDFSignatureHandler_ETSI_base::verifyCallback(int ok, X509_STORE_CTX* contex
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case X509_V_ERR_UNABLE_TO_GET_CRL:
|
||||||
|
{
|
||||||
|
// We will treat this as only warning. It means that
|
||||||
|
// CRL cannot be downloaded or other error occured.
|
||||||
|
s_ETSI_currentResult->addCertificateUnableToGetCRLWarning();
|
||||||
|
X509_STORE_CTX_set_error(context, X509_V_OK);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
|
case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
|
||||||
{
|
{
|
||||||
// We must handle all critical extensions manually
|
// We must handle all critical extensions manually
|
||||||
|
|
|
@ -319,6 +319,7 @@ public:
|
||||||
Warning_Signature_NotCoveredBytes = 0x00200000, ///< Some bytes in source data are not covered by signature
|
Warning_Signature_NotCoveredBytes = 0x00200000, ///< Some bytes in source data are not covered by signature
|
||||||
Warning_Certificate_CRLValidityTimeExpired = 0x00400000, ///< Certificate revocation list was not checked, because it's validity expired
|
Warning_Certificate_CRLValidityTimeExpired = 0x00400000, ///< Certificate revocation list was not checked, because it's validity expired
|
||||||
Warning_Certificate_QualifiedStatement = 0x00800000, ///< Qualified certificate statement not verified
|
Warning_Certificate_QualifiedStatement = 0x00800000, ///< Qualified certificate statement not verified
|
||||||
|
Warning_Certificate_UnableToGetCRL = 0x01000000, ///< Unable to get CRL
|
||||||
|
|
||||||
Error_Certificates_Mask = Error_Certificate_Invalid | Error_Certificate_NoSignatures | Error_Certificate_Missing | Error_Certificate_Generic |
|
Error_Certificates_Mask = Error_Certificate_Invalid | Error_Certificate_NoSignatures | Error_Certificate_Missing | Error_Certificate_Generic |
|
||||||
Error_Certificate_Expired | Error_Certificate_SelfSigned | Error_Certificate_SelfSignedChain | Error_Certificate_TrustedNotFound |
|
Error_Certificate_Expired | Error_Certificate_SelfSigned | Error_Certificate_SelfSignedChain | Error_Certificate_TrustedNotFound |
|
||||||
|
@ -327,7 +328,7 @@ public:
|
||||||
Error_Signatures_Mask = Error_Signature_Invalid | Error_Signature_SourceCertificateMissing | Error_Signature_NoSignaturesFound |
|
Error_Signatures_Mask = Error_Signature_Invalid | Error_Signature_SourceCertificateMissing | Error_Signature_NoSignaturesFound |
|
||||||
Error_Signature_DigestFailure | Error_Signature_DataOther | Error_Signature_DataCoveredBySignatureMissing,
|
Error_Signature_DigestFailure | Error_Signature_DataOther | Error_Signature_DataCoveredBySignatureMissing,
|
||||||
|
|
||||||
Warning_Certificates_Mask = Warning_Certificate_CRLValidityTimeExpired | Warning_Certificate_QualifiedStatement,
|
Warning_Certificates_Mask = Warning_Certificate_CRLValidityTimeExpired | Warning_Certificate_QualifiedStatement | Warning_Certificate_UnableToGetCRL,
|
||||||
Warning_Signatures_Mask = Warning_Signature_NotCoveredBytes,
|
Warning_Signatures_Mask = Warning_Signature_NotCoveredBytes,
|
||||||
|
|
||||||
Warnings_Mask = Warning_Certificates_Mask | Warning_Signatures_Mask
|
Warnings_Mask = Warning_Certificates_Mask | Warning_Signatures_Mask
|
||||||
|
@ -361,6 +362,7 @@ public:
|
||||||
void addSignatureNotCoveredBytesWarning(PDFInteger count);
|
void addSignatureNotCoveredBytesWarning(PDFInteger count);
|
||||||
void addCertificateCRLValidityTimeExpiredWarning();
|
void addCertificateCRLValidityTimeExpiredWarning();
|
||||||
void addCertificateQualifiedStatementNotVerifiedWarning();
|
void addCertificateQualifiedStatementNotVerifiedWarning();
|
||||||
|
void addCertificateUnableToGetCRLWarning();
|
||||||
|
|
||||||
bool isValid() const { return hasFlag(OK); }
|
bool isValid() const { return hasFlag(OK); }
|
||||||
bool isCertificateValid() const { return hasFlag(Certificate_OK); }
|
bool isCertificateValid() const { return hasFlag(Certificate_OK); }
|
||||||
|
|
|
@ -383,10 +383,9 @@ QByteArray PDFFlateDecodeFilter::apply(const QByteArray& data,
|
||||||
return predictor.apply(uncompress(data));
|
return predictor.apply(uncompress(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray PDFFlateDecodeFilter::recompress(const QByteArray& data)
|
QByteArray PDFFlateDecodeFilter::compress(const QByteArray& decompressedData)
|
||||||
{
|
{
|
||||||
QByteArray result;
|
QByteArray result;
|
||||||
QByteArray decompressedData = uncompress(data);
|
|
||||||
|
|
||||||
z_stream stream = { };
|
z_stream stream = { };
|
||||||
stream.next_in = const_cast<Bytef*>(convertByteArrayToUcharPtr(decompressedData));
|
stream.next_in = const_cast<Bytef*>(convertByteArrayToUcharPtr(decompressedData));
|
||||||
|
@ -431,13 +430,19 @@ QByteArray PDFFlateDecodeFilter::recompress(const QByteArray& data)
|
||||||
errorMessage = PDFTranslationContext::tr("zlib code: %1").arg(error);
|
errorMessage = PDFTranslationContext::tr("zlib code: %1").arg(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw PDFException(PDFTranslationContext::tr("Error decompressing by flate method: %1").arg(errorMessage));
|
throw PDFException(PDFTranslationContext::tr("Error compressing by flate method: %1").arg(errorMessage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray PDFFlateDecodeFilter::recompress(const QByteArray& data)
|
||||||
|
{
|
||||||
|
QByteArray decompressedData = uncompress(data);
|
||||||
|
return compress(decompressedData);
|
||||||
|
}
|
||||||
|
|
||||||
PDFInteger PDFFlateDecodeFilter::getStreamDataLength(const QByteArray& data, PDFInteger offset) const
|
PDFInteger PDFFlateDecodeFilter::getStreamDataLength(const QByteArray& data, PDFInteger offset) const
|
||||||
{
|
{
|
||||||
if (offset < 0 || offset >= data.size())
|
if (offset < 0 || offset >= data.size())
|
||||||
|
|
|
@ -215,6 +215,10 @@ public:
|
||||||
|
|
||||||
/// Recompresses data. So, first, data are decompressed, and then
|
/// Recompresses data. So, first, data are decompressed, and then
|
||||||
/// recompressed again with maximal compress ratio possible.
|
/// recompressed again with maximal compress ratio possible.
|
||||||
|
/// \param data Uncompressed data to be compressed
|
||||||
|
static QByteArray compress(const QByteArray& decompressedData);
|
||||||
|
|
||||||
|
/// Compress data with maximal compress ratio possible.
|
||||||
/// \param data Compressed data to be recompressed
|
/// \param data Compressed data to be recompressed
|
||||||
static QByteArray recompress(const QByteArray& data);
|
static QByteArray recompress(const QByteArray& data);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,949 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "pdftexteditpseudowidget.h"
|
||||||
|
#include "pdfpainterutils.h"
|
||||||
|
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QClipboard>
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
PDFTextEditPseudowidget::PDFTextEditPseudowidget(PDFFormField::FieldFlags flags) :
|
||||||
|
m_flags(flags),
|
||||||
|
m_selectionStart(0),
|
||||||
|
m_selectionEnd(0),
|
||||||
|
m_positionCursor(0),
|
||||||
|
m_maxTextLength(0)
|
||||||
|
{
|
||||||
|
m_textLayout.setCacheEnabled(true);
|
||||||
|
m_passwordReplacementCharacter = QApplication::style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(widget);
|
||||||
|
constexpr QKeySequence::StandardKey acceptedKeys[] = { QKeySequence::Delete, QKeySequence::Cut, QKeySequence::Copy, QKeySequence::Paste,
|
||||||
|
QKeySequence::SelectAll, QKeySequence::MoveToNextChar, QKeySequence::MoveToPreviousChar,
|
||||||
|
QKeySequence::MoveToNextWord, QKeySequence::MoveToPreviousWord, QKeySequence::MoveToNextLine,
|
||||||
|
QKeySequence::MoveToPreviousLine, QKeySequence::MoveToStartOfLine, QKeySequence::MoveToEndOfLine,
|
||||||
|
QKeySequence::MoveToStartOfBlock, QKeySequence::MoveToEndOfBlock, QKeySequence::MoveToStartOfDocument,
|
||||||
|
QKeySequence::MoveToEndOfDocument, QKeySequence::SelectNextChar, QKeySequence::SelectPreviousChar,
|
||||||
|
QKeySequence::SelectNextWord, QKeySequence::SelectPreviousWord, QKeySequence::SelectNextLine,
|
||||||
|
QKeySequence::SelectPreviousLine, QKeySequence::SelectStartOfLine, QKeySequence::SelectEndOfLine,
|
||||||
|
QKeySequence::SelectStartOfBlock, QKeySequence::SelectEndOfBlock, QKeySequence::SelectStartOfDocument,
|
||||||
|
QKeySequence::SelectEndOfDocument, QKeySequence::DeleteStartOfWord, QKeySequence::DeleteEndOfWord,
|
||||||
|
QKeySequence::DeleteEndOfLine, QKeySequence::Deselect, QKeySequence::DeleteCompleteLine, QKeySequence::Backspace };
|
||||||
|
|
||||||
|
if (std::any_of(std::begin(acceptedKeys), std::end(acceptedKeys), [event](QKeySequence::StandardKey standardKey) { return event == standardKey; }))
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event->key())
|
||||||
|
{
|
||||||
|
case Qt::Key_Direction_L:
|
||||||
|
case Qt::Key_Direction_R:
|
||||||
|
case Qt::Key_Up:
|
||||||
|
case Qt::Key_Down:
|
||||||
|
case Qt::Key_Left:
|
||||||
|
case Qt::Key_Right:
|
||||||
|
event->accept();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!event->text().isEmpty())
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
for (const QChar& character : event->text())
|
||||||
|
{
|
||||||
|
if (!character.isPrint())
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(widget);
|
||||||
|
|
||||||
|
/*
|
||||||
|
We will support following key sequences:
|
||||||
|
Delete
|
||||||
|
Cut,
|
||||||
|
Copy,
|
||||||
|
Paste,
|
||||||
|
SelectAll,
|
||||||
|
MoveToNextChar,
|
||||||
|
MoveToPreviousChar,
|
||||||
|
MoveToNextWord,
|
||||||
|
MoveToPreviousWord,
|
||||||
|
MoveToNextLine,
|
||||||
|
MoveToPreviousLine,
|
||||||
|
MoveToStartOfLine,
|
||||||
|
MoveToEndOfLine,
|
||||||
|
MoveToStartOfBlock,
|
||||||
|
MoveToEndOfBlock,
|
||||||
|
MoveToStartOfDocument,
|
||||||
|
MoveToEndOfDocument,
|
||||||
|
SelectNextChar,
|
||||||
|
SelectPreviousChar,
|
||||||
|
SelectNextWord,
|
||||||
|
SelectPreviousWord,
|
||||||
|
SelectNextLine,
|
||||||
|
SelectPreviousLine,
|
||||||
|
SelectStartOfLine,
|
||||||
|
SelectEndOfLine,
|
||||||
|
SelectStartOfBlock,
|
||||||
|
SelectEndOfBlock,
|
||||||
|
SelectStartOfDocument,
|
||||||
|
SelectEndOfDocument,
|
||||||
|
DeleteStartOfWord,
|
||||||
|
DeleteEndOfWord,
|
||||||
|
DeleteEndOfLine,
|
||||||
|
Deselect,
|
||||||
|
DeleteCompleteLine,
|
||||||
|
Backspace,
|
||||||
|
* */
|
||||||
|
|
||||||
|
event->accept();
|
||||||
|
|
||||||
|
if (event == QKeySequence::Delete)
|
||||||
|
{
|
||||||
|
performDelete();
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::Cut)
|
||||||
|
{
|
||||||
|
performCut();
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::Copy)
|
||||||
|
{
|
||||||
|
performCopy();
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::Paste)
|
||||||
|
{
|
||||||
|
performPaste();
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::SelectAll)
|
||||||
|
{
|
||||||
|
setSelection(0, getTextLength());
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::MoveToNextChar)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorCharacterForward(), false);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::MoveToPreviousChar)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorCharacterBackward(), false);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::MoveToNextWord)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorWordForward(), false);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::MoveToPreviousWord)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorWordBackward(), false);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::MoveToNextLine)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorLineDown(), false);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::MoveToPreviousLine)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorLineUp(), false);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorLineStart(), false);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorLineEnd(), false);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::MoveToStartOfDocument)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorDocumentStart(), false);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::MoveToEndOfDocument)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorDocumentEnd(), false);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::SelectNextChar)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorCharacterForward(), true);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::SelectPreviousChar)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorCharacterBackward(), true);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::SelectNextWord)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorWordForward(), true);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::SelectPreviousWord)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorWordBackward(), true);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::SelectNextLine)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorLineDown(), true);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::SelectPreviousLine)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorLineUp(), true);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorLineStart(), true);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorLineEnd(), true);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::SelectStartOfDocument)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorDocumentStart(), true);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::SelectEndOfDocument)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorDocumentEnd(), true);
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::DeleteStartOfWord)
|
||||||
|
{
|
||||||
|
if (!isReadonly())
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorWordBackward(), true);
|
||||||
|
performRemoveSelectedText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::DeleteEndOfWord)
|
||||||
|
{
|
||||||
|
if (!isReadonly())
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorWordForward(), true);
|
||||||
|
performRemoveSelectedText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::DeleteEndOfLine)
|
||||||
|
{
|
||||||
|
if (!isReadonly())
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorLineEnd(), true);
|
||||||
|
performRemoveSelectedText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::Deselect)
|
||||||
|
{
|
||||||
|
clearSelection();
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::DeleteCompleteLine)
|
||||||
|
{
|
||||||
|
if (!isReadonly())
|
||||||
|
{
|
||||||
|
m_selectionStart = getCurrentLineTextStart();
|
||||||
|
m_selectionEnd = getCurrentLineTextEnd();
|
||||||
|
performRemoveSelectedText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event == QKeySequence::Backspace || event->key() == Qt::Key_Backspace)
|
||||||
|
{
|
||||||
|
performBackspace();
|
||||||
|
}
|
||||||
|
else if (event->key() == Qt::Key_Direction_L)
|
||||||
|
{
|
||||||
|
QTextOption option = m_textLayout.textOption();
|
||||||
|
option.setTextDirection(Qt::LeftToRight);
|
||||||
|
m_textLayout.setTextOption(qMove(option));
|
||||||
|
updateTextLayout();
|
||||||
|
}
|
||||||
|
else if (event->key() == Qt::Key_Direction_R)
|
||||||
|
{
|
||||||
|
QTextOption option = m_textLayout.textOption();
|
||||||
|
option.setTextDirection(Qt::LeftToRight);
|
||||||
|
m_textLayout.setTextOption(qMove(option));
|
||||||
|
updateTextLayout();
|
||||||
|
}
|
||||||
|
else if (event->key() == Qt::Key_Up)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorLineUp(), event->modifiers().testFlag(Qt::ShiftModifier));
|
||||||
|
}
|
||||||
|
else if (event->key() == Qt::Key_Down)
|
||||||
|
{
|
||||||
|
setCursorPosition(getCursorLineDown(), event->modifiers().testFlag(Qt::ShiftModifier));
|
||||||
|
}
|
||||||
|
else if (event->key() == Qt::Key_Left)
|
||||||
|
{
|
||||||
|
const int position = (event->modifiers().testFlag(Qt::ControlModifier)) ? getCursorWordBackward() : getCursorCharacterBackward();
|
||||||
|
setCursorPosition(position, event->modifiers().testFlag(Qt::ShiftModifier));
|
||||||
|
}
|
||||||
|
else if (event->key() == Qt::Key_Right)
|
||||||
|
{
|
||||||
|
const int position = (event->modifiers().testFlag(Qt::ControlModifier)) ? getCursorWordForward() : getCursorCharacterForward();
|
||||||
|
setCursorPosition(position, event->modifiers().testFlag(Qt::ShiftModifier));
|
||||||
|
}
|
||||||
|
else if (isMultiline() && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return))
|
||||||
|
{
|
||||||
|
performInsertText(QString::fromUtf16(u"\u2028"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QString text = event->text();
|
||||||
|
if (!text.isEmpty())
|
||||||
|
{
|
||||||
|
performInsertText(text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::setSelection(int startPosition, int selectionLength)
|
||||||
|
{
|
||||||
|
if (selectionLength > 0)
|
||||||
|
{
|
||||||
|
// We are selecting to the right
|
||||||
|
m_selectionStart = startPosition;
|
||||||
|
m_selectionEnd = qMin(startPosition + selectionLength, getTextLength());
|
||||||
|
m_positionCursor = m_selectionEnd;
|
||||||
|
}
|
||||||
|
else if (selectionLength < 0)
|
||||||
|
{
|
||||||
|
// We are selecting to the left
|
||||||
|
m_selectionStart = qMax(startPosition + selectionLength, 0);
|
||||||
|
m_selectionEnd = startPosition;
|
||||||
|
m_positionCursor = m_selectionStart;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Clear the selection
|
||||||
|
m_selectionStart = 0;
|
||||||
|
m_selectionEnd = 0;
|
||||||
|
m_positionCursor = startPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::setCursorPosition(int position, bool select)
|
||||||
|
{
|
||||||
|
if (select)
|
||||||
|
{
|
||||||
|
const bool isTextSelected = this->isTextSelected();
|
||||||
|
const bool isCursorAtStartOfSelection = isTextSelected && m_selectionStart == m_positionCursor;
|
||||||
|
const bool isCursorAtEndOfSelection = isTextSelected && m_selectionEnd == m_positionCursor;
|
||||||
|
|
||||||
|
// Do we have selected text, and cursor is at the end of selected text?
|
||||||
|
// In this case, we must preserve start of the selection (we are manipulating
|
||||||
|
// with the end of selection.
|
||||||
|
if (isCursorAtEndOfSelection)
|
||||||
|
{
|
||||||
|
m_selectionStart = qMin(m_selectionStart, position);
|
||||||
|
m_selectionEnd = qMax(m_selectionStart, position);
|
||||||
|
}
|
||||||
|
else if (isCursorAtStartOfSelection)
|
||||||
|
{
|
||||||
|
// We must preserve end of the text selection, because we are manipulating
|
||||||
|
// with start of text selection.
|
||||||
|
m_selectionStart = qMin(m_selectionEnd, position);
|
||||||
|
m_selectionEnd = qMax(m_selectionEnd, position);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Otherwise we are manipulating with cursor
|
||||||
|
m_selectionStart = qMin(m_positionCursor, position);
|
||||||
|
m_selectionEnd = qMax(m_positionCursor, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Why we are clearing text selection, even if we doesn't have it?
|
||||||
|
// We can have, for example m_selectionStart == m_selectionEnd == 3,
|
||||||
|
// and we want to have it both zero.
|
||||||
|
if (!select || !isTextSelected())
|
||||||
|
{
|
||||||
|
clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_positionCursor = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::setText(const QString& text)
|
||||||
|
{
|
||||||
|
clearSelection();
|
||||||
|
m_editText = text;
|
||||||
|
setCursorPosition(getPositionEnd(), false);
|
||||||
|
updateTextLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::setAppearance(const PDFAnnotationDefaultAppearance& appearance, Qt::Alignment textAlignment, QRectF rect, int maxTextLength)
|
||||||
|
{
|
||||||
|
// Set appearance
|
||||||
|
qreal fontSize = appearance.getFontSize();
|
||||||
|
if (qFuzzyIsNull(fontSize))
|
||||||
|
{
|
||||||
|
fontSize = rect.height();
|
||||||
|
}
|
||||||
|
|
||||||
|
QFont font(appearance.getFontName());
|
||||||
|
font.setHintingPreference(QFont::PreferNoHinting);
|
||||||
|
font.setPixelSize(qCeil(fontSize));
|
||||||
|
font.setStyleStrategy(QFont::ForceOutline);
|
||||||
|
m_textLayout.setFont(font);
|
||||||
|
|
||||||
|
QTextOption option = m_textLayout.textOption();
|
||||||
|
option.setWrapMode(isMultiline() ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap);
|
||||||
|
option.setAlignment(textAlignment);
|
||||||
|
option.setUseDesignMetrics(true);
|
||||||
|
m_textLayout.setTextOption(option);
|
||||||
|
|
||||||
|
m_textColor = appearance.getFontColor();
|
||||||
|
if (!m_textColor.isValid())
|
||||||
|
{
|
||||||
|
m_textColor = Qt::black;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_maxTextLength = maxTextLength;
|
||||||
|
m_widgetRect = rect;
|
||||||
|
updateTextLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::setAppearance(const QFont& font,
|
||||||
|
Qt::Alignment textAlignment,
|
||||||
|
QRectF rect,
|
||||||
|
int maxTextLength,
|
||||||
|
QColor textColor)
|
||||||
|
{
|
||||||
|
// Set appearance
|
||||||
|
m_textLayout.setFont(font);
|
||||||
|
|
||||||
|
QTextOption option = m_textLayout.textOption();
|
||||||
|
option.setWrapMode(isMultiline() ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap);
|
||||||
|
option.setAlignment(textAlignment);
|
||||||
|
option.setUseDesignMetrics(true);
|
||||||
|
m_textLayout.setTextOption(option);
|
||||||
|
|
||||||
|
m_textColor = textColor;
|
||||||
|
if (!m_textColor.isValid())
|
||||||
|
{
|
||||||
|
m_textColor = Qt::black;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_maxTextLength = maxTextLength;
|
||||||
|
m_widgetRect = rect;
|
||||||
|
updateTextLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::performCut()
|
||||||
|
{
|
||||||
|
if (isReadonly())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
performCopy();
|
||||||
|
performRemoveSelectedText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::performCopy()
|
||||||
|
{
|
||||||
|
if (isTextSelected() && !isPassword())
|
||||||
|
{
|
||||||
|
QApplication::clipboard()->setText(getSelectedText(), QClipboard::Clipboard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::performPaste()
|
||||||
|
{
|
||||||
|
// We always insert text, even if it is empty. Because we want
|
||||||
|
// to erase selected text.
|
||||||
|
performInsertText(QApplication::clipboard()->text(QClipboard::Clipboard));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::performClear()
|
||||||
|
{
|
||||||
|
if (isReadonly())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
performSelectAll();
|
||||||
|
performRemoveSelectedText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::performSelectAll()
|
||||||
|
{
|
||||||
|
m_selectionStart = getPositionStart();
|
||||||
|
m_selectionEnd = getPositionEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::performBackspace()
|
||||||
|
{
|
||||||
|
if (isReadonly())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have selection, then delete selected text. If we do not have
|
||||||
|
// selection, then we delete previous character.
|
||||||
|
if (!isTextSelected())
|
||||||
|
{
|
||||||
|
setCursorPosition(m_textLayout.previousCursorPosition(m_positionCursor, QTextLayout::SkipCharacters), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
performRemoveSelectedText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::performDelete()
|
||||||
|
{
|
||||||
|
if (isReadonly())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have selection, then delete selected text. If we do not have
|
||||||
|
// selection, then we delete previous character.
|
||||||
|
if (!isTextSelected())
|
||||||
|
{
|
||||||
|
setCursorPosition(m_textLayout.nextCursorPosition(m_positionCursor, QTextLayout::SkipCharacters), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
performRemoveSelectedText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::performRemoveSelectedText()
|
||||||
|
{
|
||||||
|
if (isTextSelected())
|
||||||
|
{
|
||||||
|
m_editText.remove(m_selectionStart, getSelectionLength());
|
||||||
|
setCursorPosition(m_selectionStart, false);
|
||||||
|
clearSelection();
|
||||||
|
updateTextLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::performInsertText(const QString& text)
|
||||||
|
{
|
||||||
|
if (isReadonly())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert text at the cursor
|
||||||
|
performRemoveSelectedText();
|
||||||
|
m_editText.insert(m_positionCursor, text);
|
||||||
|
setCursorPosition(m_positionCursor + text.length(), false);
|
||||||
|
updateTextLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMatrix PDFTextEditPseudowidget::createTextBoxTransformMatrix(bool edit) const
|
||||||
|
{
|
||||||
|
QMatrix matrix;
|
||||||
|
|
||||||
|
matrix.translate(m_widgetRect.left(), m_widgetRect.bottom());
|
||||||
|
matrix.scale(1.0, -1.0);
|
||||||
|
|
||||||
|
if (edit && !isComb() && m_textLayout.isValidCursorPosition(m_positionCursor))
|
||||||
|
{
|
||||||
|
// Jakub Melka: we must scroll the control, so cursor is always
|
||||||
|
// visible in the widget area. If we are not editing, this not the
|
||||||
|
// case, because we always show the text from the beginning.
|
||||||
|
|
||||||
|
const QTextLine line = m_textLayout.lineForTextPosition(m_positionCursor);
|
||||||
|
if (line.isValid())
|
||||||
|
{
|
||||||
|
const qreal xCursorPosition = line.cursorToX(m_positionCursor);
|
||||||
|
if (xCursorPosition >= m_widgetRect.width())
|
||||||
|
{
|
||||||
|
const qreal delta = xCursorPosition - m_widgetRect.width();
|
||||||
|
matrix.translate(-delta, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check, if we aren't outside of y position
|
||||||
|
const qreal lineSpacing = line.leadingIncluded() ? line.height() : line.leading() + line.height();
|
||||||
|
const qreal lineBottom = lineSpacing * (line.lineNumber() + 1);
|
||||||
|
|
||||||
|
if (lineBottom >= m_widgetRect.height())
|
||||||
|
{
|
||||||
|
const qreal delta = lineBottom - m_widgetRect.height();
|
||||||
|
matrix.translate(0.0, -delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isMultiline() && !isComb())
|
||||||
|
{
|
||||||
|
// If text is single line, then adjust text position to the vertical center
|
||||||
|
QTextLine textLine = m_textLayout.lineAt(0);
|
||||||
|
if (textLine.isValid())
|
||||||
|
{
|
||||||
|
const qreal lineSpacing = textLine.leadingIncluded() ? textLine.height() : textLine.leading() + textLine.height();
|
||||||
|
const qreal textBoxHeight = m_widgetRect.height();
|
||||||
|
|
||||||
|
if (lineSpacing < textBoxHeight)
|
||||||
|
{
|
||||||
|
const qreal delta = (textBoxHeight - lineSpacing) * 0.5;
|
||||||
|
matrix.translate(0.0, delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> PDFTextEditPseudowidget::getCursorPositions() const
|
||||||
|
{
|
||||||
|
std::vector<int> result;
|
||||||
|
result.reserve(m_editText.length());
|
||||||
|
result.push_back(0);
|
||||||
|
|
||||||
|
int currentPos = 0;
|
||||||
|
while (currentPos < m_editText.length())
|
||||||
|
{
|
||||||
|
currentPos = m_textLayout.nextCursorPosition(currentPos, QTextLayout::SkipCharacters);
|
||||||
|
result.push_back(currentPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::draw(AnnotationDrawParameters& parameters, bool edit) const
|
||||||
|
{
|
||||||
|
pdf::PDFPainterStateGuard guard(parameters.painter);
|
||||||
|
|
||||||
|
if (parameters.annotation)
|
||||||
|
{
|
||||||
|
parameters.boundingRectangle = parameters.annotation->getRectangle();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPalette palette = QApplication::palette();
|
||||||
|
|
||||||
|
auto getAdjustedColor = [¶meters](QColor color)
|
||||||
|
{
|
||||||
|
if (parameters.invertColors)
|
||||||
|
{
|
||||||
|
return invertColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
};
|
||||||
|
|
||||||
|
QPainter* painter = parameters.painter;
|
||||||
|
|
||||||
|
if (edit)
|
||||||
|
{
|
||||||
|
pdf::PDFPainterStateGuard guard(painter);
|
||||||
|
painter->setPen(getAdjustedColor(Qt::black));
|
||||||
|
painter->setBrush(Qt::NoBrush);
|
||||||
|
painter->drawRect(parameters.boundingRectangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->setClipRect(parameters.boundingRectangle, Qt::IntersectClip);
|
||||||
|
painter->setWorldMatrix(createTextBoxTransformMatrix(edit), true);
|
||||||
|
painter->setPen(getAdjustedColor(Qt::black));
|
||||||
|
|
||||||
|
if (isComb())
|
||||||
|
{
|
||||||
|
const qreal combCount = qMax(m_maxTextLength, 1);
|
||||||
|
qreal combWidth = m_widgetRect.width() / combCount;
|
||||||
|
QRectF combRect(0.0, 0.0, combWidth, m_widgetRect.height());
|
||||||
|
painter->setFont(m_textLayout.font());
|
||||||
|
|
||||||
|
QColor textColor = getAdjustedColor(m_textColor);
|
||||||
|
QColor highlightTextColor = getAdjustedColor(palette.color(QPalette::HighlightedText));
|
||||||
|
QColor highlightColor = getAdjustedColor(palette.color(QPalette::Highlight));
|
||||||
|
|
||||||
|
std::vector<int> positions = getCursorPositions();
|
||||||
|
for (size_t i = 1; i < positions.size(); ++i)
|
||||||
|
{
|
||||||
|
if (positions[i - 1] >= m_selectionStart && positions[i] - 1 < m_selectionEnd)
|
||||||
|
{
|
||||||
|
// We are in text selection
|
||||||
|
painter->fillRect(combRect, highlightColor);
|
||||||
|
painter->setPen(highlightTextColor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We are not in text selection
|
||||||
|
painter->setPen(textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
int length = positions[i] - positions[i - 1];
|
||||||
|
QString text = m_displayText.mid(positions[i - 1], length);
|
||||||
|
painter->drawText(combRect, Qt::AlignCenter, text);
|
||||||
|
|
||||||
|
// Draw the cursor?
|
||||||
|
if (edit && m_positionCursor >= positions[i - 1] && m_positionCursor < positions[i])
|
||||||
|
{
|
||||||
|
QRectF cursorRect(combRect.left(), combRect.bottom() - 1, combRect.width(), 1);
|
||||||
|
painter->fillRect(cursorRect, textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
combRect.translate(combWidth, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the cursor onto next unfilled cell?
|
||||||
|
if (edit && m_positionCursor == getPositionEnd())
|
||||||
|
{
|
||||||
|
QRectF cursorRect(combRect.left(), combRect.bottom() - 1, combRect.width(), 1);
|
||||||
|
painter->fillRect(cursorRect, textColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QVector<QTextLayout::FormatRange> selections;
|
||||||
|
|
||||||
|
QTextLayout::FormatRange defaultFormat;
|
||||||
|
defaultFormat.start = getPositionStart();
|
||||||
|
defaultFormat.length = getTextLength();
|
||||||
|
defaultFormat.format.clearBackground();
|
||||||
|
defaultFormat.format.setForeground(QBrush(getAdjustedColor(m_textColor), Qt::SolidPattern));
|
||||||
|
|
||||||
|
// If we are editing, draw selections
|
||||||
|
if (edit && isTextSelected())
|
||||||
|
{
|
||||||
|
QTextLayout::FormatRange before = defaultFormat;
|
||||||
|
QTextLayout::FormatRange after = defaultFormat;
|
||||||
|
|
||||||
|
before.start = getPositionStart();
|
||||||
|
before.length = m_selectionStart;
|
||||||
|
after.start = m_selectionEnd;
|
||||||
|
after.length = getTextLength() - m_selectionEnd;
|
||||||
|
|
||||||
|
QTextLayout::FormatRange selectedFormat = defaultFormat;
|
||||||
|
selectedFormat.start = m_selectionStart;
|
||||||
|
selectedFormat.length = getSelectionLength();
|
||||||
|
selectedFormat.format.setForeground(QBrush(getAdjustedColor(palette.color(QPalette::HighlightedText)), Qt::SolidPattern));
|
||||||
|
selectedFormat.format.setBackground(QBrush(getAdjustedColor(palette.color(QPalette::Highlight)), Qt::SolidPattern));
|
||||||
|
|
||||||
|
selections = { before, selectedFormat, after};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
selections.push_back(defaultFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw text
|
||||||
|
m_textLayout.draw(painter, QPointF(0.0, 0.0), selections, QRectF());
|
||||||
|
|
||||||
|
// If we are editing, also draw text
|
||||||
|
if (edit && !isReadonly())
|
||||||
|
{
|
||||||
|
m_textLayout.drawCursor(painter, QPointF(0.0, 0.0), m_positionCursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFTextEditPseudowidget::getCursorPositionFromWidgetPosition(const QPointF& point, bool edit) const
|
||||||
|
{
|
||||||
|
QMatrix textBoxSpaceToPageSpace = createTextBoxTransformMatrix(edit);
|
||||||
|
QMatrix pageSpaceToTextBoxSpace = textBoxSpaceToPageSpace.inverted();
|
||||||
|
|
||||||
|
QPointF textBoxPoint = pageSpaceToTextBoxSpace.map(point);
|
||||||
|
|
||||||
|
if (isComb())
|
||||||
|
{
|
||||||
|
// If it is comb, then characters are spaced equidistantly
|
||||||
|
const qreal x = qBound(0.0, textBoxPoint.x(), m_widgetRect.width());
|
||||||
|
const size_t position = qFloor(x * qreal(m_maxTextLength) / qreal(m_widgetRect.width()));
|
||||||
|
std::vector<int> positions = getCursorPositions();
|
||||||
|
if (position < positions.size())
|
||||||
|
{
|
||||||
|
return positions[position];
|
||||||
|
}
|
||||||
|
|
||||||
|
return positions.back();
|
||||||
|
}
|
||||||
|
else if (m_textLayout.lineCount() > 0)
|
||||||
|
{
|
||||||
|
QTextLine line;
|
||||||
|
qreal yPos = 0.0;
|
||||||
|
|
||||||
|
// Find line under cursor
|
||||||
|
for (int i = 0; i < m_textLayout.lineCount(); ++i)
|
||||||
|
{
|
||||||
|
QTextLine currentLine = m_textLayout.lineAt(i);
|
||||||
|
const qreal lineSpacing = currentLine.leadingIncluded() ? currentLine.height() : currentLine.leading() + currentLine.height();
|
||||||
|
const qreal yNextPos = yPos + lineSpacing;
|
||||||
|
|
||||||
|
if (textBoxPoint.y() >= yPos && textBoxPoint.y() < yNextPos)
|
||||||
|
{
|
||||||
|
line = currentLine;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
yPos = yNextPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no line is found, select last line
|
||||||
|
if (!line.isValid())
|
||||||
|
{
|
||||||
|
if (textBoxPoint.y() < 0.0)
|
||||||
|
{
|
||||||
|
line = m_textLayout.lineAt(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line = m_textLayout.lineAt(m_textLayout.lineCount() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return line.xToCursor(textBoxPoint.x(), QTextLine::CursorBetweenCharacters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFTextEditPseudowidget::updateTextLayout()
|
||||||
|
{
|
||||||
|
// Prepare display text
|
||||||
|
if (isPassword())
|
||||||
|
{
|
||||||
|
m_displayText.resize(m_editText.length(), m_passwordReplacementCharacter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_displayText = m_editText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform text layout
|
||||||
|
m_textLayout.clearLayout();
|
||||||
|
m_textLayout.setText(m_displayText);
|
||||||
|
m_textLayout.beginLayout();
|
||||||
|
|
||||||
|
QPointF textLinePosition(0.0, 0.0);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
QTextLine textLine = m_textLayout.createLine();
|
||||||
|
if (!textLine.isValid())
|
||||||
|
{
|
||||||
|
// We are finished with layout
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
textLinePosition.ry() += textLine.leading();
|
||||||
|
textLine.setLineWidth(m_widgetRect.width());
|
||||||
|
textLine.setPosition(textLinePosition);
|
||||||
|
textLinePosition.ry() += textLine.height();
|
||||||
|
}
|
||||||
|
m_textLayout.endLayout();
|
||||||
|
|
||||||
|
// Check length
|
||||||
|
if (m_maxTextLength > 0)
|
||||||
|
{
|
||||||
|
int length = 0;
|
||||||
|
int currentPos = 0;
|
||||||
|
|
||||||
|
while (currentPos < m_editText.length())
|
||||||
|
{
|
||||||
|
currentPos = m_textLayout.nextCursorPosition(currentPos, QTextLayout::SkipCharacters);
|
||||||
|
++length;
|
||||||
|
|
||||||
|
if (length == m_maxTextLength)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPos < m_editText.length())
|
||||||
|
{
|
||||||
|
m_editText = m_editText.left(currentPos);
|
||||||
|
m_positionCursor = qBound(getPositionStart(), m_positionCursor, getPositionEnd());
|
||||||
|
updateTextLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFTextEditPseudowidget::getSingleStepForward() const
|
||||||
|
{
|
||||||
|
// If direction is right-to-left, then move backward (because
|
||||||
|
// text is painted from right to left.
|
||||||
|
return (m_textLayout.textOption().textDirection() == Qt::RightToLeft) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFTextEditPseudowidget::getNextPrevCursorPosition(int referencePosition, int steps, QTextLayout::CursorMode mode) const
|
||||||
|
{
|
||||||
|
int cursor = referencePosition;
|
||||||
|
|
||||||
|
if (steps > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < steps; ++i)
|
||||||
|
{
|
||||||
|
cursor = m_textLayout.nextCursorPosition(cursor, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (steps < 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < -steps; ++i)
|
||||||
|
{
|
||||||
|
cursor = m_textLayout.previousCursorPosition(cursor, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFTextEditPseudowidget::getCurrentLineTextStart() const
|
||||||
|
{
|
||||||
|
return m_textLayout.lineForTextPosition(m_positionCursor).textStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFTextEditPseudowidget::getCurrentLineTextEnd() const
|
||||||
|
{
|
||||||
|
QTextLine textLine = m_textLayout.lineForTextPosition(m_positionCursor);
|
||||||
|
return textLine.textStart() + textLine.textLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFTextEditPseudowidget::getCursorLineUp() const
|
||||||
|
{
|
||||||
|
QTextLine line = m_textLayout.lineForTextPosition(m_positionCursor);
|
||||||
|
const int lineIndex = line.lineNumber() - 1;
|
||||||
|
|
||||||
|
if (lineIndex >= 0)
|
||||||
|
{
|
||||||
|
QTextLine upLine = m_textLayout.lineAt(lineIndex);
|
||||||
|
return upLine.xToCursor(line.cursorToX(m_positionCursor), QTextLine::CursorBetweenCharacters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_positionCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFTextEditPseudowidget::getCursorLineDown() const
|
||||||
|
{
|
||||||
|
QTextLine line = m_textLayout.lineForTextPosition(m_positionCursor);
|
||||||
|
const int lineIndex = line.lineNumber() + 1;
|
||||||
|
|
||||||
|
if (lineIndex < m_textLayout.lineCount())
|
||||||
|
{
|
||||||
|
QTextLine downLine = m_textLayout.lineAt(lineIndex);
|
||||||
|
return downLine.xToCursor(line.cursorToX(m_positionCursor), QTextLine::CursorBetweenCharacters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_positionCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdf
|
|
@ -0,0 +1,217 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef PDFTEXTEDITPSEUDOWIDGET_H
|
||||||
|
#define PDFTEXTEDITPSEUDOWIDGET_H
|
||||||
|
|
||||||
|
#include "pdfglobal.h"
|
||||||
|
#include "pdfform.h"
|
||||||
|
|
||||||
|
#include <QRectF>
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
class QWidget;
|
||||||
|
class QKeyEvent;
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
/// "Pseudo" widget, which is emulating text editor, which can be single line, or multiline.
|
||||||
|
/// Passwords can also be edited and editor can be read only.
|
||||||
|
class PDFTextEditPseudowidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFTextEditPseudowidget(PDFFormField::FieldFlags flags);
|
||||||
|
|
||||||
|
void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event);
|
||||||
|
void keyPressEvent(QWidget* widget, QKeyEvent* event);
|
||||||
|
|
||||||
|
inline bool isReadonly() const { return m_flags.testFlag(PDFFormField::ReadOnly); }
|
||||||
|
inline bool isMultiline() const { return m_flags.testFlag(PDFFormField::Multiline); }
|
||||||
|
inline bool isPassword() const { return m_flags.testFlag(PDFFormField::Password); }
|
||||||
|
inline bool isFileSelect() const { return m_flags.testFlag(PDFFormField::FileSelect); }
|
||||||
|
inline bool isComb() const { return m_flags.testFlag(PDFFormField::Comb); }
|
||||||
|
|
||||||
|
inline bool isEmpty() const { return m_editText.isEmpty(); }
|
||||||
|
inline bool isTextSelected() const { return !isEmpty() && getSelectionLength() > 0; }
|
||||||
|
inline bool isWholeTextSelected() const { return !isEmpty() && getSelectionLength() == m_editText.length(); }
|
||||||
|
|
||||||
|
inline int getTextLength() const { return m_editText.length(); }
|
||||||
|
inline int getSelectionLength() const { return m_selectionEnd - m_selectionStart; }
|
||||||
|
|
||||||
|
inline int getPositionCursor() const { return m_positionCursor; }
|
||||||
|
inline int getPositionStart() const { return 0; }
|
||||||
|
inline int getPositionEnd() const { return getTextLength(); }
|
||||||
|
|
||||||
|
inline void clearSelection() { m_selectionStart = m_selectionEnd = 0; }
|
||||||
|
|
||||||
|
inline const QString& getText() const { return m_editText; }
|
||||||
|
inline QString getSelectedText() const { return m_editText.mid(m_selectionStart, getSelectionLength()); }
|
||||||
|
|
||||||
|
/// Sets (updates) text selection
|
||||||
|
/// \param startPosition From where we are selecting text
|
||||||
|
/// \param selectionLength Selection length (positive - to the right, negative - to the left)
|
||||||
|
void setSelection(int startPosition, int selectionLength);
|
||||||
|
|
||||||
|
/// Moves cursor position. It behaves as usual in text boxes,
|
||||||
|
/// when user moves the cursor. If \p select is true, then
|
||||||
|
/// selection is updated.
|
||||||
|
/// \param position New position of the cursor
|
||||||
|
/// \param select Select text when moving the cursor?
|
||||||
|
void setCursorPosition(int position, bool select);
|
||||||
|
|
||||||
|
/// Sets text content of the widget. This functions sets the text,
|
||||||
|
/// even if widget is readonly.
|
||||||
|
/// \param text Text to be set
|
||||||
|
void setText(const QString& text);
|
||||||
|
|
||||||
|
/// Sets widget appearance, such as font, font size, color, text alignment,
|
||||||
|
/// and rectangle, in which widget resides on page (in page coordinates)
|
||||||
|
/// \param appearance Appearance
|
||||||
|
/// \param textAlignment Text alignment
|
||||||
|
/// \param rect Widget rectangle in page coordinates
|
||||||
|
/// \param maxTextLength Maximal text length
|
||||||
|
void setAppearance(const PDFAnnotationDefaultAppearance& appearance,
|
||||||
|
Qt::Alignment textAlignment,
|
||||||
|
QRectF rect,
|
||||||
|
int maxTextLength);
|
||||||
|
|
||||||
|
/// Sets widget appearance, such as font, font size, color, text alignment,
|
||||||
|
/// and rectangle, in which widget resides on page (in page coordinates)
|
||||||
|
/// \param font Font
|
||||||
|
/// \param textAlignment Text alignment
|
||||||
|
/// \param rect Widget rectangle in page coordinates
|
||||||
|
/// \param maxTextLength Maximal text length
|
||||||
|
/// \param textColor Color
|
||||||
|
void setAppearance(const QFont& font,
|
||||||
|
Qt::Alignment textAlignment,
|
||||||
|
QRectF rect,
|
||||||
|
int maxTextLength,
|
||||||
|
QColor textColor);
|
||||||
|
|
||||||
|
void performCut();
|
||||||
|
void performCopy();
|
||||||
|
void performPaste();
|
||||||
|
void performClear();
|
||||||
|
void performSelectAll();
|
||||||
|
void performBackspace();
|
||||||
|
void performDelete();
|
||||||
|
void performRemoveSelectedText();
|
||||||
|
void performInsertText(const QString& text);
|
||||||
|
|
||||||
|
/// Draw text edit using given parameters
|
||||||
|
/// \param parameters Parameters
|
||||||
|
void draw(AnnotationDrawParameters& parameters, bool edit) const;
|
||||||
|
|
||||||
|
/// Returns valid cursor position retrieved from position in the widget.
|
||||||
|
/// \param point Point in page coordinate space
|
||||||
|
/// \param edit Are we using edit transformations?
|
||||||
|
/// \returns Cursor position
|
||||||
|
int getCursorPositionFromWidgetPosition(const QPointF& point, bool edit) const;
|
||||||
|
|
||||||
|
inline int getCursorForward(QTextLayout::CursorMode mode) const { return getNextPrevCursorPosition(getSingleStepForward(), mode); }
|
||||||
|
inline int getCursorBackward(QTextLayout::CursorMode mode) const { return getNextPrevCursorPosition(getSingleStepBackward(), mode); }
|
||||||
|
inline int getCursorCharacterForward() const { return getCursorForward(QTextLayout::SkipCharacters); }
|
||||||
|
inline int getCursorCharacterBackward() const { return getCursorBackward(QTextLayout::SkipCharacters); }
|
||||||
|
inline int getCursorWordForward() const { return getCursorForward(QTextLayout::SkipWords); }
|
||||||
|
inline int getCursorWordBackward() const { return getCursorBackward(QTextLayout::SkipWords); }
|
||||||
|
inline int getCursorDocumentStart() const { return (getSingleStepForward() > 0) ? getPositionStart() : getPositionEnd(); }
|
||||||
|
inline int getCursorDocumentEnd() const { return (getSingleStepForward() > 0) ? getPositionEnd() : getPositionStart(); }
|
||||||
|
inline int getCursorLineStart() const { return (getSingleStepForward() > 0) ? getCurrentLineTextStart() : getCurrentLineTextEnd(); }
|
||||||
|
inline int getCursorLineEnd() const { return (getSingleStepForward() > 0) ? getCurrentLineTextEnd() : getCurrentLineTextStart(); }
|
||||||
|
inline int getCursorNextLine() const { return getCurrentLineTextEnd(); }
|
||||||
|
inline int getCursorPreviousLine() const { return getNextPrevCursorPosition(getCurrentLineTextStart(), -1, QTextLayout::SkipCharacters); }
|
||||||
|
|
||||||
|
const QRectF& getWidgetRect() const { return m_widgetRect; }
|
||||||
|
QFont getFont() const { return m_textLayout.font(); }
|
||||||
|
QColor getFontColor() const { return m_textColor; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// This function does following things:
|
||||||
|
/// 1) Clamps edit text to fit maximum length
|
||||||
|
/// 2) Creates display string from edit string
|
||||||
|
/// 3) Updates text layout
|
||||||
|
void updateTextLayout();
|
||||||
|
|
||||||
|
/// Returns single step forward, which is determined
|
||||||
|
/// by cursor move style and layout direction.
|
||||||
|
int getSingleStepForward() const;
|
||||||
|
|
||||||
|
/// Returns single step backward, which is determined
|
||||||
|
/// by cursor move style and layout direction.
|
||||||
|
int getSingleStepBackward() const { return -getSingleStepForward(); }
|
||||||
|
|
||||||
|
/// Returns next/previous position, by number of steps,
|
||||||
|
/// using given cursor mode (skipping characters or whole words).
|
||||||
|
/// \param steps Number of steps to proceed (can be negative number)
|
||||||
|
/// \param mode Skip mode - letters or words?
|
||||||
|
int getNextPrevCursorPosition(int steps, QTextLayout::CursorMode mode) const { return getNextPrevCursorPosition(m_positionCursor, steps, mode); }
|
||||||
|
|
||||||
|
/// Returns next/previous position from reference cursor position, by number of steps,
|
||||||
|
/// using given cursor mode (skipping characters or whole words).
|
||||||
|
/// \param referencePosition Reference cursor position
|
||||||
|
/// \param steps Number of steps to proceed (can be negative number)
|
||||||
|
/// \param mode Skip mode - letters or words?
|
||||||
|
int getNextPrevCursorPosition(int referencePosition, int steps, QTextLayout::CursorMode mode) const;
|
||||||
|
|
||||||
|
/// Returns current line text start position
|
||||||
|
int getCurrentLineTextStart() const;
|
||||||
|
|
||||||
|
/// Returns current line text end position
|
||||||
|
int getCurrentLineTextEnd() const;
|
||||||
|
|
||||||
|
/// Creates text box transform matrix, which transforms from
|
||||||
|
/// widget space to page space.
|
||||||
|
/// \param edit Create matrix for text editing?
|
||||||
|
QMatrix createTextBoxTransformMatrix(bool edit) const;
|
||||||
|
|
||||||
|
/// Returns vector of cursor positions (which may be not equal
|
||||||
|
/// to edit string length, because edit string can contain surrogates,
|
||||||
|
/// or graphemes, which are single glyphs, but represented by more
|
||||||
|
/// 16-bit unicode codes).
|
||||||
|
std::vector<int> getCursorPositions() const;
|
||||||
|
|
||||||
|
int getCursorLineUp() const;
|
||||||
|
int getCursorLineDown() const;
|
||||||
|
|
||||||
|
PDFFormField::FieldFlags m_flags;
|
||||||
|
|
||||||
|
/// Text edited by the user
|
||||||
|
QString m_editText;
|
||||||
|
|
||||||
|
/// Text, which is displayed. It can differ from text
|
||||||
|
/// edited by user, in case password is being entered.
|
||||||
|
QString m_displayText;
|
||||||
|
|
||||||
|
/// Text layout
|
||||||
|
QTextLayout m_textLayout;
|
||||||
|
|
||||||
|
/// Character for displaying passwords
|
||||||
|
QChar m_passwordReplacementCharacter;
|
||||||
|
|
||||||
|
int m_selectionStart;
|
||||||
|
int m_selectionEnd;
|
||||||
|
int m_positionCursor;
|
||||||
|
int m_maxTextLength;
|
||||||
|
|
||||||
|
QRectF m_widgetRect;
|
||||||
|
QColor m_textColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdf
|
||||||
|
|
||||||
|
#endif // PDFTEXTEDITPSEUDOWIDGET_H
|
|
@ -465,6 +465,11 @@ constexpr bool isRectangleHorizontallyOverlapped(const QRectF& r1, const QRectF&
|
||||||
return isIntervalOverlap(r1.left(), r1.right(), r2.left(), r2.right());
|
return isIntervalOverlap(r1.left(), r1.right(), r2.left(), r2.right());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool isRectangleVerticallyOverlapped(const QRectF& r1, const QRectF& r2)
|
||||||
|
{
|
||||||
|
return isIntervalOverlap(r1.top(), r1.bottom(), r2.top(), r2.bottom());
|
||||||
|
}
|
||||||
|
|
||||||
inline QColor invertColor(QColor color)
|
inline QColor invertColor(QColor color)
|
||||||
{
|
{
|
||||||
qreal r = 0.0;
|
qreal r = 0.0;
|
||||||
|
|
|
@ -101,11 +101,19 @@ void PDFWidgetTool::setActive(bool active)
|
||||||
setActiveImpl(active);
|
setActiveImpl(active);
|
||||||
updateActions();
|
updateActions();
|
||||||
|
|
||||||
m_proxy->repaintNeeded();
|
emit m_proxy->repaintNeeded();
|
||||||
emit toolActivityChanged(active);
|
emit toolActivityChanged(active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFWidgetTool::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
||||||
|
{
|
||||||
|
if (PDFWidgetTool* tool = getTopToolstackTool())
|
||||||
|
{
|
||||||
|
tool->shortcutOverrideEvent(widget, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PDFWidgetTool::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
void PDFWidgetTool::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||||
{
|
{
|
||||||
if (PDFWidgetTool* tool = getTopToolstackTool())
|
if (PDFWidgetTool* tool = getTopToolstackTool())
|
||||||
|
@ -130,6 +138,14 @@ void PDFWidgetTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFWidgetTool::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
||||||
|
{
|
||||||
|
if (PDFWidgetTool* tool = getTopToolstackTool())
|
||||||
|
{
|
||||||
|
tool->mouseDoubleClickEvent(widget, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PDFWidgetTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
void PDFWidgetTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
if (PDFWidgetTool* tool = getTopToolstackTool())
|
if (PDFWidgetTool* tool = getTopToolstackTool())
|
||||||
|
@ -194,11 +210,13 @@ PDFWidgetTool* PDFWidgetTool::getTopToolstackTool() const
|
||||||
|
|
||||||
void PDFWidgetTool::addTool(PDFWidgetTool* tool)
|
void PDFWidgetTool::addTool(PDFWidgetTool* tool)
|
||||||
{
|
{
|
||||||
|
tool->setActive(isActive());
|
||||||
m_toolStack.push_back(tool);
|
m_toolStack.push_back(tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFWidgetTool::removeTool()
|
void PDFWidgetTool::removeTool()
|
||||||
{
|
{
|
||||||
|
m_toolStack.back()->setActive(false);
|
||||||
m_toolStack.pop_back();
|
m_toolStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,8 +827,12 @@ PDFMagnifierTool* PDFToolManager::getMagnifierTool() const
|
||||||
|
|
||||||
void PDFToolManager::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
void PDFToolManager::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
event->ignore();
|
||||||
Q_UNUSED(event);
|
|
||||||
|
if (PDFWidgetTool* activeTool = getActiveTool())
|
||||||
|
{
|
||||||
|
activeTool->shortcutOverrideEvent(widget, event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFToolManager::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
void PDFToolManager::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||||
|
@ -854,8 +876,12 @@ void PDFToolManager::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||||
|
|
||||||
void PDFToolManager::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
void PDFToolManager::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(widget);
|
event->ignore();
|
||||||
Q_UNUSED(event);
|
|
||||||
|
if (PDFWidgetTool* activeTool = getActiveTool())
|
||||||
|
{
|
||||||
|
activeTool->mouseDoubleClickEvent(widget, event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFToolManager::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
void PDFToolManager::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||||
|
@ -1070,6 +1096,11 @@ void PDFPickTool::drawPage(QPainter* painter,
|
||||||
Q_UNUSED(layoutGetter);
|
Q_UNUSED(layoutGetter);
|
||||||
Q_UNUSED(errors);
|
Q_UNUSED(errors);
|
||||||
|
|
||||||
|
if (!isActive())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If we are picking rectangles, then draw current selection rectangle
|
// If we are picking rectangles, then draw current selection rectangle
|
||||||
if (m_mode == Mode::Rectangles && m_drawSelectionRectangle && m_pageIndex == pageIndex && !m_pickedPoints.empty())
|
if (m_mode == Mode::Rectangles && m_drawSelectionRectangle && m_pageIndex == pageIndex && !m_pickedPoints.empty())
|
||||||
{
|
{
|
||||||
|
@ -1097,6 +1128,11 @@ void PDFPickTool::drawPage(QPainter* painter,
|
||||||
|
|
||||||
void PDFPickTool::drawPostRendering(QPainter* painter, QRect rect) const
|
void PDFPickTool::drawPostRendering(QPainter* painter, QRect rect) const
|
||||||
{
|
{
|
||||||
|
if (!isActive())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_mode != Mode::Images)
|
if (m_mode != Mode::Images)
|
||||||
{
|
{
|
||||||
m_snapper.drawSnapPoints(painter);
|
m_snapper.drawSnapPoints(painter);
|
||||||
|
@ -1233,7 +1269,7 @@ void PDFPickTool::resetTool()
|
||||||
m_snapper.clearReferencePoint();
|
m_snapper.clearReferencePoint();
|
||||||
|
|
||||||
buildSnapData();
|
buildSnapData();
|
||||||
getProxy()->repaintNeeded();
|
emit getProxy()->repaintNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFPickTool::buildSnapData()
|
void PDFPickTool::buildSnapData()
|
||||||
|
|
|
@ -62,6 +62,11 @@ public:
|
||||||
/// Returns action for activating/deactivating this tool
|
/// Returns action for activating/deactivating this tool
|
||||||
QAction* getAction() const { return m_action; }
|
QAction* getAction() const { return m_action; }
|
||||||
|
|
||||||
|
/// Handles shortcut override event from widget, over which tool operates
|
||||||
|
/// \param widget Widget, over which tool operates
|
||||||
|
/// \param event Event
|
||||||
|
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event);
|
||||||
|
|
||||||
/// Handles key press event from widget, over which tool operates
|
/// Handles key press event from widget, over which tool operates
|
||||||
/// \param widget Widget, over which tool operates
|
/// \param widget Widget, over which tool operates
|
||||||
/// \param event Event
|
/// \param event Event
|
||||||
|
@ -77,6 +82,11 @@ public:
|
||||||
/// \param event Event
|
/// \param event Event
|
||||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event);
|
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event);
|
||||||
|
|
||||||
|
/// Handles mouse double click event from widget, over which tool operates
|
||||||
|
/// \param widget Widget, over which tool operates
|
||||||
|
/// \param event Event
|
||||||
|
virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event);
|
||||||
|
|
||||||
/// Handles mouse release event from widget, over which tool operates
|
/// Handles mouse release event from widget, over which tool operates
|
||||||
/// \param widget Widget, over which tool operates
|
/// \param widget Widget, over which tool operates
|
||||||
/// \param event Event
|
/// \param event Event
|
||||||
|
@ -344,8 +354,8 @@ public:
|
||||||
void setSelectionRectangleColor(QColor selectionRectangleColor);
|
void setSelectionRectangleColor(QColor selectionRectangleColor);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void pointPicked(PDFInteger pageIndex, QPointF pagePoint);
|
void pointPicked(pdf::PDFInteger pageIndex, QPointF pagePoint);
|
||||||
void rectanglePicked(PDFInteger pageIndex, QRectF pageRectangle);
|
void rectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||||
void imagePicked(const QImage& image);
|
void imagePicked(const QImage& image);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -74,5 +74,21 @@
|
||||||
<file>resources/save.svg</file>
|
<file>resources/save.svg</file>
|
||||||
<file>resources/save-as.svg</file>
|
<file>resources/save-as.svg</file>
|
||||||
<file>resources/select-all-text.svg</file>
|
<file>resources/select-all-text.svg</file>
|
||||||
|
<file>resources/pce-align-bottom.svg</file>
|
||||||
|
<file>resources/pce-align-h-center.svg</file>
|
||||||
|
<file>resources/pce-align-left.svg</file>
|
||||||
|
<file>resources/pce-align-right.svg</file>
|
||||||
|
<file>resources/pce-align-top.svg</file>
|
||||||
|
<file>resources/pce-align-v-center.svg</file>
|
||||||
|
<file>resources/pce-center-h.svg</file>
|
||||||
|
<file>resources/pce-center-v.svg</file>
|
||||||
|
<file>resources/pce-center-vh.svg</file>
|
||||||
|
<file>resources/pce-layout-form.svg</file>
|
||||||
|
<file>resources/pce-layout-grid.svg</file>
|
||||||
|
<file>resources/pce-layout-h.svg</file>
|
||||||
|
<file>resources/pce-layout-v.svg</file>
|
||||||
|
<file>resources/pce-same-height.svg</file>
|
||||||
|
<file>resources/pce-same-size.svg</file>
|
||||||
|
<file>resources/pce-same-width.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -58,7 +58,7 @@ void PDFAdvancedFindWidget::setDocument(const pdf::PDFModifiedDocument& document
|
||||||
|
|
||||||
// If document is not being reset, then page text should remain the same,
|
// If document is not being reset, then page text should remain the same,
|
||||||
// so, there is no need to clear the results.
|
// so, there is no need to clear the results.
|
||||||
if (document.hasReset())
|
if (document.hasReset() || document.hasPageContentsChanged())
|
||||||
{
|
{
|
||||||
m_findResults.clear();
|
m_findResults.clear();
|
||||||
updateUI();
|
updateUI();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M7.596,1.491c0.546,0,0.991,0.443,0.991,0.99v19.036c0,0.545-0.444,0.989-0.991,0.989l0,0
|
||||||
|
c-0.547,0-0.991-0.444-0.991-0.989V2.481C6.605,1.935,7.049,1.491,7.596,1.491L7.596,1.491z"/>
|
||||||
|
<path fill="#292D32" d="M16.405,1.491c0.547,0,0.99,0.443,0.99,0.99v19.036c0,0.545-0.443,0.989-0.99,0.989l0,0
|
||||||
|
c-0.547,0-0.99-0.444-0.99-0.989V2.481C15.415,1.935,15.858,1.491,16.405,1.491L16.405,1.491z"/>
|
||||||
|
<path fill="#292D32" d="M11.999,6.869c0.546,0,0.99,0.443,0.99,0.99v13.652c0,0.547-0.443,0.989-0.99,0.989l0,0
|
||||||
|
c-0.545,0-0.989-0.442-0.989-0.989V7.859C11.011,7.313,11.454,6.869,11.999,6.869L11.999,6.869z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M1.493,7.591c0-0.547,0.443-0.989,0.99-0.989h19.035c0.547,0,0.99,0.442,0.99,0.989l0,0
|
||||||
|
c0,0.548-0.443,0.99-0.99,0.99H2.482C1.937,8.581,1.493,8.139,1.493,7.591L1.493,7.591z"/>
|
||||||
|
<path fill="#292D32" d="M1.493,16.409c0-0.548,0.443-0.99,0.99-0.99h19.035c0.547,0,0.99,0.442,0.99,0.99l0,0
|
||||||
|
c0,0.547-0.443,0.989-0.99,0.989H2.482C1.937,17.398,1.493,16.956,1.493,16.409L1.493,16.409z"/>
|
||||||
|
<path fill="#292D32" d="M4.185,12c0-0.546,0.443-0.988,0.99-0.988h13.652c0.547,0,0.988,0.442,0.988,0.988l0,0
|
||||||
|
c0,0.545-0.441,0.988-0.988,0.988H5.174C4.627,12.988,4.185,12.545,4.185,12L4.185,12z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M22.508,7.595c0,0.546-0.443,0.991-0.99,0.991H2.482c-0.546,0-0.99-0.444-0.99-0.991l0,0
|
||||||
|
c0-0.547,0.444-0.991,0.99-0.991h19.035C22.064,6.604,22.508,7.048,22.508,7.595L22.508,7.595z"/>
|
||||||
|
<path fill="#292D32" d="M22.508,16.404c0,0.547-0.443,0.99-0.99,0.99H2.482c-0.546,0-0.99-0.443-0.99-0.99l0,0
|
||||||
|
c0-0.547,0.444-0.99,0.99-0.99h19.035C22.064,15.414,22.508,15.857,22.508,16.404L22.508,16.404z"/>
|
||||||
|
<path fill="#292D32" d="M17.124,11.999c0,0.546-0.443,0.989-0.99,0.989H2.482c-0.547,0-0.99-0.443-0.99-0.989l0,0
|
||||||
|
c0-0.545,0.443-0.989,0.99-0.989h13.652C16.681,11.01,17.124,11.454,17.124,11.999L17.124,11.999z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M22.508,7.595c0,0.546-0.443,0.991-0.99,0.991H2.482c-0.546,0-0.99-0.444-0.99-0.991l0,0
|
||||||
|
c0-0.547,0.444-0.991,0.99-0.991h19.035C22.064,6.604,22.508,7.048,22.508,7.595L22.508,7.595z"/>
|
||||||
|
<path fill="#292D32" d="M22.508,16.404c0,0.547-0.443,0.99-0.99,0.99H2.482c-0.546,0-0.99-0.443-0.99-0.99l0,0
|
||||||
|
c0-0.547,0.444-0.99,0.99-0.99h19.035C22.064,15.414,22.508,15.857,22.508,16.404L22.508,16.404z"/>
|
||||||
|
<path fill="#292D32" d="M22.508,12.005c0,0.546-0.443,0.99-0.99,0.99H7.866c-0.547,0-0.99-0.443-0.99-0.99l0,0
|
||||||
|
c0-0.545,0.443-0.989,0.99-0.989h13.652C22.064,11.017,22.508,11.46,22.508,12.005L22.508,12.005z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M16.409,1.492c0.547,0,0.989,0.443,0.989,0.99v19.035c0,0.547-0.442,0.99-0.989,0.99l0,0
|
||||||
|
c-0.548,0-0.99-0.443-0.99-0.99V2.482C15.419,1.936,15.861,1.492,16.409,1.492L16.409,1.492z"/>
|
||||||
|
<path fill="#292D32" d="M7.591,1.492c0.547,0,0.989,0.443,0.989,0.99v19.035c0,0.547-0.442,0.99-0.989,0.99l0,0
|
||||||
|
c-0.547,0-0.99-0.443-0.99-0.99V2.482C6.601,1.936,7.044,1.492,7.591,1.492L7.591,1.492z"/>
|
||||||
|
<path fill="#292D32" d="M12,1.492c0.547,0,0.989,0.443,0.989,0.99v13.652c0,0.547-0.442,0.99-0.989,0.99l0,0
|
||||||
|
c-0.545,0-0.989-0.443-0.989-0.99V2.482C11.011,1.936,11.454,1.492,12,1.492L12,1.492z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M16.409,1.492c0.547,0,0.989,0.443,0.989,0.99v19.035c0,0.547-0.442,0.99-0.989,0.99l0,0
|
||||||
|
c-0.548,0-0.99-0.443-0.99-0.99V2.482C15.419,1.936,15.861,1.492,16.409,1.492L16.409,1.492z"/>
|
||||||
|
<path fill="#292D32" d="M7.591,1.492c0.547,0,0.99,0.443,0.99,0.99v19.035c0,0.547-0.443,0.99-0.99,0.99l0,0
|
||||||
|
c-0.547,0-0.99-0.443-0.99-0.99V2.482C6.601,1.936,7.044,1.492,7.591,1.492L7.591,1.492z"/>
|
||||||
|
<path fill="#292D32" d="M12,4.184c0.546,0,0.988,0.443,0.988,0.99v13.652c0,0.547-0.442,0.99-0.988,0.99l0,0
|
||||||
|
c-0.545,0-0.989-0.443-0.989-0.99V5.174C11.011,4.627,11.455,4.184,12,4.184L12,4.184z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,68 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M11.146,0.884c0.291,0.252,0.333,0.693,0.081,0.985L9.933,3.411l-0.009,0L9.903,3.437L9.066,4.44
|
||||||
|
L8.725,4.841L8.569,5.023C8.316,5.316,7.884,5.357,7.592,5.114C7.556,5.085,7.52,5.046,7.493,5.008
|
||||||
|
C7.475,4.988,7.457,4.969,7.439,4.94C7.42,4.921,7.412,4.893,7.404,4.874C7.386,4.836,7.369,4.808,7.369,4.77
|
||||||
|
C7.334,4.694,7.328,4.619,7.33,4.544c0-0.009,0-0.009,0-0.02c0-0.009,0-0.009,0-0.018c0.002-0.046,0.012-0.103,0.032-0.14
|
||||||
|
C7.364,4.348,7.375,4.33,7.375,4.32c0.021-0.055,0.051-0.11,0.089-0.156c0-0.018,0.019-0.027,0.03-0.046l2.667-3.154
|
||||||
|
C10.404,0.672,10.854,0.64,11.146,0.884z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M8.369,3.959c0.028,0.009,0.056,0.02,0.074,0.04l0.092,0.069L9.066,4.44l0.65,0.461l0.045,0.029
|
||||||
|
l1.859,1.324c0.321,0.216,0.39,0.659,0.174,0.971c-0.226,0.32-0.667,0.39-0.979,0.174L8.27,5.595L7.629,5.144
|
||||||
|
C7.62,5.134,7.602,5.123,7.592,5.114C7.556,5.085,7.52,5.046,7.493,5.008C7.475,4.988,7.457,4.969,7.439,4.94
|
||||||
|
C7.42,4.921,7.412,4.893,7.404,4.874C7.386,4.836,7.369,4.808,7.369,4.77C7.334,4.694,7.328,4.619,7.33,4.544
|
||||||
|
c0-0.009,0-0.009,0-0.02c0-0.009,0-0.009,0-0.018c0.002-0.046,0.012-0.103,0.032-0.14C7.364,4.348,7.375,4.33,7.375,4.32
|
||||||
|
c0.021-0.055,0.051-0.11,0.089-0.156C7.67,3.861,8.066,3.781,8.369,3.959z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M16.644,19.227c0.002-0.037-0.017-0.065-0.033-0.103c-0.019-0.049-0.054-0.096-0.09-0.135
|
||||||
|
c-0.036-0.048-0.081-0.097-0.136-0.136l-0.642-0.452l-2.545-1.805c-0.312-0.226-0.754-0.146-0.98,0.165
|
||||||
|
c-0.215,0.321-0.145,0.764,0.176,0.98l1.857,1.324c-0.51,0.16-1.037,0.266-1.582,0.313c-0.18,0.013-0.366,0.025-0.554,0.028
|
||||||
|
c-0.122,0.006-0.243,0.002-0.356-0.002c-0.487-0.016-0.962-0.076-1.427-0.187c-0.232-0.054-0.455-0.116-0.678-0.189
|
||||||
|
c-0.009-0.001-0.018-0.001-0.027-0.011c-0.204-0.063-0.408-0.144-0.601-0.234c-0.046-0.011-0.083-0.031-0.111-0.051
|
||||||
|
c-0.185-0.08-0.369-0.171-0.544-0.278c-0.184-0.1-0.367-0.21-0.541-0.337c-0.074-0.04-0.138-0.088-0.202-0.147
|
||||||
|
c-0.118-0.079-0.238-0.166-0.347-0.263c-0.055-0.04-0.101-0.078-0.146-0.127c-0.1-0.087-0.2-0.176-0.291-0.262
|
||||||
|
c-0.045-0.04-0.082-0.078-0.118-0.127c-0.082-0.076-0.164-0.163-0.236-0.249c-0.082-0.079-0.153-0.175-0.225-0.261
|
||||||
|
c-0.153-0.183-0.288-0.365-0.414-0.557c-0.554-0.814-0.928-1.726-1.112-2.687c-0.089-0.433-0.14-0.885-0.145-1.334
|
||||||
|
c0-0.274,0.012-0.555,0.036-0.83H3.227C3.214,11.42,3.2,11.563,3.195,11.706c-0.005,0.14-0.009,0.279-0.004,0.421
|
||||||
|
c0.01,0.871,0.15,1.728,0.415,2.541c0.042,0.134,0.084,0.266,0.137,0.398c0.344,0.947,0.859,1.825,1.527,2.613
|
||||||
|
c0.09,0.107,0.189,0.214,0.289,0.32c0.1,0.115,0.2,0.212,0.309,0.318c0.1,0.097,0.2,0.193,0.3,0.281
|
||||||
|
c0.374,0.33,0.767,0.624,1.18,0.881c0.11,0.068,0.221,0.138,0.34,0.199c0.119,0.068,0.24,0.139,0.369,0.197
|
||||||
|
c0.121,0.061,0.249,0.122,0.369,0.182c0.045,0.02,0.092,0.04,0.138,0.06C8.774,20.2,8.987,20.282,9.2,20.354
|
||||||
|
c0.139,0.051,0.269,0.093,0.409,0.126c0.129,0.041,0.269,0.073,0.408,0.107c0.279,0.064,0.558,0.12,0.839,0.147
|
||||||
|
c0.129,0.023,0.26,0.037,0.391,0.051c0.3,0.018,0.588,0.038,0.889,0.028c0.244-0.002,0.487-0.012,0.723-0.042
|
||||||
|
c0.196-0.013,0.385-0.044,0.583-0.075c0.225-0.03,0.451-0.079,0.668-0.139l-0.02,0.028l-1.304,1.541
|
||||||
|
c-0.253,0.291-0.211,0.731,0.081,0.986c0.291,0.252,0.741,0.21,0.985-0.091l2.667-3.146c0.009-0.017,0.029-0.027,0.03-0.046
|
||||||
|
c0.039-0.056,0.068-0.1,0.09-0.156c0-0.018,0.009-0.027,0.011-0.046c0.02-0.056,0.03-0.102,0.033-0.158
|
||||||
|
c0.001-0.01,0.001-0.01,0-0.02C16.686,19.378,16.68,19.304,16.644,19.227z"/>
|
||||||
|
<path fill="#292D32" d="M7.369,4.773C7.367,4.811,7.386,4.839,7.403,4.875c0.018,0.049,0.054,0.096,0.089,0.135
|
||||||
|
c0.036,0.048,0.082,0.096,0.135,0.135l0.642,0.453l2.546,1.804c0.312,0.226,0.754,0.146,0.979-0.165
|
||||||
|
c0.216-0.322,0.146-0.764-0.175-0.98L9.762,4.933c0.51-0.16,1.038-0.265,1.582-0.313c0.179-0.013,0.367-0.025,0.554-0.028
|
||||||
|
c0.121-0.005,0.243-0.002,0.356,0.002c0.487,0.016,0.963,0.077,1.427,0.187c0.232,0.054,0.455,0.117,0.678,0.19
|
||||||
|
c0.01,0.001,0.019,0.001,0.028,0.011c0.203,0.063,0.407,0.144,0.6,0.234c0.047,0.011,0.084,0.031,0.111,0.05
|
||||||
|
c0.185,0.08,0.369,0.171,0.545,0.279c0.183,0.1,0.367,0.21,0.541,0.336c0.072,0.041,0.137,0.089,0.201,0.148
|
||||||
|
c0.118,0.079,0.238,0.166,0.347,0.262c0.055,0.04,0.101,0.079,0.146,0.127c0.1,0.087,0.199,0.176,0.291,0.262
|
||||||
|
c0.045,0.04,0.081,0.078,0.117,0.126c0.082,0.077,0.164,0.164,0.236,0.25c0.081,0.079,0.152,0.174,0.225,0.26
|
||||||
|
c0.153,0.183,0.288,0.366,0.414,0.557c0.554,0.814,0.927,1.726,1.111,2.687c0.09,0.433,0.141,0.885,0.145,1.334
|
||||||
|
c0,0.274-0.011,0.555-0.036,0.83h1.405c0.013-0.144,0.027-0.286,0.032-0.43c0.004-0.14,0.008-0.28,0.004-0.422
|
||||||
|
c-0.01-0.87-0.15-1.727-0.414-2.541c-0.042-0.134-0.085-0.265-0.138-0.398c-0.344-0.947-0.859-1.825-1.526-2.613
|
||||||
|
c-0.09-0.107-0.19-0.214-0.289-0.32c-0.101-0.115-0.2-0.212-0.309-0.318c-0.101-0.097-0.199-0.194-0.3-0.281
|
||||||
|
c-0.373-0.33-0.767-0.625-1.179-0.881c-0.111-0.068-0.222-0.138-0.34-0.199c-0.12-0.068-0.24-0.138-0.37-0.197
|
||||||
|
c-0.12-0.061-0.248-0.122-0.369-0.181c-0.046-0.02-0.091-0.04-0.138-0.06c-0.213-0.082-0.425-0.164-0.638-0.236
|
||||||
|
c-0.14-0.051-0.27-0.093-0.409-0.126c-0.13-0.041-0.269-0.073-0.407-0.107c-0.28-0.065-0.559-0.121-0.839-0.148
|
||||||
|
c-0.13-0.023-0.261-0.037-0.392-0.05c-0.3-0.018-0.589-0.038-0.89-0.028c-0.243,0.002-0.486,0.012-0.722,0.042
|
||||||
|
c-0.196,0.013-0.385,0.044-0.583,0.075c-0.225,0.03-0.452,0.079-0.668,0.139l0.02-0.028l1.304-1.541
|
||||||
|
c0.252-0.292,0.21-0.732-0.082-0.986c-0.291-0.252-0.741-0.21-0.985,0.091L7.493,4.122c-0.009,0.017-0.029,0.027-0.03,0.045
|
||||||
|
C7.424,4.223,7.395,4.268,7.374,4.324c0,0.018-0.009,0.027-0.011,0.046C7.343,4.426,7.333,4.472,7.33,4.528
|
||||||
|
c-0.001,0.009-0.001,0.009,0,0.019C7.327,4.622,7.333,4.696,7.369,4.773z"/>
|
||||||
|
<circle fill="#292D32" cx="5.032" cy="7.813" r="1.855"/>
|
||||||
|
<rect x="17.042" y="13.903" fill="#292D32" width="3.487" height="3.584"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-width="1.2" stroke-miterlimit="10" d="M5.269,12c0-0.47,0.382-0.851,0.853-0.851
|
||||||
|
h11.757c0.471,0,0.85,0.381,0.85,0.851l0,0c0,0.469-0.379,0.852-0.85,0.852H6.121C5.65,12.852,5.269,12.469,5.269,12L5.269,12z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M19.842,2.181c-0.463-0.263-1.258-0.484-2.377-0.68c-0.029-0.005-0.057-0.011-0.086-0.015
|
||||||
|
c-0.086-0.015-0.158-0.031-0.246-0.045c-0.033-0.006-0.064,0.004-0.098,0.003c-0.607-0.083-1.256-0.134-1.973-0.134H12H8.937
|
||||||
|
c-0.718,0-1.365,0.051-1.974,0.134C6.931,1.445,6.9,1.435,6.867,1.44C6.778,1.455,6.706,1.471,6.62,1.485
|
||||||
|
C6.591,1.49,6.564,1.496,6.535,1.5c-1.119,0.196-1.914,0.417-2.377,0.68c-2.02,1.15-2.971,3.3-2.971,6.76v6
|
||||||
|
c0,5.43,2.32,7.75,7.75,7.75h1.291h0.568h0.762H12h0.441h0.762h0.568h1.291c5.43,0,7.75-2.32,7.75-7.75v-6
|
||||||
|
C22.813,5.48,21.861,3.331,19.842,2.181z M21.313,14.94c0,4.609-1.641,6.25-6.25,6.25H12H8.937c-4.609,0-6.25-1.641-6.25-6.25v-6
|
||||||
|
c0-0.643,0.039-1.215,0.108-1.742c0-0.001,0.001-0.003,0.001-0.004c0.24-1.52,0.601-2.015,0.69-2.175
|
||||||
|
C4.13,3.889,5.219,3.225,6.913,2.954c0.036-0.006,0.069-0.012,0.106-0.019C7.589,2.852,8.226,2.81,8.937,2.81H12h3.063
|
||||||
|
c0.711,0,1.348,0.042,1.918,0.126c0.037,0.007,0.07,0.013,0.105,0.019c1.693,0.271,2.783,0.935,3.426,2.065
|
||||||
|
c0.09,0.16,0.451,0.655,0.691,2.175c0,0.001,0,0.003,0,0.004c0.07,0.527,0.109,1.1,0.109,1.742V14.94z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-width="1.2" stroke-miterlimit="10" d="M12,18.73c-0.47,0-0.851-0.381-0.851-0.852V6.12
|
||||||
|
c0-0.471,0.381-0.85,0.851-0.85l0,0c0.469,0,0.852,0.379,0.852,0.85v11.759C12.852,18.35,12.469,18.73,12,18.73L12,18.73z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M19.842,2.181c-0.463-0.263-1.258-0.484-2.377-0.68c-0.029-0.005-0.057-0.011-0.086-0.015
|
||||||
|
c-0.086-0.015-0.158-0.031-0.246-0.045c-0.033-0.006-0.064,0.004-0.098,0.003c-0.607-0.083-1.256-0.134-1.973-0.134H12H8.937
|
||||||
|
c-0.718,0-1.365,0.051-1.974,0.134C6.931,1.445,6.9,1.435,6.867,1.44C6.778,1.455,6.706,1.471,6.62,1.485
|
||||||
|
C6.591,1.49,6.564,1.496,6.535,1.5c-1.119,0.196-1.914,0.417-2.377,0.68c-2.02,1.15-2.971,3.3-2.971,6.76v6
|
||||||
|
c0,5.43,2.32,7.75,7.75,7.75h1.291h0.568h0.762H12h0.441h0.762h0.568h1.291c5.43,0,7.75-2.32,7.75-7.75v-6
|
||||||
|
C22.813,5.48,21.861,3.331,19.842,2.181z M21.313,14.94c0,4.609-1.641,6.25-6.25,6.25H12H8.937c-4.609,0-6.25-1.641-6.25-6.25v-6
|
||||||
|
c0-0.643,0.039-1.215,0.108-1.742c0-0.001,0.001-0.003,0.001-0.004c0.24-1.52,0.601-2.015,0.69-2.175
|
||||||
|
C4.13,3.889,5.219,3.225,6.913,2.954c0.036-0.006,0.069-0.012,0.106-0.019C7.589,2.852,8.226,2.81,8.937,2.81H12h3.063
|
||||||
|
c0.711,0,1.348,0.042,1.918,0.126c0.037,0.007,0.07,0.013,0.105,0.019c1.693,0.271,2.783,0.935,3.426,2.065
|
||||||
|
c0.09,0.16,0.451,0.655,0.691,2.175c0,0.001,0,0.003,0,0.004c0.07,0.527,0.109,1.1,0.109,1.742V14.94z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-width="1.2" stroke-miterlimit="10" d="M5.269,12c0-0.47,0.382-0.851,0.853-0.851
|
||||||
|
h11.757c0.471,0,0.85,0.381,0.85,0.851l0,0c0,0.469-0.379,0.852-0.85,0.852H6.121C5.65,12.852,5.269,12.469,5.269,12L5.269,12z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-width="1.2" stroke-miterlimit="10" d="M12,18.73c-0.47,0-0.851-0.381-0.851-0.852V6.12
|
||||||
|
c0-0.471,0.381-0.85,0.851-0.85l0,0c0.469,0,0.852,0.379,0.852,0.85v11.759C12.852,18.35,12.469,18.73,12,18.73L12,18.73z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M19.842,2.181c-0.463-0.263-1.258-0.484-2.377-0.68c-0.029-0.005-0.057-0.011-0.086-0.015
|
||||||
|
c-0.086-0.015-0.158-0.031-0.246-0.045c-0.033-0.006-0.064,0.004-0.098,0.003c-0.607-0.083-1.256-0.134-1.973-0.134H12H8.937
|
||||||
|
c-0.718,0-1.365,0.051-1.974,0.134C6.931,1.445,6.9,1.435,6.867,1.44C6.778,1.455,6.706,1.471,6.62,1.485
|
||||||
|
C6.591,1.49,6.564,1.496,6.535,1.5c-1.119,0.196-1.914,0.417-2.377,0.68c-2.02,1.15-2.971,3.3-2.971,6.76v6
|
||||||
|
c0,5.43,2.32,7.75,7.75,7.75h1.291h0.568h0.762H12h0.441h0.762h0.568h1.291c5.43,0,7.75-2.32,7.75-7.75v-6
|
||||||
|
C22.813,5.48,21.861,3.331,19.842,2.181z M21.313,14.94c0,4.609-1.641,6.25-6.25,6.25H12H8.937c-4.609,0-6.25-1.641-6.25-6.25v-6
|
||||||
|
c0-0.643,0.039-1.215,0.108-1.742c0-0.001,0.001-0.003,0.001-0.004c0.24-1.52,0.601-2.015,0.69-2.175
|
||||||
|
C4.13,3.889,5.219,3.225,6.913,2.954c0.036-0.006,0.069-0.012,0.106-0.019C7.589,2.852,8.226,2.81,8.937,2.81H12h3.063
|
||||||
|
c0.711,0,1.348,0.042,1.918,0.126c0.037,0.007,0.07,0.013,0.105,0.019c1.693,0.271,2.783,0.935,3.426,2.065
|
||||||
|
c0.09,0.16,0.451,0.655,0.691,2.175c0,0.001,0,0.003,0,0.004c0.07,0.527,0.109,1.1,0.109,1.742V14.94z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<path fill="#292D32" d="M21.813,17.132c0.127-0.61,0.19-1.327,0.201-2.187V9.091C22,8.212,21.938,7.518,21.811,6.909
|
||||||
|
c-0.246-1.375-0.748-2.431-1.525-3.229c-0.581-0.611-1.371-1.077-2.348-1.386c-0.894-0.278-1.992-0.42-3.266-0.42L9.066,1.878
|
||||||
|
c-5.077,0-7.34,2.264-7.34,7.342v5.613c0,5.067,2.265,7.328,7.34,7.328h5.606c1.273,0,2.372-0.144,3.266-0.418
|
||||||
|
c0.972-0.302,1.738-0.752,2.351-1.38C21.063,19.566,21.563,18.512,21.813,17.132z M18.007,20.044
|
||||||
|
c-0.634,0.281-1.425,0.44-2.421,0.492c-0.297,0.021-0.598,0.028-0.911,0.028H9.066c-4.296,0-5.744-1.444-5.744-5.731V9.218
|
||||||
|
c0-4.267,1.526-5.735,5.744-5.756l0,0h5.606c0.325,0,0.637,0.011,0.926,0.028c1,0.063,1.793,0.226,2.42,0.503
|
||||||
|
c1.182,0.501,1.877,1.414,2.199,2.872c0.129,0.624,0.191,1.35,0.2,2.223v5.857c-0.009,0.877-0.073,1.603-0.2,2.222
|
||||||
|
C19.896,18.634,19.195,19.546,18.007,20.044z"/>
|
||||||
|
<g>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-miterlimit="10" d="M16.758,17.7H7.502c-0.552,0-1-0.447-1-1v-5.063c0-0.552,0.448-1,1-1
|
||||||
|
h9.255c0.554,0,1,0.448,1,1V16.7C17.758,17.253,17.311,17.7,16.758,17.7z"/>
|
||||||
|
<path fill="#292D32" d="M12.171,8.575H6.984c-0.552,0-1-0.448-1-1v-0.24c0-0.552,0.448-1,1-1h5.188c0.553,0,1,0.448,1,1v0.24
|
||||||
|
C13.172,8.127,12.725,8.575,12.171,8.575z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,65 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M21.943,17.114c0.127-0.611,0.191-1.328,0.201-2.186V9.074c-0.014-0.879-0.076-1.573-0.203-2.182
|
||||||
|
c-0.246-1.375-0.748-2.43-1.525-3.229c-0.582-0.611-1.371-1.077-2.348-1.386c-0.893-0.278-1.992-0.42-3.266-0.42L9.196,1.861
|
||||||
|
c-5.076,0-7.34,2.264-7.34,7.342v5.612c0,5.068,2.266,7.328,7.34,7.328h5.607c1.273,0,2.373-0.143,3.266-0.418
|
||||||
|
c0.971-0.301,1.738-0.752,2.35-1.379C21.193,19.55,21.691,18.493,21.943,17.114z M18.137,20.026
|
||||||
|
c-0.633,0.281-1.424,0.44-2.42,0.492c-0.297,0.021-0.598,0.028-0.912,0.028H9.196c-4.296,0-5.743-1.444-5.743-5.731V9.201
|
||||||
|
c0-4.267,1.525-5.735,5.743-5.756l0,0h5.607c0.326,0,0.637,0.011,0.926,0.028c1,0.062,1.793,0.226,2.42,0.503
|
||||||
|
c1.182,0.501,1.877,1.414,2.199,2.872c0.129,0.624,0.191,1.35,0.201,2.223v5.858c-0.01,0.877-0.074,1.602-0.201,2.221
|
||||||
|
C20.025,18.616,19.326,19.528,18.137,20.026z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M7.432,8.581L6.17,8.58c-0.811,0-1.47-0.711-1.47-1.585s0.66-1.585,1.471-1.585h1.261
|
||||||
|
c0.811,0,1.47,0.711,1.47,1.585C8.902,7.87,8.242,8.581,7.432,8.581z M6.17,6.409c-0.26,0-0.471,0.263-0.471,0.585
|
||||||
|
S5.911,7.58,6.17,7.58l1.261,0.001c0.259,0,0.47-0.263,0.47-0.586c0-0.323-0.211-0.585-0.47-0.585H6.17z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M7.432,13.575H6.17c-0.811,0-1.471-0.712-1.471-1.588c0-0.874,0.66-1.585,1.471-1.585h1.261
|
||||||
|
c0.811,0,1.47,0.711,1.47,1.585C8.902,12.863,8.242,13.575,7.432,13.575z M6.17,11.402c-0.26,0-0.471,0.262-0.471,0.585
|
||||||
|
c0,0.319,0.215,0.588,0.471,0.588h1.261c0.255,0,0.47-0.269,0.47-0.588c0-0.323-0.211-0.585-0.47-0.585H6.17z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M7.432,18.593H6.17c-0.811,0-1.471-0.712-1.471-1.586c0-0.873,0.66-1.584,1.471-1.584h1.261
|
||||||
|
c0.811,0,1.47,0.711,1.47,1.584C8.902,17.881,8.242,18.593,7.432,18.593z M6.17,16.423c-0.26,0-0.471,0.262-0.471,0.584
|
||||||
|
c0,0.323,0.211,0.586,0.471,0.586h1.261c0.259,0,0.47-0.263,0.47-0.586c0-0.322-0.211-0.584-0.47-0.584H6.17z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M12.631,8.593H11.37c-0.811,0-1.471-0.711-1.471-1.586c0-0.874,0.66-1.585,1.471-1.585h1.261
|
||||||
|
c0.811,0,1.471,0.711,1.471,1.585C14.102,7.882,13.441,8.593,12.631,8.593z M11.37,6.421c-0.255,0-0.471,0.268-0.471,0.585
|
||||||
|
c0,0.318,0.215,0.586,0.471,0.586h1.261c0.26,0,0.471-0.263,0.471-0.586c0-0.323-0.211-0.585-0.471-0.585H11.37z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M12.631,13.588H11.37c-0.811,0-1.471-0.712-1.471-1.588c0-0.874,0.66-1.585,1.471-1.585h1.261
|
||||||
|
c0.811,0,1.471,0.711,1.471,1.585C14.102,12.876,13.441,13.588,12.631,13.588z M11.37,11.415c-0.26,0-0.471,0.263-0.471,0.585
|
||||||
|
c0,0.319,0.215,0.588,0.471,0.588h1.261c0.255,0,0.471-0.269,0.471-0.588c0-0.323-0.211-0.585-0.471-0.585H11.37z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M12.631,18.606H11.37c-0.811,0-1.471-0.711-1.471-1.585s0.66-1.586,1.471-1.586h1.261
|
||||||
|
c0.811,0,1.471,0.712,1.471,1.586S13.441,18.606,12.631,18.606z M11.37,16.436c-0.26,0-0.471,0.263-0.471,0.586
|
||||||
|
c0,0.317,0.215,0.585,0.471,0.585h1.261c0.26,0,0.471-0.263,0.471-0.585c0-0.323-0.211-0.586-0.471-0.586H11.37z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M17.83,8.565h-1.262c-0.811,0-1.471-0.711-1.471-1.586c0-0.874,0.66-1.585,1.471-1.585h1.262
|
||||||
|
c0.811,0,1.471,0.711,1.471,1.585C19.301,7.854,18.641,8.565,17.83,8.565z M16.568,6.394c-0.255,0-0.471,0.268-0.471,0.585
|
||||||
|
s0.216,0.586,0.471,0.586h1.262c0.26,0,0.471-0.263,0.471-0.586c0-0.323-0.211-0.585-0.471-0.585H16.568z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M17.83,13.559h-1.262c-0.811,0-1.471-0.712-1.471-1.587c0-0.874,0.66-1.585,1.471-1.585h1.262
|
||||||
|
c0.811,0,1.471,0.711,1.471,1.585C19.301,12.847,18.641,13.559,17.83,13.559z M16.568,11.387c-0.255,0-0.471,0.268-0.471,0.585
|
||||||
|
c0,0.318,0.216,0.587,0.471,0.587h1.262c0.26,0,0.471-0.263,0.471-0.587c0-0.323-0.211-0.585-0.471-0.585H16.568z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M17.83,18.578h-1.262c-0.811,0-1.471-0.711-1.471-1.585s0.66-1.586,1.471-1.586h1.262
|
||||||
|
c0.811,0,1.471,0.712,1.471,1.586S18.641,18.578,17.83,18.578z M16.568,16.407c-0.255,0-0.471,0.269-0.471,0.586
|
||||||
|
s0.216,0.585,0.471,0.585h1.262c0.26,0,0.471-0.263,0.471-0.585c0-0.323-0.211-0.586-0.471-0.586H16.568z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.5 KiB |
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<path fill="#292D32" d="M21.943,17.113c0.127-0.611,0.19-1.328,0.201-2.186V9.072c-0.014-0.879-0.076-1.573-0.203-2.182
|
||||||
|
c-0.246-1.375-0.748-2.43-1.526-3.229c-0.581-0.611-1.371-1.077-2.347-1.386c-0.894-0.278-1.993-0.42-3.266-0.42L9.196,1.859
|
||||||
|
c-5.077,0-7.34,2.264-7.34,7.342v5.613c0,5.068,2.265,7.328,7.34,7.328h5.607c1.273,0,2.372-0.143,3.266-0.418
|
||||||
|
c0.971-0.301,1.738-0.752,2.35-1.379C21.193,19.549,21.691,18.492,21.943,17.113z M18.137,20.025
|
||||||
|
c-0.634,0.281-1.425,0.44-2.421,0.492c-0.297,0.021-0.597,0.028-0.911,0.028H9.196c-4.296,0-5.744-1.444-5.744-5.731V9.199
|
||||||
|
c0-4.267,1.526-5.735,5.744-5.756l0,0h5.607c0.325,0,0.637,0.011,0.926,0.028c1,0.062,1.793,0.226,2.42,0.503
|
||||||
|
c1.181,0.501,1.877,1.414,2.199,2.872c0.129,0.624,0.191,1.35,0.2,2.223v5.859c-0.009,0.877-0.073,1.602-0.2,2.221
|
||||||
|
C20.025,18.615,19.325,19.527,18.137,20.025z"/>
|
||||||
|
<g>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-miterlimit="10" d="M8.813,7.372v9.255c0,0.553-0.448,1-1,1H7.125c-0.552,0-1-0.447-1-1
|
||||||
|
V7.372c0-0.554,0.448-1,1-1h0.688C8.365,6.372,8.813,6.818,8.813,7.372z"/>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-miterlimit="10" d="M13.344,7.372v9.256c0,0.552-0.447,1-1,1h-0.688
|
||||||
|
c-0.553,0-1-0.448-1-1V7.372c0-0.554,0.448-1,1-1h0.688C12.896,6.372,13.344,6.818,13.344,7.372z"/>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-miterlimit="10" d="M17.875,7.372v9.255c0,0.553-0.447,1-1,1h-0.688
|
||||||
|
c-0.554,0-1-0.447-1-1V7.372c0-0.554,0.446-1,1-1h0.688C17.428,6.372,17.875,6.818,17.875,7.372z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M21.943,17.113c0.127-0.611,0.19-1.328,0.201-2.186V9.072c-0.014-0.879-0.076-1.573-0.203-2.182
|
||||||
|
c-0.246-1.375-0.748-2.43-1.526-3.229c-0.581-0.611-1.371-1.077-2.347-1.386c-0.894-0.278-1.993-0.42-3.266-0.42L9.196,1.859
|
||||||
|
c-5.077,0-7.34,2.264-7.34,7.342v5.613c0,5.068,2.265,7.328,7.34,7.328h5.607c1.273,0,2.372-0.143,3.266-0.418
|
||||||
|
c0.971-0.301,1.738-0.752,2.35-1.379C21.193,19.549,21.691,18.492,21.943,17.113z M18.137,20.025
|
||||||
|
c-0.634,0.281-1.425,0.44-2.421,0.492c-0.297,0.021-0.597,0.028-0.911,0.028H9.196c-4.296,0-5.744-1.444-5.744-5.731V9.199
|
||||||
|
c0-4.267,1.526-5.735,5.744-5.756l0,0h5.607c0.325,0,0.637,0.011,0.926,0.028c1,0.062,1.793,0.226,2.42,0.503
|
||||||
|
c1.181,0.501,1.877,1.414,2.199,2.872c0.129,0.624,0.191,1.35,0.2,2.223v5.859c-0.009,0.877-0.073,1.602-0.2,2.221
|
||||||
|
C20.025,18.615,19.325,19.527,18.137,20.025z"/>
|
||||||
|
<g>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-miterlimit="10" d="M16.628,8.813H7.373c-0.553,0-1-0.448-1-1V7.125
|
||||||
|
c0-0.552,0.447-1,1-1h9.255c0.554,0,1,0.448,1,1v0.688C17.628,8.365,17.182,8.813,16.628,8.813z"/>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-miterlimit="10" d="M16.628,13.344H7.372c-0.552,0-1-0.447-1-1v-0.688
|
||||||
|
c0-0.553,0.448-1,1-1h9.256c0.554,0,1,0.448,1,1v0.688C17.628,12.896,17.182,13.344,16.628,13.344z"/>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-miterlimit="10" d="M16.628,17.875H7.373c-0.552,0-1-0.447-1-1v-0.688
|
||||||
|
c0-0.554,0.448-1,1-1h9.255c0.554,0,1,0.446,1,1v0.688C17.628,17.428,17.182,17.875,16.628,17.875z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M11.733,3.771c-0.089,0.031-0.166,0.086-0.223,0.154L9.372,6.061C9.228,6.199,9.163,6.375,9.163,6.557
|
||||||
|
c0,0.178,0.068,0.361,0.209,0.496c0.269,0.279,0.719,0.279,0.995,0l0.885-0.885v0.369v10.987v0.368l-0.885-0.884
|
||||||
|
c-0.276-0.277-0.727-0.277-0.995,0c-0.142,0.136-0.209,0.317-0.209,0.497c0,0.182,0.065,0.357,0.209,0.496l2.138,2.133
|
||||||
|
c0.057,0.068,0.134,0.125,0.223,0.155c0.077,0.046,0.172,0.06,0.268,0.06c0.087-0.014,0.183-0.031,0.265-0.064
|
||||||
|
c0.084-0.035,0.166-0.086,0.229-0.153l2.133-2.134c0.281-0.277,0.281-0.727,0-1.003c-0.275-0.276-0.723-0.276-1,0l-0.883,0.893
|
||||||
|
v-0.363V11.4v-0.738V6.537V6.174l0.883,0.893c0.277,0.275,0.725,0.275,1,0c0.281-0.275,0.281-0.725,0-1.002L12.494,3.93
|
||||||
|
c-0.063-0.066-0.145-0.117-0.229-0.152c-0.082-0.035-0.177-0.051-0.265-0.066C11.905,3.711,11.81,3.727,11.733,3.771z"/>
|
||||||
|
<path fill="#292D32" d="M16.625,1.428c0.432,0,0.781,0.334,0.781,0.746l0,0c0,0.412-0.35,0.744-0.781,0.744h-9.25
|
||||||
|
c-0.432,0-0.781-0.332-0.781-0.744l0,0c0-0.412,0.35-0.746,0.781-0.746H16.625z"/>
|
||||||
|
<path fill="#292D32" d="M16.625,21.082c0.432,0,0.781,0.334,0.781,0.746l0,0c0,0.412-0.35,0.744-0.781,0.744h-9.25
|
||||||
|
c-0.432,0-0.781-0.332-0.781-0.744l0,0c0-0.412,0.35-0.746,0.781-0.746H16.625z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<path fill="#292D32" d="M11.733,3.771c-0.089,0.031-0.166,0.086-0.223,0.154L9.372,6.061C9.228,6.199,9.163,6.375,9.163,6.557
|
||||||
|
c0,0.178,0.068,0.361,0.209,0.496c0.269,0.279,0.719,0.279,0.995,0l0.885-0.885v0.369v10.987v0.368l-0.885-0.884
|
||||||
|
c-0.276-0.277-0.727-0.277-0.995,0c-0.142,0.136-0.209,0.317-0.209,0.497c0,0.182,0.065,0.357,0.209,0.496l2.138,2.133
|
||||||
|
c0.057,0.068,0.134,0.125,0.223,0.155c0.077,0.046,0.172,0.06,0.268,0.06c0.087-0.014,0.183-0.031,0.265-0.064
|
||||||
|
c0.084-0.035,0.166-0.086,0.229-0.153l2.133-2.134c0.281-0.277,0.281-0.727,0-1.003c-0.275-0.276-0.723-0.276-1,0l-0.883,0.893
|
||||||
|
v-0.363V11.4v-0.738V6.537V6.174l0.883,0.893c0.277,0.275,0.725,0.275,1,0c0.281-0.275,0.281-0.725,0-1.002L12.494,3.93
|
||||||
|
c-0.063-0.066-0.145-0.117-0.229-0.152c-0.082-0.035-0.177-0.051-0.265-0.066C11.905,3.711,11.81,3.727,11.733,3.771z"/>
|
||||||
|
<path fill="#292D32" d="M16.625,1.428c0.432,0,0.781,0.334,0.781,0.746l0,0c0,0.412-0.35,0.744-0.781,0.744h-9.25
|
||||||
|
c-0.432,0-0.781-0.332-0.781-0.744l0,0c0-0.412,0.35-0.746,0.781-0.746H16.625z"/>
|
||||||
|
<path fill="#292D32" d="M16.625,21.082c0.432,0,0.781,0.334,0.781,0.746l0,0c0,0.412-0.35,0.744-0.781,0.744h-9.25
|
||||||
|
c-0.432,0-0.781-0.332-0.781-0.744l0,0c0-0.412,0.35-0.746,0.781-0.746H16.625z"/>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M3.771,12.298c0.031,0.088,0.086,0.166,0.154,0.223l2.135,2.138c0.139,0.145,0.314,0.21,0.496,0.21
|
||||||
|
c0.178,0,0.361-0.068,0.496-0.21c0.279-0.269,0.279-0.72,0-0.995l-0.885-0.885h0.369h10.987h0.368l-0.884,0.885
|
||||||
|
c-0.277,0.275-0.277,0.727,0,0.995c0.136,0.142,0.317,0.21,0.497,0.21c0.182,0,0.357-0.065,0.496-0.21l2.133-2.138
|
||||||
|
c0.068-0.057,0.125-0.135,0.155-0.223c0.046-0.077,0.06-0.173,0.06-0.269c-0.014-0.087-0.031-0.183-0.064-0.265
|
||||||
|
c-0.035-0.084-0.086-0.166-0.153-0.229l-2.134-2.133c-0.277-0.281-0.727-0.281-1.003,0c-0.276,0.275-0.276,0.723,0,1l0.893,0.883
|
||||||
|
h-0.363H11.4h-0.738H6.537H6.174l0.893-0.883c0.275-0.277,0.275-0.725,0-1c-0.275-0.281-0.725-0.281-1.002,0L3.93,11.536
|
||||||
|
c-0.066,0.063-0.117,0.145-0.152,0.229c-0.035,0.082-0.051,0.178-0.066,0.265C3.711,12.125,3.727,12.221,3.771,12.298z"/>
|
||||||
|
<path fill="#292D32" d="M1.428,7.405c0-0.432,0.334-0.781,0.746-0.781l0,0c0.412,0,0.744,0.35,0.744,0.781v9.25
|
||||||
|
c0,0.432-0.332,0.781-0.744,0.781l0,0c-0.412,0-0.746-0.35-0.746-0.781V7.405z"/>
|
||||||
|
<path fill="#292D32" d="M21.082,7.405c0-0.432,0.334-0.781,0.746-0.781l0,0c0.412,0,0.744,0.35,0.744,0.781v9.25
|
||||||
|
c0,0.432-0.332,0.781-0.744,0.781l0,0c-0.412,0-0.746-0.35-0.746-0.781V7.405z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M20.229,11.733c-0.031-0.089-0.086-0.166-0.154-0.223l-2.135-2.138c-0.139-0.145-0.314-0.209-0.496-0.209
|
||||||
|
c-0.178,0-0.361,0.068-0.496,0.209c-0.279,0.269-0.279,0.719,0,0.995l0.885,0.885h-0.369H6.476H6.107l0.884-0.885
|
||||||
|
c0.277-0.276,0.277-0.727,0-0.995C6.855,9.23,6.673,9.163,6.494,9.163c-0.182,0-0.357,0.065-0.496,0.209L3.865,11.51
|
||||||
|
c-0.068,0.057-0.124,0.134-0.155,0.223c-0.046,0.077-0.06,0.172-0.06,0.268c0.014,0.087,0.031,0.183,0.065,0.265
|
||||||
|
c0.035,0.084,0.085,0.166,0.153,0.229l2.134,2.133c0.277,0.281,0.727,0.281,1.002,0c0.276-0.275,0.276-0.723,0-1l-0.893-0.883
|
||||||
|
h0.363H12.6h0.738h4.125h0.363l-0.893,0.883c-0.275,0.277-0.275,0.725,0,1c0.275,0.281,0.725,0.281,1.002,0l2.135-2.133
|
||||||
|
c0.066-0.063,0.117-0.145,0.152-0.229c0.035-0.082,0.051-0.177,0.066-0.265C20.289,11.905,20.273,11.81,20.229,11.733z"/>
|
||||||
|
<path fill="#292D32" d="M22.572,16.625c0,0.432-0.334,0.781-0.746,0.781l0,0c-0.412,0-0.744-0.35-0.744-0.781v-9.25
|
||||||
|
c0-0.432,0.332-0.781,0.744-0.781l0,0c0.412,0,0.746,0.35,0.746,0.781V16.625z"/>
|
||||||
|
<path fill="#292D32" d="M2.917,16.625c0,0.432-0.333,0.781-0.745,0.781l0,0c-0.412,0-0.745-0.35-0.745-0.781v-9.25
|
||||||
|
c0-0.432,0.333-0.781,0.745-0.781l0,0c0.412,0,0.745,0.35,0.745,0.781V16.625z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M17.221,14.709c-0.115,0-0.225,0.018-0.336,0.047c-0.113-0.285-0.307-0.496-0.574-0.621
|
||||||
|
c-0.27-0.133-0.557-0.152-0.848-0.063c-0.205-0.393-0.422-0.584-0.695-0.645l-0.041-0.016c-0.105-0.021-0.191-0.035-0.342-0.023
|
||||||
|
c-0.082,0.008-0.158,0.025-0.223,0.045v-0.123v-0.845c0-0.625-0.301-1.028-0.893-1.198c-0.08-0.019-0.162-0.028-0.252-0.028
|
||||||
|
c-0.059,0-0.152,0.004-0.273,0.031c-0.59,0.179-0.879,0.573-0.879,1.213v4.207c-0.008-0.014-0.018-0.025-0.025-0.039
|
||||||
|
c-0.07-0.102-0.141-0.203-0.213-0.301c-0.316-0.43-0.763-0.613-1.279-0.533c-0.461,0.076-0.834,0.354-1.02,0.766
|
||||||
|
c-0.184,0.408-0.146,0.891,0.104,1.289c0.61,0.973,1.225,1.941,1.848,2.908c0.314,0.494,0.764,0.84,1.332,1.033l0.061,0.018
|
||||||
|
c0.523,0.129,0.93,0.133,0.949,0.133h2.178l0.16-0.029c0.115-0.021,0.234-0.047,0.35-0.076c1.191-0.33,2.033-1.418,2.047-2.645
|
||||||
|
c0.012-1.059,0.006-2.137,0.002-3.18v-0.166C18.354,15.217,17.854,14.709,17.221,14.709z M17.457,19.133
|
||||||
|
c0,0.92-0.6,1.68-1.484,1.883c-0.137,0.031-0.281,0.047-0.434,0.047c-0.68,0.006-1.355,0.008-2.039,0
|
||||||
|
c-0.652-0.004-1.16-0.285-1.506-0.832c-0.486-0.758-0.966-1.52-1.449-2.281l-0.359-0.566c-0.113-0.178-0.098-0.393,0.039-0.541
|
||||||
|
c0.086-0.094,0.203-0.148,0.326-0.148c0.068,0,0.135,0.02,0.195,0.053c0.064,0.039,0.127,0.096,0.166,0.154
|
||||||
|
c0.376,0.553,0.751,1.107,1.134,1.676c0.031,0.035,0.193,0.215,0.387,0.215c0.066,0,0.189-0.021,0.291-0.195
|
||||||
|
c0.027-0.068,0.041-0.188,0.041-0.361V12.43c0-0.209,0.1-0.265,0.184-0.288c0.145-0.039,0.293,0.063,0.309,0.204
|
||||||
|
c0.004,0.044,0.004,0.092,0.004,0.138v3.286c0.01,0.127,0.07,0.381,0.426,0.381h0.102c0,0,0.129-0.002,0.24-0.117
|
||||||
|
c0.123-0.115,0.133-0.596,0.133-0.596c0-0.297,0-0.594,0-0.891c0.002-0.168,0.1-0.279,0.254-0.279
|
||||||
|
c0.141,0.002,0.244,0.109,0.244,0.258c0.004,0.326,0,0.65,0,0.975v0.383c0.006,0.082,0.055,0.223,0.34,0.268h0.234
|
||||||
|
c0.359,0.031,0.326-0.311,0.326-0.311v-0.346v-0.311c0.002-0.158,0.107-0.268,0.252-0.268c0.143,0,0.248,0.107,0.25,0.256
|
||||||
|
c0.004,0.178,0.004,0.357,0.002,0.535c0,0-0.002,0.439,0.279,0.439h0.25c0,0,0.223-0.014,0.275-0.324l0,0
|
||||||
|
c0.045-0.127,0.139-0.25,0.342-0.217c0.131,0,0.242,0.104,0.246,0.23l0.004,1.141C17.461,17.695,17.461,18.414,17.457,19.133z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M13.481,1.166c-0.026-0.066-0.058-0.122-0.097-0.185c-0.068-0.085-0.149-0.131-0.191-0.152
|
||||||
|
c-0.246-0.12-0.476-0.076-0.726,0.151c-0.122,0.109-0.262,0.241-0.367,0.396l-0.275,0.403c-0.317,0.46-0.645,0.937-0.933,1.428
|
||||||
|
c-1.396,2.372-2.738,4.99-4.103,8c-0.102,0.227-0.19,0.376-0.356,0.471c-0.054,0.03-0.19,0.107-0.341,0.218
|
||||||
|
c-0.719,0.544-1.079,1.253-1.069,2.11c0.003,0.245,0.032,0.49,0.06,0.738c0.018,0.156,0.039,0.312,0.061,0.465
|
||||||
|
c0.033,0.241,0.066,0.48,0.085,0.723c0.021,0.268-0.069,0.467-0.263,0.612l0.002,0.003c0,0-0.184,0.117-0.316,0.305
|
||||||
|
c-0.001,0.002-0.006,0.01-0.01,0.015C4.617,16.905,4.6,16.95,4.581,16.994c-0.037,0.106-0.05,0.249,0.075,0.389
|
||||||
|
c0.037,0.035,0.082,0.067,0.141,0.096c0.095,0.034,0.189,0.049,0.271,0.046c0.229-0.005,0.456-0.02,0.681-0.045
|
||||||
|
c0.739-0.079,1.385-0.261,1.976-0.553c0.733-0.363,1.254-0.852,1.594-1.491c0.35-0.666,0.469-1.416,0.372-2.365
|
||||||
|
c-0.008-0.079,0.003-0.163,0.029-0.226c1.357-3.189,2.417-6.049,3.239-8.744l0.053-0.164c0.247-0.801,0.501-1.631,0.522-2.521
|
||||||
|
C13.53,1.342,13.515,1.267,13.481,1.166z M8.666,14.712c-0.251,0.694-0.752,1.181-1.575,1.527c-0.306,0.13-0.644,0.226-1.061,0.293
|
||||||
|
c0.154-0.47,0.083-0.943,0.014-1.403l-0.023-0.146c-0.037-0.245-0.073-0.486-0.099-0.731c-0.082-0.75,0.205-1.327,0.874-1.765
|
||||||
|
c0.076-0.052,0.137-0.078,0.19-0.083c0.036-0.004,0.094-0.004,0.198,0.048c0.453,0.226,0.924,0.434,1.379,0.634l0.223,0.098
|
||||||
|
l0.025,0.044C8.867,13.813,8.821,14.285,8.666,14.712z M12.017,4.154c-0.609,1.956-1.369,4.055-2.404,6.635L9.569,10.9
|
||||||
|
c-0.003,0.007-0.006,0.014-0.008,0.021l-0.56,1.336l-1.409-0.602l0.225-0.545c0.019-0.046,0.04-0.09,0.06-0.134
|
||||||
|
c0.021-0.045,0.042-0.088,0.061-0.133l0.405-0.88c0.132-0.271,0.26-0.54,0.392-0.805c0.949-1.932,1.995-3.991,3.204-5.965
|
||||||
|
c0.181-0.296,0.385-0.588,0.585-0.872C12.392,2.936,12.209,3.54,12.017,4.154z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.4 KiB |
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<circle fill="#FFF10A" cx="11.064" cy="10.958" r="8.041"/>
|
||||||
|
<path fill="#292D32" d="M19.836,13.828c-0.115,0-0.225,0.018-0.336,0.047c-0.113-0.285-0.307-0.496-0.574-0.621
|
||||||
|
c-0.27-0.133-0.557-0.152-0.848-0.063c-0.205-0.393-0.422-0.584-0.695-0.645l-0.041-0.016C17.236,12.51,17.15,12.496,17,12.508
|
||||||
|
c-0.082,0.008-0.158,0.025-0.223,0.045V12.43v-0.844c0-0.625-0.301-1.028-0.893-1.198c-0.08-0.019-0.162-0.028-0.252-0.028
|
||||||
|
c-0.059,0-0.152,0.004-0.273,0.031c-0.59,0.179-0.879,0.573-0.879,1.213v4.206c-0.008-0.014-0.018-0.025-0.025-0.039
|
||||||
|
c-0.07-0.102-0.141-0.203-0.213-0.301c-0.316-0.43-0.764-0.613-1.279-0.533c-0.461,0.076-0.834,0.354-1.02,0.766
|
||||||
|
c-0.184,0.408-0.146,0.891,0.104,1.289c0.61,0.973,1.225,1.941,1.848,2.908c0.314,0.494,0.764,0.84,1.332,1.033l0.061,0.018
|
||||||
|
c0.523,0.129,0.93,0.133,0.949,0.133h2.178l0.16-0.029c0.115-0.021,0.234-0.047,0.35-0.076c1.191-0.33,2.033-1.418,2.047-2.645
|
||||||
|
c0.012-1.059,0.006-2.137,0.002-3.18v-0.166C20.969,14.336,20.469,13.828,19.836,13.828z M20.072,18.252
|
||||||
|
c0,0.92-0.6,1.68-1.484,1.883c-0.137,0.031-0.281,0.047-0.434,0.047c-0.68,0.006-1.355,0.008-2.039,0
|
||||||
|
c-0.652-0.004-1.16-0.285-1.506-0.832c-0.486-0.758-0.967-1.52-1.449-2.281l-0.359-0.566c-0.113-0.178-0.098-0.393,0.039-0.541
|
||||||
|
c0.086-0.094,0.203-0.148,0.326-0.148c0.068,0,0.135,0.02,0.195,0.053c0.064,0.039,0.127,0.096,0.166,0.154
|
||||||
|
c0.377,0.553,0.752,1.107,1.135,1.676c0.031,0.035,0.193,0.215,0.387,0.215c0.066,0,0.189-0.021,0.291-0.195
|
||||||
|
c0.027-0.068,0.041-0.188,0.041-0.361V11.55c0-0.209,0.1-0.265,0.184-0.288c0.145-0.039,0.293,0.063,0.309,0.204
|
||||||
|
c0.004,0.044,0.004,0.092,0.004,0.138v3.285c0.01,0.127,0.07,0.381,0.426,0.381h0.102c0,0,0.129-0.002,0.24-0.117
|
||||||
|
c0.123-0.115,0.133-0.596,0.133-0.596c0-0.297,0-0.594,0-0.891c0.002-0.168,0.1-0.279,0.254-0.279
|
||||||
|
c0.141,0.002,0.244,0.109,0.244,0.258c0.004,0.326,0,0.65,0,0.975v0.383c0.006,0.082,0.055,0.223,0.34,0.268h0.234
|
||||||
|
c0.359,0.031,0.326-0.311,0.326-0.311v-0.346v-0.311c0.002-0.158,0.107-0.268,0.252-0.268c0.143,0,0.248,0.107,0.25,0.256
|
||||||
|
c0.004,0.178,0.004,0.357,0.002,0.535c0,0-0.002,0.439,0.279,0.439h0.25c0,0,0.223-0.014,0.275-0.324l0,0
|
||||||
|
c0.045-0.127,0.139-0.25,0.342-0.217c0.131,0,0.242,0.104,0.246,0.23l0.004,1.141C20.076,16.814,20.076,17.533,20.072,18.252z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M7.225,9.536H3.946l-0.475,1.151H1.706l3.003-7.356h1.767l3.003,7.356h-1.78L7.225,9.536z M6.676,8.197
|
||||||
|
L5.584,5.51L4.492,8.197H6.676z"/>
|
||||||
|
<path fill="#292D32" d="M16.262,7.921c0,1.699-1.066,2.901-2.545,2.901c-0.777,0-1.413-0.331-1.855-0.911v0.776h-1.567V3.203h1.567
|
||||||
|
v2.721c0.442-0.567,1.078-0.896,1.855-0.896C15.195,5.029,16.262,6.228,16.262,7.921z M14.742,7.921
|
||||||
|
c0-0.921-0.609-1.574-1.48-1.574c-0.762,0-1.315,0.558-1.4,1.355v0.431c0.085,0.813,0.639,1.374,1.4,1.374
|
||||||
|
C14.133,9.506,14.742,8.852,14.742,7.921z"/>
|
||||||
|
<path fill="#292D32" d="M17.053,7.921c0-1.574,1.393-2.892,3.037-2.892c0.895,0,1.635,0.362,2.174,0.939l-1.043,0.891
|
||||||
|
c-0.279-0.313-0.717-0.513-1.146-0.513c-0.814,0-1.506,0.719-1.506,1.563c0,0.863,0.691,1.597,1.521,1.597
|
||||||
|
c0.428,0,0.873-0.211,1.168-0.539l1.037,0.877c-0.551,0.603-1.295,0.978-2.217,0.978C18.438,10.822,17.053,9.488,17.053,7.921z"/>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M21.096,13.729c-0.115,0-0.225,0.017-0.336,0.047c-0.113-0.286-0.307-0.496-0.574-0.622
|
||||||
|
c-0.27-0.132-0.557-0.152-0.848-0.062c-0.205-0.393-0.422-0.584-0.695-0.646l-0.041-0.015c-0.105-0.022-0.191-0.036-0.342-0.024
|
||||||
|
c-0.082,0.008-0.158,0.026-0.223,0.046v-0.123v-0.845c0-0.625-0.301-1.028-0.893-1.198c-0.08-0.019-0.162-0.028-0.252-0.028
|
||||||
|
c-0.059,0-0.152,0.004-0.273,0.031c-0.59,0.179-0.879,0.573-0.879,1.213v4.206c-0.008-0.015-0.018-0.026-0.025-0.04
|
||||||
|
c-0.07-0.102-0.141-0.202-0.213-0.3c-0.316-0.431-0.764-0.614-1.279-0.533c-0.461,0.076-0.834,0.354-1.02,0.765
|
||||||
|
c-0.184,0.409-0.146,0.891,0.104,1.29c0.609,0.972,1.225,1.941,1.848,2.907c0.314,0.494,0.764,0.841,1.332,1.034l0.061,0.017
|
||||||
|
c0.523,0.129,0.93,0.133,0.949,0.134h2.178l0.16-0.029c0.115-0.022,0.234-0.047,0.35-0.077c1.191-0.329,2.033-1.417,2.047-2.644
|
||||||
|
c0.012-1.059,0.006-2.137,0.002-3.181v-0.166C22.229,14.237,21.729,13.729,21.096,13.729z M21.332,18.152
|
||||||
|
c0,0.921-0.6,1.68-1.484,1.883c-0.137,0.031-0.281,0.047-0.434,0.047c-0.68,0.006-1.355,0.008-2.039,0.001
|
||||||
|
c-0.652-0.005-1.16-0.286-1.506-0.833c-0.486-0.757-0.967-1.52-1.449-2.28l-0.359-0.567c-0.113-0.178-0.098-0.393,0.039-0.54
|
||||||
|
c0.086-0.094,0.203-0.148,0.326-0.148c0.068,0,0.135,0.02,0.195,0.053c0.064,0.038,0.127,0.096,0.166,0.153
|
||||||
|
c0.377,0.554,0.752,1.107,1.135,1.676c0.031,0.035,0.193,0.215,0.387,0.215c0.066,0,0.189-0.021,0.291-0.194
|
||||||
|
c0.027-0.069,0.041-0.188,0.041-0.362v-5.803c0-0.209,0.1-0.265,0.184-0.288c0.145-0.039,0.293,0.063,0.309,0.204
|
||||||
|
c0.004,0.044,0.004,0.092,0.004,0.138v3.285c0.009,0.127,0.07,0.38,0.426,0.38h0.101c0,0,0.13-0.002,0.241-0.117
|
||||||
|
c0.123-0.114,0.133-0.595,0.133-0.595c0-0.298,0-0.594,0-0.892c0.002-0.168,0.1-0.278,0.254-0.278
|
||||||
|
c0.141,0.001,0.244,0.108,0.244,0.257c0.004,0.326,0,0.65,0,0.976v0.383c0.006,0.081,0.054,0.222,0.34,0.267h0.234
|
||||||
|
c0.358,0.032,0.326-0.311,0.326-0.311v-0.345v-0.312c0.002-0.157,0.107-0.267,0.252-0.267c0.143,0,0.248,0.107,0.25,0.256
|
||||||
|
c0.004,0.178,0.004,0.357,0.002,0.535c0,0-0.002,0.438,0.279,0.438h0.25c0,0,0.223-0.014,0.275-0.324v0.001
|
||||||
|
c0.045-0.128,0.139-0.25,0.342-0.218c0.131,0,0.242,0.104,0.246,0.231l0.004,1.141C21.336,16.716,21.336,17.434,21.332,18.152z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.4 KiB |
|
@ -0,0 +1,50 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M17.221,14.709c-0.115,0-0.225,0.018-0.336,0.047c-0.113-0.285-0.307-0.496-0.574-0.621
|
||||||
|
c-0.27-0.133-0.557-0.152-0.848-0.063c-0.205-0.393-0.422-0.584-0.695-0.645l-0.041-0.016c-0.105-0.021-0.191-0.035-0.342-0.023
|
||||||
|
c-0.082,0.008-0.158,0.025-0.223,0.045v-0.123v-0.845c0-0.625-0.301-1.028-0.893-1.198c-0.08-0.019-0.162-0.028-0.252-0.028
|
||||||
|
c-0.059,0-0.152,0.004-0.273,0.031c-0.59,0.179-0.879,0.573-0.879,1.213v4.207c-0.008-0.014-0.018-0.025-0.025-0.039
|
||||||
|
c-0.07-0.102-0.141-0.203-0.213-0.301c-0.316-0.43-0.763-0.613-1.279-0.533c-0.461,0.076-0.834,0.354-1.02,0.766
|
||||||
|
c-0.184,0.408-0.146,0.891,0.104,1.289c0.61,0.973,1.225,1.941,1.848,2.908c0.314,0.494,0.764,0.84,1.332,1.033l0.061,0.018
|
||||||
|
c0.523,0.129,0.93,0.133,0.949,0.133h2.178l0.16-0.029c0.115-0.021,0.234-0.047,0.35-0.076c1.191-0.33,2.033-1.418,2.047-2.645
|
||||||
|
c0.012-1.059,0.006-2.137,0.002-3.18v-0.166C18.354,15.217,17.854,14.709,17.221,14.709z M17.457,19.133
|
||||||
|
c0,0.92-0.6,1.68-1.484,1.883c-0.137,0.031-0.281,0.047-0.434,0.047c-0.68,0.006-1.355,0.008-2.039,0
|
||||||
|
c-0.652-0.004-1.16-0.285-1.506-0.832c-0.486-0.758-0.966-1.52-1.449-2.281l-0.359-0.566c-0.113-0.178-0.098-0.393,0.039-0.541
|
||||||
|
c0.086-0.094,0.203-0.148,0.326-0.148c0.068,0,0.135,0.02,0.195,0.053c0.064,0.039,0.127,0.096,0.166,0.154
|
||||||
|
c0.376,0.553,0.751,1.107,1.134,1.676c0.031,0.035,0.193,0.215,0.387,0.215c0.066,0,0.189-0.021,0.291-0.195
|
||||||
|
c0.027-0.068,0.041-0.188,0.041-0.361V12.43c0-0.209,0.1-0.265,0.184-0.288c0.145-0.039,0.293,0.063,0.309,0.204
|
||||||
|
c0.004,0.044,0.004,0.092,0.004,0.138v3.286c0.01,0.127,0.07,0.381,0.426,0.381h0.102c0,0,0.129-0.002,0.24-0.117
|
||||||
|
c0.123-0.115,0.133-0.596,0.133-0.596c0-0.297,0-0.594,0-0.891c0.002-0.168,0.1-0.279,0.254-0.279
|
||||||
|
c0.141,0.002,0.244,0.109,0.244,0.258c0.004,0.326,0,0.65,0,0.975v0.383c0.006,0.082,0.055,0.223,0.34,0.268h0.234
|
||||||
|
c0.359,0.031,0.326-0.311,0.326-0.311v-0.346v-0.311c0.002-0.158,0.107-0.268,0.252-0.268c0.143,0,0.248,0.107,0.25,0.256
|
||||||
|
c0.004,0.178,0.004,0.357,0.002,0.535c0,0-0.002,0.439,0.279,0.439h0.25c0,0,0.223-0.014,0.275-0.324l0,0
|
||||||
|
c0.045-0.127,0.139-0.25,0.342-0.217c0.131,0,0.242,0.104,0.246,0.23l0.004,1.141C17.461,17.695,17.461,18.414,17.457,19.133z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M14.682,4.783c-0.109-0.145-0.284-0.204-0.456-0.167c-0.152,0.029-0.267,0.125-0.344,0.287
|
||||||
|
c-0.064,0.14-0.131,0.277-0.2,0.416L13.62,5.443l-0.053-0.025l0.268-0.548c0.161-0.342,0.222-0.634,0.198-0.918
|
||||||
|
c-0.068-0.899-0.687-1.625-1.57-1.85c-0.172-0.042-0.347-0.064-0.521-0.064c-0.75,0-1.406,0.392-1.709,1.021
|
||||||
|
c-1.5,3.085-2.997,6.172-4.486,9.261c-0.073,0.15-0.114,0.332-0.11,0.503c0.011,0.703,0.042,1.41,0.071,2.07
|
||||||
|
c0.006,0.129,0.015,0.303,0.102,0.418c0.1,0.131,0.095,0.232-0.024,0.414c-0.016,0.027-0.029,0.059-0.043,0.092
|
||||||
|
c-0.103,0.242-0.006,0.51,0.223,0.619c0.061,0.031,0.125,0.047,0.192,0.047c0.166,0,0.32-0.096,0.41-0.25
|
||||||
|
c0.029-0.047,0.053-0.1,0.078-0.152c0.021-0.047,0.043-0.094,0.064-0.131c0.009-0.014,0.03-0.027,0.035-0.029
|
||||||
|
c0.244-0.014,0.464-0.1,0.674-0.26c0.519-0.383,1.04-0.766,1.562-1.145c0.177-0.127,0.31-0.287,0.413-0.492
|
||||||
|
c0.709-1.473,1.42-2.934,2.134-4.402c0.539-1.11,1.079-2.221,1.616-3.332c0.007-0.012,0.014-0.023,0.017-0.035
|
||||||
|
c0.018,0.008,0.036,0.018,0.052,0.026l-1.615,3.328c-0.037,0.073-0.066,0.145-0.086,0.222c-0.061,0.246,0.077,0.48,0.324,0.547
|
||||||
|
c0.043,0.014,0.084,0.018,0.127,0.018c0.128,0,0.308-0.059,0.446-0.334l1.571-3.244c0.157-0.32,0.311-0.639,0.469-0.959
|
||||||
|
l0.279-0.579C14.813,5.106,14.797,4.934,14.682,4.783z M11.559,7.422c-0.094,0.199-0.188,0.394-0.28,0.586l-0.908,1.872
|
||||||
|
c-0.577,1.188-1.153,2.378-1.731,3.568c-0.052,0.104-0.074,0.072-0.13,0.064c-0.715-0.115-1.322-0.418-1.85-0.924
|
||||||
|
c-0.017-0.016-0.022-0.023-0.01-0.043c0.738-1.512,1.472-3.027,2.207-4.541l0.743-1.534C10.255,6.79,10.904,7.104,11.559,7.422z
|
||||||
|
M11.915,2.845v0.118c0.466,0,0.817,0.194,1.046,0.577c0.188,0.312,0.191,0.621,0.016,0.975c-0.243,0.483-0.478,0.97-0.712,1.457
|
||||||
|
l-0.285,0.587c-0.005,0.008-0.008,0.017-0.015,0.027l-1.956-0.95c0.049-0.106,0.1-0.208,0.147-0.309l0.325-0.673
|
||||||
|
c0.176-0.364,0.353-0.728,0.527-1.092c0.191-0.394,0.492-0.596,0.896-0.6L11.915,2.845L11.915,2.845z M7.709,14.295l-0.188,0.139
|
||||||
|
c-0.222,0.162-0.444,0.324-0.663,0.486c-0.083,0.059-0.129,0.07-0.175,0.047c-0.038-0.018-0.057-0.045-0.061-0.164
|
||||||
|
c-0.008-0.246-0.017-0.482-0.026-0.738l-0.014-0.344C6.938,13.963,7.303,14.148,7.709,14.295z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.7 KiB |
|
@ -0,0 +1,57 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Vrstva_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
width="24px"
|
||||||
|
height="24px"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
enable-background="new 0 0 24 24"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="placeholder.svg"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata
|
||||||
|
id="metadata15"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs13" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2035"
|
||||||
|
id="namedview11"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="9.8333333"
|
||||||
|
inkscape:cx="12"
|
||||||
|
inkscape:cy="12"
|
||||||
|
inkscape:window-x="-13"
|
||||||
|
inkscape:window-y="-13"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="Vrstva_1" />
|
||||||
|
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:21.33333397px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||||
|
x="6.4067798"
|
||||||
|
y="21.355932"
|
||||||
|
id="text827"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan825"
|
||||||
|
x="6.4067798"
|
||||||
|
y="21.355932">?</tspan></text>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.9 KiB |
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="256px" height="256px" viewBox="0 0 256 256" enable-background="new 0 0 256 256" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<polygon fill="#C53620" points="146.424,82.454 146.424,0.009 41.555,0.009 41.555,132.476 41.555,134.875 41.555,136.483
|
||||||
|
41.555,149.734 41.555,164.561 41.555,210.879 41.555,222.338 41.555,232.549 41.555,238.801 41.555,249.24 41.555,255.99
|
||||||
|
214.445,255.99 214.445,82.454 "/>
|
||||||
|
<polygon fill="#6CBD45" points="155.248,0.053 155.248,73.619 214.445,73.619 "/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M192.199,165.65c-0.854-1.037-1.693-2.096-2.588-3.148l-5.592,6.719l-1.477,1.682
|
||||||
|
c-10.063,11.535-21.186,21.324-35.246,27.479c-13.006,5.668-25.996,5.518-39.008-0.277c-11.053-4.9-20.348-12.098-28.746-20.637
|
||||||
|
c-2.506-2.588-4.963-5.318-7.471-8.037c0.834-0.967,1.535-1.893,2.307-2.73c8.604-9.725,18.113-18.189,29.643-24.201
|
||||||
|
c8.184-4.269,16.779-6.838,26.145-6.363c6.088,0.289,11.889,1.895,17.482,4.277c8.947,3.975,16.779,9.5,23.982,15.996l5.67-6.641
|
||||||
|
c-8.67-7.823-18.256-14.473-29.375-18.588c-7.477-2.868-15.303-4.278-23.346-3.726c-9.861,0.713-18.945,3.992-27.479,8.89
|
||||||
|
c-12.93,7.465-23.777,17.471-33.006,29.164c-0.771,0.896-1.258,2.021-1.887,2.992v1.529c0.555,0.99,1.049,2.041,1.748,2.873
|
||||||
|
c4.26,5.535,8.943,10.563,14.049,15.244c8.957,8.115,18.738,14.963,30.066,19.299c7.551,2.875,15.385,4.191,23.42,3.631
|
||||||
|
c9.857-0.629,18.957-3.906,27.484-8.865c12.863-7.357,23.563-17.275,32.785-28.805c0.844-0.982,1.402-2.248,2.029-3.365v-1.523
|
||||||
|
C193.318,167.615,192.818,166.576,192.199,165.65z"/>
|
||||||
|
<path fill="#FFFFFF" d="M154.039,169.348c-0.027,14.379-11.768,26.051-26.102,25.965c-14.373-0.1-25.922-11.721-25.898-26.041
|
||||||
|
c0.039-14.396,11.748-26.074,26.098-25.963C142.514,143.414,154.072,155.018,154.039,169.348z M145.383,169.348
|
||||||
|
c0.027-9.547-7.68-17.303-17.283-17.379c-9.529-0.105-17.438,7.814-17.391,17.379c0.053,9.566,7.805,17.314,17.338,17.314
|
||||||
|
C137.584,186.662,145.344,178.914,145.383,169.348z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -10,6 +10,6 @@ Pdf4QtPlugin {
|
||||||
]
|
]
|
||||||
Properties {
|
Properties {
|
||||||
condition: qbs.hostOS.contains("windows")
|
condition: qbs.hostOS.contains("windows")
|
||||||
cpp.defines: "DIMENTIONPLUGIN_LIBRARY"
|
cpp.defines: "DIMENSIONPLUGIN_LIBRARY"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ SUBDIRS += \
|
||||||
RedactPlugin \
|
RedactPlugin \
|
||||||
OutputPreviewPlugin \
|
OutputPreviewPlugin \
|
||||||
ObjectInspectorPlugin \
|
ObjectInspectorPlugin \
|
||||||
AudioBookPlugin
|
AudioBookPlugin \
|
||||||
|
SignaturePlugin
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"Name" : "Signature",
|
||||||
|
"Author" : "Jakub Melka",
|
||||||
|
"Version" : "1.0.0",
|
||||||
|
"License" : "LGPL v3",
|
||||||
|
"Description" : "Electronically or digitally sign PDF document."
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
# Copyright (C) 2022 Jakub Melka
|
||||||
|
#
|
||||||
|
# This file is part of PDF4QT.
|
||||||
|
#
|
||||||
|
# PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# with the written consent of the copyright owner, any later version.
|
||||||
|
#
|
||||||
|
# PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
TEMPLATE = lib
|
||||||
|
DEFINES += SIGNATUREPLUGIN_LIBRARY
|
||||||
|
|
||||||
|
QT += gui widgets
|
||||||
|
|
||||||
|
LIBS += -L$$OUT_PWD/../..
|
||||||
|
|
||||||
|
LIBS += -lPdf4QtLib
|
||||||
|
|
||||||
|
QMAKE_CXXFLAGS += /std:c++latest /utf-8
|
||||||
|
|
||||||
|
INCLUDEPATH += $$PWD/../../Pdf4QtLib/Sources
|
||||||
|
|
||||||
|
DESTDIR = $$OUT_PWD/../../pdfplugins
|
||||||
|
|
||||||
|
CONFIG += c++11
|
||||||
|
|
||||||
|
Pdf4Qt_OPENSSL_PATH = $$absolute_path(../../Tools, $$[QT_INSTALL_PREFIX])
|
||||||
|
|
||||||
|
# Link OpenSSL
|
||||||
|
LIBS += -L$$Pdf4Qt_OPENSSL_PATH/OpenSSL/Win_x64/bin -L$$Pdf4Qt_OPENSSL_PATH/OpenSSL/Win_x64/lib -llibcrypto -llibssl
|
||||||
|
INCLUDEPATH += $$Pdf4Qt_OPENSSL_PATH/OpenSSL/Win_x64/include
|
||||||
|
DEPENDPATH += $$Pdf4Qt_OPENSSL_PATH/OpenSSL/Win_x64/include
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
certificatemanager.cpp \
|
||||||
|
certificatemanagerdialog.cpp \
|
||||||
|
createcertificatedialog.cpp \
|
||||||
|
signatureplugin.cpp \
|
||||||
|
signdialog.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
certificatemanager.h \
|
||||||
|
certificatemanagerdialog.h \
|
||||||
|
createcertificatedialog.h \
|
||||||
|
signatureplugin.h \
|
||||||
|
signdialog.h
|
||||||
|
|
||||||
|
CONFIG += force_debug_info
|
||||||
|
|
||||||
|
DISTFILES += \
|
||||||
|
SignaturePlugin.json
|
||||||
|
|
||||||
|
RESOURCES += \
|
||||||
|
icons.qrc
|
||||||
|
|
||||||
|
FORMS += \
|
||||||
|
certificatemanagerdialog.ui \
|
||||||
|
createcertificatedialog.ui \
|
||||||
|
signdialog.ui
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import qbs
|
||||||
|
|
||||||
|
Pdf4QtPlugin {
|
||||||
|
name: "SignaturePlugin"
|
||||||
|
files: [
|
||||||
|
"*.h",
|
||||||
|
"*.cpp",
|
||||||
|
"*.ui",
|
||||||
|
"icons.qrc",
|
||||||
|
]
|
||||||
|
Properties {
|
||||||
|
condition: qbs.hostOS.contains("windows")
|
||||||
|
cpp.defines: "SIGNATUREPLUGIN_LIBRARY"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<circle fill="#21E900" cx="12" cy="12" r="11.098"/>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M10.896,18.354c-0.24,0-0.474-0.087-0.658-0.247L6.28,14.649c-0.416-0.363-0.459-0.995-0.095-1.411
|
||||||
|
c0.363-0.414,0.996-0.458,1.411-0.095l3.042,2.656l5.56-9.652c0.274-0.478,0.887-0.643,1.365-0.368
|
||||||
|
c0.479,0.276,0.644,0.887,0.367,1.366l-6.167,10.707c-0.149,0.26-0.407,0.438-0.702,0.487
|
||||||
|
C11.005,18.349,10.95,18.354,10.896,18.354z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 889 B |
|
@ -0,0 +1,35 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M22.52,5.539c-0.157-0.208-0.406-0.292-0.655-0.239c-0.214,0.042-0.379,0.179-0.491,0.411
|
||||||
|
c-0.093,0.199-0.189,0.396-0.286,0.594L21,6.484l-0.076-0.036l0.385-0.784c0.228-0.49,0.318-0.908,0.283-1.315
|
||||||
|
c-0.098-1.286-0.982-2.325-2.247-2.646C19.099,1.643,18.85,1.611,18.6,1.611c-1.073,0-2.012,0.56-2.448,1.46
|
||||||
|
c-2.148,4.415-4.288,8.831-6.421,13.249c-0.104,0.213-0.163,0.475-0.158,0.72c0.017,1.006,0.06,2.014,0.102,2.961
|
||||||
|
c0.009,0.183,0.021,0.43,0.146,0.596c0.143,0.19,0.136,0.335-0.034,0.595c-0.023,0.038-0.041,0.081-0.062,0.13
|
||||||
|
c-0.147,0.347-0.01,0.728,0.319,0.886c0.087,0.043,0.179,0.065,0.274,0.065c0.238,0,0.458-0.135,0.586-0.355
|
||||||
|
c0.042-0.071,0.077-0.146,0.112-0.221c0.03-0.067,0.062-0.132,0.093-0.187c0.012-0.017,0.042-0.037,0.049-0.041
|
||||||
|
c0.349-0.018,0.665-0.14,0.964-0.369c0.743-0.55,1.489-1.097,2.238-1.637c0.252-0.182,0.443-0.413,0.588-0.707
|
||||||
|
c1.016-2.102,2.035-4.198,3.055-6.297c0.771-1.588,1.544-3.177,2.314-4.767c0.008-0.017,0.016-0.033,0.024-0.05
|
||||||
|
c0.024,0.012,0.049,0.025,0.073,0.037l-2.31,4.762c-0.052,0.104-0.095,0.209-0.124,0.317c-0.086,0.35,0.112,0.688,0.463,0.782
|
||||||
|
c0.063,0.018,0.123,0.026,0.183,0.026c0.182,0,0.441-0.083,0.637-0.477l2.249-4.64c0.224-0.458,0.446-0.915,0.67-1.373
|
||||||
|
l0.401-0.827C22.709,6.001,22.686,5.755,22.52,5.539z M18.052,9.316c-0.135,0.285-0.27,0.563-0.401,0.838l-1.302,2.679
|
||||||
|
c-0.826,1.701-1.652,3.403-2.476,5.104c-0.075,0.152-0.108,0.107-0.187,0.093c-1.024-0.164-1.89-0.596-2.646-1.32
|
||||||
|
c-0.025-0.023-0.032-0.034-0.014-0.061c1.055-2.166,2.105-4.33,3.156-6.496l1.064-2.195C16.184,8.41,17.113,8.861,18.052,9.316z
|
||||||
|
M18.562,2.766v0.169c0.666,0,1.169,0.278,1.497,0.825c0.266,0.446,0.273,0.889,0.022,1.395c-0.349,0.691-0.685,1.388-1.021,2.084
|
||||||
|
l-0.405,0.841c-0.008,0.012-0.014,0.024-0.02,0.038l-2.804-1.358c0.071-0.151,0.143-0.298,0.212-0.442l0.466-0.963
|
||||||
|
c0.253-0.521,0.506-1.042,0.756-1.563c0.271-0.564,0.704-0.852,1.281-0.858L18.562,2.766L18.562,2.766z M12.541,19.15l-0.27,0.198
|
||||||
|
c-0.317,0.231-0.635,0.463-0.948,0.695c-0.119,0.086-0.185,0.105-0.25,0.071c-0.055-0.028-0.081-0.068-0.086-0.237
|
||||||
|
c-0.012-0.349-0.025-0.693-0.039-1.053l-0.02-0.496C11.438,18.672,11.96,18.939,12.541,19.15z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M7.684,22.389c-1.105,0-1.947-0.215-2.457-0.847C4.544,20.695,4.598,19.261,5.4,16.89
|
||||||
|
c0.505-1.492,0.518-2.515,0.035-2.955c-0.804-0.737-2.982-0.025-3.682,0.282l-0.418-0.951c0.339-0.147,3.359-1.42,4.801-0.098
|
||||||
|
c0.82,0.751,0.903,2.116,0.247,4.055c-0.648,1.916-0.766,3.15-0.349,3.667c0.465,0.578,1.855,0.505,3.152,0.358l0.116,1.032
|
||||||
|
C8.716,22.346,8.174,22.389,7.684,22.389z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.0 KiB |
|
@ -0,0 +1,250 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "certificatemanager.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/rsaerr.h>
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/x509v3.h>
|
||||||
|
#include <openssl/pkcs12.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace pdfplugin
|
||||||
|
{
|
||||||
|
|
||||||
|
CertificateManager::CertificateManager()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using openssl_ptr = std::unique_ptr<T, void(*)(T*)>;
|
||||||
|
|
||||||
|
void CertificateManager::createCertificate(const NewCertificateInfo& info)
|
||||||
|
{
|
||||||
|
openssl_ptr<BIO> pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
||||||
|
|
||||||
|
if (pksBuffer)
|
||||||
|
{
|
||||||
|
openssl_ptr<BIGNUM> bignumber(BN_new(), &BN_free);
|
||||||
|
openssl_ptr<RSA> rsaKey(RSA_new(), &RSA_free);
|
||||||
|
|
||||||
|
BN_set_word(bignumber.get(), RSA_F4);
|
||||||
|
const int rsaResult = RSA_generate_key_ex(rsaKey.get(), info.rsaKeyLength, bignumber.get(), nullptr);
|
||||||
|
if (rsaResult)
|
||||||
|
{
|
||||||
|
openssl_ptr<X509> certificate(X509_new(), &X509_free);
|
||||||
|
openssl_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), &EVP_PKEY_free);
|
||||||
|
|
||||||
|
EVP_PKEY_set1_RSA(privateKey.get(), rsaKey.get());
|
||||||
|
ASN1_INTEGER* serialNumber = X509_get_serialNumber(certificate.get());
|
||||||
|
ASN1_INTEGER_set(serialNumber, info.serialNumber);
|
||||||
|
|
||||||
|
// Set validity of the certificate
|
||||||
|
X509_gmtime_adj(X509_getm_notBefore(certificate.get()), 0);
|
||||||
|
X509_gmtime_adj(X509_getm_notAfter(certificate.get()), info.validityInSeconds);
|
||||||
|
|
||||||
|
// Set name
|
||||||
|
X509_NAME* name = X509_get_subject_name(certificate.get());
|
||||||
|
|
||||||
|
auto addString = [name](const char* identifier, QString string)
|
||||||
|
{
|
||||||
|
if (string.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray stringUtf8 = string.toUtf8();
|
||||||
|
X509_NAME_add_entry_by_txt(name, identifier, MBSTRING_UTF8, reinterpret_cast<const unsigned char*>(stringUtf8.constData()), stringUtf8.length(), -1, 0);
|
||||||
|
};
|
||||||
|
addString("C", info.certCountryCode);
|
||||||
|
addString("O", info.certOrganization);
|
||||||
|
addString("OU", info.certOrganizationUnit);
|
||||||
|
addString("CN", info.certCommonName);
|
||||||
|
addString("E", info.certEmail);
|
||||||
|
|
||||||
|
X509_EXTENSION* extension = nullptr;
|
||||||
|
X509V3_CTX context = { };
|
||||||
|
X509V3_set_ctx_nodb(&context);
|
||||||
|
X509V3_set_ctx(&context, certificate.get(), certificate.get(), nullptr, nullptr, 0);
|
||||||
|
extension = X509V3_EXT_conf_nid (NULL, &context, NID_key_usage, "digitalSignature, keyAgreement");
|
||||||
|
X509_add_ext(certificate.get(), extension, -1);
|
||||||
|
X509_EXTENSION_free(extension);
|
||||||
|
|
||||||
|
X509_set_issuer_name(certificate.get(), name);
|
||||||
|
|
||||||
|
// Set public key
|
||||||
|
X509_set_pubkey(certificate.get(), privateKey.get());
|
||||||
|
X509_sign(certificate.get(), privateKey.get(), EVP_sha512());
|
||||||
|
|
||||||
|
// Private key password
|
||||||
|
QByteArray privateKeyPaswordUtf8 = info.privateKeyPasword.toUtf8();
|
||||||
|
|
||||||
|
// Write the data
|
||||||
|
openssl_ptr<PKCS12> pkcs12(PKCS12_create(privateKeyPaswordUtf8.constData(),
|
||||||
|
nullptr,
|
||||||
|
privateKey.get(),
|
||||||
|
certificate.get(),
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
PKCS12_DEFAULT_ITER,
|
||||||
|
PKCS12_DEFAULT_ITER,
|
||||||
|
0), &PKCS12_free);
|
||||||
|
i2d_PKCS12_bio(pksBuffer.get(), pkcs12.get());
|
||||||
|
|
||||||
|
BUF_MEM* pksMemoryBuffer = nullptr;
|
||||||
|
BIO_get_mem_ptr(pksBuffer.get(), &pksMemoryBuffer);
|
||||||
|
|
||||||
|
if (!info.fileName.isEmpty())
|
||||||
|
{
|
||||||
|
QFile file(info.fileName);
|
||||||
|
if (file.open(QFile::WriteOnly | QFile::Truncate))
|
||||||
|
{
|
||||||
|
file.write(pksMemoryBuffer->data, pksMemoryBuffer->length);
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfoList CertificateManager::getCertificates()
|
||||||
|
{
|
||||||
|
QDir directory(getCertificateDirectory());
|
||||||
|
return directory.entryInfoList(QStringList() << "*.pfx", QDir::Files | QDir::NoDotAndDotDot | QDir::Readable, QDir::Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CertificateManager::getCertificateDirectory()
|
||||||
|
{
|
||||||
|
QDir directory(QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).front() + "/certificates/");
|
||||||
|
return directory.absolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CertificateManager::generateCertificateFileName()
|
||||||
|
{
|
||||||
|
QString directoryString = getCertificateDirectory();
|
||||||
|
QDir directory(directoryString);
|
||||||
|
|
||||||
|
int certificateIndex = 1;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
QString fileName = directory.absoluteFilePath(QString("cert_%1.pfx").arg(certificateIndex++));
|
||||||
|
if (!QFile::exists(fileName))
|
||||||
|
{
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CertificateManager::isCertificateValid(QString fileName, QString password)
|
||||||
|
{
|
||||||
|
QFile file(fileName);
|
||||||
|
if (file.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
QByteArray data = file.readAll();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
openssl_ptr<BIO> pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
||||||
|
BIO_write(pksBuffer.get(), data.constData(), data.length());
|
||||||
|
|
||||||
|
openssl_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free);
|
||||||
|
if (pkcs12)
|
||||||
|
{
|
||||||
|
const char* passwordPointer = nullptr;
|
||||||
|
QByteArray passwordByteArray = password.isEmpty() ? QByteArray() : password.toUtf8();
|
||||||
|
if (!passwordByteArray.isEmpty())
|
||||||
|
{
|
||||||
|
passwordPointer = passwordByteArray.constData();
|
||||||
|
}
|
||||||
|
|
||||||
|
return PKCS12_parse(pkcs12.get(), passwordPointer, nullptr, nullptr, nullptr) == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SignatureFactory::sign(QString certificateName, QString password, QByteArray data, QByteArray& result)
|
||||||
|
{
|
||||||
|
QFile file(certificateName);
|
||||||
|
if (file.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
QByteArray certificateData = file.readAll();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
openssl_ptr<BIO> certificateBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
||||||
|
BIO_write(certificateBuffer.get(), certificateData.constData(), certificateData.length());
|
||||||
|
|
||||||
|
openssl_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(certificateBuffer.get(), nullptr), &PKCS12_free);
|
||||||
|
if (pkcs12)
|
||||||
|
{
|
||||||
|
const char* passwordPointer = nullptr;
|
||||||
|
QByteArray passwordByteArray = password.isEmpty() ? QByteArray() : password.toUtf8();
|
||||||
|
if (!passwordByteArray.isEmpty())
|
||||||
|
{
|
||||||
|
passwordPointer = passwordByteArray.constData();
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_PKEY* key = nullptr;
|
||||||
|
X509* certificate = nullptr;
|
||||||
|
STACK_OF(X509)* certificates = nullptr;
|
||||||
|
if (PKCS12_parse(pkcs12.get(), passwordPointer, &key, &certificate, &certificates) == 1)
|
||||||
|
{
|
||||||
|
openssl_ptr<BIO> signedDataBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
||||||
|
BIO_write(signedDataBuffer.get(), data.constData(), data.length());
|
||||||
|
|
||||||
|
PKCS7* signature = PKCS7_sign(certificate, key, certificates, signedDataBuffer.get(), PKCS7_DETACHED | PKCS7_BINARY);
|
||||||
|
if (signature)
|
||||||
|
{
|
||||||
|
openssl_ptr<BIO> outputBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
||||||
|
i2d_PKCS7_bio(outputBuffer.get(), signature);
|
||||||
|
|
||||||
|
BUF_MEM* pksMemoryBuffer = nullptr;
|
||||||
|
BIO_get_mem_ptr(outputBuffer.get(), &pksMemoryBuffer);
|
||||||
|
|
||||||
|
result = QByteArray(pksMemoryBuffer->data, int(pksMemoryBuffer->length));
|
||||||
|
|
||||||
|
EVP_PKEY_free(key);
|
||||||
|
X509_free(certificate);
|
||||||
|
sk_X509_free(certificates);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_PKEY_free(key);
|
||||||
|
X509_free(certificate);
|
||||||
|
sk_X509_free(certificates);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdfplugin
|
|
@ -0,0 +1,64 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef CERTIFICATEMANAGER_H
|
||||||
|
#define CERTIFICATEMANAGER_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QFileInfoList>
|
||||||
|
|
||||||
|
namespace pdfplugin
|
||||||
|
{
|
||||||
|
|
||||||
|
class CertificateManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CertificateManager();
|
||||||
|
|
||||||
|
struct NewCertificateInfo
|
||||||
|
{
|
||||||
|
QString fileName;
|
||||||
|
QString privateKeyPasword;
|
||||||
|
|
||||||
|
QString certCountryCode;
|
||||||
|
QString certOrganization;
|
||||||
|
QString certOrganizationUnit;
|
||||||
|
QString certCommonName;
|
||||||
|
QString certEmail;
|
||||||
|
|
||||||
|
int rsaKeyLength = 1024;
|
||||||
|
int validityInSeconds = 2 * 365 * 24 * 3600;
|
||||||
|
long serialNumber = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
void createCertificate(const NewCertificateInfo& info);
|
||||||
|
|
||||||
|
static QFileInfoList getCertificates();
|
||||||
|
static QString getCertificateDirectory();
|
||||||
|
static QString generateCertificateFileName();
|
||||||
|
static bool isCertificateValid(QString fileName, QString password);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SignatureFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool sign(QString certificateName, QString password, QByteArray data, QByteArray& result);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdfplugin
|
||||||
|
|
||||||
|
#endif // CERTIFICATEMANAGER_H
|
|
@ -0,0 +1,133 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "certificatemanagerdialog.h"
|
||||||
|
#include "ui_certificatemanagerdialog.h"
|
||||||
|
#include "createcertificatedialog.h"
|
||||||
|
|
||||||
|
#include "pdfwidgetutils.h"
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QFileSystemModel>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
|
namespace pdfplugin
|
||||||
|
{
|
||||||
|
|
||||||
|
CertificateManagerDialog::CertificateManagerDialog(QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::CertificateManagerDialog),
|
||||||
|
m_newCertificateButton(nullptr),
|
||||||
|
m_openCertificateDirectoryButton(nullptr),
|
||||||
|
m_deleteCertificateButton(nullptr),
|
||||||
|
m_importCertificateButton(nullptr),
|
||||||
|
m_certificateFileModel(nullptr)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
QDir::root().mkpath(CertificateManager::getCertificateDirectory());
|
||||||
|
|
||||||
|
m_certificateFileModel = new QFileSystemModel(this);
|
||||||
|
QModelIndex rootIndex = m_certificateFileModel->setRootPath(CertificateManager::getCertificateDirectory());
|
||||||
|
ui->fileView->setModel(m_certificateFileModel);
|
||||||
|
ui->fileView->setRootIndex(rootIndex);
|
||||||
|
|
||||||
|
m_newCertificateButton = ui->buttonBox->addButton(tr("Create"), QDialogButtonBox::ActionRole);
|
||||||
|
m_openCertificateDirectoryButton = ui->buttonBox->addButton(tr("Open Directory"), QDialogButtonBox::ActionRole);
|
||||||
|
m_deleteCertificateButton = ui->buttonBox->addButton(tr("Delete"), QDialogButtonBox::ActionRole);
|
||||||
|
m_importCertificateButton = ui->buttonBox->addButton(tr("Import"), QDialogButtonBox::ActionRole);
|
||||||
|
|
||||||
|
connect(m_newCertificateButton, &QPushButton::clicked, this, &CertificateManagerDialog::onNewCertificateClicked);
|
||||||
|
connect(m_openCertificateDirectoryButton, &QPushButton::clicked, this, &CertificateManagerDialog::onOpenCertificateDirectoryClicked);
|
||||||
|
connect(m_deleteCertificateButton, &QPushButton::clicked, this, &CertificateManagerDialog::onDeleteCertificateClicked);
|
||||||
|
connect(m_importCertificateButton, &QPushButton::clicked, this, &CertificateManagerDialog::onImportCertificateClicked);
|
||||||
|
|
||||||
|
setMinimumSize(pdf::PDFWidgetUtils::scaleDPI(this, QSize(640, 480)));
|
||||||
|
}
|
||||||
|
|
||||||
|
CertificateManagerDialog::~CertificateManagerDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CertificateManagerDialog::onNewCertificateClicked()
|
||||||
|
{
|
||||||
|
CreateCertificateDialog dialog(this);
|
||||||
|
if (dialog.exec() == CreateCertificateDialog::Accepted)
|
||||||
|
{
|
||||||
|
const CertificateManager::NewCertificateInfo info = dialog.getNewCertificateInfo();
|
||||||
|
m_certificateManager.createCertificate(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CertificateManagerDialog::onOpenCertificateDirectoryClicked()
|
||||||
|
{
|
||||||
|
QDesktopServices::openUrl(QString("file:///%1").arg(CertificateManager::getCertificateDirectory(), QUrl::TolerantMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CertificateManagerDialog::onDeleteCertificateClicked()
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo = m_certificateFileModel->fileInfo(ui->fileView->currentIndex());
|
||||||
|
if (fileInfo.exists())
|
||||||
|
{
|
||||||
|
if (QMessageBox::question(this, tr("Confirm delete"), tr("Do you want to delete certificate '%1'?").arg(fileInfo.fileName()), QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
QFile file(fileInfo.filePath());
|
||||||
|
if (!file.remove())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Cannot delete certificate '%1'").arg(fileInfo.fileName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CertificateManagerDialog::onImportCertificateClicked()
|
||||||
|
{
|
||||||
|
QString selectedFile = QFileDialog::getOpenFileName(this, tr("Import Certificate"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), tr("Certificate file (*.pfx);;All files (*.*)"));
|
||||||
|
|
||||||
|
if (selectedFile.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(selectedFile);
|
||||||
|
if (file.exists())
|
||||||
|
{
|
||||||
|
QString path = CertificateManager::getCertificateDirectory();
|
||||||
|
QString targetFile = QString("%1/%2").arg(path, QFileInfo(file).fileName());
|
||||||
|
if (QFile::exists(targetFile))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Target file exists. Please rename the certificate file to import."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (file.copy(targetFile))
|
||||||
|
{
|
||||||
|
QMessageBox::information(this, tr("Import Certificate"), tr("Certificate '%1' was successfully imported.").arg(file.fileName()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Import Certificate"), tr("Error occured during certificate '%1' import.").arg(file.fileName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdfplugin
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef CERTIFICATEMANAGERDIALOG_H
|
||||||
|
#define CERTIFICATEMANAGERDIALOG_H
|
||||||
|
|
||||||
|
#include "certificatemanager.h"
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
class QAction;
|
||||||
|
class QFileSystemModel;
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class CertificateManagerDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace pdfplugin
|
||||||
|
{
|
||||||
|
|
||||||
|
class CertificateManagerDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CertificateManagerDialog(QWidget* parent);
|
||||||
|
virtual ~CertificateManagerDialog() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onNewCertificateClicked();
|
||||||
|
void onOpenCertificateDirectoryClicked();
|
||||||
|
void onDeleteCertificateClicked();
|
||||||
|
void onImportCertificateClicked();
|
||||||
|
|
||||||
|
Ui::CertificateManagerDialog* ui;
|
||||||
|
CertificateManager m_certificateManager;
|
||||||
|
QPushButton* m_newCertificateButton;
|
||||||
|
QPushButton* m_openCertificateDirectoryButton;
|
||||||
|
QPushButton* m_deleteCertificateButton;
|
||||||
|
QPushButton* m_importCertificateButton;
|
||||||
|
QFileSystemModel* m_certificateFileModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdfplugin
|
||||||
|
|
||||||
|
#endif // CERTIFICATEMANAGERDIALOG_H
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>CertificateManagerDialog</class>
|
||||||
|
<widget class="QDialog" name="CertificateManagerDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>789</width>
|
||||||
|
<height>511</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Certificate Manager</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="certificateGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Certificates</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeView" name="fileView"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Close</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>CertificateManagerDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>CertificateManagerDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
|
@ -0,0 +1,80 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" stroke="#292D32" stroke-width="0.2" stroke-miterlimit="10" d="M11.987,14.505
|
||||||
|
c-2.647,0.009-4.82-2.152-4.828-4.801c-0.01-2.663,2.153-4.833,4.818-4.837c2.656-0.003,4.824,2.144,4.828,4.8
|
||||||
|
C16.82,12.329,14.656,14.501,11.987,14.505z M11.958,13.266c1.961,0.02,3.586-1.575,3.61-3.538
|
||||||
|
c0.023-1.964-1.566-3.599-3.525-3.622C10.048,6.084,8.42,7.665,8.396,9.641C8.374,11.625,9.969,13.245,11.958,13.266z"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" fill="#292D32" stroke="#292D32" stroke-width="0.3" stroke-miterlimit="10" d="
|
||||||
|
M11.287,10.553c0.721-0.681,1.413-1.333,2.104-1.987c0.166-0.156,0.33-0.314,0.498-0.468c0.189-0.174,0.41-0.183,0.561-0.027
|
||||||
|
c0.154,0.158,0.137,0.374-0.057,0.556c-0.932,0.881-1.865,1.761-2.798,2.638c-0.21,0.198-0.409,0.193-0.612-0.013
|
||||||
|
c-0.476-0.483-0.947-0.97-1.42-1.456c-0.114-0.118-0.2-0.259-0.12-0.413c0.052-0.1,0.161-0.193,0.266-0.234
|
||||||
|
c0.155-0.061,0.281,0.042,0.389,0.153c0.357,0.368,0.715,0.735,1.071,1.104C11.208,10.446,11.24,10.494,11.287,10.553z"/>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M19.605,9.754c-0.025-0.07-0.025-0.168,0-0.247c0.203-0.596,0.377-1.082,0.547-1.53
|
||||||
|
c0.059-0.156,0.033-0.271-0.094-0.396c-0.373-0.355-0.76-0.74-1.154-1.142c-0.055-0.055-0.098-0.137-0.105-0.201
|
||||||
|
c-0.061-0.479-0.125-1.045-0.172-1.618c-0.014-0.186-0.094-0.285-0.275-0.341c-0.48-0.159-0.99-0.329-1.498-0.511
|
||||||
|
c-0.084-0.031-0.174-0.104-0.223-0.179c-0.316-0.489-0.615-0.986-0.84-1.365C15.703,2.08,15.607,2.03,15.426,2.05
|
||||||
|
c-0.547,0.076-1.096,0.138-1.66,0.202c-0.047,0.006-0.107-0.002-0.107-0.002c-0.52-0.337-1.043-0.679-1.563-1.02L12.07,1.213
|
||||||
|
h-0.144L11.9,1.23c-0.095,0.063-0.192,0.125-0.289,0.187c-0.218,0.139-0.444,0.283-0.65,0.449
|
||||||
|
c-0.426,0.35-0.866,0.451-1.398,0.315c-0.216-0.054-0.44-0.074-0.657-0.093C8.787,2.077,8.668,2.066,8.551,2.05
|
||||||
|
c-0.189-0.027-0.276,0.073-0.33,0.161C7.979,2.619,7.688,3.1,7.379,3.575C7.321,3.662,7.218,3.743,7.123,3.778
|
||||||
|
C6.622,3.967,6.108,4.138,5.627,4.294C5.459,4.349,5.388,4.442,5.371,4.625c-0.047,0.58-0.112,1.143-0.169,1.616
|
||||||
|
C5.193,6.31,5.15,6.393,5.098,6.445c-0.34,0.347-0.719,0.722-1.158,1.148c-0.091,0.089-0.165,0.198-0.092,0.39
|
||||||
|
c0.201,0.532,0.384,1.046,0.545,1.528c0.025,0.075,0.026,0.177,0,0.247c-0.167,0.499-0.349,1.007-0.541,1.511
|
||||||
|
c-0.065,0.172-0.039,0.297,0.095,0.432c0.348,0.325,0.712,0.683,1.146,1.126c0.057,0.058,0.102,0.147,0.108,0.224
|
||||||
|
c0.067,0.547,0.126,1.098,0.174,1.636c0.015,0.151,0.08,0.234,0.229,0.289c0.175,0.056,0.349,0.114,0.527,0.175
|
||||||
|
c0.088,0.03,0.177,0.061,0.268,0.091l0.872,0.238l0.547,0.922l0.003,0.011c0.13,0.209,0.26,0.416,0.376,0.622
|
||||||
|
c0.078,0.132,0.174,0.191,0.313,0.191c0.021,0,0.043-0.002,0.069-0.005c0.497-0.066,0.995-0.128,1.493-0.188l0.045-0.007
|
||||||
|
c0.063-0.008,0.134-0.011,0.196-0.004l0.005-0.002l0.016,0.009c0.036,0.006,0.076,0.011,0.09,0.03c0.003,0.004-0.002-0.004,0,0
|
||||||
|
l1.556,0.89c0,0-0.005,0.023-0.012,0.052c0.083,0.009,0.164-0.012,0.241-0.052l1.364-0.884c0.002-0.002,0-0.008,0.002-0.01
|
||||||
|
c0.014-0.017,0.037-0.026,0.064-0.032v-0.001l0,0c0.027-0.006,0.057-0.007,0.076-0.007c0.025,0,0.053,0.001,0.082,0.005
|
||||||
|
c0.24,0.022,0.482,0.054,0.725,0.084c0.141,0.017,0.279,0.034,0.418,0.051c0.061,0.006,0.125,0.019,0.188,0.031
|
||||||
|
c0.178,0.034,0.367,0.054,0.494,0.003l1.182-2.006h0.961c0.188-0.069,0.363-0.135,0.547-0.182c0.254-0.065,0.305-0.23,0.32-0.402
|
||||||
|
c0.039-0.53,0.102-1.061,0.166-1.557c0.006-0.073,0.051-0.161,0.107-0.22c0.355-0.366,0.725-0.73,1.131-1.111
|
||||||
|
c0.146-0.138,0.178-0.273,0.104-0.468C19.967,10.791,19.793,10.304,19.605,9.754z M18.111,9.891
|
||||||
|
c0.086,0.221,0.166,0.447,0.248,0.672c0.059,0.162,0.115,0.324,0.176,0.484c0.031,0.078,0.025,0.107-0.033,0.16
|
||||||
|
c-0.281,0.266-0.58,0.56-0.914,0.9c-0.092,0.098-0.154,0.23-0.17,0.354c-0.059,0.406-0.105,0.836-0.139,1.277
|
||||||
|
c-0.006,0.084-0.027,0.106-0.117,0.138c-0.396,0.13-0.807,0.265-1.211,0.418c-0.117,0.043-0.229,0.132-0.293,0.231
|
||||||
|
c-0.258,0.392-0.475,0.743-0.664,1.073c-0.063,0.112-0.129,0.104-0.215,0.096c-0.443-0.064-0.846-0.114-1.232-0.152l-0.033-0.001
|
||||||
|
c-0.109,0-0.236,0.033-0.352,0.095c-0.316,0.191-0.658,0.409-1.049,0.668c-0.049,0.032-0.083,0.047-0.112,0.047
|
||||||
|
c-0.018,0-0.048-0.004-0.105-0.043c-0.328-0.222-0.682-0.446-1.076-0.685c-0.065-0.044-0.138-0.065-0.186-0.079
|
||||||
|
c-0.013-0.004-0.023-0.007-0.031-0.011l-0.023-0.009l-0.438,0.054c-0.315,0.038-0.613,0.074-0.915,0.116
|
||||||
|
c-0.097,0.016-0.161,0.021-0.231-0.098c-0.192-0.34-0.408-0.693-0.661-1.081c-0.059-0.091-0.159-0.17-0.278-0.22
|
||||||
|
c-0.426-0.157-0.822-0.292-1.208-0.414c-0.096-0.033-0.122-0.054-0.128-0.153c-0.035-0.444-0.08-0.854-0.136-1.251
|
||||||
|
c-0.017-0.132-0.088-0.272-0.195-0.386c-0.271-0.289-0.559-0.563-0.836-0.828l-0.061-0.058c-0.057-0.058-0.059-0.083-0.033-0.146
|
||||||
|
l0.029-0.077c0.135-0.362,0.274-0.736,0.393-1.112C5.929,9.734,5.928,9.549,5.88,9.4C5.751,8.992,5.597,8.581,5.464,8.235
|
||||||
|
C5.436,8.155,5.441,8.13,5.499,8.075C5.86,7.731,6.151,7.445,6.411,7.176c0.087-0.086,0.156-0.218,0.173-0.338
|
||||||
|
c0.053-0.401,0.1-0.831,0.143-1.314C6.733,5.455,6.748,5.438,6.82,5.415C7.19,5.293,7.619,5.15,8.033,4.998
|
||||||
|
c0.125-0.046,0.251-0.147,0.322-0.256c0.249-0.377,0.48-0.763,0.673-1.089c0.054-0.09,0.088-0.08,0.149-0.072
|
||||||
|
c0.479,0.066,0.916,0.118,1.334,0.158c0.095,0.008,0.21-0.021,0.309-0.079c0.356-0.22,0.724-0.447,1.079-0.691
|
||||||
|
c0.054-0.036,0.084-0.04,0.102-0.04c0.03,0,0.065,0.014,0.113,0.046c0.354,0.236,0.717,0.467,1.08,0.688
|
||||||
|
c0.074,0.048,0.184,0.076,0.291,0.076l0.041-0.001c0.486-0.051,0.916-0.102,1.309-0.156c0.055-0.007,0.086-0.021,0.133,0.061
|
||||||
|
c0.207,0.353,0.434,0.729,0.68,1.09c0.074,0.113,0.203,0.215,0.336,0.267c0.211,0.079,0.422,0.15,0.631,0.221
|
||||||
|
c0.191,0.065,0.383,0.13,0.572,0.2c0.031,0.011,0.078,0.069,0.08,0.099c0.033,0.233,0.057,0.466,0.082,0.698
|
||||||
|
c0.023,0.211,0.045,0.421,0.072,0.628c0.012,0.11,0.076,0.236,0.162,0.321c0.311,0.32,0.623,0.628,0.928,0.915
|
||||||
|
c0.055,0.053,0.059,0.073,0.031,0.141C18.475,8.4,18.41,8.58,18.346,8.759c-0.078,0.216-0.156,0.432-0.236,0.643
|
||||||
|
C18.045,9.564,18.047,9.719,18.111,9.891z"/>
|
||||||
|
</g>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" fill="#292D32" d="M14.105,22.69c0.283,0,0.5-0.146,0.641-0.435
|
||||||
|
c0.209-0.434,0.42-0.868,0.629-1.303l0.426-0.881c0.031-0.064,0.064-0.127,0.1-0.196l0.084-0.159l0.078,0.021
|
||||||
|
c0.701,0.196,1.398,0.388,2.094,0.579l0.17,0.047c0.051,0.015,0.104,0.029,0.156,0.045c0.074,0.022,0.15,0.045,0.225,0.063
|
||||||
|
c0.084,0.021,0.164,0.03,0.238,0.03c0.205,0,0.369-0.077,0.504-0.235c0.191-0.222,0.223-0.478,0.098-0.76
|
||||||
|
c-0.275-0.615-0.553-1.229-0.832-1.844c-0.133-0.296-0.285-0.62-0.441-0.955c-0.301-0.65-0.613-1.322-0.859-1.908l-1.152,0.738
|
||||||
|
l0.547,1.245c0.264,0.584,0.527,1.17,0.799,1.773l0.084,0.187l-0.199-0.049c-0.041-0.01-0.074-0.017-0.102-0.022
|
||||||
|
c-0.033-0.008-0.061-0.014-0.086-0.021l-1.369-0.376c-0.527-0.146-0.777-0.032-1.018,0.466l-0.49,1.01
|
||||||
|
c-0.063,0.13-0.125,0.26-0.213,0.438l-0.094,0.19l-1.525-3.376l-0.826,0.324l-0.825-0.324l-1.527,3.376l-0.093-0.19
|
||||||
|
c-0.087-0.178-0.15-0.308-0.213-0.438l-0.49-1.009c-0.24-0.498-0.492-0.61-1.017-0.466l-1.371,0.377
|
||||||
|
c-0.024,0.007-0.05,0.013-0.085,0.021c-0.027,0.006-0.06,0.013-0.101,0.022l-0.199,0.049l0.084-0.187
|
||||||
|
c0.271-0.604,0.535-1.189,0.8-1.774l0.655-1.438l-1.362-0.281c-0.224,0.534-0.477,1.064-0.722,1.578
|
||||||
|
c-0.162,0.34-0.324,0.68-0.479,1.021c-0.278,0.615-0.556,1.229-0.831,1.844c-0.126,0.282-0.094,0.538,0.096,0.759
|
||||||
|
c0.185,0.217,0.429,0.285,0.742,0.206c0.076-0.019,0.151-0.041,0.227-0.063c0.052-0.016,0.104-0.03,0.156-0.045l0.17-0.047
|
||||||
|
c0.695-0.191,1.392-0.383,2.093-0.579l0.078-0.021l0.083,0.159c0.036,0.069,0.069,0.133,0.1,0.197l0.425,0.88
|
||||||
|
c0.21,0.435,0.419,0.869,0.63,1.303c0.141,0.288,0.356,0.435,0.641,0.435c0.299-0.006,0.511-0.154,0.647-0.441
|
||||||
|
c0.023-0.048,0.044-0.094,0.065-0.14l1.623-3.59l1.623,3.59c0.021,0.046,0.043,0.092,0.064,0.139
|
||||||
|
c0.137,0.288,0.35,0.437,0.631,0.442l0.018,0.098l0,0V22.69z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.0 KiB |
|
@ -0,0 +1,51 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M22.52,5.539c-0.156-0.208-0.406-0.292-0.654-0.239c-0.215,0.042-0.379,0.179-0.491,0.411
|
||||||
|
c-0.093,0.199-0.188,0.396-0.286,0.594L21,6.484l-0.076-0.036l0.385-0.784c0.229-0.49,0.318-0.908,0.283-1.315
|
||||||
|
c-0.098-1.286-0.982-2.325-2.246-2.646C19.1,1.643,18.85,1.611,18.6,1.611c-1.072,0-2.012,0.56-2.447,1.46
|
||||||
|
c-2.148,4.415-4.289,8.831-6.421,13.25c-0.104,0.213-0.163,0.475-0.158,0.72c0.017,1.006,0.06,2.015,0.102,2.961
|
||||||
|
c0.009,0.183,0.021,0.431,0.146,0.597c0.143,0.189,0.136,0.334-0.034,0.594c-0.023,0.039-0.041,0.082-0.062,0.131
|
||||||
|
c-0.147,0.347-0.01,0.728,0.319,0.886c0.087,0.043,0.179,0.065,0.274,0.065c0.238,0,0.458-0.135,0.586-0.355
|
||||||
|
c0.042-0.07,0.077-0.146,0.112-0.221c0.03-0.067,0.062-0.133,0.093-0.188c0.012-0.017,0.042-0.037,0.049-0.041
|
||||||
|
c0.349-0.018,0.665-0.14,0.964-0.369c0.743-0.55,1.489-1.097,2.237-1.637c0.252-0.182,0.443-0.413,0.589-0.707
|
||||||
|
c1.016-2.102,2.034-4.197,3.055-6.297c0.771-1.588,1.544-3.177,2.313-4.767c0.009-0.017,0.017-0.033,0.024-0.05
|
||||||
|
c0.024,0.012,0.05,0.025,0.073,0.037l-2.311,4.762c-0.051,0.104-0.095,0.209-0.123,0.317c-0.086,0.35,0.111,0.688,0.463,0.782
|
||||||
|
c0.063,0.019,0.123,0.026,0.183,0.026c0.183,0,0.44-0.084,0.638-0.478l2.248-4.64c0.225-0.458,0.446-0.915,0.67-1.373l0.401-0.827
|
||||||
|
C22.709,6.001,22.686,5.755,22.52,5.539z M18.052,9.316c-0.135,0.285-0.27,0.563-0.401,0.838l-1.301,2.679
|
||||||
|
c-0.826,1.701-1.652,3.403-2.477,5.104c-0.075,0.151-0.107,0.106-0.188,0.092c-1.023-0.163-1.89-0.596-2.646-1.319
|
||||||
|
c-0.025-0.022-0.032-0.034-0.014-0.062c1.055-2.166,2.105-4.33,3.156-6.496l1.064-2.195C16.184,8.41,17.113,8.861,18.052,9.316z
|
||||||
|
M18.563,2.766v0.169c0.666,0,1.168,0.278,1.496,0.825c0.267,0.446,0.273,0.889,0.022,1.395c-0.349,0.691-0.685,1.388-1.021,2.084
|
||||||
|
L18.654,8.08c-0.008,0.012-0.014,0.024-0.02,0.038L15.831,6.76c0.071-0.151,0.144-0.298,0.212-0.442l0.466-0.963
|
||||||
|
c0.253-0.521,0.507-1.042,0.757-1.563c0.271-0.564,0.703-0.852,1.28-0.858L18.563,2.766L18.563,2.766z M12.541,19.15l-0.27,0.197
|
||||||
|
c-0.317,0.231-0.635,0.463-0.948,0.695c-0.119,0.086-0.185,0.105-0.25,0.07c-0.055-0.027-0.081-0.067-0.086-0.236
|
||||||
|
c-0.012-0.35-0.025-0.693-0.039-1.053l-0.02-0.496C11.438,18.672,11.96,18.939,12.541,19.15z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M7.684,22.389c-1.105,0-1.947-0.215-2.457-0.847c-0.683-0.847-0.629-2.28,0.173-4.651
|
||||||
|
c0.505-1.492,0.518-2.516,0.035-2.955c-0.804-0.738-2.982-0.025-3.682,0.281l-0.418-0.951c0.339-0.146,3.359-1.419,4.801-0.098
|
||||||
|
c0.82,0.751,0.903,2.116,0.247,4.055c-0.648,1.916-0.766,3.15-0.349,3.668c0.465,0.578,1.855,0.504,3.152,0.357l0.116,1.031
|
||||||
|
C8.716,22.346,8.174,22.389,7.684,22.389z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<circle fill="#F12D32" cx="8.572" cy="5.808" r="4.197"/>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M6.366,7.536c0-0.004,0-0.009,0-0.013C6.367,7.508,6.375,7.502,6.377,7.49
|
||||||
|
c0.006-0.127,0.07-0.231,0.157-0.32c0.438-0.433,0.866-0.871,1.301-1.302c0.066-0.063,0.066-0.049,0-0.115
|
||||||
|
C7.401,5.316,6.969,4.88,6.531,4.446C6.457,4.373,6.402,4.285,6.384,4.18c-0.006-0.028-0.012-0.051-0.018-0.08
|
||||||
|
c0-0.004,0-0.011,0-0.016C6.37,4.071,6.377,4.057,6.377,4.042c0.019-0.201,0.161-0.374,0.365-0.419
|
||||||
|
c0.033-0.008,0.07-0.015,0.106-0.022c0.005,0,0.008,0,0.008,0C6.867,3.604,6.878,3.61,6.886,3.61
|
||||||
|
c0.141,0.005,0.249,0.076,0.344,0.174c0.435,0.437,0.874,0.873,1.312,1.31c0.027,0.026,0.048,0.032,0.073,0
|
||||||
|
c0.006-0.009,0.015-0.02,0.027-0.027C9.076,4.63,9.51,4.199,9.945,3.765c0.072-0.076,0.159-0.125,0.259-0.147
|
||||||
|
c0.032-0.004,0.059-0.011,0.091-0.016h0.005c0.018,0.002,0.036,0.009,0.049,0.009c0.237,0.017,0.442,0.261,0.429,0.495
|
||||||
|
c-0.013,0.14-0.069,0.251-0.164,0.345c-0.44,0.438-0.88,0.875-1.315,1.315c-0.042,0.042-0.042,0.042,0,0.086
|
||||||
|
c0.435,0.437,0.871,0.868,1.306,1.307c0.019,0.013,0.034,0.035,0.051,0.048c0.227,0.247,0.136,0.652-0.177,0.768
|
||||||
|
c-0.2,0.076-0.38,0.035-0.531-0.116C9.51,7.421,9.064,6.976,8.629,6.539c-0.048-0.05-0.048-0.05-0.096,0
|
||||||
|
c-0.444,0.44-0.887,0.888-1.329,1.328C7.068,8,6.907,8.042,6.727,7.992c-0.184-0.05-0.293-0.178-0.339-0.365
|
||||||
|
C6.375,7.595,6.372,7.565,6.366,7.536z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.3 KiB |
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M4.679,14.168c0-2.972,2.008-5.06,4.817-5.06c2.811,0,4.735,2.088,4.735,5.06
|
||||||
|
c0,2.889-1.848,5.057-4.815,5.057C6.604,19.225,4.679,17.057,4.679,14.168z"/>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M12.926,7.973c0,0.318,0.227,0.577,0.506,0.577h5.382c0.277,0,0.507-0.259,0.507-0.577l0,0
|
||||||
|
c0-0.318-0.229-0.576-0.507-0.576h-5.382C13.152,7.396,12.926,7.655,12.926,7.973L12.926,7.973z"/>
|
||||||
|
<path fill="#292D32" d="M16.121,11.169c0.317,0,0.576-0.228,0.576-0.508V5.283c0-0.279-0.259-0.508-0.576-0.508l0,0
|
||||||
|
c-0.315,0-0.574,0.229-0.574,0.508v5.38C15.547,10.943,15.806,11.169,16.121,11.169L16.121,11.169z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-width="1.5" stroke-miterlimit="10" d="M2.219,16.916c0,0,1.829-5.375,9.253-3.27
|
||||||
|
c7.8,2.213,8.95,1.967,10.308-0.605"/>
|
||||||
|
<path fill="#292D32" d="M14.854,9.8c0,0.271,0.192,0.49,0.429,0.49h4.568c0.236,0,0.431-0.22,0.431-0.49l0,0
|
||||||
|
c0-0.27-0.193-0.489-0.431-0.489h-4.568C15.047,9.311,14.854,9.53,14.854,9.8L14.854,9.8z"/>
|
||||||
|
<path fill="#292D32" d="M17.567,12.516c0.27,0,0.489-0.196,0.489-0.433V7.517c0-0.237-0.22-0.432-0.489-0.432l0,0
|
||||||
|
c-0.269,0-0.488,0.194-0.488,0.432v4.565C17.079,12.322,17.299,12.516,17.567,12.516L17.567,12.516z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<circle fill="#292D32" cx="3.012" cy="14.734" r="1.631"/>
|
||||||
|
<path fill="#292D32" d="M22.55,14.455c-0.039-0.09-0.091-0.176-0.163-0.242l-2.266-2.265c-0.294-0.297-0.771-0.297-1.064,0
|
||||||
|
c-0.293,0.292-0.293,0.767,0,1.062l0.948,0.938h-7.672H5.83v1.584h14.18l-0.938,0.939c-0.295,0.293-0.295,0.771,0,1.057
|
||||||
|
c0.144,0.15,0.337,0.221,0.527,0.221c0.194,0,0.38-0.07,0.528-0.221l2.263-2.27c0.074-0.061,0.134-0.143,0.164-0.236
|
||||||
|
c0.049-0.082,0.065-0.184,0.065-0.285C22.604,14.645,22.586,14.543,22.55,14.455z"/>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M13.716,9.075c0,0.281,0.2,0.51,0.445,0.51h4.749c0.246,0,0.448-0.229,0.448-0.51l0,0
|
||||||
|
c0-0.28-0.201-0.509-0.448-0.509h-4.749C13.916,8.566,13.716,8.794,13.716,9.075L13.716,9.075z"/>
|
||||||
|
<path fill="#292D32" d="M16.536,6.252c-0.279,0-0.508,0.202-0.508,0.449v4.746c0,0.25,0.229,0.451,0.508,0.451l0,0
|
||||||
|
c0.28,0,0.509-0.203,0.509-0.45V6.701C17.045,6.455,16.816,6.252,16.536,6.252"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
|
||||||
|
<rect x="3.138" y="12.585" transform="matrix(-0.7801 0.6256 -0.6256 -0.7801 29.7118 16.3621)" fill="#292D32" width="17.685" height="1.633"/>
|
||||||
|
<path fill="#292D32" d="M14.923,5.652h-1.865V3.788c0-0.247-0.229-0.449-0.511-0.449c-0.279,0-0.508,0.202-0.508,0.449v1.864
|
||||||
|
h-1.867C9.928,5.653,9.727,5.881,9.727,6.161c0,0.281,0.201,0.51,0.445,0.51h1.867v1.862c0,0.25,0.229,0.451,0.508,0.451
|
||||||
|
c0.282,0,0.511-0.203,0.511-0.449V6.671h1.865c0.246,0,0.447-0.229,0.447-0.51C15.37,5.881,15.169,5.652,14.923,5.652z"/>
|
||||||
|
<path fill="#292D32" d="M3.815,20.035c0.579,0.721,1.634,0.836,2.356,0.256c0.723-0.58,0.839-1.633,0.261-2.354
|
||||||
|
c-0.58-0.725-1.635-0.842-2.358-0.262C3.352,18.256,3.236,19.313,3.815,20.035z"/>
|
||||||
|
<circle fill="#292D32" cx="18.878" cy="7.87" r="1.677"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<circle fill="#F12D32" cx="10.482" cy="13.178" r="7.749"/>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M6.412,16.367c0-0.009,0-0.015,0-0.023c0.002-0.028,0.013-0.04,0.02-0.062
|
||||||
|
c0.01-0.233,0.13-0.426,0.289-0.586c0.81-0.802,1.6-1.61,2.403-2.405c0.122-0.117,0.122-0.09,0-0.211
|
||||||
|
c-0.803-0.808-1.602-1.614-2.411-2.411c-0.132-0.142-0.234-0.306-0.269-0.494c-0.01-0.053-0.019-0.096-0.032-0.147
|
||||||
|
c0-0.008,0-0.021,0-0.028c0.006-0.027,0.02-0.049,0.02-0.078c0.033-0.371,0.298-0.688,0.671-0.778
|
||||||
|
c0.065-0.012,0.131-0.024,0.201-0.037c0.004,0,0.01,0,0.01,0c0.021,0.002,0.038,0.017,0.055,0.017
|
||||||
|
C7.63,9.131,7.826,9.262,8.002,9.443c0.803,0.807,1.612,1.614,2.419,2.416c0.049,0.051,0.09,0.062,0.137,0
|
||||||
|
c0.01-0.017,0.027-0.037,0.048-0.047c0.803-0.803,1.603-1.604,2.41-2.402c0.131-0.143,0.293-0.233,0.477-0.274
|
||||||
|
c0.06-0.008,0.113-0.021,0.169-0.031h0.008c0.034,0.002,0.067,0.019,0.096,0.019c0.435,0.032,0.814,0.479,0.79,0.913
|
||||||
|
c-0.027,0.258-0.127,0.465-0.305,0.641c-0.813,0.804-1.626,1.615-2.427,2.418c-0.082,0.082-0.082,0.082,0,0.164
|
||||||
|
c0.801,0.805,1.605,1.604,2.409,2.412c0.032,0.024,0.064,0.066,0.094,0.091c0.417,0.454,0.25,1.204-0.326,1.421
|
||||||
|
c-0.368,0.137-0.702,0.057-0.976-0.217c-0.815-0.812-1.637-1.626-2.439-2.443c-0.088-0.086-0.088-0.086-0.176,0
|
||||||
|
c-0.82,0.817-1.638,1.645-2.454,2.455c-0.251,0.244-0.548,0.323-0.883,0.231c-0.335-0.092-0.539-0.329-0.623-0.675
|
||||||
|
C6.428,16.475,6.425,16.422,6.412,16.367z"/>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M15.623,5.896c0,0.281,0.2,0.51,0.445,0.51h4.749c0.246,0,0.448-0.229,0.448-0.51l0,0
|
||||||
|
c0-0.28-0.201-0.509-0.448-0.509h-4.749C15.823,5.388,15.623,5.616,15.623,5.896L15.623,5.896z"/>
|
||||||
|
<path fill="#292D32" d="M18.443,3.074c-0.279,0-0.508,0.202-0.508,0.449v4.746c0,0.25,0.229,0.451,0.508,0.451l0,0
|
||||||
|
c0.28,0,0.509-0.203,0.509-0.45V3.523C18.952,3.276,18.724,3.074,18.443,3.074"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
|
||||||
|
<rect x="3.069" y="8.156" fill="none" stroke="#292D32" stroke-width="1.4" stroke-miterlimit="10" width="12.628" height="12.629"/>
|
||||||
|
<path fill="#292D32" d="M15.287,6.038c0,0.281,0.2,0.51,0.445,0.51h4.749c0.246,0,0.448-0.229,0.448-0.51l0,0
|
||||||
|
c0-0.279-0.201-0.508-0.448-0.508h-4.749C15.487,5.53,15.287,5.758,15.287,6.038L15.287,6.038z"/>
|
||||||
|
<path fill="#292D32" d="M18.107,3.215c-0.279,0-0.508,0.203-0.508,0.449v4.746c0,0.25,0.229,0.451,0.508,0.451l0,0
|
||||||
|
c0.28,0,0.509-0.203,0.509-0.45V3.665C18.616,3.418,18.388,3.215,18.107,3.215"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1014 B |
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-width="1.4" stroke-miterlimit="10" d="M5.069,8.156h8.628c1.104,0,2,0.896,2,2v8.629
|
||||||
|
c0,1.104-0.896,2-2,2H5.069c-1.104,0-2-0.896-2-2v-8.629C3.069,9.051,3.965,8.156,5.069,8.156z"/>
|
||||||
|
<path fill="#292D32" d="M15.287,6.038c0,0.281,0.2,0.51,0.445,0.51h4.749c0.246,0,0.448-0.229,0.448-0.51l0,0
|
||||||
|
c0-0.279-0.201-0.508-0.448-0.508h-4.749C15.487,5.53,15.287,5.758,15.287,6.038L15.287,6.038z"/>
|
||||||
|
<path fill="#292D32" d="M18.107,3.215c-0.279,0-0.508,0.203-0.508,0.449v4.746c0,0.25,0.229,0.451,0.508,0.451l0,0
|
||||||
|
c0.28,0,0.509-0.203,0.509-0.45V3.665C18.616,3.418,18.388,3.215,18.107,3.215"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="none" stroke="#292D32" stroke-width="1.4" stroke-miterlimit="10" d="M5.069,8.156h8.628c1.104,0,2,0.896,2,2v8.629
|
||||||
|
c0,1.104-0.896,2-2,2H5.069c-1.104,0-2-0.896-2-2v-8.629C3.069,9.051,3.965,8.156,5.069,8.156z"/>
|
||||||
|
<path fill="#292D32" d="M15.287,6.038c0,0.281,0.199,0.51,0.445,0.51h4.748c0.246,0,0.449-0.229,0.449-0.51l0,0
|
||||||
|
c0-0.279-0.201-0.508-0.449-0.508h-4.748C15.486,5.53,15.287,5.758,15.287,6.038L15.287,6.038z"/>
|
||||||
|
<path fill="#292D32" d="M18.107,3.215c-0.279,0-0.508,0.203-0.508,0.449V8.41c0,0.25,0.229,0.451,0.508,0.451l0,0
|
||||||
|
c0.279,0,0.509-0.203,0.509-0.45V3.665C18.616,3.418,18.389,3.215,18.107,3.215"/>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M13.564,12.111c0.007,1.156-0.962,2.128-2.12,2.13c-1.174,0-2.135-0.961-2.135-2.13
|
||||||
|
c0-1.165,0.947-2.117,2.12-2.128C12.591,9.969,13.559,10.933,13.564,12.111z M11.429,13.078c0.525,0.007,0.974-0.435,0.975-0.963
|
||||||
|
c0.002-0.53-0.437-0.972-0.969-0.972c-0.52,0-0.955,0.43-0.965,0.955C10.458,12.627,10.894,13.072,11.429,13.078z"/>
|
||||||
|
<path fill="#292D32" d="M15.411,17.156c-0.478-0.384-0.938-0.75-1.396-1.104c-0.638-0.505-1.34-0.527-1.999-0.055
|
||||||
|
c-0.583,0.417-1.176,0.846-1.758,1.273c-0.252,0.176-0.407,0.165-0.627-0.044c-0.57-0.582-1.141-1.153-1.713-1.724
|
||||||
|
c-0.681-0.681-1.526-0.715-2.263-0.088c-0.935,0.79-1.867,1.57-2.802,2.361c-0.011,0.011-0.021,0.022-0.044,0.032v1.594
|
||||||
|
c0.056-0.109,0.154-0.221,0.275-0.319c1.121-0.912,2.23-1.856,3.351-2.789c0.252-0.221,0.428-0.21,0.658,0.033
|
||||||
|
c0.572,0.581,1.143,1.164,1.713,1.746c0.649,0.659,1.461,0.715,2.197,0.153c0.55-0.428,1.099-0.856,1.66-1.285
|
||||||
|
c0.23-0.187,0.384-0.187,0.614,0c0.704,0.56,1.417,1.132,2.109,1.702c0.01,0.007,0.015,0.02,0.023,0.027V17.156z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M6.694,16.22h-3.22l-0.465,1.132H1.275l2.947-7.224h1.734l2.949,7.224H7.157L6.694,16.22z M6.155,14.905
|
||||||
|
l-1.072-2.64l-1.072,2.64H6.155z"/>
|
||||||
|
<path fill="#292D32" d="M15.564,14.633c0,1.666-1.047,2.851-2.5,2.851c-0.763,0-1.388-0.327-1.82-0.897v0.766H9.706v-7.349h1.539
|
||||||
|
v2.672c0.432-0.557,1.057-0.881,1.82-0.881C14.518,11.794,15.564,12.968,15.564,14.633z M14.072,14.633
|
||||||
|
c0-0.905-0.598-1.545-1.453-1.545c-0.748,0-1.292,0.546-1.375,1.331v0.425c0.083,0.794,0.626,1.347,1.375,1.347
|
||||||
|
C13.475,16.188,14.072,15.545,14.072,14.633z"/>
|
||||||
|
<path fill="#292D32" d="M16.34,14.633c0-1.545,1.367-2.839,2.98-2.839c0.879,0,1.605,0.354,2.133,0.921l-1.021,0.875
|
||||||
|
c-0.273-0.307-0.705-0.505-1.125-0.505c-0.799,0-1.48,0.708-1.48,1.536c0,0.851,0.682,1.568,1.494,1.568
|
||||||
|
c0.422,0,0.859-0.208,1.146-0.53l1.02,0.86c-0.539,0.592-1.271,0.961-2.178,0.961C17.697,17.483,16.34,16.169,16.34,14.633z"/>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M18.639,8.562c0,0.203,0.145,0.369,0.322,0.369h3.438c0.18,0,0.326-0.166,0.326-0.369l0,0
|
||||||
|
c0-0.202-0.146-0.368-0.326-0.368h-3.438C18.783,8.193,18.639,8.359,18.639,8.562L18.639,8.562z"/>
|
||||||
|
<path fill="#292D32" d="M20.682,6.518c-0.203,0-0.369,0.146-0.369,0.325v3.436c0,0.183,0.166,0.328,0.369,0.328l0,0
|
||||||
|
c0.201,0,0.367-0.147,0.367-0.326V6.843C21.049,6.664,20.885,6.518,20.682,6.518"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<circle fill="#292D32" cx="8.556" cy="20.988" r="1.631"/>
|
||||||
|
<path fill="#292D32" d="M8.277,1.45c-0.09,0.038-0.176,0.091-0.242,0.163L5.77,3.879c-0.297,0.294-0.297,0.771,0,1.064
|
||||||
|
c0.292,0.293,0.767,0.293,1.062,0l0.938-0.948v7.672v6.503h1.584V3.99l0.939,0.938c0.293,0.295,0.772,0.295,1.057,0
|
||||||
|
c0.15-0.144,0.222-0.337,0.222-0.527c0-0.193-0.069-0.379-0.222-0.527L9.08,1.609C9.019,1.536,8.937,1.477,8.843,1.445
|
||||||
|
C8.761,1.396,8.66,1.381,8.558,1.381C8.466,1.396,8.365,1.414,8.277,1.45z"/>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M12.793,4.273c0,0.281,0.2,0.51,0.445,0.51h4.749c0.246,0,0.447-0.229,0.447-0.51l0,0
|
||||||
|
c0-0.28-0.2-0.509-0.447-0.509h-4.749C12.993,3.764,12.793,3.992,12.793,4.273L12.793,4.273z"/>
|
||||||
|
<path fill="#292D32" d="M15.613,1.45c-0.279,0-0.509,0.202-0.509,0.449v4.746c0,0.25,0.229,0.451,0.509,0.451l0,0
|
||||||
|
c0.28,0,0.509-0.203,0.509-0.45V1.899C16.122,1.653,15.894,1.45,15.613,1.45"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<circle fill="#57B400" cx="10.453" cy="13.176" r="7.736"/>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M15.982,10.202c-0.053,0.27-0.221,0.466-0.413,0.657c-1.996,1.992-3.996,3.988-5.987,5.976
|
||||||
|
c-0.271,0.276-0.585,0.392-0.961,0.259c-0.131-0.047-0.262-0.134-0.364-0.235c-1.016-1.004-2.024-2.022-3.038-3.034
|
||||||
|
c-0.152-0.15-0.243-0.329-0.291-0.535c0-0.074,0-0.147,0-0.22c0.049-0.203,0.127-0.39,0.287-0.536
|
||||||
|
c0.378-0.332,0.881-0.307,1.255,0.068c0.783,0.776,1.562,1.557,2.346,2.342c0.026,0.03,0.05,0.06,0.089,0.121
|
||||||
|
c0.047-0.057,0.063-0.091,0.094-0.116c1.812-1.81,3.625-3.625,5.441-5.445c0.262-0.262,0.568-0.376,0.931-0.262
|
||||||
|
c0.32,0.104,0.507,0.323,0.591,0.648c0.008,0.026,0.016,0.047,0.022,0.065C15.982,10.043,15.982,10.121,15.982,10.202z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M15.623,5.896c0,0.281,0.2,0.51,0.445,0.51h4.748c0.246,0,0.449-0.229,0.449-0.51l0,0
|
||||||
|
c0-0.28-0.201-0.509-0.449-0.509h-4.748C15.823,5.388,15.623,5.616,15.623,5.896L15.623,5.896z"/>
|
||||||
|
<path fill="#292D32" d="M18.443,3.074c-0.279,0-0.508,0.202-0.508,0.449v4.746c0,0.25,0.229,0.451,0.508,0.451l0,0
|
||||||
|
c0.279,0,0.509-0.203,0.509-0.45V3.523C18.952,3.276,18.725,3.074,18.443,3.074"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,162 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "createcertificatedialog.h"
|
||||||
|
#include "ui_createcertificatedialog.h"
|
||||||
|
|
||||||
|
#include "certificatemanager.h"
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include <QDate>
|
||||||
|
#include <QCalendar>
|
||||||
|
|
||||||
|
namespace pdfplugin
|
||||||
|
{
|
||||||
|
|
||||||
|
CreateCertificateDialog::CreateCertificateDialog(QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::CreateCertificateDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
ui->fileNameEdit->setReadOnly(true);
|
||||||
|
ui->fileNameEdit->setText(CertificateManager::generateCertificateFileName());
|
||||||
|
|
||||||
|
ui->keyLengthCombo->addItem(tr("1024 bits"), 1024);
|
||||||
|
ui->keyLengthCombo->addItem(tr("2048 bits"), 2048);
|
||||||
|
ui->keyLengthCombo->addItem(tr("4096 bits"), 4096);
|
||||||
|
ui->keyLengthCombo->setCurrentIndex(ui->keyLengthCombo->findData(2048));
|
||||||
|
|
||||||
|
QList<QLocale> locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
|
||||||
|
std::sort(locales.begin(), locales.end(), [](const QLocale& left, const QLocale& right) { return QString::compare(left.nativeCountryName(), right.nativeCountryName(), Qt::CaseInsensitive) < 0; });
|
||||||
|
|
||||||
|
int currentIndex = 0;
|
||||||
|
QLocale currentLocale = QLocale::system();
|
||||||
|
|
||||||
|
for (const QLocale& locale : locales)
|
||||||
|
{
|
||||||
|
if (locale.country() == QLocale::AnyCountry)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locale.nativeCountryName().isEmpty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString localeName = locale.name();
|
||||||
|
QString countryCode = localeName.split(QChar('_')).back();
|
||||||
|
QString text = QString("%1 | %2").arg(countryCode, locale.nativeCountryName());
|
||||||
|
|
||||||
|
if (ui->countryCombo->findText(text) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locale.bcp47Name() == currentLocale.bcp47Name())
|
||||||
|
{
|
||||||
|
currentIndex = ui->countryCombo->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->countryCombo->addItem(text, countryCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->countryCombo->setCurrentIndex(currentIndex);
|
||||||
|
ui->countryCombo->setMaxVisibleItems(25);
|
||||||
|
|
||||||
|
QDate minDate = QDate::currentDate();
|
||||||
|
ui->validTillEdit->setMinimumDate(minDate);
|
||||||
|
|
||||||
|
QDate selectedDate = minDate;
|
||||||
|
selectedDate = selectedDate.addYears(5, ui->validTillEdit->calendar());
|
||||||
|
ui->validTillEdit->setSelectedDate(selectedDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateCertificateDialog::~CreateCertificateDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateCertificateDialog::accept()
|
||||||
|
{
|
||||||
|
if (validate())
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
QString password1 = QInputDialog::getText(this, tr("Certificate Protection"), tr("Enter password to protect your certificate."), QLineEdit::Password, QString(), &ok);
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString password2 = QInputDialog::getText(this, tr("Certificate Protection"), tr("Enter password again to verify password text."), QLineEdit::Password, QString(), &ok);
|
||||||
|
|
||||||
|
if (password1 != password2)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Reentered password is not equal to the first one!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDate date = ui->validTillEdit->selectedDate();
|
||||||
|
QDate currentDate = QDate::currentDate();
|
||||||
|
int days = currentDate.daysTo(date);
|
||||||
|
|
||||||
|
// Fill certificate info
|
||||||
|
m_newCertificateInfo.fileName = ui->fileNameEdit->text();
|
||||||
|
m_newCertificateInfo.privateKeyPasword = password1;
|
||||||
|
m_newCertificateInfo.certCountryCode = ui->countryCombo->currentData().toString();
|
||||||
|
m_newCertificateInfo.certOrganization = ui->organizationEdit->text();
|
||||||
|
m_newCertificateInfo.certOrganizationUnit = ui->organizationUnitEdit->text();
|
||||||
|
m_newCertificateInfo.certCommonName = ui->commonNameEdit->text();
|
||||||
|
m_newCertificateInfo.certEmail = ui->emailEdit->text();
|
||||||
|
m_newCertificateInfo.rsaKeyLength = ui->keyLengthCombo->currentData().toInt();
|
||||||
|
m_newCertificateInfo.validityInSeconds = days * 24 * 3600;
|
||||||
|
|
||||||
|
BaseClass::accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateCertificateDialog::validate()
|
||||||
|
{
|
||||||
|
// validate empty text fields
|
||||||
|
if (ui->commonNameEdit->text().isEmpty())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Please enter a name!"));
|
||||||
|
ui->commonNameEdit->setFocus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui->organizationEdit->text().isEmpty())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Please enter an organization name!"));
|
||||||
|
ui->organizationEdit->setFocus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui->emailEdit->text().isEmpty())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Please enter an email address!"));
|
||||||
|
ui->emailEdit->setFocus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace plugin
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef CREATECERTIFICATEDIALOG_H
|
||||||
|
#define CREATECERTIFICATEDIALOG_H
|
||||||
|
|
||||||
|
#include "certificatemanager.h"
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class CreateCertificateDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace pdfplugin
|
||||||
|
{
|
||||||
|
|
||||||
|
class CreateCertificateDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
using BaseClass = QDialog;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CreateCertificateDialog(QWidget* parent);
|
||||||
|
virtual ~CreateCertificateDialog() override;
|
||||||
|
|
||||||
|
const CertificateManager::NewCertificateInfo& getNewCertificateInfo() const { return m_newCertificateInfo; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void accept() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool validate();
|
||||||
|
|
||||||
|
CertificateManager::NewCertificateInfo m_newCertificateInfo;
|
||||||
|
|
||||||
|
Ui::CreateCertificateDialog* ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace plugin
|
||||||
|
|
||||||
|
#endif // CREATECERTIFICATEDIALOG_H
|
|
@ -0,0 +1,182 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>CreateCertificateDialog</class>
|
||||||
|
<widget class="QDialog" name="CreateCertificateDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>514</width>
|
||||||
|
<height>488</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Create Certificate</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="certificateGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Create Self Signed Certificate</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="nameLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="commonNameEdit">
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="organizationLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Organization</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="organizationUnitLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Organization Unit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="emailLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Email</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="organizationEdit">
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLineEdit" name="organizationUnitEdit">
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QLineEdit" name="emailEdit">
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="countryLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Country</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="keyLengthLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Key length</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="validityLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Valid till</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QCalendarWidget" name="validTillEdit"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="QComboBox" name="keyLengthCombo"/>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QComboBox" name="countryCombo"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="fileNameEdit"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="certificateFileLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Certificate file</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>CreateCertificateDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>CreateCertificateDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/pdfplugins/signatureplugin">
|
||||||
|
<file>accept-mark.svg</file>
|
||||||
|
<file>reject-mark.svg</file>
|
||||||
|
<file>activate.svg</file>
|
||||||
|
<file>certificates.svg</file>
|
||||||
|
<file>clear.svg</file>
|
||||||
|
<file>create-dot.svg</file>
|
||||||
|
<file>create-freehand-curve.svg</file>
|
||||||
|
<file>create-horizontal-line.svg</file>
|
||||||
|
<file>create-line.svg</file>
|
||||||
|
<file>create-no-mark.svg</file>
|
||||||
|
<file>create-rectangle.svg</file>
|
||||||
|
<file>create-rounded-rectangle.svg</file>
|
||||||
|
<file>create-svg-image.svg</file>
|
||||||
|
<file>create-text.svg</file>
|
||||||
|
<file>create-vertical-line.svg</file>
|
||||||
|
<file>create-yes-mark.svg</file>
|
||||||
|
<file>sign-digitally.svg</file>
|
||||||
|
<file>sign-electronically.svg</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<circle fill="#C80000" cx="12" cy="12" r="11.098"/>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M13.713,12l5.063-4.201c0.46-0.381,0.524-1.07,0.143-1.539c-0.394-0.466-1.077-0.531-1.54-0.141
|
||||||
|
l-5.382,4.466L6.622,6.119C6.157,5.733,5.469,5.796,5.084,6.26C4.699,6.728,4.763,7.417,5.227,7.798L10.289,12l-5.062,4.204
|
||||||
|
c-0.464,0.389-0.528,1.074-0.143,1.54c0.216,0.258,0.527,0.394,0.84,0.394c0.246,0,0.491-0.079,0.697-0.253l5.377-4.462
|
||||||
|
l5.38,4.462c0.207,0.174,0.458,0.253,0.698,0.253c0.31,0,0.625-0.133,0.842-0.394c0.382-0.466,0.317-1.151-0.143-1.54L13.713,12z"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1,109 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M22.52,5.539c-0.156-0.208-0.406-0.292-0.653-0.239c-0.216,0.042-0.38,0.179-0.491,0.411
|
||||||
|
c-0.093,0.199-0.188,0.396-0.286,0.594L21,6.484l-0.076-0.036l0.385-0.784c0.229-0.49,0.318-0.908,0.283-1.315
|
||||||
|
c-0.098-1.286-0.982-2.325-2.246-2.646C19.1,1.643,18.85,1.611,18.6,1.611c-1.072,0-2.012,0.56-2.447,1.46
|
||||||
|
c-2.147,4.415-4.289,8.831-6.42,13.25c-0.104,0.214-0.163,0.476-0.158,0.721c0.017,1.006,0.06,2.016,0.102,2.961
|
||||||
|
c0.009,0.184,0.021,0.432,0.146,0.598c0.143,0.188,0.136,0.334-0.034,0.594c-0.023,0.039-0.041,0.082-0.062,0.131
|
||||||
|
c-0.147,0.347-0.01,0.729,0.319,0.886c0.087,0.043,0.179,0.065,0.274,0.065c0.238,0,0.458-0.135,0.586-0.355
|
||||||
|
c0.042-0.07,0.077-0.146,0.112-0.221c0.03-0.067,0.062-0.133,0.093-0.188c0.012-0.018,0.042-0.037,0.049-0.041
|
||||||
|
c0.349-0.019,0.665-0.141,0.964-0.369c0.743-0.551,1.488-1.098,2.236-1.638c0.252-0.183,0.443-0.413,0.59-0.707
|
||||||
|
c1.016-2.103,2.033-4.196,3.055-6.297c0.771-1.588,1.544-3.177,2.313-4.767c0.01-0.017,0.018-0.033,0.024-0.05
|
||||||
|
c0.024,0.012,0.05,0.025,0.073,0.037l-2.311,4.762c-0.052,0.104-0.096,0.208-0.123,0.317c-0.086,0.351,0.11,0.688,0.463,0.782
|
||||||
|
c0.063,0.02,0.123,0.025,0.183,0.025c0.183,0,0.44-0.084,0.638-0.478l2.248-4.64c0.225-0.458,0.446-0.915,0.67-1.373l0.401-0.827
|
||||||
|
C22.709,6.001,22.686,5.755,22.52,5.539z M18.052,9.316c-0.135,0.285-0.27,0.563-0.401,0.838l-1.301,2.679
|
||||||
|
c-0.826,1.701-1.651,3.403-2.477,5.104c-0.075,0.15-0.107,0.105-0.188,0.092c-1.023-0.163-1.891-0.596-2.646-1.319
|
||||||
|
c-0.025-0.022-0.032-0.034-0.014-0.062c1.055-2.166,2.105-4.331,3.157-6.497l1.063-2.195C16.184,8.41,17.113,8.861,18.052,9.316z
|
||||||
|
M18.563,2.935L18.563,2.935c0.666,0,1.168,0.278,1.496,0.825c0.268,0.446,0.273,0.889,0.022,1.395
|
||||||
|
c-0.349,0.691-0.685,1.388-1.021,2.084L18.654,8.08c-0.008,0.012-0.014,0.024-0.021,0.038L15.831,6.76
|
||||||
|
c0.071-0.151,0.144-0.298,0.212-0.442l0.466-0.963c0.253-0.521,0.507-1.042,0.757-1.563c0.271-0.564,0.703-0.852,1.28-0.858
|
||||||
|
L18.563,2.935L18.563,2.935z M12.541,19.15l-0.27,0.197c-0.317,0.23-0.635,0.463-0.948,0.694c-0.119,0.086-0.185,0.104-0.25,0.069
|
||||||
|
c-0.055-0.026-0.081-0.066-0.086-0.235c-0.012-0.351-0.025-0.692-0.039-1.054l-0.02-0.495
|
||||||
|
C11.438,18.672,11.96,18.939,12.541,19.15z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M7.684,22.389c-1.105,0-1.947-0.215-2.457-0.847c-0.683-0.847-0.629-2.28,0.173-4.651
|
||||||
|
c0.505-1.492,0.518-2.516,0.035-2.955c-0.804-0.738-2.982-0.024-3.682,0.281l-0.418-0.951c0.339-0.146,3.359-1.418,4.801-0.098
|
||||||
|
c0.82,0.751,0.903,2.116,0.247,4.055c-0.648,1.916-0.766,3.15-0.349,3.668c0.465,0.578,1.855,0.504,3.152,0.357l0.116,1.031
|
||||||
|
C8.716,22.346,8.174,22.389,7.684,22.389z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" stroke="#292D32" stroke-width="0.2" stroke-miterlimit="10" d="M8.341,8.233
|
||||||
|
C7.022,8.237,5.939,7.161,5.936,5.841c-0.005-1.327,1.072-2.408,2.4-2.41C9.659,3.43,10.739,4.5,10.741,5.823
|
||||||
|
C10.749,7.149,9.671,8.231,8.341,8.233z M8.327,7.615c0.977,0.011,1.786-0.784,1.798-1.762c0.011-0.978-0.78-1.793-1.756-1.804
|
||||||
|
C7.375,4.038,6.564,4.825,6.552,5.81C6.541,6.798,7.335,7.605,8.327,7.615z"/>
|
||||||
|
<path fill="#292D32" stroke="#292D32" stroke-width="0.3" stroke-miterlimit="10" d="M7.992,6.264
|
||||||
|
C8.351,5.925,8.696,5.6,9.04,5.274c0.083-0.078,0.165-0.156,0.249-0.233c0.095-0.087,0.204-0.091,0.28-0.013
|
||||||
|
c0.076,0.079,0.068,0.186-0.029,0.277C9.075,5.744,8.61,6.182,8.146,6.619C8.041,6.718,7.942,6.715,7.84,6.612
|
||||||
|
c-0.236-0.24-0.472-0.483-0.707-0.726c-0.057-0.059-0.1-0.128-0.06-0.206C7.1,5.631,7.154,5.585,7.206,5.564
|
||||||
|
c0.077-0.03,0.14,0.021,0.194,0.077C7.578,5.824,7.756,6.007,7.933,6.19C7.953,6.21,7.969,6.235,7.992,6.264z"/>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M12.136,5.866c-0.012-0.034-0.012-0.083,0-0.123c0.102-0.296,0.188-0.539,0.272-0.762
|
||||||
|
c0.03-0.078,0.017-0.135-0.047-0.198c-0.185-0.176-0.379-0.368-0.575-0.569c-0.027-0.027-0.049-0.068-0.052-0.1
|
||||||
|
c-0.03-0.239-0.063-0.521-0.086-0.806c-0.007-0.093-0.046-0.143-0.137-0.17c-0.239-0.079-0.494-0.164-0.747-0.254
|
||||||
|
c-0.041-0.016-0.086-0.052-0.111-0.09c-0.157-0.243-0.307-0.491-0.418-0.68c-0.043-0.072-0.091-0.097-0.182-0.087
|
||||||
|
C9.782,2.065,9.508,2.096,9.227,2.128C9.204,2.131,9.174,2.127,9.174,2.127C8.915,1.959,8.654,1.789,8.396,1.62L8.382,1.611H8.311
|
||||||
|
L8.297,1.62C8.25,1.65,8.202,1.681,8.154,1.712C8.045,1.782,7.933,1.854,7.83,1.936C7.618,2.11,7.398,2.161,7.133,2.094
|
||||||
|
C7.025,2.066,6.914,2.056,6.806,2.047C6.747,2.042,6.688,2.036,6.629,2.028c-0.094-0.014-0.137,0.037-0.164,0.08
|
||||||
|
c-0.121,0.204-0.266,0.443-0.42,0.68c-0.029,0.043-0.08,0.083-0.127,0.101c-0.25,0.094-0.506,0.18-0.746,0.257
|
||||||
|
C5.089,3.173,5.053,3.22,5.044,3.311C5.021,3.6,4.989,3.88,4.96,4.116C4.956,4.15,4.935,4.192,4.909,4.217
|
||||||
|
C4.739,4.391,4.551,4.577,4.332,4.79C4.287,4.834,4.25,4.888,4.286,4.984c0.1,0.265,0.191,0.521,0.271,0.761
|
||||||
|
c0.012,0.038,0.013,0.088,0,0.123C4.475,6.117,4.383,6.37,4.288,6.621C4.256,6.707,4.269,6.769,4.335,6.836
|
||||||
|
c0.174,0.162,0.355,0.34,0.571,0.562C4.935,7.426,4.957,7.471,4.96,7.509c0.033,0.272,0.063,0.547,0.087,0.815
|
||||||
|
c0.008,0.075,0.04,0.116,0.114,0.144c0.087,0.027,0.174,0.057,0.262,0.087C5.467,8.57,5.512,8.585,5.557,8.601l0.434,0.119
|
||||||
|
l0.273,0.459l0.001,0.005c0.065,0.104,0.129,0.208,0.188,0.31C6.492,9.559,6.54,9.589,6.609,9.589c0.01,0,0.021,0,0.034-0.003
|
||||||
|
c0.248-0.033,0.496-0.063,0.744-0.093l0.022-0.004C7.44,9.485,7.476,9.484,7.507,9.487l0.002-0.001l0.008,0.005
|
||||||
|
c0.018,0.003,0.038,0.005,0.045,0.015c0.001,0.002-0.001-0.002,0,0l0.775,0.444c0,0-0.002,0.012-0.006,0.025
|
||||||
|
c0.041,0.005,0.082-0.006,0.12-0.025l0.68-0.441c0.001-0.001,0-0.004,0.001-0.005C9.139,9.495,9.15,9.491,9.164,9.488V9.487l0,0
|
||||||
|
c0.013-0.003,0.028-0.003,0.038-0.003c0.013,0,0.026,0,0.041,0.002c0.119,0.011,0.241,0.027,0.361,0.042
|
||||||
|
c0.07,0.008,0.139,0.017,0.208,0.025c0.03,0.003,0.062,0.009,0.094,0.015c0.089,0.018,0.183,0.027,0.246,0.002l0.589-1h0.479
|
||||||
|
c0.093-0.035,0.18-0.067,0.272-0.091c0.126-0.033,0.152-0.114,0.159-0.2c0.019-0.265,0.051-0.528,0.083-0.776
|
||||||
|
c0.003-0.036,0.025-0.08,0.053-0.109c0.177-0.183,0.362-0.364,0.564-0.553c0.072-0.069,0.088-0.137,0.052-0.233
|
||||||
|
C12.316,6.383,12.229,6.141,12.136,5.866z M11.392,5.934c0.043,0.11,0.083,0.223,0.124,0.334c0.029,0.081,0.058,0.162,0.087,0.242
|
||||||
|
c0.016,0.039,0.013,0.054-0.016,0.08c-0.14,0.132-0.29,0.279-0.456,0.448c-0.046,0.049-0.077,0.115-0.084,0.177
|
||||||
|
c-0.029,0.203-0.052,0.417-0.069,0.636c-0.003,0.042-0.014,0.052-0.058,0.069c-0.198,0.064-0.402,0.131-0.604,0.208
|
||||||
|
c-0.059,0.021-0.114,0.066-0.146,0.115c-0.128,0.195-0.236,0.37-0.331,0.534C9.808,8.833,9.775,8.83,9.732,8.825
|
||||||
|
C9.511,8.793,9.311,8.769,9.118,8.75l-0.017,0c-0.054,0-0.118,0.016-0.175,0.048C8.769,8.892,8.598,9,8.404,9.13
|
||||||
|
C8.379,9.145,8.362,9.153,8.348,9.153c-0.009,0-0.023-0.002-0.052-0.021C8.132,9.021,7.956,8.909,7.759,8.79
|
||||||
|
C7.728,8.768,7.691,8.758,7.667,8.75C7.66,8.749,7.655,8.748,7.652,8.745L7.64,8.741L7.422,8.768
|
||||||
|
C7.265,8.787,7.117,8.805,6.966,8.825c-0.048,0.008-0.08,0.01-0.115-0.048c-0.096-0.17-0.203-0.346-0.33-0.538
|
||||||
|
c-0.029-0.046-0.079-0.085-0.138-0.11C6.171,8.05,5.973,7.983,5.781,7.922C5.733,7.906,5.72,7.895,5.717,7.846
|
||||||
|
C5.7,7.625,5.678,7.421,5.65,7.223C5.641,7.157,5.606,7.087,5.552,7.03C5.417,6.887,5.274,6.75,5.136,6.618l-0.03-0.029
|
||||||
|
C5.077,6.56,5.076,6.547,5.089,6.516l0.015-0.038c0.067-0.18,0.137-0.367,0.196-0.554c0.024-0.068,0.023-0.16-0.001-0.234
|
||||||
|
C5.234,5.486,5.158,5.282,5.091,5.109C5.077,5.07,5.08,5.057,5.109,5.03c0.179-0.172,0.325-0.314,0.454-0.448
|
||||||
|
C5.606,4.539,5.64,4.473,5.649,4.413C5.675,4.214,5.699,4,5.72,3.758c0.003-0.034,0.011-0.042,0.047-0.054
|
||||||
|
c0.184-0.061,0.398-0.131,0.604-0.208c0.062-0.022,0.125-0.073,0.16-0.127c0.124-0.188,0.239-0.38,0.335-0.543
|
||||||
|
c0.027-0.045,0.044-0.04,0.074-0.036C7.179,2.823,7.397,2.849,7.605,2.87C7.653,2.874,7.71,2.859,7.759,2.83
|
||||||
|
C7.937,2.72,8.12,2.607,8.297,2.486c0.027-0.018,0.042-0.02,0.051-0.02c0.015,0,0.033,0.007,0.057,0.023
|
||||||
|
C8.58,2.606,8.762,2.721,8.942,2.832C8.979,2.855,9.034,2.87,9.087,2.87l0.021-0.001C9.35,2.843,9.564,2.818,9.76,2.792
|
||||||
|
c0.028-0.004,0.043-0.011,0.066,0.03c0.103,0.175,0.216,0.363,0.339,0.542c0.037,0.057,0.101,0.107,0.167,0.133
|
||||||
|
c0.105,0.04,0.21,0.075,0.314,0.11c0.095,0.032,0.19,0.064,0.285,0.099c0.015,0.006,0.039,0.035,0.04,0.05
|
||||||
|
C10.988,3.873,11,3.989,11.012,4.105c0.011,0.104,0.023,0.209,0.036,0.313c0.006,0.055,0.038,0.118,0.081,0.16
|
||||||
|
c0.155,0.16,0.31,0.313,0.462,0.456c0.027,0.027,0.029,0.037,0.015,0.071c-0.033,0.088-0.065,0.178-0.097,0.267
|
||||||
|
c-0.039,0.107-0.078,0.215-0.118,0.32C11.359,5.771,11.36,5.849,11.392,5.934z"/>
|
||||||
|
</g>
|
||||||
|
<path fill="#292D32" d="M9.396,12.311c0.141,0,0.249-0.072,0.319-0.216c0.104-0.217,0.209-0.433,0.313-0.649l0.212-0.439
|
||||||
|
c0.015-0.032,0.032-0.063,0.049-0.097l0.042-0.079l0.039,0.01c0.35,0.099,0.697,0.193,1.044,0.289l0.084,0.023
|
||||||
|
c0.025,0.007,0.052,0.015,0.077,0.022c0.038,0.011,0.075,0.023,0.113,0.032c0.042,0.01,0.082,0.015,0.118,0.015
|
||||||
|
c0.102,0,0.184-0.039,0.251-0.117c0.095-0.111,0.111-0.239,0.049-0.379c-0.137-0.306-0.275-0.612-0.415-0.918
|
||||||
|
c-0.066-0.147-0.142-0.309-0.22-0.476c-0.149-0.324-0.306-0.659-0.428-0.95l-0.574,0.368l0.272,0.62
|
||||||
|
c0.132,0.292,0.263,0.583,0.398,0.883l0.042,0.094l-0.099-0.024c-0.021-0.005-0.038-0.009-0.051-0.011
|
||||||
|
c-0.017-0.004-0.03-0.007-0.042-0.01L10.31,10.11c-0.263-0.072-0.387-0.016-0.507,0.233l-0.244,0.503
|
||||||
|
c-0.031,0.065-0.063,0.129-0.106,0.218l-0.046,0.095l-0.76-1.682L8.234,9.638L7.823,9.477l-0.761,1.682l-0.046-0.095
|
||||||
|
c-0.043-0.089-0.075-0.153-0.106-0.218l-0.245-0.502c-0.119-0.249-0.245-0.304-0.506-0.232l-0.683,0.188
|
||||||
|
c-0.012,0.003-0.025,0.006-0.042,0.01c-0.014,0.003-0.03,0.006-0.05,0.011l-0.099,0.024l0.042-0.093
|
||||||
|
c0.135-0.301,0.267-0.592,0.398-0.884l0.327-0.716l-0.679-0.14C5.261,8.777,5.134,9.042,5.013,9.298
|
||||||
|
C4.932,9.467,4.851,9.637,4.774,9.806c-0.139,0.306-0.277,0.613-0.414,0.919c-0.063,0.141-0.047,0.268,0.047,0.378
|
||||||
|
c0.092,0.108,0.214,0.142,0.37,0.103c0.038-0.01,0.075-0.021,0.113-0.032c0.026-0.008,0.051-0.015,0.078-0.022l0.084-0.023
|
||||||
|
c0.346-0.095,0.694-0.19,1.043-0.288l0.039-0.01l0.041,0.079c0.019,0.035,0.035,0.066,0.05,0.097l0.212,0.439
|
||||||
|
c0.104,0.217,0.208,0.433,0.313,0.648c0.07,0.144,0.178,0.218,0.319,0.218c0.149-0.003,0.255-0.077,0.322-0.221
|
||||||
|
c0.012-0.023,0.022-0.046,0.033-0.07l0.809-1.789l0.808,1.789c0.011,0.023,0.021,0.047,0.032,0.07
|
||||||
|
c0.068,0.144,0.174,0.218,0.314,0.221l0.009,0.048l0,0L9.396,12.311L9.396,12.311z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,44 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<circle fill="#57B400" cx="8.629" cy="5.827" r="4.192"/>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M11.625,4.216c-0.029,0.146-0.12,0.252-0.225,0.356C10.32,5.652,9.236,6.733,8.157,7.81
|
||||||
|
C8.01,7.96,7.84,8.022,7.637,7.95C7.566,7.925,7.495,7.878,7.439,7.824C6.889,7.279,6.342,6.728,5.793,6.179
|
||||||
|
C5.71,6.097,5.661,6.001,5.635,5.889c0-0.041,0-0.08,0-0.119c0.026-0.11,0.069-0.211,0.155-0.291
|
||||||
|
C5.996,5.3,6.269,5.313,6.471,5.516c0.424,0.42,0.846,0.844,1.271,1.269C7.756,6.802,7.769,6.818,7.79,6.851
|
||||||
|
C7.816,6.82,7.824,6.802,7.841,6.789c0.982-0.981,1.964-1.965,2.948-2.951c0.143-0.143,0.308-0.204,0.505-0.143
|
||||||
|
c0.174,0.057,0.275,0.175,0.32,0.352c0.005,0.014,0.009,0.025,0.013,0.035C11.625,4.129,11.625,4.172,11.625,4.216z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M22.52,5.539c-0.156-0.208-0.406-0.292-0.653-0.239c-0.216,0.042-0.38,0.179-0.491,0.411
|
||||||
|
c-0.093,0.199-0.188,0.396-0.286,0.594L21,6.484l-0.076-0.036l0.385-0.784c0.229-0.49,0.318-0.908,0.283-1.315
|
||||||
|
c-0.098-1.286-0.982-2.325-2.246-2.646C19.1,1.643,18.85,1.611,18.6,1.611c-1.072,0-2.012,0.56-2.447,1.46
|
||||||
|
c-2.147,4.415-4.289,8.831-6.42,13.25c-0.104,0.214-0.163,0.476-0.158,0.721c0.017,1.006,0.06,2.016,0.102,2.961
|
||||||
|
c0.009,0.184,0.021,0.432,0.146,0.598c0.143,0.188,0.136,0.334-0.034,0.594c-0.023,0.039-0.041,0.082-0.062,0.131
|
||||||
|
c-0.147,0.347-0.01,0.729,0.319,0.886c0.087,0.043,0.179,0.065,0.274,0.065c0.238,0,0.458-0.135,0.586-0.355
|
||||||
|
c0.042-0.07,0.077-0.146,0.112-0.221c0.03-0.067,0.062-0.133,0.093-0.188c0.012-0.018,0.042-0.037,0.049-0.041
|
||||||
|
c0.349-0.019,0.665-0.141,0.964-0.369c0.743-0.551,1.488-1.098,2.236-1.638c0.252-0.183,0.443-0.413,0.59-0.707
|
||||||
|
c1.016-2.103,2.033-4.196,3.055-6.297c0.771-1.588,1.544-3.177,2.313-4.767c0.01-0.017,0.018-0.033,0.024-0.05
|
||||||
|
c0.024,0.012,0.05,0.025,0.073,0.037l-2.311,4.762c-0.052,0.104-0.096,0.208-0.123,0.317c-0.086,0.351,0.11,0.688,0.463,0.782
|
||||||
|
c0.063,0.02,0.123,0.025,0.183,0.025c0.183,0,0.44-0.084,0.638-0.478l2.248-4.64c0.225-0.458,0.446-0.915,0.67-1.373l0.401-0.827
|
||||||
|
C22.709,6.001,22.686,5.755,22.52,5.539z M18.052,9.316c-0.135,0.285-0.27,0.563-0.401,0.838l-1.301,2.679
|
||||||
|
c-0.826,1.701-1.651,3.403-2.477,5.104c-0.075,0.15-0.107,0.105-0.188,0.092c-1.023-0.163-1.891-0.596-2.646-1.319
|
||||||
|
c-0.025-0.022-0.032-0.034-0.014-0.062c1.055-2.166,2.105-4.331,3.157-6.497l1.063-2.195C16.184,8.41,17.113,8.861,18.052,9.316z
|
||||||
|
M18.563,2.766v0.169c0.666,0,1.168,0.278,1.496,0.825c0.268,0.446,0.273,0.889,0.022,1.395c-0.349,0.691-0.685,1.388-1.021,2.084
|
||||||
|
L18.654,8.08c-0.008,0.012-0.014,0.024-0.021,0.038L15.831,6.76c0.071-0.151,0.144-0.298,0.212-0.442l0.466-0.963
|
||||||
|
c0.253-0.521,0.507-1.042,0.757-1.563c0.271-0.564,0.703-0.852,1.28-0.858L18.563,2.766L18.563,2.766z M12.541,19.15l-0.27,0.197
|
||||||
|
c-0.317,0.23-0.635,0.463-0.948,0.694c-0.119,0.086-0.185,0.104-0.25,0.069c-0.055-0.026-0.081-0.066-0.086-0.235
|
||||||
|
c-0.012-0.351-0.025-0.692-0.039-1.054l-0.02-0.495C11.438,18.672,11.96,18.939,12.541,19.15z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#292D32" d="M7.684,22.389c-1.105,0-1.947-0.215-2.457-0.847c-0.683-0.847-0.629-2.28,0.173-4.651
|
||||||
|
c0.505-1.492,0.518-2.516,0.035-2.955c-0.804-0.738-2.982-0.024-3.682,0.281l-0.418-0.951c0.339-0.146,3.359-1.418,4.801-0.098
|
||||||
|
c0.82,0.751,0.903,2.116,0.247,4.055c-0.648,1.916-0.766,3.15-0.349,3.668c0.465,0.578,1.855,0.504,3.152,0.357l0.116,1.031
|
||||||
|
C8.716,22.346,8.174,22.389,7.684,22.389z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
|
@ -0,0 +1,666 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "signatureplugin.h"
|
||||||
|
#include "pdfdrawwidget.h"
|
||||||
|
#include "pdfutils.h"
|
||||||
|
#include "pdfpagecontenteditorwidget.h"
|
||||||
|
#include "pdfpagecontenteditorstylesettings.h"
|
||||||
|
#include "pdfdocumentbuilder.h"
|
||||||
|
#include "certificatemanagerdialog.h"
|
||||||
|
#include "signdialog.h"
|
||||||
|
#include "pdfdocumentwriter.h"
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
|
namespace pdfplugin
|
||||||
|
{
|
||||||
|
|
||||||
|
SignaturePlugin::SignaturePlugin() :
|
||||||
|
pdf::PDFPlugin(nullptr),
|
||||||
|
m_actions({ }),
|
||||||
|
m_tools({ }),
|
||||||
|
m_editorWidget(nullptr),
|
||||||
|
m_scene(nullptr),
|
||||||
|
m_sceneSelectionChangeEnabled(true)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::setWidget(pdf::PDFWidget* widget)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!m_widget);
|
||||||
|
|
||||||
|
BaseClass::setWidget(widget);
|
||||||
|
|
||||||
|
QAction* activateAction = new QAction(QIcon(":/pdfplugins/signatureplugin/activate.svg"), tr("Activate signature creator"), this);
|
||||||
|
QAction* createTextAction = new QAction(QIcon(":/pdfplugins/signatureplugin/create-text.svg"), tr("Create Text Label"), this);
|
||||||
|
QAction* createFreehandCurveAction = new QAction(QIcon(":/pdfplugins/signatureplugin/create-freehand-curve.svg"), tr("Create Freehand Curve"), this);
|
||||||
|
QAction* createAcceptMarkAction = new QAction(QIcon(":/pdfplugins/signatureplugin/create-yes-mark.svg"), tr("Create Accept Mark"), this);
|
||||||
|
QAction* createRejectMarkAction = new QAction(QIcon(":/pdfplugins/signatureplugin/create-no-mark.svg"), tr("Create Reject Mark"), this);
|
||||||
|
QAction* createRectangleAction = new QAction(QIcon(":/pdfplugins/signatureplugin/create-rectangle.svg"), tr("Create Rectangle"), this);
|
||||||
|
QAction* createRoundedRectangleAction = new QAction(QIcon(":/pdfplugins/signatureplugin/create-rounded-rectangle.svg"), tr("Create Rounded Rectangle"), this);
|
||||||
|
QAction* createHorizontalLineAction = new QAction(QIcon(":/pdfplugins/signatureplugin/create-horizontal-line.svg"), tr("Create Horizontal Line"), this);
|
||||||
|
QAction* createVerticalLineAction = new QAction(QIcon(":/pdfplugins/signatureplugin/create-vertical-line.svg"), tr("Create Vertical Line"), this);
|
||||||
|
QAction* createLineAction = new QAction(QIcon(":/pdfplugins/signatureplugin/create-line.svg"), tr("Create Line"), this);
|
||||||
|
QAction* createDotAction = new QAction(QIcon(":/pdfplugins/signatureplugin/create-dot.svg"), tr("Create Dot"), this);
|
||||||
|
QAction* createSvgImageAction = new QAction(QIcon(":/pdfplugins/signatureplugin/create-svg-image.svg"), tr("Create SVG Image"), this);
|
||||||
|
QAction* clearAction = new QAction(QIcon(":/pdfplugins/signatureplugin/clear.svg"), tr("Clear All Graphics"), this);
|
||||||
|
QAction* signElectronicallyAction = new QAction(QIcon(":/pdfplugins/signatureplugin/sign-electronically.svg"), tr("Sign Electronically"), this);
|
||||||
|
QAction* signDigitallyAction = new QAction(QIcon(":/pdfplugins/signatureplugin/sign-digitally.svg"), tr("Sign Digitally With Certificate"), this);
|
||||||
|
QAction* certificatesAction = new QAction(QIcon(":/pdfplugins/signatureplugin/certificates.svg"), tr("Certificates Manager"), this);
|
||||||
|
|
||||||
|
activateAction->setObjectName("signaturetool_activateAction");
|
||||||
|
createTextAction->setObjectName("signaturetool_createTextAction");
|
||||||
|
createFreehandCurveAction->setObjectName("signaturetool_createFreehandCurveAction");
|
||||||
|
createAcceptMarkAction->setObjectName("signaturetool_createAcceptMarkAction");
|
||||||
|
createRejectMarkAction->setObjectName("signaturetool_createRejectMarkAction");
|
||||||
|
createRectangleAction->setObjectName("signaturetool_createRectangleAction");
|
||||||
|
createRoundedRectangleAction->setObjectName("signaturetool_createRoundedRectangleAction");
|
||||||
|
createHorizontalLineAction->setObjectName("signaturetool_createHorizontalLineAction");
|
||||||
|
createVerticalLineAction->setObjectName("signaturetool_createVerticalLineAction");
|
||||||
|
createLineAction->setObjectName("signaturetool_createLineAction");
|
||||||
|
createDotAction->setObjectName("signaturetool_createDotAction");
|
||||||
|
createSvgImageAction->setObjectName("signaturetool_createSvgImageAction");
|
||||||
|
clearAction->setObjectName("signaturetool_clearAction");
|
||||||
|
signElectronicallyAction->setObjectName("signaturetool_signElectronicallyAction");
|
||||||
|
signDigitallyAction->setObjectName("signaturetool_signDigitallyAction");
|
||||||
|
certificatesAction->setObjectName("signaturetool_certificatesAction");
|
||||||
|
|
||||||
|
activateAction->setCheckable(true);
|
||||||
|
createTextAction->setCheckable(true);
|
||||||
|
createFreehandCurveAction->setCheckable(true);
|
||||||
|
createAcceptMarkAction->setCheckable(true);
|
||||||
|
createRejectMarkAction->setCheckable(true);
|
||||||
|
createRectangleAction->setCheckable(true);
|
||||||
|
createRoundedRectangleAction->setCheckable(true);
|
||||||
|
createHorizontalLineAction->setCheckable(true);
|
||||||
|
createVerticalLineAction->setCheckable(true);
|
||||||
|
createLineAction->setCheckable(true);
|
||||||
|
createDotAction->setCheckable(true);
|
||||||
|
createSvgImageAction->setCheckable(true);
|
||||||
|
|
||||||
|
m_actions[Activate] = activateAction;
|
||||||
|
m_actions[Text] = createTextAction;
|
||||||
|
m_actions[FreehandCurve] = createFreehandCurveAction;
|
||||||
|
m_actions[AcceptMark] = createAcceptMarkAction;
|
||||||
|
m_actions[RejectMark] = createRejectMarkAction;
|
||||||
|
m_actions[Rectangle] = createRectangleAction;
|
||||||
|
m_actions[RoundedRectangle] = createRoundedRectangleAction;
|
||||||
|
m_actions[HorizontalLine] = createHorizontalLineAction;
|
||||||
|
m_actions[VerticalLine] = createVerticalLineAction;
|
||||||
|
m_actions[Line] = createLineAction;
|
||||||
|
m_actions[Dot] = createDotAction;
|
||||||
|
m_actions[SvgImage] = createSvgImageAction;
|
||||||
|
m_actions[Clear] = clearAction;
|
||||||
|
m_actions[SignElectronically] = signElectronicallyAction;
|
||||||
|
m_actions[SignDigitally] = signDigitallyAction;
|
||||||
|
m_actions[Certificates] = certificatesAction;
|
||||||
|
|
||||||
|
QFile acceptMarkFile(":/pdfplugins/signatureplugin/accept-mark.svg");
|
||||||
|
QByteArray acceptMarkContent;
|
||||||
|
if (acceptMarkFile.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
acceptMarkContent = acceptMarkFile.readAll();
|
||||||
|
acceptMarkFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile rejectMarkFile(":/pdfplugins/signatureplugin/reject-mark.svg");
|
||||||
|
QByteArray rejectMarkContent;
|
||||||
|
if (rejectMarkFile.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
rejectMarkContent = rejectMarkFile.readAll();
|
||||||
|
rejectMarkFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_tools[TextTool] = new pdf::PDFCreatePCElementTextTool(widget->getDrawWidgetProxy(), &m_scene, createTextAction, this);
|
||||||
|
m_tools[FreehandCurveTool] = new pdf::PDFCreatePCElementFreehandCurveTool(widget->getDrawWidgetProxy(), &m_scene, createFreehandCurveAction, this);
|
||||||
|
m_tools[AcceptMarkTool] = new pdf::PDFCreatePCElementImageTool(widget->getDrawWidgetProxy(), &m_scene, createAcceptMarkAction, acceptMarkContent, false, this);
|
||||||
|
m_tools[RejectMarkTool] = new pdf::PDFCreatePCElementImageTool(widget->getDrawWidgetProxy(), &m_scene, createRejectMarkAction, rejectMarkContent, false, this);
|
||||||
|
m_tools[RectangleTool] = new pdf::PDFCreatePCElementRectangleTool(widget->getDrawWidgetProxy(), &m_scene, createRectangleAction, false, this);
|
||||||
|
m_tools[RoundedRectangleTool] = new pdf::PDFCreatePCElementRectangleTool(widget->getDrawWidgetProxy(), &m_scene, createRoundedRectangleAction, true, this);
|
||||||
|
m_tools[HorizontalLineTool] = new pdf::PDFCreatePCElementLineTool(widget->getDrawWidgetProxy(), &m_scene, createHorizontalLineAction, true, false, this);
|
||||||
|
m_tools[VerticalLineTool] = new pdf::PDFCreatePCElementLineTool(widget->getDrawWidgetProxy(), &m_scene, createVerticalLineAction, false, true, this);
|
||||||
|
m_tools[LineTool] = new pdf::PDFCreatePCElementLineTool(widget->getDrawWidgetProxy(), &m_scene, createLineAction, false, false, this);
|
||||||
|
m_tools[DotTool] = new pdf::PDFCreatePCElementDotTool(widget->getDrawWidgetProxy(), &m_scene, createDotAction, this);
|
||||||
|
m_tools[ImageTool] = new pdf::PDFCreatePCElementImageTool(widget->getDrawWidgetProxy(), &m_scene, createSvgImageAction, QByteArray(), true, this);
|
||||||
|
|
||||||
|
pdf::PDFToolManager* toolManager = widget->getToolManager();
|
||||||
|
for (pdf::PDFWidgetTool* tool : m_tools)
|
||||||
|
{
|
||||||
|
toolManager->addTool(tool);
|
||||||
|
connect(tool, &pdf::PDFWidgetTool::toolActivityChanged, this, &SignaturePlugin::onToolActivityChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_widget->addInputInterface(&m_scene);
|
||||||
|
m_widget->getDrawWidgetProxy()->registerDrawInterface(&m_scene);
|
||||||
|
m_scene.setWidget(m_widget);
|
||||||
|
connect(&m_scene, &pdf::PDFPageContentScene::sceneChanged, this, &SignaturePlugin::onSceneChanged);
|
||||||
|
connect(&m_scene, &pdf::PDFPageContentScene::selectionChanged, this, &SignaturePlugin::onSceneSelectionChanged);
|
||||||
|
connect(&m_scene, &pdf::PDFPageContentScene::editElementRequest, this, &SignaturePlugin::onSceneEditElement);
|
||||||
|
connect(clearAction, &QAction::triggered, &m_scene, &pdf::PDFPageContentScene::clear);
|
||||||
|
connect(activateAction, &QAction::triggered, this, &SignaturePlugin::setActive);
|
||||||
|
connect(signElectronicallyAction, &QAction::triggered, this, &SignaturePlugin::onSignElectronically);
|
||||||
|
connect(signDigitallyAction, &QAction::triggered, this, &SignaturePlugin::onSignDigitally);
|
||||||
|
connect(certificatesAction, &QAction::triggered, this, &SignaturePlugin::onOpenCertificatesManager);
|
||||||
|
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::setDocument(const pdf::PDFModifiedDocument& document)
|
||||||
|
{
|
||||||
|
BaseClass::setDocument(document);
|
||||||
|
|
||||||
|
if (document.hasReset())
|
||||||
|
{
|
||||||
|
setActive(false);
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<QAction*> SignaturePlugin::getActions() const
|
||||||
|
{
|
||||||
|
std::vector<QAction*> result;
|
||||||
|
|
||||||
|
result.push_back(m_actions[Activate]);
|
||||||
|
result.push_back(m_actions[SignElectronically]);
|
||||||
|
result.push_back(m_actions[SignDigitally]);
|
||||||
|
result.push_back(m_actions[Certificates]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onSceneChanged(bool graphicsOnly)
|
||||||
|
{
|
||||||
|
if (!graphicsOnly)
|
||||||
|
{
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_editorWidget)
|
||||||
|
{
|
||||||
|
m_editorWidget->updateItemsInListWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGraphics();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onSceneSelectionChanged()
|
||||||
|
{
|
||||||
|
if (m_editorWidget && m_sceneSelectionChangeEnabled)
|
||||||
|
{
|
||||||
|
m_editorWidget->setSelection(m_scene.getSelectedElementIds());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onWidgetSelectionChanged()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_editorWidget);
|
||||||
|
|
||||||
|
pdf::PDFTemporaryValueChange guard(&m_sceneSelectionChangeEnabled, false);
|
||||||
|
m_scene.setSelectedElementIds(m_editorWidget->getSelection());
|
||||||
|
}
|
||||||
|
|
||||||
|
pdf::PDFWidgetTool* SignaturePlugin::getActiveTool()
|
||||||
|
{
|
||||||
|
for (pdf::PDFWidgetTool* currentTool : m_tools)
|
||||||
|
{
|
||||||
|
if (currentTool->isActive())
|
||||||
|
{
|
||||||
|
return currentTool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onToolActivityChanged()
|
||||||
|
{
|
||||||
|
if (m_editorWidget)
|
||||||
|
{
|
||||||
|
pdf::PDFWidgetTool* activeTool = getActiveTool();
|
||||||
|
|
||||||
|
const pdf::PDFPageContentElement* element = nullptr;
|
||||||
|
pdf::PDFCreatePCElementTool* tool = qobject_cast<pdf::PDFCreatePCElementTool*>(activeTool);
|
||||||
|
if (tool)
|
||||||
|
{
|
||||||
|
element = tool->getElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_editorWidget->loadStyleFromElement(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onSceneEditElement(const std::set<pdf::PDFInteger>& elements)
|
||||||
|
{
|
||||||
|
if (elements.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdf::PDFPageContentElement* element = nullptr;
|
||||||
|
for (pdf::PDFInteger id : elements)
|
||||||
|
{
|
||||||
|
element = m_scene.getElementById(id);
|
||||||
|
if (element)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!element)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdf::PDFPageContentEditorStyleSettings::showEditElementStyleDialog(m_dataExchangeInterface->getMainWindow(), element))
|
||||||
|
{
|
||||||
|
updateGraphics();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onSignElectronically()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_document);
|
||||||
|
Q_ASSERT(!m_scene.isEmpty());
|
||||||
|
|
||||||
|
if (QMessageBox::question(m_dataExchangeInterface->getMainWindow(), tr("Confirm Signature"), tr("Document will be signed electronically. Do you want to continue?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
pdf::PDFDocumentModifier modifier(m_document);
|
||||||
|
|
||||||
|
std::set<pdf::PDFInteger> pageIndices = m_scene.getPageIndices();
|
||||||
|
for (pdf::PDFInteger pageIndex : pageIndices)
|
||||||
|
{
|
||||||
|
const pdf::PDFPage* page = m_document->getCatalog()->getPage(pageIndex);
|
||||||
|
pdf::PDFPageContentStreamBuilder pageContentStreamBuilder(modifier.getBuilder(),
|
||||||
|
pdf::PDFContentStreamBuilder::CoordinateSystem::PDF,
|
||||||
|
pdf::PDFPageContentStreamBuilder::Mode::PlaceAfter);
|
||||||
|
QPainter* painter = pageContentStreamBuilder.begin(page->getPageReference());
|
||||||
|
QList<pdf::PDFRenderError> errors;
|
||||||
|
pdf::PDFTextLayoutGetter nullGetter(nullptr, pageIndex);
|
||||||
|
m_scene.drawElements(painter, pageIndex, nullGetter, QMatrix(), nullptr, errors);
|
||||||
|
pageContentStreamBuilder.end(painter);
|
||||||
|
modifier.markPageContentsChanged();
|
||||||
|
}
|
||||||
|
m_scene.clear();
|
||||||
|
|
||||||
|
if (modifier.finalize())
|
||||||
|
{
|
||||||
|
emit m_widget->getToolManager()->documentModified(pdf::PDFModifiedDocument(modifier.getDocument(), nullptr, modifier.getFlags()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onSignDigitally()
|
||||||
|
{
|
||||||
|
// Jakub Melka: do we have certificates? If not,
|
||||||
|
// open certificate dialog, so the user can create
|
||||||
|
// a new one.
|
||||||
|
if (CertificateManager::getCertificates().isEmpty())
|
||||||
|
{
|
||||||
|
onOpenCertificatesManager();
|
||||||
|
|
||||||
|
if (CertificateManager::getCertificates().isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SignDialog dialog(m_dataExchangeInterface->getMainWindow(), m_scene.isEmpty());
|
||||||
|
if (dialog.exec() == SignDialog::Accepted)
|
||||||
|
{
|
||||||
|
QByteArray data = "SampleDataToBeSigned" + QByteArray::number(QDateTime::currentMSecsSinceEpoch());
|
||||||
|
QByteArray signature;
|
||||||
|
if (!SignatureFactory::sign(dialog.getCertificatePath(), dialog.getPassword(), data, signature))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(m_widget, tr("Error"), tr("Failed to create digital signature."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString signatureName = QString("pdf4qt_signature_%1").arg(QString::number(QDateTime::currentMSecsSinceEpoch()));
|
||||||
|
|
||||||
|
pdf::PDFInteger offsetMark = 123456789123;
|
||||||
|
constexpr const char* offsetMarkString = "123456789123";
|
||||||
|
const auto offsetMarkStringLength = std::strlen(offsetMarkString);
|
||||||
|
|
||||||
|
pdf::PDFDocumentBuilder builder(m_document);
|
||||||
|
pdf::PDFObjectReference signatureDictionary = builder.createSignatureDictionary("Adobe.PPKLite", "adbe.pkcs7.detached", signature, QDateTime::currentDateTime(), offsetMark);
|
||||||
|
pdf::PDFObjectReference formField = builder.createFormFieldSignature(signatureName, { }, signatureDictionary);
|
||||||
|
builder.createAcroForm({ formField });
|
||||||
|
|
||||||
|
const pdf::PDFCatalog* catalog = m_document->getCatalog();
|
||||||
|
if (dialog.getSignMethod() == SignDialog::SignDigitallyInvisible)
|
||||||
|
{
|
||||||
|
if (catalog->getPageCount() > 0)
|
||||||
|
{
|
||||||
|
const pdf::PDFObjectReference pageReference = catalog->getPage(0)->getPageReference();
|
||||||
|
builder.createInvisibleFormFieldWidget(formField, pageReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dialog.getSignMethod() == SignDialog::SignDigitally)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!m_scene.isEmpty());
|
||||||
|
const pdf::PDFInteger pageIndex = *m_scene.getPageIndices().begin();
|
||||||
|
const pdf::PDFPage* page = catalog->getPage(pageIndex);
|
||||||
|
|
||||||
|
pdf::PDFContentStreamBuilder contentBuilder(page->getMediaBox().size(), pdf::PDFContentStreamBuilder::CoordinateSystem::PDF);
|
||||||
|
QPainter* painter = contentBuilder.begin();
|
||||||
|
QList<pdf::PDFRenderError> errors;
|
||||||
|
pdf::PDFTextLayoutGetter nullGetter(nullptr, pageIndex);
|
||||||
|
m_scene.drawPage(painter, pageIndex, nullptr, nullGetter, QMatrix(), errors);
|
||||||
|
pdf::PDFContentStreamBuilder::ContentStream contentStream = contentBuilder.end(painter);
|
||||||
|
|
||||||
|
QRectF boundingRect = m_scene.getBoundingBox(pageIndex);
|
||||||
|
std::vector<pdf::PDFObject> copiedObjects = builder.copyFrom({ contentStream.resources, contentStream.contents }, contentStream.document.getStorage(), true);
|
||||||
|
Q_ASSERT(copiedObjects.size() == 2);
|
||||||
|
|
||||||
|
pdf::PDFObjectReference resourcesReference = copiedObjects[0].getReference();
|
||||||
|
pdf::PDFObjectReference formReference = copiedObjects[1].getReference();
|
||||||
|
|
||||||
|
// Create form object
|
||||||
|
pdf::PDFObjectFactory formFactory;
|
||||||
|
|
||||||
|
formFactory.beginDictionary();
|
||||||
|
|
||||||
|
formFactory.beginDictionaryItem("Type");
|
||||||
|
formFactory << pdf::WrapName("XObject");
|
||||||
|
formFactory.endDictionaryItem();
|
||||||
|
|
||||||
|
formFactory.beginDictionaryItem("Subtype");
|
||||||
|
formFactory << pdf::WrapName("Form");
|
||||||
|
formFactory.endDictionaryItem();
|
||||||
|
|
||||||
|
formFactory.beginDictionaryItem("BBox");
|
||||||
|
formFactory << boundingRect;
|
||||||
|
formFactory.endDictionaryItem();
|
||||||
|
|
||||||
|
formFactory.beginDictionaryItem("Resources");
|
||||||
|
formFactory << resourcesReference;
|
||||||
|
formFactory.endDictionaryItem();
|
||||||
|
|
||||||
|
formFactory.endDictionary();
|
||||||
|
|
||||||
|
builder.mergeTo(formReference, formFactory.takeObject());
|
||||||
|
|
||||||
|
builder.createFormFieldWidget(formField, page->getPageReference(), formReference, boundingRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString reasonText = dialog.getReasonText();
|
||||||
|
if (!reasonText.isEmpty())
|
||||||
|
{
|
||||||
|
builder.setSignatureReason(signatureDictionary, reasonText);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString contactInfoText = dialog.getContactInfoText();
|
||||||
|
if (!contactInfoText.isEmpty())
|
||||||
|
{
|
||||||
|
builder.setSignatureContactInfo(signatureDictionary, contactInfoText);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdf::PDFDocument signedDocument = builder.build();
|
||||||
|
|
||||||
|
// 1) Save the document with incorrect signature
|
||||||
|
QBuffer buffer;
|
||||||
|
pdf::PDFDocumentWriter writer(m_widget->getDrawWidgetProxy()->getProgress());
|
||||||
|
buffer.open(QBuffer::ReadWrite);
|
||||||
|
writer.write(&buffer, &signedDocument);
|
||||||
|
|
||||||
|
const int indexOfSignature = buffer.data().indexOf(signature.toHex());
|
||||||
|
if (indexOfSignature == -1)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(m_widget, tr("Error"), tr("Failed to create digital signature."));
|
||||||
|
buffer.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Write ranges to be checked
|
||||||
|
const pdf::PDFInteger i1 = 0;
|
||||||
|
const pdf::PDFInteger i2 = indexOfSignature - 1;
|
||||||
|
const pdf::PDFInteger i3 = i2 + signature.size() * 2 + 2;
|
||||||
|
const pdf::PDFInteger i4 = buffer.data().size() - i3;
|
||||||
|
|
||||||
|
auto writeInt = [&](pdf::PDFInteger offset)
|
||||||
|
{
|
||||||
|
QString offsetString = QString::number(offset);
|
||||||
|
offsetString = offsetString.leftJustified(static_cast<int>(offsetMarkStringLength), ' ', true);
|
||||||
|
const auto index = buffer.data().lastIndexOf(QString(offsetMarkString), indexOfSignature);
|
||||||
|
buffer.seek(index);
|
||||||
|
buffer.write(offsetString.toLocal8Bit());
|
||||||
|
};
|
||||||
|
|
||||||
|
writeInt(i4);
|
||||||
|
writeInt(i3);
|
||||||
|
writeInt(i2);
|
||||||
|
writeInt(i1);
|
||||||
|
|
||||||
|
// 3) Sign the data
|
||||||
|
QByteArray dataToBeSigned;
|
||||||
|
buffer.seek(i1);
|
||||||
|
dataToBeSigned.append(buffer.read(i2));
|
||||||
|
buffer.seek(i3);
|
||||||
|
dataToBeSigned.append(buffer.read(i4));
|
||||||
|
|
||||||
|
if (!SignatureFactory::sign(dialog.getCertificatePath(), dialog.getPassword(), dataToBeSigned, signature))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(m_widget, tr("Error"), tr("Failed to create digital signature."));
|
||||||
|
buffer.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.seek(i2 + 1);
|
||||||
|
buffer.write(signature.toHex());
|
||||||
|
|
||||||
|
buffer.close();
|
||||||
|
|
||||||
|
QString fileName = QFileDialog::getSaveFileName(m_dataExchangeInterface->getMainWindow(), tr("Save Signed Document"), getSignedFileName(), tr("Portable Document (*.pdf);;All files (*.*)"));
|
||||||
|
if (!fileName.isEmpty())
|
||||||
|
{
|
||||||
|
QFile signedFile(fileName);
|
||||||
|
if (signedFile.open(QFile::WriteOnly | QFile::Truncate))
|
||||||
|
{
|
||||||
|
signedFile.write(buffer.data());
|
||||||
|
signedFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SignaturePlugin::getSignedFileName() const
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo(m_dataExchangeInterface->getOriginalFileName());
|
||||||
|
|
||||||
|
return fileInfo.path() + "/" + fileInfo.baseName() + "_SIGNED.pdf";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onOpenCertificatesManager()
|
||||||
|
{
|
||||||
|
CertificateManagerDialog dialog(m_dataExchangeInterface->getMainWindow());
|
||||||
|
dialog.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onPenChanged(const QPen& pen)
|
||||||
|
{
|
||||||
|
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
|
||||||
|
{
|
||||||
|
activeTool->setPen(pen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onBrushChanged(const QBrush& brush)
|
||||||
|
{
|
||||||
|
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
|
||||||
|
{
|
||||||
|
activeTool->setBrush(brush);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onFontChanged(const QFont& font)
|
||||||
|
{
|
||||||
|
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
|
||||||
|
{
|
||||||
|
activeTool->setFont(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onAlignmentChanged(Qt::Alignment alignment)
|
||||||
|
{
|
||||||
|
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
|
||||||
|
{
|
||||||
|
activeTool->setAlignment(alignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::onTextAngleChanged(pdf::PDFReal angle)
|
||||||
|
{
|
||||||
|
if (pdf::PDFCreatePCElementTool* activeTool = qobject_cast<pdf::PDFCreatePCElementTool*>(getActiveTool()))
|
||||||
|
{
|
||||||
|
activeTool->setTextAngle(angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::setActive(bool active)
|
||||||
|
{
|
||||||
|
if (m_scene.isActive() != active)
|
||||||
|
{
|
||||||
|
// Abort active tool, if we are deactivating the plugin
|
||||||
|
if (!active)
|
||||||
|
{
|
||||||
|
if (pdf::PDFWidgetTool* tool = m_widget->getToolManager()->getActiveTool())
|
||||||
|
{
|
||||||
|
auto it = std::find(m_tools.cbegin(), m_tools.cend(), tool);
|
||||||
|
if (it != m_tools.cend())
|
||||||
|
{
|
||||||
|
m_widget->getToolManager()->setActiveTool(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_scene.setActive(active);
|
||||||
|
if (!active)
|
||||||
|
{
|
||||||
|
m_scene.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updateDockWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_actions[Activate]->setChecked(active);
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::updateActions()
|
||||||
|
{
|
||||||
|
m_actions[Activate]->setEnabled(m_document);
|
||||||
|
|
||||||
|
if (!m_scene.isActive() || !m_document)
|
||||||
|
{
|
||||||
|
// Inactive scene - disable all except activate action and certificates
|
||||||
|
for (QAction* action : m_actions)
|
||||||
|
{
|
||||||
|
if (action == m_actions[Activate] ||
|
||||||
|
action == m_actions[Certificates])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
action->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool isSceneNonempty = !m_scene.isEmpty();
|
||||||
|
|
||||||
|
// Tool actions
|
||||||
|
for (auto actionId : { Text, FreehandCurve, AcceptMark, RejectMark,
|
||||||
|
Rectangle, RoundedRectangle, HorizontalLine,
|
||||||
|
VerticalLine, Line, Dot, SvgImage })
|
||||||
|
{
|
||||||
|
m_actions[actionId]->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear action
|
||||||
|
QAction* clearAction = m_actions[Clear];
|
||||||
|
clearAction->setEnabled(isSceneNonempty);
|
||||||
|
|
||||||
|
// Sign actions
|
||||||
|
QAction* signElectronicallyAction = m_actions[SignElectronically];
|
||||||
|
signElectronicallyAction->setEnabled(isSceneNonempty);
|
||||||
|
QAction* signDigitallyAction = m_actions[SignDigitally];
|
||||||
|
signDigitallyAction->setEnabled(m_document);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::updateGraphics()
|
||||||
|
{
|
||||||
|
if (m_widget)
|
||||||
|
{
|
||||||
|
m_widget->getDrawWidget()->getWidget()->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignaturePlugin::updateDockWidget()
|
||||||
|
{
|
||||||
|
if (m_editorWidget)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_editorWidget = new pdf::PDFPageContentEditorWidget(m_dataExchangeInterface->getMainWindow());
|
||||||
|
m_editorWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
||||||
|
m_dataExchangeInterface->getMainWindow()->addDockWidget(Qt::RightDockWidgetArea, m_editorWidget, Qt::Vertical);
|
||||||
|
m_editorWidget->setFloating(false);
|
||||||
|
m_editorWidget->setWindowTitle(tr("Signature Toolbox"));
|
||||||
|
m_editorWidget->setScene(&m_scene);
|
||||||
|
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::operationTriggered, &m_scene, &pdf::PDFPageContentScene::performOperation);
|
||||||
|
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::itemSelectionChangedByUser, this, &SignaturePlugin::onWidgetSelectionChanged);
|
||||||
|
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignTop))->setIcon(QIcon(":/resources/pce-align-top.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignCenterVertically))->setIcon(QIcon(":/resources/pce-align-v-center.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignBottom))->setIcon(QIcon(":/resources/pce-align-bottom.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignLeft))->setIcon(QIcon(":/resources/pce-align-left.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignCenterHorizontally))->setIcon(QIcon(":/resources/pce-align-h-center.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::AlignRight))->setIcon(QIcon(":/resources/pce-align-right.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::SetSameHeight))->setIcon(QIcon(":/resources/pce-same-height.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::SetSameWidth))->setIcon(QIcon(":/resources/pce-same-width.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::SetSameSize))->setIcon(QIcon(":/resources/pce-same-size.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::CenterHorizontally))->setIcon(QIcon(":/resources/pce-center-h.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::CenterVertically))->setIcon(QIcon(":/resources/pce-center-v.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::CenterHorAndVert))->setIcon(QIcon(":/resources/pce-center-vh.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::LayoutVertically))->setIcon(QIcon(":/resources/pce-layout-v.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::LayoutHorizontally))->setIcon(QIcon(":/resources/pce-layout-h.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::LayoutForm))->setIcon(QIcon(":/resources/pce-layout-form.svg"));
|
||||||
|
m_editorWidget->getToolButtonForOperation(static_cast<int>(pdf::PDFPageContentElementManipulator::Operation::LayoutGrid))->setIcon(QIcon(":/resources/pce-layout-grid.svg"));
|
||||||
|
|
||||||
|
for (QAction* action : m_actions)
|
||||||
|
{
|
||||||
|
m_editorWidget->addAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::penChanged, this, &SignaturePlugin::onPenChanged);
|
||||||
|
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::brushChanged, this, &SignaturePlugin::onBrushChanged);
|
||||||
|
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::fontChanged, this, &SignaturePlugin::onFontChanged);
|
||||||
|
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::alignmentChanged, this, &SignaturePlugin::onAlignmentChanged);
|
||||||
|
connect(m_editorWidget, &pdf::PDFPageContentEditorWidget::textAngleChanged, this, &SignaturePlugin::onTextAngleChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef SIGNATURESPLUGIN_H
|
||||||
|
#define SIGNATURESPLUGIN_H
|
||||||
|
|
||||||
|
#include "pdfplugin.h"
|
||||||
|
#include "pdfpagecontentelements.h"
|
||||||
|
#include "pdfpagecontenteditortools.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
class PDFPageContentEditorWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace pdfplugin
|
||||||
|
{
|
||||||
|
|
||||||
|
class SignaturePlugin : public pdf::PDFPlugin
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PLUGIN_METADATA(IID "PDF4QT.SignaturePlugin" FILE "SignaturePlugin.json")
|
||||||
|
|
||||||
|
private:
|
||||||
|
using BaseClass = pdf::PDFPlugin;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SignaturePlugin();
|
||||||
|
|
||||||
|
virtual void setWidget(pdf::PDFWidget* widget) override;
|
||||||
|
virtual void setDocument(const pdf::PDFModifiedDocument& document) override;
|
||||||
|
virtual std::vector<QAction*> getActions() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onSceneChanged(bool graphicsOnly);
|
||||||
|
void onSceneSelectionChanged();
|
||||||
|
void onWidgetSelectionChanged();
|
||||||
|
void onToolActivityChanged();
|
||||||
|
void onSceneEditElement(const std::set<pdf::PDFInteger>& elements);
|
||||||
|
void onSignElectronically();
|
||||||
|
void onSignDigitally();
|
||||||
|
void onOpenCertificatesManager();
|
||||||
|
|
||||||
|
void onPenChanged(const QPen& pen);
|
||||||
|
void onBrushChanged(const QBrush& brush);
|
||||||
|
void onFontChanged(const QFont& font);
|
||||||
|
void onAlignmentChanged(Qt::Alignment alignment);
|
||||||
|
void onTextAngleChanged(pdf::PDFReal angle);
|
||||||
|
|
||||||
|
enum Action
|
||||||
|
{
|
||||||
|
// Activate action
|
||||||
|
Activate,
|
||||||
|
|
||||||
|
// Create graphics actions
|
||||||
|
Text,
|
||||||
|
FreehandCurve,
|
||||||
|
AcceptMark,
|
||||||
|
RejectMark,
|
||||||
|
Rectangle,
|
||||||
|
RoundedRectangle,
|
||||||
|
HorizontalLine,
|
||||||
|
VerticalLine,
|
||||||
|
Line,
|
||||||
|
Dot,
|
||||||
|
SvgImage,
|
||||||
|
Clear,
|
||||||
|
|
||||||
|
// Sign actions
|
||||||
|
SignElectronically,
|
||||||
|
SignDigitally,
|
||||||
|
Certificates,
|
||||||
|
|
||||||
|
LastAction
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Tools
|
||||||
|
{
|
||||||
|
TextTool,
|
||||||
|
FreehandCurveTool,
|
||||||
|
AcceptMarkTool,
|
||||||
|
RejectMarkTool,
|
||||||
|
RectangleTool,
|
||||||
|
RoundedRectangleTool,
|
||||||
|
HorizontalLineTool,
|
||||||
|
VerticalLineTool,
|
||||||
|
LineTool,
|
||||||
|
DotTool,
|
||||||
|
ImageTool,
|
||||||
|
LastTool
|
||||||
|
};
|
||||||
|
|
||||||
|
void setActive(bool active);
|
||||||
|
|
||||||
|
void updateActions();
|
||||||
|
void updateGraphics();
|
||||||
|
void updateDockWidget();
|
||||||
|
|
||||||
|
QString getSignedFileName() const;
|
||||||
|
|
||||||
|
std::array<QAction*, LastAction> m_actions;
|
||||||
|
std::array<pdf::PDFWidgetTool*, LastTool> m_tools;
|
||||||
|
pdf::PDFPageContentEditorWidget* m_editorWidget;
|
||||||
|
|
||||||
|
pdf::PDFPageContentScene m_scene;
|
||||||
|
bool m_sceneSelectionChangeEnabled;
|
||||||
|
pdf::PDFWidgetTool* getActiveTool();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdfplugin
|
||||||
|
|
||||||
|
#endif // SIGNATURESPLUGIN_H
|
|
@ -0,0 +1,105 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "signdialog.h"
|
||||||
|
#include "ui_signdialog.h"
|
||||||
|
|
||||||
|
#include "certificatemanager.h"
|
||||||
|
|
||||||
|
#include <openssl/pkcs7.h>
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
namespace pdfplugin
|
||||||
|
{
|
||||||
|
|
||||||
|
SignDialog::SignDialog(QWidget* parent, bool isSceneEmpty) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::SignDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
if (!isSceneEmpty)
|
||||||
|
{
|
||||||
|
ui->methodCombo->addItem(tr("Sign digitally"), SignDigitally);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->methodCombo->addItem(tr("Sign digitally (invisible signature)"), SignDigitallyInvisible);
|
||||||
|
ui->methodCombo->setCurrentIndex(0);
|
||||||
|
|
||||||
|
QFileInfoList certificates = CertificateManager::getCertificates();
|
||||||
|
for (const QFileInfo& certificateFileInfo : certificates)
|
||||||
|
{
|
||||||
|
ui->certificateCombo->addItem(certificateFileInfo.fileName(), certificateFileInfo.absoluteFilePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SignDialog::~SignDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
SignDialog::SignMethod SignDialog::getSignMethod() const
|
||||||
|
{
|
||||||
|
return static_cast<SignMethod>(ui->methodCombo->currentData().toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SignDialog::getCertificatePath() const
|
||||||
|
{
|
||||||
|
return ui->certificateCombo->currentData().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SignDialog::getPassword() const
|
||||||
|
{
|
||||||
|
return ui->certificatePasswordEdit->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SignDialog::getReasonText() const
|
||||||
|
{
|
||||||
|
return ui->reasonEdit->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SignDialog::getContactInfoText() const
|
||||||
|
{
|
||||||
|
return ui->contactInfoEdit->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignDialog::accept()
|
||||||
|
{
|
||||||
|
// Check certificate
|
||||||
|
if (!QFile::exists(getCertificatePath()))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Certificate does not exist."));
|
||||||
|
ui->certificateCombo->setFocus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check we can access the certificate
|
||||||
|
if (!CertificateManager::isCertificateValid(getCertificatePath(), ui->certificatePasswordEdit->text()))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Password to open certificate is invalid."));
|
||||||
|
ui->certificatePasswordEdit->setFocus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdfplugin
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright (C) 2022 Jakub Melka
|
||||||
|
//
|
||||||
|
// This file is part of PDF4QT.
|
||||||
|
//
|
||||||
|
// PDF4QT is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// with the written consent of the copyright owner, any later version.
|
||||||
|
//
|
||||||
|
// PDF4QT is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef SIGNDIALOG_H
|
||||||
|
#define SIGNDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class SignDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace pdfplugin
|
||||||
|
{
|
||||||
|
|
||||||
|
class SignDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SignDialog(QWidget* parent, bool isSceneEmpty);
|
||||||
|
virtual ~SignDialog() override;
|
||||||
|
|
||||||
|
virtual void accept() override;
|
||||||
|
|
||||||
|
enum SignMethod
|
||||||
|
{
|
||||||
|
SignDigitally,
|
||||||
|
SignDigitallyInvisible
|
||||||
|
};
|
||||||
|
|
||||||
|
SignMethod getSignMethod() const;
|
||||||
|
QString getCertificatePath() const;
|
||||||
|
QString getPassword() const;
|
||||||
|
QString getReasonText() const;
|
||||||
|
QString getContactInfoText() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::SignDialog* ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdfplugin
|
||||||
|
|
||||||
|
#endif // SIGNDIALOG_H
|
|
@ -0,0 +1,160 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>SignDialog</class>
|
||||||
|
<widget class="QDialog" name="SignDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>501</width>
|
||||||
|
<height>332</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="selectCertificateGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Sign Method</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="methodLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Method</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="methodCombo"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="certificateLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Certificate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="certificateCombo"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="passwordLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Password</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="certificatePasswordEdit">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="parametersGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Parameters</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="reasonLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reason</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="reasonEdit">
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="contactInfoLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Contact Info</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="contactInfoEdit">
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>SignDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>SignDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 9.7 KiB |
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Vrstva_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="256px" height="256px" viewBox="0 0 256 256" enable-background="new 0 0 256 256" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<polygon fill="#C53620" points="146.473,82.454 146.473,0.01 41.606,0.01 41.606,132.477 41.606,134.876 41.606,136.482
|
||||||
|
41.606,149.734 41.606,164.563 41.606,210.88 41.606,222.339 41.606,232.549 41.606,238.801 41.606,249.241 41.606,255.991
|
||||||
|
214.494,255.991 214.494,82.454 "/>
|
||||||
|
<polygon fill="#6CBD45" points="155.246,0.053 155.246,73.619 214.443,73.619 "/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M190.029,183.913c-0.811-1-1.609-2.018-2.49-3.038l-5.4,6.486l-1.424,1.625
|
||||||
|
c-9.729,11.137-20.436,20.589-34.025,26.535c-12.545,5.456-25.094,5.313-37.66-0.28c-10.674-4.713-19.644-11.681-27.745-19.906
|
||||||
|
c-2.429-2.491-4.807-5.123-7.222-7.753c0.791-0.951,1.473-1.845,2.227-2.633c8.298-9.4,17.489-17.575,28.632-23.382
|
||||||
|
c7.893-4.113,16.191-6.593,25.244-6.138c5.877,0.279,11.469,1.82,16.871,4.14c8.654,3.833,16.225,9.158,23.152,15.449
|
||||||
|
l5.455-6.412c-8.354-7.543-17.596-13.979-28.352-17.951c-7.201-2.78-14.777-4.124-22.512-3.592
|
||||||
|
c-9.544,0.686-18.313,3.858-26.557,8.597c-12.487,7.19-22.944,16.869-31.872,28.135c-0.735,0.88-1.23,1.959-1.821,2.892v1.515
|
||||||
|
c0.551,0.928,1.033,1.96,1.689,2.767c4.113,5.32,8.629,10.193,13.586,14.7c8.629,7.86,18.078,14.47,29.019,18.644
|
||||||
|
c7.307,2.77,14.846,4.052,22.621,3.525c9.521-0.615,18.295-3.787,26.52-8.577c12.453-7.105,22.75-16.682,31.658-27.828
|
||||||
|
c0.826-0.938,1.352-2.167,1.947-3.23v-1.515C191.109,185.806,190.646,184.804,190.029,183.913z"/>
|
||||||
|
<path fill="#FFFFFF" d="M153.18,187.467c-0.018,13.892-11.355,25.153-25.199,25.063c-13.875-0.067-25.02-11.295-25.002-25.134
|
||||||
|
c0.035-13.896,11.363-25.161,25.219-25.064C142.072,162.426,153.232,173.647,153.18,187.467z M144.83,187.467
|
||||||
|
c0.018-9.205-7.402-16.699-16.679-16.766c-9.192-0.086-16.836,7.543-16.789,16.766c0.053,9.244,7.544,16.713,16.74,16.713
|
||||||
|
C137.305,204.181,144.803,196.711,144.83,187.467z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<path fill="#FFFFFF" d="M201.894,124.126c-0.016-0.146-0.027-0.23-0.027-0.23c-0.441-3.699-1.799-6.982-4.536-9.571
|
||||||
|
c-3.264-3.082-7.188-4.237-11.601-3.596c-3.511,0.51-6.249,2.457-8.607,4.996c-0.85,0.912-0.82,0.924-0.199,1.993
|
||||||
|
c0.593,1.017,1.156,2.049,1.753,3.11c0.124-0.152,0.22-0.285,0.328-0.401c1.049-1.114,2.005-2.342,3.174-3.314
|
||||||
|
c4.569-3.803,10.67-2.161,13.357,1.963c2.488,3.815,2.667,7.913,0.886,12.029c-2.438,5.631-9.465,7.549-14.436,3.49
|
||||||
|
c-2.028-1.658-3.586-3.691-4.751-6.004c-0.934-1.864-1.673-3.825-2.565-5.709c-1.85-3.894-4.224-7.391-7.831-9.888
|
||||||
|
c-4.246-2.942-8.799-3.228-13.429-1.142c-4.354,1.96-6.794,5.554-7.855,10.134c-0.11,0.468-0.189,0.943-0.265,1.419
|
||||||
|
c-0.005,0.035-0.254,2.152-0.109,4.147c0.012,0.063,0.024,0.124,0.031,0.189c0.058,0.545,0.14,1.083,0.249,1.617
|
||||||
|
c0,0.006,0.001,0.008,0.002,0.014c0.322,1.596,0.869,3.121,1.64,4.588c2.786,5.313,9.118,8.26,14.971,6.949
|
||||||
|
c3.249-0.729,5.836-2.527,8.044-4.941c0.686-0.752,0.664-0.756,0.157-1.637c-0.623-1.084-1.225-2.178-1.866-3.322
|
||||||
|
c-0.218,0.289-0.412,0.553-0.614,0.813c-1.099,1.41-2.355,2.646-3.887,3.598c-3.767,2.34-8.942,1.484-11.762-1.934
|
||||||
|
c-1.536-1.867-2.338-4.018-2.531-6.396c-0.262-3.253,0.41-6.258,2.543-8.826c2.669-3.217,7.729-4.423,11.647-1.951
|
||||||
|
c2.266,1.429,3.905,3.422,5.319,5.643c1.401,2.198,2.233,4.661,3.313,7.009c1.787,3.885,4.149,7.354,7.743,9.811
|
||||||
|
c4.271,2.922,8.848,3.215,13.495,1.123c3.887-1.75,6.242-4.801,7.462-8.689c0.038-0.113,0.076-0.234,0.114-0.367
|
||||||
|
c0.013-0.039,0.021-0.072,0.03-0.111c0.039-0.137,0.074-0.275,0.11-0.412c0.026-0.102,0.053-0.203,0.077-0.301
|
||||||
|
c0.021-0.086,0.045-0.168,0.064-0.254c0.017-0.068,0.026-0.141,0.042-0.213c0.051-0.229,0.095-0.451,0.134-0.67
|
||||||
|
c0.002-0.02,0.008-0.037,0.011-0.055c0.025-0.15,0.049-0.295,0.07-0.441c0.025-0.161,0.053-0.323,0.076-0.485
|
||||||
|
c0.061-0.338,0.096-0.7,0.114-1.063c0-0.116,0-0.229,0-0.347C202.047,125.024,201.895,124.134,201.894,124.126z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.1 KiB |