1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "findtoolwindow.h"
6#include "searchresultwindow.h"
7#include "transceiver/findreceiver.h"
8
9#include <QVBoxLayout>
10#include <QHBoxLayout>
11#include <QLineEdit>
12#include <QLabel>
13#include <QComboBox>
14#include <QCheckBox>
15#include <QPushButton>
16#include <QDebug>
17#include <QStackedWidget>
18#include <QProcess>
19#include <QMessageBox>
20#include <QScrollArea>
21
22#define LABEL_WIDTH (150)
23
24class FindToolWindowPrivate
25{
26 FindToolWindowPrivate(){}
27 QStackedWidget *stackedWidget{nullptr};
28 SearchResultWindow *searchResultWindow{nullptr};
29 QSet<QString> allProjectsPathList{nullptr};
30 QString currentProjectPath;
31 QString currentFilePath;
32 QMap<QString, QString> projectInfoMap;
33
34 QComboBox *scopeComboBox{nullptr};
35 QLineEdit *searchLineEdit{nullptr};
36 QCheckBox *senseCheckBox{nullptr};
37 QCheckBox *wholeWordsCheckBox{nullptr};
38 QCheckBox *regularCheckBox{nullptr};
39 QLineEdit *patternLineEdit{nullptr};
40 QLineEdit *expatternLineEdit{nullptr};
41
42 friend class FindToolWindow;
43};
44
45FindToolWindow::FindToolWindow(QWidget *parent)
46 : QWidget(parent)
47 , d(new FindToolWindowPrivate())
48{
49 setupUi();
50
51 connect(FindEventTransmit::instance(), QOverload<const QString &, const QString &>::of(&FindEventTransmit::sendProjectPath),
52 [=](const QString &projectPath, const QString &language){
53 d->currentProjectPath = projectPath;
54 d->projectInfoMap.insert(projectPath, language);
55 d->allProjectsPathList.insert(projectPath);
56 });
57
58 connect(FindEventTransmit::instance(), QOverload<const QString &>::of(&FindEventTransmit::sendRemovedProject),
59 [=](const QString &projectPath){
60 d->currentProjectPath = "";
61 d->allProjectsPathList.remove(projectPath);
62 d->projectInfoMap.remove(projectPath);
63 });
64
65 connect(FindEventTransmit::instance(), QOverload<const QString &, bool>::of(&FindEventTransmit::sendCurrentEditFile),
66 [=](const QString &filePath, bool actived){
67 if (actived) {
68 d->currentFilePath = filePath;
69 }
70 else
71 d->currentFilePath = "";
72 });
73}
74
75void FindToolWindow::setupUi()
76{
77 d->stackedWidget = new QStackedWidget();
78 QVBoxLayout *vLayout = new QVBoxLayout();
79
80 QScrollArea *scrollArea = new QScrollArea();
81 scrollArea->setWidgetResizable(true);
82 scrollArea->setWidget(d->stackedWidget);
83 vLayout->addWidget(scrollArea);
84
85 QWidget *searchParamWidget = new QWidget();
86 QWidget *searchResultWidget = new QWidget();
87
88 addSearchParamWidget(searchParamWidget);
89 addSearchResultWidget(searchResultWidget);
90
91 d->stackedWidget->addWidget(searchParamWidget);
92 d->stackedWidget->addWidget(searchResultWidget);
93
94 d->stackedWidget->setCurrentIndex(0);
95
96 setLayout(vLayout);
97}
98
99void FindToolWindow::addSearchParamWidget(QWidget *parentWidget)
100{
101 QHBoxLayout *hLayout = new QHBoxLayout();
102 parentWidget->setLayout(hLayout);
103
104 QWidget *widget = new QWidget();
105 widget->setFixedSize(725, 300);
106 hLayout->addWidget(widget, 0, Qt::AlignLeft);
107
108 QVBoxLayout *vLayout = new QVBoxLayout();
109 widget->setLayout(vLayout);
110
111 QHBoxLayout *scopeLayout = new QHBoxLayout();
112 QLabel *scopeLabel = new QLabel(QLabel::tr("Scope:"));
113 scopeLabel->setAlignment(Qt::AlignRight);
114 scopeLabel->setFixedWidth(LABEL_WIDTH);
115 d->scopeComboBox = new QComboBox();
116 d->scopeComboBox->addItem(tr("All Projects"));
117 d->scopeComboBox->addItem(tr("Current Project"));
118 d->scopeComboBox->addItem(tr("Current File"));
119 scopeLayout->addWidget(scopeLabel);
120 scopeLayout->addWidget(d->scopeComboBox);
121
122 QHBoxLayout *searchLayout = new QHBoxLayout();
123 QLabel *searchLabel = new QLabel(QLabel::tr("Search for:"));
124 searchLabel->setAlignment(Qt::AlignRight);
125 searchLabel->setFixedWidth(LABEL_WIDTH);
126 d->searchLineEdit = new QLineEdit();
127 searchLayout->addWidget(searchLabel);
128 searchLayout->addWidget(d->searchLineEdit);
129
130 QHBoxLayout *ruleLayout = new QHBoxLayout();
131 d->senseCheckBox = new QCheckBox(QCheckBox::tr("Case sensitive"));
132 d->wholeWordsCheckBox = new QCheckBox(QCheckBox::tr("Whole words only"));
133 d->regularCheckBox = new QCheckBox(QCheckBox::tr("Use regular expressions"));
134 ruleLayout->addStretch();
135 ruleLayout->addWidget(d->senseCheckBox);
136 ruleLayout->addWidget(d->wholeWordsCheckBox);
137 ruleLayout->addWidget(d->regularCheckBox);
138 d->regularCheckBox->setVisible(false);
139
140 QHBoxLayout *patternLayout = new QHBoxLayout();
141 QLabel *patternLabel = new QLabel(QLabel::tr("File pattern:"));
142 patternLabel->setAlignment(Qt::AlignRight);
143 patternLabel->setFixedWidth(LABEL_WIDTH);
144 d->patternLineEdit = new QLineEdit();
145 patternLayout->addWidget(patternLabel);
146 patternLayout->addWidget(d->patternLineEdit);
147
148 QHBoxLayout *expatternLayout = new QHBoxLayout();
149 QLabel *expatternLabel = new QLabel(QLabel::tr("Exclusion pattern:"));
150 expatternLabel->setAlignment(Qt::AlignRight);
151 expatternLabel->setFixedWidth(LABEL_WIDTH);
152 d->expatternLineEdit = new QLineEdit();
153 expatternLayout->addWidget(expatternLabel);
154 expatternLayout->addWidget(d->expatternLineEdit);
155
156 QPushButton *searchBtn = new QPushButton(QPushButton::tr("Search"));
157 QPushButton *replaceBtn = new QPushButton(QPushButton::tr("Search && Replace"));
158 QHBoxLayout *btnLayout = new QHBoxLayout();
159 btnLayout->addStretch();
160 btnLayout->addWidget(searchBtn);
161 btnLayout->addWidget(replaceBtn);
162
163 connect(searchBtn, &QAbstractButton::clicked, this, &FindToolWindow::search);
164 connect(replaceBtn, &QAbstractButton::clicked, this, &FindToolWindow::replace);
165
166 vLayout->addLayout(scopeLayout);
167 vLayout->addLayout(searchLayout);
168 vLayout->addLayout(ruleLayout);
169 vLayout->addLayout(patternLayout);
170 vLayout->addLayout(expatternLayout);
171 vLayout->addLayout(btnLayout);
172}
173
174void FindToolWindow::addSearchResultWidget(QWidget *parentWidget)
175{
176 QVBoxLayout *vLayout = new QVBoxLayout();
177 parentWidget->setLayout(vLayout);
178
179 d->searchResultWindow = new SearchResultWindow();
180 connect(d->searchResultWindow, &SearchResultWindow::back, this, &FindToolWindow::switchSearchParamWidget);
181 vLayout->addWidget(d->searchResultWindow);
182}
183
184void FindToolWindow::search()
185{
186 searchText();
187 d->searchResultWindow->setRepalceWidgtVisible(false);
188}
189
190bool FindToolWindow::checkSelectedScopeValid()
191{
192 int index = d->scopeComboBox->currentIndex();
193 switch (index) {
194 case 0:
195 {
196 if (d->allProjectsPathList.isEmpty()) {
197 QMessageBox::warning(this, tr("Error"), tr("All projects path is empty, please import!"));
198 return false;
199 }
200 break;
201 }
202 case 1:
203 {
204 if (d->currentProjectPath.isEmpty()) {
205 QMessageBox::warning(this, tr("Error"), tr("Current project path is empty, please import!"));
206 return false;
207 }
208 break;
209 }
210 case 2:
211 {
212 if (d->currentFilePath.isEmpty()) {
213 QMessageBox::warning(this, tr("Error"), tr("Current file path is empty, please import!"));
214 return false;
215 }
216 break;
217 }
218 default:
219 {
220 QMessageBox::warning(this, tr("Error"), tr("Scope is not selected, please select!"));
221 return false;
222 }
223 }
224
225 return true;
226}
227
228bool FindToolWindow::getSearchParams(SearchParams *searchParams)
229{
230 if (!checkSelectedScopeValid())
231 return false;
232
233 QString text = d->searchLineEdit->text();
234 if (text.isEmpty()) {
235 QMessageBox::warning(this, tr("Error"), tr("Search for text is empty, please input!"));
236 return false;
237 }
238
239 QStringList searchPathList;
240 int index = d->scopeComboBox->currentIndex();
241 switch (index) {
242 case 0:
243 searchPathList = d->allProjectsPathList.values();
244 break;
245 case 1:
246 searchPathList = QStringList{d->currentProjectPath};
247 break;
248 case 2:
249 searchPathList = QStringList{d->currentFilePath};
250 break;
251 default:
252 break;
253 }
254
255 searchParams->filePathList = searchPathList;
256 searchParams->searchText = text;
257 searchParams->sensitiveFlag = d->senseCheckBox->isChecked();
258 searchParams->wholeWordsFlag = d->wholeWordsCheckBox->isChecked();
259 searchParams->patternsList = d->patternLineEdit->text().trimmed().split(",", QString::SkipEmptyParts);
260 searchParams->exPatternsList = d->expatternLineEdit->text().trimmed().split(",", QString::SkipEmptyParts);
261 searchParams->projectInfoMap = d->projectInfoMap;
262
263 return true;
264}
265
266void FindToolWindow::searchText()
267{
268 SearchParams params;
269 if (!getSearchParams(&params)) {
270 return;
271 }
272
273 d->searchResultWindow->search(&params);
274 d->stackedWidget->setCurrentIndex(1);
275}
276
277void FindToolWindow::replace()
278{
279 if (!checkSelectedScopeValid())
280 return;
281 searchText();
282 d->searchResultWindow->setRepalceWidgtVisible(true);
283}
284
285void FindToolWindow::switchSearchParamWidget()
286{
287 d->stackedWidget->setCurrentIndex(0);
288}
289