//=========================================================================
//  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 "pqModelBuilderViewContextMenuBehavior.h"

#include "pqActiveObjects.h"
#include "pqApplicationCore.h"
#include "pqEditColorMapReaction.h"
#include "pqMultiBlockInspectorPanel.h"
#include "pqPVApplicationCore.h"
#include "pqDataRepresentation.h"
#include "pqPipelineRepresentation.h"
#include "pqRenderView.h"
#include "pqScalarsToColors.h"
#include "pqSelectionManager.h"
#include "pqServerManagerModel.h"
#include "pqSetName.h"
#include "pqSMAdaptor.h"
#include "pqUndoStack.h"
#include "pqRepresentationHelperFunctions.h"

#include "vtkDataObject.h"
#include "vtkNew.h"
#include "vtkPVCompositeDataInformation.h"
#include "vtkPVDataInformation.h"
#include "vtkPVGeneralSettings.h"
#include "vtkPVSMTKModelInformation.h"
#include "vtkSMArrayListDomain.h"
#include "vtkSMIntVectorProperty.h"
#include "vtkSMModelManagerProxy.h"
#include "vtkSMProperty.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMPVRepresentationProxy.h"
#include "vtkSMSourceProxy.h"
#include "vtkSMTransferFunctionManager.h"
#include "vtkSMTransferFunctionProxy.h"
#include "vtkSMViewProxy.h"

#include <QAction>
#include <QApplication>
#include <QColorDialog>
#include <QMenu>
#include <QMouseEvent>
#include <QPair>
#include <QWidget>
#include "pqCMBModelManager.h"
#include "pqSMTKModelPanel.h"
#include "smtk/model/Face.h"
#include "smtk/model/Group.h"
#include "smtk/model/Manager.h"
#include "smtk/model/Model.h"
#include "smtk/model/Volume.h"
#include "smtk/extension/vtk/vtkModelMultiBlockSource.h"

namespace
{
  // converts array association/name pair to QVariant.
  QVariant convert(const QPair<int, QString>& array)
    {
    if (!array.second.isEmpty())
      {
      QStringList val;
      val << QString::number(array.first)
          << array.second;
      return val;
      }
    return QVariant();
    }

  // converts QVariant to array association/name pair.
  QPair <int, QString> convert(const QVariant& val)
    {
    QPair<int, QString> result;
    if (val.canConvert<QStringList>())
      {
      QStringList list = val.toStringList();
      Q_ASSERT(list.size() == 2);
      result.first = list[0].toInt();
      result.second = list[1];
      }
    return result;
    }
bool _internal_getBlockIndex(const smtk::model::EntityRef& eref,
                             unsigned int& flatIndex)
  {
  const smtk::model::IntegerList& prop(eref.integerProperty("block_index"));
  if(!prop.empty() && prop[0] >=0)
    {
    flatIndex = prop[0]+1;
    return true;
    }
  return false;
  }

/// Fetch children for volum and group entities.
void _internal_AccumulateChildGeometricEntities(
  QSet<unsigned int>& blockIds,
  const smtk::model::EntityRef& toplevel)
  {
  unsigned int bidx = -1;
  if (toplevel.isVolume())
    { // Add free cells
    smtk::model::Faces faces = toplevel.as<smtk::model::Volume>().faces();
    // Find all boundaries of all free cells
    smtk::model::Faces::iterator fcit;
    for (fcit = faces.begin(); fcit != faces.end(); ++fcit)
      {
      if(fcit->hasIntegerProperty("block_index") &&
         _internal_getBlockIndex(*fcit, bidx))
        blockIds.insert(bidx);

      // for its edges and vertices
      smtk::model::EntityRefs bdys = fcit->lowerDimensionalBoundaries(-1); // Get *all* boundaries.
      smtk::model::EntityRefs::const_iterator evit;
      for (evit = bdys.begin(); evit != bdys.end(); ++evit)
        if(evit->hasIntegerProperty("block_index") &&
           _internal_getBlockIndex(*evit, bidx))
          blockIds.insert(bidx);
      }
    }
  else if (toplevel.isGroup())
    { // Add group members, but not their boundaries
    smtk::model::EntityRefs members =
      toplevel.as<smtk::model::Group>().members<smtk::model::EntityRefs>();
    for (smtk::model::EntityRefs::const_iterator it = members.begin();
       it != members.end(); ++it)
      // Do this recursively since a group may contain other groups
      _internal_AccumulateChildGeometricEntities(blockIds, *it);
    }
  else if(toplevel.hasIntegerProperty("block_index") &&
         _internal_getBlockIndex(toplevel, bidx))
    blockIds.insert(bidx);
  }

// only use valid color, the rest will be colored
// randomly with CTF
bool _internal_getValidEntityColor(QColor& color,
  const smtk::model::EntityRef& entref)
  {
  smtk::model::FloatList rgba = entref.color();
  if ((rgba.size() == 3 || rgba.size() ==4) &&
     !(rgba[0]+rgba[1]+rgba[2] == 0))
    {
    color.setRgbF(rgba[0], rgba[1], rgba[2]);
    return true;
    }
  return false;
  }
}

