mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-27 16:38:20 +03:00
Added global project search support to ecode.
This commit is contained in:
@@ -33,10 +33,6 @@ Detect errors and log them.
|
||||
|
||||
* Display number of results in search and number of replacements.
|
||||
|
||||
* Add support for global/project search.
|
||||
|
||||
* Add support for find and open file.
|
||||
|
||||
## UI Editor
|
||||
|
||||
* Integrate the `UICodeEditor` into the editor in order to be able to edit the layouts and CSS in app.
|
||||
|
||||
@@ -141,6 +141,7 @@ class EE_API Console : protected LogReaderInterface {
|
||||
const bool& isFading() const;
|
||||
|
||||
protected:
|
||||
Mutex mMutex;
|
||||
std::map<String, ConsoleCallback> mCallbacks;
|
||||
std::deque<String> mCmdLog;
|
||||
std::deque<String> mLastCommands;
|
||||
|
||||
@@ -44,7 +44,7 @@ class EE_API TextDocument {
|
||||
virtual void onDocumentClosed( TextDocument* ) {}
|
||||
};
|
||||
|
||||
TextDocument();
|
||||
TextDocument( bool verbose = true );
|
||||
|
||||
~TextDocument();
|
||||
|
||||
@@ -337,6 +337,7 @@ class EE_API TextDocument {
|
||||
bool mAutoDetectIndentType{true};
|
||||
bool mForceNewLineAtEndOfFile{false};
|
||||
bool mTrimTrailingWhitespaces{false};
|
||||
bool mVerbose{false};
|
||||
Uint32 mIndentWidth{4};
|
||||
IndentType mIndentType{IndentType::IndentTabs};
|
||||
Clock mTimer;
|
||||
|
||||
@@ -27,12 +27,7 @@ class EE_API Model {
|
||||
InvalidateAllIndexes = 1 << 0,
|
||||
};
|
||||
|
||||
enum class Role {
|
||||
Display,
|
||||
Icon,
|
||||
Sort,
|
||||
Custom
|
||||
};
|
||||
enum class Role { Display, Icon, Sort, Custom };
|
||||
|
||||
virtual ~Model(){};
|
||||
|
||||
@@ -91,7 +86,8 @@ class EE_API Model {
|
||||
|
||||
void onModelUpdate( unsigned flags = UpdateFlag::InvalidateAllIndexes );
|
||||
|
||||
ModelIndex createIndex( int row, int column, const void* data = nullptr ) const;
|
||||
ModelIndex createIndex( int row, int column, const void* data = nullptr,
|
||||
const Int64& internalId = 0 ) const;
|
||||
|
||||
private:
|
||||
std::unordered_set<UIAbstractView*> mViews;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define EE_UI_MODEL_MODELINDEX_HPP
|
||||
|
||||
#include <eepp/config.hpp>
|
||||
#include <limits>
|
||||
|
||||
namespace EE { namespace UI { namespace Models {
|
||||
|
||||
@@ -19,6 +20,8 @@ class EE_API ModelIndex {
|
||||
|
||||
void* data() const { return mData; }
|
||||
|
||||
Int64 internalId() const { return mInternalId; }
|
||||
|
||||
ModelIndex parent() const;
|
||||
|
||||
bool hasParent() const { return parent().isValid(); }
|
||||
@@ -40,11 +43,17 @@ class EE_API ModelIndex {
|
||||
Int64 mRow{-1};
|
||||
Int64 mColumn{-1};
|
||||
void* mData{nullptr};
|
||||
Int64 mInternalId{0};
|
||||
|
||||
ModelIndex( const Model& model, int row, int column, void* internalData ) :
|
||||
mModel( &model ), mRow( row ), mColumn( column ), mData( internalData ) {}
|
||||
ModelIndex( const Model& model, int row, int column, void* internalData,
|
||||
const Int64& internalId = 0 ) :
|
||||
mModel( &model ),
|
||||
mRow( row ),
|
||||
mColumn( column ),
|
||||
mData( internalData ),
|
||||
mInternalId( internalId ) {}
|
||||
};
|
||||
|
||||
}}} // namespace EE::UI::Model
|
||||
}}} // namespace EE::UI::Models
|
||||
|
||||
#endif // EE_UI_MODEL_MODELINDEX_HPP
|
||||
|
||||
@@ -32,14 +32,22 @@ class EE_API UITreeView : public UIAbstractTableView {
|
||||
|
||||
bool isExpanded( const ModelIndex& index ) const;
|
||||
|
||||
void expandAll( const ModelIndex& index = {} );
|
||||
|
||||
void contractAll( const ModelIndex& index = {} );
|
||||
|
||||
Drawable* getExpandIcon() const;
|
||||
|
||||
void setExpandedIcon( Drawable* expandIcon );
|
||||
|
||||
void setExpandedIcon( const std::string& expandIcon );
|
||||
|
||||
Drawable* getContractIcon() const;
|
||||
|
||||
void setContractedIcon( Drawable* contractIcon );
|
||||
|
||||
void setContractedIcon( const std::string& contractIcon );
|
||||
|
||||
bool getExpandersAsIcons() const;
|
||||
|
||||
void setExpandersAsIcons( bool expandersAsIcons );
|
||||
@@ -87,6 +95,8 @@ class EE_API UITreeView : public UIAbstractTableView {
|
||||
virtual void onOpenTreeModelIndex( const ModelIndex& index, bool open );
|
||||
|
||||
void updateContentSize();
|
||||
|
||||
void setAllExpanded( const ModelIndex& index = {}, bool expanded = true );
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -1013,6 +1013,8 @@
|
||||
../../src/tools/codeeditor/ignorematcher.hpp
|
||||
../../src/tools/codeeditor/projectdirectorytree.cpp
|
||||
../../src/tools/codeeditor/projectdirectorytree.hpp
|
||||
../../src/tools/codeeditor/projectsearch.cpp
|
||||
../../src/tools/codeeditor/projectsearch.hpp
|
||||
../../src/tools/codeeditor/uicodeeditorsplitter.cpp
|
||||
../../src/tools/codeeditor/uicodeeditorsplitter.hpp
|
||||
../../src/tools/mapeditor/mapeditor.cpp
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <eepp/graphics/pixeldensity.hpp>
|
||||
#include <eepp/graphics/renderer/renderer.hpp>
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/system/lock.hpp>
|
||||
#include <eepp/window/cursormanager.hpp>
|
||||
#include <eepp/window/engine.hpp>
|
||||
#include <eepp/window/input.hpp>
|
||||
@@ -217,6 +218,7 @@ void Console::addCommand( const String& Command, ConsoleCallback CB ) {
|
||||
}
|
||||
|
||||
void Console::draw( const Time& elapsedTime ) {
|
||||
Lock l( mMutex );
|
||||
if ( mEnabled && NULL != mFontStyleConfig.Font ) {
|
||||
fade( elapsedTime == Time::Zero ? mWindow->getElapsed() : elapsedTime );
|
||||
|
||||
@@ -418,6 +420,7 @@ void Console::processLine() {
|
||||
}
|
||||
|
||||
void Console::privPushText( const String& str ) {
|
||||
Lock l( mMutex );
|
||||
mCmdLog.push_back( str );
|
||||
|
||||
if ( mCmdLog.size() >= mMaxLogLines )
|
||||
@@ -726,7 +729,12 @@ void Console::privInputCallback( InputEvent* Event ) {
|
||||
}
|
||||
|
||||
if ( KeyCode == KEY_HOME ) {
|
||||
if ( static_cast<Int32>( mCmdLog.size() ) > linesOnScreen() )
|
||||
size_t size;
|
||||
{
|
||||
Lock l( mMutex );
|
||||
size = mCmdLog.size();
|
||||
}
|
||||
if ( static_cast<Int32>( size ) > linesOnScreen() )
|
||||
mCon.ConModif = mCon.ConMin;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ IOStreamFile* IOStreamFile::New( const std::string& path, const char* modes ) {
|
||||
|
||||
IOStreamFile::IOStreamFile( const std::string& path, const char* modes ) : mFS( NULL ), mSize( 0 ) {
|
||||
mFS = std::fopen( path.c_str(), modes );
|
||||
;
|
||||
}
|
||||
|
||||
IOStreamFile::~IOStreamFile() {
|
||||
|
||||
@@ -53,7 +53,9 @@ void Log::write( std::string Text, const bool& newLine ) {
|
||||
Text += '\n';
|
||||
}
|
||||
|
||||
lock();
|
||||
mData += Text;
|
||||
unlock();
|
||||
|
||||
writeToReaders( Text );
|
||||
|
||||
@@ -115,7 +117,9 @@ void Log::writef( const char* format, ... ) {
|
||||
tstr.resize( n );
|
||||
tstr += '\n';
|
||||
|
||||
lock();
|
||||
mData += tstr;
|
||||
unlock();
|
||||
|
||||
writeToReaders( tstr );
|
||||
|
||||
@@ -169,8 +173,10 @@ void Log::setConsoleOutput( const bool& output ) {
|
||||
mConsoleOutput = output;
|
||||
|
||||
if ( !OldOutput && output ) {
|
||||
lock();
|
||||
std::string data( mData );
|
||||
mData = "";
|
||||
unlock();
|
||||
write( data, false );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ bool TextDocument::isNonWord( String::StringBaseType ch ) const {
|
||||
return mNonWordChars.find_first_of( ch ) != String::InvalidPos;
|
||||
}
|
||||
|
||||
TextDocument::TextDocument() :
|
||||
TextDocument::TextDocument( bool verbose ) :
|
||||
mUndoStack( this ),
|
||||
mDefaultFileName( "untitled" ),
|
||||
mCleanChangeId( 0 ),
|
||||
@@ -149,8 +149,9 @@ bool TextDocument::loadFromStream( IOStream& file, std::string path ) {
|
||||
|
||||
notifyTextChanged();
|
||||
|
||||
eePRINTL( "Document \"%s\" loaded in %.2fms.", path.c_str(),
|
||||
clock.getElapsedTime().asMilliseconds() );
|
||||
if ( mVerbose )
|
||||
eePRINTL( "Document \"%s\" loaded in %.2fms.", path.c_str(),
|
||||
clock.getElapsedTime().asMilliseconds() );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,8 +26,9 @@ void Model::registerView( UIAbstractView* view ) {
|
||||
mViews.insert( view );
|
||||
}
|
||||
|
||||
ModelIndex Model::createIndex( int row, int column, const void* data ) const {
|
||||
return ModelIndex( *this, row, column, const_cast<void*>( data ) );
|
||||
ModelIndex Model::createIndex( int row, int column, const void* data,
|
||||
const Int64& internalId ) const {
|
||||
return ModelIndex( *this, row, column, const_cast<void*>( data ), internalId );
|
||||
}
|
||||
|
||||
void Model::setOnUpdate( const std::function<void()>& onUpdate ) {
|
||||
|
||||
@@ -639,6 +639,7 @@ Uint32 UICodeEditor::onFocusLoss() {
|
||||
mMouseDown = false;
|
||||
mCursorVisible = false;
|
||||
getSceneNode()->getWindow()->stopTextInput();
|
||||
getUISceneNode()->setCursor( Cursor::Arrow );
|
||||
if ( mDoc->getActiveClient() == this )
|
||||
mDoc->setActiveClient( nullptr );
|
||||
for ( auto& module : mModules )
|
||||
|
||||
@@ -383,6 +383,33 @@ bool UITreeView::isExpanded( const ModelIndex& index ) const {
|
||||
return getIndexMetadata( index ).open;
|
||||
}
|
||||
|
||||
void UITreeView::setAllExpanded( const ModelIndex& index, bool expanded ) {
|
||||
Model& model = *getModel();
|
||||
size_t count = model.rowCount( index );
|
||||
for ( size_t i = 0; i < count; i++ ) {
|
||||
auto curIndex = model.index( i, model.treeColumn(), index );
|
||||
getIndexMetadata( curIndex ).open = expanded;
|
||||
if ( model.rowCount( curIndex ) > 0 )
|
||||
setAllExpanded( curIndex, expanded );
|
||||
}
|
||||
|
||||
createOrUpdateColumns();
|
||||
}
|
||||
|
||||
void UITreeView::expandAll( const ModelIndex& index ) {
|
||||
if ( !getModel() )
|
||||
return;
|
||||
setAllExpanded( index, true );
|
||||
createOrUpdateColumns();
|
||||
}
|
||||
|
||||
void UITreeView::contractAll( const ModelIndex& index ) {
|
||||
if ( !getModel() )
|
||||
return;
|
||||
setAllExpanded( index, false );
|
||||
createOrUpdateColumns();
|
||||
}
|
||||
|
||||
Drawable* UITreeView::getExpandIcon() const {
|
||||
return mExpandIcon;
|
||||
}
|
||||
@@ -394,6 +421,10 @@ void UITreeView::setExpandedIcon( Drawable* expandIcon ) {
|
||||
}
|
||||
}
|
||||
|
||||
void UITreeView::setExpandedIcon( const std::string& expandIcon ) {
|
||||
setExpandedIcon( mUISceneNode->findIcon( expandIcon ) );
|
||||
}
|
||||
|
||||
Drawable* UITreeView::getContractIcon() const {
|
||||
return mContractIcon;
|
||||
}
|
||||
@@ -405,6 +436,10 @@ void UITreeView::setContractedIcon( Drawable* contractIcon ) {
|
||||
}
|
||||
}
|
||||
|
||||
void UITreeView::setContractedIcon( const std::string& contractIcon ) {
|
||||
setContractedIcon( mUISceneNode->findIcon( contractIcon ) );
|
||||
}
|
||||
|
||||
bool UITreeView::getExpandersAsIcons() const {
|
||||
return mExpandersAsIcons;
|
||||
}
|
||||
|
||||
@@ -192,8 +192,8 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
|
||||
|
||||
Clock clock;
|
||||
auto model = FileSystemModel::New( "." ); // std::make_shared<TestModel>();
|
||||
//UITreeView* view = UITreeView::New();
|
||||
UITableView* view = UITableView::New();
|
||||
UITreeView* view = UITreeView::New();
|
||||
//UITableView* view = UITableView::New();
|
||||
view->setId( "treeview" );
|
||||
/*view->setExpandedIcon( open );
|
||||
view->setContractedIcon( closed );*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "codeeditor.hpp"
|
||||
#include "autocompletemodule.hpp"
|
||||
#include "projectsearch.hpp"
|
||||
#include <algorithm>
|
||||
#include <args/args.hxx>
|
||||
|
||||
@@ -390,6 +391,11 @@ std::string App::getKeybind( const std::string& command ) {
|
||||
static int LOCATEBAR_MAX_VISIBLE_ITEMS = 18;
|
||||
static int LOCATEBAR_MAX_RESULTS = 100;
|
||||
|
||||
void App::hideLocateBar() {
|
||||
mLocateBarLayout->setVisible( false );
|
||||
mLocateTable->setVisible( false );
|
||||
}
|
||||
|
||||
void App::updateLocateTable() {
|
||||
if ( !mLocateInput->getText().empty() ) {
|
||||
mLocateTable->setModel(
|
||||
@@ -430,13 +436,17 @@ void App::initLocateBar() {
|
||||
mLocateTable->forceKeyDown( *keyEvent );
|
||||
} );
|
||||
mLocateBarLayout->addCommand( "close-locatebar", [&] {
|
||||
mLocateBarLayout->setVisible( false );
|
||||
mLocateTable->setVisible( false );
|
||||
hideLocateBar();
|
||||
mEditorSplitter->getCurEditor()->setFocus();
|
||||
} );
|
||||
mLocateBarLayout->getKeyBindings().addKeybindsString( {
|
||||
{"escape", "close-locatebar"},
|
||||
} );
|
||||
mLocateTable->addEventListener( Event::KeyDown, [&]( const Event* event ) {
|
||||
const KeyEvent* keyEvent = reinterpret_cast<const KeyEvent*>( event );
|
||||
if ( keyEvent->getKeyCode() == KEY_ESCAPE )
|
||||
mLocateBarLayout->execute( "close-locatebar" );
|
||||
} );
|
||||
addClickListener( mLocateBarLayout->find<UIWidget>( "locatebar_close" ), "close-locatebar" );
|
||||
mLocateTable->addEventListener( Event::OnModelEvent, [&]( const Event* event ) {
|
||||
const ModelEvent* modelEvent = static_cast<const ModelEvent*>( event );
|
||||
@@ -474,7 +484,14 @@ void App::updateLocateBar() {
|
||||
} );
|
||||
}
|
||||
|
||||
void App::hideSearchBar() {
|
||||
mSearchBarLayout->setEnabled( false )->setVisible( false );
|
||||
}
|
||||
|
||||
void App::showLocateBar() {
|
||||
hideGlobalSearchBar();
|
||||
hideSearchBar();
|
||||
|
||||
mLocateBarLayout->setVisible( true );
|
||||
mLocateInput->setFocus();
|
||||
mLocateTable->setVisible( true );
|
||||
@@ -522,8 +539,9 @@ void App::initSearchBar() {
|
||||
}
|
||||
} );
|
||||
mSearchBarLayout->addCommand( "close-searchbar", [&] {
|
||||
mSearchBarLayout->setEnabled( false )->setVisible( false );
|
||||
mEditorSplitter->getCurEditor()->setFocus();
|
||||
hideSearchBar();
|
||||
if ( mEditorSplitter->getCurEditor() )
|
||||
mEditorSplitter->getCurEditor()->setFocus();
|
||||
if ( mSearchState.editor ) {
|
||||
if ( mEditorSplitter->editorExists( mSearchState.editor ) ) {
|
||||
mSearchState.editor->setHighlightWord( "" );
|
||||
@@ -566,7 +584,154 @@ void App::initSearchBar() {
|
||||
[findInput]( const Event* ) { findInput->setFocus(); } );
|
||||
}
|
||||
|
||||
void App::showGlobalSearch() {
|
||||
hideLocateBar();
|
||||
hideSearchBar();
|
||||
mGlobalSearchBarLayout->setVisible( true )->setEnabled( true );
|
||||
mGlobalSearchInput->setFocus();
|
||||
mGlobalSearchTree->setVisible( true );
|
||||
updateGlobalSearchBar();
|
||||
}
|
||||
|
||||
void App::updateGlobalSearchBar() {
|
||||
mGlobalSearchBarLayout->runOnMainThread( [&] {
|
||||
Float width = eeceil( mGlobalSearchInput->getPixelsSize().getWidth() );
|
||||
Float rowHeight = mGlobalSearchTree->getRowHeight() * LOCATEBAR_MAX_VISIBLE_ITEMS;
|
||||
mGlobalSearchTree->setPixelsSize( width, rowHeight );
|
||||
width -= mGlobalSearchTree->getVerticalScrollBar()->getPixelsSize().getWidth();
|
||||
mGlobalSearchTree->setColumnWidth( 0, eeceil( width ) );
|
||||
Vector2f pos( mGlobalSearchInput->convertToWorldSpace( {0, 0} ) );
|
||||
pos.y -= mGlobalSearchTree->getPixelsSize().getHeight();
|
||||
mGlobalSearchTree->setPixelsPosition( pos );
|
||||
} );
|
||||
}
|
||||
|
||||
void App::hideGlobalSearchBar() {
|
||||
mGlobalSearchBarLayout->setEnabled( false )->setVisible( false );
|
||||
mGlobalSearchTree->setVisible( false );
|
||||
}
|
||||
|
||||
void App::initGlobalSearchBar() {
|
||||
auto addClickListener = [&]( UIWidget* widget, std::string cmd ) {
|
||||
widget->addEventListener( Event::MouseClick, [this, cmd]( const Event* event ) {
|
||||
const MouseEvent* mouseEvent = static_cast<const MouseEvent*>( event );
|
||||
if ( mouseEvent->getFlags() & EE_BUTTON_LMASK )
|
||||
mGlobalSearchBarLayout->execute( cmd );
|
||||
} );
|
||||
};
|
||||
UIPushButton* searchButton = mGlobalSearchBarLayout->find<UIPushButton>( "search" );
|
||||
UICheckBox* caseSensitiveBox = mGlobalSearchBarLayout->find<UICheckBox>( "case_sensitive" );
|
||||
UIWidget* searchBarClose = mGlobalSearchBarLayout->find<UIWidget>( "global_searchbar_close" );
|
||||
mGlobalSearchInput = mGlobalSearchBarLayout->find<UITextInput>( "global_search_find" );
|
||||
mGlobalSearchInput->addEventListener( Event::OnPressEnter, [this]( const Event* ) {
|
||||
mGlobalSearchBarLayout->execute( "search-in-files" );
|
||||
} );
|
||||
mGlobalSearchBarLayout->addCommand( "search-in-files", [&, caseSensitiveBox] {
|
||||
if ( mDirTree && mDirTree->getFilesCount() > 0 && !mGlobalSearchInput->getText().empty() ) {
|
||||
UILoader* loader = UILoader::New();
|
||||
loader->setId( "loader " );
|
||||
loader->setRadius( 48 );
|
||||
loader->setOutlineThickness( 6 );
|
||||
loader->setFillColor( Color::Red );
|
||||
loader->setParent( mGlobalSearchTree->getParent() );
|
||||
loader->setPosition( mGlobalSearchTree->getPosition() +
|
||||
mGlobalSearchTree->getSize() * 0.5f - loader->getSize() * 0.5f );
|
||||
Clock* clock = eeNew( Clock, () );
|
||||
std::string search( mGlobalSearchInput->getText().toUtf8() );
|
||||
ProjectSearch::find(
|
||||
mDirTree->getFiles(), search,
|
||||
#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN
|
||||
mThreadPool,
|
||||
#endif
|
||||
[&, clock, search, loader]( const ProjectSearch::Result& res ) {
|
||||
eePRINTL( "Global search for \"%s\" took %.2fms", search.c_str(),
|
||||
clock->getElapsedTime().asMilliseconds() );
|
||||
eeDelete( clock );
|
||||
mUISceneNode->runOnMainThread( [&, loader, res] {
|
||||
updateGlobalSearchBar();
|
||||
mGlobalSearchTree->setModel( ProjectSearch::asModel( res ) );
|
||||
if ( mGlobalSearchTree->getModel()->rowCount() < 50 )
|
||||
mGlobalSearchTree->expandAll();
|
||||
loader->setVisible( false );
|
||||
loader->close();
|
||||
} );
|
||||
},
|
||||
caseSensitiveBox->isChecked() );
|
||||
}
|
||||
} );
|
||||
mGlobalSearchBarLayout->addCommand( "close-global-searchbar", [&] {
|
||||
hideGlobalSearchBar();
|
||||
if ( mEditorSplitter->getCurEditor() )
|
||||
mEditorSplitter->getCurEditor()->setFocus();
|
||||
} );
|
||||
mGlobalSearchBarLayout->getKeyBindings().addKeybindsString( {
|
||||
{"escape", "close-global-searchbar"},
|
||||
} );
|
||||
mGlobalSearchInput->addEventListener( Event::OnPressEnter, [&]( const Event* ) {
|
||||
KeyEvent keyEvent( mGlobalSearchTree, Event::KeyDown, KEY_RETURN, 0, 0 );
|
||||
mGlobalSearchTree->forceKeyDown( keyEvent );
|
||||
} );
|
||||
mGlobalSearchInput->addEventListener( Event::KeyDown, [&]( const Event* event ) {
|
||||
const KeyEvent* keyEvent = reinterpret_cast<const KeyEvent*>( event );
|
||||
mGlobalSearchTree->forceKeyDown( *keyEvent );
|
||||
} );
|
||||
addClickListener( searchButton, "search-in-files" );
|
||||
addClickListener( searchBarClose, "close-global-searchbar" );
|
||||
mGlobalSearchTree = UITreeView::New();
|
||||
mGlobalSearchTree->setId( "search_tree" );
|
||||
mGlobalSearchTree->setParent( mUISceneNode->getRoot() );
|
||||
mGlobalSearchTree->setHeadersVisible( false );
|
||||
mGlobalSearchTree->setVisible( false );
|
||||
mGlobalSearchTree->setColumnsHidden(
|
||||
{ProjectSearch::ResultModel::Line, ProjectSearch::ResultModel::ColumnPosition}, true );
|
||||
mGlobalSearchTree->addEventListener( Event::KeyDown, [&]( const Event* event ) {
|
||||
const KeyEvent* keyEvent = reinterpret_cast<const KeyEvent*>( event );
|
||||
if ( keyEvent->getKeyCode() == KEY_ESCAPE )
|
||||
mGlobalSearchBarLayout->execute( "close-global-searchbar" );
|
||||
} );
|
||||
mGlobalSearchTree->addEventListener( Event::OnModelEvent, [&]( const Event* event ) {
|
||||
const ModelEvent* modelEvent = static_cast<const ModelEvent*>( event );
|
||||
if ( modelEvent->getModelEventType() == ModelEventType::Open ) {
|
||||
const Model* model = modelEvent->getModel();
|
||||
if ( !model )
|
||||
return;
|
||||
Variant vPath(
|
||||
model->data( model->index( modelEvent->getModelIndex().internalId(),
|
||||
ProjectSearch::ResultModel::FileOrPosition ) ) );
|
||||
if ( vPath.isValid() && vPath.is( Variant::Type::cstr ) ) {
|
||||
std::string path( vPath.asCStr() );
|
||||
UITab* tab = mEditorSplitter->isDocumentOpen( path );
|
||||
if ( !tab ) {
|
||||
FileInfo fileInfo( path );
|
||||
if ( fileInfo.exists() && fileInfo.isRegularFile() )
|
||||
mEditorSplitter->loadFileFromPathInNewTab( path );
|
||||
} else {
|
||||
tab->getTabWidget()->setTabSelected( tab );
|
||||
}
|
||||
Variant lineNum(
|
||||
model->data( model->index( modelEvent->getModelIndex().row(),
|
||||
ProjectSearch::ResultModel::FileOrPosition,
|
||||
modelEvent->getModelIndex().parent() ),
|
||||
Model::Role::Custom ) );
|
||||
Variant colNum(
|
||||
model->data( model->index( modelEvent->getModelIndex().row(),
|
||||
ProjectSearch::ResultModel::ColumnPosition,
|
||||
modelEvent->getModelIndex().parent() ),
|
||||
Model::Role::Custom ) );
|
||||
if ( mEditorSplitter->getCurEditor() && lineNum.isValid() && colNum.isValid() &&
|
||||
lineNum.is( Variant::Type::Int64 ) && colNum.is( Variant::Type::Int64 ) ) {
|
||||
mEditorSplitter->getCurEditor()->getDocument().setSelection(
|
||||
{lineNum.asInt64(), colNum.asInt64()} );
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void App::showFindView() {
|
||||
hideLocateBar();
|
||||
hideGlobalSearchBar();
|
||||
|
||||
UICodeEditor* editor = mEditorSplitter->getCurEditor();
|
||||
if ( !editor )
|
||||
return;
|
||||
@@ -653,7 +818,7 @@ void App::onTextDropped( String text ) {
|
||||
}
|
||||
}
|
||||
|
||||
App::App() : mThreadPool( ThreadPool::createShared( eemin<int>( 4, Sys::getCPUCount() ) ) ) {}
|
||||
App::App() : mThreadPool( ThreadPool::createShared( eemax<int>( 2, Sys::getCPUCount() ) ) ) {}
|
||||
|
||||
App::~App() {
|
||||
saveConfig();
|
||||
@@ -1286,6 +1451,7 @@ std::map<KeyBindings::Shortcut, std::string> App::getLocalKeybindings() {
|
||||
{{KEY_F7, KEYMOD_NONE}, "debug-draw-boxes-toggle"},
|
||||
{{KEY_F8, KEYMOD_NONE}, "debug-draw-debug-data"},
|
||||
{{KEY_K, KEYMOD_CTRL}, "open-locatebar"},
|
||||
{{KEY_F, KEYMOD_CTRL | KEYMOD_SHIFT}, "global-find"},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1321,6 +1487,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) {
|
||||
doc.setCommand( "save-doc", [&] { saveDoc(); } );
|
||||
doc.setCommand( "save-as-doc", [&] { saveFileDialog(); } );
|
||||
doc.setCommand( "find-replace", [&] { showFindView(); } );
|
||||
doc.setCommand( "global-find", [&] { showGlobalSearch(); } );
|
||||
doc.setCommand( "open-locatebar", [&] { showLocateBar(); } );
|
||||
doc.setCommand( "repeat-find", [&] { findNextText( mSearchState ); } );
|
||||
doc.setCommand( "close-app", [&] { closeApp(); } );
|
||||
@@ -1409,12 +1576,15 @@ bool App::setAutoComplete( bool enable ) {
|
||||
UIPopUpMenu* App::createToolsMenu() {
|
||||
mToolsMenu = UIPopUpMenu::New();
|
||||
mToolsMenu->add( "Locate...", findIcon( "search" ), getKeybind( "open-locatebar" ) );
|
||||
mToolsMenu->add( "Project Find...", findIcon( "search" ), getKeybind( "global-find" ) );
|
||||
mToolsMenu->addEventListener( Event::OnItemClicked, [&]( const Event* event ) {
|
||||
if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) )
|
||||
return;
|
||||
UIMenuItem* item = event->getNode()->asType<UIMenuItem>();
|
||||
if ( item->getText() == "Locate..." ) {
|
||||
showLocateBar();
|
||||
} else if ( item->getText() == "Project Find..." ) {
|
||||
showGlobalSearch();
|
||||
}
|
||||
} );
|
||||
return mToolsMenu;
|
||||
@@ -1565,6 +1735,8 @@ void App::initProjectTreeView( const std::string& path ) {
|
||||
FileSystemModel::Inode, FileSystemModel::Owner, FileSystemModel::SymlinkTarget,
|
||||
FileSystemModel::Permissions, FileSystemModel::ModificationTime, FileSystemModel::Path},
|
||||
true );
|
||||
mProjectTreeView->setExpandedIcon( "folder-open" );
|
||||
mProjectTreeView->setContractedIcon( "folder" );
|
||||
mProjectTreeView->setHeadersVisible( false );
|
||||
mProjectTreeView->setExpandersAsIcons( true );
|
||||
mProjectTreeView->addEventListener( Event::OnModelEvent, [&]( const Event* event ) {
|
||||
@@ -1717,11 +1889,13 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
|
||||
<style>
|
||||
TextInput#search_find,
|
||||
TextInput#search_replace,
|
||||
TextInput#locate_find {
|
||||
TextInput#locate_find,
|
||||
TextInput#global_search_find {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
#search_bar,
|
||||
#global_search_bar,
|
||||
#locate_bar {
|
||||
padding-left: 4dp;
|
||||
padding-right: 4dp;
|
||||
@@ -1773,6 +1947,9 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
|
||||
TableView#locate_bar_table > table::row:selected > table::cell:nth-child(2) {
|
||||
color: var(--font);
|
||||
}
|
||||
#search_tree treeview::cell {
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
<RelativeLayout id="main_layout" layout_width="match_parent" layout_height="match_parent">
|
||||
<Splitter id="project_splitter" layout_width="match_parent" layout_height="match_parent">
|
||||
@@ -1816,6 +1993,20 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
|
||||
<TextInput id="locate_find" layout_width="0" layout_weight="1" layout_height="18dp" padding="0" margin-bottom="2dp" margin-right="4dp" hint="Type to locate..." />
|
||||
<Widget id="locatebar_close" class="close_button" layout_width="wrap_content" layout_height="wrap_content" layout_gravity="center_vertical|right"/>
|
||||
</locatebar>
|
||||
<globalsearchbar id="global_search_bar" layout_width="match_parent" layout_height="wrap_content">
|
||||
<hbox layout_width="match_parent" layout_height="wrap_content">
|
||||
<TextView layout_width="wrap_content" layout_height="wrap_content" text="Search for:" margin-right="4dp" />
|
||||
<vbox layout_width="0" layout_weight="1" layout_height="wrap_content">
|
||||
<TextInput id="global_search_find" layout_width="match_parent" layout_height="wrap_content" layout_height="18dp" padding="0" margin-bottom="2dp" />
|
||||
<hbox layout_width="match_parent" layout_height="wrap_content">
|
||||
<CheckBox id="case_sensitive" layout_width="wrap_content" layout_height="wrap_content" text="Case sensitive" selected="true" />
|
||||
<Widget layout_width="0" layout_weight="1" layout_height="match_parent" />
|
||||
<PushButton id="search" layout_width="wrap_content" layout_height="18dp" text="Search" />
|
||||
</hbox>
|
||||
</vbox>
|
||||
<Widget id="global_searchbar_close" class="close_button" layout_width="wrap_content" layout_height="wrap_content" layout_gravity="top|right" margin-left="4dp" margin-top="4dp" />
|
||||
</hbox>
|
||||
</globalsearchbar>
|
||||
</vbox>
|
||||
</Splitter>
|
||||
<TextView id="settings" layout_width="wrap_content" layout_height="wrap_content" text="" layout_gravity="top|right" />
|
||||
@@ -1862,17 +2053,20 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
|
||||
addIcon( "cancel", 0xeb98, buttonIconSize );
|
||||
addIcon( "color-picker", 0xf13d, buttonIconSize );
|
||||
addIcon( "pixel-density", 0xed8c, buttonIconSize );
|
||||
addIcon( "tree-expanded", 0xed70, menuIconSize );
|
||||
addIcon( "tree-contracted", 0xed54, menuIconSize );
|
||||
addIcon( "tree-expanded", 0xea50, PixelDensity::dpToPx( 24 ) );
|
||||
addIcon( "tree-contracted", 0xea54, PixelDensity::dpToPx( 24 ) );
|
||||
addIcon( "search", 0xf0d1, menuIconSize );
|
||||
mUISceneNode->getUIIconThemeManager()->setCurrentTheme( iconTheme );
|
||||
|
||||
UIWidgetCreator::registerWidget( "searchbar", [] { return UISearchBar::New(); } );
|
||||
UIWidgetCreator::registerWidget( "locatebar", [] { return UILocateBar::New(); } );
|
||||
UIWidgetCreator::registerWidget( "globalsearchbar",
|
||||
[] { return UIGlobalSearchBar::New(); } );
|
||||
mUISceneNode->loadLayoutFromString( baseUI );
|
||||
mUISceneNode->bind( "main_layout", mMainLayout );
|
||||
mUISceneNode->bind( "code_container", mBaseLayout );
|
||||
mUISceneNode->bind( "search_bar", mSearchBarLayout );
|
||||
mUISceneNode->bind( "global_search_bar", mGlobalSearchBarLayout );
|
||||
mUISceneNode->bind( "locate_bar", mLocateBarLayout );
|
||||
mUISceneNode->bind( "doc_info", mDocInfo );
|
||||
mUISceneNode->bind( "doc_info_text", mDocInfoText );
|
||||
@@ -1881,6 +2075,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
|
||||
mUISceneNode->bind( "locate_find", mLocateInput );
|
||||
mDocInfo->setVisible( mConfig.editor.showDocInfo );
|
||||
mSearchBarLayout->setVisible( false )->setEnabled( false );
|
||||
mGlobalSearchBarLayout->setVisible( false )->setEnabled( false );
|
||||
mProjectSplitter->setSplitPartition( StyleSheetLength( mConfig.window.panelPartition ) );
|
||||
|
||||
if ( !mConfig.ui.showSidePanel )
|
||||
@@ -1893,6 +2088,8 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
|
||||
|
||||
initSearchBar();
|
||||
|
||||
initGlobalSearchBar();
|
||||
|
||||
initLocateBar();
|
||||
|
||||
createSettingsMenu();
|
||||
|
||||
@@ -68,6 +68,38 @@ class UILocateBar : public UILinearLayout {
|
||||
}
|
||||
};
|
||||
|
||||
class UIGlobalSearchBar : public UILinearLayout {
|
||||
public:
|
||||
typedef std::function<void()> CommandCallback;
|
||||
static UIGlobalSearchBar* New() { return eeNew( UIGlobalSearchBar, () ); }
|
||||
UIGlobalSearchBar() :
|
||||
UILinearLayout( "globalsearchbar", UIOrientation::Vertical ),
|
||||
mKeyBindings( getUISceneNode()->getWindow()->getInput() ) {}
|
||||
void addCommand( const std::string& name, const CommandCallback& cb ) { mCommands[name] = cb; }
|
||||
void execute( const std::string& command ) {
|
||||
auto cmdIt = mCommands.find( command );
|
||||
if ( cmdIt != mCommands.end() )
|
||||
cmdIt->second();
|
||||
}
|
||||
KeyBindings& getKeyBindings() { return mKeyBindings; }
|
||||
|
||||
protected:
|
||||
KeyBindings mKeyBindings;
|
||||
std::unordered_map<std::string, std::function<void()>> mCommands;
|
||||
Uint32 onKeyDown( const KeyEvent& event ) {
|
||||
std::string cmd =
|
||||
mKeyBindings.getCommandFromKeyBind( {event.getKeyCode(), event.getMod()} );
|
||||
if ( !cmd.empty() ) {
|
||||
auto cmdIt = mCommands.find( cmd );
|
||||
if ( cmdIt != mCommands.end() ) {
|
||||
cmdIt->second();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
struct UIConfig {
|
||||
StyleSheetLength fontSize{12, StyleSheetLength::Dp};
|
||||
bool showSidePanel{true};
|
||||
@@ -151,6 +183,8 @@ class App : public UICodeEditorSplitter::Client {
|
||||
|
||||
void showFindView();
|
||||
|
||||
void showGlobalSearch();
|
||||
|
||||
void showLocateBar();
|
||||
|
||||
bool replaceSelection( SearchState& search, const String& replacement );
|
||||
@@ -177,6 +211,7 @@ class App : public UICodeEditorSplitter::Client {
|
||||
UILayout* mBaseLayout{nullptr};
|
||||
UISearchBar* mSearchBarLayout{nullptr};
|
||||
UILocateBar* mLocateBarLayout{nullptr};
|
||||
UILocateBar* mGlobalSearchBarLayout{nullptr};
|
||||
UIPopUpMenu* mSettingsMenu{nullptr};
|
||||
UITextView* mSettingsButton{nullptr};
|
||||
UIPopUpMenu* mColorSchemeMenu{nullptr};
|
||||
@@ -209,6 +244,8 @@ class App : public UICodeEditorSplitter::Client {
|
||||
UITreeView* mProjectTreeView{nullptr};
|
||||
UITableView* mLocateTable{nullptr};
|
||||
UITextInput* mLocateInput{nullptr};
|
||||
UITreeView* mGlobalSearchTree{nullptr};
|
||||
UITextInput* mGlobalSearchInput;
|
||||
bool mDirTreeReady{false};
|
||||
|
||||
void initLocateBar();
|
||||
@@ -233,6 +270,8 @@ class App : public UICodeEditorSplitter::Client {
|
||||
|
||||
void initSearchBar();
|
||||
|
||||
void initGlobalSearchBar();
|
||||
|
||||
void addRemainingTabWidgets( Node* widget );
|
||||
|
||||
void createSettingsMenu();
|
||||
@@ -301,7 +340,15 @@ class App : public UICodeEditorSplitter::Client {
|
||||
|
||||
void updateLocateTable();
|
||||
|
||||
void updateGlobalSearchBar();
|
||||
|
||||
UIPopUpMenu* createToolsMenu();
|
||||
|
||||
void hideGlobalSearchBar();
|
||||
|
||||
void hideSearchBar();
|
||||
|
||||
void hideLocateBar();
|
||||
};
|
||||
|
||||
#endif // EE_TOOLS_CODEEDITOR_HPP
|
||||
|
||||
@@ -14,7 +14,7 @@ void ProjectDirectoryTree::scan( const ProjectDirectoryTree::ScanCompleteEvent&
|
||||
const bool& ignoreHidden ) {
|
||||
#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN
|
||||
mPool->run(
|
||||
[&, acceptedPattern] {
|
||||
[&, acceptedPattern, ignoreHidden] {
|
||||
#endif
|
||||
Lock l( mFilesMutex );
|
||||
if ( !acceptedPattern.empty() ) {
|
||||
@@ -112,6 +112,10 @@ size_t ProjectDirectoryTree::getFilesCount() const {
|
||||
return mFiles.size();
|
||||
}
|
||||
|
||||
const std::vector<std::string>& ProjectDirectoryTree::getFiles() const {
|
||||
return mFiles;
|
||||
}
|
||||
|
||||
void ProjectDirectoryTree::getDirectoryFiles( std::vector<std::string>& files,
|
||||
std::vector<std::string>& names,
|
||||
std::string directory,
|
||||
|
||||
@@ -29,7 +29,7 @@ class FileListModel : public Model {
|
||||
}
|
||||
|
||||
virtual Variant data( const ModelIndex& index, Role role = Role::Display ) const {
|
||||
if ( role == Role::Display ) {
|
||||
if ( role == Role::Display && index.row() < (Int64)mFiles.size() ) {
|
||||
return Variant( index.column() == 0 ? mNames[index.row()].c_str()
|
||||
: mFiles[index.row()].c_str() );
|
||||
}
|
||||
@@ -62,6 +62,8 @@ class ProjectDirectoryTree {
|
||||
|
||||
size_t getFilesCount() const;
|
||||
|
||||
const std::vector<std::string>& getFiles() const;
|
||||
|
||||
protected:
|
||||
std::string mPath;
|
||||
std::shared_ptr<ThreadPool> mPool;
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "projectsearch.hpp"
|
||||
|
||||
static std::vector<ProjectSearch::ResultData::Result>
|
||||
searchInFile( const std::string& file, const std::string& text, const bool& caseSensitive ) {
|
||||
std::vector<ProjectSearch::ResultData::Result> res;
|
||||
TextDocument doc( false );
|
||||
TextPosition pos{0, 0};
|
||||
String searchText( text );
|
||||
if ( doc.loadFromFile( file ) ) {
|
||||
do {
|
||||
pos = doc.find( searchText, pos, caseSensitive );
|
||||
if ( pos.isValid() ) {
|
||||
const auto& l = doc.line( pos.line() ).getText();
|
||||
res.push_back( {l.substr( 0, l.size() - 1 ).toUtf8(), pos} );
|
||||
pos = doc.positionOffset( pos, searchText.size() );
|
||||
}
|
||||
} while ( pos.isValid() );
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void ProjectSearch::find( const std::vector<std::string> files, const std::string& string,
|
||||
ResultCb result, bool caseSensitive ) {
|
||||
Result res;
|
||||
for ( auto& file : files ) {
|
||||
auto fileRes = searchInFile( file, string, caseSensitive );
|
||||
if ( !fileRes.empty() )
|
||||
res.push_back( {file, fileRes} );
|
||||
}
|
||||
result( res );
|
||||
}
|
||||
|
||||
struct FindData {
|
||||
Mutex resMutex;
|
||||
Mutex countMutex;
|
||||
int resCount{0};
|
||||
ProjectSearch::Result res;
|
||||
};
|
||||
|
||||
void ProjectSearch::find( const std::vector<std::string> files, const std::string& string,
|
||||
std::shared_ptr<ThreadPool> pool, ResultCb result, bool caseSensitive ) {
|
||||
if ( files.empty() )
|
||||
result( {} );
|
||||
FindData* findData = eeNew( FindData, () );
|
||||
findData->resCount = files.size();
|
||||
for ( auto& file : files ) {
|
||||
pool->run(
|
||||
[findData, file, string, caseSensitive] {
|
||||
auto fileRes = searchInFile( file, string, caseSensitive );
|
||||
if ( !fileRes.empty() ) {
|
||||
Lock l( findData->resMutex );
|
||||
findData->res.push_back( {file, fileRes} );
|
||||
}
|
||||
},
|
||||
[result, findData] {
|
||||
int count;
|
||||
{
|
||||
Lock l( findData->countMutex );
|
||||
findData->resCount--;
|
||||
count = findData->resCount;
|
||||
}
|
||||
if ( count == 0 ) {
|
||||
result( findData->res );
|
||||
eeDelete( findData );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#ifndef PROJECTSEARCH_HPP
|
||||
#define PROJECTSEARCH_HPP
|
||||
|
||||
#include <eepp/core/string.hpp>
|
||||
#include <eepp/system/threadpool.hpp>
|
||||
#include <eepp/ui/doc/textdocument.hpp>
|
||||
#include <eepp/ui/models/model.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
using namespace EE;
|
||||
using namespace EE::System;
|
||||
using namespace EE::UI::Doc;
|
||||
using namespace EE::UI::Models;
|
||||
|
||||
class ProjectSearch {
|
||||
public:
|
||||
struct ResultData {
|
||||
struct Result {
|
||||
Result( const String& line, const TextPosition& pos ) : line( line ), position( pos ) {}
|
||||
std::string line;
|
||||
TextPosition position;
|
||||
};
|
||||
std::string file;
|
||||
std::vector<Result> results;
|
||||
};
|
||||
|
||||
typedef std::vector<ResultData> Result;
|
||||
typedef std::function<void( const Result& )> ResultCb;
|
||||
|
||||
class ResultModel : public Model {
|
||||
public:
|
||||
enum Column { FileOrPosition, Line, ColumnPosition };
|
||||
|
||||
ResultModel( const Result& result ) : mResult( result ) {}
|
||||
|
||||
virtual size_t treeColumn() const { return Column::FileOrPosition; }
|
||||
|
||||
ModelIndex parentIndex( const ModelIndex& index ) const {
|
||||
if ( !index.isValid() || index.internalId() == -1 )
|
||||
return {};
|
||||
return createIndex( index.internalId(), index.column(), &mResult[index.internalId()],
|
||||
-1 );
|
||||
}
|
||||
|
||||
ModelIndex index( int row, int column, const ModelIndex& parent ) const {
|
||||
if ( row < 0 || column < 0 )
|
||||
return {};
|
||||
if ( !parent.isValid() )
|
||||
return createIndex( row, column, &mResult[row], -1 );
|
||||
if ( parent.data() )
|
||||
return createIndex( row, column, &mResult[parent.row()].results[row],
|
||||
parent.row() );
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t rowCount( const ModelIndex& index ) const {
|
||||
if ( !index.isValid() )
|
||||
return mResult.size();
|
||||
if ( index.internalId() == -1 )
|
||||
return mResult[index.row()].results.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t columnCount( const ModelIndex& ) const { return 2; }
|
||||
|
||||
std::string columnName( const size_t& colIndex ) const {
|
||||
return colIndex == 0 ? "File" : "Line";
|
||||
}
|
||||
|
||||
Variant data( const ModelIndex& index, Role role = Role::Display ) const {
|
||||
static const char* EMPTY = "";
|
||||
if ( role == Role::Display ) {
|
||||
if ( index.internalId() == -1 ) {
|
||||
if ( index.column() == FileOrPosition ) {
|
||||
return Variant( String::format( "%s (%zu)",
|
||||
mResult[index.row()].file.c_str(),
|
||||
mResult[index.row()].results.size() ) );
|
||||
}
|
||||
} else {
|
||||
switch ( index.column() ) {
|
||||
case FileOrPosition:
|
||||
return Variant( String::format(
|
||||
"%6lld %s",
|
||||
mResult[index.internalId()].results[index.row()].position.line(),
|
||||
mResult[index.internalId()].results[index.row()].line.c_str() ) );
|
||||
}
|
||||
}
|
||||
} else if ( role == Role::Custom ) {
|
||||
if ( index.internalId() != -1 ) {
|
||||
switch ( index.column() ) {
|
||||
case FileOrPosition:
|
||||
return Variant(
|
||||
mResult[index.internalId()].results[index.row()].position.line() );
|
||||
case Line:
|
||||
return Variant(
|
||||
mResult[index.internalId()].results[index.row()].line.c_str() );
|
||||
case ColumnPosition:
|
||||
return Variant( mResult[index.internalId()]
|
||||
.results[index.row()]
|
||||
.position.column() );
|
||||
}
|
||||
}
|
||||
}
|
||||
return Variant( EMPTY );
|
||||
}
|
||||
|
||||
virtual void update() { onModelUpdate(); }
|
||||
|
||||
protected:
|
||||
Result mResult;
|
||||
};
|
||||
|
||||
static std::shared_ptr<ResultModel> asModel( const Result& result ) {
|
||||
return std::make_shared<ResultModel>( result );
|
||||
}
|
||||
|
||||
static void find( const std::vector<std::string> files, const std::string& string,
|
||||
ResultCb result, bool caseSensitive );
|
||||
|
||||
static void find( const std::vector<std::string> files, const std::string& string,
|
||||
std::shared_ptr<ThreadPool> pool, ResultCb result, bool caseSensitive );
|
||||
};
|
||||
|
||||
#endif // PROJECTSEARCH_HPP
|
||||
Reference in New Issue
Block a user