1 /***************************************************************************
2     qgslayoutimagedrophandler.cpp
3     ------------------------------
4     begin                : November 2019
5     copyright            : (C) 2019 by nyall Dawson
6     email                : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 #include "qgslayoutimagedrophandler.h"
17 #include "qgslayoutdesignerinterface.h"
18 #include "qgslayout.h"
19 #include "qgslayoutview.h"
20 #include "qgslayoutitempicture.h"
21 
22 #include <QImageReader>
23 
QgsLayoutImageDropHandler(QObject * parent)24 QgsLayoutImageDropHandler::QgsLayoutImageDropHandler( QObject *parent )
25   : QgsLayoutCustomDropHandler( parent )
26 {
27 
28 }
29 
handleFileDrop(QgsLayoutDesignerInterface * iface,QPointF point,const QString & file)30 bool QgsLayoutImageDropHandler::handleFileDrop( QgsLayoutDesignerInterface *iface, QPointF point, const QString &file )
31 {
32   QFileInfo fi( file );
33   bool matched = false;
34   bool svg = false;
35   if ( fi.suffix().compare( "svg", Qt::CaseInsensitive ) == 0 )
36   {
37     matched = true;
38     svg = true;
39   }
40   else
41   {
42     const QList<QByteArray> formats = QImageReader::supportedImageFormats();
43     for ( const QByteArray &format : formats )
44     {
45       if ( fi.suffix().compare( format, Qt::CaseInsensitive ) == 0 )
46       {
47         matched = true;
48         break;
49       }
50     }
51   }
52 
53   if ( !matched )
54     return false;
55 
56   if ( !iface->layout() )
57     return false;
58 
59   std::unique_ptr< QgsLayoutItemPicture > item = qgis::make_unique< QgsLayoutItemPicture >( iface->layout() );
60 
61   QgsLayoutPoint layoutPoint = iface->layout()->convertFromLayoutUnits( point, iface->layout()->units() );
62 
63   item->setPicturePath( file, svg ? QgsLayoutItemPicture::FormatSVG : QgsLayoutItemPicture::FormatRaster );
64 
65   // force a resize to the image's actual size
66   item->setResizeMode( QgsLayoutItemPicture::FrameToImageSize );
67   // and then move back to standard freeform image sizing
68   item->setResizeMode( QgsLayoutItemPicture::Zoom );
69 
70   // we want the drop location to be the center of the placed item, because drag thumbnails are usually centered on the mouse cursor
71   item->setReferencePoint( QgsLayoutItem::Middle );
72   item->attemptMove( layoutPoint );
73 
74   // reset to standard top-left reference point location
75   item->setReferencePoint( QgsLayoutItem::UpperLeft );
76 
77   // and auto select new item for convenience
78   QList< QgsLayoutItem * > newSelection;
79   newSelection << item.get();
80   iface->layout()->addLayoutItem( item.release() );
81   iface->layout()->deselectAll();
82   iface->selectItems( newSelection );
83 
84   return true;
85 }
86 
handlePaste(QgsLayoutDesignerInterface * iface,QPointF pastePoint,const QMimeData * data,QList<QgsLayoutItem * > & pastedItems)87 bool QgsLayoutImageDropHandler::handlePaste( QgsLayoutDesignerInterface *iface, QPointF pastePoint, const QMimeData *data, QList<QgsLayoutItem *> &pastedItems )
88 {
89   if ( !data->hasImage() )
90     return false;
91 
92   QgsLayoutPoint layoutPoint = iface->layout()->convertFromLayoutUnits( pastePoint, iface->layout()->units() );
93   std::unique_ptr< QgsLayoutItemPicture > item = qgis::make_unique< QgsLayoutItemPicture >( iface->layout() );
94 
95   const QByteArray imageData = data->data( QStringLiteral( "application/x-qt-image" ) );
96   if ( imageData.isEmpty() )
97     return false;
98 
99   const QByteArray encoded = imageData.toBase64();
100 
101   QString path( encoded );
102   path.prepend( QLatin1String( "base64:" ) );
103 
104   item->setPicturePath( path, QgsLayoutItemPicture::FormatRaster );
105 
106   // force a resize to the image's actual size
107   item->setResizeMode( QgsLayoutItemPicture::FrameToImageSize );
108   // and then move back to standard freeform image sizing
109   item->setResizeMode( QgsLayoutItemPicture::Zoom );
110 
111   // we want the drop location to be the center of the placed item, because drag thumbnails are usually centered on the mouse cursor
112   item->setReferencePoint( QgsLayoutItem::Middle );
113   item->attemptMove( layoutPoint );
114 
115   // reset to standard top-left reference point location
116   item->setReferencePoint( QgsLayoutItem::UpperLeft );
117 
118   pastedItems << item.get();
119   iface->layout()->addLayoutItem( item.release() );
120 
121   return true;
122 }
123