This commit is contained in:
Martín Lucas Golini
2022-01-18 22:39:00 -03:00
parent 7667d58076
commit ff2fd46638
30 changed files with 855 additions and 72 deletions

View File

@@ -1,6 +1,7 @@
#ifndef EE_UI_MODELS_FILESYSTEMMODEL_HPP
#define EE_UI_MODELS_FILESYSTEMMODEL_HPP
#include <atomic>
#include <eepp/system/fileinfo.hpp>
#include <eepp/ui/models/model.hpp>
#include <eepp/ui/uiicon.hpp>
@@ -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<bool> mInitOK;
std::string mRootPath;
std::string mRealRootPath;
std::unique_ptr<Node> 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

View File

@@ -21,8 +21,8 @@ template <typename T> 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 {};
}

View File

@@ -2,8 +2,11 @@
#define EE_UI_MODELS_MODEL_HPP
#include <eepp/ui/models/modelindex.hpp>
#include <eepp/ui/models/modelrole.hpp>
#include <eepp/ui/models/variant.hpp>
#include <functional>
#include <memory>
#include <stack>
#include <string>
#include <unordered_set>
@@ -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<PersistentHandle> 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 <bool IsRow> void saveDeletedIndices( ModelIndex const& parent, int first, int last );
std::map<ModelIndex, std::shared_ptr<PersistentHandle>> mPersistentHandles;
std::stack<Operation> 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<std::vector<ModelIndex>> mDeletedIndicesStack;
private:
std::unordered_set<UIAbstractView*> mViews;
std::unordered_set<Client*> mClients;

View File

@@ -2,6 +2,9 @@
#define EE_UI_MODEL_MODELINDEX_HPP
#include <eepp/config.hpp>
#include <eepp/core/core.hpp>
#include <eepp/ui/models/modelrole.hpp>
#include <eepp/ui/models/variant.hpp>
#include <limits>
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 };

View File

@@ -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

View File

@@ -60,7 +60,7 @@ class EE_API ModelSelection {
return *mIndexes.begin();
}
void removeMatching( std::function<bool( const ModelIndex& )> );
void removeAllMatching( std::function<bool( ModelIndex const& )> filter );
template <typename Function> void changeFromModel( Function f ) {
{
@@ -76,8 +76,8 @@ class EE_API ModelSelection {
protected:
UIAbstractView* mView;
std::vector<ModelIndex> mIndexes;
bool mDisableNotify{false};
bool mNotifyPending{false};
bool mDisableNotify{ false };
bool mNotifyPending{ false };
void notifySelectionChanged();
};

View File

@@ -0,0 +1,59 @@
#ifndef EE_UI_MODEL_PERSISTENTMODELINDEX_HPP
#define EE_UI_MODEL_PERSISTENTMODELINDEX_HPP
#include <eepp/ui/models/model.hpp>
#include <eepp/ui/models/modelindex.hpp>
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<PersistentHandle> m_handle;
};
}}} // namespace EE::UI::Models
#endif // EE_UI_MODEL_PERSISTENTMODELINDEX_HPP

View File

@@ -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<ModelIndex, std::shared_ptr<Mapping>> mMappings;
int mKeyColumn{ -1 };
SortOrder mSortOrder{ SortOrder::Ascending };
Role mSortRole{ Role::Sort };
ModelRole mSortRole{ ModelRole::Sort };
bool mSortingCaseSensitive{ false };
};

View File

@@ -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;

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 5.0.2, 2021-11-10T19:23:21. -->
<!-- Written by QtCreator 6.0.1, 2022-01-07T02:26:18. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
@@ -148,6 +148,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-test</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -182,6 +183,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">release-test</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -222,6 +224,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-all</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -262,6 +265,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">release-all</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -296,6 +300,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-win-all</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -330,6 +335,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">release-win-all</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -364,6 +370,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-sound</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -398,6 +405,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-sprites</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -432,6 +440,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-fonts</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -466,6 +475,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-vbo-fbo-batch</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -500,6 +510,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-physics</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -534,6 +545,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-http-request</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -568,6 +580,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-static-lib</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -609,6 +622,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-eeiv</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -643,6 +657,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-ui-hello-world</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -677,6 +692,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">release-static-lib</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -711,6 +727,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-dynamic-lib</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -745,6 +762,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">release-dynamic-lib</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -787,6 +805,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-ew</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -822,6 +841,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">release-ew</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -857,6 +877,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug-es</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -892,6 +913,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">release-es</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
@@ -1438,6 +1460,7 @@
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Default</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>

View File

@@ -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

View File

@@ -424,7 +424,7 @@ UIWidget* UIAbstractTableView::updateCell( const int& rowIndex, const ModelIndex
UITableCell* cell = widget->asType<UITableCell>();
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() );

View File

@@ -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 ); } );
}
}

View File

