diff options
Diffstat (limited to 'linden/indra/llui/llalertdialog.cpp')
-rw-r--r-- | linden/indra/llui/llalertdialog.cpp | 766 |
1 files changed, 212 insertions, 554 deletions
diff --git a/linden/indra/llui/llalertdialog.cpp b/linden/indra/llui/llalertdialog.cpp index 80e54b6..f321db8 100644 --- a/linden/indra/llui/llalertdialog.cpp +++ b/linden/indra/llui/llalertdialog.cpp | |||
@@ -1,5 +1,4 @@ | |||
1 | /** | 1 | /* @file llalertdialog.cpp |
2 | * @file llalertdialog.cpp | ||
3 | * @brief LLAlertDialog base class | 2 | * @brief LLAlertDialog base class |
4 | * | 3 | * |
5 | * $LicenseInfo:firstyear=2001&license=viewergpl$ | 4 | * $LicenseInfo:firstyear=2001&license=viewergpl$ |
@@ -17,7 +16,8 @@ | |||
17 | * There are special exceptions to the terms and conditions of the GPL as | 16 | * There are special exceptions to the terms and conditions of the GPL as |
18 | * it is applied to this Source Code. View the full text of the exception | 17 | * it is applied to this Source Code. View the full text of the exception |
19 | * in the file doc/FLOSS-exception.txt in this software distribution, or | 18 | * in the file doc/FLOSS-exception.txt in this software distribution, or |
20 | * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception | 19 | * online at |
20 | * http://secondlifegrid.net/programs/open_source/licensing/flossexception | ||
21 | * | 21 | * |
22 | * By copying, modifying or distributing this software, you acknowledge | 22 | * By copying, modifying or distributing this software, you acknowledge |
23 | * that you have read and understood your obligations described above, | 23 | * that you have read and understood your obligations described above, |
@@ -46,85 +46,55 @@ | |||
46 | #include "llxmlnode.h" | 46 | #include "llxmlnode.h" |
47 | #include "lllineeditor.h" | 47 | #include "lllineeditor.h" |
48 | #include "lluictrlfactory.h" | 48 | #include "lluictrlfactory.h" |
49 | 49 | #include "llnotifications.h" | |
50 | #include "llfunctorregistry.h" | ||
50 | 51 | ||
51 | const S32 MAX_ALLOWED_MSG_WIDTH = 400; | 52 | const S32 MAX_ALLOWED_MSG_WIDTH = 400; |
52 | const F32 DEFAULT_BUTTON_DELAY = 0.5f; | 53 | const F32 DEFAULT_BUTTON_DELAY = 0.5f; |
53 | const S32 MSG_PAD = 8; | 54 | const S32 MSG_PAD = 8; |
54 | 55 | ||
55 | /*static*/ LLAlertDialog::template_map_t LLAlertDialog::sAlertTemplates; | ||
56 | /*static*/ LLAlertDialog::template_map_t LLAlertDialog::sIgnorableTemplates; | ||
57 | /*static*/ LLControlGroup* LLAlertDialog::sSettings = NULL; | 56 | /*static*/ LLControlGroup* LLAlertDialog::sSettings = NULL; |
58 | /*static*/ std::map<std::string,LLAlertDialog*> LLAlertDialog::sUniqueActiveMap; | ||
59 | /*static*/ LLAlertDialog::display_callback_t LLAlertDialog::sDisplayCallback; | ||
60 | /*static*/ std::string LLAlertDialog::sStringSkipNextTime("Skip this dialog next time"); | ||
61 | /*static*/ std::string LLAlertDialog::sStringAlwaysChoose("Always choose this option"); | ||
62 | /*static*/ LLAlertDialog::URLLoader* LLAlertDialog::sURLLoader; | 57 | /*static*/ LLAlertDialog::URLLoader* LLAlertDialog::sURLLoader; |
63 | 58 | ||
64 | |||
65 | //static | 59 | //static |
66 | LLAlertDialog* LLAlertDialog::createXml( const std::string& xml_desc, | 60 | void LLAlertDialog::initClass() |
67 | alert_callback_t callback, void *user_data) | ||
68 | { | 61 | { |
69 | LLStringUtil::format_map_t args; | 62 | LLNotificationChannel::buildChannel("Alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert")); |
70 | return createXml(xml_desc, args, callback, user_data); | 63 | LLNotificationChannel::buildChannel("AlertModal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal")); |
64 | LLNotifications::instance().getChannel("Alerts")->connectChanged(boost::bind(&onNewNotification, _1, false)); | ||
65 | LLNotifications::instance().getChannel("AlertModal")->connectChanged(boost::bind(&onNewNotification, _1, true)); | ||
71 | } | 66 | } |
72 | 67 | ||
73 | //static | 68 | //static |
74 | LLAlertDialog* LLAlertDialog::createXml( const std::string& xml_desc, const LLStringUtil::format_map_t& args, | 69 | bool LLAlertDialog::onNewNotification(const LLSD& notify, bool is_modal) |
75 | alert_callback_t callback, void *user_data) | ||
76 | { | 70 | { |
77 | template_map_t::iterator iter = sAlertTemplates.find(xml_desc); | 71 | LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); |
78 | if (iter != sAlertTemplates.end()) | 72 | |
79 | { | 73 | if(notification) |
80 | LLAlertDialogTemplate* xml_template = iter->second; | ||
81 | // deletes itself | ||
82 | llwarns << "Alert: [" << xml_desc << "] " << llendl; | ||
83 | LLAlertDialog* dialog = new LLAlertDialog( xml_template, args, callback, user_data); | ||
84 | return dialog; | ||
85 | } | ||
86 | else | ||
87 | { | 74 | { |
88 | LLStringUtil::format_map_t args; | 75 | if (notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "load") |
89 | args["[ALERT_NAME]"] = xml_desc; | ||
90 | llwarns << "Missing Alert: [" << xml_desc << "]" << llendl; | ||
91 | LLAlertDialog* dialogp = LLAlertDialog::showXml("MissingAlert", args); | ||
92 | if (dialogp == NULL) | ||
93 | { | 76 | { |
94 | llerrs << "Bad or missing alerts.xml!" << llendl; | 77 | LLAlertDialog* dialog = new LLAlertDialog(notification, is_modal); |
78 | dialog->show(); | ||
79 | } | ||
80 | else if (notify["sigtype"].asString() == "change") | ||
81 | { | ||
82 | LLAlertDialog* dialog = getInstance(notification->getID()); | ||
83 | if (dialog) | ||
84 | { | ||
85 | dialog->show(); | ||
86 | } | ||
87 | else | ||
88 | { | ||
89 | LLAlertDialog* dialog = new LLAlertDialog(notification, is_modal); | ||
90 | dialog->show(); | ||
91 | } | ||
95 | } | 92 | } |
96 | return NULL; | ||
97 | } | 93 | } |
98 | } | ||
99 | |||
100 | //static | ||
101 | LLAlertDialog* LLAlertDialog::showXml( const std::string& xml_desc, | ||
102 | alert_callback_t callback, void *user_data) | ||
103 | { | ||
104 | LLStringUtil::format_map_t args; | ||
105 | return showXml(xml_desc, args, callback, user_data); | ||
106 | } | ||
107 | 94 | ||
108 | //static | 95 | return false; |
109 | LLAlertDialog* LLAlertDialog::showXml( const std::string& xml_desc, const LLStringUtil::format_map_t& args, | ||
110 | alert_callback_t callback, void *user_data) | ||
111 | { | ||
112 | LLAlertDialog* dialog = createXml(xml_desc, args, callback, user_data); | ||
113 | return dialog && dialog->show() ? dialog : NULL; | ||
114 | } | 96 | } |
115 | 97 | ||
116 | //static | ||
117 | LLAlertDialog* LLAlertDialog::showCritical( const std::string& desc, alert_callback_t callback, void *user_data) | ||
118 | { | ||
119 | LLAlertDialogTemplate xml_template; | ||
120 | LLStringUtil::format_map_t args; | ||
121 | xml_template.mTitle = "Critical Error"; | ||
122 | xml_template.mMessage = desc; | ||
123 | xml_template.mModal = TRUE; | ||
124 | xml_template.mOptions.push_back("Quit"); | ||
125 | LLAlertDialog* dialog = new LLAlertDialog( &xml_template, args, callback, user_data); | ||
126 | return dialog && dialog->show() ? dialog : NULL; | ||
127 | } | ||
128 | 98 | ||
129 | //----------------------------------------------------------------------------- | 99 | //----------------------------------------------------------------------------- |
130 | // Private methods | 100 | // Private methods |
@@ -132,183 +102,110 @@ LLAlertDialog* LLAlertDialog::showCritical( const std::string& desc, alert_callb | |||
132 | static const S32 VPAD = 16; | 102 | static const S32 VPAD = 16; |
133 | static const S32 HPAD = 25; | 103 | static const S32 HPAD = 25; |
134 | static const S32 BTN_HPAD = 8; | 104 | static const S32 BTN_HPAD = 8; |
135 | static const LLFONT_ID font_name = LLFONT_SANSSERIF; | 105 | static const LLFONT_ID FONT_NAME = LLFONT_SANSSERIF; |
136 | 106 | ||
137 | LLAlertDialog::LLAlertDialog( const LLAlertDialogTemplate* xml_template, | 107 | LLAlertDialog::LLAlertDialog( LLNotificationPtr notification, bool modal) |
138 | const LLStringUtil::format_map_t& args, | 108 | : LLModalDialog( notification->getLabel(), 100, 100, modal ), // dummy size. Will reshape below. |
139 | alert_callback_t callback, void *user_data) | 109 | LLInstanceTracker<LLAlertDialog, LLUUID>(notification->getID()), |
140 | : LLModalDialog( xml_template->mTitle, 100, 100, xml_template->mModal ), // dummy size. Will reshape below. | ||
141 | mCallback( callback ), | ||
142 | mUserData( user_data ), | ||
143 | mNumOptions( 0 ), | ||
144 | mDefaultOption( 0 ), | 110 | mDefaultOption( 0 ), |
145 | mOptionChosen( -1 ), | ||
146 | mCheck(NULL), | 111 | mCheck(NULL), |
147 | mCaution(xml_template->mCaution), | 112 | mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH), |
148 | mUnique(xml_template->mUnique), | 113 | mLabel(notification->getName()), |
149 | mIgnorable(xml_template->mIgnorable), | ||
150 | mLabel(xml_template->mLabel), | ||
151 | mIgnoreLabel(xml_template->mIgnoreLabel), | ||
152 | mButtonData(NULL), | ||
153 | mLineEditor(NULL), | 114 | mLineEditor(NULL), |
154 | mTextCallback(NULL), | 115 | mNote(notification) |
155 | mURLOption(0) | ||
156 | { | 116 | { |
157 | mURL = xml_template->mURL; | 117 | const LLFontGL* font = LLResMgr::getInstance()->getRes( FONT_NAME ); |
158 | mURLOption = xml_template->mURLOption; | 118 | const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f); |
159 | createDialog(xml_template->mOptions, xml_template->mDefaultOption, | 119 | const S32 EDITOR_HEIGHT = 20; |
160 | xml_template->mMessage, args, | ||
161 | xml_template->mEditLineText); | ||
162 | setTitle(xml_template->mTitle); | ||
163 | if (xml_template->mIgnorable) | ||
164 | { | ||
165 | if (xml_template->mIgnorable == IGNORE_USE_DEFAULT) | ||
166 | { | ||
167 | setCheckBox(sStringSkipNextTime, xml_template->mIgnoreLabel); | ||
168 | } | ||
169 | else // xml_template->mIgnorable == IGNORE_USE_SAVED | ||
170 | { | ||
171 | setCheckBox(sStringAlwaysChoose, xml_template->mIgnoreLabel); | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | 120 | ||
176 | // All logic for deciding not to show an alert is done here, | 121 | LLNotificationFormPtr form = mNote->getForm(); |
177 | // so that the alert is valid until show() is called. | 122 | std::string edit_text_name; |
178 | bool LLAlertDialog::show() | 123 | std::string edit_text_contents; |
179 | { | 124 | bool is_password = false; |
180 | // If modal, check to see if we are not displaying alerts, | 125 | |
181 | // and do any application logic before showing modal alerts | 126 | setBackgroundVisible(TRUE); |
182 | if (sDisplayCallback) | 127 | setBackgroundOpaque(TRUE); |
183 | { | ||
184 | bool show = sDisplayCallback(isModal()); | ||
185 | if (show == false) | ||
186 | { | ||
187 | mOptionChosen = mDefaultOption; | ||
188 | llinfos << "Alert: " << mLabel << llendl; | ||
189 | close(); | ||
190 | return false; | ||
191 | } | ||
192 | } | ||
193 | 128 | ||
194 | // Check to see if the user wants to ignore this alert | 129 | |
195 | if (mIgnorable > 0) | 130 | typedef std::vector<std::pair<std::string, std::string> > options_t; |
131 | options_t supplied_options; | ||
132 | |||
133 | // for now, get LLSD to iterator over form elements | ||
134 | LLSD form_sd = form->asLLSD(); | ||
135 | |||
136 | S32 option_index = 0; | ||
137 | for (LLSD::array_const_iterator it = form_sd.beginArray(); it != form_sd.endArray(); ++it) | ||
196 | { | 138 | { |
197 | BOOL warn = sSettings->getWarning(mIgnoreLabel); | 139 | std::string type = (*it)["type"].asString(); |
198 | if (!warn) | 140 | if (type == "button") |
199 | { | 141 | { |
200 | switch(mIgnorable) | 142 | if((*it)["default"]) |
201 | { | 143 | { |
202 | case IGNORE_USE_DEFAULT: | 144 | mDefaultOption = option_index; |
203 | mOptionChosen = mDefaultOption; | ||
204 | break; | ||
205 | case IGNORE_USE_SAVED: | ||
206 | mOptionChosen = sSettings->getS32("Default" + mIgnoreLabel); | ||
207 | break; | ||
208 | case IGNORE_SHOW_AGAIN: | ||
209 | break; | ||
210 | } | 145 | } |
211 | close(); | ||
212 | return false; | ||
213 | } | ||
214 | } | ||
215 | 146 | ||
216 | // If this is a caution message, change the color and add an icon. | 147 | supplied_options.push_back(std::make_pair((*it)["name"].asString(), (*it)["text"].asString())); |
217 | if (mCaution) | ||
218 | { | ||
219 | setBackgroundColor( LLUI::sColorsGroup->getColor( "AlertCautionBoxColor" ) ); | ||
220 | } | ||
221 | else | ||
222 | { | ||
223 | setBackgroundColor( LLUI::sColorsGroup->getColor( "AlertBoxColor" ) ); | ||
224 | } | ||
225 | 148 | ||
226 | // Check to see if we are already displaying the alert | 149 | ButtonData data; |
227 | if (mUnique) | 150 | data.mSelf = this; |
228 | { | 151 | if (option_index == mNote->getURLOption()) |
229 | std::map<std::string,LLAlertDialog*>::iterator iter = sUniqueActiveMap.find(mLabel); | 152 | { |
230 | if (iter != sUniqueActiveMap.end()) | 153 | data.mURL = mNote->getURL(); |
154 | } | ||
155 | |||
156 | mButtonData.push_back(data); | ||
157 | option_index++; | ||
158 | } | ||
159 | else if (type == "text") | ||
231 | { | 160 | { |
232 | gFloaterView->bringToFront(iter->second); | 161 | edit_text_contents = (*it)["value"].asString(); |
233 | mUnique = FALSE; // don't remove entry from map on destruction | 162 | edit_text_name = (*it)["name"].asString(); |
234 | close(); | 163 | } |
235 | return false; | 164 | else if (type == "password") |
165 | { | ||
166 | edit_text_contents = (*it)["value"].asString(); | ||
167 | edit_text_name = (*it)["name"].asString(); | ||
168 | is_password = true; | ||
236 | } | 169 | } |
237 | sUniqueActiveMap[mLabel] = this; | ||
238 | } | ||
239 | startModal(); | ||
240 | gFloaterView->adjustToFitScreen(this, FALSE); | ||
241 | open(); /* Flawfinder: ignore */ | ||
242 | setFocus(TRUE); | ||
243 | if (mLineEditor) | ||
244 | { | ||
245 | mLineEditor->setFocus(TRUE); | ||
246 | mLineEditor->selectAll(); | ||
247 | } | ||
248 | if(mDefaultOption >= 0) | ||
249 | { | ||
250 | // delay before enabling default button | ||
251 | mDefaultBtnTimer.start(); | ||
252 | mDefaultBtnTimer.setTimerExpirySec(DEFAULT_BUTTON_DELAY); | ||
253 | } | 170 | } |
254 | return true; | ||
255 | } | ||
256 | |||
257 | void LLAlertDialog::format(std::string& msg, const LLStringUtil::format_map_t& args) | ||
258 | { | ||
259 | // XUI:translate! | ||
260 | LLStringUtil::format_map_t targs = args; | ||
261 | targs["[SECOND_LIFE]"] = "Second Life"; | ||
262 | targs["[_URL]"] = mURL; | ||
263 | LLStringUtil::format(msg, targs); | ||
264 | } | ||
265 | 171 | ||
266 | void LLAlertDialog::createDialog(const options_list_t& options_in, S32 default_option, | ||
267 | const std::string& msg_in, const LLStringUtil::format_map_t& args, | ||
268 | const std::string& edit_text) | ||
269 | { | ||
270 | setBackgroundVisible(TRUE); | ||
271 | setBackgroundOpaque(TRUE); | ||
272 | |||
273 | const LLFontGL* font = LLResMgr::getInstance()->getRes( font_name ); | ||
274 | const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f); | ||
275 | const S32 EDITOR_HEIGHT = 20; | ||
276 | |||
277 | const options_list_t* optionsp = &options_in; | ||
278 | |||
279 | // Buttons | 172 | // Buttons |
280 | options_list_t default_option_list; | 173 | options_t options; |
281 | mNumOptions = options_in.size(); | 174 | if (supplied_options.empty()) |
282 | if( 0 == mNumOptions ) | ||
283 | { | 175 | { |
284 | default_option_list.push_back("Close"); | 176 | options.push_back(std::make_pair(std::string("close"), std::string("Close"))); |
285 | optionsp = &default_option_list; | 177 | |
286 | default_option = 0; | 178 | // add data for ok button. |
287 | mNumOptions = 1; | 179 | ButtonData ok_button; |
180 | ok_button.mSelf = this; | ||
181 | |||
182 | mButtonData.push_back(ok_button); | ||
183 | mDefaultOption = 0; | ||
184 | } | ||
185 | else | ||
186 | { | ||
187 | options = supplied_options; | ||
288 | } | 188 | } |
289 | 189 | ||
290 | const options_list_t& options= *optionsp; | 190 | S32 num_options = options.size(); |
291 | |||
292 | mButtonData = new ButtonData[mNumOptions]; | ||
293 | 191 | ||
294 | // Calc total width of buttons | 192 | // Calc total width of buttons |
295 | S32 button_width = 0; | 193 | S32 button_width = 0; |
296 | S32 sp = font->getWidth(std::string("OO")); | 194 | S32 sp = font->getWidth(std::string("OO")); |
297 | for( S32 i = 0; i < mNumOptions; i++ ) | 195 | for( S32 i = 0; i < num_options; i++ ) |
298 | { | 196 | { |
299 | S32 w = S32(font->getWidth( options[i] ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD; | 197 | S32 w = S32(font->getWidth( options[i].second ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD; |
300 | button_width = llmax( w, button_width ); | 198 | button_width = llmax( w, button_width ); |
301 | } | 199 | } |
302 | S32 btn_total_width = button_width; | 200 | S32 btn_total_width = button_width; |
303 | if( mNumOptions > 1 ) | 201 | if( num_options > 1 ) |
304 | { | 202 | { |
305 | btn_total_width = (mNumOptions * button_width) + ((mNumOptions - 1) * BTN_HPAD); | 203 | btn_total_width = (num_options * button_width) + ((num_options - 1) * BTN_HPAD); |
306 | } | 204 | } |
307 | 205 | ||
308 | // Message: create text box using raw string, as text has been structure deliberately | 206 | // Message: create text box using raw string, as text has been structure deliberately |
309 | // Use size of created text box to generate dialog box size | 207 | // Use size of created text box to generate dialog box size |
310 | std::string msg = msg_in; | 208 | std::string msg = mNote->getMessage(); |
311 | format( msg, args ); | ||
312 | llwarns << "Alert: " << msg << llendl; | 209 | llwarns << "Alert: " << msg << llendl; |
313 | LLTextBox* msg_box = new LLTextBox( std::string("Alert message"), msg, (F32)MAX_ALLOWED_MSG_WIDTH, font ); | 210 | LLTextBox* msg_box = new LLTextBox( std::string("Alert message"), msg, (F32)MAX_ALLOWED_MSG_WIDTH, font ); |
314 | 211 | ||
@@ -321,16 +218,19 @@ void LLAlertDialog::createDialog(const options_list_t& options_in, S32 default_o | |||
321 | dialog_height += LINE_HEIGHT; // room for title bar | 218 | dialog_height += LINE_HEIGHT; // room for title bar |
322 | } | 219 | } |
323 | 220 | ||
324 | if (edit_text.size() > 0) | 221 | // it's ok for the edit text body to be empty, but we want the name to exist if we're going to draw it |
222 | if (!edit_text_name.empty()) | ||
325 | { | 223 | { |
326 | dialog_width = llmax(dialog_width, S32(font->getWidth( edit_text ) + 0.99f)); | 224 | dialog_height += EDITOR_HEIGHT + VPAD; |
327 | dialog_height += EDITOR_HEIGHT; | 225 | dialog_width = llmax(dialog_width, (S32)(font->getWidth( edit_text_contents ) + 0.99f)); |
328 | } | 226 | } |
227 | |||
329 | if (mCaution) | 228 | if (mCaution) |
330 | { | 229 | { |
331 | // Make room for the caution icon. | 230 | // Make room for the caution icon. |
332 | dialog_width += 32 + HPAD; | 231 | dialog_width += 32 + HPAD; |
333 | } | 232 | } |
233 | |||
334 | reshape( dialog_width, dialog_height, FALSE ); | 234 | reshape( dialog_width, dialog_height, FALSE ); |
335 | 235 | ||
336 | S32 msg_y = getRect().getHeight() - VPAD; | 236 | S32 msg_y = getRect().getHeight() - VPAD; |
@@ -352,6 +252,7 @@ void LLAlertDialog::createDialog(const options_list_t& options_in, S32 default_o | |||
352 | { | 252 | { |
353 | msg_box->setColor( LLUI::sColorsGroup->getColor( "AlertTextColor" ) ); | 253 | msg_box->setColor( LLUI::sColorsGroup->getColor( "AlertTextColor" ) ); |
354 | } | 254 | } |
255 | |||
355 | LLRect rect; | 256 | LLRect rect; |
356 | rect.setLeftTopAndSize( msg_x, msg_y, text_rect.getWidth(), text_rect.getHeight() ); | 257 | rect.setLeftTopAndSize( msg_x, msg_y, text_rect.getWidth(), text_rect.getHeight() ); |
357 | msg_box->setRect( rect ); | 258 | msg_box->setRect( rect ); |
@@ -360,25 +261,26 @@ void LLAlertDialog::createDialog(const options_list_t& options_in, S32 default_o | |||
360 | // Buttons | 261 | // Buttons |
361 | S32 button_left = (getRect().getWidth() - btn_total_width) / 2; | 262 | S32 button_left = (getRect().getWidth() - btn_total_width) / 2; |
362 | 263 | ||
363 | for( S32 i = 0; i < mNumOptions; i++ ) | 264 | for( S32 i = 0; i < num_options; i++ ) |
364 | { | 265 | { |
365 | LLRect button_rect; | 266 | LLRect button_rect; |
366 | button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT ); | 267 | button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT ); |
367 | 268 | ||
368 | LLButton* btn = new LLButton(std::string("btn"), button_rect, | 269 | LLButton* btn = new LLButton( |
369 | LLStringUtil::null, LLStringUtil::null, LLStringUtil::null, | 270 | options[i].first, button_rect, |
370 | &LLAlertDialog::onButtonPressed, (void*)(&mButtonData[i]), | 271 | "","", "", |
371 | font, | 272 | NULL, NULL, |
372 | options[i], | 273 | font, |
373 | options[i]); | 274 | options[i].second, |
275 | options[i].second); | ||
374 | 276 | ||
375 | mButtonData[i].mSelf = this; | ||
376 | mButtonData[i].mButton = btn; | 277 | mButtonData[i].mButton = btn; |
377 | mButtonData[i].mOption = i; | 278 | |
279 | btn->setClickedCallback(&LLAlertDialog::onButtonPressed, (void*)(&mButtonData[i])); | ||
378 | 280 | ||
379 | addChild(btn); | 281 | addChild(btn); |
380 | 282 | ||
381 | if( i == default_option ) | 283 | if( i == mDefaultOption ) |
382 | { | 284 | { |
383 | btn->setFocus(TRUE); | 285 | btn->setFocus(TRUE); |
384 | } | 286 | } |
@@ -387,21 +289,83 @@ void LLAlertDialog::createDialog(const options_list_t& options_in, S32 default_o | |||
387 | } | 289 | } |
388 | 290 | ||
389 | // (Optional) Edit Box | 291 | // (Optional) Edit Box |
390 | if (edit_text.size() > 0) | 292 | if (!edit_text_name.empty()) |
391 | { | 293 | { |
392 | S32 y = VPAD + BTN_HEIGHT + VPAD/2; | 294 | S32 y = VPAD + BTN_HEIGHT + VPAD/2; |
393 | mLineEditor = new LLLineEditor(std::string("lineeditor"), | 295 | mLineEditor = new LLLineEditor(edit_text_name, |
394 | LLRect( HPAD, y+EDITOR_HEIGHT, dialog_width-HPAD, y), | 296 | LLRect( HPAD, y+EDITOR_HEIGHT, dialog_width-HPAD, y), |
395 | edit_text, | 297 | edit_text_contents, |
396 | LLFontGL::sSansSerif, | 298 | LLFontGL::getFontSansSerif(), |
397 | STD_STRING_STR_LEN); | 299 | STD_STRING_STR_LEN); |
300 | |||
301 | // make sure all edit keys get handled properly (DEV-22396) | ||
302 | mLineEditor->setHandleEditKeysDirectly(TRUE); | ||
303 | |||
398 | addChild(mLineEditor); | 304 | addChild(mLineEditor); |
399 | } | 305 | } |
306 | |||
307 | if (mLineEditor) | ||
308 | { | ||
309 | mLineEditor->setDrawAsterixes(is_password); | ||
310 | |||
311 | setEditTextArgs(notification->getSubstitutions()); | ||
312 | } | ||
313 | |||
314 | std::string ignore_label; | ||
315 | |||
316 | if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) | ||
317 | { | ||
318 | setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label); | ||
319 | } | ||
320 | else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) | ||
321 | { | ||
322 | setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label); | ||
323 | } | ||
324 | } | ||
325 | |||
326 | // All logic for deciding not to show an alert is done here, | ||
327 | // so that the alert is valid until show() is called. | ||
328 | bool LLAlertDialog::show() | ||
329 | { | ||
330 | // If this is a caution message, change the color and add an icon. | ||
331 | if (mCaution) | ||
332 | { | ||
333 | setBackgroundColor( LLUI::sColorsGroup->getColor( "AlertCautionBoxColor" ) ); | ||
334 | } | ||
335 | else | ||
336 | { | ||
337 | setBackgroundColor( LLUI::sColorsGroup->getColor( "AlertBoxColor" ) ); | ||
338 | } | ||
339 | |||
340 | startModal(); | ||
341 | gFloaterView->adjustToFitScreen(this, FALSE); | ||
342 | open(); /* Flawfinder: ignore */ | ||
343 | setFocus(TRUE); | ||
344 | if (mLineEditor) | ||
345 | { | ||
346 | mLineEditor->setFocus(TRUE); | ||
347 | mLineEditor->selectAll(); | ||
348 | } | ||
349 | if(mDefaultOption >= 0) | ||
350 | { | ||
351 | // delay before enabling default button | ||
352 | mDefaultBtnTimer.start(); | ||
353 | mDefaultBtnTimer.setTimerExpirySec(DEFAULT_BUTTON_DELAY); | ||
354 | } | ||
355 | |||
356 | // attach to floater if necessary | ||
357 | LLUUID context_key = mNote->getPayload()["context"].asUUID(); | ||
358 | LLFloaterNotificationContext* contextp = dynamic_cast<LLFloaterNotificationContext*>(LLNotificationContext::getInstance(context_key)); | ||
359 | if (contextp && contextp->getFloater()) | ||
360 | { | ||
361 | contextp->getFloater()->addDependentFloater(this, FALSE); | ||
362 | } | ||
363 | return true; | ||
400 | } | 364 | } |
401 | 365 | ||
402 | bool LLAlertDialog::setCheckBox( const std::string& check_title, const std::string& check_control ) | 366 | bool LLAlertDialog::setCheckBox( const std::string& check_title, const std::string& check_control ) |
403 | { | 367 | { |
404 | const LLFontGL* font = LLResMgr::getInstance()->getRes( font_name ); | 368 | const LLFontGL* font = LLResMgr::getInstance()->getRes( FONT_NAME ); |
405 | const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f); | 369 | const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f); |
406 | 370 | ||
407 | // Extend dialog for "check next time" | 371 | // Extend dialog for "check next time" |
@@ -422,16 +386,9 @@ bool LLAlertDialog::setCheckBox( const std::string& check_title, const std::stri | |||
422 | check_rect.setOriginAndSize(msg_x, VPAD+BTN_HEIGHT+LINE_HEIGHT/2, | 386 | check_rect.setOriginAndSize(msg_x, VPAD+BTN_HEIGHT+LINE_HEIGHT/2, |
423 | max_msg_width, LINE_HEIGHT); | 387 | max_msg_width, LINE_HEIGHT); |
424 | 388 | ||
425 | mCheck = new LLCheckboxCtrl(std::string("check"), check_rect, check_title, font); | 389 | mCheck = new LLCheckboxCtrl(std::string("check"), check_rect, check_title, font, onClickIgnore, this); |
426 | addChild(mCheck); | 390 | addChild(mCheck); |
427 | 391 | ||
428 | // mCheck is sometimes "show again" and sometimes "hide" :-( | ||
429 | // If it's "Show Again", and we showed it, it must be checked. JC | ||
430 | if (mIgnorable == IGNORE_SHOW_AGAIN) | ||
431 | { | ||
432 | mCheck->setValue(TRUE); | ||
433 | } | ||
434 | |||
435 | return true; | 392 | return true; |
436 | } | 393 | } |
437 | 394 | ||
@@ -449,65 +406,12 @@ void LLAlertDialog::setVisible( BOOL visible ) | |||
449 | void LLAlertDialog::onClose(bool app_quitting) | 406 | void LLAlertDialog::onClose(bool app_quitting) |
450 | { | 407 | { |
451 | LLModalDialog::onClose(app_quitting); | 408 | LLModalDialog::onClose(app_quitting); |
452 | handleCallbacks(); | ||
453 | } | 409 | } |
454 | 410 | ||
455 | LLAlertDialog::~LLAlertDialog() | 411 | LLAlertDialog::~LLAlertDialog() |
456 | { | 412 | { |
457 | delete[] mButtonData; | ||
458 | if (mUnique) | ||
459 | { | ||
460 | sUniqueActiveMap.erase(mLabel); | ||
461 | } | ||
462 | } | 413 | } |
463 | 414 | ||
464 | void LLAlertDialog::handleCallbacks() | ||
465 | { | ||
466 | if (mOptionChosen >= 0) | ||
467 | { | ||
468 | if (mTextCallback && mLineEditor) | ||
469 | { | ||
470 | mTextCallback(mOptionChosen, mLineEditor->getText(), mUserData); | ||
471 | } | ||
472 | else if (mCallback) | ||
473 | { | ||
474 | mCallback(mOptionChosen, mUserData); | ||
475 | } | ||
476 | |||
477 | // If we declared a URL and chose the URL option, go to the url | ||
478 | if (mOptionChosen == mURLOption) | ||
479 | { | ||
480 | if (!mURL.empty() && sURLLoader != NULL) | ||
481 | { | ||
482 | sURLLoader->load(mURL); | ||
483 | } | ||
484 | } | ||
485 | |||
486 | // Only change warn state if we actually warned. | ||
487 | if (mCheck | ||
488 | && sSettings->getWarning(mIgnoreLabel)) | ||
489 | { | ||
490 | // mCheck sometimes means "hide and do the default" and | ||
491 | // other times means "warn me again". Yuck. JC | ||
492 | BOOL check = mCheck->getValue(); | ||
493 | switch(mIgnorable) | ||
494 | { | ||
495 | case IGNORE_USE_DEFAULT: | ||
496 | sSettings->setWarning(mIgnoreLabel, !check); | ||
497 | break; | ||
498 | case IGNORE_USE_SAVED: | ||
499 | sSettings->setWarning(mIgnoreLabel, !check); | ||
500 | sSettings->setS32("Default" + mIgnoreLabel, mOptionChosen); | ||
501 | break; | ||
502 | case IGNORE_SHOW_AGAIN: | ||
503 | sSettings->setWarning(mIgnoreLabel, check); | ||
504 | break; | ||
505 | default: | ||
506 | break; | ||
507 | } | ||
508 | } | ||
509 | } | ||
510 | } | ||
511 | BOOL LLAlertDialog::hasTitleBar() const | 415 | BOOL LLAlertDialog::hasTitleBar() const |
512 | { | 416 | { |
513 | return (getCurrentTitle() != "" && getCurrentTitle() != " ") // has title | 417 | return (getCurrentTitle() != "" && getCurrentTitle() != " ") // has title |
@@ -567,33 +471,11 @@ void LLAlertDialog::draw() | |||
567 | LLModalDialog::draw(); | 471 | LLModalDialog::draw(); |
568 | } | 472 | } |
569 | 473 | ||
570 | void LLAlertDialog::setOptionEnabled( S32 option, BOOL enable ) | 474 | void LLAlertDialog::setEditTextArgs(const LLSD& edit_args) |
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 LLStringUtil::format_map_t& edit_args) | ||
592 | { | 475 | { |
593 | if (mLineEditor) | 476 | if (mLineEditor) |
594 | { | 477 | { |
595 | std::string msg = mLineEditor->getText(); | 478 | std::string msg = mLineEditor->getText(); |
596 | format(msg, edit_args); | ||
597 | mLineEditor->setText(msg); | 479 | mLineEditor->setText(msg); |
598 | } | 480 | } |
599 | else | 481 | else |
@@ -602,268 +484,44 @@ void LLAlertDialog::setEditTextArgs(const LLStringUtil::format_map_t& edit_args) | |||
602 | } | 484 | } |
603 | } | 485 | } |
604 | 486 | ||
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 | 487 | // static |
618 | void LLAlertDialog::onButtonPressed( void* userdata ) | 488 | void LLAlertDialog::onButtonPressed( void* userdata ) |
619 | { | 489 | { |
620 | ButtonData* button_data = (ButtonData*)userdata; | 490 | ButtonData* button_data = (ButtonData*)userdata; |
621 | LLAlertDialog* self = button_data->mSelf; | 491 | LLAlertDialog* self = button_data->mSelf; |
622 | 492 | ||
623 | self->mOptionChosen = button_data->mOption; | 493 | LLSD response = self->mNote->getResponseTemplate(); |
624 | self->close(); // deletes self | 494 | if (self->mLineEditor) |
625 | } | ||
626 | |||
627 | //============================================================================= | ||
628 | |||
629 | //static | ||
630 | const std::string& LLAlertDialog::getTemplateMessage(const std::string& xml_desc) | ||
631 | { | ||
632 | template_map_t::iterator iter = sAlertTemplates.find(xml_desc); | ||
633 | if (iter != sAlertTemplates.end()) | ||
634 | { | 495 | { |
635 | return iter->second->mMessage; | 496 | response[self->mLineEditor->getName()] = self->mLineEditor->getValue(); |
636 | } | 497 | } |
637 | else | 498 | response[button_data->mButton->getName()] = true; |
499 | |||
500 | // If we declared a URL and chose the URL option, go to the url | ||
501 | if (!button_data->mURL.empty() && sURLLoader != NULL) | ||
638 | { | 502 | { |
639 | return xml_desc; | 503 | sURLLoader->load(button_data->mURL); |
640 | } | 504 | } |
505 | |||
506 | self->mNote->respond(response); // new notification reponse | ||
507 | self->close(); // deletes self | ||
641 | } | 508 | } |
642 | 509 | ||
643 | //static | 510 | //static |
644 | bool LLAlertDialog::parseAlerts(const std::string& xml_filename, LLControlGroup* settings, BOOL settings_only) | 511 | void LLAlertDialog::onClickIgnore(LLUICtrl* ctrl, void* user_data) |
645 | { | 512 | { |
646 | LLXMLNodePtr root; | 513 | LLAlertDialog* self = (LLAlertDialog*)user_data; |
647 | BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); | ||
648 | 514 | ||
649 | if (!success || root.isNull() || !root->hasName( "alerts" )) | 515 | // checkbox sometimes means "hide and do the default" and |
516 | // other times means "warn me again". Yuck. JC | ||
517 | BOOL check = ctrl->getValue(); | ||
518 | if (self->mNote->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) | ||
650 | { | 519 | { |
651 | llerrs << "Problem reading UI Alerts file: " << xml_filename << llendl; | 520 | // question was "show again" so invert value to get "ignore" |
652 | return false; | 521 | check = !check; |
653 | } | 522 | } |
654 | 523 | ||
655 | BOOL add_settings = FALSE; | 524 | self->mNote->setIgnored(check); |
656 | if (settings) | 525 | } |
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("global")) | ||
667 | { | ||
668 | std::string global_name; | ||
669 | if (alert->getAttributeString("name", global_name)) | ||
670 | { | ||
671 | if (global_name == "skipnexttime") | ||
672 | { | ||
673 | sStringSkipNextTime = alert->getTextContents(); | ||
674 | } | ||
675 | else if (global_name == "alwayschoose") | ||
676 | { | ||
677 | sStringAlwaysChoose = alert->getTextContents(); | ||
678 | } | ||
679 | } | ||
680 | continue; | ||
681 | } | ||
682 | |||
683 | if (!alert->hasName("alert")) | ||
684 | { | ||
685 | continue; | ||
686 | } | ||
687 | |||
688 | LLAlertDialogTemplate* xml_template = settings_only ? NULL : new LLAlertDialogTemplate; | ||
689 | |||
690 | // name= | ||
691 | std::string alert_name; | ||
692 | if (alert->getAttributeString("name", alert_name)) | ||
693 | { | ||
694 | if (xml_template) | ||
695 | { | ||
696 | xml_template->mLabel = alert_name; | ||
697 | } | ||
698 | } | ||
699 | else | ||
700 | { | ||
701 | llwarns << "Unable to parse alert with no name" << llendl; | ||
702 | delete xml_template; | ||
703 | continue; | ||
704 | } | ||
705 | // title= | ||
706 | std::string title; | ||
707 | if (alert->getAttributeString("title", title)) | ||
708 | { | ||
709 | if (xml_template) | ||
710 | { | ||
711 | xml_template->mTitle = title; | ||
712 | } | ||
713 | } | ||
714 | // modal= | ||
715 | BOOL modal; | ||
716 | if (alert->getAttributeBOOL("modal", modal)) | ||
717 | { | ||
718 | if (xml_template) | ||
719 | { | ||
720 | xml_template->mModal = modal; | ||
721 | } | ||
722 | } | ||
723 | // caution= | ||
724 | BOOL caution; | ||
725 | if (alert->getAttributeBOOL("caution", caution)) | ||
726 | { | ||
727 | if (xml_template) | ||
728 | { | ||
729 | xml_template->mCaution = caution; | ||
730 | } | ||
731 | } | ||
732 | // unique= | ||
733 | BOOL unique; | ||
734 | if (alert->getAttributeBOOL("unique", unique)) | ||
735 | { | ||
736 | if (xml_template) | ||
737 | { | ||
738 | xml_template->mUnique = unique; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | S32 default_option = 0; | ||
743 | BOOL nodefault; | ||
744 | if (alert->getAttributeBOOL("nodefault", nodefault)) | ||
745 | { | ||
746 | if (nodefault) | ||
747 | { | ||
748 | if (xml_template) | ||
749 | { | ||
750 | xml_template->mDefaultOption = -1; | ||
751 | } | ||
752 | default_option = -1; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | S32 btn_idx = 0; | ||
757 | for (LLXMLNode* child = alert->getFirstChild(); | ||
758 | child != NULL; child = child->getNextSibling()) | ||
759 | { | ||
760 | // <message> | ||
761 | if (child->hasName("message")) | ||
762 | { | ||
763 | if (xml_template) | ||
764 | { | ||
765 | xml_template->mMessage = child->getTextContents(); | ||
766 | } | ||
767 | } | ||
768 | 526 | ||
769 | // <option> | ||
770 | if (child->hasName("option")) | ||
771 | { | ||
772 | std::string label = child->getTextContents(); | ||
773 | BOOL is_default = FALSE; | ||
774 | child->getAttributeBOOL("default", is_default); | ||
775 | std::string ignore_text; | ||
776 | if (!child->getAttributeString("ignore", ignore_text)) | ||
777 | { | ||
778 | ignore_text = label; | ||
779 | } | ||
780 | if (xml_template) | ||
781 | { | ||
782 | xml_template->addOption(label, ignore_text, is_default); | ||
783 | } | ||
784 | if (is_default) | ||
785 | { | ||
786 | default_option = btn_idx; | ||
787 | } | ||
788 | btn_idx++; | ||
789 | } | ||
790 | |||
791 | // <editline> | ||
792 | if (child->hasName("editline")) | ||
793 | { | ||
794 | if (xml_template) | ||
795 | { | ||
796 | xml_template->mEditLineText = child->getTextContents(); | ||
797 | if (xml_template->mEditLineText.empty()) | ||
798 | { | ||
799 | xml_template->mEditLineText = " "; | ||
800 | } | ||
801 | } | ||
802 | } | ||
803 | |||
804 | // <ignore> | ||
805 | if (child->hasName("ignore")) | ||
806 | { | ||
807 | std::string ignore_text = child->getTextContents(); | ||
808 | // label= | ||
809 | std::string name; | ||
810 | child->getAttributeString("name", name); | ||
811 | |||
812 | //always set to alert_name for the sake of i18n | ||
813 | //if (name.empty()) | ||
814 | name = alert_name; | ||
815 | |||
816 | if (xml_template) | ||
817 | { | ||
818 | xml_template->mIgnorable = LLAlertDialog::IGNORE_USE_DEFAULT; | ||
819 | xml_template->mIgnoreListText = ignore_text; | ||
820 | xml_template->mIgnoreLabel = name; | ||
821 | } | ||
822 | if (!ignore_text.empty()) | ||
823 | { | ||
824 | if (add_settings) | ||
825 | { | ||
826 | settings->addWarning(name); | ||
827 | } | ||
828 | if (xml_template) | ||
829 | { | ||
830 | sIgnorableTemplates[name] = xml_template; // will override any previous entry | ||
831 | } | ||
832 | } | ||
833 | // save_option= | ||
834 | BOOL save_option = FALSE; | ||
835 | child->getAttributeBOOL("save_option", save_option); | ||
836 | if (save_option) | ||
837 | { | ||
838 | if (xml_template) | ||
839 | { | ||
840 | xml_template->mIgnorable = LLAlertDialog::IGNORE_USE_SAVED; | ||
841 | } | ||
842 | if (add_settings) | ||
843 | { | ||
844 | settings->declareS32(std::string("Default") + name, default_option, std::string("Default option number for this alert dialog")); | ||
845 | } | ||
846 | } | ||
847 | } | ||
848 | 527 | ||
849 | // <url> | ||
850 | if (child->hasName("url")) | ||
851 | { | ||
852 | S32 url_option = 0; | ||
853 | child->getAttributeS32("option", url_option); | ||
854 | if (xml_template) | ||
855 | { | ||
856 | xml_template->mURL = child->getTextContents(); | ||
857 | xml_template->mURLOption = url_option; | ||
858 | } | ||
859 | } | ||
860 | |||
861 | } | ||
862 | if (xml_template) | ||
863 | { | ||
864 | xml_template->mDefaultOption = default_option; | ||
865 | sAlertTemplates[xml_template->mLabel] = xml_template; | ||
866 | } | ||
867 | } | ||
868 | return true; | ||
869 | } | ||