#6258 General way of reordering child items in the tree view

This commit is contained in:
Gaute Lindkvist 2020-08-05 13:52:08 +02:00
parent c1bc522511
commit 1ad1f7cc05
13 changed files with 591 additions and 96 deletions

View File

@ -28,6 +28,8 @@ set( PROJECT_FILES
cafPdmFieldHandle.cpp
cafPdmFieldHandle.h
cafPdmObjectCapability.h
cafPdmFieldReorderCapability.cpp
cafPdmFieldReorderCapability.h
cafPdmObjectHandle.cpp
cafPdmObjectHandle.h
cafPdmPointer.cpp

View File

@ -151,8 +151,6 @@ void PdmChildArrayField<DataType*>::deleteAllChildObjectsAsync()
//--------------------------------------------------------------------------------------------------
/// Removes the pointer at index from the container. Does not delete the object pointed to.
/// Todo: This implementation can't be necessary in the new regime. Should be to just remove
/// the item at index (shrinking the array)
//--------------------------------------------------------------------------------------------------
template <typename DataType>
void PdmChildArrayField<DataType*>::erase( size_t index )

View File

@ -0,0 +1,143 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2020- 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 "cafPdmFieldReorderCapability.h"
#include "cafAssert.h"
using namespace caf;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmFieldReorderCapability::PdmFieldReorderCapability( PdmPtrArrayFieldHandle* field, bool giveOwnership )
: orderChanged( this )
, m_field( field )
{
field->addCapability( this, giveOwnership );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmFieldReorderCapability::itemCanBeMovedUp( size_t index ) const
{
return index != 0u;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmFieldReorderCapability::itemCanBeMovedDown( size_t index ) const
{
return m_field->size() > 1u && index < m_field->size() - 1u;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmFieldReorderCapability::moveItemUp( size_t index )
{
if ( itemCanBeMovedUp( index ) )
{
PdmObjectHandle* itemToShift = m_field->at( index );
if ( itemToShift )
{
size_t newIndex = index - 1u;
m_field->erase( index );
m_field->insertAt( (int)newIndex, itemToShift );
orderChanged.send();
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmFieldReorderCapability::moveItemDown( size_t index )
{
if ( itemCanBeMovedDown( index ) )
{
PdmObjectHandle* itemToShift = m_field->at( index );
if ( itemToShift )
{
size_t newIndex = index + 1u;
m_field->erase( index );
m_field->insertAt( (int)newIndex, itemToShift );
orderChanged.send();
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmFieldReorderCapability* PdmFieldReorderCapability::addToField( PdmPtrArrayFieldHandle* field )
{
if ( !fieldIsReorderable( field ) )
{
new PdmFieldReorderCapability( field, true );
}
return field->capability<PdmFieldReorderCapability>();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmFieldReorderCapability::fieldIsReorderable( PdmPtrArrayFieldHandle* field )
{
return field->capability<PdmFieldReorderCapability>() != nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmFieldReorderCapability::onMoveItemUp( const SignalEmitter* emitter, size_t index )
{
moveItemUp( index );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmFieldReorderCapability::onMoveItemDown( const SignalEmitter* emitter, size_t index )
{
moveItemDown( index );
}

View File

@ -0,0 +1,68 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2020- 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.
//
//##################################################################################################
#pragma once
#include "cafPdmFieldCapability.h"
#include "cafPdmPtrArrayFieldHandle.h"
#include "cafSignal.h"
namespace caf
{
class PdmFieldReorderCapability : public PdmFieldCapability, public SignalEmitter, public SignalObserver
{
public:
Signal<> orderChanged;
public:
PdmFieldReorderCapability( PdmPtrArrayFieldHandle* field, bool giveOwnership );
bool itemCanBeMovedUp( size_t index ) const;
bool itemCanBeMovedDown( size_t index ) const;
bool moveItemUp( size_t index );
bool moveItemDown( size_t index );
static PdmFieldReorderCapability* addToField( PdmPtrArrayFieldHandle* field );
static bool fieldIsReorderable( PdmPtrArrayFieldHandle* field );
void onMoveItemUp( const SignalEmitter* emitter, size_t index );
void onMoveItemDown( const SignalEmitter* emitter, size_t index );
private:
PdmPtrArrayFieldHandle* m_field;
};
}; // namespace caf

View File

@ -24,4 +24,4 @@ public:
virtual PdmObjectHandle* at( size_t index ) = 0;
};
} // namespace caf
} // namespace caf

View File

@ -133,6 +133,26 @@ public:
: m_emitter( emitter )
{
}
Signal( const Signal& rhs )
: m_emitter( rhs.m_emitter )
{
for ( auto observerCallbackPair : rhs.m_observerCallbacks )
{
connect( observerCallbackPair.first, observerCallbackPair.second.first );
}
}
Signal& operator=( const Signal& rhs )
{
m_emitter = rhs.m_emitter;
for ( auto observerCallbackPair : rhs.m_observerCallbacks )
{
connect( observerCallbackPair.first, observerCallbackPair.second.first );
}
return *this;
}
virtual ~Signal()
{
for ( auto observerCallbackPair : m_observerCallbacks )
@ -144,13 +164,18 @@ public:
template <typename ClassType>
void connect( ClassType* observer, void ( ClassType::*method )( const SignalEmitter*, Args... args ) )
{
static_assert( std::is_convertible<ClassType*, SignalObserver*>::value,
"Only classes that inherit SignalObserver can connect as an observer of a Signal." );
MemberCallback lambda = [=]( const SignalEmitter* emitter, Args... args ) {
// Call method
( observer->*method )( emitter, args... );
};
m_observerCallbacks[observer] = std::make_pair( lambda, true );
connect( observer, lambda );
}
template <typename ClassType>
void connect( ClassType* observer, const MemberCallback& callback )
{
static_assert( std::is_convertible<ClassType*, SignalObserver*>::value,
"Only classes that inherit SignalObserver can connect as an observer of a Signal." );
m_observerCallbacks[observer] = std::make_pair( callback, true );
observer->beingDeleted.connect( this );
}
@ -184,9 +209,6 @@ public:
size_t observerCount() const { return m_observerCallbacks.size(); }
private:
Signal( const Signal& rhs ) = default;
Signal& operator=( const Signal& rhs ) = default;
std::map<SignalObserver*, MemberCallbackAndActiveFlag> m_observerCallbacks;
const SignalEmitter* m_emitter;
};

View File

@ -78,6 +78,21 @@ set( PROJECT_FILES
cafFontTools.h
)
# NOTE! Resources in this subfolder appends to the variable QRC_FILES in parent scope
# CMakeList.txt in the application folder (parent scope) must use the following syntax
# to make sure the QRC_FILES variable contains appended files in subfolders
# set( QRC_FILES
# ${QRC_FILES}
# Resources/MyaApplication.qrc
# )
set( QRC_FILES
${QRC_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/Resources/caf.qrc
PARENT_SCOPE
)
add_library( ${PROJECT_NAME}
${PROJECT_FILES}
${MOC_SOURCE_FILES}

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/caf">
<file>Down16x16.png</file>
<file>Up16x16.png</file>
</qresource>
</RCC>

View File

@ -171,10 +171,9 @@ set( PROJECT_FILES
)
add_library( ${PROJECT_NAME}
${PROJECT_FILES}
${PROJECT_FILES}
${MOC_SOURCE_FILES}
${QRC_FILES_CPP}
)
if (MSVC)

View File

@ -38,7 +38,9 @@
#include "cafPdmChildArrayField.h"
#include "cafPdmField.h"
#include "cafPdmFieldReorderCapability.h"
#include "cafPdmObject.h"
#include "cafPdmPtrArrayFieldHandle.h"
#include "cafPdmUiCommandSystemProxy.h"
#include "cafPdmUiDragDropInterface.h"
#include "cafPdmUiEditorHandle.h"
@ -46,9 +48,11 @@
#include "cafPdmUiTreeViewQModel.h"
#include "cafSelectionManager.h"
#include <QDebug>
#include <QDragMoveEvent>
#include <QEvent>
#include <QGridLayout>
#include <QIcon>
#include <QMenu>
#include <QModelIndexList>
#include <QPainter>
@ -132,7 +136,7 @@ QWidget* PdmUiTreeViewEditor::createWidget( QWidget* parent )
m_treeView->setModel( m_treeViewModel );
m_treeView->installEventFilter( this );
m_delegate = new PdmUiTreeViewItemDelegate( m_treeView, m_treeViewModel );
m_delegate = new PdmUiTreeViewItemDelegate( this, m_treeViewModel );
m_treeView->setItemDelegate( m_delegate );
@ -177,7 +181,7 @@ void PdmUiTreeViewEditor::configureAndUpdateUi( const QString& uiConfigName )
if ( m_delegate )
{
m_delegate->clearAttributes();
m_delegate->clearAllTags();
updateItemDelegateForSubTree();
}
}
@ -190,6 +194,14 @@ QTreeView* PdmUiTreeViewEditor::treeView()
return m_treeView;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const QTreeView* PdmUiTreeViewEditor::treeView() const
{
return m_treeView;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -365,7 +377,7 @@ void PdmUiTreeViewEditor::selectItems( std::vector<const PdmUiItem*> uiItems )
void PdmUiTreeViewEditor::slotOnSelectionChanged( const QItemSelection& selected, const QItemSelection& deselected )
{
this->updateSelectionManager();
this->updateItemDelegateForSubTree();
emit selectionChanged();
}
@ -442,15 +454,67 @@ void PdmUiTreeViewEditor::updateItemDelegateForSubTree( const QModelIndex& model
auto allIndices = m_treeViewModel->allIndicesRecursive();
for ( QModelIndex index : allIndices )
{
m_delegate->clearTags( index );
PdmUiItem* uiItem = m_treeViewModel->uiItemFromModelIndex( index );
PdmUiObjectHandle* uiObjectHandle = dynamic_cast<PdmUiObjectHandle*>( uiItem );
if ( uiObjectHandle )
{
PdmObjectHandle* pdmObject = uiObjectHandle->objectHandle();
if ( pdmObject )
{
PdmPtrArrayFieldHandle* arrayField = dynamic_cast<PdmPtrArrayFieldHandle*>( pdmObject->parentField() );
if ( arrayField )
{
PdmFieldReorderCapability* reorderability = arrayField->capability<PdmFieldReorderCapability>();
std::vector<PdmUiItem*> selection;
selectedUiItems( selection );
if ( reorderability && index.row() >= 0 && selection.size() == 1u && selection.front() == uiItem )
{
size_t indexInParent = static_cast<size_t>( index.row() );
{
caf::PdmUiTreeViewItemAttribute::Tag tag;
tag.icon = caf::IconProvider( ":/caf/Up16x16.png" );
tag.selectedOnly = true;
if ( reorderability->itemCanBeMovedUp( indexInParent ) )
{
tag.clicked.connect( reorderability, &PdmFieldReorderCapability::onMoveItemUp );
}
else
{
tag.icon.setActive( false );
}
m_delegate->addTag( index, tag );
}
{
caf::PdmUiTreeViewItemAttribute::Tag tag;
tag.icon = caf::IconProvider( ":/caf/Down16x16.png" );
tag.selectedOnly = true;
if ( reorderability->itemCanBeMovedDown( indexInParent ) )
{
tag.clicked.connect( reorderability, &PdmFieldReorderCapability::onMoveItemDown );
}
else
{
tag.icon.setActive( false );
}
m_delegate->addTag( index, tag );
}
}
}
}
PdmUiTreeViewItemAttribute attribute;
uiObjectHandle->objectEditorAttribute( "", &attribute );
if ( !attribute.tag.isEmpty() )
for ( const PdmUiTreeViewItemAttribute::Tag& tag : attribute.tags )
{
m_delegate->addAttribute( index, attribute );
if ( !tag.text.isEmpty() || tag.icon.valid() )
{
m_delegate->addTag( index, tag );
}
}
}
}
@ -475,8 +539,9 @@ bool PdmUiTreeViewEditor::isAppendOfClassNameToUiItemTextEnabled()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiTreeViewItemDelegate::PdmUiTreeViewItemDelegate( QObject* parent, PdmUiTreeViewQModel* model )
: QStyledItemDelegate( parent )
PdmUiTreeViewItemDelegate::PdmUiTreeViewItemDelegate( PdmUiTreeViewEditor* parent, PdmUiTreeViewQModel* model )
: QStyledItemDelegate( parent->treeView() )
, m_treeView( parent )
, m_model( model )
{
}
@ -484,17 +549,66 @@ PdmUiTreeViewItemDelegate::PdmUiTreeViewItemDelegate( QObject* parent, PdmUiTree
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewItemDelegate::clearAttributes()
void PdmUiTreeViewItemDelegate::clearTags( QModelIndex index )
{
m_attributes.clear();
m_tags.erase( index );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewItemDelegate::addAttribute( QModelIndex index, const PdmUiTreeViewItemAttribute& attribute )
void PdmUiTreeViewItemDelegate::clearAllTags()
{
m_attributes[index] = attribute;
m_tags.clear();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeViewItemDelegate::addTag( QModelIndex index, const PdmUiTreeViewItemAttribute::Tag& tag )
{
std::vector<PdmUiTreeViewItemAttribute::Tag>& tagList = m_tags[index];
tagList.push_back( tag );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QRect PdmUiTreeViewItemDelegate::tagRect( const QRect& itemRect, QModelIndex index, size_t tagIndex ) const
{
auto it = m_tags.find( index );
if ( it == m_tags.end() ) return QRect();
QSize fullSize = itemRect.size();
QPoint offset( 0, 0 );
for ( size_t i = 0; i < it->second.size(); ++i )
{
const PdmUiTreeViewItemAttribute::Tag& tag = it->second[i];
if ( tag.icon.valid() )
{
auto icon = tag.icon.icon();
QSize iconSize = icon->actualSize( fullSize );
QRect iconRect;
if ( tag.position == PdmUiTreeViewItemAttribute::Tag::AT_END )
{
QPoint bottomRight = itemRect.bottomRight() - offset;
QPoint topLeft = bottomRight - QPoint( iconSize.width(), iconSize.height() );
iconRect = QRect( topLeft, bottomRight );
}
else
{
QPoint topLeft = itemRect.topLeft() + offset;
QPoint bottomRight = topLeft + QPoint( iconSize.width(), iconSize.height() );
iconRect = QRect( topLeft, bottomRight );
}
offset += QPoint( iconSize.width() + 2, 0 );
if ( i == tagIndex ) return iconRect;
}
}
return QRect();
}
//--------------------------------------------------------------------------------------------------
@ -504,68 +618,167 @@ void PdmUiTreeViewItemDelegate::paint( QPainter* painter, const QStyleOptionView
{
QStyledItemDelegate::paint( painter, option, index );
auto it = m_attributes.find( index );
if ( it == m_attributes.end() ) return;
auto it = m_tags.find( index );
if ( it == m_tags.end() ) return;
// Save painter so we can restore it
painter->save();
const int insideTopBottomMargins = 1;
const int insideleftRightMargins = 6;
const int outsideLeftRightMargins = 4;
QFont font = QApplication::font();
if ( font.pixelSize() > 0 )
{
font.setPixelSize( std::max( 1, font.pixelSize() - 1 ) );
}
else
{
font.setPointSize( std::max( 1, font.pointSize() - 1 ) );
}
painter->setFont( font );
QString text = it->second.tag;
QColor bgColor = it->second.bgColor;
QColor fgColor = it->second.fgColor;
QSize textSize( QFontMetrics( font ).size( Qt::TextSingleLine, text ) );
QRect rect = option.rect;
QSize fullSize = rect.size();
int textDiff = ( fullSize.height() - textSize.height() );
QRect textRect;
if ( it->second.position == PdmUiTreeViewItemAttribute::AT_END )
QPoint offset( 0, 0 );
for ( const PdmUiTreeViewItemAttribute::Tag& tag : it->second )
{
QPoint bottomRight = rect.bottomRight() - QPoint( outsideLeftRightMargins, 0 );
QPoint textBottomRight = bottomRight - QPoint( insideleftRightMargins, textDiff / 2 );
QPoint textTopLeft = textBottomRight - QPoint( textSize.width(), textSize.height() );
textRect = QRect( textTopLeft, textBottomRight );
if ( tag.selectedOnly && !( option.state & QStyle::State_Selected ) ) continue;
if ( tag.icon.valid() )
{
auto icon = tag.icon.icon();
QSize iconSize = icon->actualSize( fullSize );
QRect iconRect;
if ( tag.position == PdmUiTreeViewItemAttribute::Tag::AT_END )
{
QPoint bottomRight = rect.bottomRight() - offset;
QPoint topLeft = bottomRight - QPoint( iconSize.width(), iconSize.height() );
iconRect = QRect( topLeft, bottomRight );
}
else
{
QPoint topLeft = rect.topLeft() + offset;
QPoint bottomRight = topLeft + QPoint( iconSize.width(), iconSize.height() );
iconRect = QRect( topLeft, bottomRight );
}
offset += QPoint( iconSize.width() + 2, 0 );
icon->paint( painter, iconRect );
}
else
{
const int insideTopBottomMargins = 1;
const int insideleftRightMargins = 6;
const int outsideLeftRightMargins = 4;
QFont font = QApplication::font();
if ( font.pixelSize() > 0 )
{
font.setPixelSize( std::max( 1, font.pixelSize() - 1 ) );
}
else
{
font.setPointSize( std::max( 1, font.pointSize() - 1 ) );
}
painter->setFont( font );
QString text = tag.text;
QColor bgColor = tag.bgColor;
QColor fgColor = tag.fgColor;
QSize textSize( QFontMetrics( font ).size( Qt::TextSingleLine, text ) );
int textDiff = ( fullSize.height() - textSize.height() );
QRect textRect;
if ( tag.position == PdmUiTreeViewItemAttribute::Tag::AT_END )
{
QPoint bottomRight = rect.bottomRight() - QPoint( outsideLeftRightMargins, 0 ) - offset;
QPoint textBottomRight = bottomRight - QPoint( insideleftRightMargins, textDiff / 2 );
QPoint textTopLeft = textBottomRight - QPoint( textSize.width(), textSize.height() );
textRect = QRect( textTopLeft, textBottomRight );
}
else
{
QPoint textTopLeft = QPoint( 0, rect.topLeft().y() ) + offset +
QPoint( outsideLeftRightMargins + insideleftRightMargins, +textDiff / 2 );
QPoint textBottomRight = textTopLeft + QPoint( textSize.width(), textSize.height() );
textRect = QRect( textTopLeft, textBottomRight );
}
QRect tagRect = textRect.marginsAdded(
QMargins( insideleftRightMargins, insideTopBottomMargins, insideleftRightMargins, insideTopBottomMargins ) );
offset += QPoint( tagRect.width() + 2, 0 );
QBrush brush( bgColor );
painter->setBrush( brush );
painter->setPen( bgColor );
painter->setRenderHint( QPainter::Antialiasing );
const double xRoundingRadiusPercent = 50.0;
const double yRoundingRadiusPercent = 25.0;
painter->drawRoundedRect( tagRect, xRoundingRadiusPercent, yRoundingRadiusPercent, Qt::RelativeSize );
painter->setPen( fgColor );
painter->drawText( textRect, Qt::AlignCenter, text );
}
}
else
{
QPoint textTopLeft = QPoint( 0, rect.topLeft().y() ) +
QPoint( outsideLeftRightMargins + insideleftRightMargins, +textDiff / 2 );
QPoint textBottomRight = textTopLeft + QPoint( textSize.width(), textSize.height() );
textRect = QRect( textTopLeft, textBottomRight );
}
QRect tagRect = textRect.marginsAdded(
QMargins( insideleftRightMargins, insideTopBottomMargins, insideleftRightMargins, insideTopBottomMargins ) );
QBrush brush( bgColor );
painter->setBrush( brush );
painter->setPen( bgColor );
painter->setRenderHint( QPainter::Antialiasing );
const double xRoundingRadiusPercent = 50.0;
const double yRoundingRadiusPercent = 25.0;
painter->drawRoundedRect( tagRect, xRoundingRadiusPercent, yRoundingRadiusPercent, Qt::RelativeSize );
painter->setPen( fgColor );
painter->drawText( textRect, Qt::AlignCenter, text );
// Restore painter
painter->restore();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<caf::PdmUiTreeViewItemAttribute::Tag> PdmUiTreeViewItemDelegate::tags( QModelIndex index ) const
{
auto it = m_tags.find( index );
return it != m_tags.end() ? it->second : std::vector<caf::PdmUiTreeViewItemAttribute::Tag>();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmUiTreeViewItemDelegate::editorEvent( QEvent* event,
QAbstractItemModel* model,
const QStyleOptionViewItem& option,
const QModelIndex& itemIndex )
{
if ( event->type() == QEvent::MouseButtonPress )
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>( event );
if ( mouseEvent->button() == Qt::LeftButton && mouseEvent->modifiers() == Qt::NoModifier )
{
PdmUiTreeViewItemAttribute::Tag tag;
if ( tagClicked( mouseEvent->pos(), option.rect, itemIndex, &tag ) )
{
QModelIndex parentIndex = itemIndex.parent();
auto uiItem = m_treeView->uiItemFromModelIndex( itemIndex );
auto parentUiItem = m_treeView->uiItemFromModelIndex( parentIndex );
tag.clicked.send( (size_t)itemIndex.row() );
m_treeView->updateSubTree( parentUiItem );
m_treeView->selectAsCurrentItem( uiItem );
}
}
}
return QStyledItemDelegate::editorEvent( event, model, option, itemIndex );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmUiTreeViewItemDelegate::tagClicked( const QPoint& pos,
const QRect& itemRect,
const QModelIndex& itemIndex,
PdmUiTreeViewItemAttribute::Tag* tag ) const
{
if ( itemIndex.isValid() )
{
auto itemTags = tags( itemIndex );
for ( size_t i = 0; i < itemTags.size(); ++i )
{
QRect rect = tagRect( itemRect, itemIndex, i );
if ( rect.contains( pos ) )
{
*tag = itemTags[i];
return true;
}
}
}
return false;
}
} // end namespace caf

View File

@ -36,9 +36,11 @@
#pragma once
#include "cafIconProvider.h"
#include "cafPdmUiFieldEditorHandle.h"
#include "cafPdmUiTreeEditorHandle.h"
#include "cafPdmUiTreeViewQModel.h"
#include "cafSignal.h"
#include <QAbstractItemModel>
#include <QColor>
@ -48,6 +50,8 @@
#include <QTreeView>
#include <QWidget>
#include <functional>
class MySortFilterProxyModel;
class QGridLayout;
@ -67,35 +71,60 @@ class PdmUiTreeViewWidget;
class PdmUiTreeViewItemAttribute : public PdmUiEditorAttribute
{
public:
enum Position
struct Tag : public SignalEmitter
{
IN_FRONT,
AT_END
enum Position
{
IN_FRONT,
AT_END
};
Tag()
: text()
, position( AT_END )
, bgColor( Qt::red )
, fgColor( Qt::white )
, selectedOnly( false )
, clicked( this )
{
}
QString text;
IconProvider icon;
Position position;
QColor bgColor;
QColor fgColor;
bool selectedOnly;
caf::Signal<size_t> clicked;
};
PdmUiTreeViewItemAttribute()
: tag()
, position( AT_END )
, bgColor( Qt::red )
, fgColor( Qt::white )
{
}
QString tag;
Position position;
QColor bgColor;
QColor fgColor;
std::vector<Tag> tags;
};
class PdmUiTreeViewItemDelegate : public QStyledItemDelegate
{
public:
PdmUiTreeViewItemDelegate( QObject* parent, PdmUiTreeViewQModel* model );
void clearAttributes();
void addAttribute( QModelIndex index, const PdmUiTreeViewItemAttribute& attribute );
PdmUiTreeViewItemDelegate( PdmUiTreeViewEditor* parent, PdmUiTreeViewQModel* model );
void clearTags( QModelIndex index );
void clearAllTags();
void addTag( QModelIndex index, const PdmUiTreeViewItemAttribute::Tag& tag );
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const override;
std::vector<PdmUiTreeViewItemAttribute::Tag> tags( QModelIndex index ) const;
protected:
bool editorEvent( QEvent* event,
QAbstractItemModel* model,
const QStyleOptionViewItem& option,
const QModelIndex& itemIndex ) override;
bool tagClicked( const QPoint& clickPos,
const QRect& itemRect,
const QModelIndex& itemIndex,
PdmUiTreeViewItemAttribute::Tag* tag ) const;
QRect tagRect( const QRect& itemRect, QModelIndex itemIndex, size_t tagIndex ) const;
private:
PdmUiTreeViewQModel* m_model;
std::map<QModelIndex, PdmUiTreeViewItemAttribute> m_attributes;
PdmUiTreeViewEditor* m_treeView;
PdmUiTreeViewQModel* m_model;
std::map<QModelIndex, std::vector<PdmUiTreeViewItemAttribute::Tag>> m_tags;
};
//--------------------------------------------------------------------------------------------------
@ -129,8 +158,9 @@ public:
void enableAppendOfClassNameToUiItemText( bool enable );
bool isAppendOfClassNameToUiItemTextEnabled();
QTreeView* treeView();
bool isTreeItemEditWidgetActive() const;
QTreeView* treeView();
const QTreeView* treeView() const;
bool isTreeItemEditWidgetActive() const;
void selectAsCurrentItem( const PdmUiItem* uiItem );
void selectItems( std::vector<const PdmUiItem*> uiItems );
@ -151,7 +181,6 @@ protected:
void configureAndUpdateUi( const QString& uiConfigName ) override;
void updateMySubTree( PdmUiItem* uiItem ) override;
void updateContextMenuSignals();
private slots: