Skip to content

Commit

Permalink
Merge pull request #456 from Genio-The-Haiku-IDE/improve/search-panel
Browse files Browse the repository at this point in the history
  • Loading branch information
Freaxed authored Dec 1, 2024
2 parents ad8030c + 0227ae0 commit 18590d3
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 38 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ SRCS += src/ui/ProblemsPanel.cpp
SRCS += src/ui/ProjectBrowser.cpp
SRCS += src/ui/QuitAlert.cpp
SRCS += src/ui/SearchResultPanel.cpp
SRCS += src/ui/SearchResultTab.cpp
SRCS += src/ui/StyledItem.cpp
SRCS += src/ui/ToolBar.cpp
SRCS += src/templates/IconMenuItem.cpp
Expand Down
42 changes: 8 additions & 34 deletions src/ui/GenioWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
#include "ProjectItem.h"
#include "QuitAlert.h"
#include "RemoteProjectWindow.h"
#include "SearchResultPanel.h"
#include "SearchResultTab.h"
#include "SourceControlPanel.h"
#include "SwitchBranchMenu.h"
#include "Task.h"
Expand Down Expand Up @@ -175,7 +175,7 @@ GenioWindow::GenioWindow(BRect frame)
, fBuildLogView(nullptr)
, fMTermView(nullptr)
, fGoToLineWindow(nullptr)
, fSearchResultPanel(nullptr)
, fSearchResultTab(nullptr)
, fScreenMode(kDefault)
, fDisableProjectNotifications(false)
{
Expand Down Expand Up @@ -2195,35 +2195,9 @@ GenioWindow::_FindInFiles()
if (text.IsEmpty())
return;

// convert checkboxes to grep parameters..
BString extraParameters;
if ((bool)fFindWholeWordCheck->Value())
extraParameters += "w";

if ((bool)fFindCaseSensitiveCheck->Value() == false)
extraParameters += "i";

text.CharacterEscape("\\\n\"", '\\');

BString grepCommand("grep");
BString excludeDir(gCFG["find_exclude_directory"]);
if (!excludeDir.IsEmpty()) {
if (excludeDir.FindFirst(",") >= 0)
grepCommand << " --exclude-dir={" << excludeDir << "}";
else
grepCommand << " --exclude-dir=" << excludeDir << "";
}

grepCommand += " -IFHrn";
grepCommand += extraParameters;
grepCommand += " -- ";
grepCommand += EscapeQuotesWrap(text);
grepCommand += " ";
grepCommand += EscapeQuotesWrap(fActiveProject->Path());

LogInfo("Find in file, executing: [%s]", grepCommand.String());
fSearchResultPanel->StartSearch(grepCommand, fActiveProject->Path());

fSearchResultTab->SetAndStartSearch(text, (bool)fFindWholeWordCheck->Value(),
(bool)fFindCaseSensitiveCheck->Value(),
fActiveProject);
_ShowLog(kSearchResult);
_UpdateFindMenuItems(fFindTextControl->Text());
}
Expand Down Expand Up @@ -3433,12 +3407,12 @@ GenioWindow::_InitOutputSplit()

fMTermView = new MTermView(B_TRANSLATE("Console I/O"), BMessenger(this));

fSearchResultPanel = new SearchResultPanel(fOutputTabView);
fSearchResultTab = new SearchResultTab(fOutputTabView);

fOutputTabView->AddTab(fProblemsPanel);
fOutputTabView->AddTab(fBuildLogView);
fOutputTabView->AddTab(fMTermView);
fOutputTabView->AddTab(fSearchResultPanel);
fOutputTabView->AddTab(fSearchResultTab);
}


