forked from qt-creator/qt-creator
delete DetailedModel - it is unused
This commit is contained in:
@@ -136,487 +136,6 @@ bool sortNodes(Node *n1, Node *n2)
|
||||
|
||||
} // namespace anon
|
||||
|
||||
/*!
|
||||
\class DetailedModel
|
||||
|
||||
A 1:1 mapping of the internal node tree.
|
||||
|
||||
The detailed model shows the complete project file hierarchy and all containing files.
|
||||
*/
|
||||
|
||||
DetailedModel::DetailedModel(SessionNode *rootNode, QObject *parent)
|
||||
: QAbstractItemModel(parent),
|
||||
m_rootNode(rootNode),
|
||||
//m_startupProject(0),
|
||||
m_folderToAddTo(0)
|
||||
{
|
||||
NodesWatcher *watcher = new NodesWatcher(this);
|
||||
m_rootNode->registerWatcher(watcher);
|
||||
connect(watcher, SIGNAL(foldersAboutToBeAdded(FolderNode*, const QList<FolderNode*> &)),
|
||||
this, SLOT(foldersAboutToBeAdded(FolderNode*, const QList<FolderNode*> &)));
|
||||
connect(watcher, SIGNAL(foldersAdded()),
|
||||
this, SLOT(foldersAdded()));
|
||||
connect(watcher, SIGNAL(foldersAboutToBeRemoved(FolderNode*, const QList<FolderNode*> &)),
|
||||
this, SLOT(foldersAboutToBeRemoved(FolderNode*, const QList<FolderNode*> &)));
|
||||
connect(watcher, SIGNAL(filesAboutToBeAdded(FolderNode*, const QList<FileNode*> &)),
|
||||
this, SLOT(filesAboutToBeAdded(FolderNode*, const QList<FileNode*> &)));
|
||||
connect(watcher, SIGNAL(filesAdded()),
|
||||
this, SLOT(filesAdded()));
|
||||
connect(watcher, SIGNAL(filesAboutToBeRemoved(FolderNode*, const QList<FileNode*> &)),
|
||||
this, SLOT(filesAboutToBeRemoved(FolderNode*, const QList<FileNode*> &)));
|
||||
}
|
||||
|
||||
QModelIndex DetailedModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
QModelIndex result;
|
||||
if (!parent.isValid() && row == 0 && column == 0) {
|
||||
result = createIndex(0, 0, m_rootNode);
|
||||
} else if (column == 0) {
|
||||
FolderNode *parentNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
|
||||
Q_ASSERT(parentNode);
|
||||
result = createIndex(row, 0, m_childNodes.value(parentNode).at(row));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QModelIndex DetailedModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
QModelIndex parentIndex;
|
||||
|
||||
if (Node *node = nodeForIndex(index)) {
|
||||
if (FolderNode *parentFolderNode = node->parentFolderNode()) {
|
||||
if (FolderNode *grandParentFolderNode = parentFolderNode->parentFolderNode()) {
|
||||
Q_ASSERT(m_childNodes.contains(grandParentFolderNode));
|
||||
int row = m_childNodes.value(grandParentFolderNode).indexOf(parentFolderNode);
|
||||
parentIndex = createIndex(row, 0, parentFolderNode);
|
||||
} else {
|
||||
parentIndex = createIndex(0, 0, parentFolderNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parentIndex;
|
||||
}
|
||||
|
||||
Qt::ItemFlags DetailedModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags result;
|
||||
if (index.isValid()) {
|
||||
result = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
|
||||
if (Node *node = nodeForIndex(index)) {
|
||||
if (node->nodeType() == FileNodeType)
|
||||
result |= Qt::ItemIsEditable;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariant DetailedModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QVariant result;
|
||||
|
||||
if (Node *node = nodeForIndex(index)) {
|
||||
FolderNode *folderNode = qobject_cast<FolderNode*>(node);
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole: {
|
||||
if (folderNode)
|
||||
result = folderNode->name();
|
||||
else
|
||||
result = QFileInfo(node->path()).fileName(); //TODO cache that?
|
||||
break;
|
||||
}
|
||||
case Qt::ToolTipRole: {
|
||||
if (folderNode && (folderNode->nodeType() != ProjectNodeType))
|
||||
result = tr("%1 of project %2").arg(folderNode->name()).arg(folderNode->projectNode()->name());
|
||||
else
|
||||
result = node->path();
|
||||
break;
|
||||
}
|
||||
case Qt::DecorationRole: {
|
||||
if (folderNode)
|
||||
result = folderNode->icon();
|
||||
else
|
||||
result = FileIconProvider::instance()->icon(QFileInfo(node->path()));
|
||||
break;
|
||||
}
|
||||
case Qt::FontRole: {
|
||||
QFont font;
|
||||
result = font;
|
||||
break;
|
||||
}
|
||||
case ProjectExplorer::Project::FilePathRole: {
|
||||
result = node->path();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DetailedModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (Node *node = nodeForIndex(index)) {
|
||||
FileNode *fileNode = qobject_cast<FileNode*>(node);
|
||||
if (fileNode && role == Qt::EditRole && !value.toString().isEmpty()) {
|
||||
ProjectNode *projectNode = node->projectNode();
|
||||
QString newPath = QFileInfo(fileNode->path()).dir().absoluteFilePath(value.toString());
|
||||
if (!projectNode->renameFile(fileNode->fileType(), fileNode->path(), newPath))
|
||||
QMessageBox::warning(0, tr("Could not rename file"),
|
||||
tr("Renaming file %1 to %2 failed.").arg(fileNode->path())
|
||||
.arg(value.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int DetailedModel::rowCount(const QModelIndex & parent) const
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (!parent.isValid()) { // root item
|
||||
count = 1;
|
||||
} else {
|
||||
// we can be sure that internal cache
|
||||
// has been updated by fetchMore()
|
||||
FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
|
||||
if (folderNode && m_childNodes.contains(folderNode))
|
||||
count = m_childNodes.value(folderNode).size();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int DetailedModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool DetailedModel::hasChildren(const QModelIndex &parent) const
|
||||
{
|
||||
bool hasChilds = false;
|
||||
|
||||
if (!parent.isValid()) {// root index
|
||||
hasChilds = true;
|
||||
} else {
|
||||
if (FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent))) {
|
||||
if (m_childNodes.contains(folderNode)) // internal cache
|
||||
hasChilds = !m_childNodes.value(folderNode).isEmpty();
|
||||
else {
|
||||
if (!folderNode->subFolderNodes().isEmpty()
|
||||
|| !folderNode->fileNodes().isEmpty()) // underlying data
|
||||
hasChilds = true;
|
||||
else {
|
||||
// Make sure add/remove signals are emitted
|
||||
// even for empty nodes (i.e. where canFetchMore
|
||||
// returns false)
|
||||
m_childNodes.insert(folderNode, QList<Node*>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasChilds;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if internal cache has not been built up yet
|
||||
*/
|
||||
bool DetailedModel::canFetchMore(const QModelIndex & parent) const
|
||||
{
|
||||
bool canFetch = false;
|
||||
if (parent.isValid()) {
|
||||
if (FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent))) {
|
||||
canFetch = !m_childNodes.contains(folderNode);
|
||||
}
|
||||
}
|
||||
return canFetch;
|
||||
}
|
||||
|
||||
/*!
|
||||
Updates internal cache
|
||||
*/
|
||||
void DetailedModel::fetchMore(const QModelIndex & parent)
|
||||
{
|
||||
FolderNode *folderNode = qobject_cast<FolderNode*>(nodeForIndex(parent));
|
||||
Q_ASSERT(folderNode);
|
||||
Q_ASSERT(!m_childNodes.contains(folderNode));
|
||||
|
||||
m_childNodes.insert(folderNode, childNodeList(folderNode));
|
||||
}
|
||||
|
||||
void DetailedModel::reset()
|
||||
{
|
||||
// todo:How to implement this correctly?????
|
||||
m_childNodes.clear();
|
||||
QAbstractItemModel::reset();
|
||||
}
|
||||
|
||||
void DetailedModel::foldersAboutToBeAdded(FolderNode *parentFolder,
|
||||
const QList<FolderNode*> &newFolders)
|
||||
{
|
||||
Q_UNUSED(newFolders)
|
||||
Q_ASSERT(parentFolder);
|
||||
|
||||
if (m_childNodes.contains(parentFolder))
|
||||
m_folderToAddTo = parentFolder;
|
||||
}
|
||||
|
||||
void DetailedModel::foldersAdded()
|
||||
{
|
||||
if (m_folderToAddTo) {
|
||||
QList<Node*> newChildNodes = childNodeList(m_folderToAddTo);
|
||||
addToChildNodes(m_folderToAddTo, newChildNodes);
|
||||
m_folderToAddTo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DetailedModel::foldersAboutToBeRemoved(FolderNode *parentFolder,
|
||||
const QList<FolderNode*> &staleFolders)
|
||||
{
|
||||
Q_ASSERT(parentFolder);
|
||||
|
||||
if (m_childNodes.contains(parentFolder)) {
|
||||
QList<Node*> newChildNodes = m_childNodes.value(parentFolder);
|
||||
QList<FolderNode*> nodesToRemove = staleFolders;
|
||||
qSort(nodesToRemove.begin(), nodesToRemove.end(), sortNodes);
|
||||
|
||||
QList<Node*>::iterator newListIter = newChildNodes.begin();
|
||||
QList<FolderNode*>::const_iterator toRemoveIter = nodesToRemove.constBegin();
|
||||
for (; toRemoveIter != nodesToRemove.constEnd(); ++toRemoveIter) {
|
||||
while (*newListIter != *toRemoveIter)
|
||||
++newListIter;
|
||||
newListIter = newChildNodes.erase(newListIter);
|
||||
}
|
||||
|
||||
removeFromChildNodes(parentFolder, newChildNodes);
|
||||
|
||||
// Clear cache for all folders beneath the current folder
|
||||
foreach (FolderNode *folder, staleFolders) {
|
||||
foreach (FolderNode *subFolder, recursiveSubFolders(folder)) {
|
||||
m_childNodes.remove(subFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DetailedModel::filesAboutToBeAdded(FolderNode *parentFolder,
|
||||
const QList<FileNode*> &newFiles)
|
||||
{
|
||||
Q_UNUSED(newFiles)
|
||||
Q_ASSERT(parentFolder);
|
||||
|
||||
if (m_childNodes.contains(parentFolder))
|
||||
m_folderToAddTo = parentFolder;
|
||||
}
|
||||
|
||||
void DetailedModel::filesAdded()
|
||||
{
|
||||
if (m_folderToAddTo) {
|
||||
QList<Node*> newChildNodes = childNodeList(m_folderToAddTo);
|
||||
addToChildNodes(m_folderToAddTo, newChildNodes);
|
||||
m_folderToAddTo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DetailedModel::filesAboutToBeRemoved(FolderNode *parentFolder,
|
||||
const QList<FileNode*> &staleFiles)
|
||||
{
|
||||
Q_ASSERT(parentFolder);
|
||||
|
||||
if (m_childNodes.contains(parentFolder)) {
|
||||
QList<Node*> newChildNodes = m_childNodes.value(parentFolder);
|
||||
QList<FileNode*> nodesToRemove = staleFiles;
|
||||
qSort(nodesToRemove.begin(), nodesToRemove.end(), sortNodes);
|
||||
|
||||
QList<Node*>::iterator newListIter = newChildNodes.begin();
|
||||
QList<FileNode*>::const_iterator toRemoveIter = nodesToRemove.constBegin();
|
||||
for (; toRemoveIter != nodesToRemove.constEnd(); ++toRemoveIter) {
|
||||
while (*newListIter != *toRemoveIter)
|
||||
++newListIter;
|
||||
newListIter = newChildNodes.erase(newListIter);
|
||||
}
|
||||
|
||||
removeFromChildNodes(parentFolder, newChildNodes);
|
||||
}
|
||||
}
|
||||
|
||||
Node *DetailedModel::nodeForIndex(const QModelIndex &index) const
|
||||
{
|
||||
return (Node*)index.internalPointer();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the index corresponding to a node.
|
||||
*/
|
||||
QModelIndex DetailedModel::indexForNode(const Node *node)
|
||||
{
|
||||
if (!node)
|
||||
return QModelIndex();
|
||||
|
||||
if (FolderNode *parentFolder = node->parentFolderNode()) {
|
||||
// iterate recursively
|
||||
QModelIndex parentIndex = indexForNode(parentFolder);
|
||||
|
||||
// update internal cache
|
||||
if (canFetchMore(parentIndex))
|
||||
fetchMore(parentIndex);
|
||||
Q_ASSERT(m_childNodes.contains(parentFolder));
|
||||
|
||||
int row = m_childNodes.value(parentFolder).indexOf(const_cast<Node*>(node));
|
||||
if (row >= 0)
|
||||
return index(row, 0, parentIndex);
|
||||
else
|
||||
return QModelIndex();
|
||||
} else {
|
||||
// root node
|
||||
return index(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
QList<Node*> DetailedModel::childNodeList(FolderNode *folderNode) const
|
||||
{
|
||||
QList<FolderNode*> folderNodes = folderNode->subFolderNodes();
|
||||
QList<FileNode*> fileNodes = folderNode->fileNodes();
|
||||
|
||||
QList<Node*> nodes;
|
||||
foreach (FolderNode *folderNode, folderNodes)
|
||||
nodes << folderNode;
|
||||
foreach (FileNode *fileNode, fileNodes)
|
||||
nodes << fileNode;
|
||||
|
||||
qSort(nodes.begin(), nodes.end(), sortNodes);
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
void DetailedModel::addToChildNodes(FolderNode *parentFolder, QList<Node*> newChildNodes)
|
||||
{
|
||||
QList<Node*> childNodes = m_childNodes.value(parentFolder);
|
||||
QModelIndex parentIndex = indexForNode(parentFolder);
|
||||
Q_ASSERT(parentIndex.isValid());
|
||||
|
||||
// position -> nodes, with positions in decreasing order
|
||||
QList<QPair<int, QList<Node*> > > insertions;
|
||||
|
||||
// add nodes that should be added at the end or in between
|
||||
int newIndex = newChildNodes.size() - 1;
|
||||
for (int oldIndex = childNodes.size() - 1;
|
||||
oldIndex >= 0; --oldIndex, --newIndex) {
|
||||
QList<Node*> nodesPerIndex;
|
||||
Node* oldNode = childNodes.at(oldIndex);
|
||||
while (newChildNodes.at(newIndex) != oldNode) {
|
||||
nodesPerIndex.append(newChildNodes.at(newIndex));
|
||||
--newIndex;
|
||||
}
|
||||
if (!nodesPerIndex.isEmpty())
|
||||
insertions.append(QPair<int, QList<Node*> >(oldIndex + 1, nodesPerIndex));
|
||||
}
|
||||
{ // add nodes that should be added to the beginning
|
||||
QList<Node*> insertAtStart;
|
||||
while (newIndex >= 0) {
|
||||
insertAtStart.append(newChildNodes.at(newIndex--));
|
||||
}
|
||||
if (!insertAtStart.isEmpty())
|
||||
insertions.append(QPair<int, QList<Node*> >(0, insertAtStart));
|
||||
}
|
||||
|
||||
for (QList<QPair<int, QList<Node*> > >::const_iterator iter = insertions.constBegin();
|
||||
iter != insertions.constEnd(); ++iter) {
|
||||
|
||||
const int key = iter->first;
|
||||
const QList<Node*> nodesToInsert = iter->second;
|
||||
|
||||
beginInsertRows(parentIndex, key, key + nodesToInsert.size() - 1);
|
||||
|
||||
// update internal cache
|
||||
for (QList<Node*>::const_iterator nodeIterator = nodesToInsert.constBegin();
|
||||
nodeIterator != nodesToInsert.constEnd(); ++nodeIterator)
|
||||
childNodes.insert(key, *nodeIterator);
|
||||
m_childNodes.insert(parentFolder, childNodes);
|
||||
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
Q_ASSERT(childNodes == newChildNodes);
|
||||
}
|
||||
|
||||
void DetailedModel::removeFromChildNodes(FolderNode *parentFolder, QList<Node*> newChildNodes)
|
||||
{
|
||||
QList<Node*> childNodes = m_childNodes.value(parentFolder);
|
||||
QModelIndex parentIndex = indexForNode(parentFolder);
|
||||
Q_ASSERT(parentIndex.isValid());
|
||||
|
||||
// position -> nodes, with positions in decreasing order
|
||||
QList<QPair<int, QList<Node*> > > deletions;
|
||||
|
||||
// add nodes that should be removed at the end or in between
|
||||
int oldIndex = childNodes.size() - 1;
|
||||
for (int newIndex = newChildNodes.size() - 1;
|
||||
newIndex >= 0; --oldIndex, --newIndex) {
|
||||
QList<Node*> nodesPerIndex;
|
||||
Node* newNode = newChildNodes.at(newIndex);
|
||||
while (childNodes.at(oldIndex) != newNode) {
|
||||
nodesPerIndex.append(childNodes.at(oldIndex));
|
||||
--oldIndex;
|
||||
}
|
||||
if (!nodesPerIndex.isEmpty())
|
||||
deletions.append(QPair<int, QList<Node*> >(oldIndex + 1, nodesPerIndex));
|
||||
}
|
||||
{ // add nodes that should be removed to the beginning
|
||||
QList<Node*> deleteAtStart;
|
||||
while (oldIndex >= 0) {
|
||||
deleteAtStart.append(childNodes.at(oldIndex--));
|
||||
}
|
||||
if (!deleteAtStart.isEmpty())
|
||||
deletions.append(QPair<int, QList<Node*> >(0, deleteAtStart));
|
||||
}
|
||||
|
||||
for (QList<QPair<int, QList<Node*> > >::const_iterator iter = deletions.constBegin();
|
||||
iter != deletions.constEnd(); ++iter) {
|
||||
|
||||
const int key = iter->first;
|
||||
const QList<Node*> nodes = iter->second;
|
||||
|
||||
beginRemoveRows(parentIndex, key, key + nodes.size() - 1);
|
||||
|
||||
// update internal cache
|
||||
for (int i = nodes.size(); i > 0; --i)
|
||||
childNodes.removeAt(key);
|
||||
m_childNodes.insert(parentFolder, childNodes);
|
||||
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
Q_ASSERT(childNodes == newChildNodes);
|
||||
}
|
||||
|
||||
QList<FolderNode*> DetailedModel::recursiveSubFolders(FolderNode *parentFolder)
|
||||
{
|
||||
QList<FolderNode*> subFolders;
|
||||
foreach (FolderNode *subFolder, parentFolder->subFolderNodes()) {
|
||||
subFolders.append(subFolder);
|
||||
subFolders != recursiveSubFolders(subFolder);
|
||||
}
|
||||
return subFolders;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\class FlatModel
|
||||
|
||||
The flat model shows only application/library projects.
|
||||
|
||||
|
||||
Shows all application/library projects directly unter the root project
|
||||
This results in a "flattened" view (max 3 hierachies).
|
||||
*/
|
||||
|
||||
FlatModel::FlatModel(SessionNode *rootNode, QObject *parent)
|
||||
: QAbstractItemModel(parent),
|
||||
m_filterProjects(false),
|
||||
|
@@ -43,69 +43,6 @@ class SessionNode;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
// A 1:1 mapping of the internal data model
|
||||
class DetailedModel : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DetailedModel(SessionNode *rootNode, QObject *parent);
|
||||
|
||||
// QAbstractItemModel
|
||||
QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
|
||||
QModelIndex parent(const QModelIndex &index) const;
|
||||
Qt::ItemFlags flags(const QModelIndex & index) const;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
|
||||
|
||||
int rowCount(const QModelIndex & parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex & parent = QModelIndex()) const;
|
||||
bool hasChildren(const QModelIndex & parent = QModelIndex()) const;
|
||||
|
||||
bool canFetchMore(const QModelIndex & parent) const;
|
||||
void fetchMore(const QModelIndex & parent);
|
||||
|
||||
void reset();
|
||||
|
||||
void setStartupProject(ProjectNode * /* projectNode */) {}
|
||||
|
||||
Node *nodeForIndex(const QModelIndex &index) const;
|
||||
QModelIndex indexForNode(const Node *node);
|
||||
|
||||
public slots:
|
||||
void setProjectFilterEnabled(bool /* filter */) {}
|
||||
|
||||
private slots:
|
||||
void foldersAboutToBeAdded(FolderNode *parentFolder,
|
||||
const QList<FolderNode*> &newFolders);
|
||||
void foldersAdded();
|
||||
|
||||
void foldersAboutToBeRemoved(FolderNode *parentFolder,
|
||||
const QList<FolderNode*> &staleFolders);
|
||||
|
||||
void filesAboutToBeAdded(FolderNode *folder,
|
||||
const QList<FileNode*> &newFiles);
|
||||
void filesAdded();
|
||||
|
||||
void filesAboutToBeRemoved(FolderNode *folder,
|
||||
const QList<FileNode*> &staleFiles);
|
||||
|
||||
private:
|
||||
QList<Node*> childNodeList(FolderNode *folderNode) const;
|
||||
|
||||
void connectProject(ProjectNode *project);
|
||||
void addToChildNodes(FolderNode *parentFolder, QList<Node*> newList);
|
||||
void removeFromChildNodes(FolderNode *parentFolder, QList<Node*> newList);
|
||||
QList<FolderNode*> recursiveSubFolders(FolderNode *parentFolder);
|
||||
|
||||
SessionNode *m_rootNode;
|
||||
mutable QHash<FolderNode*, QList<Node*> > m_childNodes;
|
||||
FolderNode *m_folderToAddTo;
|
||||
|
||||
friend class DetailedModelManager;
|
||||
};
|
||||
|
||||
|
||||
// displays "flattened" view without pri files, subdirs pro files & virtual folders
|
||||
// This view is optimized to be used in the edit mode sidebar
|
||||
class FlatModel : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
Reference in New Issue
Block a user