//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt 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.
//=========================================================================

#include "smtk/extension/qt/qtAttributeView.h"

#include "smtk/extension/qt/qtActiveObjects.h"
#include "smtk/extension/qt/qtAssociationWidget.h"
#include "smtk/extension/qt/qtAttribute.h"
#include "smtk/extension/qt/qtAttributeRefItem.h"
#include "smtk/extension/qt/qtCheckItemComboBox.h"
#include "smtk/extension/qt/qtItem.h"
#include "smtk/extension/qt/qtReferencesWidget.h"
#include "smtk/extension/qt/qtTableWidget.h"
#include "smtk/extension/qt/qtUIManager.h"
#include "smtk/extension/qt/qtVoidItem.h"

#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/Definition.h"
#include "smtk/attribute/GroupItem.h"
#include "smtk/attribute/GroupItemDefinition.h"
#include "smtk/attribute/ItemDefinition.h"
#include "smtk/attribute/RefItem.h"
#include "smtk/attribute/Resource.h"
#include "smtk/attribute/ValueItem.h"
#include "smtk/attribute/ValueItemDefinition.h"
#include "smtk/attribute/VoidItem.h"

#include "smtk/view/View.h"

#include <QBrush>
#include <QColorDialog>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QKeyEvent>
#include <QLabel>
#include <QListWidget>
#include <QMessageBox>
#include <QModelIndex>
#include <QModelIndexList>
#include <QPointer>
#include <QPushButton>
#include <QSplitter>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QStyleOptionViewItem>
#include <QTableWidgetItem>
#include <QVBoxLayout>
#include <QVariant>

#include <iostream>
#include <set>
using namespace smtk::attribute;
using namespace smtk::extension;

class qtAttributeViewInternals
{
public:
  const QList<smtk::attribute::DefinitionPtr> getCurrentDefs(const QString strCategory) const
  {

    if (this->AttDefMap.keys().contains(strCategory))
    {
      return this->AttDefMap[strCategory];
    }
    return this->AllDefs;
  }
  qtTableWidget* ListTable;
  qtTableWidget* ValuesTable;

  QPushButton* AddButton;
  QComboBox* DefsCombo;
  QLabel* DefLabel;
  QPushButton* DeleteButton;
  QPushButton* CopyButton;

  QFrame* FiltersFrame;
  QFrame* ButtonsFrame;
  QFrame* TopFrame;    // top
  QFrame* BottomFrame; // bottom

  QComboBox* ViewByCombo;
  QComboBox* PropDefsCombo;
  QLabel* PropDefLabel;

  QPointer<qtAssociationWidget> AssociationsWidget;
  QPointer<qtReferencesWidget> ReferencesWidget;

  // <category, AttDefinitions>
  QMap<QString, QList<smtk::attribute::DefinitionPtr> > AttDefMap;

  // All definitions list
  QList<smtk::attribute::DefinitionPtr> AllDefs;

  // Attribute widget
  QPointer<qtAttribute> CurrentAtt;
  QPointer<QFrame> AttFrame;

  // Model for filtering the attribute by combobox.
  QPointer<QStandardItemModel> checkableAttComboModel;
  QMap<std::string, Qt::CheckState> AttSelections;
  qtCheckItemComboBox* SelectAttCombo;

  // Model for filtering the attribute properties by combobox.
  QPointer<QStandardItemModel> checkablePropComboModel;
  qtCheckItemComboBox* SelectPropCombo;
  QMap<std::string, Qt::CheckState> AttProperties;
  std::vector<smtk::attribute::DefinitionPtr> m_attDefinitions;
  bool m_okToCreateModelEntities;
  smtk::model::BitFlags m_modelEntityMask;
  std::map<std::string, smtk::view::View::Component> m_attCompMap;
};

qtBaseView* qtAttributeView::createViewWidget(const ViewInfo& info)
{
  qtAttributeView* view = new qtAttributeView(info);
  view->buildUI();
  return view;
}

qtAttributeView::qtAttributeView(const ViewInfo& info)
  : qtBaseView(info)
{
  this->Internals = new qtAttributeViewInternals;
}

qtAttributeView::~qtAttributeView()
{
  delete this->Internals;
}

const QMap<QString, QList<smtk::attribute::DefinitionPtr> >& qtAttributeView::attDefinitionMap()
  const
{
  return this->Internals->AttDefMap;
}

void qtAttributeView::createWidget()
{
  if (!this->getObject())
  {
    return;
  }
  // Create a frame to contain all gui components for this object
  // Create a list box for the group entries
  // Create a table widget
  // Add link from the listbox selection to the table widget
  // A common add/delete/(copy/paste ??) widget

  // this->Internals->AttDefMap has to be initialized before getAllDefinitions()
  // since the getAllDefinitions() call needs the categories list in AttDefMap
  // Create a map for all catagories so we can cluster the definitions
  this->Internals->AttDefMap.clear();
  const ResourcePtr attResource = this->uiManager()->attResource();
  std::set<std::string>::const_iterator it;
  const std::set<std::string>& cats = attResource->categories();

  for (it = cats.begin(); it != cats.end(); it++)
  {
    QList<smtk::attribute::DefinitionPtr> attdeflist;
    this->Internals->AttDefMap[it->c_str()] = attdeflist;
  }

  // Initialize definition info
  this->getAllDefinitions();

  QSplitter* frame = new QSplitter(this->parentWidget());
  //this panel looks better in a over / under layout, rather than left / right
  frame->setOrientation(Qt::Vertical);

  QFrame* TopFrame = new QFrame(frame);
  QFrame* BottomFrame = new QFrame(frame);

  this->Internals->TopFrame = TopFrame;
  this->Internals->BottomFrame = BottomFrame;
  QSizePolicy sizeFixedPolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

  QVBoxLayout* TopLayout = new QVBoxLayout(TopFrame);
  TopLayout->setMargin(0);
  TopFrame->setSizePolicy(sizeFixedPolicy);
  QVBoxLayout* BottomLayout = new QVBoxLayout(BottomFrame);
  BottomLayout->setMargin(0);
  BottomFrame->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

  // create a filter-frame with ViewBy-combo
  this->Internals->FiltersFrame = new QFrame(frame);
  QGridLayout* filterLayout = new QGridLayout(this->Internals->FiltersFrame);
  filterLayout->setMargin(0);
  this->Internals->FiltersFrame->setSizePolicy(sizeFixedPolicy);

  this->Internals->ViewByCombo = new QComboBox(this->Internals->FiltersFrame);
  this->Internals->ViewByCombo->addItem("Attribute");
  this->Internals->ViewByCombo->addItem("Property");
  QLabel* labelViewBy = new QLabel("View By: ", this->Internals->FiltersFrame);
  filterLayout->addWidget(labelViewBy, 0, 0);
  filterLayout->addWidget(this->Internals->ViewByCombo, 0, 1);

  //If we have more than 1 def then create a combo box for selecting a def for property viewing,
  // else just create a label
  if (this->Internals->AllDefs.size() > 1)
  {
    this->Internals->PropDefsCombo = new QComboBox(TopFrame);
    this->Internals->PropDefsCombo->setVisible(false);
    this->Internals->PropDefsCombo->setToolTip(
      "Select definition to filter attributes and properties");
    filterLayout->addWidget(this->Internals->PropDefsCombo, 0, 2);
    QObject::connect(this->Internals->PropDefsCombo, SIGNAL(currentIndexChanged(int)), this,
      SLOT(onPropertyDefSelected()), Qt::QueuedConnection);
    this->Internals->PropDefLabel = NULL;
  }
  else
  {
    this->Internals->PropDefLabel = new QLabel(TopFrame);
    this->Internals->PropDefLabel->setText(
      this->Internals->AllDefs[0]->displayedTypeName().c_str());
    filterLayout->addWidget(this->Internals->PropDefLabel, 0, 2);
    this->Internals->PropDefLabel->setVisible(false);
    this->Internals->PropDefsCombo = NULL;
  }
  this->Internals->SelectPropCombo = new qtCheckItemComboBox(TopFrame, "Properties");
  this->Internals->SelectPropCombo->setVisible(false);
  this->Internals->SelectPropCombo->setToolTip("Select properties to compare");
  this->Internals->checkablePropComboModel = new QStandardItemModel();
  this->Internals->SelectPropCombo->setModel(this->Internals->checkablePropComboModel);
  this->Internals->SelectPropCombo->setItemDelegate(
    new qtCheckableComboItemDelegate(this->Internals->SelectPropCombo));
  filterLayout->addWidget(this->Internals->SelectPropCombo, 0, 3);

  this->Internals->SelectAttCombo = new qtCheckItemComboBox(TopFrame, "Attributes");
  this->Internals->SelectAttCombo->setVisible(false);
  this->Internals->SelectPropCombo->setToolTip("Select attributes to compare");
  this->Internals->checkableAttComboModel = new QStandardItemModel();
  this->Internals->SelectAttCombo->setModel(this->Internals->checkableAttComboModel);
  this->Internals->SelectAttCombo->setItemDelegate(
    new qtCheckableComboItemDelegate(this->Internals->SelectAttCombo));
  filterLayout->addWidget(this->Internals->SelectAttCombo, 0, 4);

  QSizePolicy tableSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  // create a list box for all the entries
  this->Internals->ListTable = new qtTableWidget(frame);
  this->Internals->ListTable->setSelectionMode(QAbstractItemView::SingleSelection);
  this->Internals->ListTable->setSelectionBehavior(QAbstractItemView::SelectRows);
  this->Internals->ListTable->setSizePolicy(tableSizePolicy);

  // Buttons frame
  this->Internals->ButtonsFrame = new QFrame(frame);
  QHBoxLayout* buttonLayout = new QHBoxLayout(this->Internals->ButtonsFrame);
  buttonLayout->setMargin(0);
  this->Internals->ButtonsFrame->setSizePolicy(sizeFixedPolicy);

  this->Internals->AddButton = new QPushButton("New", this->Internals->ButtonsFrame);
  this->Internals->AddButton->setSizePolicy(sizeFixedPolicy);
  this->Internals->DeleteButton = new QPushButton("Delete", this->Internals->ButtonsFrame);
  this->Internals->DeleteButton->setSizePolicy(sizeFixedPolicy);
  this->Internals->CopyButton = new QPushButton("Copy", this->Internals->ButtonsFrame);
  this->Internals->CopyButton->setSizePolicy(sizeFixedPolicy);

  //If we have more than 1 def then create a combo box for selecting a def,
  // else just create a label
  if (this->Internals->AllDefs.size() > 1)
  {
    this->Internals->DefsCombo = new QComboBox(this->Internals->ButtonsFrame);
    this->Internals->DefsCombo->setVisible(false);
    buttonLayout->addWidget(this->Internals->DefsCombo);
    this->Internals->DefLabel = NULL;
  }
  else
  {
    this->Internals->DefLabel = new QLabel(this->Internals->ButtonsFrame);
    this->Internals->DefLabel->setText(this->Internals->AllDefs[0]->displayedTypeName().c_str());
    this->Internals->DefLabel->setVisible(false);
    buttonLayout->addWidget(this->Internals->DefLabel);
    this->Internals->DefsCombo = NULL;
  }
  buttonLayout->addWidget(this->Internals->AddButton);
  buttonLayout->addWidget(this->Internals->CopyButton);
  buttonLayout->addWidget(this->Internals->DeleteButton);

  // Attribute table
  this->Internals->ValuesTable = new qtTableWidget(frame);
  this->Internals->ValuesTable->setSizePolicy(tableSizePolicy);

  TopLayout->addWidget(this->Internals->FiltersFrame);
  TopLayout->addWidget(this->Internals->ButtonsFrame);
  TopLayout->addWidget(this->Internals->ListTable);

  BottomLayout->addWidget(this->Internals->ValuesTable);
  this->Internals->ValuesTable->setVisible(0);

  // Attribte frame
  this->Internals->AttFrame = new QFrame(frame);
  new QVBoxLayout(this->Internals->AttFrame);
  BottomLayout->addWidget(this->Internals->AttFrame);
  //  this->Internals->AttFrame->setVisible(0);

  frame->addWidget(TopFrame);
  frame->addWidget(BottomFrame);

  // the association widget
  this->Internals->ReferencesWidget = new qtReferencesWidget(frame);
  this->Internals->AssociationsWidget = new qtAssociationWidget(frame, this);
  this->updateAssociationEnableState(smtk::attribute::AttributePtr());
  BottomLayout->addWidget(this->Internals->AssociationsWidget);
  BottomLayout->addWidget(this->Internals->ReferencesWidget);

  this->Internals->ListTable->horizontalHeader()->setSectionResizeMode(
    QHeaderView::ResizeToContents);
  this->Internals->ValuesTable->horizontalHeader()->setSectionResizeMode(
    QHeaderView::ResizeToContents);
  this->Internals->ValuesTable->verticalHeader()->setSectionResizeMode(
    QHeaderView::ResizeToContents);
  this->Internals->ListTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
  this->Internals->ValuesTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);

  // signals/slots
  QObject::connect(this->Internals->AssociationsWidget, SIGNAL(attAssociationChanged()), this,
    SIGNAL(attAssociationChanged()));

  QObject::connect(
    this->Internals->ViewByCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onViewBy(int)));

  QObject::connect(this->Internals->ListTable, SIGNAL(itemClicked(QTableWidgetItem*)), this,
    SLOT(onListBoxClicked(QTableWidgetItem*)));
  QObject::connect(this->Internals->ListTable, SIGNAL(itemSelectionChanged()), this,
    SLOT(onListBoxSelectionChanged()));
  QObject::connect(this->Internals->ListTable, SIGNAL(itemChanged(QTableWidgetItem*)), this,
    SLOT(onAttributeNameChanged(QTableWidgetItem*)));
  // we need this so that the attribute name will also be changed
  // when a recorded test is play back, which is using setText
  // on the underline QLineEdit of the cell.
  QObject::connect(this->Internals->ListTable, SIGNAL(cellChanged(int, int)), this,
    SLOT(onAttributeCellChanged(int, int)));

  QObject::connect(this->Internals->AddButton, SIGNAL(clicked()), this, SLOT(onCreateNew()));
  QObject::connect(this->Internals->CopyButton, SIGNAL(clicked()), this, SLOT(onCopySelected()));
  QObject::connect(
    this->Internals->DeleteButton, SIGNAL(clicked()), this, SLOT(onDeleteSelected()));

  QObject::connect(this->Internals->ValuesTable, SIGNAL(itemChanged(QTableWidgetItem*)), this,
    SLOT(onAttributeValueChanged(QTableWidgetItem*)));
  //QObject::connect(this->Internals->ValuesTable,
  //  SIGNAL(keyPressed (QKeyEvent *)),
  //  this, SLOT(onAttributeTableKeyPress(QKeyEvent * )));
  this->Internals->ValuesTable->setSelectionBehavior(QAbstractItemView::SelectRows);
  this->Internals->ValuesTable->setSelectionMode(QAbstractItemView::SingleSelection);

  this->Internals->ValuesTable->setVisible(0);

  this->Widget = frame;

  this->updateModelAssociation();
}

void qtAttributeView::updateModelAssociation()
{
  this->onShowCategory();
}

smtk::attribute::AttributePtr qtAttributeView::getAttributeFromItem(QTableWidgetItem* item)
{
  if (this->Internals->ViewByCombo->currentIndex() == VIEWBY_Attribute)
  {
    Attribute* rawPtr =
      item ? static_cast<Attribute*>(item->data(Qt::UserRole).value<void*>()) : NULL;
    return rawPtr ? rawPtr->shared_from_this() : smtk::attribute::AttributePtr();
  }
  return smtk::attribute::AttributePtr();
}

smtk::attribute::ItemPtr qtAttributeView::getAttributeItemFromItem(QTableWidgetItem* item)
{
  if (this->Internals->ViewByCombo->currentIndex() == VIEWBY_PROPERTY)
  {
    Item* rawPtr = item ? static_cast<Item*>(item->data(Qt::UserRole).value<void*>()) : NULL;
    return rawPtr ? rawPtr->shared_from_this() : smtk::attribute::ItemPtr();
  }
  return smtk::attribute::ItemPtr();
}

smtk::attribute::AttributePtr qtAttributeView::getSelectedAttribute()
{
  return this->getAttributeFromItem(this->getSelectedItem());
}

QTableWidgetItem* qtAttributeView::getSelectedItem()
{
  return this->Internals->ListTable->selectedItems().count() > 0
    ? this->Internals->ListTable->selectedItems().value(0)
    : NULL;
}

void qtAttributeView::updateAssociationEnableState(smtk::attribute::AttributePtr theAtt)
{
  bool rvisible = false, avisible = false;
  if (theAtt)
  {
    if (theAtt->definition()->associationMask())
    {
      avisible = true;
      this->Internals->AssociationsWidget->showEntityAssociation(theAtt);
    }
  }
  this->Internals->AssociationsWidget->setVisible(avisible);
  this->Internals->ReferencesWidget->setVisible(rvisible);
}

void qtAttributeView::onListBoxSelectionChanged()
{
  if (this->Internals->ViewByCombo->currentIndex() == VIEWBY_PROPERTY)
  {
    return;
  }

  this->Internals->ValuesTable->blockSignals(true);
  this->Internals->ValuesTable->clear();
  this->Internals->ValuesTable->setRowCount(0);
  this->Internals->ValuesTable->setColumnCount(0);
  QTableWidgetItem* current = this->getSelectedItem();

  if (current)
  {
    smtk::attribute::AttributePtr dataItem = this->getAttributeFromItem(current);
    this->updateAssociationEnableState(dataItem);
    if (dataItem)
    {
      this->updateTableWithAttribute(dataItem);
    }
  }
  else
  {
    delete this->Internals->CurrentAtt;
    this->Internals->CurrentAtt = NULL;
    this->updateAssociationEnableState(smtk::attribute::AttributePtr());
  }

  this->Internals->ValuesTable->blockSignals(false);
  this->Internals->ValuesTable->resizeRowsToContents();
  this->Internals->ValuesTable->resizeColumnsToContents();
  this->Internals->ValuesTable->update();
}

void qtAttributeView::onAttributeNameChanged(QTableWidgetItem* item)
{
  smtk::attribute::AttributePtr aAttribute = this->getAttributeFromItem(item);
  if (aAttribute && item->text().toStdString() != aAttribute->name())
  {
    ResourcePtr attResource = aAttribute->definition()->resource();
    attResource->rename(aAttribute, item->text().toStdString());
    //aAttribute->definition()->setLabel(item->text().toAscii().constData());
  }
}

void qtAttributeView::onAttributeCellChanged(int row, int col)
{
  if (col == 0 && this->Internals->ViewByCombo->currentIndex() == VIEWBY_Attribute)
  {
    QTableWidgetItem* item = this->Internals->ListTable->item(row, col);
    this->onAttributeNameChanged(item);
  }
}

void qtAttributeView::updateTableWithProperties()
{
  if (this->Internals->ViewByCombo->currentIndex() == VIEWBY_Attribute)
  {
    return;
  }

  this->Internals->ValuesTable->blockSignals(true);
  this->Internals->ValuesTable->clear();
  this->Internals->ValuesTable->setRowCount(0);
  this->Internals->ValuesTable->setColumnCount(0);
  //  this->Internals->ComparedPropMap.clear();
  this->updateAssociationEnableState(smtk::attribute::AttributePtr());

  Definition* rawPtr;
  if (this->Internals->AllDefs.size() == 1)
  {
    rawPtr = this->Internals->AllDefs[0].get();
  }
  else
  {
    rawPtr = static_cast<Definition*>(
      this->Internals->PropDefsCombo
        ->itemData(this->Internals->PropDefsCombo->currentIndex(), Qt::UserRole)
        .value<void*>());
  }
  if (!rawPtr)
  {
    this->Internals->ValuesTable->blockSignals(false);
    return;
  }

  std::vector<smtk::attribute::AttributePtr> result;
  ResourcePtr attResource = rawPtr->resource();
  attResource->findAttributes(rawPtr->shared_from_this(), result);
  if (result.size() == 0)
  {
    this->Internals->ValuesTable->blockSignals(false);
    return;
  }

  // create column headers
  QTableWidget* vtWidget = this->Internals->ValuesTable;
  vtWidget->setColumnCount(1);
  vtWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("Property"));

  std::vector<smtk::attribute::AttributePtr>::iterator it;
  int j = 1;
  for (it = result.begin(); it != result.end(); ++it)
  {
    if (!this->Internals->AttSelections.contains((*it)->name()) ||
      this->Internals->AttSelections[(*it)->name()] == Qt::Unchecked)
    {
      continue;
    }
    this->insertTableColumn(vtWidget, j, (*it)->name().c_str(), rawPtr->advanceLevel());
    j++;
  }

  for (int r = 1; r < this->Internals->SelectPropCombo->count(); r++)
  {
    QStandardItem* current = this->Internals->checkablePropComboModel->item(r);
    if (current && current->checkState() == Qt::Checked)
    {
      Item* irawPtr = static_cast<Item*>(current->data(Qt::UserRole).value<void*>());
      if (irawPtr)
      {
        smtk::attribute::ItemPtr attItem =
          irawPtr ? irawPtr->shared_from_this() : smtk::attribute::ItemPtr();
        smtk::attribute::AttributePtr att = attItem->attribute();
        this->addComparativeProperty(current, att->definition());
      }
    }
  }

  this->Internals->ValuesTable->blockSignals(false);
  this->Internals->ValuesTable->resizeColumnsToContents();
  this->Internals->ValuesTable->resizeRowsToContents();
}

void qtAttributeView::insertTableColumn(
  QTableWidget* vtWidget, int insertCol, const QString& title, int advancedlevel)
{
  vtWidget->insertColumn(insertCol);
  vtWidget->setHorizontalHeaderItem(insertCol, new QTableWidgetItem(title));

  if (advancedlevel)
  {
    vtWidget->horizontalHeaderItem(insertCol)->setFont(this->uiManager()->advancedFont());
  }
}

void qtAttributeView::onAttributeValueChanged(QTableWidgetItem* item)
{
  Item* linkedData = item ? static_cast<Item*>(item->data(Qt::UserRole).value<void*>()) : NULL;

  if (linkedData && linkedData->isOptional())
  {
    linkedData->setIsEnabled(item->checkState() == Qt::Checked);
    this->updateChildWidgetsEnableState(linkedData->shared_from_this(), item);
  }
}

void qtAttributeView::updateChildWidgetsEnableState(
  smtk::attribute::ItemPtr attItem, QTableWidgetItem* item)
{
  if (!item || !attItem || !attItem->isOptional())
  {
    return;
  }
  bool bEnabled = attItem->isEnabled();
  int startRow = item->row();

  if (attItem->type() == smtk::attribute::Item::GroupType)
  {
    smtk::attribute::GroupItemPtr grpItem = dynamic_pointer_cast<GroupItem>(attItem);
    if (grpItem)
    {
      int numItems = static_cast<int>(grpItem->numberOfItemsPerGroup());
      for (int j = 0; j < numItems; j++) // expecting one item for each column
      {
        this->updateItemWidgetsEnableState(grpItem->item(j), startRow, bEnabled);
      }
    }
  }
  else
  {
    this->updateItemWidgetsEnableState(attItem, startRow, bEnabled);
  }
}

void qtAttributeView::updateItemWidgetsEnableState(
  smtk::attribute::ItemPtr inData, int& startRow, bool enabled)
{
  QTableWidget* tableWidget = this->Internals->ValuesTable;
  if (inData->type() == smtk::attribute::Item::AttributeRefType)
  {
    QWidget* cellWidget = tableWidget->cellWidget(startRow, 1);
    if (cellWidget)
    {
      cellWidget->setEnabled(enabled);
    }
  }
  else if (inData->type() == smtk::attribute::Item::VoidType)
  {
    QWidget* cellWidget = tableWidget->cellWidget(startRow, 0);
    if (cellWidget)
    {
      cellWidget->setEnabled(enabled);
    }
  }
  else if (dynamic_pointer_cast<ValueItem>(inData))
  {
    smtk::attribute::ValueItemPtr linkedData = dynamic_pointer_cast<ValueItem>(inData);
    for (std::size_t row = 0; row < linkedData->numberOfValues(); row++, startRow++)
    {
      QWidget* cellWidget = tableWidget->cellWidget(startRow, 1);
      if (cellWidget)
      {
        cellWidget->setEnabled(enabled);
      }
    }
  }
}

void qtAttributeView::onCreateNew()
{
  if (!this->Internals->m_attDefinitions.size())
  {
    return;
  }
  attribute::DefinitionPtr newAttDef = this->Internals->AllDefs[0];

  QString strDef;
  if (this->Internals->AllDefs.size() == 1)
  {
    strDef = this->Internals->AllDefs[0]->type().c_str();
  }
  else
  {
    strDef = this->Internals->DefsCombo->currentText();
  }
  foreach (attribute::DefinitionPtr attDef,
    this->Internals->getCurrentDefs(this->uiManager()->currentCategory().c_str()))
  {
    std::string txtDef = attDef->displayedTypeName();
    if (strDef == QString::fromUtf8(txtDef.c_str()))
    {
      newAttDef = attDef;
      break;
    }
  }
  this->createNewAttribute(newAttDef);
}

void qtAttributeView::createNewAttribute(smtk::attribute::DefinitionPtr attDef)
{
  if (!attDef)
  {
    return;
  }

  ResourcePtr attResource = attDef->resource();

  smtk::attribute::AttributePtr newAtt = attResource->createAttribute(attDef->type());
  QTableWidgetItem* item = this->addAttributeListItem(newAtt);
  if (item)
  {
    this->Internals->ListTable->selectRow(item->row());
  }
  emit this->numOfAttributesChanged();
}

void qtAttributeView::onCopySelected()
{
  smtk::attribute::AttributePtr newObject, selObject = this->getSelectedAttribute();
  if (!selObject)
  {
    return;
  }

  ResourcePtr attResource = selObject->attributeResource();
  newObject = attResource->copyAttribute(selObject);
  if (newObject)
  {
    QTableWidgetItem* item = this->addAttributeListItem(newObject);
    if (item)
    {
      this->Internals->ListTable->selectRow(item->row());
    }
    emit this->numOfAttributesChanged();
  }
}

