[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-kimageshop
Subject:    [krita/rempt/T6282-replace-add-shape-docker] /: FEATURE: Add a docker that gives access to svg symbo
From:       Boudewijn Rempt <null () kde ! org>
Date:       2017-06-08 10:03:53
Message-ID: E1dIuID-00086g-Dv () code ! kde ! org
[Download RAW message or body]

Git commit 3e2039077228535c7661468da0da3c5221cc63c9 by Boudewijn Rempt.
Committed on 08/06/2017 at 10:01.
Pushed by rempt into branch 'rempt/T6282-replace-add-shape-docker'.

FEATURE: Add a docker that gives access to svg symbol libraries

You can drag & drop svg items from the docker to the canvas. This
uses the new KoDrag and KoSvgPaste support: the KoSvgPaste methods
are made static for easier access.

The icons are still a bit iffy, and there is no support for editing
collections, searching collections or tagging collections yet, one
needs inkscape for that.

The objects are dropped as groups of shapes, instead of symbols,
and that is intentional: this is meant for things like speech bubbles
which more often need editing than being exactly the same in the whole
document. Krita's still not map-making software...

CCMAIL:kimageshop@kde.org

M  +80   -51   libs/flake/KoCanvasControllerWidgetViewport_p.cpp
M  +1    -0    libs/flake/KoDrag.cpp
M  +1    -1    libs/flake/KoShapeController.cpp
M  +18   -8    libs/flake/KoSvgPaste.cpp
M  +4    -3    libs/flake/KoSvgPaste.h
M  +6    -8    libs/flake/resources/KoSvgSymbolCollectionResource.cpp
M  +104  -11   plugins/dockers/shapedockers/SvgSymbolCollectionDocker.cpp
M  +20   -0    plugins/dockers/shapedockers/SvgSymbolCollectionDocker.h
M  +1    -1    plugins/dockers/shapedockers/WdgSvgCollection.ui

https://commits.kde.org/krita/3e2039077228535c7661468da0da3c5221cc63c9

diff --git a/libs/flake/KoCanvasControllerWidgetViewport_p.cpp \
b/libs/flake/KoCanvasControllerWidgetViewport_p.cpp index 7cc545349e8..ea0302ae59a \
                100644
--- a/libs/flake/KoCanvasControllerWidgetViewport_p.cpp
+++ b/libs/flake/KoCanvasControllerWidgetViewport_p.cpp
@@ -46,16 +46,16 @@
 #include "KoToolProxy.h"
 #include "KoCanvasControllerWidget.h"
 #include "KoViewConverter.h"
-
+#include "KoSvgPaste.h"
 
 // ********** Viewport **********
 Viewport::Viewport(KoCanvasControllerWidget *parent)
-        : QWidget(parent)
-        , m_draggedShape(0)
-        , m_drawShadow(false)
-        , m_canvas(0)
-        , m_documentOffset(QPoint(0, 0))
-        , m_margin(0)
+    : QWidget(parent)
+    , m_draggedShape(0)
+    , m_drawShadow(false)
+    , m_canvas(0)
+    , m_documentOffset(QPoint(0, 0))
+    , m_margin(0)
 {
     setAutoFillBackground(true);
     setAcceptDrops(true);
@@ -105,6 +105,9 @@ void Viewport::handleDragEnterEvent(QDragEnterEvent *event)
         return;
     }
 
+    delete m_draggedShape;
+    m_draggedShape = 0;
+
     // only allow dropping when active layer is editable
     KoSelection *selection = m_parent->canvas()->shapeManager()->selection();
     KoShapeLayer *activeLayer = selection->activeLayer();
@@ -115,50 +118,74 @@ void Viewport::handleDragEnterEvent(QDragEnterEvent *event)
 
     const QMimeData *data = event->mimeData();
     if (data->hasFormat(SHAPETEMPLATE_MIMETYPE) ||
-            data->hasFormat(SHAPEID_MIMETYPE)) {
-        QByteArray itemData;
-        bool isTemplate = true;
-        if (data->hasFormat(SHAPETEMPLATE_MIMETYPE))
-            itemData = data->data(SHAPETEMPLATE_MIMETYPE);
-        else {
-            isTemplate = false;
-            itemData = data->data(SHAPEID_MIMETYPE);
+            data->hasFormat(SHAPEID_MIMETYPE) ||
+            data->hasFormat("image/svg+xml"))
+    {
+        if (data->hasFormat("image/svg+xml")) {
+            KoCanvasBase *canvas = m_parent->canvas();
+            QSizeF fragmentSize;
+
+            QList<KoShape*> shapes = \
KoSvgPaste::fetchShapesFromData(data->data("image/svg+xml"), +                        \
canvas->shapeController()->documentRectInPixels(), +                                  \
canvas->shapeController()->pixelsPerInch(), +                                         \
&fragmentSize); +            if (!shapes.isEmpty()) {
+                m_draggedShape = shapes[0];
+            }
         }
-        QDataStream dataStream(&itemData, QIODevice::ReadOnly);
-        QString id;
-        dataStream >> id;
-        QString properties;
-        if (isTemplate)
-            dataStream >> properties;
-
-        // and finally, there is a point.
-        QPointF offset;
-        dataStream >> offset;
-
-        // The rest of this method is mostly a copy paste from the \
                KoCreateShapeStrategy
-        // So, lets remove this again when Zagge adds his new class that does this \
                kind of thing. (KoLoadSave)
-        KoShapeFactoryBase *factory = KoShapeRegistry::instance()->value(id);
-        if (! factory) {
-            warnFlake << "Application requested a shape that is not registered '" <<
-            id << "', Ignoring";
-            event->ignore();
-            return;
+        else {
+            QByteArray itemData;
+            bool isTemplate = true;
+
+            if (data->hasFormat(SHAPETEMPLATE_MIMETYPE)) {
+                itemData = data->data(SHAPETEMPLATE_MIMETYPE);
+            }
+            else if (data->hasFormat(SHAPEID_MIMETYPE)) {
+                isTemplate = false;
+                itemData = data->data(SHAPEID_MIMETYPE);
+            }
+
+
+            QDataStream dataStream(&itemData, QIODevice::ReadOnly);
+            QString id;
+            dataStream >> id;
+            QString properties;
+            if (isTemplate)
+                dataStream >> properties;
+
+            // and finally, there is a point.
+            QPointF offset;
+            dataStream >> offset;
+
+            // The rest of this method is mostly a copy paste from the \
KoCreateShapeStrategy +            // So, lets remove this again when Zagge adds his \
new class that does this kind of thing. (KoLoadSave) +            KoShapeFactoryBase \
*factory = KoShapeRegistry::instance()->value(id); +            if (! factory) {
+                warnFlake << "Application requested a shape that is not registered \
'" << +                             id << "', Ignoring";
+                event->ignore();
+                return;
+            }
+            if (isTemplate) {
+                KoProperties props;
+                props.load(properties);
+                m_draggedShape = factory->createShape(&props, \
m_parent->canvas()->shapeController()->resourceManager()); +            }
+            else {
+                m_draggedShape = \
factory->createDefaultShape(m_parent->canvas()->shapeController()->resourceManager());
 +            }
+
+            if (m_draggedShape->shapeId().isEmpty()) {
+                m_draggedShape->setShapeId(factory->id());
+            }
         }
+
         event->setDropAction(Qt::CopyAction);
         event->accept();
 
-        if (isTemplate) {
-            KoProperties props;
-            props.load(properties);
-            m_draggedShape = factory->createShape(&props, \
                m_parent->canvas()->shapeController()->resourceManager());
-        } else
-            m_draggedShape = \
factory->createDefaultShape(m_parent->canvas()->shapeController()->resourceManager());
                
-
         Q_ASSERT(m_draggedShape);
         if (!m_draggedShape) return;
 
-        if (m_draggedShape->shapeId().isEmpty())
-            m_draggedShape->setShapeId(factory->id());
         m_draggedShape->setZIndex(KoShapePrivate::MaxZIndex);
         m_draggedShape->setAbsolutePosition(correctPosition(event->pos()));
 
@@ -182,6 +209,7 @@ void Viewport::handleDropEvent(QDropEvent *event)
     QPointF newPos = correctPosition(event->pos());
     m_parent->canvas()->clipToDocument(m_draggedShape, newPos); // ensure the shape \
is dropped inside the document.  m_draggedShape->setAbsolutePosition(newPos);
+
     KUndo2Command * cmd = \
m_parent->canvas()->shapeController()->addShape(m_draggedShape);  if (cmd) {
         m_parent->canvas()->addCommand(cmd);
@@ -193,8 +221,9 @@ void Viewport::handleDropEvent(QDropEvent *event)
 
         selection->deselectAll();
         selection->select(m_draggedShape);
-    } else
+    } else {
         delete m_draggedShape;
+    }
 
     m_draggedShape = 0;
 }
@@ -265,7 +294,7 @@ void Viewport::handlePaintEvent(QPainter &painter, QPaintEvent \
*event)  QWidget *canvasWidget = m_parent->canvas()->canvasWidget();
         Q_ASSERT(canvasWidget); // since we should not allow drag if there is not.
         painter.translate(canvasWidget->x() - m_documentOffset.x(),
-                canvasWidget->y() - m_documentOffset.y());
+                          canvasWidget->y() - m_documentOffset.y());
         QPointF offset = vc->documentToView(m_draggedShape->position());
         painter.setOpacity(0.6);
         painter.translate(offset.x(), offset.y());
@@ -293,10 +322,10 @@ void Viewport::resetLayout()
     int resizeW = viewW;
     int resizeH = viewH;
 
-//     debugFlake <<"viewH:" << viewH << endl
-//              << "docH: " << docH << endl
-//              << "viewW: " << viewW << endl
-//              << "docW: " << docW << endl;
+    //     debugFlake <<"viewH:" << viewH << endl
+    //              << "docH: " << docH << endl
+    //              << "viewW: " << viewW << endl
+    //              << "docW: " << docW << endl;
 
     if (viewH == docH && viewW == docW) {
         // Do nothing
@@ -366,8 +395,8 @@ void Viewport::resetLayout()
 
     emit sizeChanged();
 #if 0
-     debugFlake <<"View port geom:" << geometry();
-     if (m_canvas)
+    debugFlake <<"View port geom:" << geometry();
+    if (m_canvas)
         debugFlake <<"Canvas widget geom:" << m_canvas->geometry();
 #endif
 }
diff --git a/libs/flake/KoDrag.cpp b/libs/flake/KoDrag.cpp
index 08d5ccd328e..c3be65f33f0 100644
--- a/libs/flake/KoDrag.cpp
+++ b/libs/flake/KoDrag.cpp
@@ -82,6 +82,7 @@ bool KoDrag::setSvg(const QList<KoShape *> originalShapes)
     writer.save(buffer);
 
     buffer.close();
+
     qDeleteAll(shapes);
 
     setData(mimeType, buffer.data());
diff --git a/libs/flake/KoShapeController.cpp b/libs/flake/KoShapeController.cpp
index d277c9366b8..0c67c96b159 100644
--- a/libs/flake/KoShapeController.cpp
+++ b/libs/flake/KoShapeController.cpp
@@ -57,7 +57,7 @@ public:
     KUndo2Command* addShape(KoShape *shape, bool showDialog, KUndo2Command *parent) \
{  
         if (canvas) {
-            if (showDialog) {
+            if (showDialog && !shape->shapeId().isEmpty()) {
                 KoShapeFactoryBase *factory = \
KoShapeRegistry::instance()->value(shape->shapeId());  Q_ASSERT(factory);
                 int z = 0;
diff --git a/libs/flake/KoSvgPaste.cpp b/libs/flake/KoSvgPaste.cpp
index 205cca02851..6da3f9abb7a 100644
--- a/libs/flake/KoSvgPaste.cpp
+++ b/libs/flake/KoSvgPaste.cpp
@@ -28,17 +28,13 @@
 #include <FlakeDebug.h>
 #include <QRectF>
 
-KoSvgPaste::KoSvgPaste()
-{
-}
-
-bool KoSvgPaste::hasShapes() const
+bool KoSvgPaste::hasShapes()
 {
     const QMimeData *mimeData = QApplication::clipboard()->mimeData();
     return mimeData && mimeData->hasFormat("image/svg+xml");
 }
 
-QList<KoShape*> KoSvgPaste::fetchShapes(const QRectF viewportInPx, qreal \
resolutionPPI, QSizeF *fragmentSize) const +QList<KoShape*> \
KoSvgPaste::fetchShapes(const QRectF viewportInPx, qreal resolutionPPI, QSizeF \
*fragmentSize)  {
     QList<KoShape*> shapes;
 
@@ -46,7 +42,21 @@ QList<KoShape*> KoSvgPaste::fetchShapes(const QRectF viewportInPx, \
qreal resolut  if (!mimeData) return shapes;
 
     QByteArray data = mimeData->data("image/svg+xml");
-    if (data.isEmpty()) return shapes;
+    if (data.isEmpty()) {
+        return shapes;
+    }
+
+    return fetchShapesFromData(data, viewportInPx, resolutionPPI, fragmentSize);
+
+}
+
+QList<KoShape*> KoSvgPaste::fetchShapesFromData(const QByteArray &data, const QRectF \
viewportInPx, qreal resolutionPPI, QSizeF *fragmentSize) +{
+    QList<KoShape*> shapes;
+
+    if (data.isEmpty()) {
+        return shapes;
+    }
 
     KoXmlDocument doc;
 
@@ -57,7 +67,7 @@ QList<KoShape*> KoSvgPaste::fetchShapes(const QRectF viewportInPx, \
                qreal resolut
     const bool documentValid = doc.setContent(data, false, &errorMsg, &errorLine, \
&errorColumn);  
     if (!documentValid) {
-        errorFlake << "Failed to process an SVG file at"
+        qWarning() << "Failed to process an SVG file at"
                    << errorLine << ":" << errorColumn << "->" << errorMsg;
         return shapes;
     }
diff --git a/libs/flake/KoSvgPaste.h b/libs/flake/KoSvgPaste.h
index 98400cf6e14..6c44b9e3f87 100644
--- a/libs/flake/KoSvgPaste.h
+++ b/libs/flake/KoSvgPaste.h
@@ -25,14 +25,15 @@
 class KoShape;
 class QRectF;
 class QSizeF;
+class QByteArray;
 
 class KRITAFLAKE_EXPORT KoSvgPaste
 {
 public:
-    KoSvgPaste();
+    static bool hasShapes();
+    static QList<KoShape*> fetchShapes(const QRectF viewportInPx, qreal \
resolutionPPI, QSizeF *fragmentSize = 0); +    static QList<KoShape*> \
fetchShapesFromData(const QByteArray &data, const QRectF viewportInPx, qreal \
resolutionPPI, QSizeF *fragmentSize = 0);  
-    bool hasShapes() const;
-    QList<KoShape*> fetchShapes(const QRectF viewportInPx, qreal resolutionPPI, \
QSizeF *fragmentSize = 0) const;  };
 
 #endif // KOSVGPASTE_H
diff --git a/libs/flake/resources/KoSvgSymbolCollectionResource.cpp \
b/libs/flake/resources/KoSvgSymbolCollectionResource.cpp index \
                d9beb8cb3a8..0951e5d7463 100644
--- a/libs/flake/resources/KoSvgSymbolCollectionResource.cpp
+++ b/libs/flake/resources/KoSvgSymbolCollectionResource.cpp
@@ -76,8 +76,6 @@ KoSvgSymbolCollectionResource::~KoSvgSymbolCollectionResource()
 
 bool KoSvgSymbolCollectionResource::load()
 {
-    qDebug() << "Going to load" << filename();
-
     QFile file(filename());
     if (file.size() == 0) return false;
     if (!file.open(QIODevice::ReadOnly)) {
@@ -136,12 +134,12 @@ bool KoSvgSymbolCollectionResource::loadFromDevice(QIODevice \
*dev)  // We're not interested in the shapes themselves
     qDeleteAll(parser.parseSvg(doc.documentElement(), &fragmentSize));
     d->symbols = parser.takeSymbols();
-    qDebug() << "Loaded" << filename() << "\n\t"
-             << "Title" << parser.documentTitle() << "\n\t"
-             << "Description" << parser.documentDescription()
-             << "\n\tgot" << d->symbols.size() << "symbols"
-             << d->symbols[0]->shape->outlineRect()
-             << d->symbols[0]->shape->size();
+//    qDebug() << "Loaded" << filename() << "\n\t"
+//             << "Title" << parser.documentTitle() << "\n\t"
+//             << "Description" << parser.documentDescription()
+//             << "\n\tgot" << d->symbols.size() << "symbols"
+//             << d->symbols[0]->shape->outlineRect()
+//             << d->symbols[0]->shape->size();
 
     d->title = parser.documentTitle();
     setName(d->title);
diff --git a/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.cpp \
b/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.cpp index \
                ebaaaf9ebb3..eb23bd549ca 100644
--- a/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.cpp
+++ b/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.cpp
@@ -22,12 +22,110 @@
 #include <klocalizedstring.h>
 
 #include <QDebug>
+#include <QAbstractListModel>
+#include <QMimeData>
+#include <QDomDocument>
+#include <QDomElement>
 
 #include <KoResourceServerProvider.h>
 #include <KoResourceServer.h>
+#include <KoShapeFactoryBase.h>
+#include <KoProperties.h>
+#include <KoDrag.h>
 
 #include "ui_WdgSvgCollection.h"
 
+#include <resources/KoSvgSymbolCollectionResource.h>
+
+//
+// SvgCollectionModel
+//
+SvgCollectionModel::SvgCollectionModel(QObject *parent)
+    : QAbstractListModel(parent)
+{
+    setSupportedDragActions(Qt::CopyAction);
+}
+
+QVariant SvgCollectionModel::data(const QModelIndex &index, int role) const
+{
+    if (!index.isValid() || index.row() > m_symbolCollection->symbols().count()) {
+        return QVariant();
+    }
+
+    switch (role) {
+    case Qt::ToolTipRole:
+        return m_symbolCollection->symbols()[index.row()]->title;
+
+    case Qt::DecorationRole:
+    {
+        QPixmap px = \
QPixmap::fromImage(m_symbolCollection->symbols()[index.row()]->icon); +        QIcon \
icon(px); +        return icon;
+    }
+    case Qt::UserRole:
+        return m_symbolCollection->symbols()[index.row()]->id;
+
+    case Qt::DisplayRole:
+        return m_symbolCollection->symbols()[index.row()]->title;
+
+    default:
+        return QVariant();
+    }
+
+    return QVariant();
+}
+
+int SvgCollectionModel::rowCount(const QModelIndex &parent) const
+{
+    Q_UNUSED(parent);
+    return m_symbolCollection->symbols().count();
+}
+
+QMimeData *SvgCollectionModel::mimeData(const QModelIndexList &indexes) const
+{
+    if (indexes.isEmpty()) {
+        return 0;
+    }
+
+    QModelIndex index = indexes.first();
+
+    if (!index.isValid()) {
+        return 0;
+    }
+
+    if (m_symbolCollection->symbols().isEmpty()) {
+        return 0;
+    }
+
+    QList<KoShape*> shapes;
+    shapes.append(m_symbolCollection->symbols()[index.row()]->shape);
+    KoDrag drag;
+    drag.setSvg(shapes);
+    QMimeData *mimeData = drag.mimeData();
+
+    return mimeData;
+}
+
+QStringList SvgCollectionModel::mimeTypes() const
+{
+    return QStringList() << SHAPETEMPLATE_MIMETYPE << "image/svg+xml";
+}
+
+Qt::ItemFlags SvgCollectionModel::flags(const QModelIndex &index) const
+{
+    if (index.isValid()) {
+        return QAbstractListModel::flags(index) | Qt::ItemIsDragEnabled;
+    }
+    return QAbstractListModel::flags(index);
+}
+
+void SvgCollectionModel::setSvgSymbolCollectionResource(KoSvgSymbolCollectionResource \
*resource) +{
+    m_symbolCollection = resource;
+}
+
+
+
 //
 // SvgSymbolCollectionDockerFactory
 //
@@ -66,8 +164,10 @@ SvgSymbolCollectionDocker::SvgSymbolCollectionDocker(QWidget \
*parent)  
     KoResourceServer<KoSvgSymbolCollectionResource>  *svgCollectionProvider = \
                KoResourceServerProvider::instance()->svgSymbolCollectionServer();
     Q_FOREACH(KoSvgSymbolCollectionResource *r, svgCollectionProvider->resources()) \
                {
-        QVariant v = QVariant::fromValue<KoSvgSymbolCollectionResource*>(r);
-        m_wdgSvgCollection->cmbCollections->addItem(r->name(), v);
+        m_wdgSvgCollection->cmbCollections->addItem(r->name());
+        SvgCollectionModel *model = new SvgCollectionModel();
+        model->setSvgSymbolCollectionResource(r);
+        m_models.append(model);
     }
 
     m_wdgSvgCollection->listCollection->setDragEnabled(true);
@@ -90,15 +190,8 @@ void SvgSymbolCollectionDocker::unsetCanvas()
 
 void SvgSymbolCollectionDocker::collectionActivated(int index)
 {
-    QVariant v = m_wdgSvgCollection->cmbCollections->itemData(index);
-    KoSvgSymbolCollectionResource *r = v.value<KoSvgSymbolCollectionResource *>();
-    if (r) {
-        m_wdgSvgCollection->listCollection->clear();
-        Q_FOREACH(KoSvgSymbol *symbol, r->symbols()) {
-            QListWidgetItem *item = new QListWidgetItem(symbol->title);
-            item->setIcon(QIcon(QPixmap::fromImage(symbol->icon)));
-            m_wdgSvgCollection->listCollection->addItem(item);
-        }
+    if (index < m_models.size()) {
+        m_wdgSvgCollection->listCollection->setModel(m_models[index]);
     }
 
 }
diff --git a/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.h \
b/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.h index \
                25e3fe8c27f..bb349bc0ac9 100644
--- a/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.h
+++ b/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.h
@@ -20,6 +20,7 @@
 #define SVGSYMBOLCOLLECTIONDOCKER_H
 
 #include <QDockWidget>
+#include <QAbstractItemModel>
 #include <QModelIndex>
 #include <QMap>
 #include <QIcon>
@@ -29,6 +30,24 @@
 
 #include "ui_WdgSvgCollection.h"
 
+class KoSvgSymbolCollectionResource;
+
+class SvgCollectionModel : public QAbstractListModel
+{
+    Q_OBJECT
+public:
+    explicit SvgCollectionModel(QObject *parent = 0);
+    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const \
override; +    int rowCount(const QModelIndex &parent = QModelIndex()) const \
override; +    QMimeData *mimeData(const QModelIndexList &indexes) const override;
+    QStringList mimeTypes() const override;
+    Qt::ItemFlags flags(const QModelIndex &index) const override;
+public:
+    void setSvgSymbolCollectionResource(KoSvgSymbolCollectionResource *resource);
+private:
+    KoSvgSymbolCollectionResource *m_symbolCollection;
+};
+
 
 class SvgSymbolCollectionDockerFactory : public KoDockFactoryBase
 {
@@ -61,6 +80,7 @@ private Q_SLOTS:
 private:
 
     Ui_WdgSvgCollection *m_wdgSvgCollection;
+    QVector<SvgCollectionModel*> m_models;
 };
 
 #endif //KOSHAPECOLLECTIONDOCKER_H
diff --git a/plugins/dockers/shapedockers/WdgSvgCollection.ui \
b/plugins/dockers/shapedockers/WdgSvgCollection.ui index e3057847eb3..64b41a2d93e \
                100644
--- a/plugins/dockers/shapedockers/WdgSvgCollection.ui
+++ b/plugins/dockers/shapedockers/WdgSvgCollection.ui
@@ -18,7 +18,7 @@
     <widget class="QComboBox" name="cmbCollections"/>
    </item>
    <item>
-    <widget class="QListWidget" name="listCollection"/>
+    <widget class="QListView" name="listCollection"/>
    </item>
   </layout>
  </widget>


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic