diff --git a/doc/release-notes-154.md b/doc/release-notes-154.md new file mode 100644 index 0000000000000..a31e82433b94b --- /dev/null +++ b/doc/release-notes-154.md @@ -0,0 +1,4 @@ +Compatibility +============== + +Dash Core change appearance when macOS "dark mode" is activated. diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index bc6b302b2d356..fbdfbd983d20a 100644 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -56,9 +56,6 @@ NSHighResolutionCapable True - NSRequiresAquaSystemAppearance - True - NSHumanReadableCopyright Copyright © 2009-@COPYRIGHT_YEAR@ The Bitcoin Core developers, 2014-@COPYRIGHT_YEAR@ @COPYRIGHT_HOLDERS_FINAL@ LSApplicationCategoryType diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 8ca112d131d98..885a0e5334006 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -87,6 +87,7 @@ QT_MOC_CPP = \ qt/moc_transactiondesc.cpp \ qt/moc_transactiondescdialog.cpp \ qt/moc_transactionfilterproxy.cpp \ + qt/moc_transactionoverviewwidget.cpp \ qt/moc_transactiontablemodel.cpp \ qt/moc_transactionview.cpp \ qt/moc_utilitydialog.cpp \ @@ -164,6 +165,7 @@ BITCOIN_QT_H = \ qt/transactiondesc.h \ qt/transactiondescdialog.h \ qt/transactionfilterproxy.h \ + qt/transactionoverviewwidget.h \ qt/transactionrecord.h \ qt/transactiontablemodel.h \ qt/transactionview.h \ diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index 4410467029c4b..062be8e6b537e 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -37,7 +37,23 @@ - + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 10 + 20 + + + + @@ -560,6 +576,19 @@ + + + + Qt::Horizontal + + + + 10 + 20 + + + + @@ -609,7 +638,7 @@ - + QFrame::NoFrame @@ -619,9 +648,15 @@ Qt::ScrollBarAlwaysOff + + QAbstractScrollArea::AdjustToContents + QAbstractItemView::NoSelection + + true + @@ -629,10 +664,33 @@ + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 10 + 20 + + + + + + + TransactionOverviewWidget + QListView +
qt/transactionoverviewwidget.h
+
+
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index c46434983314a..983ae83752c19 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1785,14 +1785,14 @@ QString formatNiceTimeOffset(qint64 secs) QString formatBytes(uint64_t bytes) { - if(bytes < 1024) + if (bytes < 1'000) return QObject::tr("%1 B").arg(bytes); - if(bytes < 1024 * 1024) - return QObject::tr("%1 KB").arg(bytes / 1024); - if(bytes < 1024 * 1024 * 1024) - return QObject::tr("%1 MB").arg(bytes / 1024 / 1024); + if (bytes < 1'000'000) + return QObject::tr("%1 kB").arg(bytes / 1'000); + if (bytes < 1'000'000'000) + return QObject::tr("%1 MB").arg(bytes / 1'000'000); - return QObject::tr("%1 GB").arg(bytes / 1024 / 1024 / 1024); + return QObject::tr("%1 GB").arg(bytes / 1'000'000'000); } qreal calculateIdealFontSize(int width, const QString& text, QFont font, qreal minPointSize, qreal font_size) { diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index c530787b32241..16c2a5dfae145 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,8 @@ #include #include +#include +#include #include #include @@ -42,7 +45,7 @@ class TxViewDelegate : public QAbstractItemDelegate explicit TxViewDelegate(QObject* parent = nullptr) : QAbstractItemDelegate(), unit(BitcoinUnits::DASH) { - + connect(this, &TxViewDelegate::width_changed, this, &TxViewDelegate::sizeHintChanged); } inline void paint(QPainter *painter, const QStyleOptionViewItem &option, @@ -83,7 +86,8 @@ class TxViewDelegate : public QAbstractItemDelegate qint64 nAmount = index.data(TransactionTableModel::AmountRole).toLongLong(); QString strAmount = BitcoinUnits::floorWithUnit(unit, nAmount, true, BitcoinUnits::SeparatorStyle::ALWAYS); painter->setPen(colorForeground); - painter->drawText(rectTopHalf, Qt::AlignRight | Qt::AlignVCenter, strAmount); + QRect amount_bounding_rect; + painter->drawText(rectTopHalf, Qt::AlignRight | Qt::AlignVCenter, strAmount, &amount_bounding_rect); // Draw second line (with the initial font) // Content: Address/label, Optional Watchonly indicator @@ -93,6 +97,7 @@ class TxViewDelegate : public QAbstractItemDelegate QString address = indexAddress.data(Qt::DisplayRole).toString(); painter->setPen(colorForeground); painter->drawText(rectBottomHalf, Qt::AlignLeft | Qt::AlignVCenter, address, &rectBounding); + int address_rect_min_width = rectBounding.width(); // Optional Watchonly indicator if (index.data(TransactionTableModel::WatchonlyRole).toBool()) { @@ -101,17 +106,32 @@ class TxViewDelegate : public QAbstractItemDelegate iconWatchonly.paint(painter, rectWatchonly); } + const int minimum_width = std::max(address_rect_min_width, amount_bounding_rect.width() /*+ date_bounding_rect.width() */); + const auto search = m_minimum_width.find(index.row()); + if (search == m_minimum_width.end() || search->second != minimum_width) { + m_minimum_width[index.row()] = minimum_width; + Q_EMIT width_changed(index); + } painter->restore(); } inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override { - return QSize(ITEM_HEIGHT, ITEM_HEIGHT); + const auto search = m_minimum_width.find(index.row()); + const int minimum_text_width = search == m_minimum_width.end() ? 0 : search->second; + return {ITEM_HEIGHT + 8 + minimum_text_width, ITEM_HEIGHT}; } int unit; +Q_SIGNALS: + //! An intermediate signal for emitting from the `paint() const` member function. + void width_changed(const QModelIndex& index) const; + +private: + mutable std::map m_minimum_width; }; + #include OverviewPage::OverviewPage(QWidget* parent) : @@ -151,7 +171,7 @@ OverviewPage::OverviewPage(QWidget* parent) : // Note: minimum height of listTransactions will be set later in updateAdvancedCJUI() to reflect actual settings ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false); - connect(ui->listTransactions, &QListView::clicked, this, &OverviewPage::handleTransactionClicked); + connect(ui->listTransactions, &TransactionOverviewWidget::clicked, this, &OverviewPage::handleTransactionClicked); // init "out of sync" warning labels ui->labelWalletStatus->setText("(" + tr("out of sync") + ")"); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 75317a98bbc91..de76e1625b158 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -239,8 +239,8 @@ void PaymentServer::handleURIOrFile(const QString& s) if (!IsValidDestination(dest)) { if (uri.hasQueryItem("r")) { // payment request Q_EMIT message(tr("URI handling"), - tr("Cannot process payment request as BIP70 is no longer supported.")+ - tr("Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70."), + tr("Cannot process payment request as BIP70 is no longer supported.\n" + "Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70."), CClientUIInterface::ICON_WARNING); } else { Q_EMIT message(tr("URI handling"), QString::fromStdString(error_msg), @@ -262,8 +262,8 @@ void PaymentServer::handleURIOrFile(const QString& s) if (QFile::exists(s)) // payment request file { Q_EMIT message(tr("Payment request file handling"), - tr("Cannot process payment request as BIP70 is no longer supported.")+ - tr("Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70."), + tr("Cannot process payment request as BIP70 is no longer supported.\n" + "Due to discontinued support, you should request the merchant to provide you with a BIP21 compatible URI or use a wallet that does continue to support BIP70."), CClientUIInterface::ICON_WARNING); } } diff --git a/src/qt/res/css/general.css b/src/qt/res/css/general.css index 59f4c3a4ab986..af65262129052 100644 --- a/src/qt/res/css/general.css +++ b/src/qt/res/css/general.css @@ -1544,7 +1544,6 @@ QWidget .QFrame#frame_2 .QLabel#labelTransactionsStatus { /* Recent Transactions QWidget .QFrame#frame_2 QListView { /* Transaction List */ background: #00000000; - max-width: 430px; margin-right: 10px; } diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index e763bb13ada44..ecd53638ed6b4 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -531,9 +531,9 @@ RPCConsole::RPCConsole(interfaces::Node& node, QWidget* parent, Qt::WindowFlags const QString list{"
  • " + Join(CONNECTION_TYPE_DOC, QString("
  • ")) + "
"}; ui->peerConnectionTypeLabel->setToolTip(ui->peerConnectionTypeLabel->toolTip().arg(list)); const QString hb_list{"
  • \"" - + tr("To") + "\" – " + tr("we selected the peer for high bandwidth relay") + "
  • \"" - + tr("From") + "\" – " + tr("the peer selected us for high bandwidth relay") + "
  • \"" - + tr("No") + "\" – " + tr("no high bandwidth relay selected") + "
"}; + + ts.to + "\" – " + tr("we selected the peer for high bandwidth relay") + "
  • \"" + + ts.from + "\" – " + tr("the peer selected us for high bandwidth relay") + "
  • \"" + + ts.no + "\" – " + tr("no high bandwidth relay selected") + "
  • "}; ui->peerHighBandwidthLabel->setToolTip(ui->peerHighBandwidthLabel->toolTip().arg(hb_list)); ui->dataDir->setToolTip(ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir")); ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(QString(nonbreaking_hyphen) + "blocksdir")); @@ -707,10 +707,10 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ // create peer table context menu actions QAction* disconnectAction = new QAction(tr("&Disconnect"), this); - QAction* banAction1h = new QAction(tr("Ban for") + " " + tr("1 &hour"), this); - QAction* banAction24h = new QAction(tr("Ban for") + " " + tr("1 &day"), this); - QAction* banAction7d = new QAction(tr("Ban for") + " " + tr("1 &week"), this); - QAction* banAction365d = new QAction(tr("Ban for") + " " + tr("1 &year"), this); + QAction* banAction1h = new QAction(ts.ban_for + " " + tr("1 &hour"), this); + QAction* banAction24h = new QAction(ts.ban_for + " " + tr("1 &day"), this); + QAction* banAction7d = new QAction(ts.ban_for + " " + tr("1 &week"), this); + QAction* banAction365d = new QAction(ts.ban_for + " " + tr("1 &year"), this); // create peer table context menu peersTableContextMenu = new QMenu(this); @@ -1301,9 +1301,9 @@ void RPCConsole::updateDetailWidget() ui->peerLastBlock->setText(TimeDurationField(time_now, stats->nodeStats.m_last_block_time)); ui->peerLastTx->setText(TimeDurationField(time_now, stats->nodeStats.m_last_tx_time)); QString bip152_hb_settings; - if (stats->nodeStats.m_bip152_highbandwidth_to) bip152_hb_settings += "To"; - if (stats->nodeStats.m_bip152_highbandwidth_from) bip152_hb_settings += (bip152_hb_settings == "" ? "From" : "/From"); - if (bip152_hb_settings == "") bip152_hb_settings = "No"; + if (stats->nodeStats.m_bip152_highbandwidth_to) bip152_hb_settings = ts.to; + if (stats->nodeStats.m_bip152_highbandwidth_from) bip152_hb_settings += (bip152_hb_settings.isEmpty() ? ts.from : QLatin1Char('/') + ts.from); + if (bip152_hb_settings.isEmpty()) bip152_hb_settings = ts.no; ui->peerHighBandwidth->setText(bip152_hb_settings); ui->peerLastSend->setText(TimeDurationField(time_now, stats->nodeStats.m_last_send)); ui->peerLastRecv->setText(TimeDurationField(time_now, stats->nodeStats.m_last_recv)); @@ -1317,7 +1317,7 @@ void RPCConsole::updateDetailWidget() ui->peerConnectionType->setText(GUIUtil::ConnectionTypeToQString(stats->nodeStats.m_conn_type, /* prepend_direction */ true)); ui->peerNetwork->setText(GUIUtil::NetworkToQString(stats->nodeStats.m_network)); if (stats->nodeStats.m_permissionFlags == NetPermissionFlags::None) { - ui->peerPermissions->setText(tr("N/A")); + ui->peerPermissions->setText(ts.na); } else { QStringList permissions; for (const auto& permission : NetPermissions::ToStrings(stats->nodeStats.m_permissionFlags)) { @@ -1325,11 +1325,11 @@ void RPCConsole::updateDetailWidget() } ui->peerPermissions->setText(permissions.join(" & ")); } - ui->peerMappedAS->setText(stats->nodeStats.m_mapped_as != 0 ? QString::number(stats->nodeStats.m_mapped_as) : tr("N/A")); + ui->peerMappedAS->setText(stats->nodeStats.m_mapped_as != 0 ? QString::number(stats->nodeStats.m_mapped_as) : ts.na); auto dmn = clientModel->getMasternodeList().first.GetMNByService(stats->nodeStats.addr); if (dmn == nullptr) { ui->peerNodeType->setText(tr("Regular")); - ui->peerPoSeScore->setText(tr("N/A")); + ui->peerPoSeScore->setText(ts.na); } else { if (stats->nodeStats.verifiedProRegTxHash.IsNull()) { ui->peerNodeType->setText(tr("Masternode")); @@ -1343,23 +1343,23 @@ void RPCConsole::updateDetailWidget() // nodeStateStats couldn't be fetched. if (stats->fNodeStateStatsAvailable) { // Sync height is init to -1 - if (stats->nodeStateStats.nSyncHeight > -1) + if (stats->nodeStateStats.nSyncHeight > -1) { ui->peerSyncHeight->setText(QString("%1").arg(stats->nodeStateStats.nSyncHeight)); - else - ui->peerSyncHeight->setText(tr("Unknown")); - + } else { + ui->peerSyncHeight->setText(ts.unknown); + } // Common height is init to -1 - if (stats->nodeStateStats.nCommonHeight > -1) + if (stats->nodeStateStats.nCommonHeight > -1) { ui->peerCommonHeight->setText(QString("%1").arg(stats->nodeStateStats.nCommonHeight)); - else - ui->peerCommonHeight->setText(tr("Unknown")); - + } else { + ui->peerCommonHeight->setText(ts.unknown); + } ui->peerHeight->setText(QString::number(stats->nodeStateStats.m_starting_height)); ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStateStats.m_ping_wait)); - ui->peerAddrRelayEnabled->setText(stats->nodeStateStats.m_addr_relay_enabled ? "Yes" : "No"); + ui->peerAddrRelayEnabled->setText(stats->nodeStateStats.m_addr_relay_enabled ? ts.yes : ts.no); ui->peerAddrProcessed->setText(QString::number(stats->nodeStateStats.m_addr_processed)); ui->peerAddrRateLimited->setText(QString::number(stats->nodeStateStats.m_addr_rate_limited)); - ui->peerRelayTxes->setText(stats->nodeStateStats.m_relay_txs ? "Yes" : "No"); + ui->peerRelayTxes->setText(stats->nodeStateStats.m_relay_txs ? ts.yes : ts.no); } ui->peersTabRightPanel->show(); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 5549d30b70af2..2834311ca5666 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -154,6 +154,11 @@ public Q_SLOTS: void handleRestart(QStringList args); private: + struct TranslatedStrings { + const QString yes{tr("Yes")}, no{tr("No")}, to{tr("To")}, from{tr("From")}, + ban_for{tr("Ban for")}, na{tr("N/A")}, unknown{tr("Unknown")}; + } const ts; + void startExecutor(); void setTrafficGraphRange(TrafficGraphData::GraphRange range); /** Build parameter list for restart */ diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index 5f19928456722..f33d7845358ee 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -98,7 +98,7 @@ void TrafficGraphWidget::paintEvent(QPaintEvent *) float val = pow(10.0f, base); float val2 = val; - const QString units = tr("KB/s"); + const QString units = tr("kB/s"); const float yMarginText = 2.0; // draw lines diff --git a/src/qt/transactionoverviewwidget.h b/src/qt/transactionoverviewwidget.h new file mode 100644 index 0000000000000..2bdead7bc40e9 --- /dev/null +++ b/src/qt/transactionoverviewwidget.h @@ -0,0 +1,41 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H +#define BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QShowEvent; +class QWidget; +QT_END_NAMESPACE + +class TransactionOverviewWidget : public QListView +{ + Q_OBJECT + +public: + explicit TransactionOverviewWidget(QWidget* parent = nullptr) : QListView(parent) {} + + QSize sizeHint() const override + { + return {sizeHintForColumn(TransactionTableModel::ToAddress), QListView::sizeHint().height()}; + } + +protected: + void showEvent(QShowEvent* event) override + { + Q_UNUSED(event); + QSizePolicy sp = sizePolicy(); + sp.setHorizontalPolicy(QSizePolicy::Minimum); + setSizePolicy(sp); + } +}; + +#endif // BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 573d91d64fd3a..b51361a64683e 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -126,24 +126,23 @@ TransactionView::TransactionView(QWidget* parent) : vlayout->setContentsMargins(0,0,0,0); vlayout->setSpacing(0); - QTableView *view = new QTableView(this); + transactionView = new QTableView(this); vlayout->addLayout(hlayout); vlayout->addWidget(createDateRangeWidget()); - vlayout->addWidget(view); + vlayout->addWidget(transactionView); vlayout->setSpacing(0); #ifndef Q_OS_MAC - int width = view->verticalScrollBar()->sizeHint().width(); + int width = transactionView->verticalScrollBar()->sizeHint().width(); // Cover scroll bar width with spacing hlayout->addSpacing(width); // Always show scroll bar - view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + transactionView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); #endif - view->setTabKeyNavigation(false); - view->setContextMenuPolicy(Qt::CustomContextMenu); + transactionView->setTabKeyNavigation(false); + transactionView->setContextMenuPolicy(Qt::CustomContextMenu); - view->installEventFilter(this); + transactionView->installEventFilter(this); - transactionView = view; transactionView->setObjectName("transactionView"); // Actions @@ -185,9 +184,9 @@ TransactionView::TransactionView(QWidget* parent) : connect(search_widget, &QLineEdit::textChanged, prefix_typing_delay, static_cast(&QTimer::start)); connect(prefix_typing_delay, &QTimer::timeout, this, &TransactionView::changedSearch); - connect(view, &QTableView::doubleClicked, this, &TransactionView::doubleClicked); - connect(view, &QTableView::clicked, this, &TransactionView::computeSum); - connect(view, &QTableView::customContextMenuRequested, this, &TransactionView::contextualMenu); + connect(transactionView, &QTableView::doubleClicked, this, &TransactionView::doubleClicked); + connect(transactionView, &QTableView::clicked, this, &TransactionView::computeSum); + connect(transactionView, &QTableView::customContextMenuRequested, this, &TransactionView::contextualMenu); connect(abandonAction, &QAction::triggered, this, &TransactionView::abandonTx); connect(resendAction, &QAction::triggered, this, &TransactionView::resendTx); diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 4da9cf9dbbcd7..67d2b112e11a5 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -123,9 +123,24 @@ void WalletFrame::setCurrentWallet(WalletModel* wallet_model) { if (mapWalletViews.count(wallet_model) == 0) return; + // Stop the effect of hidden widgets on the size hint of the shown one in QStackedWidget. + WalletView* view_about_to_hide = currentWalletView(); + if (view_about_to_hide) { + QSizePolicy sp = view_about_to_hide->sizePolicy(); + sp.setHorizontalPolicy(QSizePolicy::Ignored); + view_about_to_hide->setSizePolicy(sp); + } + WalletView *walletView = mapWalletViews.value(wallet_model); - walletStack->setCurrentWidget(walletView); assert(walletView); + + // Set or restore the default QSizePolicy which could be set to QSizePolicy::Ignored previously. + QSizePolicy sp = walletView->sizePolicy(); + sp.setHorizontalPolicy(QSizePolicy::Preferred); + walletView->setSizePolicy(sp); + walletView->updateGeometry(); + + walletStack->setCurrentWidget(walletView); walletView->updateEncryptionStatus(); }