void qtAttributeView::onDeleteSelected()
{
  smtk::attribute::AttributePtr selObject = this->getSelectedAttribute();
  if (selObject)
  {
    std::string keyName = selObject->name();
    this->Internals->AttSelections.remove(keyName);

    attribute::DefinitionPtr attDef = selObject->definition();
    ResourcePtr attResource = attDef->resource();
    attResource->removeAttribute(selObject);

    QTableWidgetItem* selItem = this->getSelectedItem();
    this->Internals->ListTable->removeRow(selItem->row());
    emit this->numOfAttributesChanged();
  }
}

QTableWidgetItem* qtAttributeView::addAttributeListItem(smtk::attribute::AttributePtr childData)
{
  QTableWidgetItem* item =
    new QTableWidgetItem(QString::fromUtf8(childData->name().c_str()), smtk_USER_DATA_TYPE);
  Qt::ItemFlags nonEditableFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);

  QVariant vdata;
  vdata.setValue(static_cast<void*>(childData.get()));
  item->setData(Qt::UserRole, vdata);
  item->setFlags(nonEditableFlags | Qt::ItemIsEditable);

  int numRows = this->Internals->ListTable->rowCount();
  this->Internals->ListTable->setRowCount(++numRows);
  this->Internals->ListTable->setItem(numRows - 1, 0, item);

  // add the type column too.
  std::string txtDef = childData->definition()->displayedTypeName();

  QTableWidgetItem* defitem =
    new QTableWidgetItem(QString::fromUtf8(txtDef.c_str()), smtk_USER_DATA_TYPE);
  defitem->setFlags(nonEditableFlags);
  this->Internals->ListTable->setItem(numRows - 1, 1, defitem);

  // ToDo: Reactivate Color Option when we are ready to use it
  if (false)
  {
    QTableWidgetItem* colorItem = new QTableWidgetItem();
    this->Internals->ListTable->setItem(numRows - 1, 2, colorItem);
    const double* rgba = childData->color();
    QBrush bgBrush(QColor::fromRgbF(rgba[0], rgba[1], rgba[2], rgba[3]));
    colorItem->setBackground(bgBrush);
    colorItem->setFlags(Qt::ItemIsEnabled);
  }
  return item;
}

void qtAttributeView::onViewBy(int viewBy)
{
  if (!this->Internals->m_attDefinitions.size())
  {
    return;
  }

  QList<smtk::attribute::DefinitionPtr> currentDefs =
    this->Internals->getCurrentDefs(this->uiManager()->currentCategory().c_str());
  this->Internals->AddButton->setEnabled(currentDefs.count() > 0);

  bool viewAtt = (viewBy == VIEWBY_Attribute);
  this->Internals->ButtonsFrame->setVisible(viewAtt);
  this->Internals->ListTable->setVisible(viewAtt);
  this->Internals->ListTable->blockSignals(true);
  this->Internals->ListTable->clear();
  this->Internals->ListTable->setRowCount(0);

  // ToDo: Reactivate Color Option when we are ready to use it
  //int numCols = viewAtt ? 3 : 2;
  int numCols = 2;
  this->Internals->ListTable->setColumnCount(numCols);
  this->Internals->ListTable->setHorizontalHeaderItem(
    0, new QTableWidgetItem(viewAtt ? "Attribute" : "Property"));
  this->Internals->ListTable->setHorizontalHeaderItem(1, new QTableWidgetItem("Type"));
  if (numCols == 3)
  {
    this->Internals->ListTable->setHorizontalHeaderItem(2, new QTableWidgetItem("Color"));
  }
  if (this->Internals->AllDefs.size() == 1)
  {
    this->Internals->DefLabel->setVisible(true);
    this->Internals->PropDefLabel->setVisible(!viewAtt);
  }
  else
  {
    this->Internals->DefsCombo->clear();
    this->Internals->PropDefsCombo->clear();
    foreach (attribute::DefinitionPtr attDef, currentDefs)
    {
      if (!attDef->isAbstract())
      {
        std::string txtDef = attDef->displayedTypeName();
        this->Internals->DefsCombo->addItem(QString::fromUtf8(txtDef.c_str()));
        this->Internals->PropDefsCombo->addItem(QString::fromUtf8(txtDef.c_str()));
        QVariant vdata;
        vdata.setValue(static_cast<void*>(attDef.get()));
        int idx = this->Internals->PropDefsCombo->count() - 1;
        this->Internals->PropDefsCombo->setItemData(idx, vdata, Qt::UserRole);
      }
    }

    this->Internals->DefsCombo->setCurrentIndex(0);
    this->Internals->DefsCombo->setVisible(true);
    this->Internals->PropDefsCombo->setVisible(!viewAtt);
    this->Internals->PropDefsCombo->blockSignals(true);
    this->Internals->PropDefsCombo->setCurrentIndex(0);
    this->Internals->PropDefsCombo->blockSignals(false);
  }
  this->initSelectionFilters();
  if (viewAtt)
  {
    foreach (attribute::DefinitionPtr attDef, currentDefs)
    {
      this->onViewByWithDefinition(viewBy, attDef);
    }
  }
  this->Internals->ListTable->blockSignals(false);
  this->Internals->ListTable->resizeColumnsToContents();

  QSplitter* frame = qobject_cast<QSplitter*>(this->Widget);
  if (viewAtt)
  {
    if (this->Internals->ListTable->rowCount() && !this->getSelectedItem())
    {
      // so switch tabs would not reset selection
      if (!this->Internals->AssociationsWidget->hasSelectedItem())
      {
        this->Internals->ListTable->selectRow(0);
      }
    }
    else
    {
      this->onListBoxSelectionChanged();
    }
  }
  else
  {
    this->updateTableWithProperties();
    QList<int> sizes;
    sizes.push_back(this->Internals->ViewByCombo->height());
    sizes.push_back(this->Internals->ValuesTable->height());
    frame->setSizes(sizes);
  }
  frame->handle(1)->setEnabled(viewAtt);
}

void qtAttributeView::onViewByWithDefinition(int viewBy, smtk::attribute::DefinitionPtr attDef)
{
  if (viewBy == VIEWBY_PROPERTY)
  {
    return;
  }
  std::vector<smtk::attribute::AttributePtr> result;
  ResourcePtr attResource = attDef->resource();
  attResource->findAttributes(attDef, result);
  if (result.size() && viewBy == VIEWBY_Attribute)
  {
    std::vector<smtk::attribute::AttributePtr>::iterator it;
    for (it = result.begin(); it != result.end(); ++it)
    {
      QTableWidgetItem* item = this->addAttributeListItem(*it);
      if ((*it)->definition()->advanceLevel())
      {
        item->setFont(this->uiManager()->advancedFont());
      }
    }
  }
}

