1 // This may look like C code, but it's really -*- C++ -*- 2 /* 3 * Copyright (C) 2008 Emweb bv, Herent, Belgium. 4 * 5 * See the LICENSE file for terms of use. 6 */ 7 #ifndef GIT_MODEL_H_ 8 #define GIT_MODEL_H_ 9 10 #include <Wt/WAbstractItemModel.h> 11 12 #include "Git.h" 13 14 using namespace Wt; 15 16 /** 17 * @addtogroup gitmodelexample 18 */ 19 /*@{*/ 20 21 /*! \class GitModel 22 * \brief A model that retrieves revision trees from a git repository. 23 * 24 * In its present form, it presents only a single column of data: the 25 * file names. Additional data could be easily added. Git "tree" objects 26 * correspond to folders, and "blob" objects to files. 27 * 28 * The model is read-only, does not support sorting (that could be 29 * provided by using a WSortFilterProxyModel). 30 * 31 * The model loads only minimal information in memory: to create model indexes 32 * for folders. These cannot be uniquely identified by their SHA1 id, since 33 * two identical folders at different locations would have the same SHA1 id. 34 * 35 * The internal id of model indexes created by the model uniquely identify 36 * a containing folder for a particular file. 37 */ 38 class GitModel : public Wt::WAbstractItemModel 39 { 40 public: 41 /*! \brief The role which may be used on a file to retrieve its contents. 42 */ 43 static const ItemDataRole ContentsRole; 44 static const ItemDataRole FilePathRole; 45 46 /*! \brief Constructor. 47 */ 48 GitModel(); 49 50 /*! \brief Set the repository and load its 'master' revision. 51 */ 52 void setRepositoryPath(const std::string& repositoryPath); 53 54 /*! \brief Load a particular revision. 55 * 56 * The revision name may be any revision accepted by git, by 57 * git-rev-parse(1). 58 */ 59 void loadRevision(const std::string& revName); 60 61 /*! \brief Returns the parent index. 62 * 63 * Consults the internal data structure to find the parent index. 64 */ 65 virtual WModelIndex parent(const WModelIndex& index) const; 66 67 /*! \brief Returns the column count. 68 * 69 * Returns 1. 70 */ 71 virtual int columnCount(const WModelIndex& parent = WModelIndex()) 72 const; 73 74 /*! \brief Returns the row count. 75 * 76 * Returns 0 unless the item represents a folder, in which case it returns 77 * the number of items in the tree object that corresponds to the folder. 78 */ 79 virtual int rowCount(const WModelIndex& parent = WModelIndex()) const; 80 81 /*! \brief Returns a child index. 82 * 83 * Consults the internal data structure to create a child index. If 84 * necessary, the internal data structure is expanded by adding an 85 * entry for using the <i>parent</i> index as a parent index. 86 */ 87 virtual WModelIndex 88 index(int row, int column, const WModelIndex& parent = WModelIndex()) 89 const; 90 91 /*! \brief Returns data. 92 * 93 * Returns only data corresponding to DisplayRole and ContentsRole. 94 */ 95 virtual cpp17::any 96 data(const WModelIndex& index, ItemDataRole role = ItemDataRole::Display) const; 97 98 /*! \brief Returns header data. 99 */ 100 virtual cpp17::any 101 headerData(int section, Orientation orientation = Orientation::Horizontal, 102 ItemDataRole role = ItemDataRole::Display) const; 103 104 using WAbstractItemModel::data; 105 106 private: 107 /*! \brief The git repository. */ 108 Git git_; 109 110 /*! \class ChildIndex 111 * \brief Index usable as a key to a map, that identifies a child/row 112 * within a tree. 113 */ 114 struct ChildIndex { 115 int parentId; 116 int index; 117 ChildIndexChildIndex118 ChildIndex(int aParent, int anIndex) 119 : parentId(aParent), index(anIndex) { } 120 121 bool operator< (const ChildIndex& other) const { 122 if (parentId < other.parentId) 123 return true; 124 else if (parentId > other.parentId) 125 return false; 126 else return index < other.index; 127 } 128 }; 129 130 /*! \class Tree 131 * \brief Used to uniquely locate a folder within the folder hierarchy. 132 */ 133 class Tree { 134 public: 135 /*! \brief Constructor. 136 */ Tree(int parentId,int index,const Git::ObjectId & object,int rowCount)137 Tree(int parentId, int index, const Git::ObjectId& object, 138 int rowCount) 139 : index_(parentId, index), 140 treeObject_(object), 141 rowCount_(rowCount) 142 { } 143 144 /*! \brief Returns the parent id. 145 * 146 * Index of the parent folder within the treeData_ vector. 147 */ parentId()148 int parentId() const { return index_.parentId; } 149 150 /*! \brief Returns the child index within the parent folder. 151 * 152 * Index of this folder within the file list of the parent folder. 153 */ index()154 int index() const { return index_.index; } 155 156 /*! \brief Returns the SHA1 id for the git tree object. 157 */ treeObject()158 const Git::ObjectId& treeObject() const { return treeObject_; } 159 160 /*! \brief Returns the (cached) row count. 161 */ rowCount()162 int rowCount() const { return rowCount_; } 163 164 private: 165 ChildIndex index_; 166 Git::ObjectId treeObject_; 167 int rowCount_; 168 }; 169 170 typedef std::map<ChildIndex, int> ChildPointerMap; 171 172 /*! \brief List of folder objects. 173 * 174 * This list contains folders for which a model index has been allocated. 175 * 176 * Model indexes have an internal id that are indexes into this vector, 177 * identifying the folder that contains a particular file. 178 * 179 * Note: only for folders this is needed, since files will never be used 180 * as a 'parent' index. 181 * 182 * It is populated on-the-fly, as the user navigates the model. 183 */ 184 mutable std::vector<Tree> treeData_; 185 186 /*! \brief Maps child indexes to tree indexes. 187 * 188 * This map provides a way to lookup data in treeData_. It has an entry 189 * corresponding to every entry in treeData_: it maps child indexes for 190 * folders to indexes in the treeData_ vector. 191 * 192 * It is populated on-the-fly, as the user navigates the model. 193 */ 194 mutable ChildPointerMap childPointer_; 195 196 /*! \brief Get or allocate an id for a folder. 197 * 198 * The folder is identified by a given childIndex within a parent 199 * folder. This method adds data to the treeData_ (and 200 * childPointer_) data structures. 201 */ 202 int getTreeId(int parentId, int childIndex) const; 203 204 /*! \brief Get the Git::Object that corresponds to an index. 205 */ 206 Git::Object getObject(const WModelIndex& index) const; 207 }; 208 209 /*@}*/ 210 211 #endif // GIT_MODEL_H_ 212