QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsimagedroptextedit.cpp
Go to the documentation of this file.
1/****************************************************************************
2**
3** Copyright (C) 2013 Jiří Procházka (Hobrasoft)
4** Contact: http://www.hobrasoft.cz/
5**
6** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
7** Contact: http://www.qt-project.org/legal
8**
9** This library is free software; you can redistribute it and/or
10** modify it under the terms of the GNU Lesser General Public
11** License as published by the Free Software Foundation; either
12** version 2.1 of the License, or (at your option) any later version.
13**
14** $QT_BEGIN_LICENSE:LGPL$
15** GNU Lesser General Public License Usage
16** This file is under the terms of the GNU Lesser General Public License
17** version 2.1 as published by the Free Software Foundation and appearing
18** in the file LICENSE.LGPL included in the packaging of this file.
19** Please review the following information to ensure the
20** GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Digia gives you certain additional
24** rights. These rights are described in the Digia Qt LGPL Exception
25** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
26**
27** $QT_END_LICENSE$
28**
29****************************************************************************/
30
32#include "qgsguiutils.h"
33
34#include <QMimeData>
35#include <QBuffer>
36#include <QFileInfo>
37#include <QImageReader>
38#include <QMouseEvent>
39#include <QApplication>
40#include <QDesktopServices>
41
43QgsImageDropTextEdit::QgsImageDropTextEdit( QWidget *parent )
44 : QTextEdit( parent )
45{
46 setTextInteractionFlags( Qt::TextEditorInteraction | Qt::LinksAccessibleByMouse );
47}
48
49QgsImageDropTextEdit::~QgsImageDropTextEdit() = default;
50
51bool QgsImageDropTextEdit::canInsertFromMimeData( const QMimeData *source ) const
52{
53 if ( source->hasImage() || QTextEdit::canInsertFromMimeData( source ) )
54 return true;
55
56 const QList<QUrl> urls = source->urls();
57 QStringList files;
58 files.reserve( urls.size() );
59 for ( const QUrl &url : urls )
60 {
61 QString fileName = url.toLocalFile();
62 // seems that some drag and drop operations include an empty url
63 // so we test for length to make sure we have something
64 if ( !fileName.isEmpty() )
65 {
66 files << fileName;
67 }
68 }
69
70 bool matched = false;
71 for ( const QString &file : std::as_const( files ) )
72 {
73 QFileInfo fi( file );
74 const QList<QByteArray> formats = QImageReader::supportedImageFormats();
75 for ( const QByteArray &format : formats )
76 {
77 if ( fi.suffix().compare( format, Qt::CaseInsensitive ) == 0 )
78 {
79 matched = true;
80 break;
81 }
82 }
83 }
84
85 return matched;
86}
87
88void QgsImageDropTextEdit::insertFromMimeData( const QMimeData *source )
89{
90 if ( source->hasImage() )
91 {
92 const QStringList formats = source->formats();
93 QString format;
94 for ( const QString &string : formats )
95 {
96 if ( string == QLatin1String( "image/bmp" ) )
97 {
98 format = QStringLiteral( "BMP" );
99 break;
100 }
101 if ( string == QLatin1String( "image/jpeg" ) )
102 {
103 format = QStringLiteral( "JPG" );
104 break;
105 }
106 if ( string == QLatin1String( "image/jpg" ) )
107 {
108 format = QStringLiteral( "JPG" );
109 break;
110 }
111 if ( string == QLatin1String( "image/gif" ) )
112 {
113 format = QStringLiteral( "GIF" );
114 break;
115 }
116 if ( string == QLatin1String( "image/png" ) )
117 {
118 format = QStringLiteral( "PNG" );
119 break;
120 }
121 if ( string == QLatin1String( "image/pbm" ) )
122 {
123 format = QStringLiteral( "PBM" );
124 break;
125 }
126 if ( string == QLatin1String( "image/pgm" ) )
127 {
128 format = QStringLiteral( "PGM" );
129 break;
130 }
131 if ( string == QLatin1String( "image/ppm" ) )
132 {
133 format = QStringLiteral( "PPM" );
134 break;
135 }
136 if ( string == QLatin1String( "image/tiff" ) )
137 {
138 format = QStringLiteral( "TIFF" );
139 break;
140 }
141 if ( string == QLatin1String( "image/xbm" ) )
142 {
143 format = QStringLiteral( "XBM" );
144 break;
145 }
146 if ( string == QLatin1String( "image/xpm" ) )
147 {
148 format = QStringLiteral( "XPM" );
149 break;
150 }
151 }
152 if ( !format.isEmpty() )
153 {
154 dropImage( qvariant_cast<QImage>( source->imageData() ), format );
155 return;
156 }
157 }
158 else
159 {
160 const QList<QUrl> urls = source->urls();
161 QStringList files;
162 files.reserve( urls.size() );
163 for ( const QUrl &url : urls )
164 {
165 if ( url.isLocalFile() )
166 {
167 QString fileName = url.toLocalFile();
168 // seems that some drag and drop operations include an empty url
169 // so we test for length to make sure we have something
170 if ( !fileName.isEmpty() )
171 {
172 files << fileName;
173 }
174 }
175 else
176 {
177 dropLink( url );
178 }
179 }
180
181 for ( const QString &file : std::as_const( files ) )
182 {
183 const QFileInfo fi( file );
184 const QList<QByteArray> formats = QImageReader::supportedImageFormats();
185 bool isImage = false;
186 for ( const QByteArray &format : formats )
187 {
188 if ( fi.suffix().compare( format, Qt::CaseInsensitive ) == 0 )
189 {
190 const QImage image( file );
191 dropImage( image, format );
192 isImage = true;
193 break;
194 }
195 }
196 if ( !isImage )
197 {
198 dropLink( QUrl::fromLocalFile( file ) );
199 }
200 }
201 if ( !files.empty() )
202 return;
203 }
204
205 QTextEdit::insertFromMimeData( source );
206}
207
208void QgsImageDropTextEdit::mouseMoveEvent( QMouseEvent *e )
209{
210 QTextEdit::mouseMoveEvent( e );
211 mActiveAnchor = anchorAt( e->pos() );
212 if ( !mActiveAnchor.isEmpty() && !mCursorOverride )
213 mCursorOverride = std::make_unique< QgsTemporaryCursorOverride >( Qt::PointingHandCursor );
214 else if ( mActiveAnchor.isEmpty() && mCursorOverride )
215 mCursorOverride.reset();
216}
217
218void QgsImageDropTextEdit::mouseReleaseEvent( QMouseEvent *e )
219{
220 if ( e->button() == Qt::LeftButton && !mActiveAnchor.isEmpty() )
221 {
222 QDesktopServices::openUrl( QUrl( mActiveAnchor ) );
223 if ( mCursorOverride )
224 mCursorOverride.reset();
225 mActiveAnchor.clear();
226 }
227 else
228 {
229 QTextEdit::mouseReleaseEvent( e );
230 }
231}
232
233void QgsImageDropTextEdit::dropImage( const QImage &image, const QString &format )
234{
235 QByteArray bytes;
236 QBuffer buffer( &bytes );
237 buffer.open( QIODevice::WriteOnly );
238 image.save( &buffer, format.toLocal8Bit().data() );
239 buffer.close();
240 QByteArray base64 = bytes.toBase64();
241 QByteArray base64l;
242 for ( int i = 0; i < base64.size(); i++ )
243 {
244 base64l.append( base64[i] );
245 if ( i % 80 == 0 )
246 {
247 base64l.append( "\n" );
248 }
249 }
250
251 QTextCursor cursor = textCursor();
252 QTextImageFormat imageFormat;
253 imageFormat.setWidth( image.width() );
254 imageFormat.setHeight( image.height() );
255 imageFormat.setName( QStringLiteral( "data:image/%1;base64,%2" )
256 .arg( QStringLiteral( "%1.%2" ).arg( rand() ).arg( format ),
257 base64l.data() )
258 );
259 cursor.insertImage( imageFormat );
260}
261
262void QgsImageDropTextEdit::dropLink( const QUrl &url )
263{
264 QTextCursor cursor = textCursor();
265 cursor.insertHtml( QStringLiteral( "<a href=\"%1\">%1</a>" ).arg( url.toString() ) );
266}
267