diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llui/llalertdialog.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llui/llalertdialog.cpp')
-rw-r--r-- | linden/indra/llui/llalertdialog.cpp | 829 |
1 files changed, 829 insertions, 0 deletions
diff --git a/linden/indra/llui/llalertdialog.cpp b/linden/indra/llui/llalertdialog.cpp new file mode 100644 index 0000000..861bbc6 --- /dev/null +++ b/linden/indra/llui/llalertdialog.cpp | |||
@@ -0,0 +1,829 @@ | |||
1 | /** | ||
2 | * @file llalertdialog.cpp | ||
3 | * @brief LLAlertDialog base class | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | #include "llboost.h" | ||
31 | |||
32 | #include "llalertdialog.h" | ||
33 | #include "llfontgl.h" | ||
34 | #include "llresmgr.h" | ||
35 | #include "lltextbox.h" | ||
36 | #include "llbutton.h" | ||
37 | #include "llcheckboxctrl.h" | ||
38 | #include "llkeyboard.h" | ||
39 | #include "llfocusmgr.h" | ||
40 | #include "llui.h" | ||
41 | #include "llxmlnode.h" | ||
42 | #include "lllineeditor.h" | ||
43 | #include "lluictrlfactory.h" | ||
44 | |||
45 | |||
46 | const S32 MAX_ALLOWED_MSG_WIDTH = 400; | ||
47 | const F32 DEFAULT_BUTTON_DELAY = 0.5f; | ||
48 | const S32 MSG_PAD = 8; | ||
49 | |||
50 | /*static*/ LLAlertDialog::template_map_t LLAlertDialog::sAlertTemplates; | ||
51 | /*static*/ LLAlertDialog::template_map_t LLAlertDialog::sIgnorableTemplates; | ||
52 | /*static*/ LLControlGroup* LLAlertDialog::sSettings = NULL; | ||
53 | /*static*/ std::map<LLString,LLAlertDialog*> LLAlertDialog::sUniqueActiveMap; | ||
54 | /*static*/ LLAlertDialog::display_callback_t LLAlertDialog::sDisplayCallback; | ||
55 | |||
56 | //static | ||
57 | LLAlertDialog* LLAlertDialog::createXml( const LLString& xml_desc, | ||
58 | alert_callback_t callback, void *user_data) | ||
59 | { | ||
60 | LLString::format_map_t args; | ||
61 | return createXml(xml_desc, args, callback, user_data); | ||
62 | } | ||
63 | |||
64 | //static | ||
65 | LLAlertDialog* LLAlertDialog::createXml( const LLString& xml_desc, const LLString::format_map_t& args, | ||
66 | alert_callback_t callback, void *user_data) | ||
67 | { | ||
68 | template_map_t::iterator iter = sAlertTemplates.find(xml_desc); | ||
69 | if (iter != sAlertTemplates.end()) | ||
70 | { | ||
71 | LLAlertDialogTemplate* xml_template = iter->second; | ||
72 | // deletes itself | ||
73 | llwarns << "Alert: [" << xml_desc << "] " << llendl; | ||
74 | LLAlertDialog* dialog = new LLAlertDialog( xml_template, args, callback, user_data); | ||
75 | return dialog; | ||
76 | } | ||
77 | else | ||
78 | { | ||
79 | LLString::format_map_t args; | ||
80 | args["[ALERT_NAME]"] = xml_desc; | ||
81 | llwarns << "Missing Alert: [" << xml_desc << "]" << llendl; | ||
82 | LLAlertDialog* dialogp = LLAlertDialog::showXml("MissingAlert", args); | ||
83 | if (dialogp == NULL) | ||
84 | { | ||
85 | llerrs << "Bad or missing alerts.xml!" << llendl; | ||
86 | } | ||
87 | return NULL; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | //static | ||
92 | LLAlertDialog* LLAlertDialog::showXml( const LLString& xml_desc, | ||
93 | alert_callback_t callback, void *user_data) | ||
94 | { | ||
95 | LLString::format_map_t args; | ||
96 | return showXml(xml_desc, args, callback, user_data); | ||
97 | } | ||
98 | |||
99 | //static | ||
100 | LLAlertDialog* LLAlertDialog::showXml( const LLString& xml_desc, const LLString::format_map_t& args, | ||
101 | alert_callback_t callback, void *user_data) | ||
102 | { | ||
103 | LLAlertDialog* dialog = createXml(xml_desc, args, callback, user_data); | ||
104 | return dialog && dialog->show() ? dialog : NULL; | ||
105 | } | ||
106 | |||
107 | //static | ||
108 | LLAlertDialog* LLAlertDialog::showCritical( const LLString& desc, alert_callback_t callback, void *user_data) | ||
109 | { | ||
110 | LLAlertDialogTemplate xml_template; | ||
111 | LLString::format_map_t args; | ||
112 | xml_template.mTitle = "Critical Error"; | ||
113 | xml_template.mMessage = desc; | ||
114 | xml_template.mModal = TRUE; | ||
115 | xml_template.mOptions.push_back("Quit"); | ||
116 | LLAlertDialog* dialog = new LLAlertDialog( &xml_template, args, callback, user_data); | ||
117 | return dialog && dialog->show() ? dialog : NULL; | ||
118 | } | ||
119 | |||
120 | //----------------------------------------------------------------------------- | ||
121 | // Private methods | ||
122 | |||
123 | static const S32 VPAD = 16; | ||
124 | static const S32 HPAD = 25; | ||
125 | static const S32 BTN_HPAD = 8; | ||
126 | static const LLFONT_ID font_name = LLFONT_SANSSERIF; | ||
127 | |||
128 | LLAlertDialog::LLAlertDialog( const LLAlertDialogTemplate* xml_template, | ||
129 | const LLString::format_map_t& args, | ||
130 | alert_callback_t callback, void *user_data) | ||
131 | : LLModalDialog( xml_template->mTitle, 100, 100, xml_template->mModal ), // dummy size. Will reshape below. | ||
132 | mCallback( callback ), | ||
133 | mUserData( user_data ), | ||
134 | mNumOptions( 0 ), | ||
135 | mDefaultOption( 0 ), | ||
136 | mOptionChosen( -1 ), | ||
137 | mCheck(NULL), | ||
138 | mUnique(xml_template->mUnique), | ||
139 | mIgnorable(xml_template->mIgnorable), | ||
140 | mLabel(xml_template->mLabel), | ||
141 | mIgnoreLabel(xml_template->mIgnoreLabel), | ||
142 | mButtonData(NULL), | ||
143 | mLineEditor(NULL), | ||
144 | mTextCallback(NULL) | ||
145 | { | ||
146 | createDialog(&(xml_template->mOptions), xml_template->mDefaultOption, | ||
147 | xml_template->mMessage, args, | ||
148 | xml_template->mEditLineText); | ||
149 | setTitle(xml_template->mTitle); | ||
150 | if (xml_template->mIgnorable) | ||
151 | { | ||
152 | //XUI:translate! | ||
153 | LLString msg; | ||
154 | if (xml_template->mIgnorable == IGNORE_USE_DEFAULT) | ||
155 | { | ||
156 | msg = "Skip this dialog next time"; | ||
157 | } | ||
158 | else // xml_template->mIgnorable == IGNORE_USE_SAVED | ||
159 | { | ||
160 | msg = "Always choose this option"; | ||
161 | } | ||
162 | setCheckBox(msg, xml_template->mIgnoreLabel); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | // All logic for deciding not to show an alert is done here, | ||
167 | // so that the alert is valid until show() is called. | ||
168 | bool LLAlertDialog::show() | ||
169 | { | ||
170 | // If mModal, check to see if we are not displaying alerts, | ||
171 | // and do any application logic before showing modal alerts | ||
172 | if (sDisplayCallback) | ||
173 | { | ||
174 | bool show = sDisplayCallback(mModal); | ||
175 | if (show == false) | ||
176 | { | ||
177 | mOptionChosen = mDefaultOption; | ||
178 | llinfos << "Alert: " << mLabel << llendl; | ||
179 | delete this; | ||
180 | return false; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | // Check to see if the user wants to ignore this alert | ||
185 | if (mIgnorable > 0) | ||
186 | { | ||
187 | BOOL warn = sSettings->getWarning(mIgnoreLabel); | ||
188 | if (!warn) | ||
189 | { | ||
190 | switch(mIgnorable) | ||
191 | { | ||
192 | case IGNORE_USE_DEFAULT: | ||
193 | mOptionChosen = mDefaultOption; | ||
194 | break; | ||
195 | case IGNORE_USE_SAVED: | ||
196 | mOptionChosen = sSettings->getS32("Default" + mIgnoreLabel); | ||
197 | break; | ||
198 | case IGNORE_SHOW_AGAIN: | ||
199 | break; | ||
200 | } | ||
201 | delete this; | ||
202 | return false; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | // Check to see if we are already displaying the alert | ||
207 | if (mUnique) | ||
208 | { | ||
209 | std::map<LLString,LLAlertDialog*>::iterator iter = sUniqueActiveMap.find(mLabel); | ||
210 | if (iter != sUniqueActiveMap.end()) | ||
211 | { | ||
212 | gFloaterView->bringToFront(iter->second); | ||
213 | mUnique = FALSE; // don't remove entry from map on destruction | ||
214 | delete this; | ||
215 | return false; | ||
216 | } | ||
217 | sUniqueActiveMap[mLabel] = this; | ||
218 | } | ||
219 | startModal(); | ||
220 | gFloaterView->adjustToFitScreen(this, FALSE); | ||
221 | open(); | ||
222 | setFocus(TRUE); | ||
223 | if (mLineEditor) | ||
224 | { | ||
225 | mLineEditor->setFocus(TRUE); | ||
226 | mLineEditor->selectAll(); | ||
227 | } | ||
228 | if(mDefaultOption >= 0) | ||
229 | { | ||
230 | // delay before enabling default button | ||
231 | mDefaultBtnTimer.start(); | ||
232 | mDefaultBtnTimer.setTimerExpirySec(DEFAULT_BUTTON_DELAY); | ||
233 | } | ||
234 | return true; | ||
235 | } | ||
236 | |||
237 | //static | ||
238 | void LLAlertDialog::format(LLString& msg, const LLString::format_map_t& args) | ||
239 | { | ||
240 | // XUI:translate! | ||
241 | LLString::format_map_t targs = args; | ||
242 | targs["[SECOND_LIFE]"] = "Second Life"; | ||
243 | LLString::format(msg, targs); | ||
244 | } | ||
245 | |||
246 | void LLAlertDialog::createDialog(const std::vector<LLString>* optionsp, S32 default_option, | ||
247 | const LLString& msg_in, const LLString::format_map_t& args, | ||
248 | const LLString& edit_text) | ||
249 | { | ||
250 | setBackgroundVisible(TRUE); | ||
251 | setBackgroundOpaque(TRUE); | ||
252 | |||
253 | const LLFontGL* font = gResMgr->getRes( font_name ); | ||
254 | const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f); | ||
255 | const S32 EDITOR_HEIGHT = 20; | ||
256 | |||
257 | // buttons | ||
258 | std::vector<LLString> default_option_list; | ||
259 | |||
260 | mNumOptions = optionsp->size(); | ||
261 | |||
262 | if( 0 == mNumOptions ) | ||
263 | { | ||
264 | default_option_list.push_back("Close"); | ||
265 | optionsp = &default_option_list; | ||
266 | default_option = 0; | ||
267 | mNumOptions = 1; | ||
268 | } | ||
269 | |||
270 | const std::vector<LLString>& options = *optionsp; | ||
271 | |||
272 | mButtonData = new ButtonData[mNumOptions]; | ||
273 | |||
274 | // Calc total width of buttons | ||
275 | S32 button_width = 0; | ||
276 | S32 sp = font->getWidth("OO"); | ||
277 | for( S32 i = 0; i < mNumOptions; i++ ) | ||
278 | { | ||
279 | S32 w = S32(font->getWidth( options[i] ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD; | ||
280 | button_width = llmax( w, button_width ); | ||
281 | } | ||
282 | S32 btn_total_width = button_width; | ||
283 | if( mNumOptions > 1 ) | ||
284 | { | ||
285 | btn_total_width = (mNumOptions * button_width) + ((mNumOptions - 1) * BTN_HPAD); | ||
286 | } | ||
287 | |||
288 | // Split message into lines, separated by '\n' | ||
289 | LLString msg = msg_in; | ||
290 | LLAlertDialog::format(msg, args); | ||
291 | |||
292 | llwarns << "Alert: " << msg << llendl; | ||
293 | |||
294 | S32 max_msg_width = 0; | ||
295 | std::vector<LLString> msg_lines; | ||
296 | |||
297 | boost_tokenizer tokens(msg, boost::char_separator<char>("\n")); | ||
298 | for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) | ||
299 | { | ||
300 | LLString line(*token_iter); | ||
301 | boost_tokenizer line_toks(line, boost::char_separator<char>(" \t")); | ||
302 | LLString cur_line; | ||
303 | S32 cur_line_width = 0; | ||
304 | for (boost_tokenizer::iterator token_iter2 = line_toks.begin(); token_iter2 != line_toks.end(); ++token_iter2) | ||
305 | { | ||
306 | LLString tok(*token_iter2); | ||
307 | LLString word; | ||
308 | if (cur_line_width > 0) | ||
309 | { | ||
310 | word = " "; | ||
311 | } | ||
312 | word += tok; | ||
313 | S32 word_width = S32(font->getWidth( word ) + 0.99f); | ||
314 | if (cur_line_width > 0 && cur_line_width + word_width > MAX_ALLOWED_MSG_WIDTH) | ||
315 | { | ||
316 | max_msg_width = llmax( max_msg_width, cur_line_width + MSG_PAD); | ||
317 | msg_lines.push_back( cur_line ); | ||
318 | cur_line.clear(); | ||
319 | cur_line_width = 0; | ||
320 | word = tok; // no ' ' | ||
321 | } | ||
322 | cur_line += word; | ||
323 | cur_line_width += word_width; | ||
324 | } | ||
325 | if (cur_line_width > 0) | ||
326 | { | ||
327 | max_msg_width = llmax( max_msg_width, cur_line_width ); | ||
328 | msg_lines.push_back( cur_line ); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | // pad message box so we don't clip last character | ||
333 | max_msg_width += 2; | ||
334 | |||
335 | S32 dialog_width = llmax( btn_total_width, max_msg_width ) + 2 * HPAD; | ||
336 | S32 dialog_height = LINE_HEIGHT * msg_lines.size() + 3 * VPAD + BTN_HEIGHT; | ||
337 | |||
338 | if (hasTitleBar()) | ||
339 | { | ||
340 | dialog_height += LINE_HEIGHT; // room for title bar | ||
341 | } | ||
342 | |||
343 | if (edit_text.size() > 0) | ||
344 | { | ||
345 | dialog_width = llmax(dialog_width, S32(font->getWidth( edit_text ) + 0.99f)); | ||
346 | dialog_height += EDITOR_HEIGHT; | ||
347 | } | ||
348 | |||
349 | reshape( dialog_width, dialog_height, FALSE ); | ||
350 | |||
351 | // Message | ||
352 | S32 msg_x = (mRect.getWidth() - max_msg_width) / 2; | ||
353 | S32 msg_y = mRect.getHeight() - VPAD - LINE_HEIGHT; | ||
354 | if (hasTitleBar()) | ||
355 | { | ||
356 | msg_y -= LINE_HEIGHT; // room for title | ||
357 | } | ||
358 | |||
359 | for( std::vector<LLString>::iterator iter = msg_lines.begin(); iter != msg_lines.end(); ++iter ) | ||
360 | { | ||
361 | LLRect msg_rect; | ||
362 | msg_rect.setOriginAndSize( msg_x, msg_y, max_msg_width, LINE_HEIGHT ); | ||
363 | LLTextBox* label_box = new LLTextBox( "Alert message", msg_rect, iter->c_str(), font ); | ||
364 | label_box->setColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ); | ||
365 | addChild(label_box); | ||
366 | msg_y -= LINE_HEIGHT; | ||
367 | } | ||
368 | |||
369 | // Buttons | ||
370 | S32 button_left = (mRect.getWidth() - btn_total_width) / 2; | ||
371 | |||
372 | for( S32 i = 0; i < mNumOptions; i++ ) | ||
373 | { | ||
374 | LLRect button_rect; | ||
375 | button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT ); | ||
376 | |||
377 | LLButton* btn = new LLButton( | ||
378 | "btn", button_rect, | ||
379 | "","", "", | ||
380 | &LLAlertDialog::onButtonPressed, (void*)(&mButtonData[i]), | ||
381 | font, | ||
382 | options[i], | ||
383 | options[i]); | ||
384 | |||
385 | mButtonData[i].mSelf = this; | ||
386 | mButtonData[i].mButton = btn; | ||
387 | mButtonData[i].mOption = i; | ||
388 | |||
389 | addChild(btn); | ||
390 | |||
391 | if( i == default_option ) | ||
392 | { | ||
393 | btn->setFocus(TRUE); | ||
394 | } | ||
395 | |||
396 | button_left += button_width + BTN_HPAD; | ||
397 | } | ||
398 | |||
399 | // (Optional) Edit Box | ||
400 | if (edit_text.size() > 0) | ||
401 | { | ||
402 | S32 y = VPAD + BTN_HEIGHT + VPAD/2; | ||
403 | mLineEditor = new LLLineEditor("lineeditor", | ||
404 | LLRect( HPAD, y+EDITOR_HEIGHT, dialog_width-HPAD, y), | ||
405 | edit_text, | ||
406 | LLFontGL::sSansSerif, | ||
407 | STD_STRING_STR_LEN); | ||
408 | addChild(mLineEditor); | ||
409 | } | ||
410 | |||
411 | } | ||
412 | |||
413 | bool LLAlertDialog::setCheckBox( const LLString& check_title, const LLString& check_control ) | ||
414 | { | ||
415 | const LLFontGL* font = gResMgr->getRes( font_name ); | ||
416 | const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f); | ||
417 | |||
418 | // Extend dialog for "check next time" | ||
419 | S32 max_msg_width = mRect.getWidth() - 2 * HPAD; | ||
420 | S32 check_width = S32(font->getWidth(check_title) + 0.99f) + 16; | ||
421 | max_msg_width = llmax(max_msg_width, check_width); | ||
422 | S32 dialog_width = max_msg_width + 2 * HPAD; | ||
423 | |||
424 | S32 dialog_height = mRect.getHeight(); | ||
425 | dialog_height += LINE_HEIGHT; | ||
426 | dialog_height += LINE_HEIGHT / 2; | ||
427 | |||
428 | reshape( dialog_width, dialog_height, FALSE ); | ||
429 | |||
430 | S32 msg_x = (mRect.getWidth() - max_msg_width) / 2; | ||
431 | |||
432 | LLRect check_rect; | ||
433 | check_rect.setOriginAndSize(msg_x, VPAD+BTN_HEIGHT+LINE_HEIGHT/2, | ||
434 | max_msg_width, LINE_HEIGHT); | ||
435 | |||
436 | mCheck = new LLCheckboxCtrl("check", check_rect, check_title, font); | ||
437 | addChild(mCheck); | ||
438 | |||
439 | // mCheck is sometimes "show again" and sometimes "hide" :-( | ||
440 | // If it's "Show Again", and we showed it, it must be checked. JC | ||
441 | if (mIgnorable == IGNORE_SHOW_AGAIN) | ||
442 | { | ||
443 | mCheck->setValue(TRUE); | ||
444 | } | ||
445 | |||
446 | return true; | ||
447 | } | ||
448 | |||
449 | void LLAlertDialog::setVisible( BOOL visible ) | ||
450 | { | ||
451 | LLModalDialog::setVisible( visible ); | ||
452 | |||
453 | if( visible ) | ||
454 | { | ||
455 | centerOnScreen(); | ||
456 | make_ui_sound("UISndAlert"); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | LLAlertDialog::~LLAlertDialog() | ||
461 | { | ||
462 | if (mOptionChosen >= 0) | ||
463 | { | ||
464 | if (mTextCallback && mLineEditor) | ||
465 | { | ||
466 | mTextCallback(mOptionChosen, mLineEditor->getText(), mUserData); | ||
467 | } | ||
468 | else if (mCallback) | ||
469 | { | ||
470 | mCallback(mOptionChosen, mUserData); | ||
471 | } | ||
472 | |||
473 | // Only change warn state if we actually warned. | ||
474 | if (mCheck | ||
475 | && sSettings->getWarning(mIgnoreLabel)) | ||
476 | { | ||
477 | // mCheck sometimes means "hide and do the default" and | ||
478 | // other times means "warn me again". Yuck. JC | ||
479 | BOOL check = mCheck->getValue(); | ||
480 | switch(mIgnorable) | ||
481 | { | ||
482 | case IGNORE_USE_DEFAULT: | ||
483 | sSettings->setWarning(mIgnoreLabel, !check); | ||
484 | break; | ||
485 | case IGNORE_USE_SAVED: | ||
486 | sSettings->setWarning(mIgnoreLabel, !check); | ||
487 | sSettings->setS32("Default" + mIgnoreLabel, mOptionChosen); | ||
488 | break; | ||
489 | case IGNORE_SHOW_AGAIN: | ||
490 | sSettings->setWarning(mIgnoreLabel, check); | ||
491 | break; | ||
492 | default: | ||
493 | break; | ||
494 | } | ||
495 | } | ||
496 | } | ||
497 | delete[] mButtonData; | ||
498 | if (mUnique) | ||
499 | { | ||
500 | sUniqueActiveMap.erase(mLabel); | ||
501 | } | ||
502 | } | ||
503 | |||
504 | BOOL LLAlertDialog::hasTitleBar() const | ||
505 | { | ||
506 | return (getTitle() != "" && getTitle() != " ") // has title | ||
507 | || isMinimizeable() | ||
508 | || isCloseable(); | ||
509 | } | ||
510 | |||
511 | BOOL LLAlertDialog::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent ) | ||
512 | { | ||
513 | if( KEY_RETURN == key && mask == MASK_NONE ) | ||
514 | { | ||
515 | // Warning: handleKeyHere may result in the default button | ||
516 | // being committed, which will destroy this object. | ||
517 | // Everything works, but the call stack will pass through | ||
518 | // the very end of functions that belong to deleted objects. | ||
519 | // Should find a less fragile way to do this. | ||
520 | LLModalDialog::handleKeyHere( key, mask , called_from_parent ); | ||
521 | return TRUE; | ||
522 | } | ||
523 | else if (KEY_RIGHT == key) | ||
524 | { | ||
525 | focusNextItem(FALSE); | ||
526 | return TRUE; | ||
527 | } | ||
528 | else if (KEY_LEFT == key) | ||
529 | { | ||
530 | focusPrevItem(FALSE); | ||
531 | return TRUE; | ||
532 | } | ||
533 | else if (KEY_TAB == key && mask == MASK_NONE) | ||
534 | { | ||
535 | focusNextItem(FALSE); | ||
536 | return TRUE; | ||
537 | } | ||
538 | else if (KEY_TAB == key && mask == MASK_SHIFT) | ||
539 | { | ||
540 | focusPrevItem(FALSE); | ||
541 | return TRUE; | ||
542 | } | ||
543 | else | ||
544 | { | ||
545 | return LLModalDialog::handleKeyHere( key, mask , called_from_parent ); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | // virtual | ||
550 | void LLAlertDialog::draw() | ||
551 | { | ||
552 | // if the default button timer has just expired, activate the default button | ||
553 | if(mDefaultBtnTimer.hasExpired() && mDefaultBtnTimer.getStarted()) | ||
554 | { | ||
555 | mDefaultBtnTimer.stop(); // prevent this block from being run more than once | ||
556 | setDefaultBtn(mButtonData[mDefaultOption].mButton); | ||
557 | } | ||
558 | if (getVisible()) | ||
559 | { | ||
560 | LLColor4 shadow_color = LLUI::sColorsGroup->getColor("ColorDropShadow"); | ||
561 | S32 shadow_lines = LLUI::sConfigGroup->getS32("DropShadowFloater"); | ||
562 | |||
563 | gl_drop_shadow( 0, mRect.getHeight(), mRect.getWidth(), 0, | ||
564 | shadow_color, shadow_lines); | ||
565 | |||
566 | LLModalDialog::draw(); | ||
567 | } | ||
568 | } | ||
569 | |||
570 | void LLAlertDialog::setOptionEnabled( S32 option, BOOL enable ) | ||
571 | { | ||
572 | if( (option >= 0) && (option < mNumOptions) ) | ||
573 | { | ||
574 | mButtonData[option].mButton->setEnabled( enable ); | ||
575 | } | ||
576 | } | ||
577 | |||
578 | void LLAlertDialog::setEditTextCallback(alert_text_callback_t callback, void *user_data) | ||
579 | { | ||
580 | if (mLineEditor) | ||
581 | { | ||
582 | mTextCallback = callback; | ||
583 | mUserData = user_data; | ||
584 | } | ||
585 | else | ||
586 | { | ||
587 | llwarns << "LLAlertDialog::setEditTextCallback called on dialog with no line editor" << llendl; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | void LLAlertDialog::setEditTextArgs(const LLString::format_map_t& edit_args) | ||
592 | { | ||
593 | if (mLineEditor) | ||
594 | { | ||
595 | LLString msg = mLineEditor->getText(); | ||
596 | LLAlertDialog::format(msg, edit_args); | ||
597 | mLineEditor->setText(msg); | ||
598 | } | ||
599 | else | ||
600 | { | ||
601 | llwarns << "LLAlertDialog::setEditTextArgs called on dialog with no line editor" << llendl; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | void LLAlertDialog::setDrawAsterixes(BOOL enable) | ||
606 | { | ||
607 | if (mLineEditor) | ||
608 | { | ||
609 | if (enable) | ||
610 | { | ||
611 | mLineEditor->clear(); | ||
612 | } | ||
613 | mLineEditor->setDrawAsterixes(enable); | ||
614 | } | ||
615 | } | ||
616 | |||
617 | // static | ||
618 | void LLAlertDialog::onButtonPressed( void* userdata ) | ||
619 | { | ||
620 | ButtonData* button_data = (ButtonData*)userdata; | ||
621 | LLAlertDialog* self = button_data->mSelf; | ||
622 | |||
623 | self->mOptionChosen = button_data->mOption; | ||
624 | self->close(); // deletes self | ||
625 | } | ||
626 | |||
627 | //============================================================================= | ||
628 | |||
629 | //static | ||
630 | const LLString& LLAlertDialog::getTemplateMessage(const LLString& xml_desc) | ||
631 | { | ||
632 | template_map_t::iterator iter = sAlertTemplates.find(xml_desc); | ||
633 | if (iter != sAlertTemplates.end()) | ||
634 | { | ||
635 | return iter->second->mMessage; | ||
636 | } | ||
637 | else | ||
638 | { | ||
639 | return xml_desc; | ||
640 | } | ||
641 | } | ||
642 | |||
643 | //static | ||
644 | bool LLAlertDialog::parseAlerts(const LLString& xml_filename, LLControlGroup* settings, BOOL settings_only) | ||
645 | { | ||
646 | LLXMLNodePtr root; | ||
647 | BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); | ||
648 | |||
649 | if (!success || root.isNull() || !root->hasName( "alerts" )) | ||
650 | { | ||
651 | llerrs << "Problem reading UI Alerts file: " << xml_filename << llendl; | ||
652 | return false; | ||
653 | } | ||
654 | |||
655 | BOOL add_settings = FALSE; | ||
656 | if (settings) | ||
657 | { | ||
658 | sSettings = settings; | ||
659 | add_settings = TRUE; | ||
660 | } | ||
661 | llassert(sSettings); | ||
662 | |||
663 | for (LLXMLNode* alert = root->getFirstChild(); | ||
664 | alert != NULL; alert = alert->getNextSibling()) | ||
665 | { | ||
666 | if (!alert->hasName("alert")) | ||
667 | { | ||
668 | continue; | ||
669 | } | ||
670 | |||
671 | LLAlertDialogTemplate* xml_template = settings_only ? NULL : new LLAlertDialogTemplate; | ||
672 | |||
673 | // name= | ||
674 | LLString alert_name; | ||
675 | if (alert->getAttributeString("name", alert_name)) | ||
676 | { | ||
677 | if (xml_template) | ||
678 | { | ||
679 | xml_template->mLabel = alert_name; | ||
680 | } | ||
681 | } | ||
682 | else | ||
683 | { | ||
684 | llwarns << "Unable to parse alert with no name" << llendl; | ||
685 | delete xml_template; | ||
686 | continue; | ||
687 | } | ||
688 | // title= | ||
689 | LLString title; | ||
690 | if (alert->getAttributeString("title", title)) | ||
691 | { | ||
692 | if (xml_template) | ||
693 | { | ||
694 | xml_template->mTitle = title; | ||
695 | } | ||
696 | } | ||
697 | // modal= | ||
698 | BOOL modal; | ||
699 | if (alert->getAttributeBOOL("modal", modal)) | ||
700 | { | ||
701 | if (xml_template) | ||
702 | { | ||
703 | xml_template->mModal = modal; | ||
704 | } | ||
705 | } | ||
706 | // unique= | ||
707 | BOOL unique; | ||
708 | if (alert->getAttributeBOOL("unique", unique)) | ||
709 | { | ||
710 | if (xml_template) | ||
711 | { | ||
712 | xml_template->mUnique = unique; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | S32 default_option = 0; | ||
717 | BOOL nodefault; | ||
718 | if (alert->getAttributeBOOL("nodefault", nodefault)) | ||
719 | { | ||
720 | if (nodefault) | ||
721 | { | ||
722 | if (xml_template) | ||
723 | { | ||
724 | xml_template->mDefaultOption = -1; | ||
725 | } | ||
726 | default_option = -1; | ||
727 | } | ||
728 | } | ||
729 | |||
730 | S32 btn_idx = 0; | ||
731 | for (LLXMLNode* child = alert->getFirstChild(); | ||
732 | child != NULL; child = child->getNextSibling()) | ||
733 | { | ||
734 | // <message> | ||
735 | if (child->hasName("message")) | ||
736 | { | ||
737 | if (xml_template) | ||
738 | { | ||
739 | xml_template->mMessage = child->getTextContents(); | ||
740 | } | ||
741 | } | ||
742 | |||
743 | // <option> | ||
744 | if (child->hasName("option")) | ||
745 | { | ||
746 | LLString label = child->getTextContents(); | ||
747 | BOOL is_default = FALSE; | ||
748 | child->getAttributeBOOL("default", is_default); | ||
749 | LLString ignore_text; | ||
750 | if (!child->getAttributeString("ignore", ignore_text)) | ||
751 | { | ||
752 | ignore_text = label; | ||
753 | } | ||
754 | if (xml_template) | ||
755 | { | ||
756 | xml_template->addOption(label, ignore_text, is_default); | ||
757 | } | ||
758 | if (is_default) | ||
759 | { | ||
760 | default_option = btn_idx; | ||
761 | } | ||
762 | btn_idx++; | ||
763 | } | ||
764 | |||
765 | // <editline> | ||
766 | if (child->hasName("editline")) | ||
767 | { | ||
768 | if (xml_template) | ||
769 | { | ||
770 | xml_template->mEditLineText = child->getTextContents(); | ||
771 | if (xml_template->mEditLineText.empty()) | ||
772 | { | ||
773 | xml_template->mEditLineText = " "; | ||
774 | } | ||
775 | } | ||
776 | } | ||
777 | |||
778 | // <ignore> | ||
779 | if (child->hasName("ignore")) | ||
780 | { | ||
781 | LLString ignore_text = child->getTextContents(); | ||
782 | // label= | ||
783 | LLString name; | ||
784 | child->getAttributeString("name", name); | ||
785 | if (name.empty()) | ||
786 | { | ||
787 | name = alert_name; | ||
788 | } | ||
789 | if (xml_template) | ||
790 | { | ||
791 | xml_template->mIgnorable = LLAlertDialog::IGNORE_USE_DEFAULT; | ||
792 | xml_template->mIgnoreListText = ignore_text; | ||
793 | xml_template->mIgnoreLabel = name; | ||
794 | } | ||
795 | if (!ignore_text.empty()) | ||
796 | { | ||
797 | if (add_settings) | ||
798 | { | ||
799 | settings->addWarning(name); | ||
800 | } | ||
801 | if (xml_template) | ||
802 | { | ||
803 | sIgnorableTemplates[name] = xml_template; // will override any previous entry | ||
804 | } | ||
805 | } | ||
806 | // save_option= | ||
807 | BOOL save_option = FALSE; | ||
808 | child->getAttributeBOOL("save_option", save_option); | ||
809 | if (save_option) | ||
810 | { | ||
811 | if (xml_template) | ||
812 | { | ||
813 | xml_template->mIgnorable = LLAlertDialog::IGNORE_USE_SAVED; | ||
814 | } | ||
815 | if (add_settings) | ||
816 | { | ||
817 | settings->declareS32("Default" + name, default_option, "Default option number for this alert dialog"); | ||
818 | } | ||
819 | } | ||
820 | } | ||
821 | } | ||
822 | if (xml_template) | ||
823 | { | ||
824 | xml_template->mDefaultOption = default_option; | ||
825 | sAlertTemplates[xml_template->mLabel] = xml_template; | ||
826 | } | ||
827 | } | ||
828 | return true; | ||
829 | } | ||