Merge bitcoin/bitcoin#34276: Remove empty caption from user interface (noui, gui)

fad7bd9ba3eef03fcdd7cb17011ea0c6e483c767 noui: Remove always empty caption while formatting (MarcoFalke)
fa8ebeb332325604e8ca6080262543e10de4e46c refactor: [gui] Document that the title is always empty for node message (MarcoFalke)
fafe71b743a0637d16812d26430d99464cab0cee refactor: Remove empty caption from ThreadSafeMessageBox (MarcoFalke)
fa8d0088e76d4def59dff92bfb2ebbfc6cd4c195 refactor: Remove empty caption from ThreadSafeQuestion (MarcoFalke)
fa0195499ca611b513d9d1986d79c5e3a58cd0f2 refactor: [gui] Use lambdas over std::bind (MarcoFalke)
eeee1e341fa59b5b0b05f974105104fb2a0df9c3 refactor: Remove trailing semicolon after ADD_SIGNALS_DECL_WRAPPER (MarcoFalke)

Pull request description:

  Currently, the user interface (noui, gui) has a caption for each message. However, the caption has many issues:

  * It is always hard-coded to the empty string.
  * This is confusing and tedious when reading or maintaining the code.
  * It is redundant, because `noui` will ignore the caption and set the logging prefix (error, warning, info) based on the `style`.
  * The gui does prefer to set the title based on the caption, but since it the caption is always empty, the fallback will always be used.

  Fix all issues by removing it.

ACKs for top commit:
  hebasto:
    ACK fad7bd9ba3eef03fcdd7cb17011ea0c6e483c767, I have reviewed the code and it looks OK. Tested on Ubuntu 25.10.
  sedited:
    ACK fad7bd9ba3eef03fcdd7cb17011ea0c6e483c767

Tree-SHA512: 58ef538b9b3e1cfdcf2955f6de9b8cee335edbf6339723cb693cb4d584817904c962dac5199ee44d7e2860a5332dec1a6abf47e621eb5cf919aa1cdae271b55f
This commit is contained in:
merge-script 2026-01-28 13:43:56 +01:00
commit 6ae96ed607
No known key found for this signature in database
GPG Key ID: 9B79B45691DB4173
12 changed files with 38 additions and 35 deletions

View File

@ -230,7 +230,7 @@ static bool InitHTTPAllowList()
if (!subnet.IsValid()) {
uiInterface.ThreadSafeMessageBox(
Untranslated(strprintf("Invalid -rpcallowip subnet specification: %s. Valid values are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all ipv4 (0.0.0.0/0), or all ipv6 (::/0). RFC4193 is allowed only if -cjdnsreachable=0.", strAllow)),
"", CClientUIInterface::MSG_ERROR);
CClientUIInterface::MSG_ERROR);
return false;
}
rpc_allow_subnets.push_back(subnet);

View File

@ -1377,7 +1377,7 @@ static ChainstateLoadResult InitAndLoadChainstate(
options.coins_error_cb = [] {
uiInterface.ThreadSafeMessageBox(
_("Error reading from database, shutting down."),
"", CClientUIInterface::MSG_ERROR);
CClientUIInterface::MSG_ERROR);
};
uiInterface.InitMessage(_("Loading block index…"));
auto catch_exceptions = [](auto&& f) -> ChainstateLoadResult {
@ -1819,7 +1819,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
uiInterface.ThreadSafeQuestion(
error + Untranslated(".\n\n") + _("Do you want to rebuild the databases now?"),
error.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT)};
CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT)};
if (!do_retry) {
return false;
}

View File

@ -219,13 +219,12 @@ public:
//! Register handler for message box messages.
using MessageBoxFn =
std::function<bool(const bilingual_str& message, const std::string& caption, unsigned int style)>;
std::function<bool(const bilingual_str& message, unsigned int style)>;
virtual std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) = 0;
//! Register handler for question messages.
using QuestionFn = std::function<bool(const bilingual_str& message,
const std::string& non_interactive_message,
const std::string& caption,
unsigned int style)>;
virtual std::unique_ptr<Handler> handleQuestion(QuestionFn fn) = 0;

