Skip to content

Commit

Permalink
feat: add a find in files panel on the GUI
Browse files Browse the repository at this point in the history
Fixes KDAB#22
Depends on KDAB#21
  • Loading branch information
smnppKDAB committed Aug 22, 2024
1 parent 6041dbf commit 6561722
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ set(PROJECT_SOURCES
fileselector.h
fileselector.cpp
findwidget.h
findinfilespanel.cpp
findinfilespanel.h
findwidget.cpp
findwidget.ui
gui_constants.h
Expand Down
155 changes: 155 additions & 0 deletions src/gui/findinfilespanel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
This file is part of Knut.
SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
SPDX-License-Identifier: GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/

#include "findinfilespanel.h"
#include "core/project.h"
#include "core/textdocument.h"
#include "guisettings.h"
#include <QFile>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QTreeWidgetItem>
#include <QVBoxLayout>

namespace Gui {

enum FindInFilesRoles { LineRole = Qt::UserRole + 1, ColumnRole };

FindInFilesPanel::FindInFilesPanel(QWidget *parent)
: QWidget(parent)
, m_toolBar(new QWidget(this))
, m_resultsDisplay(new QTreeWidget(this))
{
setWindowTitle(tr("Find in Files"));
setObjectName("FindInFilesPanel");

auto mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
setupToolBar();
mainLayout->addWidget(m_toolBar);

m_resultsDisplay->setHeaderHidden(true);
m_resultsDisplay->header()->setSectionResizeMode(0, QHeaderView::Stretch);
mainLayout->addWidget(m_resultsDisplay);

connect(m_resultsDisplay, &QTreeWidget::itemDoubleClicked, this, [this](QTreeWidgetItem *item, int) {
openFileAtItem(item);
});
connect(m_resultsDisplay, &QTreeWidget::itemActivated, this, [this](QTreeWidgetItem *item, int) {
openFileAtItem(item);
});
}

QWidget *FindInFilesPanel::toolBar() const
{
return m_toolBar;
}

void FindInFilesPanel::setupToolBar()
{
auto layout = new QHBoxLayout(m_toolBar);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);

m_searchInput = new QLineEdit(m_toolBar);
m_searchInput->setPlaceholderText(tr("Enter search pattern..."));
layout->addWidget(m_searchInput);

m_searchButton = new QToolButton(m_toolBar);
m_searchButton->setText(tr("Find"));
layout->addWidget(m_searchButton);

connect(m_searchButton, &QToolButton::clicked, this, [this]() {
findInFiles(m_searchInput->text());
});

connect(m_searchInput, &QLineEdit::returnPressed, this, [this]() {
findInFiles(m_searchInput->text());
});
}

void FindInFilesPanel::findInFiles(const QString &searchText)
{
if (searchText.isEmpty()) {
qWarning() << "The text to search for is empty";
return;
}

auto results = Core::Project::instance()->findInFiles(searchText);

for (auto &resultVariant : results) {
auto result = resultVariant.toMap();

QFile file(result["file"].toString());
if (file.open(QFile::ReadOnly)) {
QTextStream stream(&file);
int currentLine = 0;
const int line = result["line"].toInt();
while (!stream.atEnd()) {
const QString lineText = stream.readLine();
++currentLine;
if (currentLine == line) {
result["text"] = lineText;
break;
}
}
}
resultVariant = result;
}

displayResults(results);
}

void FindInFilesPanel::displayResults(const QVariantList &results) const
{
m_resultsDisplay->clear();
QMap<QString, QTreeWidgetItem *> fileItems;

for (const auto &result : results) {
const auto map = result.toMap();
const QString filePath = map["file"].toString();
const int line = map["line"].toInt();
const int column = map["column"].toInt();
const QString text = map["text"].toString();

auto it = fileItems.find(filePath);
if (it == fileItems.end()) {
auto fileItem = new QTreeWidgetItem(m_resultsDisplay);
fileItem->setText(0, filePath);
it = fileItems.insert(filePath, fileItem);
}

auto lineItem = new QTreeWidgetItem(it.value());
lineItem->setText(0, QString("%1 %2").arg(line).arg(text));
lineItem->setData(0, LineRole, line);
lineItem->setData(1, ColumnRole, column);
}
}

void FindInFilesPanel::openFileAtItem(QTreeWidgetItem *item)
{
if (item->childCount() > 0)
return;

QTreeWidgetItem *parentItem = item->parent();
const QString filePath = parentItem->text(0);
const int line = item->data(0, LineRole).toInt();
const int column = item->data(1, ColumnRole).toInt();

if (auto *doc = qobject_cast<Core::TextDocument *>(Core::Project::instance()->open(filePath))) {
doc->gotoLine(line, column);
doc->selectEndOfWord();
} else {
qWarning() << "Unable to open the file:" << filePath;
}
}

} // namespace Gui
41 changes: 41 additions & 0 deletions src/gui/findinfilespanel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
This file is part of Knut.
SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
SPDX-License-Identifier: GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/

