ResInsight/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewQModel.cpp
Magne Sjaastad 6ce456d43e Performance: Make sure the model list is created once
Creating multiple lists during recursion caused a quite large performance penalty.
2023-10-13 16:31:14 +02:00

950 lines
33 KiB
C++

//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2014 Ceetron Solutions AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#include "cafPdmUiTreeViewQModel.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmUiCommandSystemProxy.h"
#include "cafPdmUiDragDropInterface.h"
#include "cafPdmUiTreeItemEditor.h"
#include "cafPdmUiTreeOrdering.h"
#include "cafPdmUiTreeViewEditor.h"
#include <QDragMoveEvent>
#include <QMimeData>
#include <QTreeView>
namespace caf
{
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiTreeViewQModel::PdmUiTreeViewQModel( PdmUiTreeViewEditor* treeViewEditor )
{
m_treeOrderingRoot = nullptr;
m_dragDropInterface = nullptr;
m_treeViewEditor = treeViewEditor;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiTreeViewQModel::~PdmUiTreeViewQModel()
{
if ( m_dragDropInterface )
{
delete m_dragDropInterface;
m_dragDropInterface = nullptr;
}
}
//--------------------------------------------------------------------------------------------------
/// Will populate the tree with the contents of the Pdm data structure rooted at rootItem.
/// Will not show the rootItem itself, only the children and downwards
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewQModel::setPdmItemRoot( PdmUiItem* rootItem )
{
// Check if we are already watching this root
if ( rootItem && m_treeOrderingRoot && m_treeOrderingRoot->activeItem() == rootItem )
{
bool notifyEditors = false;
this->updateSubTree( rootItem, notifyEditors );
return;
}
PdmUiTreeOrdering* newRoot = nullptr;
PdmUiFieldHandle* field = dynamic_cast<PdmUiFieldHandle*>( rootItem );
if ( field )
{
newRoot = new PdmUiTreeOrdering( field->fieldHandle() );
PdmUiObjectHandle::expandUiTree( newRoot, m_uiConfigName );
}
else
{
PdmUiObjectHandle* obj = dynamic_cast<PdmUiObjectHandle*>( rootItem );
if ( obj )
{
newRoot = obj->uiTreeOrdering( m_uiConfigName );
}
}
CAF_ASSERT( newRoot || rootItem == nullptr ); // Only fields, objects or NULL is allowed.
// if (newRoot) newRoot->debugDump(0);
this->resetTree( newRoot );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewQModel::resetTree( PdmUiTreeOrdering* newRoot )
{
beginResetModel();
if ( m_treeOrderingRoot )
{
delete m_treeOrderingRoot;
}
m_treeOrderingRoot = newRoot;
updateEditorsForSubTree( m_treeOrderingRoot );
endResetModel();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewQModel::setColumnHeaders( const QStringList& columnHeaders )
{
m_columnHeaders = columnHeaders;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewQModel::emitDataChanged( const QModelIndex& index )
{
emit dataChanged( index, index );
}
//--------------------------------------------------------------------------------------------------
/// Refreshes the UI-tree below the supplied root PdmUiItem
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewQModel::updateSubTree( PdmUiItem* pdmRoot, bool notifyEditors )
{
// Build the new "Correct" Tree
PdmUiTreeOrdering* newTreeRootTmp = nullptr;
PdmUiFieldHandle* field = dynamic_cast<PdmUiFieldHandle*>( pdmRoot );
if ( field )
{
newTreeRootTmp = new PdmUiTreeOrdering( field->fieldHandle() );
}
else
{
PdmUiObjectHandle* obj = dynamic_cast<PdmUiObjectHandle*>( pdmRoot );
if ( obj )
{
newTreeRootTmp = new PdmUiTreeOrdering( obj->objectHandle() );
}
}
PdmUiObjectHandle::expandUiTree( newTreeRootTmp, m_uiConfigName );
#if CAF_PDM_TREE_VIEW_DEBUG_PRINT
std::cout << std::endl << "New Stuff: " << std::endl;
newTreeRootTmp->debugDump( 0 );
#endif
// Find the corresponding entry for "root" in the existing Ui tree
QModelIndex existingSubTreeRootModIdx = findModelIndex( pdmRoot );
PdmUiTreeOrdering* existingSubTreeRoot = nullptr;
if ( existingSubTreeRootModIdx.isValid() )
{
existingSubTreeRoot = treeItemFromIndex( existingSubTreeRootModIdx );
}
else
{
existingSubTreeRoot = m_treeOrderingRoot;
}
#if CAF_PDM_TREE_VIEW_DEBUG_PRINT
std::cout << std::endl << "Old :" << std::endl;
existingSubTreeRoot->debugDump( 0 );
#endif
updateSubTreeRecursive( existingSubTreeRootModIdx, existingSubTreeRoot, newTreeRootTmp, notifyEditors );
delete newTreeRootTmp;
updateEditorsForSubTree( existingSubTreeRoot );
#if CAF_PDM_TREE_VIEW_DEBUG_PRINT
std::cout << std::endl << "Result :" << std::endl;
existingSubTreeRoot->debugDump( 0 );
#endif
}
class RecursiveUpdateData
{
public:
RecursiveUpdateData( int row, PdmUiTreeOrdering* existingChild, PdmUiTreeOrdering* sourceChild )
: m_row( row )
, m_existingChild( existingChild )
, m_sourceChild( sourceChild ){};
int m_row;
PdmUiTreeOrdering* m_existingChild;
PdmUiTreeOrdering* m_sourceChild;
};
//--------------------------------------------------------------------------------------------------
/// Makes the existingSubTreeRoot tree become identical to the tree in sourceSubTreeRoot,
/// calling begin..() end..() to make the UI update accordingly.
/// This assumes that all the items have a pointer an unique PdmObject
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewQModel::updateSubTreeRecursive( const QModelIndex& existingSubTreeRootModIdx,
PdmUiTreeOrdering* existingSubTreeRoot,
PdmUiTreeOrdering* sourceSubTreeRoot,
bool notifyEditors )
{
// Build map for source items
std::map<caf::PdmUiItem*, int> sourceTreeMap;
for ( int i = 0; i < sourceSubTreeRoot->childCount(); ++i )
{
PdmUiTreeOrdering* child = sourceSubTreeRoot->child( i );
if ( child && child->activeItem() )
{
sourceTreeMap[child->activeItem()] = i;
}
}
// Detect items to be deleted from existing tree
std::vector<int> indicesToRemoveFromExisting;
for ( int i = 0; i < existingSubTreeRoot->childCount(); ++i )
{
PdmUiTreeOrdering* child = existingSubTreeRoot->child( i );
std::map<caf::PdmUiItem*, int>::iterator it = sourceTreeMap.find( child->activeItem() );
if ( it == sourceTreeMap.end() )
{
indicesToRemoveFromExisting.push_back( i );
}
}
// Delete items with largest index first from existing
for ( std::vector<int>::reverse_iterator it = indicesToRemoveFromExisting.rbegin();
it != indicesToRemoveFromExisting.rend();
++it )
{
this->beginRemoveRows( existingSubTreeRootModIdx, *it, *it );
existingSubTreeRoot->removeChildren( *it, 1 );
this->endRemoveRows();
}
// Build map for existing items without the deleted items
std::map<caf::PdmUiItem*, int> existingTreeMap;
for ( int i = 0; i < existingSubTreeRoot->childCount(); ++i )
{
PdmUiTreeOrdering* child = existingSubTreeRoot->child( i );
if ( child && child->activeItem() )
{
existingTreeMap[child->activeItem()] = i;
}
}
// Check if there are any changes between existing and source
// If no changes, update the subtree recursively
bool anyChanges = false;
if ( existingSubTreeRoot->childCount() == sourceSubTreeRoot->childCount() )
{
for ( int i = 0; i < existingSubTreeRoot->childCount(); ++i )
{
if ( existingSubTreeRoot->child( i )->activeItem() != sourceSubTreeRoot->child( i )->activeItem() )
{
anyChanges = true;
break;
}
}
}
else
{
anyChanges = true;
}
if ( !anyChanges )
{
// Notify Qt that the toggle/name/icon etc might have been changed
if ( notifyEditors ) emitDataChanged( existingSubTreeRootModIdx );
// No changes to list of children at this level, call update on all children
for ( int i = 0; i < existingSubTreeRoot->childCount(); ++i )
{
updateSubTreeRecursive( index( i, 0, existingSubTreeRootModIdx ),
existingSubTreeRoot->child( i ),
sourceSubTreeRoot->child( i ),
notifyEditors );
}
}
else
{
std::vector<RecursiveUpdateData> recursiveUpdateData;
std::vector<PdmUiTreeOrdering*> newMergedOrdering;
if ( notifyEditors ) emit layoutAboutToBeChanged();
{
// Detect items to be moved from source to existing
// Merge items from existing and source into newMergedOrdering using order in sourceSubTreeRoot
std::vector<int> indicesToRemoveFromSource;
for ( int i = 0; i < sourceSubTreeRoot->childCount(); ++i )
{
PdmUiTreeOrdering* sourceChild = sourceSubTreeRoot->child( i );
std::map<caf::PdmUiItem*, int>::iterator it = existingTreeMap.find( sourceChild->activeItem() );
if ( it != existingTreeMap.end() )
{
newMergedOrdering.push_back( existingSubTreeRoot->child( it->second ) );
int rowIndexToBeUpdated = static_cast<int>( newMergedOrdering.size() - 1 );
recursiveUpdateData.push_back(
RecursiveUpdateData( rowIndexToBeUpdated, existingSubTreeRoot->child( it->second ), sourceChild ) );
}
else
{
newMergedOrdering.push_back( sourceChild );
indicesToRemoveFromSource.push_back( i );
}
}
// Delete new items from source because they have been moved into newMergedOrdering
for ( std::vector<int>::reverse_iterator it = indicesToRemoveFromSource.rbegin();
it != indicesToRemoveFromSource.rend();
++it )
{
// Use the removeChildNoDelete() to remove the pointer from the list without deleting the pointer
sourceSubTreeRoot->removeChildrenNoDelete( *it, 1 );
}
// Delete all items from existingSubTreeRoot, as the complete list is present in newMergedOrdering
existingSubTreeRoot->removeChildrenNoDelete( 0, existingSubTreeRoot->childCount() );
// First, reorder all items in existing tree, as this operation is valid when later emitting the signal
// layoutChanged() Insert of new items before issuing this signal causes the tree items below the inserted
// item to collapse
for ( size_t i = 0; i < newMergedOrdering.size(); i++ )
{
if ( existingTreeMap.find( newMergedOrdering[i]->activeItem() ) != existingTreeMap.end() )
{
existingSubTreeRoot->appendChild( newMergedOrdering[i] );
}
}
}
if ( notifyEditors ) emit layoutChanged();
// Insert new items into existingSubTreeRoot
for ( size_t i = 0; i < newMergedOrdering.size(); i++ )
{
if ( existingTreeMap.find( newMergedOrdering[i]->activeItem() ) == existingTreeMap.end() )
{
this->beginInsertRows( existingSubTreeRootModIdx, static_cast<int>( i ), static_cast<int>( i ) );
existingSubTreeRoot->insertChild( static_cast<int>( i ), newMergedOrdering[i] );
this->endInsertRows();
}
}
for ( size_t i = 0; i < recursiveUpdateData.size(); i++ )
{
// Using the index() function here is OK, as new items has been inserted in the previous for-loop
// This code used to be executed before insertion of new items, and caused creation of invalid indices
QModelIndex mi = index( recursiveUpdateData[i].m_row, 0, existingSubTreeRootModIdx );
CAF_ASSERT( mi.isValid() );
updateSubTreeRecursive( mi,
recursiveUpdateData[i].m_existingChild,
recursiveUpdateData[i].m_sourceChild,
notifyEditors );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewQModel::updateEditorsForSubTree( PdmUiTreeOrdering* root )
{
if ( !root ) return;
if ( !root->editor() )
{
PdmUiTreeItemEditor* treeItemEditor = new PdmUiTreeItemEditor( root->activeItem() );
root->setEditor( treeItemEditor );
CAF_ASSERT( root->editor() );
}
PdmUiTreeItemEditor* treeItemEditor = dynamic_cast<PdmUiTreeItemEditor*>( root->editor() );
if ( treeItemEditor )
{
treeItemEditor->setTreeViewEditor( m_treeViewEditor );
}
for ( int i = 0; i < root->childCount(); ++i )
{
updateEditorsForSubTree( root->child( i ) );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewQModel::allIndicesRecursiveImpl( const QModelIndex& current, std::list<QModelIndex>& modelList ) const
{
modelList.insert( modelList.end(), current );
int rows = rowCount( current );
int cols = columnCount( current );
for ( int row = 0; row < rows; ++row )
{
for ( int col = 0; col < cols; ++col )
{
QModelIndex childIndex = index( row, col, current );
allIndicesRecursiveImpl( childIndex, modelList );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::list<QModelIndex> PdmUiTreeViewQModel::allIndicesRecursive( const QModelIndex& current ) const
{
std::list<QModelIndex> currentAndDescendants;
allIndicesRecursiveImpl( current, currentAndDescendants );
return currentAndDescendants;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiTreeOrdering* caf::PdmUiTreeViewQModel::treeItemFromIndex( const QModelIndex& index ) const
{
if ( !index.isValid() )
{
return m_treeOrderingRoot;
}
CAF_ASSERT( index.internalPointer() );
PdmUiTreeOrdering* treeItem = static_cast<PdmUiTreeOrdering*>( index.internalPointer() );
return treeItem;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QModelIndex caf::PdmUiTreeViewQModel::findModelIndex( const PdmUiItem* object ) const
{
QModelIndex foundIndex;
int numRows = rowCount( QModelIndex() );
int r = 0;
while ( r < numRows && !foundIndex.isValid() )
{
foundIndex = findModelIndexRecursive( index( r, 0, QModelIndex() ), object );
++r;
}
return foundIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QModelIndex caf::PdmUiTreeViewQModel::findModelIndexRecursive( const QModelIndex& currentIndex, const PdmUiItem* pdmItem ) const
{
if ( currentIndex.internalPointer() )
{
PdmUiTreeOrdering* treeItem = static_cast<PdmUiTreeOrdering*>( currentIndex.internalPointer() );
if ( treeItem->activeItem() == pdmItem ) return currentIndex;
}
int row;
for ( row = 0; row < rowCount( currentIndex ); ++row )
{
QModelIndex foundIndex = findModelIndexRecursive( index( row, 0, currentIndex ), pdmItem );
if ( foundIndex.isValid() ) return foundIndex;
}
return QModelIndex();
}
//--------------------------------------------------------------------------------------------------
/// An invalid parent index is implicitly meaning the root item, and not "above" root, since
/// we are not showing the root item itself
//--------------------------------------------------------------------------------------------------
QModelIndex PdmUiTreeViewQModel::index( int row, int column, const QModelIndex& parentIndex ) const
{
if ( !m_treeOrderingRoot ) return QModelIndex();
PdmUiTreeOrdering* parentItem = nullptr;
if ( !parentIndex.isValid() )
parentItem = m_treeOrderingRoot;
else
parentItem = static_cast<PdmUiTreeOrdering*>( parentIndex.internalPointer() );
CAF_ASSERT( parentItem );
if ( parentItem->childCount() <= row )
{
return QModelIndex();
}
PdmUiTreeOrdering* childItem = parentItem->child( row );
if ( childItem )
return createIndex( row, column, childItem );
else
return QModelIndex();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QModelIndex PdmUiTreeViewQModel::parent( const QModelIndex& childIndex ) const
{
if ( !childIndex.isValid() ) return QModelIndex();
PdmUiTreeOrdering* childItem = static_cast<PdmUiTreeOrdering*>( childIndex.internalPointer() );
if ( !childItem ) return QModelIndex();
PdmUiTreeOrdering* parentItem = childItem->parent();
if ( !parentItem ) return QModelIndex();
if ( parentItem == m_treeOrderingRoot ) return QModelIndex();
return createIndex( parentItem->indexInParent(), 0, parentItem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int PdmUiTreeViewQModel::rowCount( const QModelIndex& parentIndex ) const
{
if ( !m_treeOrderingRoot ) return 0;
if ( parentIndex.column() > 0 ) return 0;
PdmUiTreeOrdering* parentItem = this->treeItemFromIndex( parentIndex );
return parentItem->childCount();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int PdmUiTreeViewQModel::columnCount( const QModelIndex& parentIndex ) const
{
if ( !m_treeOrderingRoot ) return 0;
return 1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QVariant PdmUiTreeViewQModel::data( const QModelIndex& index, int role ) const
{
if ( !index.isValid() )
{
return QVariant();
}
PdmUiTreeOrdering* uitreeOrdering = static_cast<PdmUiTreeOrdering*>( index.internalPointer() );
if ( !uitreeOrdering )
{
return QVariant();
}
bool isObjRep = uitreeOrdering->isRepresentingObject();
if ( role == Qt::DisplayRole && !uitreeOrdering->isValid() )
{
QString str;
#ifdef DEBUG
str = "Invalid uiordering";
#endif
return QVariant( str );
}
if ( role == Qt::DisplayRole || role == Qt::EditRole )
{
if ( isObjRep )
{
PdmUiObjectHandle* pdmUiObject = uiObj( uitreeOrdering->object() );
if ( pdmUiObject )
{
QVariant v;
if ( pdmUiObject->userDescriptionField() )
{
caf::PdmUiFieldHandle* uiFieldHandle = pdmUiObject->userDescriptionField()->uiCapability();
if ( uiFieldHandle )
{
v = uiFieldHandle->uiValue();
}
}
else
{
v = pdmUiObject->uiName();
}
QString txt = v.toString();
if ( m_treeViewEditor->isAppendOfClassNameToUiItemTextEnabled() )
{
PdmObjectHandle* pdmObjHandle = pdmUiObject->objectHandle();
if ( pdmObjHandle )
{
txt += " - ";
txt += typeid( *pdmObjHandle ).name();
}
}
return txt;
}
else
{
return QVariant();
}
}
if ( uitreeOrdering->activeItem() )
{
return uitreeOrdering->activeItem()->uiName();
}
else
{
return QVariant();
}
}
else if ( role == Qt::DecorationRole )
{
if ( uitreeOrdering->activeItem() )
{
auto icon = uitreeOrdering->activeItem()->uiIcon();
return icon ? *icon : QIcon();
}
else
{
return QVariant();
}
}
else if ( role == Qt::ToolTipRole )
{
if ( uitreeOrdering->activeItem() )
{
return uitreeOrdering->activeItem()->uiToolTip();
}
else
{
return QVariant();
}
}
else if ( role == Qt::WhatsThisRole )
{
if ( uitreeOrdering->activeItem() )
{
return uitreeOrdering->activeItem()->uiWhatsThis();
}
else
{
return QVariant();
}
}
else if ( role == Qt::CheckStateRole )
{
if ( isObjRep )
{
PdmUiObjectHandle* pdmUiObj = uiObj( uitreeOrdering->object() );
if ( pdmUiObj && pdmUiObj->objectToggleField() )
{
caf::PdmUiFieldHandle* uiFieldHandle = pdmUiObj->objectToggleField()->uiCapability();
if ( uiFieldHandle )
{
bool isToggledOn = uiFieldHandle->uiValue().toBool();
if ( isToggledOn )
{
return Qt::Checked;
}
else
{
return Qt::Unchecked;
}
}
else
{
return QVariant();
}
}
}
}
return QVariant();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmUiTreeViewQModel::setData( const QModelIndex& index, const QVariant& value, int role /*= Qt::EditRole*/ )
{
if ( !index.isValid() )
{
return false;
}
PdmUiTreeOrdering* treeItem = PdmUiTreeViewQModel::treeItemFromIndex( index );
CAF_ASSERT( treeItem );
if ( !treeItem->isRepresentingObject() ) return false;
PdmUiObjectHandle* uiObject = uiObj( treeItem->object() );
if ( uiObject )
{
if ( role == Qt::EditRole && uiObject->userDescriptionField() )
{
PdmUiFieldHandle* userDescriptionUiField = uiObject->userDescriptionField()->uiCapability();
if ( userDescriptionUiField )
{
PdmUiCommandSystemProxy::instance()->setUiValueToField( userDescriptionUiField, value );
}
return true;
}
else if ( role == Qt::CheckStateRole && uiObject->objectToggleField() &&
!uiObject->objectToggleField()->uiCapability()->isUiReadOnly( m_uiConfigName ) )
{
bool toggleOn = ( value == Qt::Checked );
PdmUiFieldHandle* toggleUiField = uiObject->objectToggleField()->uiCapability();
if ( toggleUiField )
{
PdmUiCommandSystemProxy::instance()->setUiValueToField( toggleUiField, toggleOn );
}
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
/// Enable edit of this item if we have a editable user description field for a pdmObject
/// Disable edit for other items
//--------------------------------------------------------------------------------------------------
Qt::ItemFlags PdmUiTreeViewQModel::flags( const QModelIndex& index ) const
{
if ( !index.isValid() )
{
return Qt::ItemIsEnabled;
}
Qt::ItemFlags flagMask = QAbstractItemModel::flags( index );
PdmUiTreeOrdering* treeItem = treeItemFromIndex( index );
CAF_ASSERT( treeItem );
if ( treeItem->isRepresentingObject() )
{
PdmUiObjectHandle* pdmUiObject = uiObj( treeItem->object() );
if ( pdmUiObject )
{
if ( pdmUiObject->userDescriptionField() &&
!pdmUiObject->userDescriptionField()->uiCapability()->isUiReadOnly() )
{
flagMask = flagMask | Qt::ItemIsEditable;
}
if ( pdmUiObject->objectToggleField() )
{
flagMask = flagMask | Qt::ItemIsUserCheckable;
}
}
}
if ( treeItem->isValid() )
{
if ( treeItem->activeItem()->isUiReadOnly() )
{
flagMask = flagMask & ( ~Qt::ItemIsEnabled );
}
}
if ( m_dragDropInterface )
{
Qt::ItemFlags dragDropFlags = m_dragDropInterface->flags( index );
flagMask |= dragDropFlags;
}
return flagMask;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QVariant PdmUiTreeViewQModel::headerData( int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole */ ) const
{
if ( role != Qt::DisplayRole ) return QVariant();
if ( section < m_columnHeaders.size() )
{
return m_columnHeaders[section];
}
return QVariant();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiItem* PdmUiTreeViewQModel::uiItemFromModelIndex( const QModelIndex& index ) const
{
PdmUiTreeOrdering* treeItem = this->treeItemFromIndex( index );
if ( treeItem )
{
return treeItem->activeItem();
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewQModel::setDragDropInterface( PdmUiDragDropInterface* dragDropInterface )
{
m_dragDropInterface = dragDropInterface;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiDragDropInterface* PdmUiTreeViewQModel::dragDropInterface()
{
return m_dragDropInterface;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList PdmUiTreeViewQModel::mimeTypes() const
{
if ( m_dragDropInterface )
{
return m_dragDropInterface->mimeTypes();
}
else
{
return QAbstractItemModel::mimeTypes();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QMimeData* PdmUiTreeViewQModel::mimeData( const QModelIndexList& indexes ) const
{
if ( m_dragDropInterface )
{
QStringList objectPaths;
for ( const auto& i : indexes )
{
auto uiObjHandle = dynamic_cast<PdmUiObjectHandle*>( uiItemFromModelIndex( i ) );
if ( uiObjHandle && uiObjHandle->objectHandle() )
{
auto objHandle = uiObjHandle->objectHandle();
auto root = PdmReferenceHelper::findRoot( objHandle );
auto path = PdmReferenceHelper::referenceFromRootToObject( root, objHandle );
objectPaths.push_back( path );
}
}
auto mimeDataObject = m_dragDropInterface->mimeData( indexes );
QByteArray data;
QDataStream dataStreamWrite( &data, QIODevice::WriteOnly );
dataStreamWrite << objectPaths;
QString mimeType = PdmUiDragDropInterface::mimeTypeForObjectReferenceList();
// The QModelIndexList is useful for drag and drop internally in one tree widget. If we
// drag from a tree into other widgets, it is useful to have the full path as text from root to object.
mimeDataObject->setData( mimeType, data );
return mimeDataObject;
}
else
{
return QAbstractItemModel::mimeData( indexes );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmUiTreeViewQModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
{
if ( m_dragDropInterface )
{
return m_dragDropInterface->dropMimeData( data, action, row, column, parent );
}
else
{
return QAbstractItemModel::dropMimeData( data, action, row, column, parent );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Qt::DropActions PdmUiTreeViewQModel::supportedDropActions() const
{
if ( m_dragDropInterface )
{
return m_dragDropInterface->supportedDropActions();
}
else
{
return QAbstractItemModel::supportedDropActions();
}
}
} // end namespace caf