View File

@ -3409,7 +3409,7 @@ bool CConnman::Bind(const CService& addr_, unsigned int flags, NetPermissionFlag
bilingual_str strError;
if (!BindListenPort(addr, strError, permissions)) {
if ((flags & BF_REPORT_ERROR) && m_client_interface) {
m_client_interface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR);
m_client_interface->ThreadSafeMessageBox(strError, CClientUIInterface::MSG_ERROR);
}
return false;
}
@ -3464,7 +3464,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
if (m_client_interface) {
m_client_interface->ThreadSafeMessageBox(
_("Failed to listen on any port. Use -listen=0 if you want this."),
"", CClientUIInterface::MSG_ERROR);
CClientUIInterface::MSG_ERROR);
}
return false;
}
@ -3532,7 +3532,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
if (m_client_interface) {
m_client_interface->ThreadSafeMessageBox(
_("Cannot provide specific connections and have addrman find outgoing connections at the same time."),
"", CClientUIInterface::MSG_ERROR);
CClientUIInterface::MSG_ERROR);
}
return false;
}

View File

@ -47,8 +47,8 @@ ADD_SIGNALS_IMPL_WRAPPER(NotifyBlockTip);
ADD_SIGNALS_IMPL_WRAPPER(NotifyHeaderTip);
ADD_SIGNALS_IMPL_WRAPPER(BannedListChanged);
bool CClientUIInterface::ThreadSafeMessageBox(const bilingual_str& message, const std::string& caption, unsigned int style) { return g_ui_signals.ThreadSafeMessageBox(message, caption, style).value_or(false);}
bool CClientUIInterface::ThreadSafeQuestion(const bilingual_str& message, const std::string& non_interactive_message, const std::string& caption, unsigned int style) { return g_ui_signals.ThreadSafeQuestion(message, non_interactive_message, caption, style).value_or(false);}
bool CClientUIInterface::ThreadSafeMessageBox(const bilingual_str& message, unsigned int style) { return g_ui_signals.ThreadSafeMessageBox(message, style).value_or(false);}
bool CClientUIInterface::ThreadSafeQuestion(const bilingual_str& message, const std::string& non_interactive_message, unsigned int style) { return g_ui_signals.ThreadSafeQuestion(message, non_interactive_message, style).value_or(false);}
void CClientUIInterface::InitMessage(const std::string& message) { return g_ui_signals.InitMessage(message); }
void CClientUIInterface::InitWallet() { return g_ui_signals.InitWallet(); }
void CClientUIInterface::NotifyNumConnectionsChanged(int newNumConnections) { return g_ui_signals.NotifyNumConnectionsChanged(newNumConnections); }
@ -61,7 +61,7 @@ void CClientUIInterface::BannedListChanged() { return g_ui_signals.BannedListCha
bool InitError(const bilingual_str& str)
{
uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR);
uiInterface.ThreadSafeMessageBox(str, CClientUIInterface::MSG_ERROR);
return false;
}
@ -79,5 +79,5 @@ bool InitError(const bilingual_str& str, const std::vector<std::string>& details
void InitWarning(const bilingual_str& str)
{
uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING);
uiInterface.ThreadSafeMessageBox(str, CClientUIInterface::MSG_WARNING);
}

View File

