text: // Copyright (c) 2011-2018 The Bitcoin Core developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #if defined(HAVE_CONFIG_H)
  #include <config/bitcoin-config.h>
  #endif
  #include <policy/policy.h>
  #include <qt/overviewpage.h>
  #include <qt/forms/ui_overviewpage.h>
  
  #include <qt/bitcoinunits.h>
  #include <qt/clientmodel.h>
  #include <qt/guiconstants.h>
  #include <qt/guiutil.h>
  #include <qt/optionsmodel.h>
  #include <qt/platformstyle.h>
  #include <qt/transactionfilterproxy.h>
  #include <qt/transactiontablemodel.h>
  #include <qt/walletmodel.h>
  #include <qt/txviewdelegate.h>
  #include <QSettings>
  
  #include <QAbstractItemDelegate>
  #include <QPainter>
  
  Q_DECLARE_METATYPE(interfaces::WalletBalances)
  
  static const auto KEY_SETTINGS_WATCH_ONLY = "includeWatchOnly";
  
  OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
      QWidget(parent),
      ui(new Ui::OverviewPage),
      clientModel(nullptr),
      walletModel(nullptr),
      txdelegate(new TxViewDelegate(platformStyle, this))
  {
      ui->setupUi(this);
  
      m_balances.balance = {{policyAsset, -1}};
  
      // use a SingleColorIcon for the "out of sync warning" icon
      QIcon icon = platformStyle->SingleColorIcon(":/icons/warning");
      icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503)
      ui->labelTransactionsStatus->setIcon(icon);
      ui->labelWalletStatus->setIcon(icon);
  
      // Recent transactions
      ui->listTransactions->setItemDelegate(txdelegate);
      ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
      ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
      ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
  
      connect(ui->listTransactions, &QListView::clicked, this, &OverviewPage::handleTransactionClicked);
  
      // start with displaying the "out of sync" warnings
      showOutOfSyncWarning(true);
      connect(ui->labelWalletStatus, &QPushButton::clicked, this, &OverviewPage::handleOutOfSyncWarningClicks);
      connect(ui->labelTransactionsStatus, &QPushButton::clicked, this, &OverviewPage::handleOutOfSyncWarningClicks);
  
      QSettings settings;
      if (!settings.contains(KEY_SETTINGS_WATCH_ONLY)) {
        settings.setValue(KEY_SETTINGS_WATCH_ONLY, true);
      }
      auto state = settings.value(KEY_SETTINGS_WATCH_ONLY, true).toBool() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked;
      ui->btnShowWatchOnly->setChecked(state);
  }
  
  void OverviewPage::handleTransactionClicked(const QModelIndex &index)
  {
      if(filter)
          Q_EMIT transactionClicked(filter->mapToSource(index));
  }
  
  void OverviewPage::handleOutOfSyncWarningClicks()
  {
      Q_EMIT outOfSyncWarningClicked();
  }
  
  OverviewPage::~OverviewPage()
  {
      delete ui;
  }
  
  void OverviewPage::setBalance(const interfaces::WalletBalances& balances)
  {
      int unit = walletModel->getOptionsModel()->getDisplayUnit();
      m_balances = balances;
      auto extractPolicy = [](const CAmountMap& balance) {
          auto it = balance.find(policyAsset);
          return it == balance.end() ? 0 : it->second;
      };
      if (walletModel->privateKeysDisabled()) {
          ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.watch_only_balance), false, BitcoinUnits::separatorAlways));
          ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.unconfirmed_watch_only_balance), false, BitcoinUnits::separatorAlways));
          ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.immature_watch_only_balance), false, BitcoinUnits::separatorAlways));
          ui->labelTotal->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance), false, BitcoinUnits::separatorAlways));
      } else {
          ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.balance), false, BitcoinUnits::separatorAlways));
          ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.unconfirmed_balance), false, BitcoinUnits::separatorAlways));
          ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.immature_balance), false, BitcoinUnits::separatorAlways));
          ui->labelTotal->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.balance + balances.unconfirmed_balance + balances.immature_balance), false, BitcoinUnits::separatorAlways));
          ui->labelWatchAvailable->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.watch_only_balance), false, BitcoinUnits::separatorAlways));
          ui->labelWatchPending->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.unconfirmed_watch_only_balance), false, BitcoinUnits::separatorAlways));
          ui->labelWatchImmature->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.immature_watch_only_balance), false, BitcoinUnits::separatorAlways));
          ui->labelWatchTotal->setText(BitcoinUnits::formatWithUnit(unit, extractPolicy(balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance), false, BitcoinUnits::separatorAlways));
      }
      // only show immature (newly mined) balance if it's non-zero, so as not to complicate things
      // for the non-mining users
      bool showImmature = extractPolicy(balances.immature_balance) != 0;
      bool showWatchOnlyImmature = extractPolicy(balances.immature_watch_only_balance) != 0;
  
      // for symmetry reasons also show immature label when the watch-only one is shown
      ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature);
      ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature);
      ui->labelWatchImmature->setVisible(!walletModel->privateKeysDisabled() && showWatchOnlyImmature); // show watch-only immature balance
  }
  
  // show/hide watch-only labels
  void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly)
  {
      ui->btnShowWatchOnly->setEnabled(showWatchOnly);
      showWatchOnly = showWatchOnly && ui->btnShowWatchOnly->isChecked();
  
      ui->labelSpendable->setVisible(showWatchOnly);      // show spendable label (only when watch-only is active)
      ui->labelWatchonly->setVisible(showWatchOnly);      // show watch-only label
      ui->lineWatchBalance->setVisible(showWatchOnly);    // show watch-only balance separator line
      ui->labelWatchAvailable->setVisible(showWatchOnly); // show watch-only available balance
      ui->labelWatchPending->setVisible(showWatchOnly);   // show watch-only pending balance
      ui->labelWatchTotal->setVisible(showWatchOnly);     // show watch-only total balance
  
      if (!showWatchOnly)
          ui->labelWatchImmature->hide();
  }
  
  void OverviewPage::setClientModel(ClientModel *model)
  {
      this->clientModel = model;
      if(model)
      {
          // Show warning if this is a prerelease version
          connect(model, &ClientModel::alertsChanged, this, &OverviewPage::updateAlerts);
          updateAlerts(model->getStatusBarWarnings());
      }
  }
  
  void OverviewPage::setWalletModel(WalletModel *model)
  {
      this->walletModel = model;
      if(model && model->getOptionsModel())
      {
          // Set up transaction list
          filter.reset(new TransactionFilterProxy());
          filter->setSourceModel(model->getTransactionTableModel());
          filter->setLimit(NUM_ITEMS);
          filter->setDynamicSortFilter(true);
          filter->setSortRole(Qt::EditRole);
          filter->setShowInactive(false);
          auto watchOnly = ui->btnShowWatchOnly->isChecked() ? TransactionFilterProxy::WatchOnlyFilter_All : TransactionFilterProxy::WatchOnlyFilter_No;
          filter->setWatchOnlyFilter(watchOnly);
          filter->sort(TransactionTableModel::Date, Qt::DescendingOrder);
  
          ui->listTransactions->setModel(filter.get());
          ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
  
          // Keep up to date with wallet
          interfaces::Wallet& wallet = model->wallet();
          interfaces::WalletBalances balances = wallet.getBalances();
          setBalance(balances);
          connect(model, &WalletModel::balanceChanged, this, &OverviewPage::setBalance);
  
          connect(model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &OverviewPage::updateDisplayUnit);
  
          updateWatchOnlyLabels(wallet.haveWatchOnly() && !model->privateKeysDisabled());
          connect(model, &WalletModel::notifyWatchonlyChanged, [this](bool showWatchOnly) {
            updateWatchOnlyLabels(showWatchOnly && !walletModel->privateKeysDisabled());
          });
      }
  
      // update the display unit, to not use the default ("BTC")
      updateDisplayUnit();
  }
  
  void OverviewPage::updateDisplayUnit()
  {
      if(walletModel && walletModel->getOptionsModel())
      {
          if (m_balances.balance[::policyAsset] != -1) {
              setBalance(m_balances);
          }
  
          // Update txdelegate->unit with the current unit
          txdelegate->unit = walletModel->getOptionsModel()->getDisplayUnit();
  
          ui->listTransactions->update();
      }
  }
  
  void OverviewPage::updateAlerts(const QString &warnings)
  {
      this->ui->labelAlerts->setVisible(!warnings.isEmpty());
      this->ui->labelAlerts->setText(warnings);
  }
  
  void OverviewPage::showOutOfSyncWarning(bool fShow)
  {
      ui->labelWalletStatus->setVisible(fShow);
      ui->labelTransactionsStatus->setVisible(fShow);
  }
  
  void OverviewPage::on_btnShowWatchOnly_stateChanged(int arg1)
  {
      if (!this->walletModel) {
          return;
      }
      {
        QSettings settings;
        settings.setValue(KEY_SETTINGS_WATCH_ONLY, ui->btnShowWatchOnly->isChecked());
      }
  
      if(filter) {
        auto watchOnly = ui->btnShowWatchOnly->isChecked() ? TransactionFilterProxy::WatchOnlyFilter_All : TransactionFilterProxy::WatchOnlyFilter_No;
        filter->setWatchOnlyFilter(watchOnly);
      }
  
      interfaces::Wallet& wallet = this->walletModel->wallet();
      updateWatchOnlyLabels(wallet.haveWatchOnly() && !this->walletModel->privateKeysDisabled());
  }
  