void qtAttributeView::onShowCategory()
{
  int viewBy = this->Internals->ViewByCombo->currentIndex();
  this->onViewBy(viewBy);
}

void qtAttributeView::updateTableWithAttribute(smtk::attribute::AttributePtr att)
{
  this->Internals->ValuesTable->setVisible(0);
  this->Internals->AttFrame->setVisible(1);

  if (this->Internals->CurrentAtt && this->Internals->CurrentAtt->widget())
  {
    delete this->Internals->CurrentAtt;
  }

  int currentLen = this->fixedLabelWidth();
  int tmpLen = this->uiManager()->getWidthOfAttributeMaxLabel(
    att->definition(), this->uiManager()->advancedFont());
  this->setFixedLabelWidth(tmpLen);
  auto it = this->Internals->m_attCompMap.find(att->definition()->type());
  if (it != this->Internals->m_attCompMap.end())
  {
    this->Internals->CurrentAtt = new qtAttribute(att, it->second, this->Internals->AttFrame, this);
  }
  else
  {
    smtk::view::View::Component comp;
    this->Internals->CurrentAtt = new qtAttribute(att, comp, this->Internals->AttFrame, this);
  }
  // By default use the basic layout with no model associations since this class
  // takes care of it
  this->Internals->CurrentAtt->createBasicLayout(false);
  this->setFixedLabelWidth(currentLen);
  if (this->Internals->CurrentAtt && this->Internals->CurrentAtt->widget())
  {
    this->Internals->AttFrame->layout()->addWidget(this->Internals->CurrentAtt->widget());
    if (this->advanceLevelVisible())
    {
      this->Internals->CurrentAtt->showAdvanceLevelOverlay(true);
    }
  }
}

void qtAttributeView::initSelectionFilters()
{
  bool viewAtt = this->Internals->ViewByCombo->currentIndex() == VIEWBY_Attribute;
  this->Internals->SelectAttCombo->setVisible(!viewAtt);
  this->Internals->SelectPropCombo->setVisible(!viewAtt);
  if (viewAtt)
  {
    return;
  }
  this->Internals->AttFrame->setVisible(0);
  this->Internals->ValuesTable->setVisible(1);
  DefinitionPtr dp;
  if (this->Internals->AllDefs.size() > 1)
  {
    Definition* rawPtr = static_cast<Definition*>(
      this->Internals->PropDefsCombo
        ->itemData(this->Internals->PropDefsCombo->currentIndex(), Qt::UserRole)
        .value<void*>());
    if (!rawPtr)
    {
      return;
    }
    dp = rawPtr->shared_from_this();
  }
  else
  {
    dp = this->Internals->AllDefs[0];
  }
  this->initSelectPropCombo(dp);
  this->initSelectAttCombo(dp);
  this->updateTableWithProperties();
}

void qtAttributeView::initSelectPropCombo(smtk::attribute::DefinitionPtr attDef)
{
  this->Internals->SelectPropCombo->blockSignals(true);
  this->Internals->SelectPropCombo->clear();
  this->Internals->SelectPropCombo->init();
  this->Internals->checkablePropComboModel->disconnect();
  if (!attDef)
  {
    this->Internals->SelectPropCombo->blockSignals(false);
    return;
  }
  std::vector<smtk::attribute::AttributePtr> result;
  ResourcePtr attResource = attDef->resource();
  attResource->findAttributes(attDef, result);
  if (result.size() == 0)
  {
    this->Internals->SelectPropCombo->blockSignals(false);
    return;
  }
  smtk::attribute::AttributePtr childData = result[0];
  // Now lets process its items
  std::size_t i, n = childData->numberOfItems();
  int row = 1;
  for (i = 0; i < n; i++)
  {
    smtk::attribute::ItemPtr attItem = childData->item(static_cast<int>(i));
    if (this->uiManager()->passItemCategoryCheck(attItem->definition()) &&
      this->uiManager()->passAdvancedCheck(attItem->advanceLevel()))
    {
      // No User data, not editable
      std::string strItemLabel = attItem->label().empty() ? attItem->name() : attItem->label();
      std::string keyName = childData->definition()->type() + strItemLabel;
      QStandardItem* item = new QStandardItem;
      item->setText(strItemLabel.c_str());
      if (!this->Internals->AttProperties.contains(keyName))
      {
        this->Internals->AttProperties[keyName] = Qt::Unchecked;
      }

      item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
      //item->setData(this->Internals->AttSelections[keyName], Qt::CheckStateRole);
      item->setData(Qt::Unchecked, Qt::CheckStateRole);
      item->setCheckable(true);
      item->setCheckState(this->Internals->AttProperties[keyName]);
      QVariant vdata;
      vdata.setValue(static_cast<void*>(attItem.get()));
      item->setData(vdata, Qt::UserRole);
      this->Internals->checkablePropComboModel->insertRow(row++, item);
      if (attItem->advanceLevel())
      {
        item->setFont(this->uiManager()->advancedFont());
      }
    }
  }

  connect(this->Internals->checkablePropComboModel,
    SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this,
    SLOT(propertyFilterChanged(const QModelIndex&, const QModelIndex&)));

  this->Internals->SelectPropCombo->blockSignals(false);
  this->Internals->SelectPropCombo->updateText();
  this->Internals->SelectPropCombo->hidePopup();
}

void qtAttributeView::initSelectAttCombo(smtk::attribute::DefinitionPtr attDef)
{
  this->Internals->SelectAttCombo->blockSignals(true);
  this->Internals->SelectAttCombo->clear();
  this->Internals->SelectAttCombo->init();
  this->Internals->checkableAttComboModel->disconnect();

  if (!attDef)
  {
    this->Internals->SelectAttCombo->blockSignals(false);
    return;
  }

  std::vector<smtk::attribute::AttributePtr> result;
  ResourcePtr attResource = attDef->resource();
  attResource->findAttributes(attDef, result);
  std::vector<smtk::attribute::AttributePtr>::iterator it;
  int row = 1;
  for (it = result.begin(); it != result.end(); ++it, ++row)
  {
    QStandardItem* item = new QStandardItem;
    item->setText((*it)->name().c_str());
    std::string keyName = (*it)->name();
    if (!this->Internals->AttSelections.contains(keyName))
    {
      this->Internals->AttSelections[keyName] = Qt::Unchecked;
    }

    item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
    //item->setData(this->Internals->AttSelections[keyName], Qt::CheckStateRole);
    item->setData(Qt::Unchecked, Qt::CheckStateRole);
    item->setCheckable(true);
    item->setCheckState(this->Internals->AttSelections[keyName]);
    QVariant vdata;
    vdata.setValue(static_cast<void*>((*it).get()));
    item->setData(vdata, Qt::UserRole);
    this->Internals->checkableAttComboModel->insertRow(row, item);
    if ((*it)->definition()->advanceLevel())
    {
      item->setFont(this->uiManager()->advancedFont());
    }
  }
  connect(this->Internals->checkableAttComboModel,
    SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this,
    SLOT(attributeFilterChanged(const QModelIndex&, const QModelIndex&)));

  //connect(this->Internals->checkableAttComboModel, SIGNAL(itemChanged ( QStandardItem*)),
  //  this, SLOT(attributeFilterChanged(QStandardItem*)));
  this->Internals->SelectAttCombo->blockSignals(false);
  this->Internals->SelectAttCombo->updateText();
  this->Internals->SelectAttCombo->hidePopup();
}

