1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2015 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtVersit module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL21$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 or version 3 as published by the Free |
20 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and |
21 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the |
22 | ** following information to ensure the GNU Lesser General Public License |
23 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and |
24 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
25 | ** |
26 | ** As a special exception, The Qt Company gives you certain additional |
27 | ** rights. These rights are described in The Qt Company LGPL Exception |
28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
29 | ** |
30 | ** $QT_END_LICENSE$ |
31 | ** |
32 | ****************************************************************************/ |
33 | |
34 | #include "qversitwriter.h" |
35 | #include "qversitwriter_p.h" |
36 | |
37 | #include <QtCore/qbuffer.h> |
38 | #include <QtCore/qtextcodec.h> |
39 | |
40 | #include "qversitutils_p.h" |
41 | |
42 | QT_BEGIN_NAMESPACE_VERSIT |
43 | |
44 | /*! |
45 | \class QVersitWriter |
46 | \brief The QVersitWriter class writes Versit documents such as vCards to a device. |
47 | \ingroup versit |
48 | \inmodule QtVersit |
49 | |
50 | QVersitWriter converts a QVersitDocument into its textual representation. |
51 | QVersitWriter supports writing to an abstract I/O device |
52 | which can be for example a file or a memory buffer. |
53 | The writing can be done asynchronously and the waitForFinished() |
54 | function can be used to implement a blocking write. |
55 | |
56 | The serialization of the document is done in accordance with the type of the QVersitDocument |
57 | being written. The value of each QVersitProperty is encoded according to the type of object: |
58 | \list |
59 | \li \l{QString}{QStrings} are serialized verbatim, unless the default codec of the writer cannot |
60 | encode the string: in this case, UTF-8 is used to encode it (and the CHARSET parameter added to |
61 | the property, as per the vCard 2.1 specification). If the document type is vCard 2.1, |
62 | quoted-printable encoding may also be performed. |
63 | \li \l{QByteArray}{QByteArrays} are assumed to be binary data and are serialized as base-64 encoded |
64 | values. |
65 | \li \l{QVersitDocument}{QVersitDocuments} are serialized as a nested document (eg. as per the |
66 | AGENT property in vCard). |
67 | \endlist |
68 | |
69 | \sa QVersitDocument, QVersitProperty |
70 | */ |
71 | |
72 | |
73 | /*! |
74 | * \enum QVersitWriter::Error |
75 | * This enum specifies an error that occurred during the most recent operation: |
76 | * \value NoError The most recent operation was successful |
77 | * \value UnspecifiedError The most recent operation failed for an undocumented reason |
78 | * \value IOError The most recent operation failed because of a problem with the device |
79 | * \value OutOfMemoryError The most recent operation failed due to running out of memory |
80 | * \value NotReadyError The most recent operation failed because there is an operation in progress |
81 | */ |
82 | |
83 | /*! |
84 | * \enum QVersitWriter::State |
85 | * Enumerates the various states that a reader may be in at any given time |
86 | * \value InactiveState Write operation not yet started |
87 | * \value ActiveState Write operation started, not yet finished |
88 | * \value CanceledState Write operation is finished due to cancelation |
89 | * \value FinishedState Write operation successfully completed |
90 | */ |
91 | |
92 | /*! |
93 | * \fn QVersitWriter::stateChanged(QVersitWriter::State state) |
94 | * The signal is emitted by the writer when its state has changed (eg. when it has finished |
95 | * writing to the device). |
96 | * \a state is the new state of the writer. |
97 | */ |
98 | |
99 | /*! Constructs a new writer. */ |
100 | QVersitWriter::QVersitWriter() : d(new QVersitWriterPrivate) |
101 | { |
102 | d->init(writer: this); |
103 | } |
104 | |
105 | /*! Constructs a new writer that writes to \a outputDevice. */ |
106 | QVersitWriter::QVersitWriter(QIODevice *outputDevice) : d(new QVersitWriterPrivate) |
107 | { |
108 | d->init(writer: this); |
109 | d->mIoDevice = outputDevice; |
110 | } |
111 | |
112 | /*! Constructs a new writer that appends to \a outputBytes. */ |
113 | QVersitWriter::QVersitWriter(QByteArray *outputBytes) : d(new QVersitWriterPrivate) |
114 | { |
115 | d->init(writer: this); |
116 | d->mOutputBytes.reset(other: new QBuffer); |
117 | d->mOutputBytes->setBuffer(outputBytes); |
118 | d->mOutputBytes->open(openMode: QIODevice::WriteOnly); |
119 | d->mIoDevice = d->mOutputBytes.data(); |
120 | } |
121 | |
122 | /*! |
123 | * Frees the memory used by the writer. |
124 | * Waits until a pending asynchronous writing has been completed. |
125 | */ |
126 | QVersitWriter::~QVersitWriter() |
127 | { |
128 | d->wait(); |
129 | delete d; |
130 | } |
131 | |
132 | /*! |
133 | * Sets the device used for writing to \a device. |
134 | * Does not take ownership of the device. |
135 | */ |
136 | void QVersitWriter::setDevice(QIODevice* device) |
137 | { |
138 | d->mOutputBytes.reset(other: 0); |
139 | d->mIoDevice = device; |
140 | } |
141 | |
142 | /*! |
143 | * Returns the device used for writing, or 0 if no device has been set. |
144 | */ |
145 | QIODevice* QVersitWriter::device() const |
146 | { |
147 | if (d->mOutputBytes.isNull()) |
148 | return d->mIoDevice; |
149 | else |
150 | return 0; |
151 | } |
152 | |
153 | /*! |
154 | * Sets the default codec for the writer to use for writing the entire output. |
155 | * |
156 | * If \a codec is NULL, the writer uses the codec according to the specification prescribed default. |
157 | * (for vCard 2.1, ASCII; for vCard 3.0, UTF-8). |
158 | */ |
159 | void QVersitWriter::setDefaultCodec(QTextCodec *codec) |
160 | { |
161 | d->mDefaultCodec = codec; |
162 | } |
163 | |
164 | /*! |
165 | * Returns the document's codec. |
166 | */ |
167 | QTextCodec* QVersitWriter::defaultCodec() const |
168 | { |
169 | return d->mDefaultCodec; |
170 | } |
171 | |
172 | /*! |
173 | * Returns the state of the writer. |
174 | */ |
175 | QVersitWriter::State QVersitWriter::state() const |
176 | { |
177 | return d->state(); |
178 | } |
179 | |
180 | /*! |
181 | * Returns the error encountered by the last operation. |
182 | */ |
183 | QVersitWriter::Error QVersitWriter::error() const |
184 | { |
185 | return d->error(); |
186 | } |
187 | |
188 | /*! |
189 | * Starts writing \a input to device() asynchronously. The serialization format is determined based |
190 | * on the contents of the input documents. |
191 | * |
192 | * Returns false if the output device has not been set or opened or if there is another asynchronous |
193 | * write operation already pending. Signal \l stateChanged() is emitted with parameter |
194 | * FinishedState when the writing has finished. |
195 | * |
196 | * The device must be already open. The client is responsible for closing it when finished. |
197 | */ |
198 | bool QVersitWriter::startWriting(const QList<QVersitDocument>& input) |
199 | { |
200 | return startWriting(input, type: QVersitDocument::InvalidType); |
201 | } |
202 | |
203 | /*! |
204 | * Starts writing \a input to device() asynchronously using the serialization format specified by \a |
205 | * type. If \a type is QVersitDocument::InvalidType, the format will be determined based on the |
206 | * contents of the input documents. |
207 | * |
208 | * Returns false if the output device has not been set or opened or if there is another asynchronous |
209 | * write operation already pending. Signal \l stateChanged() is emitted with parameter |
210 | * FinishedState when the writing has finished. |
211 | * |
212 | * The device must be already open. The client is responsible for closing it when finished. |
213 | */ |
214 | bool QVersitWriter::startWriting(const QList<QVersitDocument>& input, QVersitDocument::VersitType type) |
215 | { |
216 | d->mInput = input; |
217 | if (d->state() == ActiveState || d->isRunning()) { |
218 | d->setError(QVersitWriter::NotReadyError); |
219 | return false; |
220 | } else if (!d->mIoDevice || !d->mIoDevice->isWritable()) { |
221 | d->setError(QVersitWriter::IOError); |
222 | return false; |
223 | } else { |
224 | d->setState(ActiveState); |
225 | d->setError(NoError); |
226 | d->setDocumentType(type); |
227 | d->start(); |
228 | return true; |
229 | } |
230 | } |
231 | |
232 | /*! |
233 | * Starts writing \a input to device() asynchronously. The serialization format is determined based |
234 | * on the contents of the input documents. |
235 | * |
236 | * Returns false if the output device has not been set or opened or if there is another asynchronous |
237 | * write operation already pending. Signal \l stateChanged() is emitted with parameter |
238 | * FinishedState when the writing has finished. |
239 | * |
240 | * The device must be already open. The client is responsible for closing it when finished. |
241 | */ |
242 | bool QVersitWriter::startWriting(const QVersitDocument& input) |
243 | { |
244 | return startWriting(input: QList<QVersitDocument>() << input, type: QVersitDocument::InvalidType); |
245 | } |
246 | |
247 | /*! |
248 | * Starts writing \a input to device() asynchronously using the serialization format specified by \a |
249 | * type. If \a type is QVersitDocument::InvalidType, the format will be determined based on the |
250 | * contents of the input documents. |
251 | * |
252 | * Returns false if the output device has not been set or opened or if there is another asynchronous |
253 | * write operation already pending. Signal \l stateChanged() is emitted with parameter |
254 | * FinishedState when the writing has finished. |
255 | * |
256 | * The device must be already open. The client is responsible for closing it when finished. |
257 | */ |
258 | bool QVersitWriter::startWriting(const QVersitDocument& input, QVersitDocument::VersitType type) |
259 | { |
260 | return startWriting(input: QList<QVersitDocument>() << input, type); |
261 | } |
262 | |
263 | /*! |
264 | * Attempts to asynchronously cancel the write request. |
265 | */ |
266 | void QVersitWriter::cancel() |
267 | { |
268 | d->setCanceling(true); |
269 | } |
270 | |
271 | /*! |
272 | * If the state is ActiveState, blocks until the writer has finished writing or \a msec milliseconds |
273 | * has elapsed, returning true if it successfully finishes or is cancelled by the user. |
274 | * If \a msec is negative or zero, the function blocks until the writer has finished, regardless of |
275 | * how long it takes. |
276 | * If the state is FinishedState, returns true immediately. |
277 | * Otherwise, returns false immediately. |
278 | */ |
279 | bool QVersitWriter::waitForFinished(int msec) |
280 | { |
281 | State state = d->state(); |
282 | if (state != InactiveState) { |
283 | if (msec <= 0) |
284 | return d->wait(ULONG_MAX); |
285 | else |
286 | return d->wait(time: msec); |
287 | } else { |
288 | return false; |
289 | } |
290 | } |
291 | |
292 | #include "moc_qversitwriter.cpp" |
293 | |
294 | QT_END_NAMESPACE_VERSIT |
295 | |