text: #include "masternodelist.h"
  #include "ui_masternodelist.h"
  
  #include "activemasternode.h"
  #include "clientmodel.h"
  #include "guiutil.h"
  #include "init.h"
  #include "masternode-sync.h"
  #include "masternodeconfig.h"
  #include "masternodeman.h"
  #include "sync.h"
  #include "wallet/wallet.h"
  #include "walletmodel.h"
  #include "askpassphrasedialog.h"
  
  #include <QMessageBox>
  #include <QErrorMessage>
  #include <QTimer>
  
  RecursiveMutex cs_masternodes;
  
  MasternodeList::MasternodeList(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint),
                                                    ui(new Ui::MasternodeList),
                                                    clientModel(0),
                                                    // m_SizeGrip(this),
                                                    walletModel(0)
  {
      ui->setupUi(this);
  
      ui->startButton->setEnabled(false);
  
      int columnAliasWidth = 100;
      int columnAddressWidth = 200;
      int columnStatusWidth = 80;
      int columnActiveWidth = 130;
      int columnLastSeenWidth = 130;
  
      ui->tableWidgetMyMasternodes->setColumnWidth(0, columnAliasWidth);
      ui->tableWidgetMyMasternodes->setColumnWidth(1, columnAddressWidth);
      ui->tableWidgetMyMasternodes->setColumnWidth(3, columnStatusWidth);
      ui->tableWidgetMyMasternodes->setColumnWidth(4, columnActiveWidth);
      ui->tableWidgetMyMasternodes->setColumnWidth(5, columnLastSeenWidth);
  
      ui->tableWidgetMyMasternodes->setContextMenuPolicy(Qt::CustomContextMenu);
  
      QAction* startAliasAction = new QAction(tr("Start alias"), this);
      contextMenu = new QMenu();
      contextMenu->addAction(startAliasAction);
      connect(ui->tableWidgetMyMasternodes, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&)));
      connect(startAliasAction, SIGNAL(triggered()), this, SLOT(on_startButton_clicked()));
  
      timer = new QTimer(this);
      connect(timer, SIGNAL(timeout()), this, SLOT(updateMyNodeList()));
      timer->start(1000);
  
      // Fill MN list
      fFilterUpdated = true;
      nTimeFilterUpdated = GetTime();
  }
  
  MasternodeList::~MasternodeList()
  {
      delete ui;
  }
  
  void MasternodeList::setClientModel(ClientModel* model)
  {
      this->clientModel = model;
  }
  
  void MasternodeList::setWalletModel(WalletModel* model)
  {
      this->walletModel = model;
  }
  
  void MasternodeList::showContextMenu(const QPoint& point)
  {
      QTableWidgetItem* item = ui->tableWidgetMyMasternodes->itemAt(point);
      if (item) contextMenu->exec(QCursor::pos());
  }
  
  void MasternodeList::resizeEvent(QResizeEvent* event)
  {
      QWidget::resizeEvent(event);
  }
  
  void MasternodeList::StartAlias(std::string strAlias)
  {
      LOCK2(cs_main, pwalletMain->cs_wallet);
      {
          std::string strStatusHtml;
          strStatusHtml += "<center>Alias: " + strAlias;
  
          for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
              if (mne.getAlias() == strAlias) {
                  std::string strError;
                  CMasternodeBroadcast mnb;
  
                  bool fSuccess = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb);
  
                  if (fSuccess) {
                      strStatusHtml += "<br>Successfully started masternode.";
                      mnodeman.UpdateMasternodeList(mnb);
                      mnb.Relay();
                  } else {
                      strStatusHtml += "<br>Failed to start masternode.<br>Error: " + strError;
                  }
                  break;
              }
          }
          strStatusHtml += "</center>";
  
          QMessageBox msg;
          msg.setText(strStatusHtml.c_str());
          msg.setStyleSheet(GUIUtil::loadStyleSheet());
          msg.exec();
      }
      updateMyNodeList(true);
  }
  
  void MasternodeList::StartAll(std::string strCommand)
  {
      LOCK2(cs_main, pwalletMain->cs_wallet);
      {
          int nCountSuccessful = 0;
          int nCountFailed = 0;
          std::string strFailedHtml;
  
          for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
              std::string strError;
              CMasternodeBroadcast mnb;
  
              int nIndex;
              if(!mne.castOutputIndex(nIndex))
                  continue;
  
              CTxIn txin = CTxIn(uint256S(mne.getTxHash()), uint32_t(nIndex));
              CMasternode* pmn = mnodeman.Find(txin);
  
              if (strCommand == "start-missing" && pmn) continue;
  
              bool fSuccess = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb);
  
              if (fSuccess) {
                  nCountSuccessful++;
                  mnodeman.UpdateMasternodeList(mnb);
                  mnb.Relay();
              } else {
                  nCountFailed++;
                  strFailedHtml += "\nFailed to start " + mne.getAlias() + ". Error: " + strError;
              }
          }
  
          std::string returnObj;
          returnObj = strprintf("Successfully started %d masternodes, failed to start %d, total %d", nCountSuccessful, nCountFailed, nCountFailed + nCountSuccessful);
          if (nCountFailed > 0) {
              returnObj += strFailedHtml;
          }
  
          QMessageBox msg;
          msg.setText(QString::fromStdString(returnObj));
          msg.setStyleSheet(GUIUtil::loadStyleSheet());
          msg.exec();
      }
      updateMyNodeList(true);
  }
  
  void MasternodeList::updateMyMasternodeInfo(QString strAlias, QString strAddr, CMasternode* pmn)
  {
      LOCK(cs_mnlistupdate);
      bool fOldRowFound = false;
      int nNewRow = 0;
  
      for (int i = 0; i < ui->tableWidgetMyMasternodes->rowCount(); i++) {
          if (ui->tableWidgetMyMasternodes->item(i, 0)->text() == strAlias) {
              fOldRowFound = true;
              nNewRow = i;
              break;
          }
      }
  
      if (nNewRow == 0 && !fOldRowFound) {
          nNewRow = ui->tableWidgetMyMasternodes->rowCount();
          ui->tableWidgetMyMasternodes->insertRow(nNewRow);
      }
  
      QTableWidgetItem* aliasItem = new QTableWidgetItem(strAlias);
      QTableWidgetItem* addrItem = new QTableWidgetItem(pmn ? QString::fromStdString(pmn->addr.ToString()) : strAddr);
      QTableWidgetItem* statusItem = new QTableWidgetItem(QString::fromStdString(pmn ? pmn->GetStatus() : "MISSING"));
      GUIUtil::DHMSTableWidgetItem* activeSecondsItem = new GUIUtil::DHMSTableWidgetItem(pmn ? (pmn->lastPing.sigTime - pmn->sigTime) : 0);
      QTableWidgetItem* lastSeenItem = new QTableWidgetItem(QString::fromStdString(pmn ? DateTimeStrFormat("%Y-%m-%d %H:%M",  pmn->lastPing.sigTime) : ""));
      QTableWidgetItem* pubkeyItem = new QTableWidgetItem(QString::fromStdString(pmn ? pmn->pubKeyCollateralAddress.GetHex() : ""));
  
      ui->tableWidgetMyMasternodes->setItem(nNewRow, 0, aliasItem);
      ui->tableWidgetMyMasternodes->setItem(nNewRow, 1, addrItem);
      ui->tableWidgetMyMasternodes->setItem(nNewRow, 2, statusItem);
      ui->tableWidgetMyMasternodes->setItem(nNewRow, 3, activeSecondsItem);
      ui->tableWidgetMyMasternodes->setItem(nNewRow, 4, lastSeenItem);
      ui->tableWidgetMyMasternodes->setItem(nNewRow, 5, pubkeyItem);
  }
  
  void MasternodeList::updateMyNodeList(bool fForce)
  {
      {
          static int64_t nTimeMyListUpdated = 0;
  
          // automatically update my masternode list only once in MY_MASTERNODELIST_UPDATE_SECONDS seconds,
          // this update still can be triggered manually at any time via button click
          int64_t nSecondsTillUpdate = nTimeMyListUpdated + MY_MASTERNODELIST_UPDATE_SECONDS - GetTime();
  
          if (nSecondsTillUpdate > 0 && !fForce) return;
          nTimeMyListUpdated = GetTime();
  
          ui->tableWidgetMyMasternodes->setSortingEnabled(false);
          for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
              int nIndex;
              if(!mne.castOutputIndex(nIndex))
                  continue;
  
              CTxIn txin = CTxIn(uint256S(mne.getTxHash()), uint32_t(nIndex));
              CMasternode* pmn = mnodeman.Find(txin);
              updateMyMasternodeInfo(QString::fromStdString(mne.getAlias()), QString::fromStdString(mne.getIp()), pmn);
          }
          ui->tableWidgetMyMasternodes->setSortingEnabled(true);
      }
  }
  
  void MasternodeList::on_startButton_clicked()
  {
      // Find selected node alias
      QItemSelectionModel* selectionModel = ui->tableWidgetMyMasternodes->selectionModel();
      QModelIndexList selected = selectionModel->selectedRows();
  
      if (selected.count() == 0) return;
  
      QModelIndex index = selected.at(0);
      int nSelectedRow = index.row();
      std::string strAlias = ui->tableWidgetMyMasternodes->item(nSelectedRow, 0)->text().toStdString();
  
      // Display message box
      QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm masternode start"),
          tr("Are you sure you want to start masternode %1?").arg(QString::fromStdString(strAlias)),
          QMessageBox::Yes | QMessageBox::Cancel,
          QMessageBox::Cancel);
  
      if (retval != QMessageBox::Yes) return;
  
      WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus();
  
      if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForStakingOnly) {
          WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full));
  
          if (!ctx.isValid()) return; // Unlock wallet was cancelled
  
          StartAlias(strAlias);
          return;
      }
  
      StartAlias(strAlias);
  }
  
  void MasternodeList::on_startAllButton_clicked()
  {
      // Display message box
      QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm all masternodes start"),
          tr("Are you sure you want to start ALL masternodes?"),
          QMessageBox::Yes | QMessageBox::Cancel,
          QMessageBox::Cancel);
  
      if (retval != QMessageBox::Yes) return;
  
      WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus();
  
      if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForStakingOnly) {
          WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full));
  
          if (!ctx.isValid()) return; // Unlock wallet was cancelled
  
          StartAll();
          return;
      }
  
      StartAll();
  }
  
  void MasternodeList::on_startMissingButton_clicked()
  {
      if (!masternodeSync.IsMasternodeListSynced()) {
          QMessageBox::critical(this, tr("Command is not available right now"),
              tr("You can't use this command until masternode list is synced"));
          return;
      }
  
      // Display message box
      QMessageBox::StandardButton retval = QMessageBox::question(this,
          tr("Confirm missing masternodes start"),
          tr("Are you sure you want to start MISSING masternodes?"),
          QMessageBox::Yes | QMessageBox::Cancel,
          QMessageBox::Cancel);
  
      if (retval != QMessageBox::Yes) return;
  
      WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus();
  
      if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForStakingOnly) {
          WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full));
  
          if (!ctx.isValid()) return; // Unlock wallet was cancelled
  
          StartAll("start-missing");
          return;
      }
  
      StartAll("start-missing");
  }
  
  void MasternodeList::on_tableWidgetMyMasternodes_itemSelectionChanged()
  {
      if (ui->tableWidgetMyMasternodes->selectedItems().count() > 0) {
          ui->startButton->setEnabled(true);
      }
  }
  
  void MasternodeList::on_UpdateButton_clicked()
  {
      updateMyNodeList(true);
  }
  