From ff2fd46638399c3333ffb69acddd104ce6edb4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Tue, 18 Jan 2022 22:39:00 -0300 Subject: [PATCH] WIP. --- include/eepp/ui/models/filesystemmodel.hpp | 37 +- include/eepp/ui/models/itemlistmodel.hpp | 4 +- include/eepp/ui/models/model.hpp | 93 ++++- include/eepp/ui/models/modelindex.hpp | 11 +- include/eepp/ui/models/modelrole.hpp | 10 + include/eepp/ui/models/modelselection.hpp | 6 +- .../eepp/ui/models/persistentmodelindex.hpp | 59 +++ include/eepp/ui/models/sortingproxymodel.hpp | 8 +- include/eepp/ui/models/widgettreemodel.hpp | 2 +- projects/linux/ee.creator.user | 25 +- projects/linux/ee.files | 4 + src/eepp/ui/abstract/uiabstracttableview.cpp | 4 +- src/eepp/ui/abstract/uiabstractview.cpp | 2 +- src/eepp/ui/models/filesystemmodel.cpp | 120 +++++- src/eepp/ui/models/model.cpp | 344 +++++++++++++++++- src/eepp/ui/models/modelindex.cpp | 25 ++ src/eepp/ui/models/modelselection.cpp | 14 +- src/eepp/ui/models/persistentmodelindex.cpp | 79 ++++ src/eepp/ui/models/sortingproxymodel.cpp | 14 +- src/eepp/ui/models/widgettreemodel.cpp | 12 +- src/eepp/ui/uifiledialog.cpp | 2 +- src/eepp/ui/uitreeview.cpp | 10 +- src/tests/ui_perf_test/ui_perf_test.cpp | 10 +- src/tools/codeeditor/codeeditor.cpp | 2 +- src/tools/codeeditor/filelocator.cpp | 2 +- src/tools/codeeditor/filesystemlistener.cpp | 6 +- .../codeeditor/globalsearchcontroller.cpp | 6 +- src/tools/codeeditor/projectdirectorytree.hpp | 4 +- src/tools/codeeditor/projectsearch.hpp | 8 +- .../codeeditor/uitreeviewglobalsearch.cpp | 4 +- 30 files changed, 855 insertions(+), 72 deletions(-) create mode 100644 include/eepp/ui/models/modelrole.hpp create mode 100644 include/eepp/ui/models/persistentmodelindex.hpp create mode 100644 src/eepp/ui/models/modelindex.cpp create mode 100644 src/eepp/ui/models/persistentmodelindex.cpp diff --git a/include/eepp/ui/models/filesystemmodel.hpp b/include/eepp/ui/models/filesystemmodel.hpp index 622b1f5c9..bd8555813 100644 --- a/include/eepp/ui/models/filesystemmodel.hpp +++ b/include/eepp/ui/models/filesystemmodel.hpp @@ -1,6 +1,7 @@ #ifndef EE_UI_MODELS_FILESYSTEMMODEL_HPP #define EE_UI_MODELS_FILESYSTEMMODEL_HPP +#include #include #include #include @@ -8,6 +9,28 @@ namespace EE { namespace UI { namespace Models { +enum FileSystemEventType { + /// Sent when a file is created or renamed + Add = 1, + /// Sent when a file is deleted or renamed + Delete = 2, + /// Sent when a file is modified + Modified = 3, + /// Sent when a file is moved + Moved = 4 +}; + +struct FileEvent { + FileSystemEventType type; + std::string directory; + std::string filename; + std::string oldFilename; + + FileEvent( const FileSystemEventType& action, const std::string& directory, + const std::string& filename, const std::string& oldFilename = "" ) : + type( action ), directory( directory ), filename( filename ), oldFilename( oldFilename ) {} +}; + class EE_API FileSystemModel : public Model { public: enum class Mode { DirectoriesOnly, FilesAndDirectories }; @@ -77,6 +100,13 @@ class EE_API FileSystemModel : public Model { private: friend class FileSystemModel; + + Node() {} + + FileSystemModel::Node createChild( const std::string& childName, + const FileSystemModel& model ); + + friend class FileSystemModel; std::string mName; std::string mMimeType; Node* mParent{ nullptr }; @@ -116,7 +146,7 @@ class EE_API FileSystemModel : public Model { virtual size_t rowCount( const ModelIndex& = ModelIndex() ) const; virtual size_t columnCount( const ModelIndex& = ModelIndex() ) const; virtual std::string columnName( const size_t& column ) const; - virtual Variant data( const ModelIndex&, Role role = Role::Display ) const; + virtual Variant data( const ModelIndex&, ModelRole role = ModelRole::Display ) const; virtual ModelIndex parentIndex( const ModelIndex& ) const; virtual ModelIndex index( int row, int column = 0, const ModelIndex& parent = ModelIndex() ) const; @@ -133,7 +163,11 @@ class EE_API FileSystemModel : public Model { void setPreviouslySelectedIndex( const ModelIndex& previouslySelectedIndex ); + void handleFileEvent( const FileEvent& event ); + + ~FileSystemModel(); protected: + std::atomic mInitOK; std::string mRootPath; std::string mRealRootPath; std::unique_ptr mRoot{ nullptr }; @@ -146,6 +180,7 @@ class EE_API FileSystemModel : public Model { FileSystemModel( const std::string& rootPath, const Mode& mode, const DisplayConfig displayConfig ); + }; }}} // namespace EE::UI::Models diff --git a/include/eepp/ui/models/itemlistmodel.hpp b/include/eepp/ui/models/itemlistmodel.hpp index 7dce1217a..4c5052ac2 100644 --- a/include/eepp/ui/models/itemlistmodel.hpp +++ b/include/eepp/ui/models/itemlistmodel.hpp @@ -21,8 +21,8 @@ template class ItemListModel final : public Model { virtual std::string columnName( const size_t& ) const { return "Data"; } - virtual Variant data( const ModelIndex& index, Role role = Role::Display ) const { - if ( role == Role::Display ) + virtual Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const { + if ( role == ModelRole::Display ) return Variant( mData[index.row()] ); return {}; } diff --git a/include/eepp/ui/models/model.hpp b/include/eepp/ui/models/model.hpp index b07ec73da..063f12306 100644 --- a/include/eepp/ui/models/model.hpp +++ b/include/eepp/ui/models/model.hpp @@ -2,8 +2,11 @@ #define EE_UI_MODELS_MODEL_HPP #include +#include #include #include +#include +#include #include #include @@ -18,6 +21,8 @@ using namespace EE::UI::Abstract; namespace EE { namespace UI { namespace Models { +class PersistentHandle; + enum class SortOrder { None, Ascending, Descending }; class EE_API Model { @@ -27,6 +32,25 @@ class EE_API Model { virtual ~Client() {} virtual void onModelUpdated( unsigned flags ) = 0; + + virtual void modelDidInsertRows( [[maybe_unused]] ModelIndex const& parent, + [[maybe_unused]] int first, [[maybe_unused]] int last ) {} + virtual void modelDidInsertColumns( [[maybe_unused]] ModelIndex const& parent, + [[maybe_unused]] int first, + [[maybe_unused]] int last ) {} + virtual void modelDidMoveRows( [[maybe_unused]] ModelIndex const& source_parent, + [[maybe_unused]] int first, [[maybe_unused]] int last, + [[maybe_unused]] ModelIndex const& target_parent, + [[maybe_unused]] int target_index ) {} + virtual void modeldidMoveColumns( [[maybe_unused]] ModelIndex const& source_parent, + [[maybe_unused]] int first, [[maybe_unused]] int last, + [[maybe_unused]] ModelIndex const& target_parent, + [[maybe_unused]] int target_index ) {} + virtual void modelDidDeleteRows( [[maybe_unused]] ModelIndex const& parent, + [[maybe_unused]] int first, [[maybe_unused]] int last ) {} + virtual void modelDidDeleteColumns( [[maybe_unused]] ModelIndex const& parent, + [[maybe_unused]] int first, + [[maybe_unused]] int last ) {} }; enum UpdateFlag { @@ -34,8 +58,6 @@ class EE_API Model { InvalidateAllIndexes = 1 << 0, }; - enum class Role { Display, Icon, Sort, Custom }; - virtual ~Model(){}; virtual size_t rowCount( const ModelIndex& = ModelIndex() ) const = 0; @@ -44,7 +66,7 @@ class EE_API Model { virtual std::string columnName( const size_t& /*column*/ ) const { return {}; } - virtual Variant data( const ModelIndex&, Role = Role::Display ) const = 0; + virtual Variant data( const ModelIndex&, ModelRole = ModelRole::Display ) const = 0; virtual void update() = 0; @@ -94,6 +116,24 @@ class EE_API Model { void invalidate( unsigned int flags = Model::UpdateFlag::InvalidateAllIndexes ); + std::weak_ptr registerPersistentIndex( ModelIndex const& ); + + void beginInsertRows( ModelIndex const& parent, int first, int last ); + void beginInsertColumns( ModelIndex const& parent, int first, int last ); + void beginMoveRows( ModelIndex const& source_parent, int first, int last, + ModelIndex const& target_parent, int target_index ); + void beginMoveColumns( ModelIndex const& source_parent, int first, int last, + ModelIndex const& target_parent, int target_index ); + void beginDeleteRows( ModelIndex const& parent, int first, int last ); + void beginDeleteColumns( ModelIndex const& parent, int first, int last ); + + void endInsertRows(); + void endInsertColumns(); + void endMoveRows(); + void endMoveColumns(); + void endDeleteRows(); + void endDeleteColumns(); + protected: Model(){}; @@ -104,6 +144,53 @@ class EE_API Model { ModelIndex createIndex( int row, int column, const void* data = nullptr, const Int64& internalId = 0 ) const; + enum class OperationType { Invalid = 0, Insert, Move, Delete, Reset }; + enum class Direction { Row, Column }; + + struct Operation { + OperationType type{ OperationType::Invalid }; + Direction direction{ Direction::Row }; + ModelIndex source_parent; + int first{ 0 }; + int last{ 0 }; + ModelIndex target_parent; + int target{ 0 }; + + Operation( OperationType type ) : type( type ) {} + + Operation( OperationType type, Direction direction, ModelIndex const& parent, int first, + int last ) : + type( type ), + direction( direction ), + source_parent( parent ), + first( first ), + last( last ) {} + + Operation( OperationType type, Direction direction, ModelIndex const& sourceParent, + int first, int last, ModelIndex const& targetParent, int target ) : + type( type ), + direction( direction ), + source_parent( sourceParent ), + first( first ), + last( last ), + target_parent( targetParent ), + target( target ) {} + }; + + void handleInsert( Operation const& ); + void handleMove( Operation const& ); + void handleDelete( Operation const& ); + + template void saveDeletedIndices( ModelIndex const& parent, int first, int last ); + + std::map> mPersistentHandles; + std::stack mOperationStack; + // NOTE: We need to save which indices have been deleted before the delete + // actually happens, because we can't figure out which persistent handles + // belong to us in end_delete_rows/columns (because accessing the parents of + // the indices might be impossible). + std::stack> mDeletedIndicesStack; + private: std::unordered_set mViews; std::unordered_set mClients; diff --git a/include/eepp/ui/models/modelindex.hpp b/include/eepp/ui/models/modelindex.hpp index b51b557dd..87673ce9e 100644 --- a/include/eepp/ui/models/modelindex.hpp +++ b/include/eepp/ui/models/modelindex.hpp @@ -2,6 +2,9 @@ #define EE_UI_MODEL_MODELINDEX_HPP #include +#include +#include +#include #include namespace EE { namespace UI { namespace Models { @@ -18,7 +21,9 @@ class EE_API ModelIndex { const Int64& column() const { return mColumn; } - void* data() const { return mData; } + Variant data( ModelRole = ModelRole::Display ) const; + + void* internalData() const { return mData; } Int64 internalId() const { return mInternalId; } @@ -39,6 +44,10 @@ class EE_API ModelIndex { const Model* model() const { return mModel; } + ModelIndex sibling( int row, int column ) const; + + ModelIndex siblingAtColumn( int column ) const; + protected: friend class Model; const Model* mModel{ nullptr }; diff --git a/include/eepp/ui/models/modelrole.hpp b/include/eepp/ui/models/modelrole.hpp new file mode 100644 index 000000000..8f6853027 --- /dev/null +++ b/include/eepp/ui/models/modelrole.hpp @@ -0,0 +1,10 @@ +#ifndef EE_UI_MODLE_MODELROLE_HPP +#define EE_UI_MODLE_MODELROLE_HPP + +namespace EE { namespace UI { namespace Models { + +enum class ModelRole { Display, Icon, Sort, Custom }; + +}}} // namespace EE::UI::Models + +#endif // EE_UI_MODLE_MODELROLE_HPP diff --git a/include/eepp/ui/models/modelselection.hpp b/include/eepp/ui/models/modelselection.hpp index f8508b08a..754c4cf0d 100644 --- a/include/eepp/ui/models/modelselection.hpp +++ b/include/eepp/ui/models/modelselection.hpp @@ -60,7 +60,7 @@ class EE_API ModelSelection { return *mIndexes.begin(); } - void removeMatching( std::function ); + void removeAllMatching( std::function filter ); template void changeFromModel( Function f ) { { @@ -76,8 +76,8 @@ class EE_API ModelSelection { protected: UIAbstractView* mView; std::vector mIndexes; - bool mDisableNotify{false}; - bool mNotifyPending{false}; + bool mDisableNotify{ false }; + bool mNotifyPending{ false }; void notifySelectionChanged(); }; diff --git a/include/eepp/ui/models/persistentmodelindex.hpp b/include/eepp/ui/models/persistentmodelindex.hpp new file mode 100644 index 000000000..a8fe4ef47 --- /dev/null +++ b/include/eepp/ui/models/persistentmodelindex.hpp @@ -0,0 +1,59 @@ +#ifndef EE_UI_MODEL_PERSISTENTMODELINDEX_HPP +#define EE_UI_MODEL_PERSISTENTMODELINDEX_HPP + +#include +#include + +namespace EE { namespace UI { namespace Models { + +/// A PersistentHandle is an internal data structure used to keep track of the +/// target of multiple PersistentModelIndex instances. +class PersistentHandle { + public: + friend class Model; + friend class PersistentModelIndex; + + PersistentHandle( ModelIndex const& index ) : m_index( index ) {} + + ModelIndex m_index; +}; + +class PersistentModelIndex { + public: + PersistentModelIndex() {} + PersistentModelIndex( ModelIndex const& ); + PersistentModelIndex( PersistentModelIndex const& ) = default; + PersistentModelIndex( PersistentModelIndex&& ) = default; + + PersistentModelIndex& operator=( PersistentModelIndex const& ) = default; + PersistentModelIndex& operator=( PersistentModelIndex&& ) = default; + + bool isValid() const { return hasValidHandle() && m_handle.lock()->m_index.isValid(); } + bool hasValidHandle() const { return !m_handle.expired(); } + + int row() const; + int column() const; + PersistentModelIndex parent() const; + PersistentModelIndex siblingAtColumn( int column ) const; + Variant data( ModelRole = ModelRole::Display ) const; + + void* internalData() const { + if ( hasValidHandle() ) + return m_handle.lock()->m_index.internalData(); + else + return nullptr; + } + + operator ModelIndex() const; + bool operator==( PersistentModelIndex const& ) const; + bool operator!=( PersistentModelIndex const& ) const; + bool operator==( ModelIndex const& ) const; + bool operator!=( ModelIndex const& ) const; + + private: + std::weak_ptr m_handle; +}; + +}}} // namespace EE::UI::Models + +#endif // EE_UI_MODEL_PERSISTENTMODELINDEX_HPP diff --git a/include/eepp/ui/models/sortingproxymodel.hpp b/include/eepp/ui/models/sortingproxymodel.hpp index 7be3ed818..a7a1bf5d6 100644 --- a/include/eepp/ui/models/sortingproxymodel.hpp +++ b/include/eepp/ui/models/sortingproxymodel.hpp @@ -22,7 +22,7 @@ class EE_API SortingProxyModel final : public Model, private Model::Client { virtual std::string columnName( const size_t& ) const; - virtual Variant data( const ModelIndex& proxyIndex, Role = Role::Display ) const; + virtual Variant data( const ModelIndex& proxyIndex, ModelRole role = ModelRole::Display ) const; virtual ModelIndex parentIndex( const ModelIndex& ) const; @@ -46,9 +46,9 @@ class EE_API SortingProxyModel final : public Model, private Model::Client { ModelIndex mapToProxy( const ModelIndex& sourceIndex ) const; - Role sortRole() const; + ModelRole sortRole() const; - void setSortRrole( Role role ); + void setSortRrole( ModelRole role ); bool lessThan( const ModelIndex& index1, const ModelIndex& index2 ) const; @@ -86,7 +86,7 @@ class EE_API SortingProxyModel final : public Model, private Model::Client { std::map> mMappings; int mKeyColumn{ -1 }; SortOrder mSortOrder{ SortOrder::Ascending }; - Role mSortRole{ Role::Sort }; + ModelRole mSortRole{ ModelRole::Sort }; bool mSortingCaseSensitive{ false }; }; diff --git a/include/eepp/ui/models/widgettreemodel.hpp b/include/eepp/ui/models/widgettreemodel.hpp index 66f68e990..53fe932a5 100644 --- a/include/eepp/ui/models/widgettreemodel.hpp +++ b/include/eepp/ui/models/widgettreemodel.hpp @@ -17,7 +17,7 @@ class EE_API WidgetTreeModel : public Model { virtual size_t columnCount( const ModelIndex& = ModelIndex() ) const override; - virtual Variant data( const ModelIndex&, Role = Role::Display ) const override; + virtual Variant data( const ModelIndex&, ModelRole role = ModelRole::Display ) const override; virtual ModelIndex index( int row, int column, const ModelIndex& parent = ModelIndex() ) const override; diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index e6093f7e8..bf9d6a0c9 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -148,6 +148,7 @@ 2 false + false debug-test GenericProjectManager.GenericBuildConfiguration @@ -182,6 +183,7 @@ 2 false + false release-test GenericProjectManager.GenericBuildConfiguration @@ -222,6 +224,7 @@ 2 false + false debug-all GenericProjectManager.GenericBuildConfiguration @@ -262,6 +265,7 @@ 2 false + false release-all GenericProjectManager.GenericBuildConfiguration @@ -296,6 +300,7 @@ 2 false + false debug-win-all GenericProjectManager.GenericBuildConfiguration @@ -330,6 +335,7 @@ 2 false + false release-win-all GenericProjectManager.GenericBuildConfiguration @@ -364,6 +370,7 @@ 2 false + false debug-sound GenericProjectManager.GenericBuildConfiguration @@ -398,6 +405,7 @@ 2 false + false debug-sprites GenericProjectManager.GenericBuildConfiguration @@ -432,6 +440,7 @@ 2 false + false debug-fonts GenericProjectManager.GenericBuildConfiguration @@ -466,6 +475,7 @@ 2 false + false debug-vbo-fbo-batch GenericProjectManager.GenericBuildConfiguration @@ -500,6 +510,7 @@ 2 false + false debug-physics GenericProjectManager.GenericBuildConfiguration @@ -534,6 +545,7 @@ 2 false + false debug-http-request GenericProjectManager.GenericBuildConfiguration @@ -568,6 +580,7 @@ 2 false + false debug-static-lib GenericProjectManager.GenericBuildConfiguration @@ -609,6 +622,7 @@ 2 false + false debug-eeiv GenericProjectManager.GenericBuildConfiguration @@ -643,6 +657,7 @@ 2 false + false debug-ui-hello-world GenericProjectManager.GenericBuildConfiguration @@ -677,6 +692,7 @@ 2 false + false release-static-lib GenericProjectManager.GenericBuildConfiguration @@ -711,6 +727,7 @@ 2 false + false debug-dynamic-lib GenericProjectManager.GenericBuildConfiguration @@ -745,6 +762,7 @@ 2 false + false release-dynamic-lib GenericProjectManager.GenericBuildConfiguration @@ -787,6 +805,7 @@ 2 false + false debug-ew GenericProjectManager.GenericBuildConfiguration @@ -822,6 +841,7 @@ 2 false + false release-ew GenericProjectManager.GenericBuildConfiguration @@ -857,6 +877,7 @@ 2 false + false debug-es GenericProjectManager.GenericBuildConfiguration @@ -892,6 +913,7 @@ 2 false + false release-es GenericProjectManager.GenericBuildConfiguration @@ -1438,6 +1460,7 @@ 2 false + false Default GenericProjectManager.GenericBuildConfiguration diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 3382ac845..35e8eba60 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -343,7 +343,9 @@ ../../include/eepp/ui/models/itemlistmodel.hpp ../../include/eepp/ui/models/model.hpp ../../include/eepp/ui/models/modelindex.hpp +../../include/eepp/ui/models/modelrole.hpp ../../include/eepp/ui/models/modelselection.hpp +../../include/eepp/ui/models/persistentmodelindex.hpp ../../include/eepp/ui/models/sortingproxymodel.hpp ../../include/eepp/ui/models/widgettreemodel.hpp ../../include/eepp/ui/tools/textureatlaseditor.hpp @@ -818,7 +820,9 @@ ../../src/eepp/ui/keyboardshortcut.cpp ../../src/eepp/ui/models/filesystemmodel.cpp ../../src/eepp/ui/models/model.cpp +../../src/eepp/ui/models/modelindex.cpp ../../src/eepp/ui/models/modelselection.cpp +../../src/eepp/ui/models/persistentmodelindex.cpp ../../src/eepp/ui/models/sortingproxymodel.cpp ../../src/eepp/ui/models/widgettreemodel.cpp ../../src/eepp/ui/tools/textureatlaseditor.cpp diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index 7618c765f..9298d5a35 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -424,7 +424,7 @@ UIWidget* UIAbstractTableView::updateCell( const int& rowIndex, const ModelIndex UITableCell* cell = widget->asType(); cell->setCurIndex( index ); - Variant txt( getModel()->data( index, Model::Role::Display ) ); + Variant txt( getModel()->data( index, ModelRole::Display ) ); if ( txt.isValid() ) { if ( txt.is( Variant::Type::String ) ) cell->setText( txt.asString() ); @@ -433,7 +433,7 @@ UIWidget* UIAbstractTableView::updateCell( const int& rowIndex, const ModelIndex } bool isVisible = false; - Variant icon( getModel()->data( index, Model::Role::Icon ) ); + Variant icon( getModel()->data( index, ModelRole::Icon ) ); if ( icon.is( Variant::Type::Drawable ) && icon.asDrawable() ) { isVisible = true; cell->setIcon( icon.asDrawable() ); diff --git a/src/eepp/ui/abstract/uiabstractview.cpp b/src/eepp/ui/abstract/uiabstractview.cpp index 0b307a1a1..9c3c796b2 100644 --- a/src/eepp/ui/abstract/uiabstractview.cpp +++ b/src/eepp/ui/abstract/uiabstractview.cpp @@ -48,7 +48,7 @@ void UIAbstractView::modelUpdate( unsigned flags ) { if ( !getModel() || ( flags & Model::InvalidateAllIndexes ) ) { getSelection().clear(); } else { - getSelection().removeMatching( + getSelection().removeAllMatching( [this]( auto& index ) { return !getModel()->isValid( index ); } ); } } diff --git a/src/eepp/ui/models/filesystemmodel.cpp b/src/eepp/ui/models/filesystemmodel.cpp index 1419740f8..77040b722 100644 --- a/src/eepp/ui/models/filesystemmodel.cpp +++ b/src/eepp/ui/models/filesystemmodel.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,21 @@ FileSystemModel::Node* FileSystemModel::Node::findChildName( const std::string& return nullptr; } +FileSystemModel::Node FileSystemModel::Node::createChild( const std::string& childName, + const FileSystemModel& model ) { + std::string childPath( mInfo.getDirectoryPath() + childName ); + FileInfo file( childPath ); + auto child = Node( std::move( file ), this ); + + if ( model.getDisplayConfig().ignoreHidden && file.isHidden() ) + return {}; + + if ( model.getMode() == Mode::DirectoriesOnly && !file.isDirectory() ) + return {}; + + return child; +} + ModelIndex FileSystemModel::Node::index( const FileSystemModel& model, int column ) const { if ( !mParent ) return {}; @@ -113,6 +129,7 @@ void FileSystemModel::Node::refreshIfNeeded( const FileSystemModel& model ) { bool FileSystemModel::Node::fetchData( const String& fullPath ) { if ( mInfoDirty ) { mInfo = FileInfo( fullPath, mParent == nullptr ); + mName = FileSystem::fileNameFromPath( mInfo.getFilepath() ); mInfoDirty = false; } return true; @@ -131,9 +148,14 @@ FileSystemModel::FileSystemModel( const std::string& rootPath, const FileSystemM mMode( mode ), mDisplayConfig( displayConfig ) { mRoot = std::make_unique( mRootPath, *this ); + mInitOK = true; onModelUpdate(); } +FileSystemModel::~FileSystemModel() { + mInitOK = false; +} + const std::string& FileSystemModel::getRootPath() const { return mRootPath; } @@ -193,7 +215,7 @@ const FileSystemModel::Node& FileSystemModel::node( const ModelIndex& index ) co FileSystemModel::Node& FileSystemModel::nodeRef( const ModelIndex& index ) const { if ( !index.isValid() ) return *mRoot; - return *(Node*)index.data(); + return *(Node*)index.internalData(); } size_t FileSystemModel::rowCount( const ModelIndex& index ) const { @@ -248,15 +270,15 @@ static std::string permissionString( const FileInfo& info ) { return builder; } -Variant FileSystemModel::data( const ModelIndex& index, Model::Role role ) const { +Variant FileSystemModel::data( const ModelIndex& index, ModelRole role ) const { eeASSERT( index.isValid() ); auto& node = this->nodeRef( index ); - if ( role == Role::Custom ) + if ( role == ModelRole::Custom ) return Variant( node.info().getFilepath().c_str() ); - if ( role == Role::Sort ) { + if ( role == ModelRole::Sort ) { switch ( index.column() ) { case Column::Icon: return node.info().isDirectory() ? 0 : 1; @@ -283,7 +305,7 @@ Variant FileSystemModel::data( const ModelIndex& index, Model::Role role ) const } } - if ( role == Role::Display ) { + if ( role == ModelRole::Display ) { switch ( index.column() ) { case Column::Icon: return iconFor( node, index ); @@ -308,7 +330,7 @@ Variant FileSystemModel::data( const ModelIndex& index, Model::Role role ) const } } - if ( role == Role::Icon ) + if ( role == ModelRole::Icon ) return iconFor( node, index ); return {}; @@ -372,4 +394,90 @@ void FileSystemModel::setPreviouslySelectedIndex( const ModelIndex& previouslySe mPreviouslySelectedIndex = previouslySelectedIndex; } +void FileSystemModel::handleFileEvent( const FileEvent& event ) { + if ( !mInitOK ) + return; + + switch ( event.type ) { + case FileSystemEventType::Add: { + FileInfo file( event.directory + event.filename ); + auto* parent = getNodeFromPath( + file.isDirectory() ? FileSystem::removeLastFolderFromPath( file.getDirectoryPath() ) + : file.getDirectoryPath(), + true, false ); + + if ( parent ) { + auto* childNodeExists = + getNodeFromPath( file.getFilepath(), file.isDirectory(), false ); + if ( childNodeExists ) + return; + + size_t childCount = parent->childCount(); + + Node childNode = parent->createChild( file.getFilepath(), *this ); + + if ( !childNode.getName().empty() ) { + beginInsertRows( parent->index( *this, 0 ), childCount, childCount ); + + parent->mChildren.emplace_back( std::move( childNode ) ); + + endInsertRows(); + } else { + return; + } + } + break; + } + case FileSystemEventType::Delete: { + FileInfo file( event.directory + event.filename ); + + auto* child = getNodeFromPath( file.getFilepath(), file.isDirectory(), false ); + if ( !child ) + return; + + Node* parent = child->mParent; + if ( !parent ) + return; + + ModelIndex index = child->index( *this, 0 ); + if ( !index.isValid() ) + return; + + beginDeleteRows( index.parent(), index.row(), index.row() ); + + parent->mChildren.erase( parent->mChildren.begin() + index.row() ); + + endDeleteRows(); + + forEachView( [&]( UIAbstractView* view ) { + view->getSelection().removeAllMatching( [&]( auto& selectionIndex ) { + return selectionIndex.internalData() == index.internalData(); + } ); + } ); + + break; + } + case FileSystemEventType::Moved: { + FileInfo file( event.directory + event.filename ); + if ( file.exists() ) { + auto* node = getNodeFromPath( event.directory + event.oldFilename, + file.isDirectory(), false ); + if ( node ) { + node->mInfo = std::move( file ); + node->mName = FileSystem::fileNameFromPath( node->mInfo.getFilepath() ); + } else { + handleFileEvent( + { FileSystemEventType::Add, event.directory, event.filename } ); + } + } + break; + } + case FileSystemEventType::Modified: { + break; + } + } + + onModelUpdate( UpdateFlag::DontInvalidateIndexes ); +} + }}} // namespace EE::UI::Models diff --git a/src/eepp/ui/models/model.cpp b/src/eepp/ui/models/model.cpp index 313eeafa7..edf9aa023 100644 --- a/src/eepp/ui/models/model.cpp +++ b/src/eepp/ui/models/model.cpp @@ -1,12 +1,13 @@ #include #include +#include namespace EE { namespace UI { namespace Models { void Model::onModelUpdate( unsigned flags ) { if ( mOnUpdate ) mOnUpdate(); - for ( auto client : mClients ) + for ( auto& client : mClients ) client->onModelUpdated( flags ); forEachView( [&]( UIAbstractView* view ) { view->onModelUpdate( flags ); } ); } @@ -62,4 +63,345 @@ bool Model::acceptsDrag( const ModelIndex&, const std::string& ) { return false; } +void Model::beginInsertRows( ModelIndex const& parent, int first, int last ) { + eeASSERT( first >= 0 ); + eeASSERT( first <= last ); + mOperationStack.push( { OperationType::Insert, Direction::Row, parent, first, last } ); +} + +void Model::beginInsertColumns( ModelIndex const& parent, int first, int last ) { + eeASSERT( first >= 0 ); + eeASSERT( first <= last ); + mOperationStack.push( { OperationType::Insert, Direction::Column, parent, first, last } ); +} + +void Model::beginMoveRows( ModelIndex const& source_parent, int first, int last, + ModelIndex const& target_parent, int target_index ) { + eeASSERT( first >= 0 ); + eeASSERT( first <= last ); + eeASSERT( target_index >= 0 ); + mOperationStack.push( { OperationType::Move, Direction::Row, source_parent, first, last, + target_parent, target_index } ); +} + +void Model::beginMoveColumns( ModelIndex const& source_parent, int first, int last, + ModelIndex const& target_parent, int target_index ) { + eeASSERT( first >= 0 ); + eeASSERT( first <= last ); + eeASSERT( target_index >= 0 ); + mOperationStack.push( { OperationType::Move, Direction::Column, source_parent, first, last, + target_parent, target_index } ); +} + +void Model::beginDeleteRows( ModelIndex const& parent, int first, int last ) { + eeASSERT( first >= 0 ); + eeASSERT( first <= last ); + eeASSERT( (size_t)last < rowCount( parent ) ); + + saveDeletedIndices( parent, first, last ); + mOperationStack.push( { OperationType::Delete, Direction::Row, parent, first, last } ); +} + +void Model::beginDeleteColumns( ModelIndex const& parent, int first, int last ) { + eeASSERT( first >= 0 ); + eeASSERT( first <= last ); + eeASSERT( (size_t)last < columnCount( parent ) ); + + saveDeletedIndices( parent, first, last ); + mOperationStack.push( { OperationType::Delete, Direction::Column, parent, first, last } ); +} + +std::weak_ptr Model::registerPersistentIndex( ModelIndex const& index ) { + if ( !index.isValid() ) + return {}; + + auto it = mPersistentHandles.find( index ); + // Easy modo: we already have a handle for this model index. + if ( it != mPersistentHandles.end() ) { + return it->second; + } + + // Hard modo: create a new persistent handle. + auto handle = std::make_shared( index ); + std::weak_ptr weak_handle = handle; + mPersistentHandles[index] = std::move( handle ); + + return weak_handle; +} + +template +void Model::saveDeletedIndices( ModelIndex const& parent, int first, int last ) { + std::vector deleted_indices; + + for ( auto& entry : mPersistentHandles ) { + auto current_index = entry.first; + + // Walk up the persistent handle's parents to see if it is contained + // within the range that is being deleted. + while ( current_index.isValid() ) { + auto current_parent = current_index.parent(); + + if ( current_parent == parent ) { + if ( IsRow ) { + if ( current_index.row() >= first && current_index.row() <= last ) + deleted_indices.emplace_back( current_index ); + } else { + if ( current_index.column() >= first && current_index.column() <= last ) + deleted_indices.emplace_back( current_index ); + } + } + + current_index = current_parent; + } + } + + mDeletedIndicesStack.push( std::move( deleted_indices ) ); +} + +void Model::endInsertRows() { + auto operation = mOperationStack.top(); + mOperationStack.pop(); + eeASSERT( operation.type == OperationType::Insert ); + eeASSERT( operation.direction == Direction::Row ); + handleInsert( operation ); + + for ( auto& client : mClients ) { + client->modelDidInsertRows( operation.source_parent, operation.first, operation.last ); + } +} + +void Model::endInsertColumns() { + auto operation = mOperationStack.top(); + mOperationStack.pop(); + eeASSERT( operation.type == OperationType::Insert ); + eeASSERT( operation.direction == Direction::Column ); + handleInsert( operation ); + + for ( auto& client : mClients ) + client->modelDidInsertColumns( operation.source_parent, operation.first, operation.last ); +} + +void Model::endMoveRows() { + auto operation = mOperationStack.top(); + mOperationStack.pop(); + eeASSERT( operation.type == OperationType::Move ); + eeASSERT( operation.direction == Direction::Row ); + handleMove( operation ); + + for ( auto& client : mClients ) + client->modelDidMoveRows( operation.source_parent, operation.first, operation.last, + operation.target_parent, operation.target ); +} + +void Model::endMoveColumns() { + auto operation = mOperationStack.top(); + mOperationStack.pop(); + eeASSERT( operation.type == OperationType::Move ); + eeASSERT( operation.direction == Direction::Column ); + handleMove( operation ); + + for ( auto& client : mClients ) { + client->modeldidMoveColumns( operation.source_parent, operation.first, operation.last, + operation.target_parent, operation.target ); + } +} + +void Model::endDeleteRows() { + auto operation = mOperationStack.top(); + mOperationStack.pop(); + eeASSERT( operation.type == OperationType::Delete ); + eeASSERT( operation.direction == Direction::Row ); + handleDelete( operation ); + + for ( auto& client : mClients ) { + client->modelDidDeleteRows( operation.source_parent, operation.first, operation.last ); + } +} + +void Model::endDeleteColumns() { + auto operation = mOperationStack.top(); + mOperationStack.pop(); + eeASSERT( operation.type == OperationType::Delete ); + eeASSERT( operation.direction == Direction::Column ); + handleDelete( operation ); + + for ( auto& client : mClients ) { + client->modelDidDeleteColumns( operation.source_parent, operation.first, operation.last ); + } +} + +void Model::handleInsert( Operation const& operation ) { + bool is_row = operation.direction == Direction::Row; + std::vector to_shift; + + for ( auto& entry : mPersistentHandles ) { + if ( entry.first.parent() == operation.source_parent ) { + if ( is_row && entry.first.row() >= operation.first ) { + to_shift.emplace_back( &entry.first ); + } else if ( !is_row && entry.first.column() >= operation.first ) { + to_shift.emplace_back( &entry.first ); + } + } + } + + int offset = operation.last - operation.first + 1; + + for ( auto current_index : to_shift ) { + int new_row = is_row ? current_index->row() + offset : current_index->row(); + int new_column = is_row ? current_index->column() : current_index->column() + offset; + auto new_index = createIndex( new_row, new_column, current_index->internalData() ); + + auto it = mPersistentHandles.find( *current_index ); + auto handle = std::move( it->second ); + + handle->m_index = new_index; + + mPersistentHandles.erase( it ); + mPersistentHandles[std::move( new_index )] = std::move( handle ); + } +} + +void Model::handleDelete( Operation const& operation ) { + bool is_row = operation.direction == Direction::Row; + std::vector deleted_indices = mDeletedIndicesStack.top(); + mDeletedIndicesStack.pop(); + std::vector to_shift; + + // Get rid of all persistent handles which have been marked for death + for ( auto& deleted_index : deleted_indices ) { + mPersistentHandles.erase( deleted_index ); + } + + for ( auto& entry : mPersistentHandles ) { + if ( entry.first.parent() == operation.source_parent ) { + if ( is_row ) { + if ( entry.first.row() > operation.last ) { + to_shift.emplace_back( &entry.first ); + } + } else { + if ( entry.first.column() > operation.last ) { + to_shift.emplace_back( &entry.first ); + } + } + } + } + + int offset = operation.last - operation.first + 1; + + for ( auto current_index : to_shift ) { + int new_row = is_row ? current_index->row() - offset : current_index->row(); + int new_column = is_row ? current_index->column() : current_index->column() - offset; + auto new_index = createIndex( new_row, new_column, current_index->internalData() ); + + auto it = mPersistentHandles.find( *current_index ); + auto handle = std::move( it->second ); + + handle->m_index = new_index; + + mPersistentHandles.erase( it ); + mPersistentHandles[std::move( new_index )] = std::move( handle ); + } +} + +void Model::handleMove( Operation const& operation ) { + bool is_row = operation.direction == Direction::Row; + bool move_within = operation.source_parent == operation.target_parent; + bool moving_down = operation.target > operation.first; + + if ( move_within && operation.first == operation.target ) + return; + + if ( is_row ) { + eeASSERT( operation.target <= (int)rowCount( operation.target_parent ) ); + eeASSERT( operation.last < (int)rowCount( operation.source_parent ) ); + } else { + eeASSERT( operation.target <= (int)columnCount( operation.target_parent ) ); + eeASSERT( operation.last < (int)columnCount( operation.source_parent ) ); + } + + // NOTE: to_shift_down is used as a generic "to shift" when move_within is true. + std::vector to_move; // Items to be moved between the source and target + std::vector to_shift_down; // Items to be shifted down after a move-to + std::vector to_shift_up; // Items to be shifted up after a move-from + + int count = operation.last - operation.first + 1; + // [start, end) + int work_area_start = std::min( operation.first, operation.target ); + int work_area_end = std::max( operation.last + 1, operation.target + count ); + + for ( auto& entry : mPersistentHandles ) { + int dimension = is_row ? entry.first.row() : entry.first.column(); + + if ( move_within ) { + if ( entry.first.parent() == operation.source_parent ) { + if ( dimension >= operation.first && dimension <= operation.last ) { + to_move.emplace_back( &entry.first ); + } else if ( moving_down && dimension > operation.last && + dimension < work_area_end ) { + to_shift_down.emplace_back( &entry.first ); + } else if ( !moving_down && dimension >= work_area_start && + dimension < operation.first ) { + to_shift_down.emplace_back( &entry.first ); + } + } + } else { + if ( entry.first.parent() == operation.source_parent ) { + if ( dimension >= operation.first && dimension <= operation.last ) { + to_move.emplace_back( &entry.first ); + } else if ( dimension > operation.last ) { + to_shift_up.emplace_back( &entry.first ); + } + } else if ( entry.first.parent() == operation.target_parent ) { + if ( dimension >= operation.target ) { + to_shift_down.emplace_back( &entry.first ); + } + } + } + } + + auto replace_handle = [&]( ModelIndex const& current_index, int new_dimension, bool relative ) { + int new_row = is_row ? ( relative ? current_index.row() + new_dimension : new_dimension ) + : current_index.row(); + int new_column = !is_row + ? ( relative ? current_index.column() + new_dimension : new_dimension ) + : current_index.column(); + auto new_index = index( new_row, new_column, operation.target_parent ); + + auto it = mPersistentHandles.find( current_index ); + auto handle = std::move( it->second ); + + handle->m_index = new_index; + + mPersistentHandles.erase( it ); + mPersistentHandles[std::move( new_index )] = std::move( handle ); + }; + + for ( auto current_index : to_move ) { + int dimension = is_row ? current_index->row() : current_index->column(); + int target_offset = dimension - operation.first; + int new_dimension = operation.target + target_offset; + + replace_handle( *current_index, new_dimension, false ); + } + + if ( move_within ) { + for ( auto current_index : to_shift_down ) { + int dimension = is_row ? current_index->row() : current_index->column(); + int target_offset = moving_down ? dimension - ( operation.last + 1 ) + : dimension - work_area_start + count; + int new_dimension = work_area_start + target_offset; + + replace_handle( *current_index, new_dimension, false ); + } + } else { + for ( auto current_index : to_shift_down ) { + replace_handle( *current_index, count, true ); + } + + for ( auto current_index : to_shift_up ) { + replace_handle( *current_index, count, true ); + } + } +} + }}} // namespace EE::UI::Models diff --git a/src/eepp/ui/models/modelindex.cpp b/src/eepp/ui/models/modelindex.cpp new file mode 100644 index 000000000..27a809483 --- /dev/null +++ b/src/eepp/ui/models/modelindex.cpp @@ -0,0 +1,25 @@ +#include +#include +namespace EE { namespace UI { namespace Models { + +ModelIndex ModelIndex::sibling( int row, int column ) const { + if ( !isValid() ) + return {}; + eeASSERT( model() ); + return model()->index( row, column, parent() ); +} + +ModelIndex ModelIndex::siblingAtColumn( int column ) const { + if ( !isValid() ) + return {}; + return sibling( row(), column ); +} + +Variant ModelIndex::data( ModelRole role ) const { + if ( !isValid() ) + return {}; + eeASSERT( model() ); + return model()->data( *this, role ); +} + +}}} // namespace EE::UI::Models diff --git a/src/eepp/ui/models/modelselection.cpp b/src/eepp/ui/models/modelselection.cpp index 758d4c713..9cf119158 100644 --- a/src/eepp/ui/models/modelselection.cpp +++ b/src/eepp/ui/models/modelselection.cpp @@ -4,14 +4,14 @@ namespace EE { namespace UI { namespace Models { -void ModelSelection::removeMatching( std::function filter ) { - std::vector::iterator> toRemove; - for ( auto it = mIndexes.begin(); it != mIndexes.end(); it++ ) { - if ( filter( *it ) ) - toRemove.push_back( it ); +void ModelSelection::removeAllMatching( std::function filter ) { + std::vector notMatching; + for ( auto& index : mIndexes ) { + if ( !filter( index ) ) { + notMatching.emplace_back( index ); + } } - for ( auto& index : toRemove ) - mIndexes.erase( index ); + mIndexes = notMatching; } void ModelSelection::set( const ModelIndex& index ) { diff --git a/src/eepp/ui/models/persistentmodelindex.cpp b/src/eepp/ui/models/persistentmodelindex.cpp new file mode 100644 index 000000000..dca5e71c8 --- /dev/null +++ b/src/eepp/ui/models/persistentmodelindex.cpp @@ -0,0 +1,79 @@ +#include + +namespace EE { namespace UI { namespace Models { + +PersistentModelIndex::PersistentModelIndex( ModelIndex const& index ) { + if ( !index.isValid() ) + return; + + auto* model = const_cast( index.model() ); + m_handle = model->registerPersistentIndex( index ); +} + +int PersistentModelIndex::row() const { + if ( !hasValidHandle() ) + return -1; + return m_handle.lock()->m_index.row(); +} + +int PersistentModelIndex::column() const { + if ( !hasValidHandle() ) + return -1; + return m_handle.lock()->m_index.column(); +} + +PersistentModelIndex PersistentModelIndex::parent() const { + if ( !hasValidHandle() ) + return {}; + return { m_handle.lock()->m_index.parent() }; +} + +PersistentModelIndex PersistentModelIndex::siblingAtColumn( int column ) const { + if ( !hasValidHandle() ) + return {}; + + return { m_handle.lock()->m_index.siblingAtColumn( column ) }; +} + +Variant PersistentModelIndex::data( ModelRole role ) const { + if ( !hasValidHandle() ) + return {}; + return { m_handle.lock()->m_index.data( role ) }; +} + +PersistentModelIndex::operator ModelIndex() const { + if ( !hasValidHandle() ) + return {}; + else + return m_handle.lock()->m_index; +} + +bool PersistentModelIndex::operator==( PersistentModelIndex const& other ) const { + bool is_this_valid = hasValidHandle(); + bool is_other_valid = other.hasValidHandle(); + + if ( !is_this_valid && !is_other_valid ) + return true; + if ( is_this_valid != is_other_valid ) + return false; + + return m_handle.lock()->m_index == other.m_handle.lock()->m_index; +} + +bool PersistentModelIndex::operator!=( PersistentModelIndex const& other ) const { + return !( *this == other ); +} + +bool PersistentModelIndex::operator==( ModelIndex const& other ) const { + if ( !hasValidHandle() ) { + return !other.isValid(); + } + + return m_handle.lock()->m_index == other; +} + +bool PersistentModelIndex::operator!=( ModelIndex const& other ) const { + return !( *this == other ); +} + +}}} // namespace EE::UI::Models diff --git a/src/eepp/ui/models/sortingproxymodel.cpp b/src/eepp/ui/models/sortingproxymodel.cpp index d1ad009ec..c6488c553 100644 --- a/src/eepp/ui/models/sortingproxymodel.cpp +++ b/src/eepp/ui/models/sortingproxymodel.cpp @@ -58,9 +58,9 @@ ModelIndex SortingProxyModel::mapToSource( const ModelIndex& proxyIndex ) const return {}; eeASSERT( proxyIndex.model() == this ); - eeASSERT( proxyIndex.data() ); + eeASSERT( proxyIndex.internalData() ); - auto& indexMapping = *static_cast( proxyIndex.data() ); + auto& indexMapping = *static_cast( proxyIndex.internalData() ); auto it = mMappings.find( indexMapping.sourceParent ); eeASSERT( it != mMappings.end() ); @@ -119,11 +119,11 @@ ModelIndex SortingProxyModel::mapToProxy( const ModelIndex& sourceIndex ) const return createIndex( proxyRow, proxyColumn, &mapping ); } -Model::Role SortingProxyModel::sortRole() const { +ModelRole SortingProxyModel::sortRole() const { return mSortRole; } -void SortingProxyModel::setSortRrole( Model::Role role ) { +void SortingProxyModel::setSortRrole( ModelRole role ) { mSortRole = role; } @@ -131,7 +131,7 @@ std::string SortingProxyModel::columnName( const size_t& column ) const { return source().columnName( column ); } -Variant SortingProxyModel::data( const ModelIndex& proxyIndex, Role role ) const { +Variant SortingProxyModel::data( const ModelIndex& proxyIndex, ModelRole role ) const { auto targetIndex = mapToSource( proxyIndex ); eeASSERT( targetIndex.isValid() ); return source().data( targetIndex, role ); @@ -157,9 +157,9 @@ ModelIndex SortingProxyModel::parentIndex( const ModelIndex& proxyIndex ) const return {}; eeASSERT( proxyIndex.model() == this ); - eeASSERT( proxyIndex.data() ); + eeASSERT( proxyIndex.internalData() ); - auto& index_mapping = *static_cast( proxyIndex.data() ); + auto& index_mapping = *static_cast( proxyIndex.internalData() ); auto it = mMappings.find( index_mapping.sourceParent ); eeASSERT( it != mMappings.end() ); diff --git a/src/eepp/ui/models/widgettreemodel.cpp b/src/eepp/ui/models/widgettreemodel.cpp index e4e32fb3d..3bcc2a756 100644 --- a/src/eepp/ui/models/widgettreemodel.cpp +++ b/src/eepp/ui/models/widgettreemodel.cpp @@ -14,7 +14,7 @@ WidgetTreeModel::WidgetTreeModel( Node* node ) : mRoot( node ) { size_t WidgetTreeModel::rowCount( const ModelIndex& index ) const { if ( !index.isValid() ) return mRoot->getChildCount(); - Node* node = static_cast( index.data() ); + Node* node = static_cast( index.internalData() ); return node->getChildCount(); } @@ -22,10 +22,10 @@ size_t WidgetTreeModel::columnCount( const ModelIndex& ) const { return 1; } -Variant WidgetTreeModel::data( const ModelIndex& index, Model::Role role ) const { +Variant WidgetTreeModel::data( const ModelIndex& index, ModelRole role ) const { const char* EMPTY = ""; - Node* node = static_cast( index.data() ); - if ( role == Role::Display ) { + Node* node = static_cast( index.internalData() ); + if ( role == ModelRole::Display ) { if ( node->isWidget() ) { return Variant( node->asType()->getElementTag().c_str() ); } else if ( node->isUISceneNode() ) { @@ -42,14 +42,14 @@ Variant WidgetTreeModel::data( const ModelIndex& index, Model::Role role ) const ModelIndex WidgetTreeModel::index( int row, int column, const ModelIndex& parent ) const { if ( !parent.isValid() ) return createIndex( row, column, mRoot ); - Node* parentNode = static_cast( parent.data() ); + Node* parentNode = static_cast( parent.internalData() ); return createIndex( row, column, parentNode->getChildAt( row ) ); } ModelIndex WidgetTreeModel::parentIndex( const ModelIndex& index ) const { if ( !index.isValid() ) return {}; - Node* node = static_cast( index.data() ); + Node* node = static_cast( index.internalData() ); if ( node == mRoot ) return {}; return createIndex( node->getParent()->getNodeIndex(), 0, node->getParent() ); diff --git a/src/eepp/ui/uifiledialog.cpp b/src/eepp/ui/uifiledialog.cpp index 9ff90f0bc..a45a0f6ce 100644 --- a/src/eepp/ui/uifiledialog.cpp +++ b/src/eepp/ui/uifiledialog.cpp @@ -148,7 +148,7 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa const ModelEvent* modelEvent = static_cast( event ); if ( modelEvent->getModelEventType() == ModelEventType::Open ) { Variant vPath( - modelEvent->getModel()->data( modelEvent->getModelIndex(), Model::Role::Custom ) ); + modelEvent->getModel()->data( modelEvent->getModelIndex(), ModelRole::Custom ) ); if ( vPath.isValid() && vPath.is( Variant::Type::cstr ) ) { bool shouldOpenFolder = false; if ( getAllowFolderSelect() && modelEvent->getTriggerEvent() && diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index d0d86642c..614d838d6 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -31,12 +31,12 @@ bool UITreeView::isType( const Uint32& type ) const { UITreeView::MetadataForIndex& UITreeView::getIndexMetadata( const ModelIndex& index ) const { eeASSERT( index.isValid() ); - auto it = mViewMetadata.find( index.data() ); + auto it = mViewMetadata.find( index.internalData() ); if ( it != mViewMetadata.end() ) return it->second; auto newMetadata = MetadataForIndex(); - mViewMetadata.insert( { index.data(), std::move( newMetadata ) } ); - return mViewMetadata[index.data()]; + mViewMetadata.insert( { index.internalData(), std::move( newMetadata ) } ); + return mViewMetadata[index.internalData()]; } void UITreeView::traverseTree( TreeViewCallback callback ) const { @@ -185,7 +185,7 @@ UIWidget* UITreeView::updateCell( const int& rowIndex, const ModelIndex& index, UITableCell* cell = widget->asType(); cell->setCurIndex( index ); - Variant txt( getModel()->data( index, Model::Role::Display ) ); + Variant txt( getModel()->data( index, ModelRole::Display ) ); if ( txt.isValid() ) { if ( txt.is( Variant::Type::String ) ) cell->setText( txt.asString() ); @@ -236,7 +236,7 @@ UIWidget* UITreeView::updateCell( const int& rowIndex, const ModelIndex& index, } bool isVisible = false; - Variant icon( getModel()->data( index, Model::Role::Icon ) ); + Variant icon( getModel()->data( index, ModelRole::Icon ) ); if ( icon.is( Variant::Type::Drawable ) && icon.asDrawable() ) { isVisible = true; cell->setIcon( icon.asDrawable() ); diff --git a/src/tests/ui_perf_test/ui_perf_test.cpp b/src/tests/ui_perf_test/ui_perf_test.cpp index f9c0bb2a8..70d898766 100644 --- a/src/tests/ui_perf_test/ui_perf_test.cpp +++ b/src/tests/ui_perf_test/ui_perf_test.cpp @@ -58,7 +58,7 @@ class TestModel : public Model { const NodeT& node( const ModelIndex& index ) const { if ( !index.isValid() ) return mRoot; - return *(NodeT*)index.data(); + return *(NodeT*)index.internalData(); } ModelIndex index( int row, int column, const ModelIndex& parent ) const { @@ -74,12 +74,12 @@ class TestModel : public Model { return String::format( "Column %ld", column ); } - virtual Variant data( const ModelIndex& index, Role role = Role::Display ) const { + virtual Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const { switch ( role ) { - case Role::Display: { + case ModelRole::Display: { return Variant( String::format( "Test %lld-%lld", index.row(), index.column() ) ); } - case Role::Icon: { + case ModelRole::Icon: { if ( index.column() == 0 && rowCount( index ) == 0 ) { return Variant( SceneManager::instance() ->getUISceneNode() @@ -141,7 +141,7 @@ void mainLoop() { } } -EE_MAIN_FUNC int main( int argc, char* argv[] ) { +EE_MAIN_FUNC int main( int, char*[] ) { win = Engine::instance()->createWindow( WindowSettings( 1024, 768, "eepp - UI Perf Test" ), ContextSettings( true ) ); diff --git a/src/tools/codeeditor/codeeditor.cpp b/src/tools/codeeditor/codeeditor.cpp index 8eacae94e..37f1ba657 100644 --- a/src/tools/codeeditor/codeeditor.cpp +++ b/src/tools/codeeditor/codeeditor.cpp @@ -1717,7 +1717,7 @@ void App::initProjectTreeView( const std::string& path ) { const ModelEvent* modelEvent = static_cast( event ); if ( modelEvent->getModelEventType() == ModelEventType::Open ) { Variant vPath( - modelEvent->getModel()->data( modelEvent->getModelIndex(), Model::Role::Custom ) ); + modelEvent->getModel()->data( modelEvent->getModelIndex(), ModelRole::Custom ) ); if ( vPath.isValid() && vPath.is( Variant::Type::cstr ) ) { std::string path( vPath.asCStr() ); UITab* tab = mEditorSplitter->isDocumentOpen( path ); diff --git a/src/tools/codeeditor/filelocator.cpp b/src/tools/codeeditor/filelocator.cpp index 908f65423..71977c43d 100644 --- a/src/tools/codeeditor/filelocator.cpp +++ b/src/tools/codeeditor/filelocator.cpp @@ -98,7 +98,7 @@ void FileLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locateInpu if ( modelEvent->getModelEventType() == ModelEventType::Open ) { Variant vPath( modelEvent->getModel()->data( modelEvent->getModel()->index( modelEvent->getModelIndex().row(), 1 ), - Model::Role::Display ) ); + ModelRole::Display ) ); if ( vPath.isValid() && vPath.is( Variant::Type::cstr ) ) { std::string path( vPath.asCStr() ); UITab* tab = mEditorSplitter->isDocumentOpen( path ); diff --git a/src/tools/codeeditor/filesystemlistener.cpp b/src/tools/codeeditor/filesystemlistener.cpp index 593622bab..8914c0f03 100644 --- a/src/tools/codeeditor/filesystemlistener.cpp +++ b/src/tools/codeeditor/filesystemlistener.cpp @@ -13,7 +13,7 @@ void FileSystemListener::handleFileAction( efsw::WatchID, const std::string& dir case efsw::Actions::Add: case efsw::Actions::Delete: case efsw::Actions::Moved: { - auto* node = mFileSystemModel.get()->getNodeFromPath( + /*auto* node = mFileSystemModel.get()->getNodeFromPath( file.isDirectory() ? FileSystem::removeLastFolderFromPath( file.getDirectoryPath() ) : file.getDirectoryPath(), true, false ); @@ -21,7 +21,9 @@ void FileSystemListener::handleFileAction( efsw::WatchID, const std::string& dir !file.isHidden() ) ) { node->invalidate(); mFileSystemModel.get()->invalidate(); - } + }*/ + FileEvent event( (FileSystemEventType)action, dir, filename, oldFilename ); + mFileSystemModel.get()->handleFileEvent( event ); if ( mDirTree ) mDirTree.get()->onChange( (ProjectDirectoryTree::Action)action, file, oldFilename ); diff --git a/src/tools/codeeditor/globalsearchcontroller.cpp b/src/tools/codeeditor/globalsearchcontroller.cpp index c1047222a..533b09b54 100644 --- a/src/tools/codeeditor/globalsearchcontroller.cpp +++ b/src/tools/codeeditor/globalsearchcontroller.cpp @@ -409,7 +409,7 @@ void GlobalSearchController::initGlobalSearchTree( UITreeViewGlobalSearch* searc Variant vPath( model->data( model->index( modelEvent->getModelIndex().internalId(), ProjectSearch::ResultModel::FileOrPosition ), - Model::Role::Custom ) ); + ModelRole::Custom ) ); if ( vPath.isValid() && vPath.is( Variant::Type::cstr ) ) { std::string path( vPath.asCStr() ); UITab* tab = mEditorSplitter->isDocumentOpen( path ); @@ -424,11 +424,11 @@ void GlobalSearchController::initGlobalSearchTree( UITreeViewGlobalSearch* searc model->data( model->index( modelEvent->getModelIndex().row(), ProjectSearch::ResultModel::FileOrPosition, modelEvent->getModelIndex().parent() ), - Model::Role::Custom ) ); + ModelRole::Custom ) ); Variant colNum( model->data( model->index( modelEvent->getModelIndex().row(), ProjectSearch::ResultModel::ColumnStart, modelEvent->getModelIndex().parent() ), - Model::Role::Custom ) ); + ModelRole::Custom ) ); if ( mEditorSplitter->getCurEditor() && lineNum.isValid() && colNum.isValid() && lineNum.is( Variant::Type::Int64 ) && colNum.is( Variant::Type::Int64 ) ) { TextPosition pos{ lineNum.asInt64(), colNum.asInt64() }; diff --git a/src/tools/codeeditor/projectdirectorytree.hpp b/src/tools/codeeditor/projectdirectorytree.hpp index f6d2d68ef..678bf32ce 100644 --- a/src/tools/codeeditor/projectdirectorytree.hpp +++ b/src/tools/codeeditor/projectdirectorytree.hpp @@ -29,8 +29,8 @@ class FileListModel : public Model { return index == 0 ? "Name" : "Path"; } - virtual Variant data( const ModelIndex& index, Role role = Role::Display ) const { - if ( role == Role::Display && index.row() < (Int64)mFiles.size() ) { + virtual Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const { + if ( role == ModelRole::Display && index.row() < (Int64)mFiles.size() ) { return Variant( index.column() == 0 ? mNames[index.row()].c_str() : mFiles[index.row()].c_str() ); } diff --git a/src/tools/codeeditor/projectsearch.hpp b/src/tools/codeeditor/projectsearch.hpp index 6899bab1e..423bb5249 100644 --- a/src/tools/codeeditor/projectsearch.hpp +++ b/src/tools/codeeditor/projectsearch.hpp @@ -82,7 +82,7 @@ class ProjectSearch { return {}; if ( !parent.isValid() ) return createIndex( row, column, &mResult[row], -1 ); - if ( parent.data() ) + if ( parent.internalData() ) return createIndex( row, column, &mResult[parent.row()].results[row], parent.row() ); return {}; @@ -109,9 +109,9 @@ class ProjectSearch { return count; } - Variant data( const ModelIndex& index, Role role = Role::Display ) const { + Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const { static const char* EMPTY = ""; - if ( role == Role::Display ) { + if ( role == ModelRole::Display ) { if ( index.internalId() == -1 ) { if ( index.column() == FileOrPosition ) { return Variant( String::format( "%s (%zu)", @@ -133,7 +133,7 @@ class ProjectSearch { .c_str() ) ); } } - } else if ( role == Role::Custom ) { + } else if ( role == ModelRole::Custom ) { if ( index.internalId() != -1 ) { switch ( index.column() ) { case FileOrPosition: diff --git a/src/tools/codeeditor/uitreeviewglobalsearch.cpp b/src/tools/codeeditor/uitreeviewglobalsearch.cpp index 1f441f5cc..632eed54f 100644 --- a/src/tools/codeeditor/uitreeviewglobalsearch.cpp +++ b/src/tools/codeeditor/uitreeviewglobalsearch.cpp @@ -77,7 +77,7 @@ void* UITreeViewCellGlobalSearch::getDataPtr( const ModelIndex& modelIndex ) { static_cast( modelIndex.model() ); ModelIndex index = model->index( modelIndex.row(), ProjectSearch::ResultModel::Data, modelIndex.parent() ); - Variant var( model->data( index, Model::Role::Custom ) ); + Variant var( model->data( index, ModelRole::Custom ) ); if ( var.is( Variant::Type::DataPtr ) ) return var.asDataPtr(); return nullptr; @@ -122,7 +122,7 @@ UIPushButton* UITreeViewCellGlobalSearch::updateText( const std::string& text ) if ( getCurIndex().internalId() != -1 ) { UITreeViewGlobalSearch* pp = getParent()->getParent()->asType(); - ProjectSearch::ResultData* res = (ProjectSearch::ResultData*)getCurIndex().parent().data(); + ProjectSearch::ResultData* res = (ProjectSearch::ResultData*)getCurIndex().parent().internalData(); auto styleDef = SyntaxDefinitionManager::instance()->getStyleByExtension( res->file );