@ -71,13 +71,13 @@ public:
#define ADD_SIGNALS_DECL_WRAPPER(signal_name, rtype, ...) \
rtype signal_name(__VA_ARGS__); \
using signal_name##Sig = rtype(__VA_ARGS__); \
boost::signals2::connection signal_name##_connect(std::function<signal_name##Sig> fn);
boost::signals2::connection signal_name##_connect(std::function<signal_name##Sig> fn)
/** Show message box. */
ADD_SIGNALS_DECL_WRAPPER(ThreadSafeMessageBox, bool, const bilingual_str& message, const std::string& caption, unsigned int style);
ADD_SIGNALS_DECL_WRAPPER(ThreadSafeMessageBox, bool, const bilingual_str& message, unsigned int style);
/** If possible, ask the user a question. If not, falls back to ThreadSafeMessageBox(noninteractive_message, caption, style) and returns false. */
ADD_SIGNALS_DECL_WRAPPER(ThreadSafeQuestion, bool, const bilingual_str& message, const std::string& noninteractive_message, const std::string& caption, unsigned int style);
/** If possible, ask the user a question. If not, falls back to ThreadSafeMessageBox(noninteractive_message, style) and returns false. */
ADD_SIGNALS_DECL_WRAPPER(ThreadSafeQuestion, bool, const bilingual_str& message, const std::string& noninteractive_message, unsigned int style);
/** Progress message during initialization. */
ADD_SIGNALS_DECL_WRAPPER(InitMessage, void, const std::string& message);

View File

@ -19,7 +19,7 @@ boost::signals2::connection noui_ThreadSafeMessageBoxConn;
boost::signals2::connection noui_ThreadSafeQuestionConn;
boost::signals2::connection noui_InitMessageConn;
bool noui_ThreadSafeMessageBox(const bilingual_str& message, const std::string& caption, unsigned int style)
bool noui_ThreadSafeMessageBox(const bilingual_str& message, unsigned int style)
{
bool fSecure = style & CClientUIInterface::SECURE;
style &= ~CClientUIInterface::SECURE;
@ -39,7 +39,6 @@ bool noui_ThreadSafeMessageBox(const bilingual_str& message, const std::string&
if (!fSecure) LogInfo("%s\n", message.original);
break;
default:
strCaption = caption + ": "; // Use supplied caption (can be empty)
if (!fSecure) LogInfo("%s%s\n", strCaption, message.original);
}
@ -47,9 +46,9 @@ bool noui_ThreadSafeMessageBox(const bilingual_str& message, const std::string&
return false;
}
bool noui_ThreadSafeQuestion(const bilingual_str& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)
bool noui_ThreadSafeQuestion(const bilingual_str& /* ignored interactive message */, const std::string& message, unsigned int style)
{
return noui_ThreadSafeMessageBox(Untranslated(message), caption, style);
return noui_ThreadSafeMessageBox(Untranslated(message), style);
}
void noui_InitMessage(const std::string& message)
@ -64,15 +63,15 @@ void noui_connect()
noui_InitMessageConn = uiInterface.InitMessage_connect(noui_InitMessage);
}
bool noui_ThreadSafeMessageBoxRedirect(const bilingual_str& message, const std::string& caption, unsigned int style)
bool noui_ThreadSafeMessageBoxRedirect(const bilingual_str& message, unsigned int style)
{
LogInfo("%s: %s", caption, message.original);
LogInfo("%s", message.original);
return false;
}
bool noui_ThreadSafeQuestionRedirect(const bilingual_str& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)
bool noui_ThreadSafeQuestionRedirect(const bilingual_str& /* ignored interactive message */, const std::string& message, unsigned int style)
{
LogInfo("%s: %s", caption, message);
LogInfo("%s", message);
return false;
}

View File

@ -10,9 +10,9 @@
struct bilingual_str;
/** Non-GUI handler, which logs and prints messages. */
bool noui_ThreadSafeMessageBox(const bilingual_str& message, const std::string& caption, unsigned int style);
bool noui_ThreadSafeMessageBox(const bilingual_str& message, unsigned int style);
/** Non-GUI handler, which logs and prints questions. */
bool noui_ThreadSafeQuestion(const bilingual_str& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style);
bool noui_ThreadSafeQuestion(const bilingual_str& /* ignored interactive message */, const std::string& message, unsigned int style);
/** Non-GUI handler, which only logs a message. */
void noui_InitMessage(const std::string& message);

View File