@@ -2,6 +2,7 @@
#include <eepp/scene/scenemanager.hpp>
#include <eepp/system/filesystem.hpp>
#include <eepp/system/sys.hpp>
#include <eepp/ui/abstract/uiabstractview.hpp>
#include <eepp/ui/models/filesystemmodel.hpp>
#include <eepp/ui/uiscenenode.hpp>
#include <iomanip>
@@ -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<Node>( 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

View File

@@ -1,12 +1,13 @@
#include <eepp/ui/abstract/uiabstractview.hpp>
#include <eepp/ui/models/model.hpp>
#include <eepp/ui/models/persistentmodelindex.hpp>
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<true>( 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<false>( parent, first, last );
mOperationStack.push( { OperationType::Delete, Direction::Column, parent, first, last } );
}
std::weak_ptr<PersistentHandle> 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<PersistentHandle>( index );
std::weak_ptr<PersistentHandle> weak_handle = handle;
mPersistentHandles[index] = std::move( handle );
return weak_handle;
}
template <bool IsRow>
void Model::saveDeletedIndices( ModelIndex const& parent, int first, int last ) {
std::vector<ModelIndex> 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<const ModelIndex*> 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<ModelIndex> deleted_indices = mDeletedIndicesStack.top();
mDeletedIndicesStack.pop();
std::vector<const ModelIndex*> 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<const ModelIndex*> to_move; // Items to be moved between the source and target
std::vector<const ModelIndex*> to_shift_down; // Items to be shifted down after a move-to
std::vector<const ModelIndex*> 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

View File

@@ -0,0 +1,25 @@
#include <eepp/ui/models/model.hpp>
#include <eepp/ui/models/modelindex.hpp>
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

View File

@@ -4,14 +4,14 @@
namespace EE { namespace UI { namespace Models {
void ModelSelection::removeMatching( std::function<bool( const ModelIndex& )> filter ) {
std::vector<std::vector<ModelIndex>::iterator> toRemove;
for ( auto it = mIndexes.begin(); it != mIndexes.end(); it++ ) {
if ( filter( *it ) )
toRemove.push_back( it );
void ModelSelection::removeAllMatching( std::function<bool( const ModelIndex& )> filter ) {
std::vector<ModelIndex> 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 ) {

View File

@@ -0,0 +1,79 @@
#include <eepp/ui/models/persistentmodelindex.hpp>
namespace EE { namespace UI { namespace Models {
PersistentModelIndex::PersistentModelIndex( ModelIndex const& index ) {
if ( !index.isValid() )
return;
auto* model = const_cast<Model*>( 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

View File

@@ -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<Mapping*>( proxyIndex.data() );
auto& indexMapping = *static_cast<Mapping*>( 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<Mapping*>( proxyIndex.data() );
auto& index_mapping = *static_cast<Mapping*>( proxyIndex.internalData() );
auto it = mMappings.find( index_mapping.sourceParent );
eeASSERT( it != mMappings.end() );

View File

@@ -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<Node*>( index.data() );
Node* node = static_cast<Node*>( 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<Node*>( index.data() );
if ( role == Role::Display ) {
Node* node = static_cast<Node*>( index.internalData() );
if ( role == ModelRole::Display ) {
if ( node->isWidget() ) {
return Variant( node->asType<UIWidget>()->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<Node*>( parent.data() );
Node* parentNode = static_cast<Node*>( parent.internalData() );
return createIndex( row, column, parentNode->getChildAt( row ) );
}
ModelIndex WidgetTreeModel::parentIndex( const ModelIndex& index ) const {
if ( !index.isValid() )
return {};
Node* node = static_cast<Node*>( index.data() );
Node* node = static_cast<Node*>( index.internalData() );
if ( node == mRoot )
return {};
return createIndex( node->getParent()->getNodeIndex(), 0, node->getParent() );

View File

@@ -148,7 +148,7 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa
const ModelEvent* modelEvent = static_cast<const ModelEvent*>( 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() &&

View File

@@ -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<UITableCell>();
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() );

View File

@@ -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 ) );

View File

@@ -1717,7 +1717,7 @@ void App::initProjectTreeView( const std::string& path ) {
const ModelEvent* modelEvent = static_cast<const ModelEvent*>( 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 );

View File

@@ -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 );

View File

@@ -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 );

View File

@@ -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() };

View File

@@ -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() );
}

View File

@@ -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:

View File

@@ -77,7 +77,7 @@ void* UITreeViewCellGlobalSearch::getDataPtr( const ModelIndex& modelIndex ) {
static_cast<const ProjectSearch::ResultModel*>( 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<UITreeViewGlobalSearch>();
ProjectSearch::ResultData* res = (ProjectSearch::ResultData*)getCurIndex().parent().data();
ProjectSearch::ResultData* res = (ProjectSearch::ResultData*)getCurIndex().parent().internalData();
auto styleDef = SyntaxDefinitionManager::instance()->getStyleByExtension( res->file );