text: /*
   * Copyright (c) Contributors to the Open 3D Engine Project.
   * For complete copyright and license terms please see the LICENSE at the root of this distribution.
   *
   * SPDX-License-Identifier: Apache-2.0 OR MIT
   *
   */
  
  #include <AzCore/PlatformDef.h>
  
  AZ_PUSH_DISABLE_WARNING(4251 4800 4244, "-Wunknown-warning-option")
  #include <QEvent>
  #include <QFocusEvent>
  #include <QHeaderView>
  #include <QScopedValueRollback>
  #include <QToolButton>
  #include <QVBoxLayout>
  #include <QWidgetAction>
  AZ_POP_DISABLE_WARNING
  
  #include <Widgets/GraphCanvasComboBox.h>
  
  namespace GraphCanvas
  {
      ////////////////////////////////////////
      // GraphCanvasComboBoxFilterProxyModel
      ////////////////////////////////////////    
  
      GraphCanvasComboBoxFilterProxyModel::GraphCanvasComboBoxFilterProxyModel(QObject*)
      {
      }
  
      bool GraphCanvasComboBoxFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
      {
          if (m_filter.isEmpty())
          {
              return true;
          }
  
          QAbstractItemModel* model = sourceModel();
  
          if (!model)
          {
              return false;
          }
  
          QModelIndex index = model->index(sourceRow, filterKeyColumn(), sourceParent);
          QString test = model->data(index, filterRole()).toString();
  
          return (test.lastIndexOf(m_testRegex) >= 0);
      }
  
      void GraphCanvasComboBoxFilterProxyModel::SetFilter(const QString& filter)
      {
          m_filter = filter;
          m_testRegex = QRegExp(m_filter, Qt::CaseInsensitive);
          invalidateFilter();
  
          if (m_filter.isEmpty())
          {
              sort(-1);
          }
          else
          {
              sort(filterKeyColumn());
          }
      }
  
      ////////////////////////////
      // GraphCanvasComboBoxMenu
      ////////////////////////////
  
      GraphCanvasComboBoxMenu::GraphCanvasComboBoxMenu(ComboBoxItemModelInterface* model, QWidget* parent)
          : QDialog(parent, Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint)
          , m_disableHiding(false)
          , m_ignoreNextFocusIn(false)
          , m_modelInterface(model)
      {
          setProperty("HasNoWindowDecorations", true);
  
          setAttribute(Qt::WA_ShowWithoutActivating);
  
          m_filterProxyModel.setSourceModel(m_modelInterface->GetDropDownItemModel());
          m_filterProxyModel.sort(m_modelInterface->GetSortColumn());
          m_filterProxyModel.setFilterKeyColumn(m_modelInterface->GetCompleterColumn());
  
          m_tableView.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
          m_tableView.setSelectionBehavior(QAbstractItemView::SelectRows);
          m_tableView.setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
  
          m_tableView.setModel(GetProxyModel());
          m_tableView.verticalHeader()->hide();
          m_tableView.verticalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents);
  
          m_tableView.horizontalHeader()->hide();
          m_tableView.horizontalHeader()->setStretchLastSection(true);
  
          m_tableView.installEventFilter(this);
          m_tableView.setFocusPolicy(Qt::FocusPolicy::ClickFocus);
  
          m_tableView.setMinimumWidth(0);
  
          QVBoxLayout* layout = new QVBoxLayout();
          layout->addWidget(&m_tableView);
          setLayout(layout);
  
          m_disableHidingStateSetter.AddStateController(GetDisableHidingStateController());
  
          QObject::connect(&m_tableView, &QTableView::clicked, this, &GraphCanvasComboBoxMenu::OnTableClicked);
  
          m_closeTimer.setInterval(0);
  
          QAction* escapeAction = new QAction(this);
          escapeAction->setShortcut(Qt::Key_Escape);
  
          addAction(escapeAction);
  
          QObject::connect(escapeAction, &QAction::triggered, this, &GraphCanvasComboBoxMenu::CancelMenu);
      }
  
      GraphCanvasComboBoxMenu::~GraphCanvasComboBoxMenu()
      {
      }
  
      ComboBoxItemModelInterface* GraphCanvasComboBoxMenu::GetInterface()
      {
          return m_modelInterface;
      }
  
      const ComboBoxItemModelInterface* GraphCanvasComboBoxMenu::GetInterface() const
      {
          return m_modelInterface;
      }
  
      GraphCanvasComboBoxFilterProxyModel* GraphCanvasComboBoxMenu::GetProxyModel()
      {
          return &m_filterProxyModel;
      }
  
      const GraphCanvasComboBoxFilterProxyModel* GraphCanvasComboBoxMenu::GetProxyModel() const
      {
          return &m_filterProxyModel;
      }
  
      void GraphCanvasComboBoxMenu::ShowMenu()
      {
          clearFocus();
          m_tableView.clearFocus();
          m_tableView.selectionModel()->clearSelection();
  
          m_filterProxyModel.BeginModelReset();
          m_modelInterface->OnDropDownAboutToShow();
          m_filterProxyModel.EndModelReset();
  
          show();
  
          m_disableHidingStateSetter.ReleaseState();
  
          int rowHeight = m_tableView.rowHeight(0);
  
          if (rowHeight > 0)
          {
              // Generic padding of like 20 pixels.
              setMinimumHeight(aznumeric_cast<int>(rowHeight * 4.5 + 20));
              setMaximumHeight(aznumeric_cast<int>(rowHeight * 4.5 + 20));
          }
      }
  
      void GraphCanvasComboBoxMenu::HideMenu()
      {
          m_disableHidingStateSetter.ReleaseState();
  
          m_tableView.clearFocus();
          m_tableView.selectionModel()->clearSelection();
  
          clearFocus();
          reject();
  
          m_filterProxyModel.BeginModelReset();
          m_modelInterface->OnDropDownHidden();
          m_filterProxyModel.EndModelReset();
      }
  
      void GraphCanvasComboBoxMenu::reject()
      {
          if (!m_disableHiding.GetState())
          {
              QDialog::reject();
          }
      }
  
      bool GraphCanvasComboBoxMenu::eventFilter(QObject* object, QEvent* event)
      {
          if (object == &m_tableView)
          {
              if (event->type() == QEvent::FocusOut)
              {
                  HandleFocusOut();
              }
              else if (event->type() == QEvent::FocusIn)
              {
                  HandleFocusIn();
              }
          }
  
          return false;
      }
  
      void GraphCanvasComboBoxMenu::focusInEvent(QFocusEvent* focusEvent)
      {
          QDialog::focusInEvent(focusEvent);
  
          if (focusEvent->isAccepted())
          {
              if (!m_ignoreNextFocusIn)
              {
                  HandleFocusIn();
              }
              else
              {
                  m_ignoreNextFocusIn = false;
              }
          }
      }
  
      void GraphCanvasComboBoxMenu::focusOutEvent(QFocusEvent* focusEvent)
      {
          QDialog::focusOutEvent(focusEvent);
          HandleFocusOut();
      }
  
      void GraphCanvasComboBoxMenu::showEvent(QShowEvent* showEvent)
      {
          QDialog::showEvent(showEvent);
  
          // So, despite me telling it to not activate, the window still gets a focus in event.
          // But, it doesn't get a focus out event, since it doesn't actually accept the focus in event?
          m_ignoreNextFocusIn = true;
          m_tableView.selectionModel()->clearSelection();
  
          Q_EMIT VisibilityChanged(true);
      }
  
      void GraphCanvasComboBoxMenu::hideEvent(QHideEvent* hideEvent)
      {
          QDialog::hideEvent(hideEvent);
  
          clearFocus();
  
          Q_EMIT VisibilityChanged(false);
          m_tableView.selectionModel()->clearSelection();
          m_filterProxyModel.invalidate();
      }
  
      GraphCanvas::StateController<bool>* GraphCanvasComboBoxMenu::GetDisableHidingStateController()
      {
          return &m_disableHiding;
      }
  
      void GraphCanvasComboBoxMenu::SetSelectedIndex(QModelIndex index)
      {
          m_tableView.selectionModel()->clear();
  
          if (index.isValid()
              && index.row() >= 0
              && index.row() < m_filterProxyModel.rowCount())
          {
              QItemSelection rowSelection(m_filterProxyModel.index(index.row(), 0, index.parent()), m_filterProxyModel.index(index.row(), m_filterProxyModel.columnCount() - 1, index.parent()));
              m_tableView.selectionModel()->select(rowSelection, QItemSelectionModel::Select);
  
              m_tableView.scrollTo(m_filterProxyModel.index(index.row(), 0, index.parent()));
          }
      }
  
      QModelIndex GraphCanvasComboBoxMenu::GetSelectedIndex() const
      {
          if (m_tableView.selectionModel()->hasSelection())
          {
              QModelIndexList selectedIndexes = m_tableView.selectionModel()->selectedIndexes();
  
              if (!selectedIndexes.empty())
              {
                  return selectedIndexes.front();
              }
          }
  
          return QModelIndex();
      }
  
      QModelIndex GraphCanvasComboBoxMenu::GetSelectedSourceIndex() const
      {
          if (m_tableView.selectionModel()->hasSelection())
          {
              QModelIndexList selectedIndexes = m_tableView.selectionModel()->selectedIndexes();
  
              if (!selectedIndexes.empty())
              {
                  return m_filterProxyModel.mapToSource(selectedIndexes.front());
              }
          }
  
          return QModelIndex();
      }
  
      void GraphCanvasComboBoxMenu::OnTableClicked(const QModelIndex& modelIndex)
      {
          if (modelIndex.isValid())
          {
              QModelIndex sourceIndex = m_filterProxyModel.mapToSource(modelIndex);
  
              if (sourceIndex.isValid())
              {
                  Q_EMIT OnIndexSelected(sourceIndex);
  
                  QObject::disconnect(m_closeConnection);
                  m_closeConnection = QObject::connect(&m_closeTimer, &QTimer::timeout, this, &QDialog::accept);
  
                  m_closeTimer.start();
              }
          }
      }
  
      void GraphCanvasComboBoxMenu::HandleFocusIn()
      {
          m_disableHidingStateSetter.SetState(true);
  
          emit OnFocusIn();
      }
  
      void GraphCanvasComboBoxMenu::HandleFocusOut()
      {
          m_disableHidingStateSetter.ReleaseState();
  
          QObject::disconnect(m_closeConnection);
          m_closeConnection = QObject::connect(&m_closeTimer, &QTimer::timeout, this, &QDialog::reject);
  
          m_closeTimer.start();
  
          emit OnFocusOut();
      }
  
      ////////////////////////
      // GraphCanvasComboBox
      ////////////////////////
  
      GraphCanvasComboBox::GraphCanvasComboBox(ComboBoxItemModelInterface* modelInterface, QWidget* parent)
          : QLineEdit(parent)
          , m_lineEditInFocus(false)
          , m_popUpMenuInFocus(false)
          , m_hasFocus(false)
          , m_ignoreNextComplete(false)
          , m_recursionBlocker(false)
          , m_comboBoxMenu(modelInterface)
          , m_modelInterface(modelInterface)
      {
          setObjectName("ComboBoxLineEdit");
  
          setProperty("HasNoWindowDecorations", true);
          setProperty("DisableFocusWindowFix", true);
  
          QAction* action = addAction(QIcon(":/GraphCanvasEditorResources/settings_icon.png"), QLineEdit::ActionPosition::TrailingPosition);
          QObject::connect(action, &QAction::triggered, this, &GraphCanvasComboBox::OnOptionsClicked);        
  
          QAction* escapeAction = new QAction(this);
          escapeAction->setShortcut(Qt::Key_Escape);
  
          addAction(escapeAction);
  
          QObject::connect(escapeAction, &QAction::triggered, this, &GraphCanvasComboBox::ResetComboBox);
  
          m_completer.setModel(m_modelInterface->GetCompleterItemModel());
          m_completer.setCompletionColumn(m_modelInterface->GetCompleterColumn());
          m_completer.setCompletionMode(QCompleter::CompletionMode::InlineCompletion);
          m_completer.setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
  
          QObject::connect(this, &QLineEdit::textEdited, this, &GraphCanvasComboBox::OnTextChanged);
          QObject::connect(this, &QLineEdit::returnPressed, this, &GraphCanvasComboBox::OnReturnPressed);
          QObject::connect(this, &QLineEdit::editingFinished, this, &GraphCanvasComboBox::OnEditComplete);
  
          m_filterTimer.setInterval(500);
          QObject::connect(&m_filterTimer, &QTimer::timeout, this, &GraphCanvasComboBox::UpdateFilter);
  
          m_closeTimer.setInterval(0);
          QObject::connect(&m_closeTimer, &QTimer::timeout, this, &GraphCanvasComboBox::CloseMenu);
  
          m_focusTimer.setInterval(0);
          QObject::connect(&m_focusTimer, &QTimer::timeout, this, &GraphCanvasComboBox::HandleFocusState);
  
          QObject::connect(&m_comboBoxMenu, &GraphCanvasComboBoxMenu::OnIndexSelected, this, &GraphCanvasComboBox::UserSelectedIndex);
          QObject::connect(&m_comboBoxMenu, &GraphCanvasComboBoxMenu::OnFocusIn, this, &GraphCanvasComboBox::OnMenuFocusIn);
          QObject::connect(&m_comboBoxMenu, &GraphCanvasComboBoxMenu::OnFocusOut, this, &GraphCanvasComboBox::OnMenuFocusOut);
          QObject::connect(&m_comboBoxMenu, &GraphCanvasComboBoxMenu::CancelMenu, this, &GraphCanvasComboBox::ResetComboBox);
  
          m_comboBoxMenu.accept();
  
          m_disableHidingStateSetter.AddStateController(m_comboBoxMenu.GetDisableHidingStateController());
      }
  
      GraphCanvasComboBox::~GraphCanvasComboBox()
      {
      }
  
      void GraphCanvasComboBox::RegisterViewId(const ViewId& viewId)
      {
          m_viewId = viewId;
      }
  
      void GraphCanvasComboBox::SetAnchorPoint(QPoint globalPoint)
      {
          m_anchorPoint = globalPoint;
          UpdateMenuPosition();
      }
  
      void GraphCanvasComboBox::SetMenuWidth(qreal width)
      {
          m_displayWidth = width;
          UpdateMenuPosition();
      }
  
      void GraphCanvasComboBox::SetSelectedIndex(const QModelIndex& selectedIndex)
      {
          QModelIndex previousIndex = m_modelInterface->FindIndexForName(m_selectedName);
  
          if (previousIndex != selectedIndex)
          {
              m_selectedName = m_modelInterface->GetNameForIndex(selectedIndex);
  
              if (DisplayIndex(selectedIndex))
              {
                  Q_EMIT SelectedIndexChanged(selectedIndex);
              }
          }
      }
      
      QModelIndex GraphCanvasComboBox::GetSelectedIndex() const
      {
          return m_modelInterface->FindIndexForName(m_selectedName);
      }
  
      void GraphCanvasComboBox::SetOutlineColor(const QColor& outlineColor, const QColor& backgroundColor)
      {
          QString styleString = QString("QLineEdit#ComboBoxLineEdit { border: 1px solid %1; background-color: %2; }").arg(outlineColor.name()).arg(backgroundColor.name());
          AZ_UNUSED(styleString);
          //setStyleSheet(styleString);
      }
  
      void GraphCanvasComboBox::SetOutlineColor(const QGradient& gradient, const QColor& backgroundColor)
      {
          QString stops;
  
          for (auto currentStop : gradient.stops())
          {
              if (!stops.isEmpty())
              {
                  stops.append(", ");
              }
  
              QString currentStopStyle = QString("stop: %1 %2").arg(currentStop.first).arg(currentStop.second.name());
              stops.append(currentStopStyle);
          }        
          
          QString styleString = QString("QLineEdit#ComboBoxLineEdit { border: 1px solid qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0 %1); background-color: %2; }").arg(stops).arg(backgroundColor.name());
          AZ_UNUSED(styleString);
          //setStyleSheet(styleString);
      }
  
      void GraphCanvasComboBox::SetOutline(const QBrush& brush, const QColor& backgroundColor)
      {
          if (brush.gradient() != nullptr)
          {
              SetOutlineColor((*brush.gradient()), backgroundColor);
          }
          else
          {
              SetOutlineColor(brush.color(), backgroundColor);
          }
      }
  
      void GraphCanvasComboBox::ClearOutlineColor()
      {
          setStyleSheet("");
      }
  
      void GraphCanvasComboBox::ResetComboBox()
      {        
          HideMenu();
  
          QModelIndex selectedIndex = m_modelInterface->FindIndexForName(m_selectedName);
          DisplayIndex(selectedIndex);
  
          m_selectedName.clear();
      }
      
      void GraphCanvasComboBox::CancelInput()
      {
          QModelIndex selectedIndex = m_modelInterface->FindIndexForName(m_selectedName);
          DisplayIndex(selectedIndex);
          HideMenu();
      }
      
      void GraphCanvasComboBox::HideMenu()
      {
          m_disableHidingStateSetter.ReleaseState();
  
          m_comboBoxMenu.HideMenu();
  
          ViewNotificationBus::Handler::BusDisconnect(m_viewId);
      }
  
      bool GraphCanvasComboBox::IsMenuVisible() const
      {
          return !m_comboBoxMenu.isHidden();
      }
  
      void GraphCanvasComboBox::focusInEvent(QFocusEvent* focusEvent)
      {
          QLineEdit::focusInEvent(focusEvent);
  
          m_lineEditInFocus = true;
          m_focusTimer.start();
  
          grabKeyboard();
      }
  
      void GraphCanvasComboBox::focusOutEvent(QFocusEvent* focusEvent)
      {
          QLineEdit::focusOutEvent(focusEvent);
  
          m_lineEditInFocus = false;
          m_focusTimer.start();
  
          releaseKeyboard();
      }
  
      void GraphCanvasComboBox::keyPressEvent(QKeyEvent* keyEvent)
      {
          QLineEdit::keyPressEvent(keyEvent);
  
          if (keyEvent->key() == Qt::Key_Down)
          {
              if (m_comboBoxMenu.isHidden())
              {
                  ClearFilter();
                  DisplayMenu();
              }
  
              QModelIndex selectedIndex = m_comboBoxMenu.GetSelectedSourceIndex();
  
              if (!selectedIndex.isValid())
              {
                  selectedIndex = m_modelInterface->FindIndexForName(m_selectedName);
              }
  
              QModelIndex mappedIndex;
              QModelIndex sourceIndex;
  
              if (selectedIndex.isValid())
              {
                  sourceIndex = m_modelInterface->GetNextIndex(selectedIndex);
              }
              else
              {
                  sourceIndex = m_modelInterface->GetDefaultIndex();
              }
  
              while (sourceIndex != selectedIndex)
              {
                  mappedIndex = m_comboBoxMenu.GetProxyModel()->mapFromSource(sourceIndex);
  
                  if (mappedIndex.isValid())
                  {
                      break;
                  }
  
                  sourceIndex = m_modelInterface->GetNextIndex(sourceIndex);
              }
  
              selectedIndex = sourceIndex;
              m_comboBoxMenu.SetSelectedIndex(mappedIndex);
  
              QString typeName = m_modelInterface->GetNameForIndex(selectedIndex);
  
              if (!typeName.isEmpty())
              {
                  setText(typeName);
                  setSelection(0, static_cast<int>(typeName.size()));
  
                  m_completer.setCompletionPrefix(typeName);
              }
  
              keyEvent->accept();
          }
          else if (keyEvent->key() == Qt::Key_Up)
          {
              if (m_comboBoxMenu.isHidden())
              {
                  m_comboBoxMenu.GetProxyModel()->SetFilter("");
                  DisplayMenu();
              }
  
              QModelIndex selectedIndex = m_comboBoxMenu.GetSelectedSourceIndex();
  
              if (!selectedIndex.isValid())
              {
                  selectedIndex = m_modelInterface->FindIndexForName(m_selectedName);
              }
  
              QModelIndex mappedIndex;
              QModelIndex sourceIndex;
  
              if (selectedIndex.isValid())
              {
                  sourceIndex = m_modelInterface->GetPreviousIndex(selectedIndex);
              }
              else
              {
                  sourceIndex = m_modelInterface->GetPreviousIndex(m_modelInterface->GetDefaultIndex());
              }
  
              while (sourceIndex != selectedIndex)
              {
                  mappedIndex = m_comboBoxMenu.GetProxyModel()->mapFromSource(sourceIndex);
  
                  if (mappedIndex.isValid())
                  {
                      break;
                  }
  
                  sourceIndex = m_modelInterface->GetPreviousIndex(sourceIndex);
              }
  
              selectedIndex = sourceIndex;
              m_comboBoxMenu.SetSelectedIndex(mappedIndex);
  
              QString typeName = m_comboBoxMenu.GetInterface()->GetNameForIndex(sourceIndex);
  
              if (!typeName.isEmpty())
              {
                  setText(typeName);
                  setSelection(0, static_cast<int>(typeName.size()));
  
                  m_completer.setCompletionPrefix(typeName);
              }
  
              keyEvent->accept();
          }
          else if (keyEvent->key() == Qt::Key_Escape)
          {
              ResetComboBox();
  
              keyEvent->accept();
          }
      }
  
      void GraphCanvasComboBox::OnViewScrolled()
      {
          ResetComboBox();
      }
  
      void GraphCanvasComboBox::OnViewCenteredOnArea()
      {
          ResetComboBox();
      }
  
      void GraphCanvasComboBox::OnZoomChanged(qreal /*zoomLevel*/)
      {
      }
  
      void GraphCanvasComboBox::UserSelectedIndex(const QModelIndex& selectedIndex)
      {
          QModelIndex previousIndex = m_modelInterface->FindIndexForName(m_selectedName);
  
          if (previousIndex != selectedIndex)
          {
              SetSelectedIndex(selectedIndex);
  
              Q_EMIT OnUserActionComplete();
          }
      }
  
      void GraphCanvasComboBox::OnTextChanged()
      {
          DisplayMenu();
          UpdateFilter();
      }
      
      void GraphCanvasComboBox::OnOptionsClicked()
      {
          if (m_comboBoxMenu.isHidden())
          {
              m_comboBoxMenu.GetProxyModel()->SetFilter("");
              DisplayMenu();
          }
          else
          {
              m_comboBoxMenu.accept();
          }
      }
      
      void GraphCanvasComboBox::OnReturnPressed()
      {
          const bool allowReset = false;
          if (SubmitData(allowReset))
          {
              m_comboBoxMenu.accept();
          }
          else
          {
              setText("");
              UpdateFilter();
          }
  
          Q_EMIT OnUserActionComplete();
  
          // When we press enter, we will also get an editing complete signal. We want to ignore that since we handled it here.
          m_ignoreNextComplete = true;
      }
      
      void GraphCanvasComboBox::OnEditComplete()
      {
          if (m_ignoreNextComplete)
          {
              m_ignoreNextComplete = false;
              return;
          }
  
          SubmitData(false);
  
          m_closeState = CloseMenuState::Reject;
          m_closeTimer.start();
      }
  
      void GraphCanvasComboBox::ClearFilter()
      {
          m_comboBoxMenu.GetProxyModel()->SetFilter("");
      }
      
      void GraphCanvasComboBox::UpdateFilter()
      {
          m_comboBoxMenu.GetProxyModel()->SetFilter(GetUserInputText());
      }
  
      void GraphCanvasComboBox::CloseMenu()
      {
          switch (m_closeState)
          {
          case CloseMenuState::Accept:
              m_comboBoxMenu.accept();
          default:
              m_comboBoxMenu.reject();
          }
  
          m_closeState = CloseMenuState::Reject;
      }
  
      void GraphCanvasComboBox::OnMenuFocusIn()
      {
          m_popUpMenuInFocus = true;
          m_focusTimer.start();
      }
  
      void GraphCanvasComboBox::OnMenuFocusOut()
      {
          m_popUpMenuInFocus = false;
          m_focusTimer.start();
      }
  
      void GraphCanvasComboBox::HandleFocusState()
      {
          bool focusState = m_lineEditInFocus || m_popUpMenuInFocus;
  
          if (focusState != m_hasFocus)
          {
              m_hasFocus = focusState;
  
              if (m_hasFocus)
              {
                  Q_EMIT OnFocusIn();
              }
              else
              {
                  Q_EMIT OnFocusOut();
                  HideMenu();
              }
          }
      }
  
      bool GraphCanvasComboBox::DisplayIndex(const QModelIndex& index)
      {
          QSignalBlocker signalBlocker(this);
  
          QString name = m_modelInterface->GetNameForIndex(index);
  
          if (!name.isEmpty())
          {
              m_completer.setCompletionPrefix(name);
              setText(name);
              ClearFilter();
          }
          else
          {
              if (!m_selectedName.isEmpty())
              {
                  QModelIndex currentIndex = m_modelInterface->FindIndexForName(m_selectedName);
  
                  if (currentIndex != index)
                  {
                      DisplayIndex(currentIndex);
                  }
              }
              else
              {
                  m_completer.setCompletionPrefix("");
                  setText("");
                  UpdateFilter();
              }
          }
  
          return !m_selectedName.isEmpty();
      }
      
      bool GraphCanvasComboBox::SubmitData(bool allowReset)
      {
          QString inputName = text();
  
          QModelIndex inputIndex = m_modelInterface->FindIndexForName(inputName);
  
          // We didn't input a valid type. So default to our last previously known value.
          if (!inputIndex.isValid())
          {
              if (allowReset)
              {
                  QModelIndex lastIndex = m_modelInterface->FindIndexForName(m_selectedName);
                  DisplayIndex(lastIndex);
  
                  inputIndex = lastIndex;
              }
          }
          else
          {
              SetSelectedIndex(inputIndex);
          }
  
          return inputIndex.isValid();
      }
      
      void GraphCanvasComboBox::DisplayMenu()
      {
          if (!m_recursionBlocker)
          {
              QScopedValueRollback<bool> valueRollback(m_recursionBlocker, true);
              if (m_comboBoxMenu.isHidden())
              {
                  Q_EMIT OnMenuAboutToDisplay();
                  ViewNotificationBus::Handler::BusConnect(m_viewId);
  
                  qreal zoomLevel = 1.0;
                  ViewRequestBus::EventResult(zoomLevel, m_viewId, &ViewRequests::GetZoomLevel);
  
                  if (zoomLevel < 1.0)
                  {
                      zoomLevel = 1.0;
                  }
  
                  m_comboBoxMenu.GetInterface()->SetFontScale(zoomLevel);
                  m_comboBoxMenu.ShowMenu();
  
                  UpdateMenuPosition();
              }
          }
  
          if (!m_disableHidingStateSetter.HasState())
          {
              m_disableHidingStateSetter.SetState(true);
          }
      }
      
      QString GraphCanvasComboBox::GetUserInputText()
      {
          QString lineEditText = text();
  
          // The QCompleter doesn't seem to update the completion prefix when you delete anything, only when things are added.
          // To get it to update correctly when the user deletes something, I'm using the combination of things:
          //
          // 1) If we have a completion, that text will be auto filled into the quick filter because of the completion model.
          // So, we will compare those two values, and if they match, we know we want to search using the completion prefix.
          //
          // 2) If they don't match, it means that user deleted something, and the Completer didn't update it's internal state, so we'll just
          // use whatever is in the text box.
          //
          // 3) When the text field is set to empty, the current completion gets invalidated, but the prefix doesn't, so that gets special cased out.
          //
          // Extra fun: If you type in something, "Like" then delete a middle character, "Lie", and then put the k back in. It will auto complete the E
          // visually but the completion prefix will be the entire word.
          if (completer()
              && completer()->currentCompletion().compare(lineEditText, Qt::CaseInsensitive) == 0
              && !lineEditText.isEmpty())
          {
              lineEditText = completer()->completionPrefix();
          }
  
          return lineEditText;
      }
  
      void GraphCanvasComboBox::UpdateMenuPosition()
      {
          if (!m_comboBoxMenu.isHidden())
          {
              QRect dialogGeometry = m_comboBoxMenu.geometry();
  
              dialogGeometry.moveTopLeft(m_anchorPoint);
              dialogGeometry.setWidth(aznumeric_cast<int>(m_displayWidth));
  
              m_comboBoxMenu.setGeometry(dialogGeometry);
          }
      }
  }
  
  #include <Source/Widgets/moc_GraphCanvasComboBox.cpp>
  