Merge remote-tracking branch 'remotes/origin/signdoc'

This commit is contained in:
Jakub Melka 2022-05-29 17:32:39 +02:00
commit 63f5c8d742
102 changed files with 12961 additions and 2158 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -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

View File

@ -15,7 +15,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
QT += gui widgets xml
QT += gui widgets xml svg
TARGET = Pdf4QtLib
TEMPLATE = lib
@ -72,6 +72,10 @@ SOURCES += \
sources/pdfoptimizer.cpp \
sources/pdfoptionalcontent.cpp \
sources/pdfoutline.cpp \
sources/pdfpagecontenteditorstylesettings.cpp \
sources/pdfpagecontenteditortools.cpp \
sources/pdfpagecontenteditorwidget.cpp \
sources/pdfpagecontentelements.cpp \
sources/pdfpagenavigation.cpp \
sources/pdfpagetransition.cpp \
sources/pdfpainterutils.cpp \
@ -87,6 +91,7 @@ SOURCES += \
sources/pdfsignaturehandler.cpp \
sources/pdfsnapper.cpp \
sources/pdfstructuretree.cpp \
sources/pdftexteditpseudowidget.cpp \
sources/pdftextlayout.cpp \
sources/pdftransparencyrenderer.cpp \
sources/pdfutils.cpp \
@ -147,6 +152,10 @@ HEADERS += \
sources/pdfoptimizer.h \
sources/pdfoptionalcontent.h \
sources/pdfoutline.h \
sources/pdfpagecontenteditorstylesettings.h \
sources/pdfpagecontenteditortools.h \
sources/pdfpagecontenteditorwidget.h \
sources/pdfpagecontentelements.h \
sources/pdfpagenavigation.h \
sources/pdfpagetransition.h \
sources/pdfpainterutils.h \
@ -165,6 +174,7 @@ HEADERS += \
sources/pdfsignaturehandler_impl.h \
sources/pdfsnapper.h \
sources/pdfstructuretree.h \
sources/pdftexteditpseudowidget.h \
sources/pdftextlayout.h \
sources/pdftransparencyrenderer.h \
sources/pdfwidgettool.h \
@ -194,6 +204,8 @@ HEADERS += \
sources/pdfimage.h
FORMS += \
sources/pdfpagecontenteditorstylesettings.ui \
sources/pdfpagecontenteditorwidget.ui \
sources/pdfrenderingerrorswidget.ui \
sources/pdfselectpagesdialog.ui

View File

@ -659,7 +659,7 @@ void PDFCreateFreehandCurveTool::mousePressEvent(QWidget* widget, QMouseEvent* e
resetTool();
}
getProxy()->repaintNeeded();
emit getProxy()->repaintNeeded();
}
void PDFCreateFreehandCurveTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
@ -1063,7 +1063,7 @@ void PDFCreateHighlightTextTool::setSelection(PDFTextSelection&& textSelection)
if (m_textSelection != textSelection)
{
m_textSelection = qMove(textSelection);
getProxy()->repaintNeeded();
emit getProxy()->repaintNeeded();
}
}

View File

@ -166,7 +166,8 @@ private:
public:
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,
PDFTextLayoutGetter& layoutGetter,
const QMatrix& pagePointToDevicePointMatrix,

View File

@ -501,10 +501,11 @@ public:
{
None = 0x0000, ///< No flag
Reset = 0x0001, ///< Whole document content is changed (for example, new document is being set)
Annotation = 0x0002, ///< Annotations changed
FormField = 0x0004, ///< Form field content changed
Authorization = 0x0008, ///< Authorization has changed (for example, old document is granted user access, but for new, owner access)
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)
PageContents = 0x0002, ///< Page contents changed (page graphics, not annotations)
Annotation = 0x0004, ///< Annotations changed
FormField = 0x0008, ///< Form field content changed
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)
@ -550,6 +551,7 @@ public:
ModificationFlags getFlags() const { return m_flags; }
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); }
operator PDFDocument*() const { return m_document; }

View File

