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");
96 if (!options()->detailedText().isEmpty()) {
97 qCWarning(lcQpaDialogs,
"Message box contains detailed text");
101 if (Qt::mightBeRichText(options()->text()) ||
102 Qt::mightBeRichText(options()->informativeText())) {
105 qCDebug(lcQpaDialogs,
"Message box contains text in rich text format");
110 m_alert = [NSAlert
new];
111 m_alert.window.title = options()->windowTitle().toNSString();
113 const QString text = toPlainText(options()->text());
114 m_alert.messageText = text.toNSString();
115 m_alert.informativeText = toPlainText(options()->informativeText()).toNSString();
117 switch (options()->standardIcon()) {
118 case QMessageDialogOptions::NoIcon: {
124 QPixmap iconPixmap = options()->iconPixmap();
125 if (!iconPixmap.isNull())
126 m_alert.icon = [NSImage imageFromQImage:iconPixmap.toImage()];
129 case QMessageDialogOptions::Information:
130 case QMessageDialogOptions::Question:
131 [m_alert setAlertStyle:NSAlertStyleInformational];
133 case QMessageDialogOptions::Warning:
134 [m_alert setAlertStyle:NSAlertStyleWarning];
136 case QMessageDialogOptions::Critical:
137 [m_alert setAlertStyle:NSAlertStyleCritical];
141 auto defaultButton = options()->defaultButton();
142 auto escapeButton = options()->escapeButton();
144 const auto addButton = [&](
auto title,
auto tag,
auto role) {
145 title = QPlatformTheme::removeMnemonics(title);
146 NSButton *button = [m_alert addButtonWithTitle:title.toNSString()];
155 qCDebug(lcQpaDialogs).verbosity(0) <<
"Adding button" << title <<
"with" << role;
157 if (!defaultButton && role == AcceptRole)
160 if (tag == defaultButton)
161 button.keyEquivalent = @
"\r";
162 else if ([button.keyEquivalent isEqualToString:@
"\r"])
163 button.keyEquivalent = @
"";
165 if (!escapeButton && role == RejectRole)
169 if (tag == escapeButton && ![button.keyEquivalent isEqualToString:@
"\r"])
170 button.keyEquivalent = @
"\e";
171 else if ([button.keyEquivalent isEqualToString:@
"\e"])
172 button.keyEquivalent = @
"";
174 button.hasDestructiveAction = role == DestructiveRole;
187 Q_ASSERT(tag >= NSAlertFirstButtonReturn);
193 struct Button { QString title;
int identifier; ButtonRole role; };
194 std::vector<Button> buttons;
196 const auto *platformTheme = QGuiApplicationPrivate::platformTheme();
197 if (
auto standardButtons = options()->standardButtons()) {
198 for (
int standardButton = FirstButton; standardButton <= LastButton; standardButton <<= 1) {
199 if (standardButtons & standardButton) {
200 auto title = platformTheme->standardButtonText(standardButton);
202 title, standardButton, buttonRole(StandardButton(standardButton))
207 const auto customButtons = options()->customButtons();
208 for (
auto customButton : customButtons)
209 buttons.push_back({customButton.label, customButton.id, customButton.role});
216 bool seenAccept =
false;
217 for (
auto &button : buttons) {
218 if (button.role == AcceptRole) {
222 button.role = AlternateRole;
226 std::vector<Button> orderedButtons;
227 const int *layoutEntry = buttonLayout(Qt::Horizontal, ButtonLayout::MacLayout);
228 while (*layoutEntry != QPlatformDialogHelper::EOL) {
229 const auto role = ButtonRole(*layoutEntry & ~ButtonRole::Reverse);
230 const bool reverse = *layoutEntry & ButtonRole::Reverse;
232 auto addButton = [&](
const Button &button) {
233 if (button.role == role)
234 orderedButtons.push_back(button);
238 std::for_each(std::crbegin(buttons), std::crend(buttons), addButton);
240 std::for_each(std::cbegin(buttons), std::cend(buttons), addButton);
246 for (
auto button = orderedButtons.crbegin(); button != orderedButtons.crend(); ++button)
247 addButton(button->title, button->identifier, button->role);
252 m_alert.buttons.firstObject.keyEquivalent = @
"\r";
254 if (
auto checkBoxLabel = options()->checkBoxLabel(); !checkBoxLabel.isNull()) {
255 checkBoxLabel = QPlatformTheme::removeMnemonics(checkBoxLabel);
256 m_alert.suppressionButton.title = checkBoxLabel.toNSString();
257 auto state = options()->checkBoxState();
258 m_alert.suppressionButton.allowsMixedState = state == Qt::PartiallyChecked;
259 m_alert.suppressionButton.state = controlStateFor(state);
260 m_alert.showsSuppressionButton = YES;
263 qCDebug(lcQpaDialogs) <<
"Showing" << m_alert;
265 if (windowModality == Qt::WindowModal) {
266 auto *cocoaWindow =
static_cast<
QCocoaWindow*>(parent->handle());
267 [m_alert beginSheetModalForWindow:cocoaWindow->nativeWindow()
268 completionHandler:^(NSModalResponse response) {
269 processResponse(response);
280 QTimer::singleShot(0,
this, [
this]{
281 if (m_alert && !m_alert.window.visible) {
282 qCDebug(lcQpaDialogs) <<
"Running deferred modal" << m_alert;
283 QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
284 processResponse(runModal());