| 1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
| 2 | // |
| 3 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 4 | |
| 5 | #include "mavenasynparse.h" |
| 6 | #include "services/project/projectgenerator.h" |
| 7 | #include "services/option/optionmanager.h" |
| 8 | |
| 9 | #include "common/common.h" |
| 10 | |
| 11 | #include <QAction> |
| 12 | #include <QDebug> |
| 13 | #include <QtXml> |
| 14 | |
| 15 | static QString kSupportArgs[] = {"clean" , "compiler:compile" , "compiler:testCompile" , |
| 16 | "package" , "install" , "validate" , "dependency:tree" , |
| 17 | "dependency:analyze" , "site:site" , "compile" , "verify" }; |
| 18 | |
| 19 | class MavenAsynParsePrivate |
| 20 | { |
| 21 | friend class MavenAsynParse; |
| 22 | QDomDocument xmlDoc; |
| 23 | QThread *thread {nullptr}; |
| 24 | QString rootPath; |
| 25 | QList<QStandardItem *> rows {}; |
| 26 | }; |
| 27 | |
| 28 | MavenAsynParse::MavenAsynParse() |
| 29 | : d(new MavenAsynParsePrivate) |
| 30 | { |
| 31 | |
| 32 | QObject::connect(this, &QFileSystemWatcher::directoryChanged, |
| 33 | this, &MavenAsynParse::doDirectoryChanged); |
| 34 | |
| 35 | d->thread = new QThread(); |
| 36 | this->moveToThread(d->thread); |
| 37 | d->thread->start(); |
| 38 | } |
| 39 | |
| 40 | MavenAsynParse::~MavenAsynParse() |
| 41 | { |
| 42 | if (d) { |
| 43 | if (d->thread) { |
| 44 | if (d->thread->isRunning()) |
| 45 | d->thread->quit(); |
| 46 | d->thread->wait(); |
| 47 | d->thread->deleteLater(); |
| 48 | d->thread = nullptr; |
| 49 | } |
| 50 | delete d; |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | void MavenAsynParse::loadPoms(const dpfservice::ProjectInfo &info) |
| 55 | { |
| 56 | QFile docFile(info.workspaceFolder() + QDir::separator() + "pom.xml" ); |
| 57 | |
| 58 | if (!docFile.exists()) { |
| 59 | parsedError("Failed, maven pro not exists!: " + docFile.fileName()); |
| 60 | } |
| 61 | |
| 62 | if (!docFile.open(QFile::OpenModeFlag::ReadOnly)) {; |
| 63 | parsedError(docFile.errorString()); |
| 64 | } |
| 65 | |
| 66 | if (!d->xmlDoc.setContent(&docFile)) { |
| 67 | docFile.close(); |
| 68 | } |
| 69 | docFile.close(); |
| 70 | } |
| 71 | |
| 72 | void MavenAsynParse::parseProject(const dpfservice::ProjectInfo &info) |
| 73 | { |
| 74 | createRows(info.workspaceFolder()); |
| 75 | emit itemsModified(d->rows); |
| 76 | } |
| 77 | |
| 78 | // TODO(mozart):get from tool or config. |
| 79 | void MavenAsynParse::parseActions(const dpfservice::ProjectInfo &info) |
| 80 | { |
| 81 | using namespace dpfservice; |
| 82 | ProjectInfo proInfo = info; |
| 83 | if (proInfo.isEmpty()) { |
| 84 | return; |
| 85 | } |
| 86 | |
| 87 | ProjectActionInfos actionInfos; |
| 88 | auto addAction = [&](QString &arg){ |
| 89 | ProjectMenuActionInfo actionInfo; |
| 90 | actionInfo.buildProgram = OptionManager::getInstance()->getMavenToolPath(); |
| 91 | actionInfo.workingDirectory = info.workspaceFolder() + QDir::separator() + "pom.xml" ; |
| 92 | actionInfo.buildArguments.append(arg); |
| 93 | actionInfo.displyText = arg; |
| 94 | actionInfo.tooltip = arg; |
| 95 | actionInfos.append(actionInfo); |
| 96 | }; |
| 97 | |
| 98 | for (auto arg : kSupportArgs) { |
| 99 | addAction(arg); |
| 100 | } |
| 101 | |
| 102 | emit parsedActions(actionInfos); |
| 103 | } |
| 104 | |
| 105 | void MavenAsynParse::doDirectoryChanged(const QString &path) |
| 106 | { |
| 107 | if (!path.startsWith(d->rootPath)) |
| 108 | return; |
| 109 | |
| 110 | d->rows.clear(); |
| 111 | |
| 112 | createRows(d->rootPath); |
| 113 | |
| 114 | emit itemsModified(d->rows); |
| 115 | } |
| 116 | |
| 117 | void MavenAsynParse::createRows(const QString &path) |
| 118 | { |
| 119 | QString rootPath = path; |
| 120 | if (rootPath.endsWith(QDir::separator())) { |
| 121 | int separatorSize = QString(QDir::separator()).size(); |
| 122 | rootPath = rootPath.remove(rootPath.size() - separatorSize, separatorSize); |
| 123 | } |
| 124 | |
| 125 | // 缓存当前工程目录 |
| 126 | d->rootPath = rootPath; |
| 127 | QFileSystemWatcher::addPath(d->rootPath); |
| 128 | |
| 129 | {// 避免变量冲突 迭代文件夹 |
| 130 | QDir dir; |
| 131 | dir.setPath(rootPath); |
| 132 | dir.setFilter(QDir::NoDotAndDotDot | QDir::Dirs); |
| 133 | dir.setSorting(QDir::Name); |
| 134 | QDirIterator dirItera(dir, QDirIterator::Subdirectories); |
| 135 | while (dirItera.hasNext()) { |
| 136 | QString childPath = dirItera.next().remove(0, rootPath.size()); |
| 137 | QFileSystemWatcher::addPath(dirItera.filePath()); |
| 138 | QStandardItem *item = findItem(childPath); |
| 139 | QIcon icon = CustomIcons::icon(dirItera.fileInfo()); |
| 140 | auto newItem = new QStandardItem(icon, dirItera.fileName()); |
| 141 | newItem->setToolTip(dirItera.filePath()); |
| 142 | if (!item) { |
| 143 | d->rows.append(newItem); |
| 144 | } else { |
| 145 | item->appendRow(newItem); |
| 146 | } |
| 147 | } |
| 148 | } |
| 149 | {// 避免变量冲突 迭代文件 |
| 150 | QDir dir; |
| 151 | dir.setPath(rootPath); |
| 152 | dir.setFilter(QDir::NoDotAndDotDot | QDir::Files); |
| 153 | dir.setSorting(QDir::Name); |
| 154 | QDirIterator fileItera(dir, QDirIterator::Subdirectories); |
| 155 | while (fileItera.hasNext()) { |
| 156 | QString childPath = fileItera.next().remove(0, rootPath.size()); |
| 157 | QStandardItem *item = findItem(childPath); |
| 158 | QIcon icon = CustomIcons::icon(fileItera.fileInfo()); |
| 159 | auto newItem = new QStandardItem(icon, fileItera.fileName()); |
| 160 | newItem->setToolTip(fileItera.filePath()); |
| 161 | if (!item) { |
| 162 | d->rows.append(newItem); |
| 163 | } else { |
| 164 | item->appendRow(newItem); |
| 165 | } |
| 166 | } |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | QList<QStandardItem *> MavenAsynParse::rows(const QStandardItem *item) const |
| 171 | { |
| 172 | QList<QStandardItem *> result; |
| 173 | for (int i = 0; i < item->rowCount(); i++) { |
| 174 | result << item->child(i); |
| 175 | } |
| 176 | return result; |
| 177 | } |
| 178 | |
| 179 | QStandardItem *MavenAsynParse::findItem(const QString &path, |
| 180 | QStandardItem *parent) const |
| 181 | { |
| 182 | QString pathTemp = path; |
| 183 | if (pathTemp.endsWith(QDir::separator())) { |
| 184 | pathTemp = pathTemp.remove(pathTemp.size() - separatorSize(), separatorSize()); |
| 185 | } |
| 186 | |
| 187 | if (pathTemp.startsWith(QDir::separator())) |
| 188 | pathTemp.remove(0, separatorSize()); |
| 189 | |
| 190 | if (pathTemp.endsWith(QDir::separator())) |
| 191 | pathTemp.remove(pathTemp.size() - separatorSize(), separatorSize()); |
| 192 | |
| 193 | if (pathTemp.isEmpty()) |
| 194 | return parent; |
| 195 | |
| 196 | QStringList splitPaths = pathTemp.split(QDir::separator()); |
| 197 | QString name = splitPaths.takeFirst(); |
| 198 | |
| 199 | QList<QStandardItem*> currRows{}; |
| 200 | if (parent) { |
| 201 | currRows = rows(parent); |
| 202 | } else { |
| 203 | currRows = d->rows; |
| 204 | } |
| 205 | |
| 206 | for (int i = 0; i < currRows.size(); i++) { |
| 207 | QStandardItem *child = currRows[i]; |
| 208 | if (name == itemDisplayName(child)) { |
| 209 | if (splitPaths.isEmpty()) { |
| 210 | return child; |
| 211 | } else { |
| 212 | return findItem(splitPaths.join(QDir::separator()), child); |
| 213 | } |
| 214 | } |
| 215 | } |
| 216 | return parent; |
| 217 | } |
| 218 | |
| 219 | int MavenAsynParse::separatorSize() const |
| 220 | { |
| 221 | return QString(QDir::separator()).size(); |
| 222 | } |
| 223 | |
| 224 | QString MavenAsynParse::itemDisplayName(const QStandardItem *item) const |
| 225 | { |
| 226 | if (!item) |
| 227 | return "" ; |
| 228 | return item->data(Qt::DisplayRole).toString(); |
| 229 | } |
| 230 | |