/*========================================================================= Program: Visualization Toolkit Module: vtkQtTableView.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /*------------------------------------------------------------------------- Copyright 2008 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. -------------------------------------------------------------------------*/ #include "vtkQtTableView.h" #include #include #include #include #include "vtkAbstractArray.h" #include "vtkAddMembershipArray.h" #include "vtkAlgorithm.h" #include "vtkAlgorithmOutput.h" #include "vtkAnnotation.h" #include "vtkAnnotationLayers.h" #include "vtkAnnotationLink.h" #include "vtkApplyColors.h" #include "vtkConvertSelection.h" #include "vtkDataObjectToTable.h" #include "vtkDataRepresentation.h" #include "vtkDataSetAttributes.h" #include "vtkGraph.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkLookupTable.h" #include "vtkObjectFactory.h" #include "vtkOutEdgeIterator.h" #include "vtkQtTableModelAdapter.h" #include "vtkSelection.h" #include "vtkSelectionNode.h" #include "vtkSmartPointer.h" #include "vtkTable.h" #include "vtkViewTheme.h" vtkStandardNewMacro(vtkQtTableView); //------------------------------------------------------------------------------ vtkQtTableView::vtkQtTableView() { this->ApplyColors = vtkSmartPointer::New(); this->DataObjectToTable = vtkSmartPointer::New(); this->AddSelectedColumn = vtkSmartPointer::New(); this->AddSelectedColumn->SetInputConnection(0, this->DataObjectToTable->GetOutputPort()); this->DataObjectToTable->SetFieldType(vtkDataObjectToTable::VERTEX_DATA); this->AddSelectedColumn->SetFieldType(vtkAddMembershipArray::VERTEX_DATA); this->FieldType = vtkQtTableView::VERTEX_DATA; this->AddSelectedColumn->SetOutputArrayName("vtkAddMembershipArray membership"); this->TableView = new QTableView(); this->TableAdapter = new vtkQtTableModelAdapter(); this->TableSorter = new QSortFilterProxyModel(); this->TableSorter->setSourceModel(this->TableAdapter); this->TableView->setModel(this->TableSorter); // Set up some default properties this->TableView->setSelectionMode(QAbstractItemView::ExtendedSelection); this->TableView->setSelectionBehavior(QAbstractItemView::SelectRows); this->TableView->setAlternatingRowColors(true); this->TableView->setSortingEnabled(true); this->TableView->resizeColumnToContents(0); this->TableView->verticalHeader()->setDefaultSectionSize(25); this->LastSelectionMTime = 0; this->LastInputMTime = 0; this->LastMTime = 0; this->ShowAll = true; this->ColumnName = nullptr; this->InSelectionChanged = false; this->ApplyRowColors = false; this->SortSelectionToTop = false; this->ColorArrayNameInternal = nullptr; double defCol[3] = { 0.827, 0.827, 0.827 }; this->ApplyColors->SetDefaultPointColor(defCol); this->ApplyColors->SetUseCurrentAnnotationColor(true); QObject::connect(this->TableView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(slotQtSelectionChanged(const QItemSelection&, const QItemSelection&))); } //------------------------------------------------------------------------------ vtkQtTableView::~vtkQtTableView() { delete this->TableView; delete this->TableAdapter; delete this->TableSorter; this->SetColumnName(nullptr); } //------------------------------------------------------------------------------ QWidget* vtkQtTableView::GetWidget() { return this->TableView; } //------------------------------------------------------------------------------ void vtkQtTableView::SetShowVerticalHeaders(bool state) { if (state) { this->TableView->verticalHeader()->show(); } else { this->TableView->verticalHeader()->hide(); } } //------------------------------------------------------------------------------ void vtkQtTableView::SetShowHorizontalHeaders(bool state) { if (state) { this->TableView->horizontalHeader()->show(); } else { this->TableView->horizontalHeader()->hide(); } } //------------------------------------------------------------------------------ void vtkQtTableView::SetEnableDragDrop(bool state) { this->TableView->setDragEnabled(state); } //------------------------------------------------------------------------------ void vtkQtTableView::SetSortingEnabled(bool state) { this->TableView->setSortingEnabled(state); } //------------------------------------------------------------------------------ void vtkQtTableView::SetFieldType(int type) { this->DataObjectToTable->SetFieldType(type); this->AddSelectedColumn->SetFieldType(type); if (this->FieldType != type) { this->FieldType = type; this->Modified(); } } //------------------------------------------------------------------------------ void vtkQtTableView::SetColumnVisibility(const QString& name, bool s) { for (int j = 0; j < this->TableAdapter->columnCount(); ++j) { QString colName = this->TableAdapter->headerData(j, Qt::Horizontal).toString(); if (colName == name) { if (s) { this->TableView->showColumn(j); } else { this->TableView->hideColumn(j); } break; } } } //------------------------------------------------------------------------------ void vtkQtTableView::SetShowAll(bool s) { if (this->ShowAll != s) { this->ShowAll = s; this->Modified(); } } void vtkQtTableView::SetApplyRowColors(bool value) { if (value != this->ApplyRowColors) { if (value) { this->DataObjectToTable->SetInputConnection(0, this->ApplyColors->GetOutputPort()); } else { vtkDataRepresentation* rep = this->GetRepresentation(); if (rep) { vtkAlgorithmOutput* conn = rep->GetInputConnection(); this->DataObjectToTable->SetInputConnection(0, conn); } } this->ApplyRowColors = value; this->Modified(); } } void vtkQtTableView::SetSortSelectionToTop(bool value) { if (value != this->SortSelectionToTop) { this->SortSelectionToTop = value; this->Modified(); } } //------------------------------------------------------------------------------ void vtkQtTableView::SetSplitMultiComponentColumns(bool value) { this->TableAdapter->SetSplitMultiComponentColumns(value); } //------------------------------------------------------------------------------ bool vtkQtTableView::GetSplitMultiComponentColumns() { return this->TableAdapter->GetSplitMultiComponentColumns(); } void vtkQtTableView::AddRepresentationInternal(vtkDataRepresentation* rep) { vtkAlgorithmOutput *selConn, *annConn, *conn; conn = rep->GetInputConnection(); annConn = rep->GetInternalAnnotationOutputPort(); selConn = rep->GetInternalSelectionOutputPort(); if (!this->ApplyRowColors) { this->DataObjectToTable->SetInputConnection(0, conn); } this->ApplyColors->SetInputConnection(0, conn); if (selConn) { this->AddSelectedColumn->SetInputConnection(1, selConn); } else { vtkSmartPointer empty = vtkSmartPointer::New(); vtkSmartPointer emptyNode = vtkSmartPointer::New(); emptyNode->SetContentType(vtkSelectionNode::INDICES); vtkSmartPointer arr = vtkSmartPointer::New(); emptyNode->SetSelectionList(arr); empty->AddNode(emptyNode); this->AddSelectedColumn->SetInputData(1, empty); } if (annConn) { this->ApplyColors->SetInputConnection(1, annConn); this->AddSelectedColumn->SetInputConnection(2, annConn); } } void vtkQtTableView::RemoveRepresentationInternal(vtkDataRepresentation* rep) { vtkAlgorithmOutput *selConn, *annConn, *conn; conn = rep->GetInputConnection(); selConn = rep->GetInternalSelectionOutputPort(); annConn = rep->GetInternalAnnotationOutputPort(); this->ApplyColors->RemoveInputConnection(0, conn); this->AddSelectedColumn->RemoveInputConnection(1, selConn); this->ApplyColors->RemoveInputConnection(1, annConn); this->AddSelectedColumn->RemoveInputConnection(2, annConn); this->TableAdapter->SetVTKDataObject(nullptr); } void vtkQtTableView::SetColorByArray(bool b) { this->ApplyColors->SetUsePointLookupTable(b); } bool vtkQtTableView::GetColorByArray() { return this->ApplyColors->GetUsePointLookupTable(); } void vtkQtTableView::SetColorArrayName(const char* name) { this->SetColorArrayNameInternal(name); this->ApplyColors->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_ROWS, name); } const char* vtkQtTableView::GetColorArrayName() { return this->GetColorArrayNameInternal(); } //------------------------------------------------------------------------------ void vtkQtTableView::slotQtSelectionChanged( const QItemSelection& vtkNotUsed(s1), const QItemSelection& vtkNotUsed(s2)) { // Convert to the correct type of selection vtkDataObject* data = this->TableAdapter->GetVTKDataObject(); if (!data) return; this->InSelectionChanged = true; // Map the selected rows through the sorter map before sending to model const QModelIndexList selectedRows = this->TableView->selectionModel()->selectedRows(); QModelIndexList origRows; for (int i = 0; i < selectedRows.size(); ++i) { origRows.push_back(this->TableSorter->mapToSource(selectedRows[i])); } vtkSelection* VTKIndexSelectList = this->TableAdapter->QModelIndexListToVTKIndexSelection(origRows); // Convert to the correct type of selection vtkDataRepresentation* rep = this->GetRepresentation(); vtkSmartPointer converted; converted.TakeReference(vtkConvertSelection::ToSelectionType( VTKIndexSelectList, data, rep->GetSelectionType(), nullptr)); // Call select on the representation rep->Select(this, converted); this->InSelectionChanged = false; // Delete the selection list VTKIndexSelectList->Delete(); this->LastSelectionMTime = rep->GetAnnotationLink()->GetMTime(); this->InSelectionChanged = true; } //------------------------------------------------------------------------------ void vtkQtTableView::SetVTKSelection() { if (this->InSelectionChanged) { // If we initiated the selection, do nothing. return; } vtkDataRepresentation* rep = this->GetRepresentation(); vtkDataObject* d = this->TableAdapter->GetVTKDataObject(); vtkAlgorithmOutput* annConn = rep->GetInternalAnnotationOutputPort(); vtkAnnotationLayers* a = vtkAnnotationLayers::SafeDownCast(annConn->GetProducer()->GetOutputDataObject(0)); vtkSelection* s = a->GetCurrentAnnotation()->GetSelection(); vtkSmartPointer selection; selection.TakeReference(vtkConvertSelection::ToSelectionType( s, d, vtkSelectionNode::INDICES, nullptr, vtkSelectionNode::ROW)); if (!selection || selection->GetNumberOfNodes() == 0) { return; } if (selection->GetNode(0)->GetSelectionList()->GetNumberOfTuples()) { QItemSelection qisList = this->TableAdapter->VTKIndexSelectionToQItemSelection(selection); QItemSelection sortedSel = this->TableSorter->mapSelectionFromSource(qisList); // Here we want the qt model to have it's selection changed // but we don't want to emit the selection. QObject::disconnect(this->TableView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(slotQtSelectionChanged(const QItemSelection&, const QItemSelection&))); this->TableView->selectionModel()->select( sortedSel, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); QObject::connect(this->TableView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(slotQtSelectionChanged(const QItemSelection&, const QItemSelection&))); if (this->SortSelectionToTop) { for (int j = 0; j < this->TableAdapter->columnCount(); ++j) { QString colName = this->TableAdapter->headerData(j, Qt::Horizontal).toString(); if (colName == "vtkAddMembershipArray membership") { this->TableView->sortByColumn(j, Qt::DescendingOrder); } } this->TableView->scrollToTop(); } } } //------------------------------------------------------------------------------ void vtkQtTableView::Update() { vtkView::Update(); if (this->InSelectionChanged) { this->InSelectionChanged = false; return; } vtkDataRepresentation* rep = this->GetRepresentation(); if (!rep) { this->TableAdapter->reset(); return; } vtkAlgorithmOutput *selConn, *annConn, *conn; conn = rep->GetInputConnection(); annConn = rep->GetInternalAnnotationOutputPort(); selConn = rep->GetInternalSelectionOutputPort(); vtkDataObject* d = conn->GetProducer()->GetOutputDataObject(0); vtkMTimeType atime = rep->GetAnnotationLink()->GetMTime(); if (d->GetMTime() > this->LastInputMTime || this->GetMTime() > this->LastMTime || atime > this->LastSelectionMTime) { annConn->GetProducer()->Update(); selConn->GetProducer()->Update(); this->TableAdapter->SetVTKDataObject(nullptr); if (this->ApplyRowColors) { this->ApplyColors->Update(); } this->DataObjectToTable->Update(); if (this->SortSelectionToTop) { this->AddSelectedColumn->Update(); this->TableAdapter->SetVTKDataObject(this->AddSelectedColumn->GetOutput()); } else { this->TableAdapter->SetVTKDataObject(this->DataObjectToTable->GetOutput()); } if (this->ApplyRowColors) { this->TableAdapter->SetColorColumnName("vtkApplyColors color"); } // if(this->TableAdapter->columnCount()>0 && // d->GetMTime() > this->LastInputMTime) // { // this->TableView->sortByColumn(0, Qt::DescendingOrder); // } if (atime > this->LastSelectionMTime) { this->SetVTKSelection(); } this->LastSelectionMTime = atime; this->LastInputMTime = d->GetMTime(); this->LastMTime = this->GetMTime(); } this->TableView->update(); if (this->TableView->columnWidth(0) < 100) { this->TableView->setColumnWidth(0, 100); } for (int j = 0; j < this->TableAdapter->columnCount(); ++j) { QString colName = this->TableAdapter->headerData(j, Qt::Horizontal).toString(); if (colName == "vtkApplyColors color" || colName == "vtkAddMembershipArray membership") { this->TableView->hideColumn(j); } /* else if(this->ShowAll) { this->TableView->showColumn(j); } else { if(colName == this->ColumnName) { this->TableView->showColumn(j); this->TableView->resizeColumnToContents(j); } else { this->TableView->hideColumn(j); } } */ } } void vtkQtTableView::SetSelectionBehavior(int type) { switch (type) { case SELECT_ITEMS: this->TableView->setSelectionBehavior(QAbstractItemView::SelectItems); break; case SELECT_ROWS: this->TableView->setSelectionBehavior(QAbstractItemView::SelectRows); break; case SELECT_COLUMNS: this->TableView->setSelectionBehavior(QAbstractItemView::SelectColumns); break; } } int vtkQtTableView::GetSelectionBehavior() { switch (this->TableView->selectionBehavior()) { case QAbstractItemView::SelectItems: return SELECT_ITEMS; case QAbstractItemView::SelectRows: return SELECT_ROWS; case QAbstractItemView::SelectColumns: return SELECT_COLUMNS; } return SELECT_ITEMS; } void vtkQtTableView::GetSelectedItems(vtkIdTypeArray* arr) { if (!arr) { return; } arr->Initialize(); if (this->TableView->selectionBehavior() == QAbstractItemView::SelectItems) { arr->SetNumberOfComponents(2); const QModelIndexList selectedItems = this->TableView->selectionModel()->selectedIndexes(); for (int i = 0; i < selectedItems.size(); i++) { QModelIndex orig = this->TableSorter->mapToSource(selectedItems.at(i)); arr->InsertNextValue(orig.row()); arr->InsertNextValue(orig.column()); } } else if (this->TableView->selectionBehavior() == QAbstractItemView::SelectRows) { arr->SetNumberOfComponents(1); const QModelIndexList selectedRows = this->TableView->selectionModel()->selectedRows(); QSet unique_ids; for (int i = 0; i < selectedRows.size(); ++i) { QModelIndex orig = this->TableSorter->mapToSource(selectedRows[i]); unique_ids.insert(orig.row()); } QSet::iterator iter; for (iter = unique_ids.begin(); iter != unique_ids.end(); ++iter) { arr->InsertNextValue(*iter); } } else { arr->SetNumberOfComponents(1); const QModelIndexList selectedColumns = this->TableView->selectionModel()->selectedColumns(); QSet unique_ids; for (int i = 0; i < selectedColumns.size(); i++) { QModelIndex orig = this->TableSorter->mapToSource(selectedColumns[i]); unique_ids.insert(orig.column()); } QSet::iterator iter; for (iter = unique_ids.begin(); iter != unique_ids.end(); ++iter) { arr->InsertNextValue(*iter); } } } void vtkQtTableView::ApplyViewTheme(vtkViewTheme* theme) { this->Superclass::ApplyViewTheme(theme); this->ApplyColors->SetPointLookupTable(theme->GetPointLookupTable()); this->ApplyColors->SetDefaultPointColor(theme->GetPointColor()); this->ApplyColors->SetDefaultPointOpacity(theme->GetPointOpacity()); this->ApplyColors->SetDefaultCellColor(theme->GetCellColor()); this->ApplyColors->SetDefaultCellOpacity(theme->GetCellOpacity()); this->ApplyColors->SetSelectedPointColor(theme->GetSelectedPointColor()); this->ApplyColors->SetSelectedPointOpacity(theme->GetSelectedPointOpacity()); this->ApplyColors->SetSelectedCellColor(theme->GetSelectedCellColor()); this->ApplyColors->SetSelectedCellOpacity(theme->GetSelectedCellOpacity()); } //------------------------------------------------------------------------------ void vtkQtTableView::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "ShowAll: " << (this->ShowAll ? "true" : "false") << endl; os << indent << "ApplyRowColors: " << (this->ApplyRowColors ? "true" : "false") << endl; os << indent << "SortSelectionToTop: " << (this->SortSelectionToTop ? "true" : "false") << endl; os << indent << "ColumnName: " << (this->ColumnName ? this->ColumnName : "(none)") << endl; }