void qtAttributeView::propertyFilterChanged(
  const QModelIndex& topLeft, const QModelIndex& /* bottomRight */)
{
  if (this->Internals->ViewByCombo->currentIndex() == VIEWBY_Attribute)
  {
    return;
  }

  QStandardItem* item = this->Internals->checkablePropComboModel->item(topLeft.row());
  if (!item)
  {
    return;
  }
  smtk::attribute::Item* rawPtr =
    static_cast<smtk::attribute::Item*>(item->data(Qt::UserRole).value<void*>());

  if (rawPtr)
  {
    this->Internals->ValuesTable->blockSignals(true);
    smtk::attribute::ItemPtr attItem = rawPtr->shared_from_this();
    smtk::attribute::AttributePtr att = attItem->attribute();
    std::string keyName = att->definition()->type() + item->text().toStdString();
    this->Internals->AttProperties[keyName] = item->checkState();
    if (item->checkState() == Qt::Checked)
    {
      this->addComparativeProperty(item, att->definition());
    }
    else
    {
      this->removeComparativeProperty(item->text());
    }
    this->Internals->SelectPropCombo->updateText();
    this->Internals->ValuesTable->blockSignals(false);
    this->Internals->ValuesTable->resizeColumnsToContents();
    this->Internals->ValuesTable->resizeRowsToContents();
  }
}

void qtAttributeView::attributeFilterChanged(
  const QModelIndex& topLeft, const QModelIndex& /* bottomRight */)
{
  QStandardItem* item = this->Internals->checkableAttComboModel->item(topLeft.row());
  if (!item)
  {
    return;
  }
  Attribute* rawPtr = static_cast<Attribute*>(item->data(Qt::UserRole).value<void*>());
  if (rawPtr)
  {
    this->Internals->ValuesTable->blockSignals(true);
    this->Internals->AttSelections[rawPtr->name()] = item->checkState();
    if (item->checkState() == Qt::Checked)
    {
      this->addComparativeAttribute(rawPtr->shared_from_this());
    }
    else
    {
      this->removeComparativeAttribute(rawPtr->shared_from_this());
    }
    this->Internals->SelectAttCombo->updateText();
    this->Internals->ValuesTable->blockSignals(false);
    this->Internals->ValuesTable->resizeColumnsToContents();
    this->Internals->ValuesTable->resizeRowsToContents();
  }
}

void qtAttributeView::addComparativeAttribute(smtk::attribute::AttributePtr att)
{
  if (!att)
  {
    return;
  }

  QTableWidget* vtWidget = this->Internals->ValuesTable;
  this->insertTableColumn(
    vtWidget, vtWidget->columnCount(), att->name().c_str(), att->definition()->advanceLevel());

  int col = vtWidget->columnCount() - 1;
  std::size_t i, n = att->numberOfItems();
  auto ui_manager = this->uiManager();
  for (int row = 0; row < vtWidget->rowCount(); ++row)
  {
    for (i = 0; i < n; i++) // for each property
    {
      smtk::attribute::ItemPtr attItem = att->item(static_cast<int>(i));
      std::string strItemLabel = attItem->label().empty() ? attItem->name() : attItem->label();
      if (vtWidget->item(row, 0)->text() == strItemLabel.c_str())
      {
        smtk::view::View::Component comp;
        comp.setAttribute("Orientation", "Vertical");
        AttributeItemInfo info(attItem, comp, NULL, this);
        auto qItem = ui_manager->createItem(info);
        qItem->setLabelVisible(false);
        qtAttributeRefItem* arItem = qobject_cast<qtAttributeRefItem*>(qItem);
        if (arItem)
        {
          arItem->setAttributeWidgetVisible(false);
        }
        vtWidget->setCellWidget(row, col, qItem->widget());
        vtWidget->setItem(row, col, new QTableWidgetItem());
        break;
      }
    }
  }
}

void qtAttributeView::removeComparativeAttribute(smtk::attribute::AttributePtr att)
{
  if (!att)
  {
    return;
  }

  QTableWidget* vtWidget = this->Internals->ValuesTable;
  for (int c = 1; c < vtWidget->columnCount(); c++)
  {
    if (vtWidget->horizontalHeaderItem(c)->text().toStdString() == att->name())
    {
      vtWidget->removeColumn(c);
      break;
    }
  }
  //  vtWidget->resizeRowsToContents();
}

void qtAttributeView::onPropertyDefSelected()
{
  if (this->Internals->ViewByCombo->currentIndex() == VIEWBY_Attribute)
  {
    return;
  }

  Definition* rawPtr;
  if (this->Internals->AllDefs.size() == 1)
  {
    rawPtr = this->Internals->AllDefs[0].get();
  }
  else
  {
    rawPtr = static_cast<Definition*>(
      this->Internals->PropDefsCombo
        ->itemData(this->Internals->PropDefsCombo->currentIndex(), Qt::UserRole)
        .value<void*>());
  }
  if (!rawPtr)
  {
    return;
  }

  this->initSelectionFilters();
  this->updateTableWithProperties();
}

void qtAttributeView::removeComparativeProperty(const QString& propertyName)
{
  if (!this->Internals->m_attDefinitions.size())
  {
    return;
  }

  QTableWidget* vtWidget = this->Internals->ValuesTable;
  for (int c = 0; c < vtWidget->rowCount(); c++)
  {
    if (vtWidget->item(c, 0)->text() == propertyName)
    {
      vtWidget->removeRow(c);
      break;
    }
  }
  //  vtWidget->resizeRowsToContents();
}

