1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "binarytoolsdialog.h"
6#include "binarytoolsconfigview.h"
7#include "common/util/eventdefinitions.h"
8
9#include <QPushButton>
10#include <QDialogButtonBox>
11#include <QProcess>
12#include <QBoxLayout>
13#include <QTextBlock>
14
15class BinaryToolsDialogPrivate
16{
17 friend class BinaryToolsDialog;
18 BinaryToolsConfigView *configView = nullptr;
19 QDialogButtonBox *buttons = nullptr;
20};
21
22BinaryToolsDialog::BinaryToolsDialog(QDialog *parent)
23 : QDialog(parent)
24 , d (new BinaryToolsDialogPrivate)
25{
26 setWindowTitle(tr("Binary Tools"));
27
28 QVBoxLayout *vLayout = new QVBoxLayout(this);
29 vLayout->setContentsMargins(20, 20, 20, 20);
30 vLayout->setSpacing(6);
31
32 d->configView = new BinaryToolsConfigView;
33 vLayout->addWidget(d->configView);
34 vLayout->addStretch();
35
36 QHBoxLayout * buttonLayout = new QHBoxLayout();
37 d->buttons = new QDialogButtonBox(this);
38 d->buttons->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Save | QDialogButtonBox::Cancel);
39 d->buttons->button(QDialogButtonBox::Apply)->setText(tr("Use Tool"));
40 d->buttons->button(QDialogButtonBox::Save)->setText(tr("Save"));
41 d->buttons->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
42 d->buttons->button(QDialogButtonBox::Apply)->setDefault(true);
43 buttonLayout->addWidget(d->buttons);
44 vLayout->addLayout(buttonLayout);
45
46 connect(d->configView, &BinaryToolsConfigView::useCombinationCommand, [=](){
47 QtConcurrent::run([=](){
48 useClicked();
49 });
50 });
51 connect(d->buttons->button(QDialogButtonBox::Apply), &QPushButton::clicked, [=](){
52 QtConcurrent::run([=](){
53 useClicked();
54 });
55 });
56 connect(d->buttons->button(QDialogButtonBox::Save), &QPushButton::clicked, this, &BinaryToolsDialog::saveClicked);
57 connect(d->buttons, &QDialogButtonBox::rejected, this, &BinaryToolsDialog::reject);
58 connect(d->buttons, &QDialogButtonBox::accepted, this, &BinaryToolsDialog::accept);
59}
60
61BinaryToolsDialog::~BinaryToolsDialog()
62{
63 if (d)
64 delete d;
65}
66
67void BinaryToolsDialog::printOutput(const QString &content, OutputPane::OutputFormat format)
68{
69 editor.switchContext(tr("&Application Output"));
70 auto outputPane = OutputPane::instance();
71 QString outputContent = content;
72 if (format == OutputPane::OutputFormat::NormalMessage) {
73 QTextDocument *doc = outputPane->document();
74 QTextBlock tb = doc->lastBlock();
75 QString lastLineText = tb.text();
76 QString prefix = "\n";
77 if (lastLineText.isEmpty()) {
78 prefix = "";
79 }
80 QDateTime curDatetime = QDateTime::currentDateTime();
81 QString time = curDatetime.toString("hh:mm:ss");
82 outputContent = prefix + time + ":" + content;
83 }
84 outputContent += "\n";
85 OutputPane::AppendMode mode = OutputPane::AppendMode::Normal;
86 outputPane->appendText(outputContent, format, mode);
87}
88
89void BinaryToolsDialog::saveClicked()
90{
91 d->configView->saveConfig();
92}
93
94void BinaryToolsDialog::useClicked()
95{
96 d->configView->saveConfig();
97
98 QProcess proc;
99 QString retMsg = tr("Error: execute command error! The reason is unknown.\n");;
100 connect(&proc, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
101 [&](int exitcode, QProcess::ExitStatus exitStatus) {
102 if (0 == exitcode && exitStatus == QProcess::ExitStatus::NormalExit) {
103 retMsg = tr("The process \"%1\" exited normally.\n").arg(proc.program());
104 } else if (exitStatus == QProcess::NormalExit) {
105 retMsg = tr("The process \"%1\" exited with code %2.\n")
106 .arg(proc.program(), QString::number(exitcode));
107 } else {
108 retMsg = tr("The process \"%1\" crashed.\n").arg(proc.program());
109 }
110 });
111
112 connect(&proc, &QProcess::readyReadStandardError, [&]() {
113 proc.setReadChannel(QProcess::StandardError);
114 while (proc.canReadLine()) {
115 QString line = QString::fromUtf8(proc.readLine());
116 qInfo() << line;
117 outputMsg(line, OutputPane::OutputFormat::StdErr);
118 }
119 });
120
121 connect(&proc, &QProcess::readyReadStandardOutput, [&]() {
122 proc.setReadChannel(QProcess::StandardOutput);
123 while (proc.canReadLine()) {
124 QString line = QString::fromUtf8(proc.readLine());
125 qInfo() << line;
126 outputMsg(line, OutputPane::OutputFormat::StdOut);
127 }
128 });
129
130 QList<QString> programList = d->configView->getProgramList();
131 QList<QStringList> argsList = d->configView->getArgumentsList();
132 QList<QString> workingDirList = d->configView->getWorkingDirList();
133 QList<QMap<QString, QVariant>> envList = d->configView->getEnvironmentList();
134
135 for (int i =0; i < programList.size(); i++) {
136 proc.setProgram(programList.at(i));
137 if (!argsList.at(i).at(0).isEmpty()) {
138 proc.setArguments(argsList.at(i));
139 } else {
140 proc.setArguments({});
141 }
142 proc.setWorkingDirectory(workingDirList.at(i));
143 QProcessEnvironment env;
144 auto iterator = envList.at(i).begin();
145 while (iterator != envList.at(i).end()) {
146 env.insert(iterator.key(), iterator.value().toString());
147 ++iterator;
148 }
149 proc.setProcessEnvironment(env);
150 QString startMsg = tr("Start execute command: \"%1\" \"%2\" in workspace \"%3\".\n")
151 .arg(programList.at(i), argsList.at(i).join(" "), workingDirList.at(i));
152 outputMsg(startMsg, OutputPane::OutputFormat::NormalMessage);
153 proc.start();
154 proc.waitForFinished(-1);
155
156 outputMsg(retMsg, OutputPane::OutputFormat::NormalMessage);
157 QString endMsg = tr("Execute command finished.\n");
158 outputMsg(endMsg, OutputPane::OutputFormat::NormalMessage);
159 }
160 QDialog::reject();
161}
162
163void BinaryToolsDialog::outputMsg(const QString &content, OutputPane::OutputFormat format)
164{
165 QMetaObject::invokeMethod(this, "printOutput", Q_ARG(QString, content), Q_ARG(OutputPane::OutputFormat, format));
166}
167