72 Q_UNUSED(windowFlags);
74 qCDebug(lcQpaDialogs) <<
"Asked to show" << windowModality <<
"dialog with parent" << parent;
76 if (m_alert.window.visible) {
77 qCDebug(lcQpaDialogs) <<
"Dialog already visible, ignoring request to show";
82 if (windowModality == Qt::NonModal)
86 if (windowModality == Qt::WindowModal && (!parent || !parent->handle())) {
87 qCWarning(lcQpaDialogs,
"Cannot run window modal dialog without parent window");
92 if (windowModality == Qt::WindowModal
93 && QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSTahoe)
101 if (!options()->detailedText().isEmpty()) {
102 qCWarning(lcQpaDialogs,
"Message box contains detailed text");
106 if (Qt::mightBeRichText(options()->text()) ||
107 Qt::mightBeRichText(options()->informativeText())) {
110 qCDebug(lcQpaDialogs,
"Message box contains text in rich text format");
115 m_alert = [NSAlert
new];
116 m_alert.window.title = options()->windowTitle().toNSString();
118 const QString text = toPlainText(options()->text());
119 m_alert.messageText = text.toNSString();
120 m_alert.informativeText = toPlainText(options()->informativeText()).toNSString();
122 switch (options()->standardIcon()) {
123 case QMessageDialogOptions::NoIcon: {
129 QPixmap iconPixmap = options()->iconPixmap();
130 if (!iconPixmap.isNull())
131 m_alert.icon = [NSImage imageFromQImage:iconPixmap.toImage()];
134 case QMessageDialogOptions::Information:
135 case QMessageDialogOptions::Question:
136 [m_alert setAlertStyle:NSAlertStyleInformational];
138 case QMessageDialogOptions::Warning:
139 [m_alert setAlertStyle:NSAlertStyleWarning];
141 case QMessageDialogOptions::Critical:
142 [m_alert setAlertStyle:NSAlertStyleCritical];
146 auto defaultButton = options()->defaultButton();
147 auto escapeButton = options()->escapeButton();
149 const auto addButton = [&](
auto title,
auto tag,
auto role) {
150 title = QPlatformTheme::removeMnemonics(title);
151 NSButton *button = [m_alert addButtonWithTitle:title.toNSString()];
160 qCDebug(lcQpaDialogs).verbosity(0) <<
"Adding button" << title <<
"with" << role;
162 if (!defaultButton && role == AcceptRole)
165 if (tag == defaultButton)
166 button.keyEquivalent = @
"\r";
167 else if ([button.keyEquivalent isEqualToString:@
"\r"])
168 button.keyEquivalent = @
"";
170 if (!escapeButton && role == RejectRole)
174 if (tag == escapeButton && ![button.keyEquivalent isEqualToString:@
"\r"])
175 button.keyEquivalent = @
"\e";
176 else if ([button.keyEquivalent isEqualToString:@
"\e"])
177 button.keyEquivalent = @
"";
179 button.hasDestructiveAction = role == DestructiveRole;
192 Q_ASSERT(tag >= NSAlertFirstButtonReturn);
198 struct Button { QString title;
int identifier; ButtonRole role; };
199 std::vector<Button> buttons;
201 const auto *platformTheme = QGuiApplicationPrivate::platformTheme();
202 if (
auto standardButtons = options()->standardButtons()) {
203 for (
int standardButton = FirstButton; standardButton <= LastButton; standardButton <<= 1) {
204 if (standardButtons & standardButton) {
205 auto title = platformTheme->standardButtonText(standardButton);
207 title, standardButton, buttonRole(StandardButton(standardButton))
212 const auto customButtons = options()->customButtons();
213 for (
auto customButton : customButtons)
214 buttons.push_back({customButton.label, customButton.id, customButton.role});
221 bool seenAccept =
false;
222 for (
auto &button : buttons) {
223 if (button.role == AcceptRole) {
227 button.role = AlternateRole;
231 std::vector<Button> orderedButtons;
232 const int *layoutEntry = buttonLayout(Qt::Horizontal, ButtonLayout::MacLayout);
233 while (*layoutEntry != QPlatformDialogHelper::EOL) {
234 const auto role = ButtonRole(*layoutEntry & ~ButtonRole::Reverse);
235 const bool reverse = *layoutEntry & ButtonRole::Reverse;
237 auto addButton = [&](
const Button &button) {
238 if (button.role == role)
239 orderedButtons.push_back(button);
243 std::for_each(std::crbegin(buttons), std::crend(buttons), addButton);
245 std::for_each(std::cbegin(buttons), std::cend(buttons), addButton);
251 for (
auto button = orderedButtons.crbegin(); button != orderedButtons.crend(); ++button)
252 addButton(button->title, button->identifier, button->role);
257 m_alert.buttons.firstObject.keyEquivalent = @
"\r";
259 if (
auto checkBoxLabel = options()->checkBoxLabel(); !checkBoxLabel.isNull()) {
260 checkBoxLabel = QPlatformTheme::removeMnemonics(checkBoxLabel);
261 m_alert.suppressionButton.title = checkBoxLabel.toNSString();
262 auto state = options()->checkBoxState();
263 m_alert.suppressionButton.allowsMixedState = state == Qt::PartiallyChecked;
264 m_alert.suppressionButton.state = controlStateFor(state);
265 m_alert.showsSuppressionButton = YES;
268 qCDebug(lcQpaDialogs) <<
"Showing" << m_alert;
270 if (windowModality == Qt::WindowModal) {
271 auto *cocoaWindow =
static_cast<
QCocoaWindow*>(parent->handle());
272 [m_alert beginSheetModalForWindow:cocoaWindow->nativeWindow()
273 completionHandler:^(NSModalResponse response) {
274 processResponse(response);
285 QTimer::singleShot(0,
this, [
this]{
286 if (m_alert && !m_alert.window.visible) {
287 qCDebug(lcQpaDialogs) <<
"Running deferred modal" << m_alert;
288 QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
289 processResponse(runModal());