void qtAttributeView::addComparativeProperty(
  QStandardItem* current, smtk::attribute::DefinitionPtr attDef)
{
  if (!this->Internals->m_attDefinitions.size())
  {
    return;
  }

  Definition* rawPtr;
  if (this->Internals->AllDefs.size() == 1)
  {
    rawPtr = this->Internals->AllDefs[0].get();
  }
  else
  {
    rawPtr = static_cast<Definition*>(
      this->Internals->PropDefsCombo
        ->itemData(this->Internals->PropDefsCombo->currentIndex(), Qt::UserRole)
        .value<void*>());
  }

  if (rawPtr->shared_from_this() != attDef)
  {
    return;
  }

  QTableWidget* vtWidget = this->Internals->ValuesTable;

  std::vector<smtk::attribute::AttributePtr> result;
  ResourcePtr attResource = attDef->resource();
  attResource->findAttributes(attDef, result);

  int numRows = this->Internals->ValuesTable->rowCount();
  int insertRow = numRows;
  vtWidget->insertRow(insertRow);
  vtWidget->setItem(insertRow, 0, new QTableWidgetItem(current->text()));
  vtWidget->item(insertRow, 0)->setFont(current->font());

  std::vector<smtk::attribute::AttributePtr>::iterator it;
  int col = 1;
  for (it = result.begin(); it != result.end(); ++it)
  {
    if (!this->Internals->AttSelections.contains((*it)->name()) ||
      this->Internals->AttSelections[(*it)->name()] == Qt::Unchecked)
    {
      continue;
    }
    std::size_t i, n = (*it)->numberOfItems();
    auto ui_manager = this->uiManager();
    for (i = 0; i < n; i++) // for each property
    {
      smtk::attribute::ItemPtr attItem = (*it)->item(static_cast<int>(i));
      std::string strItemLabel = attItem->label().empty() ? attItem->name() : attItem->label();
      if (current->text() == strItemLabel.c_str())
      {
        smtk::view::View::Component comp;
        comp.setAttribute("Orientation", "Vertical");
        AttributeItemInfo info(attItem, comp, NULL, this);
        auto qItem = ui_manager->createItem(info);
        qItem->setLabelVisible(false);
        qtAttributeRefItem* arItem = qobject_cast<qtAttributeRefItem*>(qItem);
        if (arItem)
        {
          arItem->setAttributeWidgetVisible(false);
        }
        vtWidget->setCellWidget(insertRow, col, qItem->widget());
        vtWidget->setItem(insertRow, col, new QTableWidgetItem());
        break;
      }
    }
    col++;
  }
}

int qtAttributeView::currentViewBy()
{
  return this->Internals->ViewByCombo->currentIndex();
}

void qtAttributeView::getAllDefinitions()
{
  smtk::view::ViewPtr view = this->getObject();
  if (!view)
  {
    return;
  }

  smtk::attribute::ResourcePtr resource = this->uiManager()->attResource();

  std::string attName, defName, val;
  smtk::attribute::AttributePtr att;
  smtk::attribute::DefinitionPtr attDef;
  bool flag;

  // The view should have a single internal component called InstancedAttributes
  if ((view->details().numberOfChildren() != 1) ||
    (view->details().child(0).name() != "AttributeTypes"))
  {
    // Should present error message
    return;
  }

  if (view->details().attributeAsBool("CreateEntities", flag))
  {
    this->Internals->m_okToCreateModelEntities = flag;
  }
  else
  {
    this->Internals->m_okToCreateModelEntities = false;
  }

  if (view->details().attribute("ModelEntityFilter", val))
  {
    smtk::model::BitFlags flags = smtk::model::Entity::specifierStringToFlag(val);
    this->Internals->m_modelEntityMask = flags;
  }
  else
  {
    this->Internals->m_modelEntityMask = 0;
  }

  std::vector<smtk::attribute::AttributePtr> atts;
  smtk::view::View::Component& attsComp = view->details().child(0);
  std::size_t i, n = attsComp.numberOfChildren();
  for (i = 0; i < n; i++)
  {
    if (attsComp.child(i).name() != "Att")
    {
      continue;
    }
    if (!attsComp.child(i).attribute("Type", defName))
    {
      continue;
    }

    attDef = resource->findDefinition(defName);
    if (attDef == nullptr)
    {
      continue;
    }

    this->Internals->m_attCompMap[defName] = attsComp.child(i);
    this->qtBaseView::getDefinitions(attDef, this->Internals->AllDefs);
    this->Internals->m_attDefinitions.push_back(attDef);
  }

  // sort the list
  std::sort(std::begin(this->Internals->AllDefs), std::end(this->Internals->AllDefs),
    [](smtk::attribute::DefinitionPtr a, smtk::attribute::DefinitionPtr b) {
      return a->displayedTypeName() < b->displayedTypeName();
    });

#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#endif
  foreach (smtk::attribute::DefinitionPtr adef, this->Internals->AllDefs)
  {
    foreach (QString category, this->Internals->AttDefMap.keys())
    {
      if (adef->isMemberOf(category.toStdString()) &&
        !this->Internals->AttDefMap[category].contains(adef))
      {
        this->Internals->AttDefMap[category].push_back(adef);
      }
    }
  }
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
}

void qtAttributeView::onListBoxClicked(QTableWidgetItem* item)
{
  if (this->Internals->ViewByCombo->currentIndex() == VIEWBY_Attribute)
  {
    bool isColor = item->column() == 2;
    if (isColor)
    {
      QTableWidgetItem* selItem = this->Internals->ListTable->item(item->row(), 0);
      smtk::attribute::AttributePtr selAtt = this->getAttributeFromItem(selItem);
      QBrush bgBrush = item->background();
      QColor color = QColorDialog::getColor(
        bgBrush.color(), this->Widget, "Choose Attribute Color", QColorDialog::DontUseNativeDialog);
      if (color.isValid() && color != bgBrush.color() && selAtt)
      {
        bgBrush.setColor(color);
        item->setBackground(bgBrush);
        selAtt->setColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
        emit this->attColorChanged();
      }
      if (!selItem->isSelected())
      {
        this->Internals->ListTable->setCurrentItem(selItem);
        selItem->setSelected(true);
      }
    }
  }
}

void qtAttributeView::childrenResized()
{
  if (this->Internals->ValuesTable->isVisible())
  {
    this->Internals->ValuesTable->resizeRowsToContents();
    this->Internals->ValuesTable->resizeColumnsToContents();
    this->Internals->ValuesTable->update();
    this->Widget->update();
  }
}

void qtAttributeView::showAdvanceLevelOverlay(bool show)
{
  if (this->Internals->ViewByCombo->currentIndex() == VIEWBY_Attribute &&
    this->Internals->CurrentAtt)
  {
    this->Internals->CurrentAtt->showAdvanceLevelOverlay(show);
  }
  this->qtBaseView::showAdvanceLevelOverlay(show);
}

bool qtAttributeView::isEmpty() const
{
  QList<smtk::attribute::DefinitionPtr> currentDefs =
    this->Internals->getCurrentDefs(this->uiManager()->currentCategory().c_str());
  return currentDefs.isEmpty();
}