@ -22,6 +22,8 @@
#include "pdfobjectutils.h"
#include "pdfnametreeloader.h"
#include "pdfdbgheap.h"
#include "pdfparser.h"
#include "pdfstreamfilters.h"
#include <QBuffer>
#include <QPainter>
@ -698,14 +700,23 @@ PDFDocument PDFDocumentBuilder::build()
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
{
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_contentStreamBuilder(nullptr)
m_contentStreamBuilder(nullptr),
m_coordinateSystem(coordinateSystem),
m_mode(mode)
{
}
@ -733,7 +744,7 @@ QPainter* PDFPageContentStreamBuilder::begin(PDFObjectReference 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();
}
@ -762,21 +773,223 @@ void PDFPageContentStreamBuilder::end(QPainter* painter)
PDFObjectReference resourcesReference = copiedObjects[0].getReference();
PDFObjectReference contentsReference = copiedObjects[1].getReference();
PDFObjectFactory pageUpdateFactory;
if (m_mode == Mode::Replace)
{
PDFObjectFactory pageUpdateFactory;
pageUpdateFactory.beginDictionary();
pageUpdateFactory.beginDictionary();
pageUpdateFactory.beginDictionaryItem("Contents");
pageUpdateFactory << contentsReference;
pageUpdateFactory.endDictionaryItem();
pageUpdateFactory.beginDictionaryItem("Contents");
pageUpdateFactory << contentsReference;
pageUpdateFactory.endDictionaryItem();
pageUpdateFactory.beginDictionaryItem("Resources");
pageUpdateFactory << resourcesReference;
pageUpdateFactory.endDictionaryItem();
pageUpdateFactory.beginDictionaryItem("Resources");
pageUpdateFactory << resourcesReference;
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)
@ -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)
{
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,
QRectF boundingRectangle,
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,
QRectF rectangle,
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,
QRectF rectangle,
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,
QRectF rectangle,
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,
QRectF rectangle,
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()
{
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)
{
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)
{
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)
{
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)
{
PDFObjectFactory objectBuilder;

View File

@ -39,6 +39,12 @@ struct WrapName
}
WrapName(QByteArray name) :
name(std::move(name))
{
}
QByteArray name;
};
@ -86,7 +92,7 @@ struct WrapEmptyArray { };
/// Factory for creating various PDF objects, such as simple objects,
/// dictionaries, arrays etc.
class PDFObjectFactory
class PDF4QTLIBSHARED_EXPORT PDFObjectFactory
{
public:
inline explicit PDFObjectFactory() = default;
@ -261,9 +267,20 @@ private:
class PDF4QTLIBSHARED_EXPORT PDFPageContentStreamBuilder
{
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
/// uses Qt's coordinate system. Calling begin multiple times, without
/// subsequent calls to end function, is invalid and can result
@ -284,9 +301,15 @@ public:
void end(QPainter* painter);
private:
void replaceResources(PDFObjectReference contentStreamReference,
PDFObjectReference resourcesReference,
PDFObject oldResources);
PDFDocumentBuilder* m_documentBuilder;
PDFContentStreamBuilder* m_contentStreamBuilder;
PDFObjectReference m_pageReference;
PDFContentStreamBuilder::CoordinateSystem m_coordinateSystem;
Mode m_mode;
};
class PDF4QTLIBSHARED_EXPORT PDFDocumentBuilder
@ -328,6 +351,11 @@ public:
/// is returned (no exception is thrown).
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
std::array<PDFReal, 4> getAnnotationReductionRectangle(const QRectF& boundingRect, const QRectF& innerRect) const;
@ -446,6 +474,11 @@ public:
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.
/// \param destination Destination
PDFObjectReference createActionGoTo(PDFDestination destination);
@ -662,36 +695,6 @@ public:
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
/// 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
@ -741,6 +744,36 @@ public:
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
/// 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.
@ -1024,6 +1057,16 @@ public:
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
/// contain window to be opened (and commented).
/// \param page Page to which is annotation added
@ -1040,16 +1083,6 @@ public:
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
/// \param page Page to which is annotation added
/// \param rectangle Stamp area
@ -1122,22 +1155,6 @@ public:
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
/// window to be opened (and commented).
/// \param page Page to which is annotation added
@ -1158,6 +1175,22 @@ public:
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
/// this function manually.
PDFObjectReference createCatalog();
@ -1193,6 +1226,48 @@ public:
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
/// call this function manually.
/// \param catalog Reference to document catalog
@ -1393,6 +1468,11 @@ public:
PDFObject value);
/// Set document language.
/// \param locale Locale, from which is language determined
void setLanguage(QLocale locale);
/// Set document language.
/// \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 =
@ -1400,11 +1480,6 @@ public:
void setLanguage(QString language);
/// Set document language.
/// \param locale Locale, from which is language determined
void setLanguage(QLocale locale);
/// Set document outline.
/// \param outline Document outline root
void setOutline(PDFObjectReference outline);
@ -1470,6 +1545,20 @@ public:
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
/// being built.
/// \param objectCount Number of objects (including empty ones)
@ -1513,6 +1602,7 @@ public:
PDFModifiedDocument::ModificationFlags getFlags() const { return m_modificationFlags; }
void markReset() { m_modificationFlags.setFlag(PDFModifiedDocument::Reset); }
void markPageContentsChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::PageContents); }
void markAnnotationsChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::Annotation); }
void markFormFieldChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::FormField); }
void markXFAPagination() { m_modificationFlags.setFlag(PDFModifiedDocument::XFA_Pagination); }