//-----------------------------------------------------------------------------
pqModelBuilderViewContextMenuBehavior::pqModelBuilderViewContextMenuBehavior(QObject* parentObject)
  : Superclass(parentObject)
{
  QObject::connect(
    pqApplicationCore::instance()->getServerManagerModel(),
    SIGNAL(viewAdded(pqView*)),
    this, SLOT(onViewAdded(pqView*)));
  this->Menu = new QMenu();
  this->Menu << pqSetName("PipelineContextMenu");
  this->m_DataInspector = new pqMultiBlockInspectorPanel(NULL);
  this->m_DataInspector->setVisible(false);
}

//-----------------------------------------------------------------------------
pqModelBuilderViewContextMenuBehavior::~pqModelBuilderViewContextMenuBehavior()
{
  delete this->Menu;
  delete this->m_DataInspector;
  if(this->m_colormapReaction)
    {
    delete this->m_colormapReaction;
    }
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::setModelPanel(pqSMTKModelPanel* panel)
{
  this->m_ModelPanel = panel;
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::syncBlockVisibility(
    pqDataRepresentation* rep,
    const QList<unsigned int>& visBlocks, bool visible, vtkIdType numBlocks)
{
  pqMultiBlockInspectorPanel *panel = this->m_DataInspector;
  if (panel && rep)
    {
    pqOutputPort* prevOutport = pqActiveObjects::instance().activePort();
    pqDataRepresentation* prevRep = pqActiveObjects::instance().activeRepresentation();

    pqOutputPort* outport = rep->getOutputPortFromInput();
    panel->onPortChanged(outport);
    panel->onRepresentationChanged(rep);

    if(visible && visBlocks.count() && rep)
      {
      // if one block is visible, the rep has to be visible
      rep->setVisible(visible);
      }

    panel->setBlockVisibility(visBlocks, visible);

   if(!visible)
      {
      if(outport)
        {
        outport->setSelectionInput(0, 0);
        }
       // if all blocks are off, the rep should be invisible 
       if(rep && outport)
        {
        vtkSMProxy *proxy = rep->getProxy();
        vtkSMProperty *blockVisibilityProperty = proxy->GetProperty("BlockVisibility");
        proxy->UpdatePropertyInformation(blockVisibilityProperty);
        vtkSMIntVectorProperty *ivp = vtkSMIntVectorProperty::SafeDownCast(blockVisibilityProperty);

        if(ivp)
          {
/*
          vtkPVDataInformation *info = outport->getDataInformation();
          if(!info)
            return;
          vtkPVCompositeDataInformation *compositeInfo =
            info->GetCompositeDataInformation();
          if(!compositeInfo || !compositeInfo->GetDataIsComposite())
            return;
*/
          vtkIdType nbElems = static_cast<vtkIdType>(ivp->GetNumberOfElements());
          if(nbElems/2 != numBlocks)
            return;

          bool repVisible = false;
          for(vtkIdType i = 0; i + 1 < nbElems; i += 2)
            {
            if(ivp->GetElement(i+1))
              {
              repVisible = true;
              break;
              }
            }
          rep->setVisible(repVisible);
          }
        }
      }

    panel->onRepresentationChanged(prevRep);
    panel->onPortChanged(prevOutport);

    }
}

//----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::colorByEntity(
  const QString & colorMode)
{
  if(!this->m_ModelPanel || !this->m_ModelPanel->modelManager())
    return;

  // active rep
  pqDataRepresentation* activeRep = pqActiveObjects::instance().activeRepresentation();
  pqMultiBlockInspectorPanel *datapanel = this->m_DataInspector;
  if (!datapanel || !activeRep)
    return;
  cmbSMTKModelInfo* minfo = this->m_ModelPanel->modelManager()->modelInfo(activeRep);
  if(!minfo)
    return;
  if(minfo->ColorMode == colorMode)
    return;
  QStringList list;
  this->m_ModelPanel->modelManager()->supportedColorByModes(list);
  if(!list.contains(colorMode))
    return;

  smtk::common::UUID modelId = minfo->Info->GetModelUUID();
  smtk::model::Model activeModel(
    this->m_ModelPanel->modelManager()->managerProxy()->modelManager(), modelId);
  if(!activeModel.isValid())
    return;

  // turn off the current scalar bar before switch to the new array
  vtkSMProxy* ctfProxy = activeRep->getLookupTableProxy();
  vtkSMProxy* sb = vtkSMTransferFunctionProxy::FindScalarBarRepresentation(
    ctfProxy, pqActiveObjects::instance().activeView()->getProxy());
  if(sb)
    {
    vtkSMPropertyHelper(sb, "Visibility").Set(0);
    sb->UpdateVTKObjects();
    }

  // clear all colors
  QList<unsigned int> indices;
  std::map<smtk::common::UUID, unsigned int>::const_iterator uit =
    minfo->Info->GetUUID2BlockIdMap().begin();
  for(; uit != minfo->Info->GetUUID2BlockIdMap().end(); ++uit)
    {
    indices.append(uit->second + 1);
    }
  datapanel->clearBlockColor(indices);

  QColor color;
  QMap<smtk::model::EntityRef, QColor > colorEntities;
  if(colorMode ==
    vtkModelMultiBlockSource::GetVolumeTagName())
    {
    // if colorby-volume, get volumes' color,
    smtk::model::CellEntities modVols = activeModel.cells();
    for(smtk::model::CellEntities::iterator it = modVols.begin();
       it != modVols.end(); ++it)
      {
      if(it->isVolume() && it->hasColor()
        && _internal_getValidEntityColor(color, *it))
        {
        colorEntities[*it] = color;
        }
      }
    }
 else if( colorMode ==
      vtkModelMultiBlockSource::GetGroupTagName())
   {
    // if colorby-group, get groups' color,
    smtk::model::Groups modGroups = activeModel.groups();
    for(smtk::model::Groups::iterator it = modGroups.begin();
       it != modGroups.end(); ++it)
      {
      if(it->hasColor()
        && _internal_getValidEntityColor(color, *it))
        {
        colorEntities[*it] = color;
        }
      }
    }
  else if (colorMode ==
      vtkModelMultiBlockSource::GetEntityTagName())
    {
    // if colorby-entity, get entities' color, 
    for(uit = minfo->Info->GetUUID2BlockIdMap().begin();
      uit != minfo->Info->GetUUID2BlockIdMap().end(); ++uit)
      {
      smtk::model::EntityRef eref(activeModel.manager(), uit->first);
      if(eref.hasColor()
        && _internal_getValidEntityColor(color, eref))
        {
        colorEntities[eref] = color;
        }
      }
    }

  if(colorEntities.size() > 0)
    {
    this->updateColorForEntities(activeRep, colorMode, colorEntities);
    this->m_ModelPanel->modelManager()->updateEntityColorTable(
      activeRep, colorEntities, colorMode);
    }
  this->m_ModelPanel->modelManager()->colorRepresentationByEntity(
    activeRep, colorMode);

}

//----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::colorByAttribute(
    smtk::attribute::SystemPtr attSys,
    const QString& attdeftype, const QString& itemname)
{
  if(!this->m_ModelPanel || !this->m_ModelPanel->modelManager())
    return;

  // active rep
  pqDataRepresentation* activeRep = pqActiveObjects::instance().activeRepresentation();
  pqMultiBlockInspectorPanel *datapanel = this->m_DataInspector;
  if (!datapanel || !activeRep)
    return;
  cmbSMTKModelInfo* minfo = this->m_ModelPanel->modelManager()->modelInfo(activeRep);
  if(!minfo)
    return;

  smtk::common::UUID modelId = minfo->Info->GetModelUUID();
  smtk::model::Model activeModel(
    this->m_ModelPanel->modelManager()->managerProxy()->modelManager(), modelId);
  if(!activeModel.isValid())
    return;

  // turn off the current scalar bar before switch to the new array
  vtkSMProxy* ctfProxy = activeRep->getLookupTableProxy();
  vtkSMProxy* sb = vtkSMTransferFunctionProxy::FindScalarBarRepresentation(
    ctfProxy, pqActiveObjects::instance().activeView()->getProxy());
  if(sb)
    {
    vtkSMPropertyHelper(sb, "Visibility").Set(0);
    sb->UpdateVTKObjects();
    }

  // clear all colors
  QList<unsigned int> indices;
  std::map<smtk::common::UUID, unsigned int>::const_iterator uit =
    minfo->Info->GetUUID2BlockIdMap().begin();
  for(; uit != minfo->Info->GetUUID2BlockIdMap().end(); ++uit)
    {
    indices.append(uit->second + 1);
    }
  datapanel->clearBlockColor(indices);

  this->m_ModelPanel->modelManager()->colorRepresentationByAttribute(
    activeRep, attSys, attdeftype, itemname);

}

