RabbitCommon v2.3.3
Loading...
Searching...
No Matches
DlgAbout.cpp
1/*++
2Copyright (c) Kang Lin studio, All Rights Reserved
3
4Author:
5 Kang Lin <kl222@126.com>
6
7Module Name:
8
9 DlgAbout.cpp
10
11Abstract:
12
13 This file contains about dialog implement.
14 */
15
16#include <QTextEdit>
17#include <QFile>
18#include <QDir>
19#include <QMenu>
20#include <QStandardPaths>
21#include <QSslError>
22#include <QDateTime>
23#include <QCursor>
24#include <QLoggingCategory>
25#include <QApplication>
26
27#include "DlgAbout.h"
28#include "ui_DlgAbout.h"
29#include "RabbitCommonDir.h"
30#include "RabbitCommonTools.h"
31#include "Download.h"
32#include "Information.h"
33
34#ifdef HAVE_CMARK
35 #include "cmark.h"
36#endif
37#ifdef HAVE_CMARK_GFM
38 #include "cmark-gfm.h"
39 #include "cmark-gfm-core-extensions.h"
40 #include "registry.h"
41 #include "parser.h"
42#endif
43
44static Q_LOGGING_CATEGORY(log, "RabbitCommon.DlgAbout")
45
46CDlgAbout::CDlgAbout(QWidget *parent) :
47 QDialog(parent),
48 ui(new Ui::CDlgAbout),
49 m_pLicense(nullptr),
50 m_pChangeLog(nullptr),
51 m_pThanks(nullptr)
52{
53#ifdef HAVE_CMARK_GFM
54 cmark_gfm_core_extensions_ensure_registered();
55 // free extensions at application exit (cmark-gfm is not able to register/unregister more than once)
56 std::atexit(cmark_release_plugins);
57#endif
58
59 ui->setupUi(this);
60
61 setAttribute(Qt::WA_QuitOnClose, true);
62
63 m_szAppName = qApp->applicationDisplayName();
64
65 m_szVersion = qApp->applicationVersion();
66#ifdef RabbitCommon_VERSION
67 if(m_szVersion.isEmpty())
68 {
69 qWarning(log) << "The m_szVersion is not set. Please use qApp->setApplicationVersion() or m_szVersion";
70 m_szVersion = RabbitCommon_VERSION;
71 }
72#endif
73
74 m_szArch = QSysInfo::buildCpuArchitecture();
75
76 m_szAuthor = tr("KangLin");
77 m_szEmail = "kl222@126.com";
78 m_szHomePage = "https://github.com/KangLin/" + qApp->applicationName();
79 m_szCopyrightOwner = tr("Kang Lin Studio");
80 m_szCopyrightStartTime = "2019";
81 m_AppIcon = QImage(":/icon/RabbitCommon/App");
82 m_CopyrightIcon = QImage(":/icon/RabbitCommon/CopyRight");
83
84 QString szLangUage = RabbitCommon::CTools::Instance()->GetLanguage();
85 QVector<QUrl> urls;
86 if("zh_CN" == szLangUage) {
87 m_DonationIcon = QImage(":/icon/RabbitCommon/Contribute_zh_CN");
88 urls << QUrl("https://github.com/KangLin/RabbitCommon/raw/master/Src/Resource/image/Contribute_zh_CN.png")
89 << QUrl("https://gitee.com/kl222/RabbitCommon/raw/master/Src/Resource/image/Contribute_zh_CN.png")
90 << QUrl("https://gitlab.com/kl222/RabbitCommon/-/raw/master/Src/Resource/image/Contribute_zh_CN.png");
91 } else {
92 m_DonationIcon = QImage(":/icon/RabbitCommon/Contribute_en");
93 urls << QUrl("https://github.com/KangLin/RabbitCommon/raw/master/Src/Resource/image/Contribute_en.png")
94 << QUrl("https://gitee.com/kl222/RabbitCommon/raw/master/Src/Resource/image/Contribute_en.png")
95 << QUrl("https://gitlab.com/kl222/RabbitCommon/-/raw/master/Src/Resource/image/Contribute_en.png");
96 }
97 m_Download = QSharedPointer<RabbitCommon::CDownload>(
98 new RabbitCommon::CDownload(), &QObject::deleteLater);
99 bool check = connect(m_Download.data(), SIGNAL(sigFinished(const QString)),
100 this, SLOT(slotDownloadFileFinished(const QString)));
101 Q_ASSERT(check);
102 check = connect(m_Download.data(), SIGNAL(sigError(int, const QString)),
103 this, SLOT(slotDownloadError(int, const QString)));
104 Q_ASSERT(check);
105 m_Download->Start(urls);
106
107 m_pLicense = new QTextEdit(ui->tabWidget);
108 if(m_pLicense)
109 qobject_cast<QTextEdit*>(m_pLicense)->setReadOnly(true);
110
111 m_pChangeLog = new QTextEdit(ui->tabWidget);
112 if(m_pChangeLog)
113 qobject_cast<QTextEdit*>(m_pChangeLog)->setReadOnly(false);
114
115 m_pThanks = new QTextEdit(ui->tabWidget);
116 if(m_pThanks)
117 qobject_cast<QTextEdit*>(m_pThanks)->setReadOnly(false);
118
119 AppendFile(m_pChangeLog, "ChangeLog", tr("Change log"));
120 AppendFile(m_pLicense, "License", tr("License"));
121 AppendFile(m_pThanks, "Authors", tr("Thanks"));
122
123#if defined (Q_OS_ANDROID)
124 ui->lbDonation->installEventFilter(this);
125#else
126 ui->lbDonation->setContextMenuPolicy(Qt::CustomContextMenu);
127 check = connect(ui->lbDonation, SIGNAL(customContextMenuRequested(const QPoint &)),
128 this, SLOT(slotDonation(const QPoint &)));
129 Q_ASSERT(check);
130#endif
131
132}
133
134void CDlgAbout::showEvent(QShowEvent *event)
135{
136 Q_UNUSED(event)
137
138 setWindowIcon(QIcon(QPixmap::fromImage(m_AppIcon)));
139 ui->lblLogo->setPixmap(QPixmap::fromImage(m_AppIcon));
140 ui->lbCopyrightIcon->setPixmap(QPixmap::fromImage(m_CopyrightIcon));
141 ui->lbDonation->setPixmap(QPixmap::fromImage(m_DonationIcon));
142 ui->lblName->setText(m_szAppName);
143 ui->lbVersion->setText(Version());
144 ui->lbVersion->setOpenExternalLinks(true);
145 ui->lbAuthor->setText(tr("Author: ") + m_szAuthor
146 + tr(" Email: ") + "<a href=\"" + m_szEmail + "\">"
147 + m_szEmail + "</a>");
148 ui->lbAuthor->setOpenExternalLinks(true);
149 ui->lbHome->setOpenExternalLinks(true);
150 ui->lbHome->setText(tr("Home page: ") + "<a href=\"" + m_szHomePage + "\">"
151 + m_szHomePage + "</a>");
152 if(m_szCopyright.isEmpty())
153 {
154 if(m_szCopyrightTime.isEmpty())
155 m_szCopyrightTime = tr("%1 - %2").arg(m_szCopyrightStartTime,
156 QString::number(QDate::currentDate().year()));
157 m_szCopyright = tr("Copyright (C)") + " " + m_szCopyrightTime + " " + m_szCopyrightOwner;
158 }
159 ui->lbCopyright->setText(m_szCopyright);
160
161 adjustSize();
162}
163
164CDlgAbout::~CDlgAbout()
165{
166 delete ui;
167}
168
169int CDlgAbout::AppendFile(QWidget* pWidget, const QString &szFile, const QString &szTitle)
170{
171 QDir d;
172 QString szFileLocation;
173
174 szFileLocation = RabbitCommon::CDir::Instance()->GetDirDocument(
175 QApplication::applicationName(), true)
176 + QDir::separator()
177 + szFile + "_" + RabbitCommon::CTools::Instance()->GetLanguage() + ".md";
178 if(!d.exists(szFileLocation))
179 szFileLocation = RabbitCommon::CDir::Instance()->GetDirDocument(
180 QApplication::applicationName(), true)
181 + QDir::separator()
182 + szFile + ".md";
183 //TODO: be will remove in 3.0
184 if(!d.exists(szFileLocation))
185 szFileLocation = RabbitCommon::CDir::Instance()->GetDirApplicationInstallRoot() + QDir::separator()
186 + szFile + "_" + RabbitCommon::CTools::Instance()->GetLanguage() + ".md";
187 if(!d.exists(szFileLocation))
188 szFileLocation = RabbitCommon::CDir::Instance()->GetDirApplicationInstallRoot()
189 + QDir::separator() + szFile + ".md";
190
191 QFile readme(szFileLocation);
192 if(readme.open(QFile::ReadOnly))
193 {
194 QByteArray text;
195 QString szHtml;
196 text = readme.readAll();
197 szHtml = MarkDownToHtml(text);
198 if(szHtml.isEmpty())
199 szHtml = text;
200
201 QTextEdit* pEdit = qobject_cast<QTextEdit*>(pWidget);
202 if(pEdit) {
203 pEdit->setHtml(szHtml);
204 //把光标移动文档开始处
205 QTextCursor cursor = pEdit->textCursor();
206 cursor.movePosition(QTextCursor::Start);
207 pEdit->setTextCursor(cursor);
208 }
209
210 readme.close();
211 if(pWidget)
212 ui->tabWidget->addTab(pWidget, szTitle);
213 }
214 return 0;
215}
216
217QString CDlgAbout::MarkDownToHtml(const QString &szText)
218{
219 QString szRetureText = szText;
220
221#ifdef HAVE_CMARK_GFM
222
223 // TODO make this method which takes input and provides output: cmark_to_html()
224 cmark_mem* mem = cmark_get_default_mem_allocator();
225 // TODO control which extensions to use in MindForger config
226 cmark_llist* syntax_extensions = cmark_list_syntax_extensions(mem);
227 // TODO parse options
228 cmark_parser* parser = cmark_parser_new(CMARK_OPT_DEFAULT | CMARK_OPT_UNSAFE);
229 for (cmark_llist* tmp = syntax_extensions; tmp; tmp = tmp->next) {
230 cmark_parser_attach_syntax_extension(parser, (cmark_syntax_extension*)tmp->data);
231 }
232 cmark_parser_feed(parser, szText.toStdString().c_str(), szText.toStdString().length());
233
234 //cmark_node* doc = cmark_parse_document (markdown->c_str(), markdown->size(), CMARK_OPT_DEFAULT | CMARK_OPT_UNSAFE);
235 cmark_node* doc = cmark_parser_finish(parser);
236 if(doc) {
237 char *rendered_html = cmark_render_html_with_mem(doc, CMARK_OPT_DEFAULT | CMARK_OPT_UNSAFE, parser->syntax_extensions, mem);
238 if (rendered_html) {
239 szRetureText = rendered_html;
240 free(rendered_html);
241 }
242 cmark_node_free(doc);
243 }
244 cmark_llist_free(mem, syntax_extensions);
245 cmark_parser_free(parser);
246
247#elif HAVE_CMARK
248
249 char* pHtml = cmark_markdown_to_html(szText.toStdString().c_str(),
250 szText.toStdString().length(),
251 0);
252 if(pHtml)
253 {
254 szRetureText = pHtml;
255 free(pHtml);
256 } else {
257 qCritical(log) << "cmark_markdown_to_html fail";
258 }
259
260#endif
261 return szRetureText;
262}
263
264void CDlgAbout::on_pbOK_clicked()
265{
266 close();
267}
268
269void CDlgAbout::slotDonation(const QPoint &pos)
270{
271 Q_UNUSED(pos)
272 QMenu m;
273 m.addAction(QIcon::fromTheme("document-save"), tr("Save"),
274 this, SLOT(slotSaveDonation()));
275 m.exec(QCursor::pos());
276}
277
278void CDlgAbout::slotSaveDonation()
279{
280 QString szDir = RabbitCommon::CDir::Instance()->GetDirUserImage()
281 + QDir::separator() + "donation.png";
282 QString szFile = QFileDialog::getSaveFileName(this,
283 tr("Save donation picture"),
284 szDir,
285 tr("Images (*.png *.xpm *.jpg)"));
286 QFileInfo fi(szFile);
287 if(fi.suffix().isEmpty())
288 szFile += ".png";
289 if(!szFile.isEmpty())
290 m_DonationIcon.save(szFile);
291}
292
293#if defined (Q_OS_ANDROID)
294bool CDlgAbout::eventFilter(QObject *watched, QEvent *event)
295{
296 qDebug() << event->type();
297 if(event->type() == QEvent::MouseButtonRelease)
298 slotSaveDonation();
299 return QDialog::eventFilter(watched, event);
300}
301#endif
302
303int CDlgAbout::SetDonationIcon(const QImage &img)
304{
305 m_Download.clear();
306 m_DonationIcon = img;
307 return 0;
308}
309
310QString CDlgAbout::BuildTime()
311{
312 if(m_szBuildTime.isEmpty())
313 return QString("%1/%2").arg(__DATE__, __TIME__);
314 return m_szBuildTime;
315}
316
317QString CDlgAbout::Version()
318{
319 QString szVersion;
320 if(m_szVersionRevision.isEmpty())
321 {
322 szVersion = tr("Version: ") + m_szVersion + " " + tr("Arch: ") + m_szArch;
323 } else {
324 if(m_szVersionRevisionUrl.isEmpty())
325 {
326 m_szVersionRevisionUrl =
327 m_szHomePage + "/tree/" + m_szVersionRevision;
328 }
329 szVersion = tr("Version: ") + m_szVersion + tr(" (From revision: ")
330#if (defined(HAVE_CMARK) || defined(HAVE_CMARK_GFM))
331 + "<a href=\"" + m_szVersionRevisionUrl + "\">"
332 + m_szVersionRevision + "</a>"
333#else
334 + m_szVersionRevision
335#endif
336 + ") " + tr("Arch: ") + m_szArch;
337 }
338 return szVersion;
339}
340
341void CDlgAbout::slotDownloadError(int nErr, const QString szError)
342{
343 QString szMsg;
344 szMsg = tr("Failed:") + tr("Download file is Failed.");
345 if(!szError.isEmpty())
346 szMsg += "(" + szError + ")";
347 qCritical(log) << szMsg << nErr;
348}
349
350void CDlgAbout::slotDownloadFileFinished(const QString szFile)
351{
352 qDebug(log) << "slotDownloadFileFinished:" << szFile;
353 m_DonationIcon.load(szFile);
354 ui->lbDonation->setPixmap(QPixmap::fromImage(m_DonationIcon));
355}
356
357void CDlgAbout::on_pbDetails_clicked()
358{
359 QString szApp;
360
361 szApp = tr("### ") + QApplication::applicationDisplayName() + "\n";
362 szApp += "- " + Version() + "\n";
363 szApp += "- " + tr("Build Date/Time: ") + BuildTime() + "\n";
364 szApp += "- " + tr("File Path: ") + QApplication::applicationFilePath() + "\n";
365 szApp += "- " + tr("Arguments: ") + qApp->arguments().join(' ') + "\n";
366
367 QCursor cursor = this->cursor();
368 setCursor(Qt::WaitCursor);
369 CInformation info(szApp, m_szDetails, this);
370#if defined (Q_OS_ANDROID)
371 info.showMaximized();
372#endif
373 RC_SHOW_WINDOW(&info);
374 setCursor(cursor);
375}
About dialog.
Definition DlgAbout.h:72
QString m_szVersion
The application version, it is different RabbitCommon::CTools::Version()
Definition DlgAbout.h:83
QString GetDirDocument(QString szProjectName=QString(), bool bReadOnly=false)
GetDirDocument.
Download the same file from multiple URLs.
Definition Download.h:48