@ -41,8 +41,6 @@
#include <util/translation.h>
#include <validation.h>
#include <functional>
#include <QAction>
#include <QActionGroup>
#include <QApplication>
@ -1593,7 +1591,7 @@ void BitcoinGUI::showModalOverlay()
modalOverlay->toggleVisibility();
}
static bool ThreadSafeMessageBox(BitcoinGUI* gui, const bilingual_str& message, const std::string& caption, unsigned int style)
static bool ThreadSafeMessageBox(BitcoinGUI* gui, const bilingual_str& message, unsigned int style)
{
bool modal = (style & CClientUIInterface::MODAL);
// The SECURE flag has no effect in the Qt GUI.
@ -1605,11 +1603,14 @@ static bool ThreadSafeMessageBox(BitcoinGUI* gui, const bilingual_str& message,
if (message.original != message.translated) {
detailed_message = BitcoinGUI::tr("Original message:") + "\n" + QString::fromStdString(message.original);
}
// The title is empty for node messages. The fallback title is usually set
// by `style`.
const QString title{};
// In case of modal message, use blocking connection to wait for user to click a button
bool invoked = QMetaObject::invokeMethod(gui, "message",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, title),
Q_ARG(QString, QString::fromStdString(message.translated)),
Q_ARG(unsigned int, style),
Q_ARG(bool*, &ret),
@ -1621,8 +1622,12 @@ static bool ThreadSafeMessageBox(BitcoinGUI* gui, const bilingual_str& message,
void BitcoinGUI::subscribeToCoreSignals()
{
// Connect signals to client
m_handler_message_box = m_node.handleMessageBox(std::bind(ThreadSafeMessageBox, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
m_handler_question = m_node.handleQuestion(std::bind(ThreadSafeMessageBox, this, std::placeholders::_1, std::placeholders::_3, std::placeholders::_4));
m_handler_message_box = m_node.handleMessageBox([this](const bilingual_str& message, unsigned int style) {
return ThreadSafeMessageBox(this, message, style);
});
m_handler_question = m_node.handleQuestion([this](const bilingual_str& message, const std::string& /*non_interactive_message*/, unsigned int style) {
return ThreadSafeMessageBox(this, message, style);
});
}
void BitcoinGUI::unsubscribeFromCoreSignals()

View File

@ -38,7 +38,7 @@ class SegwitUpgradeTest(BitcoinTestFramework):
# because the blockchain consists of 3 insufficiently validated blocks per segwit consensus rules.
node.assert_start_raises_init_error(
extra_args=["-testactivationheight=segwit@5"],
expected_msg=": Witness data for blocks after height 5 requires "
expected_msg="Witness data for blocks after height 5 requires "
f"validation. Please restart with -reindex..{os.linesep}"
"Please restart with -reindex or -reindex-chainstate to recover.",
)

View File

@ -21,7 +21,7 @@ class ReindexInitTest(BitcoinTestFramework):
self.log.info("Removing the block index leads to init error")
shutil.rmtree(node.blocks_path / "index")
node.assert_start_raises_init_error(
expected_msg=f": Error initializing block database.{os.linesep}"
expected_msg=f"Error initializing block database.{os.linesep}"
"Please restart with -reindex or -reindex-chainstate to recover.",
)

View File

@ -124,7 +124,7 @@ class BlockchainTest(BitcoinTestFramework):
self.log.info("A block tip of more than MAX_FUTURE_BLOCK_TIME in the future raises an error")
self.nodes[0].assert_start_raises_init_error(
extra_args=[f"-mocktime={TIME_RANGE_TIP - MAX_FUTURE_BLOCK_TIME - 1}"],
expected_msg=": The block database contains a block which appears to be from the future."
expected_msg="The block database contains a block which appears to be from the future."
" This may be due to your computer's date and time being set incorrectly."
f" Only rebuild the block database if you are sure that your computer's date and time are correct.{os.linesep}"
"Please restart with -reindex or -reindex-chainstate to recover.",