//----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::updateColorForEntities(
    pqDataRepresentation* rep, const QString& colorMode,
    const QMap<smtk::model::EntityRef, QColor >& colorEntities)
{
  if(colorMode == "None")
    return;

  foreach(const smtk::model::EntityRef& entref, colorEntities.keys())
    {
    QSet<unsigned int> blockIds;
    if((entref.isVolume() && colorMode ==
      vtkModelMultiBlockSource::GetVolumeTagName()) ||
      (entref.isGroup() && colorMode ==
      vtkModelMultiBlockSource::GetGroupTagName()) ||
      (entref.hasIntegerProperty("block_index") && colorMode ==
      vtkModelMultiBlockSource::GetEntityTagName()))
      {
      _internal_AccumulateChildGeometricEntities(blockIds, entref);
      }
    if(blockIds.size() > 0)
      this->syncBlockColor(rep,
        QList<unsigned int>::fromSet(blockIds), colorEntities[entref]);
    }
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::syncBlockColor(
    pqDataRepresentation* rep,
    const QList<unsigned int>& colorBlocks, const QColor& color)
{
  if(!this->m_ModelPanel || !this->m_ModelPanel->modelManager())
    return;

  pqMultiBlockInspectorPanel *panel = this->m_DataInspector;
  if (panel && rep)
    {
    pqOutputPort* prevOutport = pqActiveObjects::instance().activePort();
    pqDataRepresentation* prevRep = pqActiveObjects::instance().activeRepresentation();

    panel->onRepresentationChanged(rep);
    panel->onPortChanged(rep->getOutputPortFromInput());
    if(color.isValid())
      panel->setBlockColor(colorBlocks, color);
    else
      panel->clearBlockColor(colorBlocks);

    panel->onRepresentationChanged(prevRep);
    panel->onPortChanged(prevOutport);

    }

}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::onViewAdded(pqView* view)
{
  if (view && view->getProxy()->IsA("vtkSMRenderViewProxy"))
    {
    // add a link view menu
    view->widget()->installEventFilter(this);
    }
}

//-----------------------------------------------------------------------------
bool pqModelBuilderViewContextMenuBehavior::eventFilter(QObject* caller, QEvent* e)
{
  if (e->type() == QEvent::MouseButtonPress)
    {
    QMouseEvent* me = static_cast<QMouseEvent*>(e);
    if (me->button() & Qt::RightButton)
      {
      this->Position = me->pos();
      }
    }
  else if (e->type() == QEvent::MouseButtonRelease)
    {
    QMouseEvent* me = static_cast<QMouseEvent*>(e);
    if (me->button() & Qt::RightButton && !this->Position.isNull())
      {
      QPoint newPos = static_cast<QMouseEvent*>(e)->pos();
      QPoint delta = newPos - this->Position;
      QWidget* senderWidget = qobject_cast<QWidget*>(caller);
      if (delta.manhattanLength() < 3 && senderWidget != NULL)
        {
        pqRenderView* view = qobject_cast<pqRenderView*>(
          pqActiveObjects::instance().activeView());
        if (view)
          {
          int pos[2] = { newPos.x(), newPos.y() } ;
          // we need to flip Y.
          int height = senderWidget->size().height();
          pos[1] = height - pos[1];
          unsigned int blockIndex = 0;
          
          this->PickedRepresentation = view->pickBlock(pos, blockIndex);

          this->buildMenu(this->PickedRepresentation, blockIndex);
          this->Menu->popup(senderWidget->mapToGlobal(newPos));

          // we want to select this block.
          if(this->PickedRepresentation)
            {
            emit this->representationBlockPicked(this->PickedRepresentation, blockIndex);
            }
          }
        }
      this->Position = QPoint();
      }
    }

  return Superclass::eventFilter(caller, e);
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::buildMenu(pqDataRepresentation* repr,
                                              unsigned int blockIndex)
{
  // get currently selected block ids
  this->PickedBlocks.clear();
  this->PickedBlocks.append(static_cast<unsigned int>(blockIndex));

  if(this->m_colormapReaction)
    {
    this->m_colormapReaction->deleteLater();
    this->m_colormapReaction = NULL;
    }

  this->Menu->clear();
  if (repr)
    {
    vtkPVDataInformation *info = repr->getInputDataInformation();
    vtkPVCompositeDataInformation *compositeInfo = info->GetCompositeDataInformation();
    if(compositeInfo && compositeInfo->GetDataIsComposite())
      {
      cmbSMTKModelInfo* minfo = this->m_ModelPanel->modelManager()->modelInfo(repr);

      bool multipleBlocks = this->PickedBlocks.size() > 1;
      if(multipleBlocks)
        {
        this->Menu->addAction(QString("%1 Entities").arg(this->PickedBlocks.size()));
        }
      else
        {
        QString blockName = this->lookupBlockName(blockIndex, minfo);
        this->Menu->addAction(QString("%1").arg(blockName));
        }
      this->Menu->addSeparator();

      if(minfo && minfo->hasAnalysisMesh())
        {
        QAction* meshaction = this->Menu->addAction("Show Analysis Mesh");
        meshaction->setCheckable(true);
        meshaction->setChecked(minfo->ShowMesh);
        this->connect(meshaction, SIGNAL(triggered()),
                      this, SLOT(switchModelTessellation()));

        this->Menu->addSeparator();
        }

      QAction *hideBlockAction =
        this->Menu->addAction(QString("Hide Selected"));
      this->connect(hideBlockAction, SIGNAL(triggered()),
                    this, SLOT(hideBlock()));

//      action = this->Menu->addAction("Hide All Entities");
//      QObject::connect(action, SIGNAL(triggered()), this, SLOT(hide()));

      QAction *showOnlyBlockAction =
        this->Menu->addAction(QString("Hide Others"));
      this->connect(showOnlyBlockAction, SIGNAL(triggered()),
                    this, SLOT(showOnlyBlock()));

      QAction *showAllBlocksAction =
        this->Menu->addAction("Show Whole Model");
      this->connect(showAllBlocksAction, SIGNAL(triggered()),
                    this, SLOT(showAllBlocks()));
/*
      QAction *unsetVisibilityAction =
        this->Menu->addAction(QString("Unset Entity %1")
            .arg(multipleBlocks ? "Visibilities" : "Visibility"));
      this->connect(unsetVisibilityAction, SIGNAL(triggered()),
                    this, SLOT(unsetBlockVisibility()));
*/
      this->Menu->addSeparator();

      QAction *setBlockColorAction =
        this->Menu->addAction(QString("Set Color%1")
          .arg(multipleBlocks ? "s" : ""));
      this->connect(setBlockColorAction, SIGNAL(triggered()),
                    this, SLOT(setBlockColor()));

      QAction *unsetBlockColorAction =
        this->Menu->addAction(QString("Unset Color%1")
          .arg(multipleBlocks ? "s" : ""));
      this->connect(unsetBlockColorAction, SIGNAL(triggered()),
                    this, SLOT(unsetBlockColor()));
/*
      this->Menu->addSeparator();

      QAction *setBlockOpacityAction =
        this->Menu->addAction(QString("Set Entity %1")
          .arg(multipleBlocks ? "Opacities" : "Opacity"));
      this->connect(setBlockOpacityAction, SIGNAL(triggered()),
                    this, SLOT(setBlockOpacity()));

      QAction *unsetBlockOpacityAction =
        this->Menu->addAction(QString("Unset Entity %1")
            .arg(multipleBlocks ? "Opacities" : "Opacity"));
      this->connect(unsetBlockOpacityAction, SIGNAL(triggered()),
                    this, SLOT(unsetBlockOpacity()));
*/
      QAction* action = this->Menu->addAction("Edit Color");
      this->m_colormapReaction = new pqEditColorMapReaction(action);

      this->Menu->addSeparator();
      }

    QMenu* reprMenu = this->Menu->addMenu("Representation")
      << pqSetName("Representation");

    // populate the representation types menu.
    QList<QVariant> rTypes = pqSMAdaptor::getEnumerationPropertyDomain(
      repr->getProxy()->GetProperty("Representation"));
    QVariant curRType = pqSMAdaptor::getEnumerationProperty(
      repr->getProxy()->GetProperty("Representation"));
    foreach (QVariant rtype, rTypes)
      {
      QAction* raction = reprMenu->addAction(rtype.toString());
      raction->setCheckable(true);
      raction->setChecked(rtype == curRType);
      }

    QObject::connect(reprMenu, SIGNAL(triggered(QAction*)),
      this, SLOT(reprTypeChanged(QAction*)));
/*
    this->Menu->addSeparator();

    pqPipelineRepresentation* pipelineRepr =
      qobject_cast<pqPipelineRepresentation*>(repr);

    if (pipelineRepr)
      {
      QMenu* colorFieldsMenu = this->Menu->addMenu("Color By")
        << pqSetName("ColorBy");
      this->buildColorFieldsMenu(pipelineRepr, colorFieldsMenu);
      }
*/

    this->Menu->addSeparator();
    }

  // when nothing was picked we show the "link camera" menu.
  this->Menu->addAction("Show All Models",
    this, SLOT(showAllRepresentations()));
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::buildColorFieldsMenu(
  pqPipelineRepresentation* pipelineRepr, QMenu* menu)
{
  QObject::connect(menu, SIGNAL(triggered(QAction*)),
    this, SLOT(colorMenuTriggered(QAction*)), Qt::QueuedConnection);

  QIcon cellDataIcon(":/pqWidgets/Icons/pqCellData16.png");
  QIcon pointDataIcon(":/pqWidgets/Icons/pqPointData16.png");
  QIcon solidColorIcon(":/pqWidgets/Icons/pqSolidColor16.png");

  menu->addAction(solidColorIcon, "Solid Color")->setData(
    convert(QPair<int, QString>()));
  vtkSMProperty* prop = pipelineRepr->getProxy()->GetProperty("ColorArrayName");
  vtkSMArrayListDomain* domain = prop?
    vtkSMArrayListDomain::SafeDownCast(prop->FindDomain("vtkSMArrayListDomain")) : NULL;
  if (!domain)
    {
    return;
    }

  // We are only showing array names here without worrying about components since that
  // keeps the menu simple and code even simpler :).
  for (unsigned int cc=0, max = domain->GetNumberOfStrings(); cc < max; cc++)
    {
    int association = domain->GetFieldAssociation(cc);
    int icon_association = domain->GetDomainAssociation(cc);
    QString name = domain->GetString(cc);

    QIcon& icon = (icon_association == vtkDataObject::CELL)?
      cellDataIcon : pointDataIcon;

    QVariant data = convert(QPair<int, QString>(association, name));
    menu->addAction(icon, name)->setData(data);
    }
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::colorMenuTriggered(QAction* action)
{
  QPair<int, QString> array = convert(action->data());
  if (this->PickedRepresentation)
    {
    BEGIN_UNDO_SET("Change coloring");
    vtkSMViewProxy* view = pqActiveObjects::instance().activeView()->getViewProxy();
    vtkSMProxy* reprProxy = this->PickedRepresentation->getProxy();

    vtkSMProxy* oldLutProxy = vtkSMPropertyHelper(reprProxy, "LookupTable", true).GetAsProxy();

    vtkSMPVRepresentationProxy::SetScalarColoring(
      reprProxy, array.second.toLatin1().data(), array.first);

    vtkNew<vtkSMTransferFunctionManager> tmgr;

    // Hide unused scalar bars, if applicable.
    vtkPVGeneralSettings* gsettings = vtkPVGeneralSettings::GetInstance();
    switch (gsettings->GetScalarBarMode())
      {
    case vtkPVGeneralSettings::AUTOMATICALLY_HIDE_SCALAR_BARS:
    case vtkPVGeneralSettings::AUTOMATICALLY_SHOW_AND_HIDE_SCALAR_BARS:
      tmgr->HideScalarBarIfNotNeeded(oldLutProxy, view);
      break;
      }

    if (!array.second.isEmpty())
      {
      // we could now respect some application setting to determine if the LUT is
      // to be reset.
      vtkSMPVRepresentationProxy::RescaleTransferFunctionToDataRange(reprProxy, true);

      /// BUG #0011858. Users often do silly things!
      bool reprVisibility =
        vtkSMPropertyHelper(reprProxy, "Visibility", /*quiet*/true).GetAsInt() == 1;

      // now show used scalar bars if applicable.
      if (reprVisibility &&
        gsettings->GetScalarBarMode() ==
        vtkPVGeneralSettings::AUTOMATICALLY_SHOW_AND_HIDE_SCALAR_BARS)
        {
        vtkSMPVRepresentationProxy::SetScalarBarVisibility(reprProxy, view, true);
        }
      }

    this->PickedRepresentation->renderViewEventually();
    END_UNDO_SET();
    }
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::switchModelTessellation()
{
  QAction *action = qobject_cast<QAction *>(sender());
  if(!action || !this->m_ModelPanel)
    {
    return;
    }
  pqDataRepresentation* repr = this->PickedRepresentation;
  cmbSMTKModelInfo* minfo = this->m_ModelPanel->modelManager()->modelInfo(repr);
  if(minfo && minfo->hasAnalysisMesh())
    {
    minfo->ShowMesh = !minfo->ShowMesh;
    this->m_ModelPanel->modelManager()->updateModelRepresentation(minfo);
    action->setChecked(minfo->ShowMesh);
    }
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::reprTypeChanged(QAction* action)
{
  pqDataRepresentation* repr = this->PickedRepresentation;
  if (repr)
    {
    BEGIN_UNDO_SET("Representation Type Changed");
    pqSMAdaptor::setEnumerationProperty(
      repr->getProxy()->GetProperty("Representation"),
      action->text());
    repr->getProxy()->UpdateVTKObjects();
    repr->renderViewEventually();
    END_UNDO_SET();
    }
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::hide()
{
  QAction *action = qobject_cast<QAction *>(sender());
  if(!action || !this->m_ModelPanel)
    {
    return;
    }
  pqDataRepresentation* repr = this->PickedRepresentation;
  QList<unsigned int> emptyList;
  this->m_ModelPanel->showOnlyBlocks(
    repr, emptyList);
}

/// This is triggered from context menu, which will set off
/// a SetProperty op in smtk, then the application will
/// process the op result to set visibilities through
/// pqModelBuilderViewContextMenuBehavior::setBlockVisibility()
//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::hideBlock()
{
  QAction *action = qobject_cast<QAction *>(sender());
  if(!action || !this->m_ModelPanel)
    {
    return;
    }
  this->m_ModelPanel->setBlockVisibility(
    this->PickedRepresentation, this->PickedBlocks, false);
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::showOnlyBlock()
{
  QAction *action = qobject_cast<QAction *>(sender());
  if(!action || !this->m_ModelPanel)
    {
    return;
    }
  this->m_ModelPanel->showOnlyBlocks(
    this->PickedRepresentation, this->PickedBlocks);
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::showAllBlocks()
{
  QAction *action = qobject_cast<QAction *>(sender());
  if(!action || !this->m_ModelPanel)
    {
    return;
    }
  this->m_ModelPanel->showAllBlocks(
    this->PickedRepresentation);
/*
  pqMultiBlockInspectorPanel *panel = this->m_DataInspector;
  if (panel)
    {
    panel->showAllBlocks();
    }
*/
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::showAllRepresentations()
{
  if(!this->m_ModelPanel || !this->m_ModelPanel->modelManager())
    return;

  foreach(pqDataRepresentation* repr,
          this->m_ModelPanel->modelManager()->modelRepresentations())
    {
    this->m_ModelPanel->showAllBlocks(repr);
    }
  pqRenderView* view = qobject_cast<pqRenderView*>(
    pqActiveObjects::instance().activeView());
  if (view)
    {
    view->resetCamera();
    view->render();
    }
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::setBlockColor()
{
  QAction *action = qobject_cast<QAction *>(sender());
  if(!action || !this->m_ModelPanel)
    {
    return;
    }
  QColor color = QColorDialog::getColor(QColor(),
    this->m_DataInspector, "Choose Block Color",
    QColorDialog::DontUseNativeDialog);
  if(color.isValid())
    {
    this->m_ModelPanel->setBlockColor(
      this->PickedRepresentation, this->PickedBlocks, color);
    }
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::unsetBlockColor()
{
  QAction *action = qobject_cast<QAction *>(sender());
  if(!action || !this->m_ModelPanel)
    {
    return;
    }
  QColor invalidColor;
  this->m_ModelPanel->setBlockColor(
    this->PickedRepresentation, this->PickedBlocks, invalidColor);
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::setBlockOpacity()
{
  QAction *action = qobject_cast<QAction *>(sender());
  if(!action)
    {
    return;
    }

  pqMultiBlockInspectorPanel *panel = this->m_DataInspector;
  if(panel)
    {
    panel->promptAndSetBlockOpacity(this->PickedBlocks);
    }
}

//-----------------------------------------------------------------------------
void pqModelBuilderViewContextMenuBehavior::unsetBlockOpacity()
{
  QAction *action = qobject_cast<QAction *>(sender());
  if(!action)
    {
    return;
    }

  pqMultiBlockInspectorPanel *panel = this->m_DataInspector;
  if(panel)
    {
    panel->clearBlockOpacity(this->PickedBlocks);
    }
}

//-----------------------------------------------------------------------------
QString pqModelBuilderViewContextMenuBehavior::lookupBlockName(
  unsigned int blockIdx, cmbSMTKModelInfo* minfo) const
{
  // if there is an entity name in smtk, use that
  if(blockIdx > 0 && minfo)
    {
    smtk::common::UUID entId = minfo->Info->GetModelEntityId(blockIdx - 1);
    const smtk::model::EntityRef entity(this->m_ModelPanel->modelManager()->
      managerProxy()->modelManager(), entId);
    if(entity.isValid())
      {
      return entity.name().c_str();
      }
    }

  // else fall back to multiblock data representation
  pqMultiBlockInspectorPanel *panel = this->m_DataInspector;
  if(panel)
    {
    return panel->lookupBlockName(blockIdx);
    }
  else
    {
    return QString();
    }
}
