1/*
2 Copyright (c) 2009 Thomas McGuire <mcguire@kde.org>
3
4 Based on KMail and libkdepim code by:
5 Copyright 2007 - 2010 Laurent Montel <montel@kde.org>
6
7 This library is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Library General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at your
10 option) any later version.
11
12 This library is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15 License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21*/
22#ifndef KPIMTEXTEDIT_TEXTEDIT_H
23#define KPIMTEXTEDIT_TEXTEDIT_H
24
25#include "kpimtextedit_export.h"
26
27#include <kpimidentities/signature.h> // TODO KF5: remove this
28
29#include <KDE/KRichTextWidget>
30#include <KActionCollection>
31
32#include <QtCore/QSharedPointer>
33
34#include <memory>
35// TODO KF5: remove this
36#define FIX_KMAIL_INSERT_IMAGE 1
37
38class KUrl;
39class QFileInfo;
40
41namespace KPIMTextEdit {
42
43class TextEditPrivate;
44class EMailQuoteHighlighter;
45
46/**
47 * Holds information about an embedded HTML image that will be useful for mail clients.
48 * A list with all images can be retrieved with TextEdit::embeddedImages().
49 */
50struct EmbeddedImage
51{
52 QByteArray image; ///< The image, encoded as PNG with base64 encoding
53 QString contentID; ///< The content id of the embedded image
54 QString imageName; ///< Name of the image as it is available as a resource in the editor
55};
56
57/**
58 * Holds information about an embedded HTML image that will be generally useful.
59 * A list with all images can be retrieved with TextEdit::imagesWithName().
60 *
61 * @since 4.4
62 */
63struct ImageWithName
64{
65 QImage image; ///< The image
66 QString name; ///< The name of the image as it is available as a resource in the editor
67};
68
69typedef QSharedPointer<ImageWithName> ImageWithNamePtr;
70typedef QList< ImageWithNamePtr > ImageWithNameList;
71typedef QList< QSharedPointer<EmbeddedImage> > ImageList;
72
73/**
74 * Special textedit that provides additional features which are useful for PIM applications
75 * like mail clients.
76 * Additional features this class provides:
77 * - Highlighting quoted text
78 * - Handling of inline images
79 * - Auto-Hiding the cursor
80 * - Handling of pastes and drops of images
81 *
82 * @since 4.3
83 */
84class KPIMTEXTEDIT_EXPORT TextEdit : public KRichTextWidget,
85 // TODO: KDE5: get rid of the spell interface
86 protected KTextEditSpellInterface
87{
88 Q_OBJECT
89
90 public:
91
92 /**
93 * Constructs a TextEdit object
94 * @param text the initial plain text of the text edit, interpreted as HTML
95 * @param parent the parent widget
96 */
97 explicit TextEdit( const QString &text, QWidget *parent = 0 );
98
99 /**
100 * Constructs a TextEdit object.
101 * @param parent the parent widget
102 */
103 explicit TextEdit( QWidget *parent = 0 );
104
105 /**
106 * Constructs a TextEdit object
107 * @param parent the parent widget
108 * @param configFile the config file
109 * @since 4.6
110 *
111 * TODO KDE-5 merge with other constructor
112 */
113 explicit TextEdit( QWidget *parent, const QString &configFile );
114
115 /**
116 * Calling this allows createActions() to create the add image actions.
117 * Call this method before calling createActions(), otherwise the action
118 * will not be added.
119 * Also, if image actions is enabled, the user can paste PNG images.
120 *
121 * Don't call this if you don't want to support adding images.
122 */
123 void enableImageActions();
124 /**
125 * Calling this allows createActions() to create the add emoticons actions.
126 * Call this method before calling createActions(), otherwise the action
127 * will not be added.
128 * Don't call this if you don't want to support emoticons actions.
129 */
130 void enableEmoticonActions();
131
132 void enableInsertHtmlActions();
133
134 void enableInsertTableActions();
135 /**
136 * Destructor
137 */
138 ~TextEdit();
139
140 /**
141 * Reimplemented from KMEditor, to support more actions.
142 *
143 * @param actionCollection the collection to put the new actions into
144 * The additional action XML names are:
145 * - add_image
146 * - delete_line
147 *
148 * The add_image actions is only added if enableImageActions() is called before.
149 */
150 virtual void createActions( KActionCollection *actionCollection );
151
152 /**
153 * Adds an image. The image is loaded from file and then pasted to the current
154 * cursor position.
155 *
156 * @param url The URL of the file which contains the image
157 */
158 void addImage( const KUrl &url );
159
160 /**
161 * Adds an image. The image is loaded from file and then pasted to the current
162 * cursor position with the given @p width and @p height.
163 *
164 * @param url The URL of the file which contains the image
165 * @param width The width the inserted image will have.
166 * @param height The height the inserted image will have.
167 *
168 * @since 4.10
169 */
170 void addImage( const KUrl &url, int width, int height );
171
172 /**
173 * Loads an image into the textedit. The difference to addImage() is that this
174 * function expects that the image tag is already present in the HTML source.
175 *
176 * @param image the image to load
177 * @param matchName the name of tags to match image
178 * @param resourceName the resource name of image
179 * So what this message does is that it scans the HTML source for the image
180 * tag that matches the @p matchName, and then inserts the @p image as a
181 * resource, giving that resource the name @p resourceName.
182 *
183 * @since 4.4
184 */
185 void loadImage( const QImage &image, const QString &matchName, const QString &resourceName );
186
187 /**
188 * Deletes the line at the current cursor position.
189 * @since 4.4
190 */
191 void deleteCurrentLine();
192
193 /**
194 * Get a list with all embedded HTML images.
195 * If the same image is contained twice or more in the editor, it will have only
196 * one entry in this list.
197 *
198 * @return a list of embedded HTML images of the editor.
199 */
200 ImageList embeddedImages() const;
201
202 /**
203 * Same as embeddedImages(), only that this returns a list of general purpose information,
204 * whereas the embeddedImages() function returns a list with mail-specific information.
205 *
206 * @since 4.4
207 */
208 ImageWithNameList imagesWithName() const;
209
210 /**
211 * Returns the text of the editor as plain text, with linebreaks inserted
212 * where word-wrapping occurred.
213 */
214 QString toWrappedPlainText() const;
215
216 /**
217 * @since 5.0
218 */
219 QString toWrappedPlainText( QTextDocument *document ) const;
220
221 /**
222 * @since 4.10
223 */
224 //TODO 5.0 merge it
225 QString toCleanPlainText( const QString &plainText ) const;
226
227 /**
228 * Same as toPlainText() from QTextEdit, only that it removes embedded
229 * images and converts non-breaking space characters to normal spaces.
230 */
231 QString toCleanPlainText() const;
232
233 /**
234 * This method is called after the highlighter is created.
235 * If you use custom colors for highlighting, override this method and
236 * set the colors to the highlighter in it.
237 *
238 * The default implementation does nothing, therefore the default colors of
239 * the EMailQuoteHighlighter class will be used.
240 *
241 * @param highlighter the highlighter that was just created. You need to
242 * set the colors of this highlighter.
243 */
244 virtual void setHighlighterColors( EMailQuoteHighlighter *highlighter );
245
246 /**
247 * Convenience method for qouteLength( line ) > 0
248 */
249 bool isLineQuoted( const QString &line ) const;
250
251 /**
252 * This is called whenever the editor needs to find out the length of the quote,
253 * i.e. the length of the quote prefix before the real text starts.
254 * The default implementation counts the number of spaces, '>' and '|' chars in
255 * front of the line.
256 *
257 * @param line the line of which the length of the quote prefix should be returned
258 * @return 0 if the line is not quoted, the length of the quote prefix otherwise
259 * FIXME: Not yet used in all places, e.g. keypressEvent() or the quote highlighter
260 */
261 virtual int quoteLength( const QString &line ) const;
262
263 /**
264 * Returns the prefix that is added to a line that is quoted.
265 * By default, this is "> ".
266 */
267 virtual const QString defaultQuoteSign() const;
268
269 /**
270 * For all given embedded images, this function replace the image name
271 * in the <img> tag of the HTML body with cid:content-id, so that the
272 * HTML references the image body parts, see RFC 2557.
273 *
274 * This is useful when building a MIME message with inline images.
275 *
276 * Note that this function works on encoded content already.
277 *
278 * @param htmlBody the HTML code in which the <img> tag will be modified.
279 * The HTML code here could come from toHtml(), for example.
280 *
281 * @param imageList the list of images of which the <img> tag will be modified.
282 * You can get such a list from the embeddedImages() function.
283 *
284 * @return a modified HTML code, where the <img> tags got replaced
285 */
286 static QByteArray imageNamesToContentIds( const QByteArray &htmlBody,
287 const ImageList &imageList );
288
289 /**
290 * Checks if rich text formatting is used anywhere.
291 * This is not the same as checking whether textMode() returns "Rich",
292 * since that only tells that rich text mode is enabled, but not if any
293 * special formatting is actually used.
294 *
295 * @return true if formatting is used anywhere
296 */
297 bool isFormattingUsed() const;
298
299 /**
300 * Return config file.
301 * @since 4.5
302 */
303 QString configFile() const;
304
305 /** Return true if richtext mode support image
306 * @since 4.6
307 */
308 bool isEnableImageActions() const;
309
310 /** Return true if emoticons actions supported
311 * @since 4.9
312 */
313 bool isEnableEmoticonActions() const;
314
315 /**
316 * @param image the image to insert
317 * @param info the info to supply with image
318 * @since 4.6
319 */
320 void insertImage( const QImage &image, const QFileInfo &info );
321
322 /**
323 * @since 4.10
324 */
325 bool isEnableInsertHtmlActions() const;
326
327 /**
328 * @since 4.10
329 */
330 bool isEnableInsertTableActions() const;
331
332 protected:
333
334 /**
335 * Reimplemented for inline image support
336 */
337 virtual bool canInsertFromMimeData( const QMimeData *source ) const;
338
339 /**
340 * Reimplemented for inline image support
341 */
342 virtual void insertFromMimeData( const QMimeData *source );
343
344 /**
345 * Reimplemented from KRichTextWidget to hide the mouse cursor when there
346 * was no mouse movement for some time, using KCursor
347 */
348 virtual bool eventFilter( QObject *o, QEvent *e );
349
350 /**
351 * Reimplemented to add qoute signs when the user presses enter
352 * on a quoted line.
353 */
354 virtual void keyPressEvent ( QKeyEvent *e );
355
356 // For the explaination for these four methods, see the comment at the
357 // spellCheckingEnabled variable of the private class.
358
359 /**
360 * Reimplemented from KTextEditSpellInterface
361 */
362 virtual bool isSpellCheckingEnabled() const;
363
364 /**
365 * Reimplemented from KTextEditSpellInterface
366 */
367 virtual void setSpellCheckingEnabled( bool enable );
368
369 /**
370 * Reimplemented from KTextEditSpellInterface, to avoid spellchecking
371 * quoted text.
372 */
373 virtual bool shouldBlockBeSpellChecked( const QString &block ) const;
374
375 /**
376 * Reimplemented to create our own highlighter which does quote and
377 * spellcheck highlighting
378 */
379 virtual void createHighlighter();
380
381 private:
382 void addImageHelper( const KUrl &url, int width = -1, int height = -1 );
383 std::auto_ptr<TextEditPrivate> const d;
384 friend class TextEditPrivate;
385 Q_PRIVATE_SLOT( d, void _k_slotAddImage() )
386 Q_PRIVATE_SLOT( d, void _k_slotDeleteLine() )
387 Q_PRIVATE_SLOT( d, void _k_slotAddEmoticon( const QString & ) )
388 Q_PRIVATE_SLOT( d, void _k_slotInsertHtml() )
389 Q_PRIVATE_SLOT( d, void _k_slotFormatReset() )
390 Q_PRIVATE_SLOT( d, void _k_slotTextModeChanged( KRichTextEdit::Mode ) )
391};
392
393} // namespace
394
395#endif
396