#pragma once

#include <QLineEdit>
#include <QToolButton>
#include <QTreeWidget>
#include <QWidget>

namespace Gui {

class FindInFilesPanel : public QWidget
{
Q_OBJECT

public:
explicit FindInFilesPanel(QWidget *parent = nullptr);

QWidget *toolBar() const;
void displayResults(const QVariantList &results) const;

private:
void setupToolBar();
void findInFiles(const QString &searchText);
void openFileAtItem(QTreeWidgetItem *item);

QWidget *const m_toolBar;
QTreeWidget *m_resultsDisplay;
QLineEdit *m_searchInput;
QToolButton *m_searchButton;
};

} // namespace Gui
8 changes: 8 additions & 0 deletions src/gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "core/textdocument.h"
#include "core/version.h"
#include "documentpalette.h"
#include "findinfilespanel.h"
#include "guisettings.h"
#include "historypanel.h"
#include "imageview.h"
Expand Down Expand Up @@ -123,6 +124,7 @@ MainWindow::MainWindow(QWidget *parent)
, m_documentPalette(new DocumentPalette(this))
, m_shortcutManager(new ShortcutManager(this))
, m_toolBar(new ToolBar(this))
, m_findInFilesPanel(new FindInFilesPanel(this))
{
// Initialize the settings before anything
GuiSettings::instance();
Expand All @@ -147,6 +149,7 @@ MainWindow::MainWindow(QWidget *parent)
auto logPanel = new LogPanel(this);
createDock(logPanel, Qt::BottomDockWidgetArea, logPanel->toolBar());
createDock(m_historyPanel, Qt::BottomDockWidgetArea, m_historyPanel->toolBar());
createDock(m_findInFilesPanel, Qt::BottomDockWidgetArea, m_findInFilesPanel->toolBar());
auto scriptDock = createDock(m_scriptPanel, Qt::LeftDockWidgetArea, m_scriptPanel->toolBar());
auto scriptListDock = createDock(m_scriptlistpanel, Qt::BottomDockWidgetArea, m_scriptlistpanel->toolBar());
scriptListDock->setAllowedAreas(Qt::AllDockWidgetAreas);
Expand Down Expand Up @@ -798,4 +801,9 @@ void MainWindow::changeCurrentDocument()
updateActions();
}

void MainWindow::displayFindResults(const QVariantList &results) const
{
m_findInFilesPanel->displayResults(results);
}

} // namespace Gui
3 changes: 3 additions & 0 deletions src/gui/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class DocumentPalette;
class ShortcutManager;
class TreeSitterInspector;
class ToolBar;
class FindInFilesPanel;

namespace Ui {
class MainWindow;
Expand Down Expand Up @@ -110,6 +111,7 @@ class MainWindow : public QMainWindow
void changeCurrentDocument();
QDockWidget *createDock(QWidget *widget, Qt::DockWidgetArea area, QWidget *toolbar = nullptr);
void reloadDocuments();
void displayFindResults(const QVariantList &results) const;

std::unique_ptr<Ui::MainWindow> ui;
QMenu *m_recentProjects = nullptr;
Expand All @@ -123,6 +125,7 @@ class MainWindow : public QMainWindow
ShortcutManager *const m_shortcutManager = nullptr;
ToolBar *const m_toolBar = nullptr;
QPointer<TreeSitterInspector> m_treeSitterInspector;
FindInFilesPanel *const m_findInFilesPanel = nullptr;
};

} // namespace Gui

0 comments on commit 6561722

Please sign in to comment.