coriolis/hurricane/src/viewer/HierarchyWidget.cpp

272 lines
9.0 KiB
C++

// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC/LIP6 2015-2016, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | H U R R I C A N E |
// | V L S I B a c k e n d D a t a - B a s e |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./HierarchyWidget.cpp" |
// +-----------------------------------------------------------------+
#include <QFontMetrics>
#include <QLabel>
#include <QLineEdit>
#include <QHeaderView>
#include <QKeyEvent>
#include <QGroupBox>
#include <QVBoxLayout>
#include <QAction>
#include <QModelIndex>
#include <QTreeView>
#include "hurricane/Commons.h"
#include "hurricane/Warning.h"
#include "hurricane/Net.h"
#include "hurricane/viewer/Graphics.h"
#include "hurricane/viewer/HierarchyModel.h"
#include "hurricane/viewer/HierarchyWidget.h"
namespace Hurricane {
// -------------------------------------------------------------------
// Class : "HierarchyWidget".
HierarchyWidget::HierarchyWidget ( QWidget* parent )
: QWidget (parent)
, _cellWidget (NULL)
, _cell (NULL)
, _baseModel (new HierarchyModel(this))
, _view (new QTreeView(this))
, _filterPatternLineEdit(new QLineEdit(this))
, _rowHeight (20)
{
setAttribute( Qt::WA_DeleteOnClose );
setAttribute( Qt::WA_QuitOnClose, false );
setContextMenuPolicy( Qt::ActionsContextMenu );
_rowHeight = QFontMetrics( Graphics::getFixedFont() ).height() + 4;
//_view->setShowGrid ( false );
_view->setAlternatingRowColors( true );
_view->setSelectionBehavior ( QAbstractItemView::SelectRows );
_view->setSelectionMode ( QAbstractItemView::SingleSelection );
_view->setSortingEnabled ( true );
_view->setModel ( _baseModel );
//_view->resizeColumnToContents ( 1 );
QHeaderView* horizontalHeader = _view->header();
horizontalHeader->setDefaultAlignment ( Qt::AlignHCenter );
horizontalHeader->setMinimumSectionSize( (Graphics::isHighDpi()) ? 600 : 300 );
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
horizontalHeader->setResizeMode ( 0, QHeaderView::Interactive );
horizontalHeader->setResizeMode ( 1, QHeaderView::Interactive );
// #else
// horizontalHeader->setSectionResizeMode ( 0, QHeaderView::Interactive );
// horizontalHeader->setSectionResizeMode ( 1, QHeaderView::Interactive );
#endif
horizontalHeader->setStretchLastSection( true );
QLabel* filterPatternLabel = new QLabel(tr("&Filter pattern:"), this);
filterPatternLabel->setBuddy( _filterPatternLineEdit );
QGridLayout* gLayout = new QGridLayout();
gLayout->addWidget( _view , 1, 0, 1, 2 );
gLayout->addWidget( filterPatternLabel , 2, 0 );
gLayout->addWidget(_filterPatternLineEdit, 2, 1);
setLayout( gLayout );
connect ( _view, SIGNAL(collapsed (const QModelIndex&))
, this , SLOT (collapseHook(const QModelIndex& )) );
connect ( _filterPatternLineEdit , SIGNAL(returnPressed ())
, this , SLOT (textFilterChanged()) );
connect ( _view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&))
, this , SLOT (followSelected (const QItemSelection&,const QItemSelection&)) );
TreeKeyFilter* filter = new TreeKeyFilter( this );
_view->installEventFilter( filter );
resize(300, 300);
}
void HierarchyWidget::setCell ( Cell* cell )
{
if (_cell == cell) return;
_cell = cell;
_view->setVisible( false );
_view->selectionModel()->clear();
_baseModel->setCell( cell );
string windowTitle = "Hierarchy" + getString(cell);
setWindowTitle( tr(windowTitle.c_str()) );
_view->selectionModel()->select( _baseModel->index(0,0,_view->rootIndex())
, QItemSelectionModel::Select|QItemSelectionModel::Rows );
_view->resizeColumnToContents( 0 );
_view->setVisible( true );
}
bool HierarchyWidget::isRSelected ( const QModelIndex& index ) const
{
HierarchyInfos* infos = const_cast<HierarchyInfos*>(_baseModel->infosFromIndex(index));
for ( size_t row=0 ; row < infos->getInstances().size() ; ++row ) {
QModelIndex childIndex = _baseModel->index( row, 0, index );
if (_view->selectionModel()->isSelected(childIndex))
return true;
if (not infos->isCollapsed() and isRSelected(childIndex)) return true;
}
return false;
}
void HierarchyWidget::rexpand ( Path path )
{
if (path.isEmpty()) return;
QModelIndex index = _baseModel->index( 0, 0, QModelIndex() );
do {
Instance* head = path.getHeadInstance();
path = path.getTailPath();
_view->expand( index );
HierarchyInfos* parentInfos = const_cast<HierarchyInfos*>( _baseModel->infosFromIndex(index) );
HierarchyInfos* childInfos = NULL;
for ( HierarchyInfos* child : parentInfos->getInstances() ) {
if (child->getInstance() == head) {
childInfos = child;
break;
}
}
if (not childInfos) {
cerr << Warning("HierarchyWidget::rexpand(): discrepency between Path and Hierarchy.") << endl;
return;
}
index = _baseModel->index( childInfos->getRowInParent(), 0, index );
} while (not path.isEmpty());
_view->selectionModel()->clear();
_view->selectionModel()->select( index, QItemSelectionModel::Select|QItemSelectionModel::Rows );
_view->setCurrentIndex( index );
}
void HierarchyWidget::rexpand ( const QModelIndex& index )
{
HierarchyInfos* infos = const_cast<HierarchyInfos*>(_baseModel->infosFromIndex(index));
if (infos) {
if (not infos->isCollapsed()) {
_view->expand( index );
for ( HierarchyInfos* child : infos->getInstances() ) {
rexpand( _baseModel->index( child->getRowInParent(), 0, index ) );
}
}
}
}
void HierarchyWidget::collapseHook ( const QModelIndex& index )
{
if (isRSelected(index)) {
_view->selectionModel()->clear();
_view->selectionModel()->select( index, QItemSelectionModel::Select|QItemSelectionModel::Rows );
}
HierarchyInfos* infos = const_cast<HierarchyInfos*>(_baseModel->infosFromIndex(index));
infos->collapse();
}
void HierarchyWidget::textFilterChanged ()
{
QModelIndexList selecteds = _view->selectionModel()->selectedIndexes();
if (not selecteds.isEmpty()) {
QModelIndex index = selecteds[0];
HierarchyInfos* infos = const_cast<HierarchyInfos*>(_baseModel->infosFromIndex(index));
infos->setFilterPattern( _filterPatternLineEdit->text() );
_view->reset();
rexpand( _view->rootIndex() );
_view->selectionModel()->select( index, QItemSelectionModel::Select|QItemSelectionModel::Rows );
_view->setCurrentIndex( index );
}
}
void HierarchyWidget::followSelected ( const QItemSelection& selecteds, const QItemSelection& deselecteds )
{
if (selecteds.indexes().isEmpty()) {
//cerr << Warning("HierarchyWidget::followSelected(): Selection should never be empty.") << endl;
return;
}
QModelIndex index = selecteds.indexes()[0];
HierarchyInfos* infos = const_cast<HierarchyInfos*>(_baseModel->infosFromIndex(index));
_filterPatternLineEdit->setText( infos->getFilterPattern() );
}
void HierarchyWidget::goTo ( int delta )
{
if (delta == 0) return;
//QModelIndex newIndex =
_baseModel->index( _view->currentIndex().row()+delta, 0, QModelIndex() );
//if (newIndex.isValid())
// _view->selectRow( newIndex.row() );
}
// -------------------------------------------------------------------
// Class : "TreeKeyFilter".
TreeKeyFilter::TreeKeyFilter ( QObject* parent )
: QObject(parent)
{ }
bool TreeKeyFilter::eventFilter ( QObject* object, QEvent* event )
{
if (event->type() == QEvent::KeyPress) {
HierarchyWidget* owner = qobject_cast<HierarchyWidget*>( parent() );
if (not owner) return false;
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Return) {
QModelIndexList selecteds = owner->_view->selectionModel()->selectedIndexes();
if (not selecteds.isEmpty()) {
QModelIndex index = selecteds[0];
HierarchyInfos* infos = const_cast<HierarchyInfos*>(owner->_baseModel->infosFromIndex(index));
if (infos) {
if (owner->getCellWidget()) {
owner->getCellWidget()->setCell( infos->getMasterCell(), infos->getPath() );
}
}
}
}
}
return QObject::eventFilter( object, event );
}
} // Hurricane namespace.