The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

761 lines
23KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. class AlertWindowTextEditor : public TextEditor
  19. {
  20. public:
  21. AlertWindowTextEditor (const String& name, const bool isPasswordBox)
  22. : TextEditor (name, isPasswordBox ? getDefaultPasswordChar() : 0)
  23. {
  24. setSelectAllWhenFocused (true);
  25. }
  26. void returnPressed()
  27. {
  28. // pass these up the component hierarchy to be trigger the buttons
  29. getParentComponent()->keyPressed (KeyPress (KeyPress::returnKey, 0, '\n'));
  30. }
  31. void escapePressed()
  32. {
  33. // pass these up the component hierarchy to be trigger the buttons
  34. getParentComponent()->keyPressed (KeyPress (KeyPress::escapeKey, 0, 0));
  35. }
  36. private:
  37. JUCE_DECLARE_NON_COPYABLE (AlertWindowTextEditor);
  38. static juce_wchar getDefaultPasswordChar() noexcept
  39. {
  40. #if JUCE_LINUX
  41. return 0x2022;
  42. #else
  43. return 0x25cf;
  44. #endif
  45. }
  46. };
  47. //==============================================================================
  48. AlertWindow::AlertWindow (const String& title,
  49. const String& message,
  50. AlertIconType iconType,
  51. Component* associatedComponent_)
  52. : TopLevelWindow (title, true),
  53. alertIconType (iconType),
  54. associatedComponent (associatedComponent_),
  55. escapeKeyCancels (true)
  56. {
  57. if (message.isEmpty())
  58. text = " "; // to force an update if the message is empty
  59. setMessage (message);
  60. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  61. {
  62. Component* const c = Desktop::getInstance().getComponent (i);
  63. if (c != nullptr && c->isAlwaysOnTop() && c->isShowing())
  64. {
  65. setAlwaysOnTop (true);
  66. break;
  67. }
  68. }
  69. if (! JUCEApplication::isStandaloneApp())
  70. setAlwaysOnTop (true); // for a plugin, make it always-on-top because the host windows are often top-level
  71. AlertWindow::lookAndFeelChanged();
  72. constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000);
  73. }
  74. AlertWindow::~AlertWindow()
  75. {
  76. removeAllChildren();
  77. }
  78. void AlertWindow::userTriedToCloseWindow()
  79. {
  80. if (escapeKeyCancels || buttons.size() > 0)
  81. exitModalState (0);
  82. }
  83. //==============================================================================
  84. void AlertWindow::setMessage (const String& message)
  85. {
  86. const String newMessage (message.substring (0, 2048));
  87. if (text != newMessage)
  88. {
  89. text = newMessage;
  90. updateLayout (true);
  91. repaint();
  92. }
  93. }
  94. //==============================================================================
  95. void AlertWindow::buttonClicked (Button* button)
  96. {
  97. if (button->getParentComponent() != nullptr)
  98. button->getParentComponent()->exitModalState (button->getCommandID());
  99. }
  100. //==============================================================================
  101. void AlertWindow::addButton (const String& name,
  102. const int returnValue,
  103. const KeyPress& shortcutKey1,
  104. const KeyPress& shortcutKey2)
  105. {
  106. TextButton* const b = new TextButton (name, String::empty);
  107. buttons.add (b);
  108. b->setWantsKeyboardFocus (true);
  109. b->setMouseClickGrabsKeyboardFocus (false);
  110. b->setCommandToTrigger (0, returnValue, false);
  111. b->addShortcut (shortcutKey1);
  112. b->addShortcut (shortcutKey2);
  113. b->addListener (this);
  114. b->changeWidthToFitText (getLookAndFeel().getAlertWindowButtonHeight());
  115. addAndMakeVisible (b, 0);
  116. updateLayout (false);
  117. }
  118. int AlertWindow::getNumButtons() const
  119. {
  120. return buttons.size();
  121. }
  122. void AlertWindow::triggerButtonClick (const String& buttonName)
  123. {
  124. for (int i = buttons.size(); --i >= 0;)
  125. {
  126. TextButton* const b = buttons.getUnchecked(i);
  127. if (buttonName == b->getName())
  128. {
  129. b->triggerClick();
  130. break;
  131. }
  132. }
  133. }
  134. void AlertWindow::setEscapeKeyCancels (bool shouldEscapeKeyCancel)
  135. {
  136. escapeKeyCancels = shouldEscapeKeyCancel;
  137. }
  138. //==============================================================================
  139. void AlertWindow::addTextEditor (const String& name,
  140. const String& initialContents,
  141. const String& onScreenLabel,
  142. const bool isPasswordBox)
  143. {
  144. AlertWindowTextEditor* const tc = new AlertWindowTextEditor (name, isPasswordBox);
  145. textBoxes.add (tc);
  146. allComps.add (tc);
  147. tc->setColour (TextEditor::outlineColourId, findColour (ComboBox::outlineColourId));
  148. tc->setFont (getLookAndFeel().getAlertWindowMessageFont());
  149. tc->setText (initialContents);
  150. tc->setCaretPosition (initialContents.length());
  151. addAndMakeVisible (tc);
  152. textboxNames.add (onScreenLabel);
  153. updateLayout (false);
  154. }
  155. TextEditor* AlertWindow::getTextEditor (const String& nameOfTextEditor) const
  156. {
  157. for (int i = textBoxes.size(); --i >= 0;)
  158. if (textBoxes.getUnchecked(i)->getName() == nameOfTextEditor)
  159. return textBoxes.getUnchecked(i);
  160. return nullptr;
  161. }
  162. String AlertWindow::getTextEditorContents (const String& nameOfTextEditor) const
  163. {
  164. TextEditor* const t = getTextEditor (nameOfTextEditor);
  165. return t != nullptr ? t->getText() : String::empty;
  166. }
  167. //==============================================================================
  168. void AlertWindow::addComboBox (const String& name,
  169. const StringArray& items,
  170. const String& onScreenLabel)
  171. {
  172. ComboBox* const cb = new ComboBox (name);
  173. comboBoxes.add (cb);
  174. allComps.add (cb);
  175. cb->addItemList (items, 1);
  176. addAndMakeVisible (cb);
  177. cb->setSelectedItemIndex (0);
  178. comboBoxNames.add (onScreenLabel);
  179. updateLayout (false);
  180. }
  181. ComboBox* AlertWindow::getComboBoxComponent (const String& nameOfList) const
  182. {
  183. for (int i = comboBoxes.size(); --i >= 0;)
  184. if (comboBoxes.getUnchecked(i)->getName() == nameOfList)
  185. return comboBoxes.getUnchecked(i);
  186. return nullptr;
  187. }
  188. //==============================================================================
  189. class AlertTextComp : public TextEditor
  190. {
  191. public:
  192. AlertTextComp (const String& message,
  193. const Font& font)
  194. {
  195. setReadOnly (true);
  196. setMultiLine (true, true);
  197. setCaretVisible (false);
  198. setScrollbarsShown (true);
  199. lookAndFeelChanged();
  200. setWantsKeyboardFocus (false);
  201. setFont (font);
  202. setText (message, false);
  203. bestWidth = 2 * (int) std::sqrt (font.getHeight() * font.getStringWidth (message));
  204. setColour (TextEditor::backgroundColourId, Colours::transparentBlack);
  205. setColour (TextEditor::outlineColourId, Colours::transparentBlack);
  206. setColour (TextEditor::shadowColourId, Colours::transparentBlack);
  207. }
  208. int getPreferredWidth() const noexcept { return bestWidth; }
  209. void updateLayout (const int width)
  210. {
  211. AttributedString s;
  212. s.setJustification (Justification::topLeft);
  213. s.append (getName(), getFont());
  214. TextLayout text;
  215. text.createLayoutWithBalancedLineLengths (s, width - 8.0f);
  216. setSize (width, jmin (width, (int) (text.getHeight() + getFont().getHeight())));
  217. }
  218. private:
  219. int bestWidth;
  220. JUCE_DECLARE_NON_COPYABLE (AlertTextComp);
  221. };
  222. void AlertWindow::addTextBlock (const String& textBlock)
  223. {
  224. AlertTextComp* const c = new AlertTextComp (textBlock, getLookAndFeel().getAlertWindowMessageFont());
  225. textBlocks.add (c);
  226. allComps.add (c);
  227. addAndMakeVisible (c);
  228. updateLayout (false);
  229. }
  230. //==============================================================================
  231. void AlertWindow::addProgressBarComponent (double& progressValue)
  232. {
  233. ProgressBar* const pb = new ProgressBar (progressValue);
  234. progressBars.add (pb);
  235. allComps.add (pb);
  236. addAndMakeVisible (pb);
  237. updateLayout (false);
  238. }
  239. //==============================================================================
  240. void AlertWindow::addCustomComponent (Component* const component)
  241. {
  242. customComps.add (component);
  243. allComps.add (component);
  244. addAndMakeVisible (component);
  245. updateLayout (false);
  246. }
  247. int AlertWindow::getNumCustomComponents() const
  248. {
  249. return customComps.size();
  250. }
  251. Component* AlertWindow::getCustomComponent (const int index) const
  252. {
  253. return customComps [index];
  254. }
  255. Component* AlertWindow::removeCustomComponent (const int index)
  256. {
  257. Component* const c = getCustomComponent (index);
  258. if (c != nullptr)
  259. {
  260. customComps.removeValue (c);
  261. allComps.removeValue (c);
  262. removeChildComponent (c);
  263. updateLayout (false);
  264. }
  265. return c;
  266. }
  267. //==============================================================================
  268. void AlertWindow::paint (Graphics& g)
  269. {
  270. getLookAndFeel().drawAlertBox (g, *this, textArea, textLayout);
  271. g.setColour (findColour (textColourId));
  272. g.setFont (getLookAndFeel().getAlertWindowFont());
  273. int i;
  274. for (i = textBoxes.size(); --i >= 0;)
  275. {
  276. const TextEditor* const te = textBoxes.getUnchecked(i);
  277. g.drawFittedText (textboxNames[i],
  278. te->getX(), te->getY() - 14,
  279. te->getWidth(), 14,
  280. Justification::centredLeft, 1);
  281. }
  282. for (i = comboBoxNames.size(); --i >= 0;)
  283. {
  284. const ComboBox* const cb = comboBoxes.getUnchecked(i);
  285. g.drawFittedText (comboBoxNames[i],
  286. cb->getX(), cb->getY() - 14,
  287. cb->getWidth(), 14,
  288. Justification::centredLeft, 1);
  289. }
  290. for (i = customComps.size(); --i >= 0;)
  291. {
  292. const Component* const c = customComps.getUnchecked(i);
  293. g.drawFittedText (c->getName(),
  294. c->getX(), c->getY() - 14,
  295. c->getWidth(), 14,
  296. Justification::centredLeft, 1);
  297. }
  298. }
  299. void AlertWindow::updateLayout (const bool onlyIncreaseSize)
  300. {
  301. const int titleH = 24;
  302. const int iconWidth = 80;
  303. const Font font (getLookAndFeel().getAlertWindowMessageFont());
  304. const int wid = jmax (font.getStringWidth (text),
  305. font.getStringWidth (getName()));
  306. const int sw = (int) std::sqrt (font.getHeight() * wid);
  307. int w = jmin (300 + sw * 2, (int) (getParentWidth() * 0.7f));
  308. const int edgeGap = 10;
  309. const int labelHeight = 18;
  310. int iconSpace = 0;
  311. AttributedString attributedText;
  312. attributedText.append (getName(), Font (font.getHeight() * 1.1f, Font::bold));
  313. if (text.isNotEmpty())
  314. attributedText.append ("\n\n" + text, font);
  315. attributedText.setColour (findColour (textColourId));
  316. if (alertIconType == NoIcon)
  317. {
  318. attributedText.setJustification (Justification::centredTop);
  319. textLayout.createLayoutWithBalancedLineLengths (attributedText, (float) w);
  320. }
  321. else
  322. {
  323. attributedText.setJustification (Justification::topLeft);
  324. textLayout.createLayoutWithBalancedLineLengths (attributedText, (float) w);
  325. iconSpace = iconWidth;
  326. }
  327. w = jmax (350, (int) textLayout.getWidth() + iconSpace + edgeGap * 4);
  328. w = jmin (w, (int) (getParentWidth() * 0.7f));
  329. const int textLayoutH = (int) textLayout.getHeight();
  330. const int textBottom = 16 + titleH + textLayoutH;
  331. int h = textBottom;
  332. int buttonW = 40;
  333. int i;
  334. for (i = 0; i < buttons.size(); ++i)
  335. buttonW += 16 + buttons.getUnchecked(i)->getWidth();
  336. w = jmax (buttonW, w);
  337. h += (textBoxes.size() + comboBoxes.size() + progressBars.size()) * 50;
  338. if (buttons.size() > 0)
  339. h += 20 + buttons.getUnchecked(0)->getHeight();
  340. for (i = customComps.size(); --i >= 0;)
  341. {
  342. Component* c = customComps.getUnchecked(i);
  343. w = jmax (w, (c->getWidth() * 100) / 80);
  344. h += 10 + c->getHeight();
  345. if (c->getName().isNotEmpty())
  346. h += labelHeight;
  347. }
  348. for (i = textBlocks.size(); --i >= 0;)
  349. {
  350. const AlertTextComp* const ac = static_cast <const AlertTextComp*> (textBlocks.getUnchecked(i));
  351. w = jmax (w, ac->getPreferredWidth());
  352. }
  353. w = jmin (w, (int) (getParentWidth() * 0.7f));
  354. for (i = textBlocks.size(); --i >= 0;)
  355. {
  356. AlertTextComp* const ac = static_cast <AlertTextComp*> (textBlocks.getUnchecked(i));
  357. ac->updateLayout ((int) (w * 0.8f));
  358. h += ac->getHeight() + 10;
  359. }
  360. h = jmin (getParentHeight() - 50, h);
  361. if (onlyIncreaseSize)
  362. {
  363. w = jmax (w, getWidth());
  364. h = jmax (h, getHeight());
  365. }
  366. if (! isVisible())
  367. {
  368. centreAroundComponent (associatedComponent, w, h);
  369. }
  370. else
  371. {
  372. const int cx = getX() + getWidth() / 2;
  373. const int cy = getY() + getHeight() / 2;
  374. setBounds (cx - w / 2,
  375. cy - h / 2,
  376. w, h);
  377. }
  378. textArea.setBounds (edgeGap, edgeGap, w - (edgeGap * 2), h - edgeGap);
  379. const int spacer = 16;
  380. int totalWidth = -spacer;
  381. for (i = buttons.size(); --i >= 0;)
  382. totalWidth += buttons.getUnchecked(i)->getWidth() + spacer;
  383. int x = (w - totalWidth) / 2;
  384. int y = (int) (getHeight() * 0.95f);
  385. for (i = 0; i < buttons.size(); ++i)
  386. {
  387. TextButton* const c = buttons.getUnchecked(i);
  388. int ny = proportionOfHeight (0.95f) - c->getHeight();
  389. c->setTopLeftPosition (x, ny);
  390. if (ny < y)
  391. y = ny;
  392. x += c->getWidth() + spacer;
  393. c->toFront (false);
  394. }
  395. y = textBottom;
  396. for (i = 0; i < allComps.size(); ++i)
  397. {
  398. Component* const c = allComps.getUnchecked(i);
  399. h = 22;
  400. const int comboIndex = comboBoxes.indexOf (dynamic_cast <ComboBox*> (c));
  401. if (comboIndex >= 0 && comboBoxNames [comboIndex].isNotEmpty())
  402. y += labelHeight;
  403. const int tbIndex = textBoxes.indexOf (dynamic_cast <TextEditor*> (c));
  404. if (tbIndex >= 0 && textboxNames[tbIndex].isNotEmpty())
  405. y += labelHeight;
  406. if (customComps.contains (c))
  407. {
  408. if (c->getName().isNotEmpty())
  409. y += labelHeight;
  410. c->setTopLeftPosition (proportionOfWidth (0.1f), y);
  411. h = c->getHeight();
  412. }
  413. else if (textBlocks.contains (c))
  414. {
  415. c->setTopLeftPosition ((getWidth() - c->getWidth()) / 2, y);
  416. h = c->getHeight();
  417. }
  418. else
  419. {
  420. c->setBounds (proportionOfWidth (0.1f), y, proportionOfWidth (0.8f), h);
  421. }
  422. y += h + 10;
  423. }
  424. setWantsKeyboardFocus (getNumChildComponents() == 0);
  425. }
  426. bool AlertWindow::containsAnyExtraComponents() const
  427. {
  428. return allComps.size() > 0;
  429. }
  430. //==============================================================================
  431. void AlertWindow::mouseDown (const MouseEvent& e)
  432. {
  433. dragger.startDraggingComponent (this, e);
  434. }
  435. void AlertWindow::mouseDrag (const MouseEvent& e)
  436. {
  437. dragger.dragComponent (this, e, &constrainer);
  438. }
  439. bool AlertWindow::keyPressed (const KeyPress& key)
  440. {
  441. for (int i = buttons.size(); --i >= 0;)
  442. {
  443. TextButton* const b = buttons.getUnchecked(i);
  444. if (b->isRegisteredForShortcut (key))
  445. {
  446. b->triggerClick();
  447. return true;
  448. }
  449. }
  450. if (key.isKeyCode (KeyPress::escapeKey) && escapeKeyCancels && buttons.size() == 0)
  451. {
  452. exitModalState (0);
  453. return true;
  454. }
  455. else if (key.isKeyCode (KeyPress::returnKey) && buttons.size() == 1)
  456. {
  457. buttons.getUnchecked(0)->triggerClick();
  458. return true;
  459. }
  460. return false;
  461. }
  462. void AlertWindow::lookAndFeelChanged()
  463. {
  464. const int newFlags = getLookAndFeel().getAlertBoxWindowFlags();
  465. setUsingNativeTitleBar ((newFlags & ComponentPeer::windowHasTitleBar) != 0);
  466. setDropShadowEnabled (isOpaque() && (newFlags & ComponentPeer::windowHasDropShadow) != 0);
  467. updateLayout (false);
  468. }
  469. int AlertWindow::getDesktopWindowStyleFlags() const
  470. {
  471. return getLookAndFeel().getAlertBoxWindowFlags();
  472. }
  473. //==============================================================================
  474. class AlertWindowInfo
  475. {
  476. public:
  477. AlertWindowInfo (const String& title_, const String& message_, Component* component,
  478. AlertWindow::AlertIconType iconType_, int numButtons_,
  479. ModalComponentManager::Callback* callback_, bool modal_)
  480. : title (title_), message (message_), iconType (iconType_),
  481. numButtons (numButtons_), returnValue (0), associatedComponent (component),
  482. callback (callback_), modal (modal_)
  483. {
  484. }
  485. String title, message, button1, button2, button3;
  486. int invoke() const
  487. {
  488. MessageManager::getInstance()->callFunctionOnMessageThread (showCallback, (void*) this);
  489. return returnValue;
  490. }
  491. private:
  492. AlertWindow::AlertIconType iconType;
  493. int numButtons, returnValue;
  494. WeakReference<Component> associatedComponent;
  495. ModalComponentManager::Callback* callback;
  496. bool modal;
  497. void show()
  498. {
  499. LookAndFeel& lf = associatedComponent != nullptr ? associatedComponent->getLookAndFeel()
  500. : LookAndFeel::getDefaultLookAndFeel();
  501. ScopedPointer <Component> alertBox (lf.createAlertWindow (title, message, button1, button2, button3,
  502. iconType, numButtons, associatedComponent));
  503. jassert (alertBox != nullptr); // you have to return one of these!
  504. #if JUCE_MODAL_LOOPS_PERMITTED
  505. if (modal)
  506. {
  507. returnValue = alertBox->runModalLoop();
  508. }
  509. else
  510. #endif
  511. {
  512. alertBox->enterModalState (true, callback, true);
  513. alertBox.release();
  514. }
  515. }
  516. static void* showCallback (void* userData)
  517. {
  518. static_cast <AlertWindowInfo*> (userData)->show();
  519. return nullptr;
  520. }
  521. };
  522. #if JUCE_MODAL_LOOPS_PERMITTED
  523. void AlertWindow::showMessageBox (AlertIconType iconType,
  524. const String& title,
  525. const String& message,
  526. const String& buttonText,
  527. Component* associatedComponent)
  528. {
  529. if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
  530. {
  531. NativeMessageBox::showMessageBox (iconType, title, message, associatedComponent);
  532. }
  533. else
  534. {
  535. AlertWindowInfo info (title, message, associatedComponent, iconType, 1, 0, true);
  536. info.button1 = buttonText.isEmpty() ? TRANS("ok") : buttonText;
  537. info.invoke();
  538. }
  539. }
  540. #endif
  541. void AlertWindow::showMessageBoxAsync (AlertIconType iconType,
  542. const String& title,
  543. const String& message,
  544. const String& buttonText,
  545. Component* associatedComponent)
  546. {
  547. if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
  548. {
  549. return NativeMessageBox::showMessageBoxAsync (iconType, title, message, associatedComponent);
  550. }
  551. else
  552. {
  553. AlertWindowInfo info (title, message, associatedComponent, iconType, 1, 0, false);
  554. info.button1 = buttonText.isEmpty() ? TRANS("ok") : buttonText;
  555. info.invoke();
  556. }
  557. }
  558. bool AlertWindow::showOkCancelBox (AlertIconType iconType,
  559. const String& title,
  560. const String& message,
  561. const String& button1Text,
  562. const String& button2Text,
  563. Component* associatedComponent,
  564. ModalComponentManager::Callback* callback)
  565. {
  566. if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
  567. {
  568. return NativeMessageBox::showOkCancelBox (iconType, title, message, associatedComponent, callback);
  569. }
  570. else
  571. {
  572. AlertWindowInfo info (title, message, associatedComponent, iconType, 2, callback, callback == nullptr);
  573. info.button1 = button1Text.isEmpty() ? TRANS("ok") : button1Text;
  574. info.button2 = button2Text.isEmpty() ? TRANS("cancel") : button2Text;
  575. return info.invoke() != 0;
  576. }
  577. }
  578. int AlertWindow::showYesNoCancelBox (AlertIconType iconType,
  579. const String& title,
  580. const String& message,
  581. const String& button1Text,
  582. const String& button2Text,
  583. const String& button3Text,
  584. Component* associatedComponent,
  585. ModalComponentManager::Callback* callback)
  586. {
  587. if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
  588. {
  589. return NativeMessageBox::showYesNoCancelBox (iconType, title, message, associatedComponent, callback);
  590. }
  591. else
  592. {
  593. AlertWindowInfo info (title, message, associatedComponent, iconType, 3, callback, callback == nullptr);
  594. info.button1 = button1Text.isEmpty() ? TRANS("yes") : button1Text;
  595. info.button2 = button2Text.isEmpty() ? TRANS("no") : button2Text;
  596. info.button3 = button3Text.isEmpty() ? TRANS("cancel") : button3Text;
  597. return info.invoke();
  598. }
  599. }
  600. #if JUCE_MODAL_LOOPS_PERMITTED
  601. bool AlertWindow::showNativeDialogBox (const String& title,
  602. const String& bodyText,
  603. bool isOkCancel)
  604. {
  605. if (isOkCancel)
  606. {
  607. return NativeMessageBox::showOkCancelBox (AlertWindow::NoIcon, title, bodyText);
  608. }
  609. else
  610. {
  611. NativeMessageBox::showMessageBox (AlertWindow::NoIcon, title, bodyText);
  612. return true;
  613. }
  614. }
  615. #endif