Expand Down Expand Up @@ -4581,7 +4555,7 @@ GenioWindow::_HandleProjectConfigurationChanged(BMessage* message)
const ProjectFolder* project
= reinterpret_cast<const ProjectFolder*>(message->GetPointer("project_folder", nullptr));
if (project == nullptr) {
LogError("Update project configuration message without a project folder pointer!");
LogError("GenioWindow: Update project configuration message without a project folder pointer!");
return;
}
BString key(message->GetString("key", ""));
Expand Down
4 changes: 2 additions & 2 deletions src/ui/GenioWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class GoToLineWindow;
class ProblemsPanel;
class ProjectFolder;
class ProjectBrowser;
class SearchResultPanel;
class SearchResultTab;
class SourceControlPanel;
class TemplatesMenu;
class ToolBar;
Expand Down Expand Up @@ -255,7 +255,7 @@ class GenioWindow : public BWindow {
ConsoleIOView* fBuildLogView;
MTermView* fMTermView;
GoToLineWindow* fGoToLineWindow;
SearchResultPanel* fSearchResultPanel;
SearchResultTab* fSearchResultTab;

scree_mode fScreenMode;
GMessage fScreenModeSettings;
Expand Down
5 changes: 4 additions & 1 deletion src/ui/ProjectBrowser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,10 @@ ProjectBrowser::MessageReceived(BMessage* message)
const ProjectFolder* project
= reinterpret_cast<const ProjectFolder*>(message->GetPointer("project_folder", nullptr));
if (project == nullptr) {
LogError("Update project configuration message without a project folder pointer!");
LogError("ProjectBrowser: Update project configuration message without a project folder pointer!");
if (Logger::IsErrorEnabled()) {
message->PrintToStream();
}
break;
}
// Save project settings
Expand Down
2 changes: 1 addition & 1 deletion src/ui/SearchResultPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ SearchResultPanel::SetTabLabel(BString label)
return;

for (int32 i = 0; i < fTabView->CountTabs(); i++) {
if (fTabView->ViewForTab(i) == this) {
if (fTabView->ViewForTab(i) == this->Parent()) {
fTabView->TabAt(i)->SetLabel(label.String());
break;
}
Expand Down
259 changes: 259 additions & 0 deletions src/ui/SearchResultTab.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
/*
* Copyright 2024, Andrea Anzani <andrea.anzani@gmail.com>
* All rights reserved. Distributed under the terms of the MIT license.
*/


#include "SearchResultTab.h"
#include "SearchResultPanel.h"
#include <LayoutBuilder.h>
#include <Catalog.h>
#include <Button.h>
#include "GenioWindow.h"
#include "GenioWindowMessages.h"
#include "ProjectBrowser.h"
#include "TextUtils.h"
#include "ConfigManager.h"
#include "ToolBar.h"
#include "ActionManager.h"


extern ConfigManager gCFG;


#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SearchResultTab"

static constexpr auto kFindReplaceMaxBytes = 50;
static constexpr auto kFindReplaceMinBytes = 32;

static constexpr uint32 kSelectProject ='PRJX';


SearchResultTab::SearchResultTab(BTabView* tabView)
: BGroupView(B_VERTICAL, 0.0f)
, fSearchResultPanel(nullptr)
, fTabView(tabView)
, fSelectedProject(nullptr)
{
fProjectMenu = new OptionList<ProjectFolder *>("ProjectMenu",
B_TRANSLATE("Project:"),
B_TRANSLATE("Choose project" B_UTF8_ELLIPSIS));

fFindGroup = new ToolBar(this);
ActionManager::AddItem(MSG_FIND_IN_FILES, fFindGroup);
fFindGroup->FindButton(MSG_FIND_IN_FILES)->SetLabel(B_TRANSLATE("Find in project"));

fFindTextControl = new BTextControl("FindTextControl", "" , "", nullptr);
fFindTextControl->TextView()->SetMaxBytes(kFindReplaceMaxBytes);
float charWidth = fFindTextControl->StringWidth("0", 1);
fFindTextControl->SetExplicitMinSize(
BSize(charWidth * kFindReplaceMinBytes + 10.0f,
B_SIZE_UNSET));
fFindTextControl->SetExplicitMaxSize(fFindTextControl->MinSize());

fFindCaseSensitiveCheck = new BCheckBox(B_TRANSLATE_COMMENT("Match case", "Short as possible."),
nullptr);
fFindWholeWordCheck = new BCheckBox(B_TRANSLATE_COMMENT("Whole word", "Short as possible."),
nullptr);

fSearchResultPanel = new SearchResultPanel(fTabView);
BLayoutBuilder::Group<>(this, B_HORIZONTAL, 0.0f)
.Add(fSearchResultPanel, 3.0f)
.AddGroup(B_VERTICAL, 0.0f)
.SetInsets(B_USE_SMALL_SPACING)
.Add(fProjectMenu)
.AddGlue()
.Add(fFindWholeWordCheck)
.Add(fFindCaseSensitiveCheck)
.AddGlue()
.Add(fFindTextControl)
.AddGlue()
.Add(fFindGroup)
.End()
.End();
}


void
SearchResultTab::MessageReceived(BMessage *message)
{
switch (message->what) {
case kSelectProject: {
fSelectedProject = const_cast<ProjectFolder*>(
reinterpret_cast<const ProjectFolder*>(message->GetPointer("value")));
}
break;
case MSG_FIND_IN_FILES:
_StartSearch(fFindTextControl->Text(), (bool) fFindWholeWordCheck->Value(),
(bool) fFindCaseSensitiveCheck->Value(), fSelectedProject);
break;
case B_OBSERVER_NOTICE_CHANGE: {
int32 code;
message->FindInt32(B_OBSERVE_WHAT_CHANGE, &code);
switch (code) {
case MSG_NOTIFY_PROJECT_LIST_CHANGED:
{
_UpdateProjectList(gMainWindow->GetProjectBrowser()->GetProjectList());
break;
}
default:
break;
}
}
break;
default:
BGroupView::MessageReceived(message);
break;
}
}


void
SearchResultTab::AttachedToWindow()
{
fProjectMenu->SetTarget(this);
fProjectMenu->SetSender("SearchResultTab");
_UpdateProjectList(gMainWindow->GetProjectBrowser()->GetProjectList());
if (Window()->LockLooper()) {
Window()->StartWatching(this, MSG_NOTIFY_PROJECT_LIST_CHANGED);
Window()->UnlockLooper();
}

fFindGroup->SetTarget(this);
fFindTextControl->SetMessage(new BMessage(MSG_FIND_IN_FILES));
fFindTextControl->SetTarget(this);
}


void
SearchResultTab::_UpdateProjectList(const BObjectList<ProjectFolder>* list)
{
if (list == nullptr) {
fProjectMenu->MakeEmpty();
return;
}

//Is the current selected project still in the new list?
bool found = _IsProjectInList(list, fSelectedProject);

fProjectMenu->MakeEmpty();
if (!found)
fSelectedProject = gMainWindow->GetActiveProject();

ProjectFolder* activeProject = gMainWindow->GetActiveProject();
ProjectFolder* selectedProject = fSelectedProject;


fProjectMenu->AddList(list,
kSelectProject,
[&active = activeProject](auto item)
{
BString projectName = item ? item->Name() : "";
BString projectPath = item ? item->Path() : "";
if (active != nullptr && active->Path() == projectPath)
projectName.Append("*");
return projectName;
},
true,
[&selected = selectedProject](auto item)
{
if (item == nullptr || selected == nullptr)
return false;
return (item->Path() == selected->Path());
}
);
}


SearchResultTab::~SearchResultTab()
{
delete fProjectMenu;
}


void
SearchResultTab::SetAndStartSearch(BString text, bool wholeWord, bool caseSensitive, ProjectFolder* project)
{
if (!project)
return;

if (text.IsEmpty())
return;

BMenu* menu = fProjectMenu->Menu();

if (!menu)
return;

if (project != fSelectedProject) {
for (int32 i=0;i<menu->CountItems();i++) {
BMessage* msg = menu->ItemAt(i)->Message();
if (msg && msg->GetPointer("value", nullptr) == project) {
fSelectedProject = project;
menu->ItemAt(i)->SetMarked(true);
break;
}
}
}
if (project != fSelectedProject)
return;

fFindCaseSensitiveCheck->SetValue((bool)caseSensitive);
fFindWholeWordCheck->SetValue((bool)wholeWord);
fFindTextControl->SetText(text.String());

_StartSearch(text, wholeWord, caseSensitive, project);
}

void
SearchResultTab::_StartSearch(BString text, bool wholeWord, bool caseSensitive, ProjectFolder* project)
{
if (!project)
return;

if (text.IsEmpty())
return;

BString extraParameters;
if (wholeWord)
extraParameters += "w";

if (caseSensitive == false)
extraParameters += "i";

text.CharacterEscape("\\\n\"", '\\');

BString grepCommand("grep");
BString excludeDir(gCFG["find_exclude_directory"]);
if (!excludeDir.IsEmpty()) {
if (excludeDir.FindFirst(",") >= 0)
grepCommand << " --exclude-dir={" << excludeDir << "}";
else
grepCommand << " --exclude-dir=" << excludeDir << "";
}

grepCommand += " -IFHrn";
grepCommand += extraParameters;
grepCommand += " -- ";
grepCommand += EscapeQuotesWrap(text);
grepCommand += " ";
grepCommand += EscapeQuotesWrap(project->Path());

LogInfo("Find in file, executing: [%s]", grepCommand.String());
fSearchResultPanel->StartSearch(grepCommand, project->Path());
}

bool
SearchResultTab::_IsProjectInList(const BObjectList<ProjectFolder>* list, ProjectFolder* proj)
{
//Is the current selected project still in the new list?
auto count = list->CountItems();
for (int index = 0; index < count; index++) {
ProjectFolder* element = list->ItemAt(index);
if (element == proj) {
return true;
}
}
return false;
}
Loading

0 comments on commit 18590d3

Please sign in to comment.