1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include "qtextdocumentwriter.h"
4
5#include <QtCore/qfile.h>
6#include <QtCore/qbytearray.h>
7#include <QtCore/qfileinfo.h>
8#include <QtCore/qtextstream.h>
9#include <QtCore/qdebug.h>
10#include "qtextdocument.h"
11#include "qtextdocumentfragment.h"
12
13#include "qtextdocumentfragment_p.h"
14#include "qtextodfwriter_p.h"
15#if QT_CONFIG(textmarkdownwriter)
16#include "qtextmarkdownwriter_p.h"
17#endif
18
19#include <algorithm>
20
21QT_BEGIN_NAMESPACE
22
23class QTextDocumentWriterPrivate
24{
25public:
26 QTextDocumentWriterPrivate(QTextDocumentWriter* qq);
27
28 // device
29 QByteArray format;
30 QIODevice *device;
31 bool deleteDevice;
32
33 QTextDocumentWriter *q;
34};
35
36/*!
37 \since 4.5
38 \class QTextDocumentWriter
39
40 \brief The QTextDocumentWriter class provides a format-independent interface for writing a QTextDocument to files or other devices.
41 \inmodule QtGui
42
43 \ingroup richtext-processing
44
45 To write a document, construct a QTextDocumentWriter object with either a
46 file name or a device object, and specify the document format to be
47 written. You can construct a writer and set the format using setFormat()
48 later.
49
50 Call write() to write the document to the device. If the document is
51 successfully written, this function returns \c true. However, if an error
52 occurs when writing the document, it will return false.
53
54 Call supportedDocumentFormats() for a list of formats that
55 QTextDocumentWriter can write.
56
57 Since the capabilities of the supported output formats vary considerably,
58 the writer simply outputs the appropriate subset of objects for each format.
59 This typically includes the formatted text and images contained in a
60 document.
61*/
62
63/*!
64 \internal
65*/
66QTextDocumentWriterPrivate::QTextDocumentWriterPrivate(QTextDocumentWriter *qq)
67 : device(nullptr),
68 deleteDevice(false),
69 q(qq)
70{
71}
72
73/*!
74 Constructs an empty QTextDocumentWriter object. Before writing, you must
75 call setFormat() to set a document format, then setDevice() or
76 setFileName().
77*/
78QTextDocumentWriter::QTextDocumentWriter()
79 : d(new QTextDocumentWriterPrivate(this))
80{
81}
82
83/*!
84 Constructs a QTextDocumentWriter object to write to the given \a device
85 in the document format specified by \a format.
86*/
87QTextDocumentWriter::QTextDocumentWriter(QIODevice *device, const QByteArray &format)
88 : d(new QTextDocumentWriterPrivate(this))
89{
90 d->device = device;
91 d->format = format;
92}
93
94/*!
95 Constructs an QTextDocumentWriter object that will write to a file with
96 the name \a fileName, using the document format specified by \a format.
97 If \a format is not provided, QTextDocumentWriter will detect the document
98 format by inspecting the extension of \a fileName.
99*/
100QTextDocumentWriter::QTextDocumentWriter(const QString &fileName, const QByteArray &format)
101 : QTextDocumentWriter(new QFile(fileName), format)
102{
103 d->deleteDevice = true;
104}
105
106/*!
107 Destroys the QTextDocumentWriter object.
108*/
109QTextDocumentWriter::~QTextDocumentWriter()
110{
111 if (d->deleteDevice)
112 delete d->device;
113 delete d;
114}
115
116/*!
117 Sets the format used to write documents to the \a format specified.
118 \a format is a case insensitive text string. For example:
119
120 \snippet code/src_gui_text_qtextdocumentwriter.cpp 0
121
122 You can call supportedDocumentFormats() for the full list of formats
123 QTextDocumentWriter supports.
124
125 \sa format()
126*/
127void QTextDocumentWriter::setFormat (const QByteArray &format)
128{
129 d->format = format;
130}
131
132/*!
133 Returns the format used for writing documents.
134
135 \sa setFormat()
136*/
137QByteArray QTextDocumentWriter::format () const
138{
139 return d->format;
140}
141
142/*!
143 Sets the writer's device to the \a device specified. If a device has
144 already been set, the old device is removed but otherwise left
145 unchanged.
146
147 If the device is not already open, QTextDocumentWriter will attempt to
148 open the device in \l {QIODeviceBase::}{WriteOnly} mode by calling open().
149
150 \note This will not work for certain devices, such as QProcess,
151 QTcpSocket and QUdpSocket, where some configuration is required before
152 the device can be opened.
153
154 \sa device(), setFileName()
155*/
156void QTextDocumentWriter::setDevice (QIODevice *device)
157{
158 if (d->device && d->deleteDevice)
159 delete d->device;
160
161 d->device = device;
162 d->deleteDevice = false;
163}
164
165/*!
166 Returns the device currently assigned, or \nullptr if no device
167 has been assigned.
168*/
169QIODevice *QTextDocumentWriter::device () const
170{
171 return d->device;
172}
173
174/*!
175 Sets the name of the file to be written to \a fileName. Internally,
176 QTextDocumentWriter will create a QFile and open it in \l
177 {QIODeviceBase::}{WriteOnly} mode, and use this file when writing the
178 document.
179
180 \sa fileName(), setDevice()
181*/
182void QTextDocumentWriter::setFileName (const QString &fileName)
183{
184 setDevice(new QFile(fileName));
185 d->deleteDevice = true;
186}
187
188/*!
189 If the currently assigned device is a QFile, or if setFileName()
190 has been called, this function returns the name of the file
191 to be written to. In all other cases, it returns an empty string.
192
193 \sa setFileName(), setDevice()
194*/
195QString QTextDocumentWriter::fileName () const
196{
197 QFile *file = qobject_cast<QFile *>(object: d->device);
198 return file ? file->fileName() : QString();
199}
200
201/*!
202 Writes the given \a document to the assigned device or file and
203 returns \c true if successful; otherwise returns \c false.
204*/
205bool QTextDocumentWriter::write(const QTextDocument *document)
206{
207 if (!d->device)
208 return false;
209
210 QByteArray suffix;
211 if (d->format.isEmpty()) {
212 // if there's no format, see if device is a file, and if so, find
213 // the file suffix
214 if (QFile *file = qobject_cast<QFile *>(object: d->device))
215 suffix = QFileInfo(file->fileName()).suffix().toLower().toLatin1();
216 }
217
218 QByteArray format = !d->format.isEmpty() ? d->format.toLower() : suffix;
219
220#ifndef QT_NO_TEXTODFWRITER
221 if (format == "odf" || format == "opendocumentformat" || format == "odt") {
222 QTextOdfWriter writer(*document, d->device);
223 return writer.writeAll();
224 }
225#endif // QT_NO_TEXTODFWRITER
226
227#if QT_CONFIG(textmarkdownwriter)
228 if (format == "md" || format == "mkd" || format == "markdown") {
229 if (!d->device->isWritable() && !d->device->open(mode: QIODevice::WriteOnly)) {
230 qWarning(msg: "QTextDocumentWriter::write: the device can not be opened for writing");
231 return false;
232 }
233 QTextStream s(d->device);
234 QTextMarkdownWriter writer(s, QTextDocument::MarkdownDialectGitHub);
235 return writer.writeAll(document);
236 }
237#endif // textmarkdownwriter
238
239#ifndef QT_NO_TEXTHTMLPARSER
240 if (format == "html" || format == "htm") {
241 if (!d->device->isWritable() && ! d->device->open(mode: QIODevice::WriteOnly)) {
242 qWarning(msg: "QTextDocumentWriter::write: the device cannot be opened for writing");
243 return false;
244 }
245 d->device->write(data: document->toHtml().toUtf8());
246 d->device->close();
247 return true;
248 }
249#endif
250 if (format == "txt" || format == "plaintext") {
251 if (!d->device->isWritable() && ! d->device->open(mode: QIODevice::WriteOnly)) {
252 qWarning(msg: "QTextDocumentWriter::write: the device cannot be opened for writing");
253 return false;
254 }
255 d->device->write(data: document->toPlainText().toUtf8());
256 d->device->close();
257 return true;
258 }
259
260 return false;
261}
262
263/*!
264 Writes the document fragment specified by \a fragment to the assigned device
265 or file and returns \c true if successful; otherwise returns \c false.
266*/
267bool QTextDocumentWriter::write(const QTextDocumentFragment &fragment)
268{
269 if (fragment.d == nullptr)
270 return false; // invalid fragment.
271 QTextDocument *doc = fragment.d->doc;
272 if (doc)
273 return write(document: doc);
274 return false;
275}
276
277/*!
278 Returns the list of document formats supported by QTextDocumentWriter.
279
280 By default, Qt can write the following formats:
281
282 \table
283 \header \li Format \li Description
284 \row \li plaintext \li Plain text
285 \row \li HTML \li HyperText Markup Language
286 \row \li markdown \li Markdown (CommonMark or GitHub dialects)
287 \row \li ODF \li OpenDocument Format
288 \endtable
289
290 \sa setFormat()
291*/
292QList<QByteArray> QTextDocumentWriter::supportedDocumentFormats()
293{
294 QList<QByteArray> answer;
295 answer << "plaintext";
296
297#ifndef QT_NO_TEXTHTMLPARSER
298 answer << "HTML";
299#endif
300#ifndef QT_NO_TEXTODFWRITER
301 answer << "ODF";
302#endif // QT_NO_TEXTODFWRITER
303#if QT_CONFIG(textmarkdownwriter)
304 answer << "markdown";
305#endif
306
307 std::sort(first: answer.begin(), last: answer.end());
308 return answer;
309}
310
311QT_END_NAMESPACE
312

source code of qtbase/src/gui/text/qtextdocumentwriter.cpp