1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "annotation.h"
27 
28 #include <QDateTime>
29 #include <QJsonArray>
30 #include <QString>
31 
32 namespace QmlDesigner {
33 
34 static const QString s_sep = " //;;// "; //separator
35 
Comment()36 Comment::Comment()
37     : m_title(QString())
38     , m_author(QString())
39     , m_text(QString())
40     , m_timestamp(0)
41 {}
42 
Comment(const QString & title,const QString & author,const QString & text,qint64 timestamp)43 Comment::Comment(const QString &title, const QString &author, const QString &text, qint64 timestamp)
44     : m_title(title)
45     , m_author(author)
46     , m_text(text)
47     , m_timestamp(timestamp)
48 {}
49 
title() const50 QString Comment::title() const
51 {
52     return m_title;
53 }
54 
setTitle(const QString & title)55 void Comment::setTitle(const QString &title)
56 {
57     m_title = title;
58 }
59 
author() const60 QString Comment::author() const
61 {
62     return m_author;
63 }
64 
setAuthor(const QString & author)65 void Comment::setAuthor(const QString &author)
66 {
67     m_author = author;
68 }
69 
text() const70 QString Comment::text() const
71 {
72     return m_text;
73 }
74 
setText(const QString & text)75 void Comment::setText(const QString &text)
76 {
77     m_text = text;
78 }
79 
deescapedText() const80 QString Comment::deescapedText() const
81 {
82     QString result = m_text;
83 
84     result.replace(QStringLiteral("*\\/"), QStringLiteral("*/"));
85     result.replace(QStringLiteral("\\n"), QStringLiteral("\n"));
86     result.replace(QStringLiteral("\\r"), QStringLiteral("\r"));
87     result.replace(QStringLiteral("\\t"), QStringLiteral("\t"));
88     result.replace(QStringLiteral("\\\""), QStringLiteral("\""));
89     result.replace(QStringLiteral("\\\'"), QStringLiteral("\'"));
90     result.replace(QStringLiteral("\\\\"), QStringLiteral("\\"));
91 
92     return result;
93 }
94 
timestampStr() const95 QString Comment::timestampStr() const
96 {
97     return QDateTime::fromSecsSinceEpoch(m_timestamp).toString();
98 }
99 
timestampStr(const QString & format) const100 QString Comment::timestampStr(const QString &format) const
101 {
102     return QDateTime::fromSecsSinceEpoch(m_timestamp).toString(format);
103 }
104 
timestamp() const105 qint64 Comment::timestamp() const
106 {
107     return m_timestamp;
108 }
109 
setTimestamp(qint64 timestamp)110 void Comment::setTimestamp(qint64 timestamp)
111 {
112     m_timestamp = timestamp;
113 }
114 
updateTimestamp()115 void Comment::updateTimestamp()
116 {
117     m_timestamp = QDateTime::currentSecsSinceEpoch();
118 }
119 
sameContent(const Comment & comment) const120 bool Comment::sameContent(const Comment &comment) const
121 {
122     return sameContent(*this, comment);
123 }
124 
sameContent(const Comment & a,const Comment & b)125 bool Comment::sameContent(const Comment &a, const Comment &b)
126 {
127     return ((a.title() == b.title())
128             && (a.author() == b.author())
129             && (a.text() == b.text()));
130 }
131 
operator ==(const Comment & comment) const132 bool Comment::operator==(const Comment &comment) const
133 {
134     return (sameContent(comment) && (m_timestamp == comment.timestamp()));
135 }
136 
isEmpty() const137 bool Comment::isEmpty() const
138 {
139     return sameContent(Comment());
140 }
141 
toQString() const142 QString Comment::toQString() const
143 {
144     QStringList result;
145 
146     result.push_back(m_title);
147     result.push_back(m_author);
148     result.push_back(m_text);
149     result.push_back(QString::number(m_timestamp));
150 
151     return result.join(s_sep);
152 }
153 
toJsonValue() const154 QJsonValue Comment::toJsonValue() const
155 {
156     return QJsonObject{
157         {{"title", m_title}, {"author", m_author}, {"text", m_text}, {"timestamp", m_timestamp}}};
158 };
159 
fromJsonValue(QJsonValue const & v)160 bool Comment::fromJsonValue(QJsonValue const &v)
161 {
162     if (!v.isObject())
163         return false;
164 
165     auto obj = v.toObject();
166     Comment comment;
167     comment.m_title = obj["title"].toString();
168     comment.m_author = obj["author"].toString();
169     comment.m_text = obj["text"].toString();
170     comment.m_timestamp = obj["timestamp"].toInt();
171     *this = comment;
172     return true;
173 }
174 
operator <<(QDebug & stream,const Comment & comment)175 QDebug &operator<<(QDebug &stream, const Comment &comment)
176 {
177     stream << "\"title: " << comment.m_title << "\" ";
178     stream << "\"author: " << comment.m_author << "\" ";
179     stream << "\"text: " << comment.m_text << "\" ";
180     stream << "\"timestamp: " << comment.m_timestamp << "\" ";
181     stream << "\"date/time: " << QDateTime::fromSecsSinceEpoch(comment.m_timestamp).toString() << "\" ";
182 
183     return stream;
184 }
185 
operator <<(QDataStream & stream,const Comment & comment)186 QDataStream &operator<<(QDataStream &stream, const Comment &comment)
187 {
188     stream << comment.m_title;
189     stream << comment.m_author;
190     stream << comment.m_text;
191     stream << comment.m_timestamp;
192 
193     return stream;
194 }
195 
operator >>(QDataStream & stream,Comment & comment)196 QDataStream &operator>>(QDataStream &stream, Comment &comment)
197 {
198     stream >> comment.m_title;
199     stream >> comment.m_author;
200     stream >> comment.m_text;
201     stream >> comment.m_timestamp;
202 
203     return stream;
204 }
205 
206 
207 //Annotation
208 
Annotation()209 Annotation::Annotation()
210     : m_comments()
211 {
212 
213 }
214 
comments() const215 QVector<Comment> Annotation::comments() const
216 {
217     return m_comments;
218 }
219 
220 
hasComments() const221 bool Annotation::hasComments() const
222 {
223     return !m_comments.isEmpty();
224 }
225 
setComments(const QVector<Comment> & comments)226 void Annotation::setComments(const QVector<Comment> &comments)
227 {
228     m_comments = comments;
229 }
230 
removeComments()231 void Annotation::removeComments()
232 {
233     m_comments.clear();
234 }
235 
commentsSize() const236 int Annotation::commentsSize() const
237 {
238     return m_comments.size();
239 }
240 
comment(int n) const241 Comment Annotation::comment(int n) const
242 {
243     if (m_comments.size() > n)
244         return m_comments.at(n);
245     else
246         return Comment();
247 }
248 
addComment(const Comment & comment)249 void Annotation::addComment(const Comment &comment)
250 {
251     m_comments.push_back(comment);
252 }
253 
updateComment(const Comment & comment,int n)254 bool Annotation::updateComment(const Comment &comment, int n)
255 {
256     bool result = false;
257 
258     if ((m_comments.size() > n) && (n > 0)) {
259         m_comments[n] = comment;
260         result = true;
261     }
262 
263     return result;
264 }
265 
removeComment(int n)266 bool Annotation::removeComment(int n)
267 {
268     bool result = false;
269 
270     if (m_comments.size() > n) {
271         m_comments.remove(n);
272         result = true;
273     }
274 
275     return result;
276 }
277 
toQString() const278 QString Annotation::toQString() const
279 {
280     QStringList result;
281 
282     result.push_back(QString::number(m_comments.size()));
283 
284     for (const Comment &com : m_comments)
285         result.push_back(com.toQString());
286 
287     return result.join(s_sep);
288 }
289 
fromQString(const QString & str)290 void Annotation::fromQString(const QString &str)
291 {
292     QStringList strl (str.split(s_sep, Qt::KeepEmptyParts));
293     removeComments();
294 
295     const int intro = 1;
296     const int comSize = 4;
297 
298     if (!strl.isEmpty()) {
299 
300         if (strl.size() >= intro) {
301 
302             int size = strl.at(0).toInt();
303 
304             if (size > 0) {
305                 if (strl.size() == (size*comSize) + intro)
306                 {
307                     for (int i = 0; i < size; i++)
308                     {
309                         const int offset = intro + (i * comSize);
310                         Comment com;
311                         com.setTitle(strl.at(offset + 0));
312                         com.setAuthor(strl.at(offset + 1));
313                         com.setText(strl.at(offset + 2));
314                         com.setTimestamp(strl.at(offset + 3).toLongLong());
315 
316                         m_comments.push_back(com);
317                     }
318                 }
319             }
320         }
321     }
322 }
323 
toJsonValue() const324 QJsonValue Annotation::toJsonValue() const
325 {
326     QJsonObject obj;
327     QJsonArray comments;
328     for (auto &comment : m_comments)
329         comments.push_back(comment.toJsonValue());
330 
331     obj["comments"] = comments;
332     return obj;
333 }
334 
fromJsonValue(const QJsonValue & v)335 bool Annotation::fromJsonValue(const QJsonValue &v)
336 {
337     if (!v.isObject())
338         return false;
339 
340     auto obj = v.toObject();
341     auto jsonComments = obj["comments"].toArray();
342     m_comments.clear();
343     for (auto json : jsonComments) {
344         Comment comment;
345         if (comment.fromJsonValue(json))
346             m_comments.push_back(comment);
347     }
348     return true;
349 }
350 
operator <<(QDebug & stream,const Annotation & annotation)351 QDebug &operator<<(QDebug &stream, const Annotation &annotation)
352 {
353     stream << "\"Annotation: " << annotation.m_comments << "\" ";
354 
355     return stream;
356 }
357 
operator <<(QDataStream & stream,const Annotation & annotation)358 QDataStream &operator<<(QDataStream &stream, const Annotation &annotation)
359 {
360     stream << annotation.m_comments;
361 
362     return stream;
363 }
364 
operator >>(QDataStream & stream,Annotation & annotation)365 QDataStream &operator>>(QDataStream &stream, Annotation &annotation)
366 {
367     stream >> annotation.m_comments;
368 
369     return stream;
370 }
371 
GlobalAnnotationStatus()372 GlobalAnnotationStatus::GlobalAnnotationStatus()
373     : m_status(GlobalAnnotationStatus::Status::NoStatus)
374 { }
375 
GlobalAnnotationStatus(GlobalAnnotationStatus::Status status)376 GlobalAnnotationStatus::GlobalAnnotationStatus(GlobalAnnotationStatus::Status status)
377     : m_status(status)
378 { }
379 
setStatus(int statusId)380 void GlobalAnnotationStatus::setStatus(int statusId)
381 {
382     switch (statusId) {
383     case 0: m_status = GlobalAnnotationStatus::Status::InProgress; break;
384     case 1: m_status = GlobalAnnotationStatus::Status::InReview; break;
385     case 2: m_status = GlobalAnnotationStatus::Status::Done; break;
386     case -1:
387     default: m_status = GlobalAnnotationStatus::Status::NoStatus; break;
388     }
389 }
390 
setStatus(GlobalAnnotationStatus::Status status)391 void GlobalAnnotationStatus::setStatus(GlobalAnnotationStatus::Status status)
392 {
393     m_status = status;
394 }
395 
status() const396 GlobalAnnotationStatus::Status GlobalAnnotationStatus::status() const
397 {
398     return m_status;
399 }
400 
toQString() const401 QString GlobalAnnotationStatus::toQString() const
402 {
403     return QString::number(static_cast<int>(m_status));
404 }
405 
fromQString(const QString & str)406 void GlobalAnnotationStatus::fromQString(const QString &str)
407 {
408     bool result = false;
409     int conversion = str.toInt(&result);
410 
411     if (result) {
412         setStatus(conversion);
413     }
414     else {
415         m_status = GlobalAnnotationStatus::Status::NoStatus;
416     }
417 }
418 
419 } // QmlDesigner namespace
420