QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
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
33#include "qgsguiutils.h"
34
35#include <QApplication>
36#include <QBuffer>
37#include <QDesktopServices>
38#include <QFileInfo>
39#include <QImageReader>
40#include <QMimeData>
41#include <QMouseEvent>
42#include <QString>
43
44#include "moc_qgsimagedroptextedit.cpp"
45
46using namespace Qt::StringLiterals;
47
49QgsImageDropTextEdit::QgsImageDropTextEdit( QWidget *parent )
50 : QTextEdit( parent )
51{
52 setTextInteractionFlags( Qt::TextEditorInteraction | Qt::LinksAccessibleByMouse );
53}
54
55QgsImageDropTextEdit::~QgsImageDropTextEdit() = default;
56
57bool QgsImageDropTextEdit::canInsertFromMimeData( const QMimeData *source ) const
58{
59 if ( source->hasImage() || QTextEdit::canInsertFromMimeData( source ) )
60 return true;
61
62 const QList<QUrl> urls = source->urls();
63 QStringList files;
64 files.reserve( urls.size() );
65 for ( const QUrl &url : urls )
66 {
67 QString fileName = url.toLocalFile();
68 // seems that some drag and drop operations include an empty url
69 // so we test for length to make sure we have something
70 if ( !fileName.isEmpty() )
71 {
72 files << fileName;
73 }
74 }
75
76 bool matched = false;
77 for ( const QString &file : std::as_const( files ) )
78 {
79 QFileInfo fi( file );
80 const QList<QByteArray> formats = QImageReader::supportedImageFormats();
81 for ( const QByteArray &format : formats )
82 {
83 if ( fi.suffix().compare( format, Qt::CaseInsensitive ) == 0 )
84 {
85 matched = true;
86 break;
87 }
88 }
89 }
90
91 return matched;
92}
93
94void QgsImageDropTextEdit::insertFromMimeData( const QMimeData *source )
95{
96 if ( source->hasImage() )
97 {
98 const QStringList formats = source->formats();
99 QString format;
100 for ( const QString &string : formats )
101 {
102 if ( string == "image/bmp"_L1 )
103 {
104 format = u"BMP"_s;
105 break;
106 }
107 if ( string == "image/jpeg"_L1 )
108 {
109 format = u"JPG"_s;
110 break;
111 }
112 if ( string == "image/jpg"_L1 )
113 {
114 format = u"JPG"_s;
115 break;
116 }
117 if ( string == "image/gif"_L1 )
118 {
119 format = u"GIF"_s;
120 break;
121 }
122 if ( string == "image/png"_L1 )
123 {
124 format = u"PNG"_s;
125 break;
126 }
127 if ( string == "image/pbm"_L1 )
128 {
129 format = u"PBM"_s;
130 break;
131 }
132 if ( string == "image/pgm"_L1 )
133 {
134 format = u"PGM"_s;
135 break;
136 }
137 if ( string == "image/ppm"_L1 )
138 {
139 format = u"PPM"_s;
140 break;
141 }
142 if ( string == "image/tiff"_L1 )
143 {
144 format = u"TIFF"_s;
145 break;
146 }
147 if ( string == "image/xbm"_L1 )
148 {
149 format = u"XBM"_s;
150 break;
151 }
152 if ( string == "image/xpm"_L1 )
153 {
154 format = u"XPM"_s;
155 break;
156 }
157 }
158 if ( !format.isEmpty() )
159 {
160 dropImage( qvariant_cast<QImage>( source->imageData() ), format );
161 return;
162 }
163 }
164 else
165 {
166 const QList<QUrl> urls = source->urls();
167 QStringList files;
168 files.reserve( urls.size() );
169 for ( const QUrl &url : urls )
170 {
171 if ( url.isLocalFile() )
172 {
173 QString fileName = url.toLocalFile();
174 // seems that some drag and drop operations include an empty url
175 // so we test for length to make sure we have something
176 if ( !fileName.isEmpty() )
177 {
178 files << fileName;
179 }
180 }
181 else
182 {
183 dropLink( url );
184 }
185 }
186
187 for ( const QString &file : std::as_const( files ) )
188 {
189 const QFileInfo fi( file );
190 const QList<QByteArray> formats = QImageReader::supportedImageFormats();
191 bool isImage = false;
192 for ( const QByteArray &format : formats )
193 {
194 if ( fi.suffix().compare( format, Qt::CaseInsensitive ) == 0 )
195 {
196 const QImage image( file );
197 dropImage( image, format );
198 isImage = true;
199 break;
200 }
201 }
202 if ( !isImage )
203 {
204 dropLink( QUrl::fromLocalFile( file ) );
205 }
206 }
207 if ( !files.empty() )
208 return;
209 }
210
211 QTextEdit::insertFromMimeData( source );
212}
213
214void QgsImageDropTextEdit::mouseMoveEvent( QMouseEvent *e )
215{
216 QTextEdit::mouseMoveEvent( e );
217 mActiveAnchor = anchorAt( e->pos() );
218 if ( !mActiveAnchor.isEmpty() && !mCursorOverride )
219 mCursorOverride = std::make_unique<QgsTemporaryCursorOverride>( Qt::PointingHandCursor );
220 else if ( mActiveAnchor.isEmpty() && mCursorOverride )
221 mCursorOverride.reset();
222}
223
224void QgsImageDropTextEdit::mouseReleaseEvent( QMouseEvent *e )
225{
226 if ( e->button() == Qt::LeftButton && !mActiveAnchor.isEmpty() )
227 {
228 QDesktopServices::openUrl( QUrl( mActiveAnchor ) );
229 if ( mCursorOverride )
230 mCursorOverride.reset();
231 mActiveAnchor.clear();
232 }
233 else
234 {
235 QTextEdit::mouseReleaseEvent( e );
236 }
237}
238
239void QgsImageDropTextEdit::dropImage( const QImage &image, const QString &format )
240{
241 QByteArray bytes;
242 QBuffer buffer( &bytes );
243 buffer.open( QIODevice::WriteOnly );
244 image.save( &buffer, format.toLocal8Bit().data() );
245 buffer.close();
246 QByteArray base64 = bytes.toBase64();
247 QByteArray base64l;
248 for ( int i = 0; i < base64.size(); i++ )
249 {
250 base64l.append( base64[i] );
251 if ( i % 80 == 0 )
252 {
253 base64l.append( "\n" );
254 }
255 }
256
257 QTextCursor cursor = textCursor();
258 QTextImageFormat imageFormat;
259 imageFormat.setWidth( image.width() );
260 imageFormat.setHeight( image.height() );
261 imageFormat.setName( u"data:image/%1;base64,%2"_s
262 .arg( u"%1.%2"_s.arg( rand() ).arg( format ), base64l.data() )
263 );
264 cursor.insertImage( imageFormat );
265}
266
267void QgsImageDropTextEdit::dropLink( const QUrl &url )
268{
269 QTextCursor cursor = textCursor();
270 cursor.insertHtml( u"<a href=\"%1\">%1</a>"_s.arg( url.toString() ) );
271}
272