View File

@ -192,7 +192,10 @@ PDFOperationResult PDFDocumentWriter::write(const QString& fileName, const PDFDo
PDFOperationResult result = write(&file, document);
if (result)
{
file.commit();
if (!file.commit())
{
return tr("File '%1' can't be opened for writing. %2").arg(fileName, file.errorString());
}
}
else
{

View File

@ -488,8 +488,8 @@ void PDFDrawWidgetProxy::setDocument(const PDFModifiedDocument& document)
if (getDocument() != document)
{
m_cacheClearTimer->stop();
m_compiler->stop(document.hasReset());
m_textLayoutCompiler->stop(document.hasReset());
m_compiler->stop(document.hasReset() || document.hasPageContentsChanged());
m_textLayoutCompiler->stop(document.hasReset() || document.hasPageContentsChanged());
m_controller->setDocument(document);
if (PDFOptionalContentActivity* optionalContentActivity = document.getOptionalContentActivity())

View File

@ -1836,7 +1836,7 @@ void PDFFontCache::setDocument(const PDFModifiedDocument& document)
// 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.
if (document.hasReset())
if (document.hasReset() || document.hasPageContentsChanged())
{
m_fontCache.clear();
m_realizedFontCache.clear();

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// Copyright (C) 2020-2021 Jakub Melka
// Copyright (C) 2020-2022 Jakub Melka
//
// This file is part of PDF4QT.
//

View File

@ -738,7 +738,7 @@ void PDFThumbnailsItemModel::setDocument(const PDFModifiedDocument& document)
{
if (m_document != document)
{
if (document.hasReset() || document.hasFlag(PDFModifiedDocument::Annotation))
if (document.hasReset() || document.hasPageContentsChanged() || document.hasFlag(PDFModifiedDocument::Annotation))
{
beginResetModel();
m_thumbnailCache.clear();

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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)
{
m_signatureFieldQualifiedName = signatureFieldQualifiedName;
@ -977,6 +986,15 @@ int PDFSignatureHandler_ETSI_base::verifyCallback(int ok, X509_STORE_CTX* contex
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:
{
// We must handle all critical extensions manually

View File

@ -319,6 +319,7 @@ public:
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_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_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_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,
Warnings_Mask = Warning_Certificates_Mask | Warning_Signatures_Mask
@ -361,6 +362,7 @@ public:
void addSignatureNotCoveredBytesWarning(PDFInteger count);
void addCertificateCRLValidityTimeExpiredWarning();
void addCertificateQualifiedStatementNotVerifiedWarning();
void addCertificateUnableToGetCRLWarning();
bool isValid() const { return hasFlag(OK); }
bool isCertificateValid() const { return hasFlag(Certificate_OK); }

View File

@ -383,10 +383,9 @@ QByteArray PDFFlateDecodeFilter::apply(const QByteArray& data,
return predictor.apply(uncompress(data));
}
QByteArray PDFFlateDecodeFilter::recompress(const QByteArray& data)
QByteArray PDFFlateDecodeFilter::compress(const QByteArray& decompressedData)
{
QByteArray result;
QByteArray decompressedData = uncompress(data);
z_stream stream = { };
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);
}
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;
}
QByteArray PDFFlateDecodeFilter::recompress(const QByteArray& data)
{
QByteArray decompressedData = uncompress(data);
return compress(decompressedData);
}
PDFInteger PDFFlateDecodeFilter::getStreamDataLength(const QByteArray& data, PDFInteger offset) const
{
if (offset < 0 || offset >= data.size())

View File

@ -215,6 +215,10 @@ public:
/// Recompresses data. So, first, data are decompressed, and then
/// 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
static QByteArray recompress(const QByteArray& data);

View File

@ -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 = [&parameters](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

View File

@ -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

View File

@ -465,6 +465,11 @@ constexpr bool isRectangleHorizontallyOverlapped(const QRectF& r1, const QRectF&
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)
{
qreal r = 0.0;

View File

@ -101,11 +101,19 @@ void PDFWidgetTool::setActive(bool active)
setActiveImpl(active);
updateActions();
m_proxy->repaintNeeded();
emit m_proxy->repaintNeeded();
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)
{
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)
{
if (PDFWidgetTool* tool = getTopToolstackTool())
@ -194,11 +210,13 @@ PDFWidgetTool* PDFWidgetTool::getTopToolstackTool() const
void PDFWidgetTool::addTool(PDFWidgetTool* tool)
{
tool->setActive(isActive());
m_toolStack.push_back(tool);
}
void PDFWidgetTool::removeTool()
{
m_toolStack.back()->setActive(false);
m_toolStack.pop_back();
}
@ -809,8 +827,12 @@ PDFMagnifierTool* PDFToolManager::getMagnifierTool() const
void PDFToolManager::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
{
Q_UNUSED(widget);
Q_UNUSED(event);
event->ignore();
if (PDFWidgetTool* activeTool = getActiveTool())
{
activeTool->shortcutOverrideEvent(widget, 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)
{
Q_UNUSED(widget);
Q_UNUSED(event);
event->ignore();
if (PDFWidgetTool* activeTool = getActiveTool())
{
activeTool->mouseDoubleClickEvent(widget, event);
}
}
void PDFToolManager::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
@ -1070,6 +1096,11 @@ void PDFPickTool::drawPage(QPainter* painter,
Q_UNUSED(layoutGetter);
Q_UNUSED(errors);
if (!isActive())
{
return;
}
// If we are picking rectangles, then draw current selection rectangle
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
{
if (!isActive())
{
return;
}
if (m_mode != Mode::Images)
{
m_snapper.drawSnapPoints(painter);
@ -1233,7 +1269,7 @@ void PDFPickTool::resetTool()
m_snapper.clearReferencePoint();
buildSnapData();
getProxy()->repaintNeeded();
emit getProxy()->repaintNeeded();
}
void PDFPickTool::buildSnapData()

View File

@ -62,6 +62,11 @@ public:
/// Returns action for activating/deactivating this tool
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
/// \param widget Widget, over which tool operates
/// \param event Event
@ -77,6 +82,11 @@ public:
/// \param event 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
/// \param widget Widget, over which tool operates
/// \param event Event
@ -344,8 +354,8 @@ public:
void setSelectionRectangleColor(QColor selectionRectangleColor);
signals:
void pointPicked(PDFInteger pageIndex, QPointF pagePoint);
void rectanglePicked(PDFInteger pageIndex, QRectF pageRectangle);
void pointPicked(pdf::PDFInteger pageIndex, QPointF pagePoint);
void rectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
void imagePicked(const QImage& image);
protected:

View File

@ -74,5 +74,21 @@
<file>resources/save.svg</file>
<file>resources/save-as.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>
</RCC>

View File

@ -58,7 +58,7 @@ void PDFAdvancedFindWidget::setDocument(const pdf::PDFModifiedDocument& document
// If document is not being reset, then page text should remain the same,
// so, there is no need to clear the results.
if (document.hasReset())
if (document.hasReset() || document.hasPageContentsChanged())
{
m_findResults.clear();
updateUI();

View File

@ -104,6 +104,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
// Initialize toolbar icon size
adjustToolbar(ui->mainToolBar);
ui->mainToolBar->setWindowTitle(tr("Standard"));
// Initialize task bar progress
#ifdef Q_OS_WIN

View File

@ -102,6 +102,7 @@ PDFViewerMainWindowLite::PDFViewerMainWindowLite(QWidget* parent) :
// Initialize toolbar icon size
adjustToolbar(ui->mainToolBar);
ui->mainToolBar->setWindowTitle(tr("Standard"));
// Initialize task bar progress
#ifdef Q_OS_WIN

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@ -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

View File

@ -10,6 +10,6 @@ Pdf4QtPlugin {
]
Properties {
condition: qbs.hostOS.contains("windows")
cpp.defines: "DIMENTIONPLUGIN_LIBRARY"
cpp.defines: "DIMENSIONPLUGIN_LIBRARY"
}
}

View File

@ -24,6 +24,7 @@ SUBDIRS += \
RedactPlugin \
OutputPreviewPlugin \
ObjectInspectorPlugin \
AudioBookPlugin
AudioBookPlugin \
SignaturePlugin

View File

@ -0,0 +1,7 @@
{
"Name" : "Signature",
"Author" : "Jakub Melka",
"Version" : "1.0.0",
"License" : "LGPL v3",
"Description" : "Electronically or digitally sign PDF document."
}

View File

@ -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

View File

@ -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"
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More