aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui
diff options
context:
space:
mode:
authorJacek Antonelli2009-04-30 13:04:20 -0500
committerJacek Antonelli2009-04-30 13:07:16 -0500
commitca8149ca6d157eb4b5fc8ba0e5ba3a6e56f72e7e (patch)
tree8348301d0ac44a524f1819b777686bf086907d76 /linden/indra/llui
parentSecond Life viewer sources 1.22.11 (diff)
downloadmeta-impy-ca8149ca6d157eb4b5fc8ba0e5ba3a6e56f72e7e.zip
meta-impy-ca8149ca6d157eb4b5fc8ba0e5ba3a6e56f72e7e.tar.gz
meta-impy-ca8149ca6d157eb4b5fc8ba0e5ba3a6e56f72e7e.tar.bz2
meta-impy-ca8149ca6d157eb4b5fc8ba0e5ba3a6e56f72e7e.tar.xz
Second Life viewer sources 1.23.0-RC
Diffstat (limited to 'linden/indra/llui')
-rw-r--r--linden/indra/llui/CMakeLists.txt10
-rw-r--r--linden/indra/llui/llalertdialog.cpp766
-rw-r--r--linden/indra/llui/llalertdialog.h156
-rw-r--r--linden/indra/llui/llbutton.cpp13
-rw-r--r--linden/indra/llui/llbutton.h5
-rw-r--r--linden/indra/llui/llcallbackmap.h3
-rw-r--r--linden/indra/llui/llcheckboxctrl.cpp9
-rw-r--r--linden/indra/llui/llcheckboxctrl.h3
-rw-r--r--linden/indra/llui/llclipboard.cpp3
-rw-r--r--linden/indra/llui/llclipboard.h3
-rw-r--r--linden/indra/llui/llcombobox.cpp39
-rw-r--r--linden/indra/llui/llcombobox.h4
-rw-r--r--linden/indra/llui/llctrlselectioninterface.cpp3
-rw-r--r--linden/indra/llui/llctrlselectioninterface.h3
-rw-r--r--linden/indra/llui/lldraghandle.cpp3
-rw-r--r--linden/indra/llui/lldraghandle.h3
-rw-r--r--linden/indra/llui/lleditmenuhandler.cpp3
-rw-r--r--linden/indra/llui/lleditmenuhandler.h3
-rw-r--r--linden/indra/llui/llfloater.cpp12
-rw-r--r--linden/indra/llui/llfloater.h29
-rw-r--r--linden/indra/llui/llfocusmgr.cpp3
-rw-r--r--linden/indra/llui/llfocusmgr.h3
-rw-r--r--linden/indra/llui/llfunctorregistry.cpp38
-rw-r--r--linden/indra/llui/llfunctorregistry.h146
-rw-r--r--linden/indra/llui/llhtmlhelp.h3
-rw-r--r--linden/indra/llui/lliconctrl.cpp3
-rw-r--r--linden/indra/llui/lliconctrl.h3
-rw-r--r--linden/indra/llui/llkeywords.cpp3
-rw-r--r--linden/indra/llui/llkeywords.h3
-rw-r--r--linden/indra/llui/lllineeditor.cpp7
-rw-r--r--linden/indra/llui/lllineeditor.h3
-rw-r--r--linden/indra/llui/llmemberlistener.h3
-rw-r--r--linden/indra/llui/llmenugl.cpp31
-rw-r--r--linden/indra/llui/llmenugl.h3
-rw-r--r--linden/indra/llui/llmodaldialog.cpp3
-rw-r--r--linden/indra/llui/llmodaldialog.h3
-rw-r--r--linden/indra/llui/llmultislider.cpp3
-rw-r--r--linden/indra/llui/llmultislider.h3
-rw-r--r--linden/indra/llui/llmultisliderctrl.cpp5
-rw-r--r--linden/indra/llui/llmultisliderctrl.h3
-rw-r--r--linden/indra/llui/llnotifications.cpp1487
-rw-r--r--linden/indra/llui/llnotifications.h903
-rw-r--r--linden/indra/llui/llpanel.cpp142
-rw-r--r--linden/indra/llui/llpanel.h33
-rw-r--r--linden/indra/llui/llprogressbar.cpp181
-rw-r--r--linden/indra/llui/llprogressbar.h76
-rw-r--r--linden/indra/llui/llradiogroup.cpp3
-rw-r--r--linden/indra/llui/llradiogroup.h3
-rw-r--r--linden/indra/llui/llresizebar.cpp3
-rw-r--r--linden/indra/llui/llresizebar.h3
-rw-r--r--linden/indra/llui/llresizehandle.cpp3
-rw-r--r--linden/indra/llui/llresizehandle.h3
-rw-r--r--linden/indra/llui/llresmgr.cpp13
-rw-r--r--linden/indra/llui/llresmgr.h3
-rw-r--r--linden/indra/llui/llrootview.cpp3
-rw-r--r--linden/indra/llui/llrootview.h3
-rw-r--r--linden/indra/llui/llscrollbar.cpp90
-rw-r--r--linden/indra/llui/llscrollbar.h5
-rw-r--r--linden/indra/llui/llscrollcontainer.cpp3
-rw-r--r--linden/indra/llui/llscrollcontainer.h3
-rw-r--r--linden/indra/llui/llscrollingpanellist.cpp3
-rw-r--r--linden/indra/llui/llscrollingpanellist.h3
-rw-r--r--linden/indra/llui/llscrolllistctrl.cpp353
-rw-r--r--linden/indra/llui/llscrolllistctrl.h118
-rw-r--r--linden/indra/llui/llslider.cpp3
-rw-r--r--linden/indra/llui/llslider.h3
-rw-r--r--linden/indra/llui/llsliderctrl.cpp5
-rw-r--r--linden/indra/llui/llsliderctrl.h3
-rw-r--r--linden/indra/llui/llspinctrl.cpp7
-rw-r--r--linden/indra/llui/llspinctrl.h4
-rw-r--r--linden/indra/llui/llstyle.cpp3
-rw-r--r--linden/indra/llui/llstyle.h3
-rw-r--r--linden/indra/llui/lltabcontainer.cpp58
-rw-r--r--linden/indra/llui/lltabcontainer.h13
-rw-r--r--linden/indra/llui/lltabcontainervertical.cpp3
-rw-r--r--linden/indra/llui/lltabcontainervertical.h3
-rw-r--r--linden/indra/llui/lltextbox.cpp113
-rw-r--r--linden/indra/llui/lltextbox.h13
-rw-r--r--linden/indra/llui/lltexteditor.cpp109
-rw-r--r--linden/indra/llui/lltexteditor.h18
-rw-r--r--linden/indra/llui/lltextparser.cpp299
-rw-r--r--linden/indra/llui/lltextparser.h73
-rw-r--r--linden/indra/llui/llui.cpp31
-rw-r--r--linden/indra/llui/llui.h241
-rw-r--r--linden/indra/llui/lluiconstants.h3
-rw-r--r--linden/indra/llui/lluictrl.cpp27
-rw-r--r--linden/indra/llui/lluictrl.h9
-rw-r--r--linden/indra/llui/lluictrlfactory.cpp9
-rw-r--r--linden/indra/llui/lluictrlfactory.h6
-rw-r--r--linden/indra/llui/lluifwd.h3
-rw-r--r--linden/indra/llui/lluistring.cpp16
-rw-r--r--linden/indra/llui/lluistring.h9
-rw-r--r--linden/indra/llui/lluitrans.cpp101
-rw-r--r--linden/indra/llui/lluitrans.h87
-rw-r--r--linden/indra/llui/lluixmltags.h3
-rw-r--r--linden/indra/llui/llundo.cpp3
-rw-r--r--linden/indra/llui/llundo.h3
-rw-r--r--linden/indra/llui/llview.cpp63
-rw-r--r--linden/indra/llui/llview.h13
-rw-r--r--linden/indra/llui/llviewborder.cpp6
-rw-r--r--linden/indra/llui/llviewborder.h3
-rw-r--r--linden/indra/llui/llviewquery.cpp3
-rw-r--r--linden/indra/llui/llviewquery.h3
103 files changed, 4873 insertions, 1287 deletions
diff --git a/linden/indra/llui/CMakeLists.txt b/linden/indra/llui/CMakeLists.txt
index 77efec5..32118e8 100644
--- a/linden/indra/llui/CMakeLists.txt
+++ b/linden/indra/llui/CMakeLists.txt
@@ -36,6 +36,7 @@ set(llui_SOURCE_FILES
36 lleditmenuhandler.cpp 36 lleditmenuhandler.cpp
37 llfloater.cpp 37 llfloater.cpp
38 llfocusmgr.cpp 38 llfocusmgr.cpp
39 llfunctorregistry.cpp
39 lliconctrl.cpp 40 lliconctrl.cpp
40 llkeywords.cpp 41 llkeywords.cpp
41 lllineeditor.cpp 42 lllineeditor.cpp
@@ -43,7 +44,9 @@ set(llui_SOURCE_FILES
43 llmodaldialog.cpp 44 llmodaldialog.cpp
44 llmultislider.cpp 45 llmultislider.cpp
45 llmultisliderctrl.cpp 46 llmultisliderctrl.cpp
47 llnotifications.cpp
46 llpanel.cpp 48 llpanel.cpp
49 llprogressbar.cpp
47 llradiogroup.cpp 50 llradiogroup.cpp
48 llresizebar.cpp 51 llresizebar.cpp
49 llresizehandle.cpp 52 llresizehandle.cpp
@@ -61,10 +64,12 @@ set(llui_SOURCE_FILES
61 lltabcontainervertical.cpp 64 lltabcontainervertical.cpp
62 lltextbox.cpp 65 lltextbox.cpp
63 lltexteditor.cpp 66 lltexteditor.cpp
67 lltextparser.cpp
64 llui.cpp 68 llui.cpp
65 lluictrl.cpp 69 lluictrl.cpp
66 lluictrlfactory.cpp 70 lluictrlfactory.cpp
67 lluistring.cpp 71 lluistring.cpp
72 lluitrans.cpp
68 llundo.cpp 73 llundo.cpp
69 llviewborder.cpp 74 llviewborder.cpp
70 llview.cpp 75 llview.cpp
@@ -85,6 +90,7 @@ set(llui_HEADER_FILES
85 lleditmenuhandler.h 90 lleditmenuhandler.h
86 llfloater.h 91 llfloater.h
87 llfocusmgr.h 92 llfocusmgr.h
93 llfunctorregistry.h
88 llhtmlhelp.h 94 llhtmlhelp.h
89 lliconctrl.h 95 lliconctrl.h
90 llkeywords.h 96 llkeywords.h
@@ -94,7 +100,9 @@ set(llui_HEADER_FILES
94 llmodaldialog.h 100 llmodaldialog.h
95 llmultisliderctrl.h 101 llmultisliderctrl.h
96 llmultislider.h 102 llmultislider.h
103 llnotifications.h
97 llpanel.h 104 llpanel.h
105 llprogressbar.h
98 llradiogroup.h 106 llradiogroup.h
99 llresizebar.h 107 llresizebar.h
100 llresizehandle.h 108 llresizehandle.h
@@ -112,12 +120,14 @@ set(llui_HEADER_FILES
112 lltabcontainervertical.h 120 lltabcontainervertical.h
113 lltextbox.h 121 lltextbox.h
114 lltexteditor.h 122 lltexteditor.h
123 lltextparser.h
115 lluiconstants.h 124 lluiconstants.h
116 lluictrlfactory.h 125 lluictrlfactory.h
117 lluictrl.h 126 lluictrl.h
118 lluifwd.h 127 lluifwd.h
119 llui.h 128 llui.h
120 lluistring.h 129 lluistring.h
130 lluitrans.h
121 lluixmltags.h 131 lluixmltags.h
122 llundo.h 132 llundo.h
123 llviewborder.h 133 llviewborder.h
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
51const S32 MAX_ALLOWED_MSG_WIDTH = 400; 52const S32 MAX_ALLOWED_MSG_WIDTH = 400;
52const F32 DEFAULT_BUTTON_DELAY = 0.5f; 53const F32 DEFAULT_BUTTON_DELAY = 0.5f;
53const S32 MSG_PAD = 8; 54const 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
66LLAlertDialog* LLAlertDialog::createXml( const std::string& xml_desc, 60void 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
74LLAlertDialog* LLAlertDialog::createXml( const std::string& xml_desc, const LLStringUtil::format_map_t& args, 69bool 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
101LLAlertDialog* 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;
109LLAlertDialog* 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
117LLAlertDialog* 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
132static const S32 VPAD = 16; 102static const S32 VPAD = 16;
133static const S32 HPAD = 25; 103static const S32 HPAD = 25;
134static const S32 BTN_HPAD = 8; 104static const S32 BTN_HPAD = 8;
135static const LLFONT_ID font_name = LLFONT_SANSSERIF; 105static const LLFONT_ID FONT_NAME = LLFONT_SANSSERIF;
136 106
137LLAlertDialog::LLAlertDialog( const LLAlertDialogTemplate* xml_template, 107LLAlertDialog::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;
178bool 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
257void 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
266void 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.
328bool 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
402bool LLAlertDialog::setCheckBox( const std::string& check_title, const std::string& check_control ) 366bool 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 )
449void LLAlertDialog::onClose(bool app_quitting) 406void LLAlertDialog::onClose(bool app_quitting)
450{ 407{
451 LLModalDialog::onClose(app_quitting); 408 LLModalDialog::onClose(app_quitting);
452 handleCallbacks();
453} 409}
454 410
455LLAlertDialog::~LLAlertDialog() 411LLAlertDialog::~LLAlertDialog()
456{ 412{
457 delete[] mButtonData;
458 if (mUnique)
459 {
460 sUniqueActiveMap.erase(mLabel);
461 }
462} 413}
463 414
464void 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}
511BOOL LLAlertDialog::hasTitleBar() const 415BOOL 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
570void LLAlertDialog::setOptionEnabled( S32 option, BOOL enable ) 474void LLAlertDialog::setEditTextArgs(const LLSD& edit_args)
571{
572 if( (option >= 0) && (option < mNumOptions) )
573 {
574 mButtonData[option].mButton->setEnabled( enable );
575 }
576}
577
578void 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
591void 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
605void 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
618void LLAlertDialog::onButtonPressed( void* userdata ) 488void 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
630const 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
644bool LLAlertDialog::parseAlerts(const std::string& xml_filename, LLControlGroup* settings, BOOL settings_only) 511void 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}
diff --git a/linden/indra/llui/llalertdialog.h b/linden/indra/llui/llalertdialog.h
index 7d82fb5..04caea6 100644
--- a/linden/indra/llui/llalertdialog.h
+++ b/linden/indra/llui/llalertdialog.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -36,6 +37,7 @@
36#include "llmodaldialog.h" 37#include "llmodaldialog.h"
37#include "llmemory.h" 38#include "llmemory.h"
38#include "llui.h" 39#include "llui.h"
40#include "llnotifications.h"
39 41
40class LLButton; 42class LLButton;
41class LLCheckBoxCtrl; 43class LLCheckBoxCtrl;
@@ -43,21 +45,20 @@ class LLAlertDialogTemplate;
43class LLLineEditor; 45class LLLineEditor;
44 46
45// https://wiki.lindenlab.com/mediawiki/index.php?title=LLAlertDialog&oldid=81388 47// https://wiki.lindenlab.com/mediawiki/index.php?title=LLAlertDialog&oldid=81388
46class LLAlertDialog : public LLModalDialog 48class LLAlertDialog
49 : public LLModalDialog,
50 public LLInitClass<LLAlertDialog>,
51 public LLInstanceTracker<LLAlertDialog, LLUUID>
52
47{ 53{
48public: 54public:
49 typedef void (*alert_callback_t)(S32 option, void* user_data);
50 typedef void (*alert_text_callback_t)(S32 option, const std::string& text, void* user_data);
51 typedef bool (*display_callback_t)(S32 modal); 55 typedef bool (*display_callback_t)(S32 modal);
52 typedef std::vector<std::string> options_list_t;
53
54 enum { IGNORE_USE_DEFAULT=1, IGNORE_USE_SAVED=2, IGNORE_SHOW_AGAIN=3 };
55 56
56 class URLLoader 57 class URLLoader
57 { 58 {
58 public: 59 public:
59 virtual void load(const std::string& url) = 0; 60 virtual void load(const std::string& url) = 0;
60 virtual ~URLLoader() {} 61 virtual ~URLLoader() {}
61 }; 62 };
62 63
63 static void setURLLoader(URLLoader* loader) 64 static void setURLLoader(URLLoader* loader)
@@ -67,8 +68,7 @@ public:
67 68
68public: 69public:
69 // User's responsibility to call show() after creating these. 70 // User's responsibility to call show() after creating these.
70 LLAlertDialog( const LLAlertDialogTemplate* xml_template, const LLStringUtil::format_map_t& args, 71 LLAlertDialog( LLNotificationPtr notep, bool is_modal );
71 alert_callback_t callback = NULL, void *user_data = NULL);
72 72
73 virtual BOOL handleKeyHere(KEY key, MASK mask ); 73 virtual BOOL handleKeyHere(KEY key, MASK mask );
74 74
@@ -77,150 +77,52 @@ public:
77 virtual void onClose(bool app_quitting); 77 virtual void onClose(bool app_quitting);
78 78
79 bool setCheckBox( const std::string&, const std::string& ); 79 bool setCheckBox( const std::string&, const std::string& );
80 void setOptionEnabled( S32 option, BOOL enable );
81 void setCaution(BOOL val = TRUE) { mCaution = val; } 80 void setCaution(BOOL val = TRUE) { mCaution = val; }
82 // If mUnique==TRUE only one copy of this message should exist 81 // If mUnique==TRUE only one copy of this message should exist
83 void setUnique(BOOL val = TRUE) { mUnique = val; } 82 void setUnique(BOOL val = TRUE) { mUnique = val; }
84 void setEditTextCallback(alert_text_callback_t callback, void *user_data); 83 void setEditTextArgs(const LLSD& edit_args);
85 void setEditTextArgs(const LLStringUtil::format_map_t& edit_args);
86 void setDrawAsterixes(BOOL enable);
87 84
88 bool show(); // May instantly destroy the message if it is unique (returns false) 85 bool show(); // May instantly destroy the message if it is unique (returns false)
89 86
90 //statics 87 //statics
91 static void onButtonPressed(void* userdata); 88 static void initClass();
92 89 static bool onNewNotification(const LLSD& notify, bool is_modal);
93 static LLAlertDialog* createXml( const std::string& xml_desc, 90 static void onButtonPressed(void* userdata);
94 alert_callback_t callback = NULL, void *user_data = NULL); 91 static void onClickIgnore(LLUICtrl* ctrl, void* user_data);
95 static LLAlertDialog* createXml( const std::string& xml_desc, const LLStringUtil::format_map_t& args,
96 alert_callback_t callback = NULL, void *user_data = NULL);
97
98 static LLAlertDialog* showXml( const std::string& xml_desc,
99 alert_callback_t callback = NULL, void *user_data = NULL);
100 static LLAlertDialog* showXml( const std::string& xml_desc, const LLStringUtil::format_map_t& args,
101 alert_callback_t callback = NULL, void *user_data = NULL);
102
103 static LLAlertDialog* showCritical( const std::string& msg, alert_callback_t callback = NULL, void *user_data = NULL);
104
105 static bool parseAlerts(const std::string& xml_filename, LLControlGroup* settings = NULL, BOOL settings_only = FALSE);
106 static const std::string& getTemplateMessage(const std::string& xml_desc);
107
108 static void setDisplayCallback(display_callback_t callback) { sDisplayCallback = callback; }
109
110private:
111 void format(std::string& msg, const LLStringUtil::format_map_t& args);
112
113public:
114 static LLControlGroup* sSettings;
115
116 // use LLPointer so they delete themselves when sTemplates is destroyed
117 typedef std::map<std::string, LLPointer<LLAlertDialogTemplate> > template_map_t;
118 static template_map_t sAlertTemplates; // by mLabel
119 static template_map_t sIgnorableTemplates; // by mIgnoreLabel
120 92
121private: 93private:
94 LLNotificationPtr mNote;
122 95
123 static std::map<std::string, LLAlertDialog*> sUniqueActiveMap; 96 static std::map<std::string, LLAlertDialog*> sUniqueActiveMap;
124 static display_callback_t sDisplayCallback;
125 97
126 static std::string sStringSkipNextTime;
127 static std::string sStringAlwaysChoose;
128
129 void createDialog(const options_list_t& options_in, S32 default_option,
130 const std::string& msg, const LLStringUtil::format_map_t& args,
131 const std::string& edit_text);
132
133 virtual ~LLAlertDialog(); 98 virtual ~LLAlertDialog();
134 void handleCallbacks();
135 // No you can't kill it. It can only kill itself. 99 // No you can't kill it. It can only kill itself.
136 100
137 // Does it have a readable title label, or minimize or close buttons? 101 // Does it have a readable title label, or minimize or close buttons?
138 BOOL hasTitleBar() const; 102 BOOL hasTitleBar() const;
139 103
104private:
105 static URLLoader* sURLLoader;
106 static LLControlGroup* sSettings;
107
140 struct ButtonData 108 struct ButtonData
141 { 109 {
142 LLAlertDialog* mSelf; 110 LLAlertDialog* mSelf;
143 LLButton* mButton; 111 LLButton* mButton;
144 S32 mOption; 112 std::string mURL;
145 } * mButtonData; 113 };
146 114 std::vector<ButtonData> mButtonData;
147 alert_callback_t mCallback; 115
148 void* mUserData; 116 S32 mDefaultOption;
149 S32 mNumOptions;
150 S32 mDefaultOption;
151 BOOL mOptionChosen;
152 LLCheckBoxCtrl* mCheck; 117 LLCheckBoxCtrl* mCheck;
153 BOOL mCaution; 118 BOOL mCaution;
154 BOOL mUnique; 119 BOOL mUnique;
155 S32 mIgnorable; 120 std::string mLabel;
156 std::string mLabel; 121 LLFrameTimer mDefaultBtnTimer;
157 std::string mIgnoreLabel;
158 LLFrameTimer mDefaultBtnTimer;
159 // For Dialogs that take a line as text as input: 122 // For Dialogs that take a line as text as input:
160 LLLineEditor* mLineEditor; 123 LLLineEditor* mLineEditor;
161 alert_text_callback_t mTextCallback;
162 // For Dialogs linked to a URL
163 std::string mURL; // Some alerts will direct the resident to a URL
164 S32 mURLOption;
165 124
166private:
167 static URLLoader* sURLLoader;
168}; 125};
169 126
170//============================================================================
171
172class LLAlertDialogTemplate : public LLRefCount
173{
174public:
175 LLAlertDialogTemplate() : mTitle(), mURLOption(0), mModal(FALSE), mCaution(FALSE), mUnique(FALSE), mIgnorable(0), mDefaultOption(0) {}
176
177 void addOption(const std::string& label, const std::string& ignore_text, BOOL is_default = FALSE)
178 {
179 if (is_default)
180 {
181 mDefaultOption = mOptions.size();
182 }
183 mOptions.push_back(label);
184 mOptionDefaultText.push_back(ignore_text);
185 }
186
187 S32 getIgnore()
188 {
189 if (mIgnorable)
190 {
191 return LLAlertDialog::sSettings->getWarning(mIgnoreLabel) ? FALSE : mIgnorable;
192 }
193 else
194 {
195 return FALSE;
196 }
197 }
198
199 void setIgnore(bool state)
200 {
201 if (mIgnorable)
202 {
203 LLAlertDialog::sSettings->setWarning(mIgnoreLabel, !state);
204 }
205 }
206
207
208public:
209 std::string mLabel; // Handle for access from code, etc
210 std::string mTitle; // (optional) text to display in title bar
211 std::string mMessage; // Message to display
212 std::string mIgnoreListText; // Text to display in enable/disable dialog (if mIgnorable == TRUE)
213 std::string mIgnoreLabel; // Handle for ignore variable (may be shared by multiple templates)
214 std::string mURL; // Some alerts will direct the resident to a URL
215 S32 mURLOption;
216 BOOL mModal;
217 BOOL mCaution;
218 BOOL mUnique;
219 S32 mIgnorable; // 0 = Never Ignore, 1 = Do default option, 2 = Do saved option
220 LLAlertDialog::options_list_t mOptions;
221 LLAlertDialog::options_list_t mOptionDefaultText;
222 S32 mDefaultOption;
223 std::string mEditLineText;
224};
225 127
226#endif // LL_ALERTDIALOG_H 128#endif // LL_ALERTDIALOG_H
diff --git a/linden/indra/llui/llbutton.cpp b/linden/indra/llui/llbutton.cpp
index 34e62c8..2c2c1c2 100644
--- a/linden/indra/llui/llbutton.cpp
+++ b/linden/indra/llui/llbutton.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -187,7 +188,7 @@ LLButton::LLButton(const std::string& name, const LLRect& rect,
187 188
188void LLButton::init(void (*click_callback)(void*), void *callback_data, const LLFontGL* font, const std::string& control_name) 189void LLButton::init(void (*click_callback)(void*), void *callback_data, const LLFontGL* font, const std::string& control_name)
189{ 190{
190 mGLFont = ( font ? font : LLFontGL::sSansSerif); 191 mGLFont = ( font ? font : LLFontGL::getFontSansSerif());
191 192
192 // Hack to make sure there is space for at least one character 193 // Hack to make sure there is space for at least one character
193 if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" "))) 194 if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" ")))
@@ -422,13 +423,7 @@ void LLButton::draw()
422 // Unselected image assignments 423 // Unselected image assignments
423 S32 local_mouse_x; 424 S32 local_mouse_x;
424 S32 local_mouse_y; 425 S32 local_mouse_y;
425 LLCoordWindow cursor_pos_window; 426 LLUI::getCursorPositionLocal(this, &local_mouse_x, &local_mouse_y);
426 getWindow()->getCursorPosition(&cursor_pos_window);
427 LLCoordGL cursor_pos_gl;
428 getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl);
429 cursor_pos_gl.mX = llround((F32)cursor_pos_gl.mX / LLUI::sGLScaleFactor.mV[VX]);
430 cursor_pos_gl.mY = llround((F32)cursor_pos_gl.mY / LLUI::sGLScaleFactor.mV[VY]);
431 screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, &local_mouse_x, &local_mouse_y);
432 427
433 BOOL pressed = pressed_by_keyboard 428 BOOL pressed = pressed_by_keyboard
434 || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y)) 429 || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y))
diff --git a/linden/indra/llui/llbutton.h b/linden/indra/llui/llbutton.h
index 556e12c..724b775 100644
--- a/linden/indra/llui/llbutton.h
+++ b/linden/indra/llui/llbutton.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -163,7 +164,7 @@ public:
163 void setDisabledLabelColor( const LLColor4& c ) { mDisabledLabelColor = c; } 164 void setDisabledLabelColor( const LLColor4& c ) { mDisabledLabelColor = c; }
164 165
165 void setFont(const LLFontGL *font) 166 void setFont(const LLFontGL *font)
166 { mGLFont = ( font ? font : LLFontGL::sSansSerif); } 167 { mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); }
167 void setScaleImage(BOOL scale) { mScaleImage = scale; } 168 void setScaleImage(BOOL scale) { mScaleImage = scale; }
168 BOOL getScaleImage() const { return mScaleImage; } 169 BOOL getScaleImage() const { return mScaleImage; }
169 170
diff --git a/linden/indra/llui/llcallbackmap.h b/linden/indra/llui/llcallbackmap.h
index db11c39..eadb9c9 100644
--- a/linden/indra/llui/llcallbackmap.h
+++ b/linden/indra/llui/llcallbackmap.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llcheckboxctrl.cpp b/linden/indra/llui/llcheckboxctrl.cpp
index d4c372a..eda9467 100644
--- a/linden/indra/llui/llcheckboxctrl.cpp
+++ b/linden/indra/llui/llcheckboxctrl.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -72,7 +73,7 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const std::string& name, const LLRect& rect,
72 } 73 }
73 else 74 else
74 { 75 {
75 mFont = LLFontGL::sSansSerifSmall; 76 mFont = LLFontGL::getFontSansSerifSmall();
76 } 77 }
77 78
78 // must be big enough to hold all children 79 // must be big enough to hold all children
@@ -122,7 +123,7 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const std::string& name, const LLRect& rect,
122 inactive_false_id = "UIImgRadioInactiveUUID"; 123 inactive_false_id = "UIImgRadioInactiveUUID";
123 mButton = new LLButton(std::string("Radio control button"), btn_rect, 124 mButton = new LLButton(std::string("Radio control button"), btn_rect,
124 active_false_id, active_true_id, control_which, 125 active_false_id, active_true_id, control_which,
125 &LLCheckBoxCtrl::onButtonPress, this, LLFontGL::sSansSerif ); 126 &LLCheckBoxCtrl::onButtonPress, this, LLFontGL::getFontSansSerif() );
126 mButton->setDisabledImages( inactive_false_id, inactive_true_id ); 127 mButton->setDisabledImages( inactive_false_id, inactive_true_id );
127 mButton->setHoverGlowStrength(0.35f); 128 mButton->setHoverGlowStrength(0.35f);
128 } 129 }
@@ -134,7 +135,7 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const std::string& name, const LLRect& rect,
134 inactive_false_id = "UIImgCheckboxInactiveUUID"; 135 inactive_false_id = "UIImgCheckboxInactiveUUID";
135 mButton = new LLButton(std::string("Checkbox control button"), btn_rect, 136 mButton = new LLButton(std::string("Checkbox control button"), btn_rect,
136 active_false_id, active_true_id, control_which, 137 active_false_id, active_true_id, control_which,
137 &LLCheckBoxCtrl::onButtonPress, this, LLFontGL::sSansSerif ); 138 &LLCheckBoxCtrl::onButtonPress, this, LLFontGL::getFontSansSerif() );
138 mButton->setDisabledImages( inactive_false_id, inactive_true_id ); 139 mButton->setDisabledImages( inactive_false_id, inactive_true_id );
139 mButton->setHoverGlowStrength(0.35f); 140 mButton->setHoverGlowStrength(0.35f);
140 } 141 }
diff --git a/linden/indra/llui/llcheckboxctrl.h b/linden/indra/llui/llcheckboxctrl.h
index 8a70c62..ff867f5 100644
--- a/linden/indra/llui/llcheckboxctrl.h
+++ b/linden/indra/llui/llcheckboxctrl.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llclipboard.cpp b/linden/indra/llui/llclipboard.cpp
index d5255e7..8a7a214 100644
--- a/linden/indra/llui/llclipboard.cpp
+++ b/linden/indra/llui/llclipboard.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llclipboard.h b/linden/indra/llui/llclipboard.h
index 706ed2a..37ed1ff 100644
--- a/linden/indra/llui/llclipboard.h
+++ b/linden/indra/llui/llclipboard.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llcombobox.cpp b/linden/indra/llui/llcombobox.cpp
index 3aec2ee..28a05c1 100644
--- a/linden/indra/llui/llcombobox.cpp
+++ b/linden/indra/llui/llcombobox.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -72,11 +73,12 @@ LLComboBox::LLComboBox( const std::string& name, const LLRect &rect, const std::
72 mTextEntryTentative(TRUE), 73 mTextEntryTentative(TRUE),
73 mListPosition(BELOW), 74 mListPosition(BELOW),
74 mPrearrangeCallback( NULL ), 75 mPrearrangeCallback( NULL ),
75 mTextEntryCallback( NULL ) 76 mTextEntryCallback( NULL ),
77 mLabel(label)
76{ 78{
77 // Always use text box 79 // Always use text box
78 // Text label button 80 // Text label button
79 mButton = new LLButton(label, 81 mButton = new LLButton(mLabel,
80 LLRect(), 82 LLRect(),
81 LLStringUtil::null, 83 LLStringUtil::null,
82 NULL, this); 84 NULL, this);
@@ -87,7 +89,7 @@ LLComboBox::LLComboBox( const std::string& name, const LLRect &rect, const std::
87 mButton->setScaleImage(TRUE); 89 mButton->setScaleImage(TRUE);
88 90
89 mButton->setMouseDownCallback(onButtonDown); 91 mButton->setMouseDownCallback(onButtonDown);
90 mButton->setFont(LLFontGL::sSansSerifSmall); 92 mButton->setFont(LLFontGL::getFontSansSerifSmall());
91 mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT); 93 mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
92 mButton->setHAlign( LLFontGL::LEFT ); 94 mButton->setHAlign( LLFontGL::LEFT );
93 mButton->setRightHPad(2); 95 mButton->setRightHPad(2);
@@ -197,7 +199,12 @@ LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *
197 } 199 }
198 } 200 }
199 201
200 combo_box->selectFirstItem(); 202 // if providing user text entry or descriptive label
203 // don't select an item under the hood
204 if (!combo_box->acceptsTextInput() && combo_box->mLabel.empty())
205 {
206 combo_box->selectFirstItem();
207 }
201 208
202 return combo_box; 209 return combo_box;
203} 210}
@@ -259,7 +266,10 @@ LLScrollListItem* LLComboBox::add(const std::string& name, EAddPosition pos, BOO
259{ 266{
260 LLScrollListItem* item = mList->addSimpleElement(name, pos); 267 LLScrollListItem* item = mList->addSimpleElement(name, pos);
261 item->setEnabled(enabled); 268 item->setEnabled(enabled);
262 mList->selectFirstItem(); 269 if (!mAllowTextEntry && mLabel.empty())
270 {
271 selectFirstItem();
272 }
263 return item; 273 return item;
264} 274}
265 275
@@ -268,7 +278,10 @@ LLScrollListItem* LLComboBox::add(const std::string& name, const LLUUID& id, EAd
268{ 278{
269 LLScrollListItem* item = mList->addSimpleElement(name, pos, id); 279 LLScrollListItem* item = mList->addSimpleElement(name, pos, id);
270 item->setEnabled(enabled); 280 item->setEnabled(enabled);
271 mList->selectFirstItem(); 281 if (!mAllowTextEntry && mLabel.empty())
282 {
283 selectFirstItem();
284 }
272 return item; 285 return item;
273} 286}
274 287
@@ -278,7 +291,10 @@ LLScrollListItem* LLComboBox::add(const std::string& name, void* userdata, EAddP
278 LLScrollListItem* item = mList->addSimpleElement(name, pos); 291 LLScrollListItem* item = mList->addSimpleElement(name, pos);
279 item->setEnabled(enabled); 292 item->setEnabled(enabled);
280 item->setUserdata( userdata ); 293 item->setUserdata( userdata );
281 mList->selectFirstItem(); 294 if (!mAllowTextEntry && mLabel.empty())
295 {
296 selectFirstItem();
297 }
282 return item; 298 return item;
283} 299}
284 300
@@ -287,7 +303,10 @@ LLScrollListItem* LLComboBox::add(const std::string& name, LLSD value, EAddPosit
287{ 303{
288 LLScrollListItem* item = mList->addSimpleElement(name, pos, value); 304 LLScrollListItem* item = mList->addSimpleElement(name, pos, value);
289 item->setEnabled(enabled); 305 item->setEnabled(enabled);
290 mList->selectFirstItem(); 306 if (!mAllowTextEntry && mLabel.empty())
307 {
308 selectFirstItem();
309 }
291 return item; 310 return item;
292} 311}
293 312
@@ -498,7 +517,7 @@ void LLComboBox::updateLayout()
498 mTextEntry = new LLLineEditor(std::string("combo_text_entry"), 517 mTextEntry = new LLLineEditor(std::string("combo_text_entry"),
499 text_entry_rect, 518 text_entry_rect,
500 LLStringUtil::null, 519 LLStringUtil::null,
501 LLFontGL::sSansSerifSmall, 520 LLFontGL::getFontSansSerifSmall(),
502 mMaxChars, 521 mMaxChars,
503 onTextCommit, 522 onTextCommit,
504 onTextEntry, 523 onTextEntry,
diff --git a/linden/indra/llui/llcombobox.h b/linden/indra/llui/llcombobox.h
index efcb798..33e1baa 100644
--- a/linden/indra/llui/llcombobox.h
+++ b/linden/indra/llui/llcombobox.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -188,6 +189,7 @@ protected:
188 LLScrollListCtrl* mList; 189 LLScrollListCtrl* mList;
189 EPreferredPosition mListPosition; 190 EPreferredPosition mListPosition;
190 LLPointer<LLUIImage> mArrowImage; 191 LLPointer<LLUIImage> mArrowImage;
192 std::string mLabel;
191 193
192private: 194private:
193 S32 mButtonPadding; 195 S32 mButtonPadding;
diff --git a/linden/indra/llui/llctrlselectioninterface.cpp b/linden/indra/llui/llctrlselectioninterface.cpp
index 282f43c..dac0939 100644
--- a/linden/indra/llui/llctrlselectioninterface.cpp
+++ b/linden/indra/llui/llctrlselectioninterface.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llctrlselectioninterface.h b/linden/indra/llui/llctrlselectioninterface.h
index 6f5f5c8..45727d6 100644
--- a/linden/indra/llui/llctrlselectioninterface.h
+++ b/linden/indra/llui/llctrlselectioninterface.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lldraghandle.cpp b/linden/indra/llui/lldraghandle.cpp
index c76bdfb..6c92ea1 100644
--- a/linden/indra/llui/lldraghandle.cpp
+++ b/linden/indra/llui/lldraghandle.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lldraghandle.h b/linden/indra/llui/lldraghandle.h
index 35408da..9eb3e55 100644
--- a/linden/indra/llui/lldraghandle.h
+++ b/linden/indra/llui/lldraghandle.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lleditmenuhandler.cpp b/linden/indra/llui/lleditmenuhandler.cpp
index d6f04f2..821afae 100644
--- a/linden/indra/llui/lleditmenuhandler.cpp
+++ b/linden/indra/llui/lleditmenuhandler.cpp
@@ -17,7 +17,8 @@
17* There are special exceptions to the terms and conditions of the GPL as 17* 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 18* 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 19* in the file doc/FLOSS-exception.txt in this software distribution, or
20* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20* online at
21* http://secondlifegrid.net/programs/open_source/licensing/flossexception
21* 22*
22* By copying, modifying or distributing this software, you acknowledge 23* By copying, modifying or distributing this software, you acknowledge
23* that you have read and understood your obligations described above, 24* that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lleditmenuhandler.h b/linden/indra/llui/lleditmenuhandler.h
index c0c6d7b..1de9c56 100644
--- a/linden/indra/llui/lleditmenuhandler.h
+++ b/linden/indra/llui/lleditmenuhandler.h
@@ -17,7 +17,8 @@
17* There are special exceptions to the terms and conditions of the GPL as 17* 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 18* 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 19* in the file doc/FLOSS-exception.txt in this software distribution, or
20* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20* online at
21* http://secondlifegrid.net/programs/open_source/licensing/flossexception
21* 22*
22* By copying, modifying or distributing this software, you acknowledge 23* By copying, modifying or distributing this software, you acknowledge
23* that you have read and understood your obligations described above, 24* that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llfloater.cpp b/linden/indra/llui/llfloater.cpp
index 2924c29..94af186 100644
--- a/linden/indra/llui/llfloater.cpp
+++ b/linden/indra/llui/llfloater.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -147,6 +148,7 @@ LLFloater::LLFloater() :
147 } 148 }
148 mDragHandle = NULL; 149 mDragHandle = NULL;
149 mHandle.bind(this); 150 mHandle.bind(this);
151 mNotificationContext = new LLFloaterNotificationContext(getHandle());
150} 152}
151 153
152LLFloater::LLFloater(const std::string& name) 154LLFloater::LLFloater(const std::string& name)
@@ -220,6 +222,7 @@ void LLFloater::initFloater(const std::string& title,
220 BOOL drag_on_left, BOOL minimizable, BOOL close_btn) 222 BOOL drag_on_left, BOOL minimizable, BOOL close_btn)
221{ 223{
222 mHandle.bind(this); 224 mHandle.bind(this);
225 mNotificationContext = new LLFloaterNotificationContext(getHandle());
223 226
224 // Init function can be called more than once, so clear out old data. 227 // Init function can be called more than once, so clear out old data.
225 for (S32 i = 0; i < BUTTON_COUNT; i++) 228 for (S32 i = 0; i < BUTTON_COUNT; i++)
@@ -429,6 +432,9 @@ void LLFloater::initFloater(const std::string& title,
429// virtual 432// virtual
430LLFloater::~LLFloater() 433LLFloater::~LLFloater()
431{ 434{
435 delete mNotificationContext;
436 mNotificationContext = NULL;
437
432 control_map_t::iterator itor; 438 control_map_t::iterator itor;
433 for (itor = mFloaterControls.begin(); itor != mFloaterControls.end(); ++itor) 439 for (itor = mFloaterControls.begin(); itor != mFloaterControls.end(); ++itor)
434 { 440 {
@@ -774,7 +780,7 @@ void LLFloater::snappedTo(const LLView* snap_view)
774 780
775void LLFloater::userSetShape(const LLRect& new_rect) 781void LLFloater::userSetShape(const LLRect& new_rect)
776{ 782{
777 const LLRect& old_rect = getRect(); 783 const LLRect old_rect = getRect();
778 LLView::userSetShape(new_rect); 784 LLView::userSetShape(new_rect);
779 785
780 // if not minimized, adjust all snapped dependents to new shape 786 // if not minimized, adjust all snapped dependents to new shape
@@ -1697,7 +1703,7 @@ void LLFloater::buildButtons()
1697 LLStringUtil::null, 1703 LLStringUtil::null,
1698 sButtonCallbacks[i], 1704 sButtonCallbacks[i],
1699 this, 1705 this,
1700 LLFontGL::sSansSerif); 1706 LLFontGL::getFontSansSerif());
1701 1707
1702 buttonp->setTabStop(FALSE); 1708 buttonp->setTabStop(FALSE);
1703 buttonp->setFollowsTop(); 1709 buttonp->setFollowsTop();
diff --git a/linden/indra/llui/llfloater.h b/linden/indra/llui/llfloater.h
index a6fe3cc..a8f7c21 100644
--- a/linden/indra/llui/llfloater.h
+++ b/linden/indra/llui/llfloater.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -39,6 +40,7 @@
39#include "llpanel.h" 40#include "llpanel.h"
40#include "lluuid.h" 41#include "lluuid.h"
41#include "lltabcontainer.h" 42#include "lltabcontainer.h"
43#include "llnotifications.h"
42#include <set> 44#include <set>
43 45
44class LLDragHandle; 46class LLDragHandle;
@@ -46,6 +48,7 @@ class LLResizeHandle;
46class LLResizeBar; 48class LLResizeBar;
47class LLButton; 49class LLButton;
48class LLMultiFloater; 50class LLMultiFloater;
51class LLFloater;
49 52
50const S32 LLFLOATER_VPAD = 6; 53const S32 LLFLOATER_VPAD = 6;
51const S32 LLFLOATER_HPAD = 6; 54const S32 LLFLOATER_HPAD = 6;
@@ -70,6 +73,20 @@ const BOOL CLOSE_NO = FALSE;
70const BOOL ADJUST_VERTICAL_YES = TRUE; 73const BOOL ADJUST_VERTICAL_YES = TRUE;
71const BOOL ADJUST_VERTICAL_NO = FALSE; 74const BOOL ADJUST_VERTICAL_NO = FALSE;
72 75
76// associates a given notification instance with a particular floater
77class LLFloaterNotificationContext :
78 public LLNotificationContext
79{
80public:
81 LLFloaterNotificationContext(LLHandle<LLFloater> floater_handle) :
82 mFloaterHandle(floater_handle)
83 {}
84
85 LLFloater* getFloater() { return mFloaterHandle.get(); }
86private:
87 LLHandle<LLFloater> mFloaterHandle;
88};
89
73 90
74class LLFloater : public LLPanel 91class LLFloater : public LLPanel
75{ 92{
@@ -213,6 +230,11 @@ public:
213 // handle refocusing. 230 // handle refocusing.
214 static void closeFocusedFloater(); 231 static void closeFocusedFloater();
215 232
233 LLNotification::Params contextualNotification(const std::string& name)
234 {
235 return LLNotification::Params(name).context(mNotificationContext);
236 }
237
216 static void onClickClose(void *userdata); 238 static void onClickClose(void *userdata);
217 static void onClickMinimize(void *userdata); 239 static void onClickMinimize(void *userdata);
218 static void onClickTearOff(void *userdata); 240 static void onClickTearOff(void *userdata);
@@ -299,7 +321,7 @@ private:
299 S32 mPreviousMinimizedBottom; 321 S32 mPreviousMinimizedBottom;
300 S32 mPreviousMinimizedLeft; 322 S32 mPreviousMinimizedLeft;
301 323
302private: 324 LLFloaterNotificationContext* mNotificationContext;
303 LLRootHandle<LLFloater> mHandle; 325 LLRootHandle<LLFloater> mHandle;
304}; 326};
305 327
@@ -461,13 +483,12 @@ public:
461 483
462 484
463// singleton implementation for floaters (provides visibility policy) 485// singleton implementation for floaters (provides visibility policy)
464// https://wiki.lindenlab.com/mediawiki/index.php?title=LLFloaterSingleton&oldid=79410 486// https://wiki.lindenlab.com/mediawiki/index.php?title=LLFloaterSingleton&oldid=164990
465 487
466template <class T> class LLFloaterSingleton : public LLUISingleton<T, VisibilityPolicy<LLFloater> > 488template <class T> class LLFloaterSingleton : public LLUISingleton<T, VisibilityPolicy<LLFloater> >
467{ 489{
468}; 490};
469 491
470
471extern LLFloaterView* gFloaterView; 492extern LLFloaterView* gFloaterView;
472 493
473#endif // LL_FLOATER_H 494#endif // LL_FLOATER_H
diff --git a/linden/indra/llui/llfocusmgr.cpp b/linden/indra/llui/llfocusmgr.cpp
index 69010cd..661ffdd 100644
--- a/linden/indra/llui/llfocusmgr.cpp
+++ b/linden/indra/llui/llfocusmgr.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llfocusmgr.h b/linden/indra/llui/llfocusmgr.h
index 61daca7..aaeb25a 100644
--- a/linden/indra/llui/llfocusmgr.h
+++ b/linden/indra/llui/llfocusmgr.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llfunctorregistry.cpp b/linden/indra/llui/llfunctorregistry.cpp
new file mode 100644
index 0000000..0c5b165
--- /dev/null
+++ b/linden/indra/llui/llfunctorregistry.cpp
@@ -0,0 +1,38 @@
1/**
2 * @file llfunctorregistry.cpp
3 * @author Kent Quirk
4 * @brief Maintains a registry of named callback functors taking a single LLSD parameter
5 *
6 * $LicenseInfo:firstyear=2008&license=viewergpl$
7 *
8 * Copyright (c) 2008-2009, Linden Research, Inc.
9 *
10 * Second Life Viewer Source Code
11 * The source code in this file ("Source Code") is provided by Linden Lab
12 * to you under the terms of the GNU General Public License, version 2.0
13 * ("GPL"), unless you have obtained a separate licensing agreement
14 * ("Other License"), formally executed by you and Linden Lab. Terms of
15 * the GPL can be found in doc/GPL-license.txt in this distribution, or
16 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
17 *
18 * There are special exceptions to the terms and conditions of the GPL as
19 * it is applied to this Source Code. View the full text of the exception
20 * in the file doc/FLOSS-exception.txt in this software distribution, or
21 * online at
22 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
23 *
24 * By copying, modifying or distributing this software, you acknowledge
25 * that you have read and understood your obligations described above,
26 * and agree to abide by those obligations.
27 *
28 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
29 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
30 * COMPLETENESS OR PERFORMANCE.
31 * $/LicenseInfo$
32 **/
33
34#include "llfunctorregistry.h"
35
36// This is a default functor always resident in the system.
37// It's used whenever a functor isn't found in the registry, so that
38// we at least log the data relating to the user response.
diff --git a/linden/indra/llui/llfunctorregistry.h b/linden/indra/llui/llfunctorregistry.h
new file mode 100644
index 0000000..8864f7a
--- /dev/null
+++ b/linden/indra/llui/llfunctorregistry.h
@@ -0,0 +1,146 @@
1/**
2 * @file llfunctorregistry.h
3 * @author Kent Quirk
4 * @brief Maintains a registry of named callback functors taking a single LLSD parameter
5 *
6 * $LicenseInfo:firstyear=2008&license=viewergpl$
7 *
8 * Copyright (c) 2008-2009, Linden Research, Inc.
9 *
10 * Second Life Viewer Source Code
11 * The source code in this file ("Source Code") is provided by Linden Lab
12 * to you under the terms of the GNU General Public License, version 2.0
13 * ("GPL"), unless you have obtained a separate licensing agreement
14 * ("Other License"), formally executed by you and Linden Lab. Terms of
15 * the GPL can be found in doc/GPL-license.txt in this distribution, or
16 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
17 *
18 * There are special exceptions to the terms and conditions of the GPL as
19 * it is applied to this Source Code. View the full text of the exception
20 * in the file doc/FLOSS-exception.txt in this software distribution, or
21 * online at
22 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
23 *
24 * By copying, modifying or distributing this software, you acknowledge
25 * that you have read and understood your obligations described above,
26 * and agree to abide by those obligations.
27 *
28 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
29 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
30 * COMPLETENESS OR PERFORMANCE.
31 * $/LicenseInfo$
32 */
33
34#ifndef LL_LLFUNCTORREGISTRY_H
35#define LL_LLFUNCTORREGISTRY_H
36
37#include <string>
38#include <map>
39
40#include <boost/function.hpp>
41
42#include "llsd.h"
43#include "llmemory.h"
44
45/**
46 * @class LLFunctorRegistry
47 * @brief Maintains a collection of named functors for remote binding
48 * (mainly for use in callbacks from notifications and other signals)
49 * @see LLNotifications
50 *
51 * This class maintains a collection of named functors in a singleton.
52 * We wanted to be able to persist notifications with their callbacks
53 * across restarts of the viewer; we couldn't store functors that way.
54 * Using this registry, systems that require a functor to be maintained
55 * long term can register it at system startup, and then pass in the
56 * functor by name.
57 */
58
59template <typename FUNCTOR_TYPE>
60class LLFunctorRegistry : public LLSingleton<LLFunctorRegistry<FUNCTOR_TYPE> >
61{
62 friend class LLSingleton<LLFunctorRegistry>;
63 LOG_CLASS(LLFunctorRegistry);
64private:
65 LLFunctorRegistry() : LOGFUNCTOR("LogFunctor"), DONOTHING("DoNothing")
66 {
67 mMap[LOGFUNCTOR] = log_functor;
68 mMap[DONOTHING] = do_nothing;
69 }
70
71public:
72 typedef FUNCTOR_TYPE ResponseFunctor;
73 typedef typename std::map<std::string, FUNCTOR_TYPE> FunctorMap;
74
75 bool registerFunctor(const std::string& name, ResponseFunctor f)
76 {
77 bool retval = true;
78 typename FunctorMap::iterator it = mMap.find(name);
79 if (mMap.count(name) == 0)
80 {
81 mMap[name] = f;
82 }
83 else
84 {
85 llerrs << "attempt to store duplicate name '" << name << "' in LLFunctorRegistry. NOT ADDED." << llendl;
86 retval = false;
87 }
88
89 return retval;
90 }
91
92 bool unregisterFunctor(const std::string& name)
93 {
94 if (mMap.count(name) == 0)
95 {
96 llwarns << "trying to remove '" << name << "' from LLFunctorRegistry but it's not there." << llendl;
97 return false;
98 }
99 mMap.erase(name);
100 return true;
101 }
102
103 FUNCTOR_TYPE getFunctor(const std::string& name)
104 {
105 typename FunctorMap::iterator it = mMap.find(name);
106 if (mMap.count(name) != 0)
107 {
108 return mMap[name];
109 }
110 else
111 {
112 llwarns << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << llendl;
113 return mMap[LOGFUNCTOR];
114 }
115 }
116
117 const std::string LOGFUNCTOR;
118 const std::string DONOTHING;
119
120private:
121
122 static void log_functor(const LLSD& notification, const LLSD& payload)
123 {
124 llwarns << "log_functor called with payload: " << payload << llendl;
125 }
126
127 static void do_nothing(const LLSD& notification, const LLSD& payload)
128 {
129 // what the sign sez
130 }
131
132 FunctorMap mMap;
133};
134
135template <typename FUNCTOR_TYPE>
136class LLFunctorRegistration
137{
138public:
139 LLFunctorRegistration(const std::string& name, FUNCTOR_TYPE functor)
140 {
141 LLFunctorRegistry<FUNCTOR_TYPE>::instance().registerFunctor(name, functor);
142 }
143};
144
145#endif//LL_LLFUNCTORREGISTRY_H
146
diff --git a/linden/indra/llui/llhtmlhelp.h b/linden/indra/llui/llhtmlhelp.h
index 3383148..2841a12 100644
--- a/linden/indra/llui/llhtmlhelp.h
+++ b/linden/indra/llui/llhtmlhelp.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lliconctrl.cpp b/linden/indra/llui/lliconctrl.cpp
index 71c2315..cb3b2a3 100644
--- a/linden/indra/llui/lliconctrl.cpp
+++ b/linden/indra/llui/lliconctrl.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lliconctrl.h b/linden/indra/llui/lliconctrl.h
index a8a265d..50778cf 100644
--- a/linden/indra/llui/lliconctrl.h
+++ b/linden/indra/llui/lliconctrl.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llkeywords.cpp b/linden/indra/llui/llkeywords.cpp
index 53df1c1..51ef3db 100644
--- a/linden/indra/llui/llkeywords.cpp
+++ b/linden/indra/llui/llkeywords.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llkeywords.h b/linden/indra/llui/llkeywords.h
index 1ae0b3c..38f5e99 100644
--- a/linden/indra/llui/llkeywords.h
+++ b/linden/indra/llui/llkeywords.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lllineeditor.cpp b/linden/indra/llui/lllineeditor.cpp
index 64b1284..6aa2aac 100644
--- a/linden/indra/llui/lllineeditor.cpp
+++ b/linden/indra/llui/lllineeditor.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -151,7 +152,7 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect,
151 } 152 }
152 else 153 else
153 { 154 {
154 mGLFont = LLFontGL::sSansSerifSmall; 155 mGLFont = LLFontGL::getFontSansSerifSmall();
155 } 156 }
156 157
157 setFocusLostCallback(focus_lost_callback); 158 setFocusLostCallback(focus_lost_callback);
@@ -361,7 +362,7 @@ void LLLineEditor::setCursor( S32 pos )
361 { 362 {
362 S32 width_chars_to_left = mGLFont->getWidth(mText.getWString().c_str(), 0, mScrollHPos); 363 S32 width_chars_to_left = mGLFont->getWidth(mText.getWString().c_str(), 0, mScrollHPos);
363 S32 last_visible_char = mGLFont->maxDrawableChars(mText.getWString().c_str(), llmax(0.f, (F32)(mMaxHPixels - mMinHPixels + width_chars_to_left))); 364 S32 last_visible_char = mGLFont->maxDrawableChars(mText.getWString().c_str(), llmax(0.f, (F32)(mMaxHPixels - mMinHPixels + width_chars_to_left)));
364 S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mMaxHPixels - mMinHPixels), mText.length(), getCursor()); 365 S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mMaxHPixels - mMinHPixels - UI_LINEEDITOR_CURSOR_THICKNESS - UI_LINEEDITOR_H_PAD), mText.length(), getCursor());
365 if (old_cursor_pos == last_visible_char) 366 if (old_cursor_pos == last_visible_char)
366 { 367 {
367 mScrollHPos = llmin(mText.length(), llmax(min_scroll, mScrollHPos + SCROLL_INCREMENT_ADD)); 368 mScrollHPos = llmin(mText.length(), llmax(min_scroll, mScrollHPos + SCROLL_INCREMENT_ADD));
diff --git a/linden/indra/llui/lllineeditor.h b/linden/indra/llui/lllineeditor.h
index 52cbfcf..254ba19 100644
--- a/linden/indra/llui/lllineeditor.h
+++ b/linden/indra/llui/lllineeditor.h
@@ -26,7 +26,8 @@
26 * There are special exceptions to the terms and conditions of the GPL as 26 * There are special exceptions to the terms and conditions of the GPL as
27 * it is applied to this Source Code. View the full text of the exception 27 * it is applied to this Source Code. View the full text of the exception
28 * in the file doc/FLOSS-exception.txt in this software distribution, or 28 * in the file doc/FLOSS-exception.txt in this software distribution, or
29 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 29 * online at
30 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
30 * 31 *
31 * By copying, modifying or distributing this software, you acknowledge 32 * By copying, modifying or distributing this software, you acknowledge
32 * that you have read and understood your obligations described above, 33 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llmemberlistener.h b/linden/indra/llui/llmemberlistener.h
index 3b702ed..a5e019c 100644
--- a/linden/indra/llui/llmemberlistener.h
+++ b/linden/indra/llui/llmemberlistener.h
@@ -43,7 +43,8 @@
43 * There are special exceptions to the terms and conditions of the GPL as 43 * There are special exceptions to the terms and conditions of the GPL as
44 * it is applied to this Source Code. View the full text of the exception 44 * it is applied to this Source Code. View the full text of the exception
45 * in the file doc/FLOSS-exception.txt in this software distribution, or 45 * in the file doc/FLOSS-exception.txt in this software distribution, or
46 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 46 * online at
47 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
47 * 48 *
48 * By copying, modifying or distributing this software, you acknowledge 49 * By copying, modifying or distributing this software, you acknowledge
49 * that you have read and understood your obligations described above, 50 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llmenugl.cpp b/linden/indra/llui/llmenugl.cpp
index 907777d..f2f2aae 100644
--- a/linden/indra/llui/llmenugl.cpp
+++ b/linden/indra/llui/llmenugl.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -58,6 +59,8 @@
58#include "llresmgr.h" 59#include "llresmgr.h"
59#include "llui.h" 60#include "llui.h"
60 61
62#include "lluitrans.h"
63
61#include "llstl.h" 64#include "llstl.h"
62 65
63#include "v2math.h" 66#include "v2math.h"
@@ -139,7 +142,7 @@ LLMenuItemGL::LLMenuItemGL( const std::string& name, const std::string& label, K
139 mHighlight( FALSE ), 142 mHighlight( FALSE ),
140 mGotHover( FALSE ), 143 mGotHover( FALSE ),
141 mBriefItem( FALSE ), 144 mBriefItem( FALSE ),
142 mFont( LLFontGL::sSansSerif ), 145 mFont( LLFontGL::getFontSansSerif() ),
143 mStyle(LLFontGL::NORMAL), 146 mStyle(LLFontGL::NORMAL),
144 mDrawTextDisabled( FALSE ) 147 mDrawTextDisabled( FALSE )
145{ 148{
@@ -266,24 +269,24 @@ void LLMenuItemGL::appendAcceleratorString( std::string& st ) const
266 { 269 {
267 if ( mAcceleratorMask & MASK_MAC_CONTROL ) 270 if ( mAcceleratorMask & MASK_MAC_CONTROL )
268 { 271 {
269 st.append( "Ctrl-" ); 272 st.append( LLUITrans::getString("accel-mac-control") );
270 } 273 }
271 else 274 else
272 { 275 {
273 st.append( "Cmd-" ); // Symbol would be "\xE2\x8C\x98" 276 st.append( LLUITrans::getString("accel-mac-command") ); // Symbol would be "\xE2\x8C\x98"
274 } 277 }
275 } 278 }
276 if( mAcceleratorMask & MASK_ALT ) 279 if( mAcceleratorMask & MASK_ALT )
277 st.append( "Opt-" ); // Symbol would be "\xE2\x8C\xA5" 280 st.append( LLUITrans::getString("accel-mac-option") ); // Symbol would be "\xE2\x8C\xA5"
278 if( mAcceleratorMask & MASK_SHIFT ) 281 if( mAcceleratorMask & MASK_SHIFT )
279 st.append( "Shift-" ); // Symbol would be "\xE2\x8C\xA7" 282 st.append( LLUITrans::getString("accel-mac-shift") ); // Symbol would be "\xE2\x8C\xA7"
280#else 283#else
281 if( mAcceleratorMask & MASK_CONTROL ) 284 if( mAcceleratorMask & MASK_CONTROL )
282 st.append( "Ctrl-" ); 285 st.append( LLUITrans::getString("accel-win-control") );
283 if( mAcceleratorMask & MASK_ALT ) 286 if( mAcceleratorMask & MASK_ALT )
284 st.append( "Alt-" ); 287 st.append( LLUITrans::getString("accel-win-alt") );
285 if( mAcceleratorMask & MASK_SHIFT ) 288 if( mAcceleratorMask & MASK_SHIFT )
286 st.append( "Shift-" ); 289 st.append( LLUITrans::getString("accel-win-shift") );
287#endif 290#endif
288 291
289 std::string keystr = LLKeyboard::stringFromKey( mAcceleratorKey ); 292 std::string keystr = LLKeyboard::stringFromKey( mAcceleratorKey );
@@ -2165,8 +2168,8 @@ void LLMenuGL::arrange( void )
2165 U32 max_width = getTornOff() ? U32_MAX : menu_region_rect.getWidth(); 2168 U32 max_width = getTornOff() ? U32_MAX : menu_region_rect.getWidth();
2166 U32 max_height = getTornOff() ? U32_MAX : menu_region_rect.getHeight(); 2169 U32 max_height = getTornOff() ? U32_MAX : menu_region_rect.getHeight();
2167 // *FIX: create the item first and then ask for its dimensions? 2170 // *FIX: create the item first and then ask for its dimensions?
2168 S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::sSansSerif->getWidth( std::string("More") ); 2171 S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") );
2169 S32 spillover_item_height = llround(LLFontGL::sSansSerif->getLineHeight()) + MENU_ITEM_PADDING; 2172 S32 spillover_item_height = llround(LLFontGL::getFontSansSerif()->getLineHeight()) + MENU_ITEM_PADDING;
2170 2173
2171 if (mHorizontalLayout) 2174 if (mHorizontalLayout)
2172 { 2175 {
@@ -3492,7 +3495,7 @@ void LLPieMenu::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
3492BOOL LLPieMenu::append(LLMenuItemGL *item) 3495BOOL LLPieMenu::append(LLMenuItemGL *item)
3493{ 3496{
3494 item->setBriefItem(TRUE); 3497 item->setBriefItem(TRUE);
3495 item->setFont( LLFontGL::sSansSerifSmall ); 3498 item->setFont( LLFontGL::getFontSansSerifSmall() );
3496 return LLMenuGL::append(item); 3499 return LLMenuGL::append(item);
3497} 3500}
3498 3501
@@ -3500,7 +3503,7 @@ BOOL LLPieMenu::append(LLMenuItemGL *item)
3500BOOL LLPieMenu::appendSeparator(const std::string &separator_name) 3503BOOL LLPieMenu::appendSeparator(const std::string &separator_name)
3501{ 3504{
3502 LLMenuItemGL* separator = new LLMenuItemBlankGL(); 3505 LLMenuItemGL* separator = new LLMenuItemBlankGL();
3503 separator->setFont( LLFontGL::sSansSerifSmall ); 3506 separator->setFont( LLFontGL::getFontSansSerifSmall() );
3504 return append( separator ); 3507 return append( separator );
3505} 3508}
3506 3509
@@ -3514,7 +3517,7 @@ BOOL LLPieMenu::appendPieMenu(LLPieMenu *menu)
3514 LLPieMenuBranch *item; 3517 LLPieMenuBranch *item;
3515 item = new LLPieMenuBranch(menu->getName(), menu->getLabel(), menu); 3518 item = new LLPieMenuBranch(menu->getName(), menu->getLabel(), menu);
3516 getParent()->addChild(item->getBranch()); 3519 getParent()->addChild(item->getBranch());
3517 item->setFont( LLFontGL::sSansSerifSmall ); 3520 item->setFont( LLFontGL::getFontSansSerifSmall() );
3518 return append( item ); 3521 return append( item );
3519} 3522}
3520 3523
diff --git a/linden/indra/llui/llmenugl.h b/linden/indra/llui/llmenugl.h
index d981e78..a2ef968 100644
--- a/linden/indra/llui/llmenugl.h
+++ b/linden/indra/llui/llmenugl.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llmodaldialog.cpp b/linden/indra/llui/llmodaldialog.cpp
index 682cc08..1662ff7 100644
--- a/linden/indra/llui/llmodaldialog.cpp
+++ b/linden/indra/llui/llmodaldialog.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llmodaldialog.h b/linden/indra/llui/llmodaldialog.h
index 5bb1a74..f6abd0a 100644
--- a/linden/indra/llui/llmodaldialog.h
+++ b/linden/indra/llui/llmodaldialog.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llmultislider.cpp b/linden/indra/llui/llmultislider.cpp
index 415e96b..c1487be 100644
--- a/linden/indra/llui/llmultislider.cpp
+++ b/linden/indra/llui/llmultislider.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llmultislider.h b/linden/indra/llui/llmultislider.h
index 08cfa78..cdbdb59 100644
--- a/linden/indra/llui/llmultislider.h
+++ b/linden/indra/llui/llmultislider.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llmultisliderctrl.cpp b/linden/indra/llui/llmultisliderctrl.cpp
index 53c0799..8bcf9f9 100644
--- a/linden/indra/llui/llmultisliderctrl.cpp
+++ b/linden/indra/llui/llmultisliderctrl.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -543,7 +544,7 @@ LLView* LLMultiSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFa
543 // HACK: Font might not be specified. 544 // HACK: Font might not be specified.
544 if (!font) 545 if (!font)
545 { 546 {
546 font = LLFontGL::sSansSerifSmall; 547 font = LLFontGL::getFontSansSerifSmall();
547 } 548 }
548 549
549 S32 label_width = 0; 550 S32 label_width = 0;
diff --git a/linden/indra/llui/llmultisliderctrl.h b/linden/indra/llui/llmultisliderctrl.h
index 4145d70..b62b5ec 100644
--- a/linden/indra/llui/llmultisliderctrl.h
+++ b/linden/indra/llui/llmultisliderctrl.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llnotifications.cpp b/linden/indra/llui/llnotifications.cpp
new file mode 100644
index 0000000..2ae9672
--- /dev/null
+++ b/linden/indra/llui/llnotifications.cpp
@@ -0,0 +1,1487 @@
1/**
2* @file llnotifications.cpp
3* @brief Non-UI queue manager for keeping a prioritized list of notifications
4*
5* $LicenseInfo:firstyear=2008&license=viewergpl$
6*
7* Copyright (c) 2008-2009, Linden Research, Inc.
8*
9* Second Life Viewer Source Code
10* The source code in this file ("Source Code") is provided by Linden Lab
11* to you under the terms of the GNU General Public License, version 2.0
12* ("GPL"), unless you have obtained a separate licensing agreement
13* ("Other License"), formally executed by you and Linden Lab. Terms of
14* the GPL can be found in doc/GPL-license.txt in this distribution, or
15* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16*
17* 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
19* in the file doc/FLOSS-exception.txt in this software distribution, or
20* online at
21* http://secondlifegrid.net/programs/open_source/licensing/flossexception
22*
23* By copying, modifying or distributing this software, you acknowledge
24* that you have read and understood your obligations described above,
25* and agree to abide by those obligations.
26*
27* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29* COMPLETENESS OR PERFORMANCE.
30* $/LicenseInfo$
31*/
32
33#include "linden_common.h"
34#include "lluictrlfactory.h"
35#include "lldir.h"
36#include "llsdserialize.h"
37
38#include "llnotifications.h"
39
40#include <algorithm>
41#include <boost/regex.hpp>
42
43
44const std::string NOTIFICATION_PERSIST_VERSION = "0.93";
45
46// local channel for notification history
47class LLNotificationHistoryChannel : public LLNotificationChannel
48{
49 LOG_CLASS(LLNotificationHistoryChannel);
50public:
51 LLNotificationHistoryChannel(const std::string& filename) :
52 LLNotificationChannel("History", "Visible", &historyFilter, LLNotificationComparators::orderByUUID()),
53 mFileName(filename)
54 {
55 connectChanged(boost::bind(&LLNotificationHistoryChannel::historyHandler, this, _1));
56 loadPersistentNotifications();
57 }
58
59private:
60 bool historyHandler(const LLSD& payload)
61 {
62 // we ignore "load" messages, but rewrite the persistence file on any other
63 std::string sigtype = payload["sigtype"];
64 if (sigtype != "load")
65 {
66 savePersistentNotifications();
67 }
68 return false;
69 }
70
71 // The history channel gets all notifications except those that have been cancelled
72 static bool historyFilter(LLNotificationPtr pNotification)
73 {
74 return !pNotification->isCancelled();
75 }
76
77 void savePersistentNotifications()
78 {
79 llinfos << "Saving open notifications to " << mFileName << llendl;
80
81 llofstream notify_file(mFileName.c_str());
82 if (!notify_file.is_open())
83 {
84 llwarns << "Failed to open " << mFileName << llendl;
85 return;
86 }
87
88 LLSD output;
89 output["version"] = NOTIFICATION_PERSIST_VERSION;
90 LLSD& data = output["data"];
91
92 for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
93 {
94 if (!LLNotifications::instance().templateExists((*it)->getName())) continue;
95
96 // only store notifications flagged as persisting
97 LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate((*it)->getName());
98 if (!templatep->mPersist) continue;
99
100 data.append((*it)->asLLSD());
101 }
102
103 LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
104 formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);
105 }
106
107 void loadPersistentNotifications()
108 {
109 llinfos << "Loading open notifications from " << mFileName << llendl;
110
111 llifstream notify_file(mFileName.c_str());
112 if (!notify_file.is_open())
113 {
114 llwarns << "Failed to open " << mFileName << llendl;
115 return;
116 }
117
118 LLSD input;
119 LLPointer<LLSDParser> parser = new LLSDXMLParser();
120 if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0)
121 {
122 llwarns << "Failed to parse open notifications" << llendl;
123 return;
124 }
125
126 if (input.isUndefined()) return;
127 std::string version = input["version"];
128 if (version != NOTIFICATION_PERSIST_VERSION)
129 {
130 llwarns << "Bad open notifications version: " << version << llendl;
131 return;
132 }
133 LLSD& data = input["data"];
134 if (data.isUndefined()) return;
135
136 LLNotifications& instance = LLNotifications::instance();
137 for (LLSD::array_const_iterator notification_it = data.beginArray();
138 notification_it != data.endArray();
139 ++notification_it)
140 {
141 instance.add(LLNotificationPtr(new LLNotification(*notification_it)));
142 }
143 }
144
145 //virtual
146 void onDelete(LLNotificationPtr pNotification)
147 {
148 // we want to keep deleted notifications in our log
149 mItems.insert(pNotification);
150
151 return;
152 }
153
154private:
155 std::string mFileName;
156};
157
158bool filterIgnoredNotifications(LLNotificationPtr notification)
159{
160 LLNotificationFormPtr form = notification->getForm();
161 // Check to see if the user wants to ignore this alert
162 if (form->getIgnoreType() != LLNotificationForm::IGNORE_NO)
163 {
164 return LLUI::sConfigGroup->getWarning(notification->getName());
165 }
166
167 return true;
168}
169
170bool handleIgnoredNotification(const LLSD& payload)
171{
172 if (payload["sigtype"].asString() == "add")
173 {
174 LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
175 if (!pNotif) return false;
176
177 LLNotificationFormPtr form = pNotif->getForm();
178 LLSD response;
179 switch(form->getIgnoreType())
180 {
181 case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE:
182 response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON);
183 break;
184 case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE:
185 response = LLUI::sIgnoresGroup->getLLSD("Default" + pNotif->getName());
186 break;
187 case LLNotificationForm::IGNORE_SHOW_AGAIN:
188 break;
189 default:
190 return false;
191 }
192 pNotif->setIgnored(true);
193 pNotif->respond(response);
194 return true; // don't process this item any further
195 }
196 return false;
197}
198
199namespace LLNotificationFilters
200{
201 // a sample filter
202 bool includeEverything(LLNotificationPtr p)
203 {
204 return true;
205 }
206};
207
208LLNotificationForm::LLNotificationForm()
209: mFormData(LLSD::emptyArray()),
210 mIgnore(IGNORE_NO)
211{
212}
213
214
215LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node)
216: mFormData(LLSD::emptyArray()),
217 mIgnore(IGNORE_NO)
218{
219 if (!xml_node->hasName("form"))
220 {
221 llwarns << "Bad xml node for form: " << xml_node->getName() << llendl;
222 }
223 LLXMLNodePtr child = xml_node->getFirstChild();
224 while(child)
225 {
226 child = LLNotifications::instance().checkForXMLTemplate(child);
227
228 LLSD item_entry;
229 std::string element_name = child->getName()->mString;
230
231 if (element_name == "ignore")
232 {
233 bool save_option = false;
234 child->getAttribute_bool("save_option", save_option);
235 if (!save_option)
236 {
237 mIgnore = IGNORE_WITH_DEFAULT_RESPONSE;
238 }
239 else
240 {
241 // remember last option chosen by user and automatically respond with that in the future
242 mIgnore = IGNORE_WITH_LAST_RESPONSE;
243 LLUI::sIgnoresGroup->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name));
244 }
245 child->getAttributeString("text", mIgnoreMsg);
246 LLUI::sIgnoresGroup->addWarning(name);
247 }
248 else
249 {
250 // flatten xml form entry into single LLSD map with type==name
251 item_entry["type"] = element_name;
252 const LLXMLAttribList::iterator attrib_end = child->mAttributes.end();
253 for(LLXMLAttribList::iterator attrib_it = child->mAttributes.begin();
254 attrib_it != attrib_end;
255 ++attrib_it)
256 {
257 item_entry[std::string(attrib_it->second->getName()->mString)] = attrib_it->second->getValue();
258 }
259 item_entry["value"] = child->getTextContents();
260 mFormData.append(item_entry);
261 }
262
263 child = child->getNextSibling();
264 }
265}
266
267LLNotificationForm::LLNotificationForm(const LLSD& sd)
268{
269 if (sd.isArray())
270 {
271 mFormData = sd;
272 }
273 else
274 {
275 llwarns << "Invalid form data " << sd << llendl;
276 mFormData = LLSD::emptyArray();
277 }
278}
279
280LLSD LLNotificationForm::asLLSD() const
281{
282 return mFormData;
283}
284
285LLSD LLNotificationForm::getElement(const std::string& element_name)
286{
287 for (LLSD::array_const_iterator it = mFormData.beginArray();
288 it != mFormData.endArray();
289 ++it)
290 {
291 if ((*it)["name"].asString() == element_name) return (*it);
292 }
293 return LLSD();
294}
295
296
297bool LLNotificationForm::hasElement(const std::string& element_name)
298{
299 for (LLSD::array_const_iterator it = mFormData.beginArray();
300 it != mFormData.endArray();
301 ++it)
302 {
303 if ((*it)["name"].asString() == element_name) return true;
304 }
305 return false;
306}
307
308void LLNotificationForm::addElement(const std::string& type, const std::string& name, const LLSD& value)
309{
310 LLSD element;
311 element["type"] = type;
312 element["name"] = name;
313 element["label"] = name;
314 element["value"] = value;
315 element["index"] = mFormData.size();
316 mFormData.append(element);
317}
318
319void LLNotificationForm::append(const LLSD& sub_form)
320{
321 if (sub_form.isArray())
322 {
323 for (LLSD::array_const_iterator it = sub_form.beginArray();
324 it != sub_form.endArray();
325 ++it)
326 {
327 mFormData.append(*it);
328 }
329 }
330}
331
332void LLNotificationForm::formatElements(const LLSD& substitutions)
333{
334 for (LLSD::array_iterator it = mFormData.beginArray();
335 it != mFormData.endArray();
336 ++it)
337 {
338 // format "text" component of each form element
339 if ((*it).has("text"))
340 {
341 std::string text = (*it)["text"].asString();
342 text = LLNotification::format(text, substitutions);
343 (*it)["text"] = text;
344 }
345 if ((*it)["type"].asString() == "text" && (*it).has("value"))
346 {
347 std::string value = (*it)["value"].asString();
348 value = LLNotification::format(value, substitutions);
349 (*it)["value"] = value;
350 }
351 }
352}
353
354std::string LLNotificationForm::getDefaultOption()
355{
356 for (LLSD::array_const_iterator it = mFormData.beginArray();
357 it != mFormData.endArray();
358 ++it)
359 {
360 if ((*it)["default"]) return (*it)["name"].asString();
361 }
362 return "";
363}
364
365LLNotificationTemplate::LLNotificationTemplate() :
366 mExpireSeconds(0),
367 mExpireOption(-1),
368 mURLOption(-1),
369 mUnique(false),
370 mPriority(NOTIFICATION_PRIORITY_NORMAL)
371{
372 mForm = LLNotificationFormPtr(new LLNotificationForm());
373}
374
375LLNotification::LLNotification(const LLNotification::Params& p) :
376 mTimestamp(p.timestamp),
377 mSubstitutions(p.substitutions),
378 mPayload(p.payload),
379 mExpiresAt(0),
380 mResponseFunctorName(p.functor_name),
381 mTemporaryResponder(p.mTemporaryResponder),
382 mRespondedTo(false),
383 mPriority(p.priority),
384 mCancelled(false),
385 mIgnored(false)
386{
387 mId.generate();
388 init(p.name, p.form_elements);
389}
390
391
392LLNotification::LLNotification(const LLSD& sd) :
393 mTemporaryResponder(false),
394 mRespondedTo(false),
395 mCancelled(false),
396 mIgnored(false)
397{
398 mId.generate();
399 mSubstitutions = sd["substitutions"];
400 mPayload = sd["payload"];
401 mTimestamp = sd["time"];
402 mExpiresAt = sd["expiry"];
403 mPriority = (ENotificationPriority)sd["priority"].asInteger();
404 mResponseFunctorName = sd["responseFunctor"].asString();
405 std::string templatename = sd["name"].asString();
406 init(templatename, LLSD());
407 // replace form with serialized version
408 mForm = LLNotificationFormPtr(new LLNotificationForm(sd["form"]));
409}
410
411
412LLSD LLNotification::asLLSD()
413{
414 LLSD output;
415 output["name"] = mTemplatep->mName;
416 output["form"] = getForm()->asLLSD();
417 output["substitutions"] = mSubstitutions;
418 output["payload"] = mPayload;
419 output["time"] = mTimestamp;
420 output["expiry"] = mExpiresAt;
421 output["priority"] = (S32)mPriority;
422 output["responseFunctor"] = mResponseFunctorName;
423 return output;
424}
425
426void LLNotification::update()
427{
428 LLNotifications::instance().update(shared_from_this());
429}
430
431void LLNotification::updateFrom(LLNotificationPtr other)
432{
433 // can only update from the same notification type
434 if (mTemplatep != other->mTemplatep) return;
435
436 // NOTE: do NOT change the ID, since it is the key to
437 // this given instance, just update all the metadata
438 //mId = other->mId;
439
440 mPayload = other->mPayload;
441 mSubstitutions = other->mSubstitutions;
442 mTimestamp = other->mTimestamp;
443 mExpiresAt = other->mExpiresAt;
444 mCancelled = other->mCancelled;
445 mIgnored = other->mIgnored;
446 mPriority = other->mPriority;
447 mForm = other->mForm;
448 mResponseFunctorName = other->mResponseFunctorName;
449 mRespondedTo = other->mRespondedTo;
450 mTemporaryResponder = other->mTemporaryResponder;
451
452 update();
453}
454
455const LLNotificationFormPtr LLNotification::getForm()
456{
457 return mForm;
458}
459
460void LLNotification::cancel()
461{
462 mCancelled = true;
463}
464
465LLSD LLNotification::getResponseTemplate(EResponseTemplateType type)
466{
467 LLSD response = LLSD::emptyMap();
468 for (S32 element_idx = 0;
469 element_idx < mForm->getNumElements();
470 ++element_idx)
471 {
472 LLSD element = mForm->getElement(element_idx);
473 if (element.has("name"))
474 {
475 response[element["name"].asString()] = element["value"];
476 }
477
478 if ((type == WITH_DEFAULT_BUTTON)
479 && element["default"].asBoolean())
480 {
481 response[element["name"].asString()] = true;
482 }
483 }
484 return response;
485}
486
487//static
488S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response)
489{
490 LLNotificationForm form(notification["form"]);
491
492 for (S32 element_idx = 0;
493 element_idx < form.getNumElements();
494 ++element_idx)
495 {
496 LLSD element = form.getElement(element_idx);
497
498 // only look at buttons
499 if (element["type"].asString() == "button"
500 && response[element["name"].asString()].asBoolean())
501 {
502 return element["index"].asInteger();
503 }
504 }
505
506 return -1;
507}
508
509//static
510std::string LLNotification::getSelectedOptionName(const LLSD& response)
511{
512 for (LLSD::map_const_iterator response_it = response.beginMap();
513 response_it != response.endMap();
514 ++response_it)
515 {
516 if (response_it->second.isBoolean() && response_it->second.asBoolean())
517 {
518 return response_it->first;
519 }
520 }
521 return "";
522}
523
524
525void LLNotification::respond(const LLSD& response)
526{
527 mRespondedTo = true;
528 LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName)(asLLSD(), response);
529 if (mTemporaryResponder)
530 {
531 LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
532 mResponseFunctorName = "";
533 mTemporaryResponder = false;
534 }
535
536 if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
537 {
538 LLUI::sIgnoresGroup->setWarning(getName(), !mIgnored);
539 if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
540 {
541 LLUI::sIgnoresGroup->setLLSD("Default" + getName(), response);
542 }
543 }
544
545 update();
546}
547
548void LLNotification::setIgnored(bool ignore)
549{
550 mIgnored = ignore;
551}
552
553void LLNotification::setResponseFunctor(std::string const &responseFunctorName)
554{
555 if (mTemporaryResponder)
556 // get rid of the old one
557 LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
558 mResponseFunctorName = responseFunctorName;
559 mTemporaryResponder = false;
560}
561
562bool LLNotification::payloadContainsAll(const std::vector<std::string>& required_fields) const
563{
564 for(std::vector<std::string>::const_iterator required_fields_it = required_fields.begin();
565 required_fields_it != required_fields.end();
566 required_fields_it++)
567 {
568 std::string required_field_name = *required_fields_it;
569 if( ! getPayload().has(required_field_name))
570 {
571 return false; // a required field was not found
572 }
573 }
574 return true; // all required fields were found
575}
576
577bool LLNotification::isEquivalentTo(LLNotificationPtr that) const
578{
579 if (this->mTemplatep->mName != that->mTemplatep->mName)
580 {
581 return false; // must have the same template name or forget it
582 }
583 if (this->mTemplatep->mUnique)
584 {
585 // highlander bit sez there can only be one of these
586 return
587 this->payloadContainsAll(that->mTemplatep->mUniqueContext) &&
588 that->payloadContainsAll(this->mTemplatep->mUniqueContext);
589 }
590 return false;
591}
592
593void LLNotification::init(const std::string& template_name, const LLSD& form_elements)
594{
595 mTemplatep = LLNotifications::instance().getTemplate(template_name);
596 if (!mTemplatep) return;
597
598 // add default substitutions
599 // TODO: change this to read from the translatable strings file!
600 mSubstitutions["SECOND_LIFE"] = "Second Life";
601 mSubstitutions["_URL"] = getURL();
602 mSubstitutions["_NAME"] = template_name;
603 // TODO: something like this so that a missing alert is sensible:
604 //mSubstitutions["_ARGS"] = get_all_arguments_as_text(mSubstitutions);
605
606 mForm = LLNotificationFormPtr(new LLNotificationForm(*mTemplatep->mForm));
607 mForm->append(form_elements);
608
609 // apply substitution to form labels
610 mForm->formatElements(mSubstitutions);
611
612 LLDate rightnow = LLDate::now();
613 if (mTemplatep->mExpireSeconds)
614 {
615 mExpiresAt = LLDate(rightnow.secondsSinceEpoch() + mTemplatep->mExpireSeconds);
616 }
617
618 if (mPriority == NOTIFICATION_PRIORITY_UNSPECIFIED)
619 {
620 mPriority = mTemplatep->mPriority;
621 }
622}
623
624std::string LLNotification::summarize() const
625{
626 std::string s = "Notification(";
627 s += getName();
628 s += ") : ";
629 s += mTemplatep ? mTemplatep->mMessage : "";
630 // should also include timestamp and expiration time (but probably not payload)
631 return s;
632}
633
634//static
635std::string LLNotification::format(const std::string& s, const LLSD& substitutions)
636{
637 if (!substitutions.isMap())
638 {
639 return s;
640 }
641
642 std::ostringstream output;
643 // match strings like [NAME]
644 const boost::regex key("\\[([0-9_A-Z]+)]");
645
646 std::string::const_iterator start = s.begin();
647 std::string::const_iterator end = s.end();
648 boost::smatch match;
649
650 while (boost::regex_search(start, end, match, key, boost::match_default))
651 {
652 bool found_replacement = false;
653 std::string replacement;
654
655 // see if we have a replacement for the bracketed string (without the brackets)
656 // test first using has() because if we just look up with operator[] we get back an
657 // empty string even if the value is missing. We want to distinguish between
658 // missing replacements and deliberately empty replacement strings.
659 if (substitutions.has(std::string(match[1].first, match[1].second)))
660 {
661 replacement = substitutions[std::string(match[1].first, match[1].second)].asString();
662 found_replacement = true;
663 }
664 // if not, see if there's one WITH brackets
665 else if (substitutions.has(std::string(match[0].first, match[0].second)))
666 {
667 replacement = substitutions[std::string(match[0].first, match[0].second)].asString();
668 found_replacement = true;
669 }
670
671 if (found_replacement)
672 {
673 // found a replacement
674 // "hello world" is output
675 output << std::string(start, match[0].first) << replacement;
676 }
677 else
678 {
679 // we had no replacement, so leave the string we searched for so that it gets noticed by QA
680 // "hello [NAME_NOT_FOUND]" is output
681 output << std::string(start, match[0].second);
682 }
683
684 // update search position
685 start = match[0].second;
686 }
687 // send the remainder of the string (with no further matches for bracketed names)
688 output << std::string(start, end);
689 return output.str();
690}
691
692std::string LLNotification::getMessage() const
693{
694 // all our callers cache this result, so it gives us more flexibility
695 // to do the substitution at call time rather than attempting to
696 // cache it in the notification
697 if (!mTemplatep)
698 return std::string();
699 return format(mTemplatep->mMessage, mSubstitutions);
700}
701
702std::string LLNotification::getLabel() const
703{
704 return (mTemplatep ? format(mTemplatep->mLabel, mSubstitutions) : "");
705}
706
707
708
709// =========================================================
710// LLNotificationChannel implementation
711// ---
712void LLNotificationChannelBase::connectChanged(const LLStandardSignal::slot_type& slot)
713{
714 // when someone wants to connect to a channel, we first throw them
715 // all of the notifications that are already in the channel
716 // we use a special signal called "load" in case the channel wants to care
717 // only about new notifications
718 for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
719 {
720 slot.get_slot_function()(LLSD().insert("sigtype", "load").insert("id", (*it)->id()));
721 }
722 // and then connect the signal so that all future notifications will also be
723 // forwarded.
724 mChanged.connect(slot);
725}
726
727void LLNotificationChannelBase::connectPassedFilter(const LLStandardSignal::slot_type& slot)
728{
729 // these two filters only fire for notifications added after the current one, because
730 // they don't participate in the hierarchy.
731 mPassedFilter.connect(slot);
732}
733
734void LLNotificationChannelBase::connectFailedFilter(const LLStandardSignal::slot_type& slot)
735{
736 mFailedFilter.connect(slot);
737}
738
739// external call, conforms to our standard signature
740bool LLNotificationChannelBase::updateItem(const LLSD& payload)
741{
742 // first check to see if it's in the master list
743 LLNotificationPtr pNotification = LLNotifications::instance().find(payload["id"]);
744 if (!pNotification)
745 return false; // not found
746
747 return updateItem(payload, pNotification);
748}
749
750
751//FIX QUIT NOT WORKING
752
753
754// internal call, for use in avoiding lookup
755bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPtr pNotification)
756{
757 std::string cmd = payload["sigtype"];
758 LLNotificationSet::iterator foundItem = mItems.find(pNotification);
759 bool wasFound = (foundItem != mItems.end());
760 bool passesFilter = mFilter(pNotification);
761
762 // first, we offer the result of the filter test to the simple
763 // signals for pass/fail. One of these is guaranteed to be called.
764 // If either signal returns true, the change processing is NOT performed
765 // (so don't return true unless you know what you're doing!)
766 bool abortProcessing = false;
767 if (passesFilter)
768 {
769 abortProcessing = mPassedFilter(payload);
770 }
771 else
772 {
773 abortProcessing = mFailedFilter(payload);
774 }
775
776 if (abortProcessing)
777 {
778 return true;
779 }
780
781 if (cmd == "load")
782 {
783 // should be no reason we'd ever get a load if we already have it
784 // if passes filter send a load message, else do nothing
785 assert(!wasFound);
786 if (passesFilter)
787 {
788 // not in our list, add it and say so
789 mItems.insert(pNotification);
790 abortProcessing = mChanged(payload);
791 onLoad(pNotification);
792 }
793 }
794 else if (cmd == "change")
795 {
796 // if it passes filter now and was found, we just send a change message
797 // if it passes filter now and wasn't found, we have to add it
798 // if it doesn't pass filter and wasn't found, we do nothing
799 // if it doesn't pass filter and was found, we need to delete it
800 if (passesFilter)
801 {
802 if (wasFound)
803 {
804 // it already existed, so this is a change
805 // since it changed in place, all we have to do is resend the signal
806 abortProcessing = mChanged(payload);
807 onChange(pNotification);
808 }
809 else
810 {
811 // not in our list, add it and say so
812 mItems.insert(pNotification);
813 // our payload is const, so make a copy before changing it
814 LLSD newpayload = payload;
815 newpayload["sigtype"] = "add";
816 abortProcessing = mChanged(newpayload);
817 onChange(pNotification);
818 }
819 }
820 else
821 {
822 if (wasFound)
823 {
824 // it already existed, so this is a delete
825 mItems.erase(pNotification);
826 // our payload is const, so make a copy before changing it
827 LLSD newpayload = payload;
828 newpayload["sigtype"] = "delete";
829 abortProcessing = mChanged(newpayload);
830 onChange(pNotification);
831 }
832 // didn't pass, not on our list, do nothing
833 }
834 }
835 else if (cmd == "add")
836 {
837 // should be no reason we'd ever get an add if we already have it
838 // if passes filter send an add message, else do nothing
839 assert(!wasFound);
840 if (passesFilter)
841 {
842 // not in our list, add it and say so
843 mItems.insert(pNotification);
844 abortProcessing = mChanged(payload);
845 onAdd(pNotification);
846 }
847 }
848 else if (cmd == "delete")
849 {
850 // if we have it in our list, pass on the delete, then delete it, else do nothing
851 if (wasFound)
852 {
853 abortProcessing = mChanged(payload);
854 mItems.erase(pNotification);
855 onDelete(pNotification);
856 }
857 }
858 return abortProcessing;
859}
860
861/* static */
862LLNotificationChannelPtr LLNotificationChannel::buildChannel(const std::string& name,
863 const std::string& parent,
864 LLNotificationFilter filter,
865 LLNotificationComparator comparator)
866{
867 // note: this is not a leak; notifications are self-registering.
868 // This factory helps to prevent excess deletions by making sure all smart
869 // pointers to notification channels come from the same source
870 new LLNotificationChannel(name, parent, filter, comparator);
871 return LLNotifications::instance().getChannel(name);
872}
873
874
875LLNotificationChannel::LLNotificationChannel(const std::string& name,
876 const std::string& parent,
877 LLNotificationFilter filter,
878 LLNotificationComparator comparator) :
879LLNotificationChannelBase(filter, comparator),
880mName(name),
881mParent(parent)
882{
883 // store myself in the channel map
884 LLNotifications::instance().addChannel(LLNotificationChannelPtr(this));
885 // bind to notification broadcast
886 if (parent.empty())
887 {
888 LLNotifications::instance().connectChanged(
889 boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
890 }
891 else
892 {
893 LLNotificationChannelPtr p = LLNotifications::instance().getChannel(parent);
894 LLStandardSignal::slot_type f = boost::bind(&LLNotificationChannelBase::updateItem, this, _1);
895 p->connectChanged(f);
896 }
897}
898
899
900void LLNotificationChannel::setComparator(LLNotificationComparator comparator)
901{
902 mComparator = comparator;
903 LLNotificationSet s2(mComparator);
904 s2.insert(mItems.begin(), mItems.end());
905 mItems.swap(s2);
906
907 // notify clients that we've been resorted
908 mChanged(LLSD().insert("sigtype", "sort"));
909}
910
911bool LLNotificationChannel::isEmpty() const
912{
913 return mItems.empty();
914}
915
916LLNotificationChannel::Iterator LLNotificationChannel::begin()
917{
918 return mItems.begin();
919}
920
921LLNotificationChannel::Iterator LLNotificationChannel::end()
922{
923 return mItems.end();
924}
925
926std::string LLNotificationChannel::summarize()
927{
928 std::string s("Channel '");
929 s += mName;
930 s += "'\n ";
931 for (LLNotificationChannel::Iterator it = begin(); it != end(); ++it)
932 {
933 s += (*it)->summarize();
934 s += "\n ";
935 }
936 return s;
937}
938
939
940// ---
941// END OF LLNotificationChannel implementation
942// =========================================================
943
944
945// =========================================================
946// LLNotifications implementation
947// ---
948LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything,
949 LLNotificationComparators::orderByUUID())
950{
951}
952
953
954// The expiration channel gets all notifications that are cancelled
955bool LLNotifications::expirationFilter(LLNotificationPtr pNotification)
956{
957 return pNotification->isCancelled() || pNotification->isRespondedTo();
958}
959
960bool LLNotifications::expirationHandler(const LLSD& payload)
961{
962 if (payload["sigtype"].asString() != "delete")
963 {
964 // anything added to this channel actually should be deleted from the master
965 cancel(find(payload["id"]));
966 return true; // don't process this item any further
967 }
968 return false;
969}
970
971bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif)
972{
973 if (!pNotif->hasUniquenessConstraints())
974 {
975 return true;
976 }
977
978 // checks against existing unique notifications
979 for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
980 existing_it != mUniqueNotifications.end();
981 ++existing_it)
982 {
983 LLNotificationPtr existing_notification = existing_it->second;
984 if (pNotif != existing_notification
985 && pNotif->isEquivalentTo(existing_notification))
986 {
987 return false;
988 }
989 }
990
991 return true;
992}
993
994bool LLNotifications::uniqueHandler(const LLSD& payload)
995{
996 LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
997 if (pNotif && pNotif->hasUniquenessConstraints())
998 {
999 if (payload["sigtype"].asString() == "add")
1000 {
1001 // not a duplicate according to uniqueness criteria, so we keep it
1002 // and store it for future uniqueness checks
1003 mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif));
1004 }
1005 else if (payload["sigtype"].asString() == "delete")
1006 {
1007 mUniqueNotifications.erase(pNotif->getName());
1008 }
1009 }
1010
1011 return false;
1012}
1013
1014bool LLNotifications::failedUniquenessTest(const LLSD& payload)
1015{
1016 LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
1017
1018 if (!pNotif || !pNotif->hasUniquenessConstraints())
1019 {
1020 return false;
1021 }
1022
1023 // checks against existing unique notifications
1024 for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
1025 existing_it != mUniqueNotifications.end();
1026 ++existing_it)
1027 {
1028 LLNotificationPtr existing_notification = existing_it->second;
1029 if (pNotif != existing_notification
1030 && pNotif->isEquivalentTo(existing_notification))
1031 {
1032 // copy notification instance data over to oldest instance
1033 // of this unique notification and update it
1034 existing_notification->updateFrom(pNotif);
1035 // then delete the new one
1036 pNotif->cancel();
1037 }
1038 }
1039
1040 return false;
1041}
1042
1043
1044void LLNotifications::addChannel(LLNotificationChannelPtr pChan)
1045{
1046 mChannels[pChan->getName()] = pChan;
1047}
1048
1049LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelName)
1050{
1051 ChannelMap::iterator p = mChannels.find(channelName);
1052 if(p == mChannels.end())
1053 {
1054 llerrs << "Did not find channel named " << channelName << llendl;
1055 }
1056 return p->second;
1057}
1058
1059
1060// this function is called once at construction time, after the object is constructed.
1061void LLNotifications::initSingleton()
1062{
1063 loadTemplates();
1064 createDefaultChannels();
1065}
1066
1067void LLNotifications::createDefaultChannels()
1068{
1069 // now construct the various channels AFTER loading the notifications,
1070 // because the history channel is going to rewrite the stored notifications file
1071 LLNotificationChannel::buildChannel("Expiration", "",
1072 boost::bind(&LLNotifications::expirationFilter, this, _1));
1073 LLNotificationChannel::buildChannel("Unexpired", "",
1074 !boost::bind(&LLNotifications::expirationFilter, this, _1)); // use negated bind
1075 LLNotificationChannel::buildChannel("Unique", "Unexpired",
1076 boost::bind(&LLNotifications::uniqueFilter, this, _1));
1077 LLNotificationChannel::buildChannel("Ignore", "Unique",
1078 filterIgnoredNotifications);
1079 LLNotificationChannel::buildChannel("Visible", "Ignore",
1080 &LLNotificationFilters::includeEverything);
1081
1082 // create special history channel
1083 //std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" );
1084 // use ^^^ when done debugging notifications serialization
1085 std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_USER_SETTINGS, "open_notifications.xml" );
1086 // this isn't a leak, don't worry about the empty "new"
1087 new LLNotificationHistoryChannel(notifications_log_file);
1088
1089 // connect action methods to these channels
1090 LLNotifications::instance().getChannel("Expiration")->
1091 connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1));
1092 LLNotifications::instance().getChannel("Unique")->
1093 connectChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1));
1094 LLNotifications::instance().getChannel("Unique")->
1095 connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1));
1096 LLNotifications::instance().getChannel("Ignore")->
1097 connectFailedFilter(&handleIgnoredNotification);
1098}
1099
1100static std::string sStringSkipNextTime("Skip this dialog next time");
1101static std::string sStringAlwaysChoose("Always choose this option");
1102
1103bool LLNotifications::addTemplate(const std::string &name,
1104 LLNotificationTemplatePtr theTemplate)
1105{
1106 if (mTemplates.count(name))
1107 {
1108 llwarns << "LLNotifications -- attempted to add template '" << name << "' twice." << llendl;
1109 return false;
1110 }
1111 mTemplates[name] = theTemplate;
1112 return true;
1113}
1114
1115LLNotificationTemplatePtr LLNotifications::getTemplate(const std::string& name)
1116{
1117 if (mTemplates.count(name))
1118 {
1119 return mTemplates[name];
1120 }
1121 else
1122 {
1123 return mTemplates["MissingAlert"];
1124 }
1125}
1126
1127bool LLNotifications::templateExists(const std::string& name)
1128{
1129 return (mTemplates.count(name) != 0);
1130}
1131
1132void LLNotifications::clearTemplates()
1133{
1134 mTemplates.clear();
1135}
1136
1137void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option)
1138{
1139 LLNotificationPtr temp_notify(new LLNotification(params));
1140 LLSD response = temp_notify->getResponseTemplate();
1141 LLSD selected_item = temp_notify->getForm()->getElement(option);
1142
1143 if (selected_item.isUndefined())
1144 {
1145 llwarns << "Invalid option" << option << " for notification " << (std::string)params.name << llendl;
1146 return;
1147 }
1148 response[selected_item["name"].asString()] = true;
1149
1150 temp_notify->respond(response);
1151}
1152
1153LLNotifications::TemplateNames LLNotifications::getTemplateNames() const
1154{
1155 TemplateNames names;
1156 for (TemplateMap::const_iterator it = mTemplates.begin(); it != mTemplates.end(); ++it)
1157 {
1158 names.push_back(it->first);
1159 }
1160 return names;
1161}
1162
1163typedef std::map<std::string, std::string> StringMap;
1164void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
1165{
1166 //llwarns << "replaceSubstitutionStrings" << llendl;
1167 // walk the list of attributes looking for replacements
1168 for (LLXMLAttribList::iterator it=node->mAttributes.begin();
1169 it != node->mAttributes.end(); ++it)
1170 {
1171 std::string value = it->second->getValue();
1172 if (value[0] == '$')
1173 {
1174 value.erase(0, 1); // trim off the $
1175 std::string replacement;
1176 StringMap::const_iterator found = replacements.find(value);
1177 if (found != replacements.end())
1178 {
1179 replacement = found->second;
1180 //llwarns << "replaceSubstituionStrings: value: " << value << " repl: " << replacement << llendl;
1181
1182 it->second->setValue(replacement);
1183 }
1184 else
1185 {
1186 llwarns << "replaceSubstituionStrings FAILURE: value: " << value << " repl: " << replacement << llendl;
1187 }
1188 }
1189 }
1190
1191 // now walk the list of children and call this recursively.
1192 for (LLXMLNodePtr child = node->getFirstChild();
1193 child.notNull(); child = child->getNextSibling())
1194 {
1195 replaceSubstitutionStrings(child, replacements);
1196 }
1197}
1198
1199// private to this file
1200// returns true if the template request was invalid and there's nothing else we
1201// can do with this node, false if you should keep processing (it may have
1202// replaced the contents of the node referred to)
1203LLXMLNodePtr LLNotifications::checkForXMLTemplate(LLXMLNodePtr item)
1204{
1205 if (item->hasName("usetemplate"))
1206 {
1207 std::string replacementName;
1208 if (item->getAttributeString("name", replacementName))
1209 {
1210 StringMap replacements;
1211 for (LLXMLAttribList::const_iterator it=item->mAttributes.begin();
1212 it != item->mAttributes.end(); ++it)
1213 {
1214 replacements[it->second->getName()->mString] = it->second->getValue();
1215 }
1216 if (mXmlTemplates.count(replacementName))
1217 {
1218 item=LLXMLNode::replaceNode(item, mXmlTemplates[replacementName]);
1219
1220 // walk the nodes looking for $(substitution) here and replace
1221 replaceSubstitutionStrings(item, replacements);
1222 }
1223 else
1224 {
1225 llwarns << "XML template lookup failure on '" << replacementName << "' " << llendl;
1226 }
1227 }
1228 }
1229 return item;
1230}
1231
1232bool LLNotifications::loadTemplates()
1233{
1234 const std::string xml_filename = "notifications.xml";
1235 LLXMLNodePtr root;
1236
1237 BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
1238
1239 if (!success || root.isNull() || !root->hasName( "notifications" ))
1240 {
1241 llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl;
1242 return false;
1243 }
1244
1245 clearTemplates();
1246
1247 for (LLXMLNodePtr item = root->getFirstChild();
1248 item.notNull(); item = item->getNextSibling())
1249 {
1250 // we do this FIRST so that item can be changed if we
1251 // encounter a usetemplate -- we just replace the
1252 // current xml node and keep processing
1253 item = checkForXMLTemplate(item);
1254
1255 if (item->hasName("global"))
1256 {
1257 std::string global_name;
1258 if (item->getAttributeString("name", global_name))
1259 {
1260 mGlobalStrings[global_name] = item->getTextContents();
1261 }
1262 continue;
1263 }
1264
1265 if (item->hasName("template"))
1266 {
1267 // store an xml template; templates must have a single node (can contain
1268 // other nodes)
1269 std::string name;
1270 item->getAttributeString("name", name);
1271 LLXMLNodePtr ptr = item->getFirstChild();
1272 mXmlTemplates[name] = ptr;
1273 continue;
1274 }
1275
1276 if (!item->hasName("notification"))
1277 {
1278 llwarns << "Unexpected entity " << item->getName()->mString <<
1279 " found in " << xml_filename << llendl;
1280 continue;
1281 }
1282
1283 // now we know we have a notification entry, so let's build it
1284 LLNotificationTemplatePtr pTemplate(new LLNotificationTemplate());
1285
1286 if (!item->getAttributeString("name", pTemplate->mName))
1287 {
1288 llwarns << "Unable to parse notification with no name" << llendl;
1289 continue;
1290 }
1291
1292 //llinfos << "Parsing " << pTemplate->mName << llendl;
1293
1294 pTemplate->mMessage = item->getTextContents();
1295 pTemplate->mDefaultFunctor = pTemplate->mName;
1296 item->getAttributeString("type", pTemplate->mType);
1297 item->getAttributeString("icon", pTemplate->mIcon);
1298 item->getAttributeString("label", pTemplate->mLabel);
1299 item->getAttributeU32("duration", pTemplate->mExpireSeconds);
1300 item->getAttributeU32("expireOption", pTemplate->mExpireOption);
1301
1302 std::string priority;
1303 item->getAttributeString("priority", priority);
1304 pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
1305 if (!priority.empty())
1306 {
1307 if (priority == "low") pTemplate->mPriority = NOTIFICATION_PRIORITY_LOW;
1308 if (priority == "normal") pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
1309 if (priority == "high") pTemplate->mPriority = NOTIFICATION_PRIORITY_HIGH;
1310 if (priority == "critical") pTemplate->mPriority = NOTIFICATION_PRIORITY_CRITICAL;
1311 }
1312
1313 item->getAttributeString("functor", pTemplate->mDefaultFunctor);
1314
1315 BOOL persist = false;
1316 item->getAttributeBOOL("persist", persist);
1317 pTemplate->mPersist = persist;
1318
1319 std::string sound;
1320 item->getAttributeString("sound", sound);
1321 if (!sound.empty())
1322 {
1323 // TODO: test for bad sound effect name / missing effect
1324 pTemplate->mSoundEffect = LLUUID(LLUI::sConfigGroup->getString(sound.c_str()));
1325 }
1326
1327 for (LLXMLNodePtr child = item->getFirstChild();
1328 !child.isNull(); child = child->getNextSibling())
1329 {
1330 child = checkForXMLTemplate(child);
1331
1332 // <url>
1333 if (child->hasName("url"))
1334 {
1335 pTemplate->mURL = child->getTextContents();
1336 child->getAttributeU32("option", pTemplate->mURLOption);
1337 }
1338
1339 if (child->hasName("unique"))
1340 {
1341 pTemplate->mUnique = true;
1342 for (LLXMLNodePtr formitem = child->getFirstChild();
1343 !formitem.isNull(); formitem = formitem->getNextSibling())
1344 {
1345 if (formitem->hasName("context"))
1346 {
1347 std::string key;
1348 formitem->getAttributeString("key", key);
1349 pTemplate->mUniqueContext.push_back(key);
1350 //llwarns << "adding " << key << " to unique context" << llendl;
1351 }
1352 else
1353 {
1354 llwarns << "'unique' has unrecognized subelement "
1355 << formitem->getName()->mString << llendl;
1356 }
1357 }
1358 }
1359
1360 // <form>
1361 if (child->hasName("form"))
1362 {
1363 pTemplate->mForm = LLNotificationFormPtr(new LLNotificationForm(pTemplate->mName, child));
1364 }
1365 }
1366 addTemplate(pTemplate->mName, pTemplate);
1367 }
1368
1369 //std::ostringstream ostream;
1370 //root->writeToOstream(ostream, "\n ");
1371 //llwarns << ostream.str() << llendl;
1372
1373 return true;
1374}
1375
1376// we provide a couple of simple add notification functions so that it's reasonable to create notifications in one line
1377LLNotificationPtr LLNotifications::add(const std::string& name,
1378 const LLSD& substitutions,
1379 const LLSD& payload)
1380{
1381 return add(LLNotification::Params(name).substitutions(substitutions).payload(payload));
1382}
1383
1384LLNotificationPtr LLNotifications::add(const std::string& name,
1385 const LLSD& substitutions,
1386 const LLSD& payload,
1387 const std::string& functor_name)
1388{
1389 return add(LLNotification::Params(name).substitutions(substitutions).payload(payload).functor_name(functor_name));
1390}
1391
1392LLNotificationPtr LLNotifications::add(const std::string& name,
1393 const LLSD& substitutions,
1394 const LLSD& payload,
1395 LLNotificationFunctorRegistry::ResponseFunctor functor)
1396{
1397 return add(LLNotification::Params(name).substitutions(substitutions).payload(payload).functor(functor));
1398}
1399
1400// generalized add function that takes a parameter block object for more complex instantiations
1401LLNotificationPtr LLNotifications::add(const LLNotification::Params& p)
1402{
1403 LLNotificationPtr pNotif(new LLNotification(p));
1404 add(pNotif);
1405 return pNotif;
1406}
1407
1408
1409void LLNotifications::add(const LLNotificationPtr pNotif)
1410{
1411 // first see if we already have it -- if so, that's a problem
1412 LLNotificationSet::iterator it=mItems.find(pNotif);
1413 if (it != mItems.end())
1414 {
1415 llerrs << "Notification added a second time to the master notification channel." << llendl;
1416 }
1417
1418 updateItem(LLSD().insert("sigtype", "add").insert("id", pNotif->id()), pNotif);
1419}
1420
1421void LLNotifications::cancel(LLNotificationPtr pNotif)
1422{
1423 LLNotificationSet::iterator it=mItems.find(pNotif);
1424 if (it == mItems.end())
1425 {
1426 llerrs << "Attempted to delete nonexistent notification " << pNotif->getName() << llendl;
1427 }
1428 updateItem(LLSD().insert("sigtype", "delete").insert("id", pNotif->id()), pNotif);
1429 pNotif->cancel();
1430}
1431
1432void LLNotifications::update(const LLNotificationPtr pNotif)
1433{
1434 LLNotificationSet::iterator it=mItems.find(pNotif);
1435 if (it != mItems.end())
1436 {
1437 updateItem(LLSD().insert("sigtype", "change").insert("id", pNotif->id()), pNotif);
1438 }
1439}
1440
1441
1442LLNotificationPtr LLNotifications::find(LLUUID uuid)
1443{
1444 LLNotificationPtr target = LLNotificationPtr(new LLNotification(uuid));
1445 LLNotificationSet::iterator it=mItems.find(target);
1446 if (it == mItems.end())
1447 {
1448 llwarns << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << llendl;
1449 return LLNotificationPtr((LLNotification*)NULL);
1450 }
1451 else
1452 {
1453 return *it;
1454 }
1455}
1456
1457void LLNotifications::forEachNotification(NotificationProcess process)
1458{
1459 std::for_each(mItems.begin(), mItems.end(), process);
1460}
1461
1462std::string LLNotifications::getGlobalString(const std::string& key) const
1463{
1464 GlobalStringMap::const_iterator it = mGlobalStrings.find(key);
1465 if (it != mGlobalStrings.end())
1466 {
1467 return it->second;
1468 }
1469 else
1470 {
1471 // if we don't have the key as a global, return the key itself so that the error
1472 // is self-diagnosing.
1473 return key;
1474 }
1475}
1476
1477
1478// ---
1479// END OF LLNotifications implementation
1480// =========================================================
1481
1482std::ostream& operator<<(std::ostream& s, const LLNotification& notification)
1483{
1484 s << notification.summarize();
1485 return s;
1486}
1487
diff --git a/linden/indra/llui/llnotifications.h b/linden/indra/llui/llnotifications.h
new file mode 100644
index 0000000..bb37912
--- /dev/null
+++ b/linden/indra/llui/llnotifications.h
@@ -0,0 +1,903 @@
1/**
2* @file llnotifications.h
3* @brief Non-UI manager and support for keeping a prioritized list of notifications
4* @author Q (with assistance from Richard and Coco)
5*
6* $LicenseInfo:firstyear=2008&license=viewergpl$
7*
8* Copyright (c) 2008-2009, Linden Research, Inc.
9*
10* Second Life Viewer Source Code
11* The source code in this file ("Source Code") is provided by Linden Lab
12* to you under the terms of the GNU General Public License, version 2.0
13* ("GPL"), unless you have obtained a separate licensing agreement
14* ("Other License"), formally executed by you and Linden Lab. Terms of
15* the GPL can be found in doc/GPL-license.txt in this distribution, or
16* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
17*
18* There are special exceptions to the terms and conditions of the GPL as
19* it is applied to this Source Code. View the full text of the exception
20* in the file doc/FLOSS-exception.txt in this software distribution, or
21* online at
22* http://secondlifegrid.net/programs/open_source/licensing/flossexception
23*
24* By copying, modifying or distributing this software, you acknowledge
25* that you have read and understood your obligations described above,
26* and agree to abide by those obligations.
27*
28* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
29* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
30* COMPLETENESS OR PERFORMANCE.
31* $/LicenseInfo$
32*/
33
34#ifndef LL_LLNOTIFICATIONS_H
35#define LL_LLNOTIFICATIONS_H
36
37/**
38 * This system is intended to provide a singleton mechanism for adding
39 * notifications to one of an arbitrary set of event channels.
40 *
41 * Controlling JIRA: DEV-9061
42 *
43 * Every notification has (see code for full list):
44 * - a textual name, which is used to look up its template in the XML files
45 * - a payload, which is a block of LLSD
46 * - a channel, which is normally extracted from the XML files but
47 * can be overridden.
48 * - a timestamp, used to order the notifications
49 * - expiration time -- if nonzero, specifies a time after which the
50 * notification will no longer be valid.
51 * - a callback name and a couple of status bits related to callbacks (see below)
52 *
53 * There is a management class called LLNotifications, which is an LLSingleton.
54 * The class maintains a collection of all of the notifications received
55 * or processed during this session, and also manages the persistence
56 * of those notifications that must be persisted.
57 *
58 * We also have Channels. A channel is a view on a collection of notifications;
59 * The collection is defined by a filter function that controls which
60 * notifications are in the channel, and its ordering is controlled by
61 * a comparator.
62 *
63 * There is a hierarchy of channels; notifications flow down from
64 * the management class (LLNotifications, which itself inherits from
65 * The channel base class) to the individual channels.
66 * Any change to notifications (add, delete, modify) is
67 * automatically propagated through the channel hierarchy.
68 *
69 * We provide methods for adding a new notification, for removing
70 * one, and for managing channels. Channels are relatively cheap to construct
71 * and maintain, so in general, human interfaces should use channels to
72 * select and manage their lists of notifications.
73 *
74 * We also maintain a collection of templates that are loaded from the
75 * XML file of template translations. The system supports substitution
76 * of named variables from the payload into the XML file.
77 *
78 * By default, only the "unknown message" template is built into the system.
79 * It is not an error to add a notification that's not found in the
80 * template system, but it is logged.
81 *
82 */
83
84#include <string>
85#include <list>
86#include <vector>
87#include <map>
88#include <set>
89#include <iomanip>
90#include <sstream>
91
92#include <boost/utility.hpp>
93#include <boost/shared_ptr.hpp>
94#include <boost/signal.hpp>
95#include <boost/type_traits.hpp>
96
97// we want to minimize external dependencies, but this one is important
98#include "llsd.h"
99
100// and we need this to manage the notification callbacks
101#include "llfunctorregistry.h"
102#include "llui.h"
103
104class LLNotification;
105typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
106
107/*****************************************************************************
108* Signal and handler declarations
109* Using a single handler signature means that we can have a common handler
110* type, rather than needing a distinct one for each different handler.
111*****************************************************************************/
112
113/**
114 * A boost::signals Combiner that stops the first time a handler returns true
115 * We need this because we want to have our handlers return bool, so that
116 * we have the option to cause a handler to stop further processing. The
117 * default handler fails when the signal returns a value but has no slots.
118 */
119struct LLStopWhenHandled
120{
121 typedef bool result_type;
122
123 template<typename InputIterator>
124 result_type operator()(InputIterator first, InputIterator last) const
125 {
126 for (InputIterator si = first; si != last; ++si)
127 {
128 if (*si)
129 {
130 return true;
131 }
132 }
133 return false;
134 }
135};
136
137
138typedef enum e_notification_priority
139{
140 NOTIFICATION_PRIORITY_UNSPECIFIED,
141 NOTIFICATION_PRIORITY_LOW,
142 NOTIFICATION_PRIORITY_NORMAL,
143 NOTIFICATION_PRIORITY_HIGH,
144 NOTIFICATION_PRIORITY_CRITICAL
145} ENotificationPriority;
146
147/**
148 * We want to have a standard signature for all signals; this way,
149 * we can easily document a protocol for communicating across
150 * dlls and into scripting languages someday.
151 * we want to return a bool to indicate whether the signal has been
152 * handled and should NOT be passed on to other listeners.
153 * Return true to stop further handling of the signal, and false
154 * to continue.
155 * We take an LLSD because this way the contents of the signal
156 * are independent of the API used to communicate it.
157 * It is const ref because then there's low cost to pass it;
158 * if you only need to inspect it, it's very cheap.
159 */
160
161typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
162
163typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
164typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
165
166typedef boost::signal<bool(const LLSD&), LLStopWhenHandled> LLStandardSignal;
167
168// context data that can be looked up via a notification's payload by the display logic
169// derive from this class to implement specific contexts
170class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LLUUID>
171{
172public:
173 LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID())
174 {
175 }
176
177 virtual ~LLNotificationContext() {}
178
179 LLSD asLLSD() const
180 {
181 return getKey();
182 }
183
184private:
185
186};
187
188// Contains notification form data, such as buttons and text fields along with
189// manipulator functions
190class LLNotificationForm
191{
192 LOG_CLASS(LLNotificationForm);
193
194public:
195 typedef enum e_ignore_type
196 {
197 IGNORE_NO,
198 IGNORE_WITH_DEFAULT_RESPONSE,
199 IGNORE_WITH_LAST_RESPONSE,
200 IGNORE_SHOW_AGAIN
201 } EIgnoreType;
202
203 LLNotificationForm();
204 LLNotificationForm(const LLSD& sd);
205 LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node);
206
207 LLSD asLLSD() const;
208
209 S32 getNumElements() { return mFormData.size(); }
210 LLSD getElement(S32 index) { return mFormData.get(index); }
211 LLSD getElement(const std::string& element_name);
212 bool hasElement(const std::string& element_name);
213 void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD());
214 void formatElements(const LLSD& substitutions);
215 // appends form elements from another form serialized as LLSD
216 void append(const LLSD& sub_form);
217 std::string getDefaultOption();
218
219 EIgnoreType getIgnoreType() { return mIgnore; }
220 std::string getIgnoreMessage() { return mIgnoreMsg; }
221
222private:
223 LLSD mFormData;
224 EIgnoreType mIgnore;
225 std::string mIgnoreMsg;
226};
227
228typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
229
230// This is the class of object read from the XML file (notifications.xml,
231// from the appropriate local language directory).
232struct LLNotificationTemplate
233{
234 LLNotificationTemplate();
235 // the name of the notification -- the key used to identify it
236 // Ideally, the key should follow variable naming rules
237 // (no spaces or punctuation).
238 std::string mName;
239 // The type of the notification
240 // used to control which queue it's stored in
241 std::string mType;
242 // The text used to display the notification. Replaceable parameters
243 // are enclosed in square brackets like this [].
244 std::string mMessage;
245 // The label for the notification; used for
246 // certain classes of notification (those with a window and a window title).
247 // Also used when a notification pops up underneath the current one.
248 // Replaceable parameters can be used in the label.
249 std::string mLabel;
250 // The name of the icon image. This should include an extension.
251 std::string mIcon;
252 // This is the Highlander bit -- "There Can Be Only One"
253 // An outstanding notification with this bit set
254 // is updated by an incoming notification with the same name,
255 // rather than creating a new entry in the queue.
256 // (used for things like progress indications, or repeating warnings
257 // like "the grid is going down in N minutes")
258 bool mUnique;
259 // if we want to be unique only if a certain part of the payload is constant
260 // specify the field names for the payload. The notification will only be
261 // combined if all of the fields named in the context are identical in the
262 // new and the old notification; otherwise, the notification will be
263 // duplicated. This is to support suppressing duplicate offers from the same
264 // sender but still differentiating different offers. Example: Invitation to
265 // conference chat.
266 std::vector<std::string> mUniqueContext;
267 // If this notification expires automatically, this value will be
268 // nonzero, and indicates the number of seconds for which the notification
269 // will be valid (a teleport offer, for example, might be valid for
270 // 300 seconds).
271 U32 mExpireSeconds;
272 // if the offer expires, one of the options is chosen automatically
273 // based on its "value" parameter. This controls which one.
274 // If expireSeconds is specified, expireOption should also be specified.
275 U32 mExpireOption;
276 // if the notification contains a url, it's stored here (and replaced
277 // into the message where [_URL] is found)
278 std::string mURL;
279 // if there's a URL in the message, this controls which option visits
280 // that URL. Obsolete this and eliminate the buttons for affected
281 // messages when we allow clickable URLs in the UI
282 U32 mURLOption;
283 // does this notification persist across sessions? if so, it will be
284 // serialized to disk on first receipt and read on startup
285 bool mPersist;
286 // This is the name of the default functor, if present, to be
287 // used for the notification's callback. It is optional, and used only if
288 // the notification is constructed without an identified functor.
289 std::string mDefaultFunctor;
290 // The form data associated with a given notification (buttons, text boxes, etc)
291 LLNotificationFormPtr mForm;
292 // default priority for notifications of this type
293 ENotificationPriority mPriority;
294 // UUID of the audio file to be played when this notification arrives
295 // this is loaded as a name, but looked up to get the UUID upon template load.
296 // If null, it wasn't specified.
297 LLUUID mSoundEffect;
298};
299
300// we want to keep a map of these by name, and it's best to manage them
301// with smart pointers
302typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
303
304/**
305 * @class LLNotification
306 * @brief The object that expresses the details of a notification
307 *
308 * We make this noncopyable because
309 * we want to manage these through LLNotificationPtr, and only
310 * ever create one instance of any given notification.
311 *
312 * The enable_shared_from_this flag ensures that if we construct
313 * a smart pointer from a notification, we'll always get the same
314 * shared pointer.
315 */
316class LLNotification :
317 boost::noncopyable,
318 public boost::enable_shared_from_this<LLNotification>
319{
320LOG_CLASS(LLNotification);
321friend class LLNotifications;
322
323public:
324 // parameter object used to instantiate a new notification
325 class Params : public LLParamBlock<Params>
326 {
327 friend class LLNotification;
328 public:
329 Params(const std::string& _name)
330 : name(_name),
331 mTemporaryResponder(false),
332 functor_name(_name),
333 priority(NOTIFICATION_PRIORITY_UNSPECIFIED),
334 timestamp(LLDate::now())
335 {
336 }
337
338 // pseudo-param
339 Params& functor(LLNotificationFunctorRegistry::ResponseFunctor f)
340 {
341 functor_name = LLUUID::generateNewID().asString();
342 LLNotificationFunctorRegistry::instance().registerFunctor(functor_name, f);
343
344 mTemporaryResponder = true;
345 return *this;
346 }
347
348 LLMandatoryParam<std::string> name;
349
350 // optional
351 LLOptionalParam<LLSD> substitutions;
352 LLOptionalParam<LLSD> payload;
353 LLOptionalParam<ENotificationPriority> priority;
354 LLOptionalParam<LLSD> form_elements;
355 LLOptionalParam<LLDate> timestamp;
356 LLOptionalParam<LLNotificationContext*> context;
357 LLOptionalParam<std::string> functor_name;
358
359 private:
360 bool mTemporaryResponder;
361 };
362
363private:
364
365 LLUUID mId;
366 LLSD mPayload;
367 LLSD mSubstitutions;
368 LLDate mTimestamp;
369 LLDate mExpiresAt;
370 bool mCancelled;
371 bool mRespondedTo; // once the notification has been responded to, this becomes true
372 bool mIgnored;
373 ENotificationPriority mPriority;
374 LLNotificationFormPtr mForm;
375
376 // a reference to the template
377 LLNotificationTemplatePtr mTemplatep;
378
379 /*
380 We want to be able to store and reload notifications so that they can survive
381 a shutdown/restart of the client. So we can't simply pass in callbacks;
382 we have to specify a callback mechanism that can be used by name rather than
383 by some arbitrary pointer -- and then people have to initialize callbacks
384 in some useful location. So we use LLNotificationFunctorRegistry to manage them.
385 */
386 std::string mResponseFunctorName;
387
388 /*
389 In cases where we want to specify an explict, non-persisted callback,
390 we store that in the callback registry under a dynamically generated
391 key, and store the key in the notification, so we can still look it up
392 using the same mechanism.
393 */
394 bool mTemporaryResponder;
395
396 void init(const std::string& template_name, const LLSD& form_elements);
397
398 LLNotification(const Params& p);
399
400 // this is just for making it easy to look things up in a set organized by UUID -- DON'T USE IT
401 // for anything real!
402 LLNotification(LLUUID uuid) : mId(uuid) {}
403
404 void cancel();
405
406 bool payloadContainsAll(const std::vector<std::string>& required_fields) const;
407
408public:
409
410 // constructor from a saved notification
411 LLNotification(const LLSD& sd);
412
413 // This is a string formatter for substituting into the message directly
414 // from LLSD without going through the hopefully-to-be-obsoleted LLString
415 static std::string format(const std::string& text, const LLSD& substitutions);
416
417 void setResponseFunctor(std::string const &responseFunctorName);
418
419 typedef enum e_response_template_type
420 {
421 WITHOUT_DEFAULT_BUTTON,
422 WITH_DEFAULT_BUTTON
423 } EResponseTemplateType;
424
425 // return response LLSD filled in with default form contents and (optionally) the default button selected
426 LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON);
427
428 // returns index of first button with value==TRUE
429 // usually this the button the user clicked on
430 // returns -1 if no button clicked (e.g. form has not been displayed)
431 static S32 getSelectedOption(const LLSD& notification, const LLSD& response);
432 // returns name of first button with value==TRUE
433 static std::string getSelectedOptionName(const LLSD& notification);
434
435 // after someone responds to a notification (usually by clicking a button,
436 // but sometimes by filling out a little form and THEN clicking a button),
437 // the result of the response (the name and value of the button clicked,
438 // plus any other data) should be packaged up as LLSD, then passed as a
439 // parameter to the notification's respond() method here. This will look up
440 // and call the appropriate responder.
441 //
442 // response is notification serialized as LLSD:
443 // ["name"] = notification name
444 // ["form"] = LLSD tree that includes form description and any prefilled form data
445 // ["response"] = form data filled in by user
446 // (including, but not limited to which button they clicked on)
447 // ["payload"] = transaction specific data, such as ["source_id"] (originator of notification),
448 // ["item_id"] (attached inventory item), etc.
449 // ["substitutions"] = string substitutions used to generate notification message
450 // from the template
451 // ["time"] = time at which notification was generated;
452 // ["expiry"] = time at which notification expires;
453 // ["responseFunctor"] = name of registered functor that handles responses to notification;
454 LLSD asLLSD();
455
456 void respond(const LLSD& sd);
457
458 void setIgnored(bool ignore);
459
460 bool isCancelled() const
461 {
462 return mCancelled;
463 }
464
465 bool isRespondedTo() const
466 {
467 return mRespondedTo;
468 }
469
470 bool isIgnored() const
471 {
472 return mIgnored;
473 }
474
475 const std::string& getName() const
476 {
477 return mTemplatep->mName;
478 }
479
480 const LLUUID& id() const
481 {
482 return mId;
483 }
484
485 const LLSD& getPayload() const
486 {
487 return mPayload;
488 }
489
490 const LLSD& getSubstitutions() const
491 {
492 return mSubstitutions;
493 }
494
495 const LLDate& getDate() const
496 {
497 return mTimestamp;
498 }
499
500 std::string getType() const
501 {
502 return (mTemplatep ? mTemplatep->mType : "");
503 }
504
505 std::string getMessage() const;
506 std::string getLabel() const;
507
508 std::string getURL() const
509 {
510 return (mTemplatep ? mTemplatep->mURL : "");
511 }
512
513 S32 getURLOption() const
514 {
515 return (mTemplatep ? mTemplatep->mURLOption : -1);
516 }
517
518 const LLNotificationFormPtr getForm();
519
520 const LLDate getExpiration() const
521 {
522 return mExpiresAt;
523 }
524
525 ENotificationPriority getPriority() const
526 {
527 return mPriority;
528 }
529
530 const LLUUID getID() const
531 {
532 return mId;
533 }
534
535 // comparing two notifications normally means comparing them by UUID (so we can look them
536 // up quickly this way)
537 bool operator<(const LLNotification& rhs) const
538 {
539 return mId < rhs.mId;
540 }
541
542 bool operator==(const LLNotification& rhs) const
543 {
544 return mId == rhs.mId;
545 }
546
547 bool operator!=(const LLNotification& rhs) const
548 {
549 return !operator==(rhs);
550 }
551
552 bool isSameObjectAs(const LLNotification* rhs) const
553 {
554 return this == rhs;
555 }
556
557 // this object has been updated, so tell all our clients
558 void update();
559
560 void updateFrom(LLNotificationPtr other);
561
562 // A fuzzy equals comparator.
563 // true only if both notifications have the same template and
564 // 1) flagged as unique (there can be only one of these) OR
565 // 2) all required payload fields of each also exist in the other.
566 bool isEquivalentTo(LLNotificationPtr that) const;
567
568 // if the current time is greater than the expiration, the notification is expired
569 bool isExpired() const
570 {
571 if (mExpiresAt.secondsSinceEpoch() == 0)
572 {
573 return false;
574 }
575
576 LLDate rightnow = LLDate::now();
577 return rightnow > mExpiresAt;
578 }
579
580 std::string summarize() const;
581
582 bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);}
583
584 virtual ~LLNotification() {}
585};
586
587std::ostream& operator<<(std::ostream& s, const LLNotification& notification);
588
589namespace LLNotificationFilters
590{
591 // a sample filter
592 bool includeEverything(LLNotificationPtr p);
593
594 typedef enum e_comparison
595 {
596 EQUAL,
597 LESS,
598 GREATER,
599 LESS_EQUAL,
600 GREATER_EQUAL
601 } EComparison;
602
603 // generic filter functor that takes method or member variable reference
604 template<typename T>
605 struct filterBy
606 {
607 typedef boost::function<T (LLNotificationPtr)> field_t;
608 typedef typename boost::remove_reference<T>::type value_t;
609
610 filterBy(field_t field, value_t value, EComparison comparison = EQUAL)
611 : mField(field),
612 mFilterValue(value),
613 mComparison(comparison)
614 {
615 }
616
617 bool operator()(LLNotificationPtr p)
618 {
619 switch(mComparison)
620 {
621 case EQUAL:
622 return mField(p) == mFilterValue;
623 case LESS:
624 return mField(p) < mFilterValue;
625 case GREATER:
626 return mField(p) > mFilterValue;
627 case LESS_EQUAL:
628 return mField(p) <= mFilterValue;
629 case GREATER_EQUAL:
630 return mField(p) >= mFilterValue;
631 default:
632 return false;
633 }
634 }
635
636 field_t mField;
637 value_t mFilterValue;
638 EComparison mComparison;
639 };
640};
641
642namespace LLNotificationComparators
643{
644 typedef enum e_direction { ORDER_DECREASING, ORDER_INCREASING } EDirection;
645
646 // generic order functor that takes method or member variable reference
647 template<typename T>
648 struct orderBy
649 {
650 typedef boost::function<T (LLNotificationPtr)> field_t;
651 orderBy(field_t field, EDirection = ORDER_INCREASING) : mField(field) {}
652 bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)
653 {
654 if (mDirection == ORDER_DECREASING)
655 {
656 return mField(lhs) > mField(rhs);
657 }
658 else
659 {
660 return mField(lhs) < mField(rhs);
661 }
662 }
663
664 field_t mField;
665 EDirection mDirection;
666 };
667
668 struct orderByUUID : public orderBy<const LLUUID&>
669 {
670 orderByUUID(EDirection direction = ORDER_INCREASING) : orderBy<const LLUUID&>(&LLNotification::id, direction) {}
671 };
672
673 struct orderByDate : public orderBy<const LLDate&>
674 {
675 orderByDate(EDirection direction = ORDER_INCREASING) : orderBy<const LLDate&>(&LLNotification::getDate, direction) {}
676 };
677};
678
679typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter;
680typedef boost::function<bool (LLNotificationPtr, LLNotificationPtr)> LLNotificationComparator;
681typedef std::set<LLNotificationPtr, LLNotificationComparator> LLNotificationSet;
682typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
683
684// ========================================================
685// Abstract base class (interface) for a channel; also used for the master container.
686// This lets us arrange channels into a call hierarchy.
687
688// We maintain a heirarchy of notification channels; events are always started at the top
689// and propagated through the hierarchy only if they pass a filter.
690// Any channel can be created with a parent. A null parent (empty string) means it's
691// tied to the root of the tree (the LLNotifications class itself).
692// The default hierarchy looks like this:
693//
694// LLNotifications --+-- Expiration --+-- Mute --+-- Ignore --+-- Visible --+-- History
695// +-- Alerts
696// +-- Notifications
697//
698// In general, new channels that want to only see notifications that pass through
699// all of the built-in tests should attach to the "Visible" channel
700//
701class LLNotificationChannelBase :
702 public boost::signals::trackable
703{
704 LOG_CLASS(LLNotificationChannelBase);
705public:
706 LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) :
707 mFilter(filter), mItems(comp)
708 {}
709 virtual ~LLNotificationChannelBase() {}
710 // you can also connect to a Channel, so you can be notified of
711 // changes to this channel
712 virtual void connectChanged(const LLStandardSignal::slot_type& slot);
713 virtual void connectPassedFilter(const LLStandardSignal::slot_type& slot);
714 virtual void connectFailedFilter(const LLStandardSignal::slot_type& slot);
715
716 // use this when items change or to add a new one
717 bool updateItem(const LLSD& payload);
718 const LLNotificationFilter& getFilter() { return mFilter; }
719
720protected:
721 LLNotificationSet mItems;
722 LLStandardSignal mChanged;
723 LLStandardSignal mPassedFilter;
724 LLStandardSignal mFailedFilter;
725
726 // these are action methods that subclasses can override to take action
727 // on specific types of changes; the management of the mItems list is
728 // still handled by the generic handler.
729 virtual void onLoad(LLNotificationPtr p) {}
730 virtual void onAdd(LLNotificationPtr p) {}
731 virtual void onDelete(LLNotificationPtr p) {}
732 virtual void onChange(LLNotificationPtr p) {}
733
734 bool updateItem(const LLSD& payload, LLNotificationPtr pNotification);
735 LLNotificationFilter mFilter;
736};
737
738// The type of the pointers that we're going to manage in the NotificationQueue system
739// Because LLNotifications is a singleton, we don't actually expect to ever
740// destroy it, but if it becomes necessary to do so, the shared_ptr model
741// will ensure that we don't leak resources.
742class LLNotificationChannel;
743typedef boost::shared_ptr<LLNotificationChannel> LLNotificationChannelPtr;
744
745// manages a list of notifications
746// Note that if this is ever copied around, we might find ourselves with multiple copies
747// of a queue with notifications being added to different nonequivalent copies. So we
748// make it inherit from boost::noncopyable, and then create a map of shared_ptr to manage it.
749//
750// NOTE: LLNotificationChannel is self-registering. The *correct* way to create one is to
751// do something like:
752// LLNotificationChannel::buildChannel("name", "parent"...);
753// This returns an LLNotificationChannelPtr, which you can store, or
754// you can then retrieve the channel by using the registry:
755// LLNotifications::instance().getChannel("name")...
756//
757class LLNotificationChannel :
758 boost::noncopyable,
759 public LLNotificationChannelBase
760{
761 LOG_CLASS(LLNotificationChannel);
762
763public:
764 virtual ~LLNotificationChannel() {}
765 typedef LLNotificationSet::iterator Iterator;
766
767 std::string getName() const { return mName; }
768 std::string getParentChannelName() { return mParent; }
769
770 bool isEmpty() const;
771
772 Iterator begin();
773 Iterator end();
774
775 // Channels have a comparator to control sort order;
776 // the default sorts by arrival date
777 void setComparator(LLNotificationComparator comparator);
778
779 std::string summarize();
780
781 // factory method for constructing these channels; since they're self-registering,
782 // we want to make sure that you can't use new to make them
783 static LLNotificationChannelPtr buildChannel(const std::string& name, const std::string& parent,
784 LLNotificationFilter filter=LLNotificationFilters::includeEverything,
785 LLNotificationComparator comparator=LLNotificationComparators::orderByUUID());
786
787protected:
788 // Notification Channels have a filter, which determines which notifications
789 // will be added to this channel.
790 // Channel filters cannot change.
791 // Channels have a protected constructor so you can't make smart pointers that don't
792 // come from our internal reference; call NotificationChannel::build(args)
793 LLNotificationChannel(const std::string& name, const std::string& parent,
794 LLNotificationFilter filter, LLNotificationComparator comparator);
795
796private:
797 std::string mName;
798 std::string mParent;
799 LLNotificationComparator mComparator;
800};
801
802
803
804class LLNotifications :
805 public LLSingleton<LLNotifications>,
806 public LLNotificationChannelBase
807{
808 LOG_CLASS(LLNotifications);
809
810 friend class LLSingleton<LLNotifications>;
811public:
812 // load notification descriptions from file;
813 // OK to call more than once because it will reload
814 bool loadTemplates();
815 LLXMLNodePtr checkForXMLTemplate(LLXMLNodePtr item);
816
817 // we provide a collection of simple add notification functions so that it's reasonable to create notifications in one line
818 LLNotificationPtr add(const std::string& name,
819 const LLSD& substitutions = LLSD(),
820 const LLSD& payload = LLSD());
821 LLNotificationPtr add(const std::string& name,
822 const LLSD& substitutions,
823 const LLSD& payload,
824 const std::string& functor_name);
825 LLNotificationPtr add(const std::string& name,
826 const LLSD& substitutions,
827 const LLSD& payload,
828 LLNotificationFunctorRegistry::ResponseFunctor functor);
829 LLNotificationPtr add(const LLNotification::Params& p);
830
831 void add(const LLNotificationPtr pNotif);
832 void cancel(LLNotificationPtr pNotif);
833 void update(const LLNotificationPtr pNotif);
834
835 LLNotificationPtr find(LLUUID uuid);
836
837 typedef boost::function<void (LLNotificationPtr)> NotificationProcess;
838
839 void forEachNotification(NotificationProcess process);
840
841 // This is all stuff for managing the templates
842 // take your template out
843 LLNotificationTemplatePtr getTemplate(const std::string& name);
844
845 // get the whole collection
846 typedef std::vector<std::string> TemplateNames;
847 TemplateNames getTemplateNames() const; // returns a list of notification names
848
849 typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap;
850
851 TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); }
852 TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); }
853
854 // test for existence
855 bool templateExists(const std::string& name);
856 // useful if you're reloading the file
857 void clearTemplates(); // erase all templates
858
859 void forceResponse(const LLNotification::Params& params, S32 option);
860
861 void createDefaultChannels();
862
863 typedef std::map<std::string, LLNotificationChannelPtr> ChannelMap;
864 ChannelMap mChannels;
865
866 void addChannel(LLNotificationChannelPtr pChan);
867 LLNotificationChannelPtr getChannel(const std::string& channelName);
868
869 std::string getGlobalString(const std::string& key) const;
870
871private:
872 // we're a singleton, so we don't have a public constructor
873 LLNotifications();
874 /*virtual*/ void initSingleton();
875
876 void loadPersistentNotifications();
877
878 bool expirationFilter(LLNotificationPtr pNotification);
879 bool expirationHandler(const LLSD& payload);
880 bool uniqueFilter(LLNotificationPtr pNotification);
881 bool uniqueHandler(const LLSD& payload);
882 bool failedUniquenessTest(const LLSD& payload);
883 LLNotificationChannelPtr pHistoryChannel;
884 LLNotificationChannelPtr pExpirationChannel;
885
886 // put your template in
887 bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate);
888 TemplateMap mTemplates;
889
890 std::string mFileName;
891
892 typedef std::map<std::string, LLXMLNodePtr> XMLTemplateMap;
893 XMLTemplateMap mXmlTemplates;
894
895 LLNotificationMap mUniqueNotifications;
896
897 typedef std::map<std::string, std::string> GlobalStringMap;
898 GlobalStringMap mGlobalStrings;
899};
900
901
902#endif//LL_LLNOTIFICATIONS_H
903
diff --git a/linden/indra/llui/llpanel.cpp b/linden/indra/llui/llpanel.cpp
index d37517f..92d045d 100644
--- a/linden/indra/llui/llpanel.cpp
+++ b/linden/indra/llui/llpanel.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -58,8 +59,6 @@
58#include "llresizebar.h" 59#include "llresizebar.h"
59#include "llcriticaldamp.h" 60#include "llcriticaldamp.h"
60 61
61LLPanel::alert_queue_t LLPanel::sAlertQueue;
62
63const S32 RESIZE_BAR_OVERLAP = 1; 62const S32 RESIZE_BAR_OVERLAP = 1;
64const S32 RESIZE_BAR_HEIGHT = 3; 63const S32 RESIZE_BAR_HEIGHT = 3;
65 64
@@ -344,14 +343,14 @@ BOOL LLPanel::checkRequirements()
344{ 343{
345 if (!mRequirementsError.empty()) 344 if (!mRequirementsError.empty())
346 { 345 {
347 LLStringUtil::format_map_t args; 346 LLSD args;
348 args["[COMPONENTS]"] = mRequirementsError; 347 args["COMPONENTS"] = mRequirementsError;
349 args["[FLOATER]"] = getName(); 348 args["FLOATER"] = getName();
350 349
351 llwarns << getName() << " failed requirements check on: \n" 350 llwarns << getName() << " failed requirements check on: \n"
352 << mRequirementsError << llendl; 351 << mRequirementsError << llendl;
353 352
354 alertXml(std::string("FailedRequirementsCheck"), args); 353 LLNotifications::instance().add(LLNotification::Params("FailedRequirementsCheck").payload(args));
355 mRequirementsError.clear(); 354 mRequirementsError.clear();
356 return FALSE; 355 return FALSE;
357 } 356 }
@@ -359,25 +358,6 @@ BOOL LLPanel::checkRequirements()
359 return TRUE; 358 return TRUE;
360} 359}
361 360
362//static
363void LLPanel::alertXml(const std::string& label, LLStringUtil::format_map_t args)
364{
365 sAlertQueue.push(LLAlertInfo(label,args));
366}
367
368//static
369BOOL LLPanel::nextAlert(LLAlertInfo &alert)
370{
371 if (!sAlertQueue.empty())
372 {
373 alert = sAlertQueue.front();
374 sAlertQueue.pop();
375 return TRUE;
376 }
377
378 return FALSE;
379}
380
381void LLPanel::setFocus(BOOL b) 361void LLPanel::setFocus(BOOL b)
382{ 362{
383 if( b ) 363 if( b )
@@ -927,7 +907,7 @@ LLPanel *LLPanel::childGetVisibleTab(const std::string& id) const
927 return NULL; 907 return NULL;
928} 908}
929 909
930void LLPanel::childSetTabChangeCallback(const std::string& id, const std::string& tabname, void (*on_tab_clicked)(void*, bool), void *userdata) 910void LLPanel::childSetTabChangeCallback(const std::string& id, const std::string& tabname, void (*on_tab_clicked)(void*, bool), void *userdata, void (*on_precommit)(void*,bool))
931{ 911{
932 LLTabContainer* child = getChild<LLTabContainer>(id); 912 LLTabContainer* child = getChild<LLTabContainer>(id);
933 if (child) 913 if (child)
@@ -937,6 +917,10 @@ void LLPanel::childSetTabChangeCallback(const std::string& id, const std::string
937 { 917 {
938 child->setTabChangeCallback(panel, on_tab_clicked); 918 child->setTabChangeCallback(panel, on_tab_clicked);
939 child->setTabUserData(panel, userdata); 919 child->setTabUserData(panel, userdata);
920 if (on_precommit)
921 {
922 child->setTabPrecommitChangeCallback(panel, on_precommit);
923 }
940 } 924 }
941 } 925 }
942} 926}
@@ -982,12 +966,12 @@ void LLPanel::childSetAction(const std::string& id, void(*function)(void*), void
982 } 966 }
983} 967}
984 968
985void LLPanel::childSetActionTextbox(const std::string& id, void(*function)(void*)) 969void LLPanel::childSetActionTextbox(const std::string& id, void(*function)(void*), void* value)
986{ 970{
987 LLTextBox* textbox = getChild<LLTextBox>(id); 971 LLTextBox* textbox = getChild<LLTextBox>(id);
988 if (textbox) 972 if (textbox)
989 { 973 {
990 textbox->setClickedCallback(function); 974 textbox->setClickedCallback(function, value);
991 } 975 }
992} 976}
993 977
@@ -1039,9 +1023,9 @@ void LLPanel::childDisplayNotFound()
1039 mExpectedMembers.insert(*itor); 1023 mExpectedMembers.insert(*itor);
1040 } 1024 }
1041 mNewExpectedMembers.clear(); 1025 mNewExpectedMembers.clear();
1042 LLStringUtil::format_map_t args; 1026 LLSD args;
1043 args["[CONTROLS]"] = msg; 1027 args["CONTROLS"] = msg;
1044 LLAlertDialog::showXml("FloaterNotFound", args); 1028 LLNotifications::instance().add("FloaterNotFound", args);
1045} 1029}
1046 1030
1047void LLPanel::storeRectControl() 1031void LLPanel::storeRectControl()
@@ -1065,6 +1049,8 @@ struct LLLayoutStack::LLEmbeddedPanel
1065 mAutoResize(auto_resize), 1049 mAutoResize(auto_resize),
1066 mUserResize(user_resize), 1050 mUserResize(user_resize),
1067 mOrientation(orientation), 1051 mOrientation(orientation),
1052 mCollapsed(FALSE),
1053 mCollapseAmt(0.f),
1068 mVisibleAmt(1.f) // default to fully visible 1054 mVisibleAmt(1.f) // default to fully visible
1069 { 1055 {
1070 LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM; 1056 LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
@@ -1095,14 +1081,28 @@ struct LLLayoutStack::LLEmbeddedPanel
1095 mResizeBar = NULL; 1081 mResizeBar = NULL;
1096 } 1082 }
1097 1083
1084 F32 getCollapseFactor()
1085 {
1086 if (mOrientation == HORIZONTAL)
1087 {
1088 return mVisibleAmt * clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)mPanel->getRect().getWidth());
1089 }
1090 else
1091 {
1092 return mVisibleAmt * clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinHeight / (F32)mPanel->getRect().getHeight());
1093 }
1094 }
1095
1098 LLPanel* mPanel; 1096 LLPanel* mPanel;
1099 S32 mMinWidth; 1097 S32 mMinWidth;
1100 S32 mMinHeight; 1098 S32 mMinHeight;
1101 BOOL mAutoResize; 1099 BOOL mAutoResize;
1102 BOOL mUserResize; 1100 BOOL mUserResize;
1101 BOOL mCollapsed;
1103 LLResizeBar* mResizeBar; 1102 LLResizeBar* mResizeBar;
1104 eLayoutOrientation mOrientation; 1103 eLayoutOrientation mOrientation;
1105 F32 mVisibleAmt; 1104 F32 mVisibleAmt;
1105 F32 mCollapseAmt;
1106}; 1106};
1107 1107
1108static LLRegisterWidget<LLLayoutStack> r2("layout_stack"); 1108static LLRegisterWidget<LLLayoutStack> r2("layout_stack");
@@ -1123,28 +1123,27 @@ LLLayoutStack::~LLLayoutStack()
1123void LLLayoutStack::draw() 1123void LLLayoutStack::draw()
1124{ 1124{
1125 updateLayout(); 1125 updateLayout();
1126
1127 e_panel_list_t::iterator panel_it;
1128 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
1126 { 1129 {
1127 e_panel_list_t::iterator panel_it; 1130 // clip to layout rectangle, not bounding rectangle
1128 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) 1131 LLRect clip_rect = (*panel_it)->mPanel->getRect();
1132 // scale clipping rectangle by visible amount
1133 if (mOrientation == HORIZONTAL)
1129 { 1134 {
1130 // clip to layout rectangle, not bounding rectangle 1135 clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor());
1131 LLRect clip_rect = (*panel_it)->mPanel->getRect(); 1136 }
1132 // scale clipping rectangle by visible amount 1137 else
1133 if (mOrientation == HORIZONTAL) 1138 {
1134 { 1139 clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor());
1135 clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->mVisibleAmt); 1140 }
1136 }
1137 else
1138 {
1139 clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->mVisibleAmt);
1140 }
1141 1141
1142 LLPanel* panelp = (*panel_it)->mPanel; 1142 LLPanel* panelp = (*panel_it)->mPanel;
1143 1143
1144 LLLocalClipRect clip(clip_rect); 1144 LLLocalClipRect clip(clip_rect);
1145 // only force drawing invisible children if visible amount is non-zero 1145 // only force drawing invisible children if visible amount is non-zero
1146 drawChild(panelp, 0, 0, !clip_rect.isNull()); 1146 drawChild(panelp, 0, 0, !clip_rect.isNull());
1147 }
1148 } 1147 }
1149} 1148}
1150 1149
@@ -1276,8 +1275,13 @@ S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
1276 return cur_width; 1275 return cur_width;
1277} 1276}
1278 1277
1279void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, S32 index) 1278void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate, S32 index)
1280{ 1279{
1280 // panel starts off invisible (collapsed)
1281 if (animate == ANIMATE)
1282 {
1283 panel->setVisible(FALSE);
1284 }
1281 LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize); 1285 LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize);
1282 1286
1283 mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel); 1287 mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
@@ -1293,6 +1297,11 @@ void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL
1293 sendChildToFront(resize_barp); 1297 sendChildToFront(resize_barp);
1294 } 1298 }
1295 1299
1300 // start expanding panel animation
1301 if (animate == ANIMATE)
1302 {
1303 panel->setVisible(TRUE);
1304 }
1296} 1305}
1297 1306
1298void LLLayoutStack::removePanel(LLPanel* panel) 1307void LLLayoutStack::removePanel(LLPanel* panel)
@@ -1300,6 +1309,14 @@ void LLLayoutStack::removePanel(LLPanel* panel)
1300 removeChild(panel); 1309 removeChild(panel);
1301} 1310}
1302 1311
1312void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
1313{
1314 LLEmbeddedPanel* panel_container = findEmbeddedPanel(panel);
1315 if (!panel_container) return;
1316
1317 panel_container->mCollapsed = collapsed;
1318}
1319
1303void LLLayoutStack::updateLayout(BOOL force_resize) 1320void LLLayoutStack::updateLayout(BOOL force_resize)
1304{ 1321{
1305 calcMinExtents(); 1322 calcMinExtents();
@@ -1332,6 +1349,15 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
1332 } 1349 }
1333 } 1350 }
1334 1351
1352 if ((*panel_it)->mCollapsed)
1353 {
1354 (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
1355 }
1356 else
1357 {
1358 (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
1359 }
1360
1335 if (mOrientation == HORIZONTAL) 1361 if (mOrientation == HORIZONTAL)
1336 { 1362 {
1337 // enforce minimize size constraint by default 1363 // enforce minimize size constraint by default
@@ -1339,7 +1365,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
1339 { 1365 {
1340 panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight()); 1366 panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight());
1341 } 1367 }
1342 total_width += llround(panelp->getRect().getWidth() * (*panel_it)->mVisibleAmt); 1368 total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor());
1343 // want n-1 panel gaps for n panels 1369 // want n-1 panel gaps for n panels
1344 if (panel_it != mPanels.begin()) 1370 if (panel_it != mPanels.begin())
1345 { 1371 {
@@ -1353,7 +1379,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
1353 { 1379 {
1354 panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight); 1380 panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight);
1355 } 1381 }
1356 total_height += llround(panelp->getRect().getHeight() * (*panel_it)->mVisibleAmt); 1382 total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor());
1357 if (panel_it != mPanels.begin()) 1383 if (panel_it != mPanels.begin())
1358 { 1384 {
1359 total_height += mPanelSpacing; 1385 total_height += mPanelSpacing;
@@ -1367,7 +1393,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
1367 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) 1393 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
1368 { 1394 {
1369 // panels that are not fully visible do not count towards shrink headroom 1395 // panels that are not fully visible do not count towards shrink headroom
1370 if ((*panel_it)->mVisibleAmt < 1.f) 1396 if ((*panel_it)->getCollapseFactor() < 1.f)
1371 { 1397 {
1372 continue; 1398 continue;
1373 } 1399 }
@@ -1431,7 +1457,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
1431 S32 delta_size = 0; 1457 S32 delta_size = 0;
1432 1458
1433 // if panel can automatically resize (not animating, and resize flag set)... 1459 // if panel can automatically resize (not animating, and resize flag set)...
1434 if ((*panel_it)->mVisibleAmt == 1.f 1460 if ((*panel_it)->getCollapseFactor() == 1.f
1435 && (force_resize || (*panel_it)->mAutoResize) 1461 && (force_resize || (*panel_it)->mAutoResize)
1436 && !(*panel_it)->mResizeBar->hasMouseCapture()) 1462 && !(*panel_it)->mResizeBar->hasMouseCapture())
1437 { 1463 {
@@ -1515,11 +1541,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
1515 1541
1516 if (mOrientation == HORIZONTAL) 1542 if (mOrientation == HORIZONTAL)
1517 { 1543 {
1518 cur_x += llround(new_width * (*panel_it)->mVisibleAmt) + mPanelSpacing; 1544 cur_x += llround(new_width * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
1519 } 1545 }
1520 else //VERTICAL 1546 else //VERTICAL
1521 { 1547 {
1522 cur_y -= llround(new_height * (*panel_it)->mVisibleAmt) + mPanelSpacing; 1548 cur_y -= llround(new_height * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
1523 } 1549 }
1524 } 1550 }
1525 1551
diff --git a/linden/indra/llui/llpanel.h b/linden/indra/llui/llpanel.h
index 46022e5..756d02e 100644
--- a/linden/indra/llui/llpanel.h
+++ b/linden/indra/llui/llpanel.h
@@ -18,7 +18,8 @@
18 * There are special exceptions to the terms and conditions of the GPL as 18 * There are special exceptions to the terms and conditions of the GPL as
19 * it is applied to this Source Code. View the full text of the exception 19 * it is applied to this Source Code. View the full text of the exception
20 * in the file doc/FLOSS-exception.txt in this software distribution, or 20 * in the file doc/FLOSS-exception.txt in this software distribution, or
21 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 21 * online at
22 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 * 23 *
23 * By copying, modifying or distributing this software, you acknowledge 24 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above, 25 * that you have read and understood your obligations described above,
@@ -49,23 +50,13 @@ const BOOL BORDER_YES = TRUE;
49const BOOL BORDER_NO = FALSE; 50const BOOL BORDER_NO = FALSE;
50 51
51 52
52struct LLAlertInfo
53{
54 std::string mLabel;
55 LLStringUtil::format_map_t mArgs;
56
57 LLAlertInfo(std::string label, LLStringUtil::format_map_t args) : mLabel(label), mArgs(args) { }
58 LLAlertInfo(){}
59};
60
61
62/* 53/*
63 * General purpose concrete view base class. 54 * General purpose concrete view base class.
64 * Transparent or opaque, 55 * Transparent or opaque,
65 * With or without border, 56 * With or without border,
66 * Can contain LLUICtrls. 57 * Can contain LLUICtrls.
67 */ 58 */
68class LLPanel : public LLUICtrl 59class LLPanel : public LLUICtrl, public boost::signals::trackable
69{ 60{
70public: 61public:
71 62
@@ -205,7 +196,7 @@ public:
205 // LLTabContainer 196 // LLTabContainer
206 void childShowTab(const std::string& id, const std::string& tabname, bool visible = true); 197 void childShowTab(const std::string& id, const std::string& tabname, bool visible = true);
207 LLPanel *childGetVisibleTab(const std::string& id) const; 198 LLPanel *childGetVisibleTab(const std::string& id) const;
208 void childSetTabChangeCallback(const std::string& id, const std::string& tabname, void (*on_tab_clicked)(void*, bool), void *userdata); 199 void childSetTabChangeCallback(const std::string& id, const std::string& tabname, void (*on_tab_clicked)(void*, bool), void *userdata, void (*on_precommit)(void*,bool) = NULL);
209 200
210 // LLTextBox 201 // LLTextBox
211 void childSetWrappedText(const std::string& id, const std::string& text, bool visible = true); 202 void childSetWrappedText(const std::string& id, const std::string& text, bool visible = true);
@@ -220,15 +211,13 @@ public:
220 211
221 // LLButton 212 // LLButton
222 void childSetAction(const std::string& id, void(*function)(void*), void* value); 213 void childSetAction(const std::string& id, void(*function)(void*), void* value);
223 void childSetActionTextbox(const std::string& id, void(*function)(void*)); 214 void childSetActionTextbox(const std::string& id, void(*function)(void*), void* value = NULL);
224 void childSetControlName(const std::string& id, const std::string& control_name); 215 void childSetControlName(const std::string& id, const std::string& control_name);
225 216
226 // Error reporting 217 // Error reporting
227 void childNotFound(const std::string& id) const; 218 void childNotFound(const std::string& id) const;
228 void childDisplayNotFound(); 219 void childDisplayNotFound();
229 220
230 static void alertXml(const std::string& label, LLStringUtil::format_map_t args = LLStringUtil::format_map_t());
231 static BOOL nextAlert(LLAlertInfo &alert);
232 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); 221 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
233 222
234protected: 223protected:
@@ -266,8 +255,6 @@ private:
266 255
267 std::string mRequirementsError; 256 std::string mRequirementsError;
268 257
269 typedef std::queue<LLAlertInfo> alert_queue_t;
270 static alert_queue_t sAlertQueue;
271}; // end class LLPanel 258}; // end class LLPanel
272 259
273 260
@@ -292,8 +279,16 @@ public:
292 S32 getMinWidth() const { return mMinWidth; } 279 S32 getMinWidth() const { return mMinWidth; }
293 S32 getMinHeight() const { return mMinHeight; } 280 S32 getMinHeight() const { return mMinHeight; }
294 281
295 void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, S32 index = S32_MAX); 282 typedef enum e_animate
283 {
284 NO_ANIMATE,
285 ANIMATE
286 } EAnimate;
287
288 void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate = NO_ANIMATE, S32 index = S32_MAX);
296 void removePanel(LLPanel* panel); 289 void removePanel(LLPanel* panel);
290 void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE);
291 S32 getNumPanels() { return mPanels.size(); }
297 292
298private: 293private:
299 struct LLEmbeddedPanel; 294 struct LLEmbeddedPanel;
diff --git a/linden/indra/llui/llprogressbar.cpp b/linden/indra/llui/llprogressbar.cpp
new file mode 100644
index 0000000..8833494
--- /dev/null
+++ b/linden/indra/llui/llprogressbar.cpp
@@ -0,0 +1,181 @@
1/**
2 * @file llprogressbar.cpp
3 * @brief LLProgressBar class implementation
4 *
5 * $LicenseInfo:firstyear=2002&license=viewergpl$
6 *
7 * Copyright (c) 2002-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * 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
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "linden_common.h"
34
35#include "llprogressbar.h"
36
37#include "indra_constants.h"
38#include "llmath.h"
39#include "llgl.h"
40#include "llui.h"
41#include "llfontgl.h"
42#include "llimagegl.h"
43#include "lltimer.h"
44#include "llglheaders.h"
45
46#include "llfocusmgr.h"
47
48static LLRegisterWidget<LLProgressBar> r("progress_bar");
49
50LLProgressBar::LLProgressBar(const std::string& name, const LLRect &rect)
51 : LLView(name, rect, FALSE),
52 mImageBar( NULL ),
53 mImageShadow( NULL )
54{
55 mPercentDone = 0.f;
56
57 // Defaults:
58
59 setImageBar("rounded_square.tga");
60 setImageShadow("rounded_square_soft.tga");
61
62 mColorBackground = LLColor4(0.3254f, 0.4000f, 0.5058f, 1.0f);
63 mColorBar = LLColor4(0.5764f, 0.6627f, 0.8352f, 1.0f);
64 mColorBar2 = LLColor4(0.5764f, 0.6627f, 0.8352f, 1.0f);
65 mColorShadow = LLColor4(0.2000f, 0.2000f, 0.4000f, 1.0f);
66}
67
68LLProgressBar::~LLProgressBar()
69{
70 gFocusMgr.releaseFocusIfNeeded( this );
71}
72
73void LLProgressBar::draw()
74{
75 static LLTimer timer;
76
77 LLUIImagePtr shadow_imagep = LLUI::getUIImage("rounded_square_soft.tga");
78 LLUIImagePtr bar_fg_imagep = LLUI::getUIImage("progressbar_fill.tga");
79 LLUIImagePtr bar_bg_imagep = LLUI::getUIImage("progressbar_track.tga");
80 LLUIImagePtr bar_imagep = LLUI::getUIImage("rounded_square.tga");
81 LLColor4 background_color = LLUI::sColorsGroup->getColor("LoginProgressBarBgColor");
82
83 bar_bg_imagep->draw(getLocalRect(),
84 background_color);
85
86 F32 alpha = 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
87 LLColor4 bar_color = LLUI::sColorsGroup->getColor("LoginProgressBarFgColor");
88 bar_color.mV[3] = alpha;
89 LLRect progress_rect = getLocalRect();
90 progress_rect.mRight = llround(getRect().getWidth() * (mPercentDone / 100.f));
91 bar_fg_imagep->draw(progress_rect);
92}
93
94void LLProgressBar::setPercent(const F32 percent)
95{
96 mPercentDone = llclamp(percent, 0.f, 100.f);
97}
98
99void LLProgressBar::setImageBar( const std::string &bar_name )
100{
101 mImageBar = LLUI::sImageProvider->getUIImage(bar_name)->getImage();
102}
103
104void LLProgressBar::setImageShadow(const std::string &shadow_name)
105{
106 mImageShadow = LLUI::sImageProvider->getUIImage(shadow_name)->getImage();
107}
108
109void LLProgressBar::setColorBar(const LLColor4 &c)
110{
111 mColorBar = c;
112}
113void LLProgressBar::setColorBar2(const LLColor4 &c)
114{
115 mColorBar2 = c;
116}
117void LLProgressBar::setColorShadow(const LLColor4 &c)
118{
119 mColorShadow = c;
120}
121void LLProgressBar::setColorBackground(const LLColor4 &c)
122{
123 mColorBackground = c;
124}
125
126
127// static
128LLView* LLProgressBar::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
129{
130 std::string name("progress_bar");
131 node->getAttributeString("name", name);
132
133 LLProgressBar *progress = new LLProgressBar(name, LLRect());
134
135
136 std::string image_bar;
137 if (node->hasAttribute("image_bar")) node->getAttributeString("image_bar",image_bar);
138 if (image_bar != LLStringUtil::null) progress->setImageBar(image_bar);
139
140
141 std::string image_shadow;
142 if (node->hasAttribute("image_shadow")) node->getAttributeString("image_shadow",image_shadow);
143 if (image_shadow != LLStringUtil::null) progress->setImageShadow(image_shadow);
144
145
146 LLColor4 color_bar;
147 if (node->hasAttribute("color_bar"))
148 {
149 node->getAttributeColor4("color_bar",color_bar);
150 progress->setColorBar(color_bar);
151 }
152
153
154 LLColor4 color_bar2;
155 if (node->hasAttribute("color_bar2"))
156 {
157 node->getAttributeColor4("color_bar2",color_bar2);
158 progress->setColorBar2(color_bar2);
159 }
160
161
162 LLColor4 color_shadow;
163 if (node->hasAttribute("color_shadow"))
164 {
165 node->getAttributeColor4("color_shadow",color_shadow);
166 progress->setColorShadow(color_shadow);
167 }
168
169
170 LLColor4 color_bg;
171 if (node->hasAttribute("color_bg"))
172 {
173 node->getAttributeColor4("color_bg",color_bg);
174 progress->setColorBackground(color_bg);
175 }
176
177
178 progress->initFromXML(node, parent);
179
180 return progress;
181}
diff --git a/linden/indra/llui/llprogressbar.h b/linden/indra/llui/llprogressbar.h
new file mode 100644
index 0000000..00ad61d
--- /dev/null
+++ b/linden/indra/llui/llprogressbar.h
@@ -0,0 +1,76 @@
1/**
2 * @file llprogressbar.h
3 * @brief LLProgressBar class definition
4 *
5 * $LicenseInfo:firstyear=2002&license=viewergpl$
6 *
7 * Copyright (c) 2002-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * 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
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#ifndef LL_LLPROGRESSBAR_H
34#define LL_LLPROGRESSBAR_H
35
36#include "llview.h"
37#include "llframetimer.h"
38
39class LLProgressBar
40 : public LLView
41{
42public:
43 LLProgressBar(const std::string& name, const LLRect &rect);
44 virtual ~LLProgressBar();
45
46 void setPercent(const F32 percent);
47
48 void setImageBar(const std::string &bar_name);
49 void setImageShadow(const std::string &shadow_name);
50
51 void setColorBar(const LLColor4 &c);
52 void setColorBar2(const LLColor4 &c);
53 void setColorShadow(const LLColor4 &c);
54 void setColorBackground(const LLColor4 &c);
55
56 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
57
58 /*virtual*/ void draw();
59
60protected:
61 F32 mPercentDone;
62
63 LLPointer<LLImageGL> mImageBar;
64 //LLUUID mImageBarID;
65 //LLString mImageBarName;
66 LLColor4 mColorBar;
67 LLColor4 mColorBar2;
68
69 LLPointer<LLImageGL> mImageShadow;
70 //LLUUID mImageShadowID;
71 //LLString mImageShadowName;
72 LLColor4 mColorShadow;
73 LLColor4 mColorBackground;
74};
75
76#endif // LL_LLPROGRESSBAR_H
diff --git a/linden/indra/llui/llradiogroup.cpp b/linden/indra/llui/llradiogroup.cpp
index f6778f3..33b9398 100644
--- a/linden/indra/llui/llradiogroup.cpp
+++ b/linden/indra/llui/llradiogroup.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llradiogroup.h b/linden/indra/llui/llradiogroup.h
index 06729bc..3410b74 100644
--- a/linden/indra/llui/llradiogroup.h
+++ b/linden/indra/llui/llradiogroup.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llresizebar.cpp b/linden/indra/llui/llresizebar.cpp
index 0ba02fa..5b9fe72 100644
--- a/linden/indra/llui/llresizebar.cpp
+++ b/linden/indra/llui/llresizebar.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llresizebar.h b/linden/indra/llui/llresizebar.h
index b8494b0..b9fc405 100644
--- a/linden/indra/llui/llresizebar.h
+++ b/linden/indra/llui/llresizebar.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llresizehandle.cpp b/linden/indra/llui/llresizehandle.cpp
index 3202ffe..c5d57d8 100644
--- a/linden/indra/llui/llresizehandle.cpp
+++ b/linden/indra/llui/llresizehandle.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llresizehandle.h b/linden/indra/llui/llresizehandle.h
index 32d382a..0e23d52 100644
--- a/linden/indra/llui/llresizehandle.h
+++ b/linden/indra/llui/llresizehandle.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llresmgr.cpp b/linden/indra/llui/llresmgr.cpp
index d111bd6..32d3d1f 100644
--- a/linden/indra/llui/llresmgr.cpp
+++ b/linden/indra/llui/llresmgr.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -54,11 +55,11 @@ LLResMgr::LLResMgr()
54 { 55 {
55 mUSAFonts[i] = NULL; 56 mUSAFonts[i] = NULL;
56 } 57 }
57 mUSAFonts[ LLFONT_OCRA ] = LLFontGL::sMonospace; 58 mUSAFonts[ LLFONT_OCRA ] = LLFontGL::getFontMonospace();
58 mUSAFonts[ LLFONT_SANSSERIF ] = LLFontGL::sSansSerif; 59 mUSAFonts[ LLFONT_SANSSERIF ] = LLFontGL::getFontSansSerif();
59 mUSAFonts[ LLFONT_SANSSERIF_SMALL ] = LLFontGL::sSansSerifSmall; 60 mUSAFonts[ LLFONT_SANSSERIF_SMALL ] = LLFontGL::getFontSansSerifSmall();
60 mUSAFonts[ LLFONT_SANSSERIF_BIG ] = LLFontGL::sSansSerifBig; 61 mUSAFonts[ LLFONT_SANSSERIF_BIG ] = LLFontGL::getFontSansSerifBig();
61 mUSAFonts[ LLFONT_SMALL ] = LLFontGL::sMonospace; 62 mUSAFonts[ LLFONT_SMALL ] = LLFontGL::getFontMonospace();
62/* 63/*
63 // USA Strings 64 // USA Strings
64 for( i=0; i<LLSTR_COUNT; i++ ) 65 for( i=0; i<LLSTR_COUNT; i++ )
diff --git a/linden/indra/llui/llresmgr.h b/linden/indra/llui/llresmgr.h
index 86bb6dd..d54505c 100644
--- a/linden/indra/llui/llresmgr.h
+++ b/linden/indra/llui/llresmgr.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llrootview.cpp b/linden/indra/llui/llrootview.cpp
index de1f90b..e4f178b 100644
--- a/linden/indra/llui/llrootview.cpp
+++ b/linden/indra/llui/llrootview.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llrootview.h b/linden/indra/llui/llrootview.h
index 4aa4467..33ebf8d 100644
--- a/linden/indra/llui/llrootview.h
+++ b/linden/indra/llui/llrootview.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llscrollbar.cpp b/linden/indra/llui/llscrollbar.cpp
index 1b87c69..65086d8 100644
--- a/linden/indra/llui/llscrollbar.cpp
+++ b/linden/indra/llui/llscrollbar.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -113,7 +114,7 @@ LLScrollbar::LLScrollbar(
113 114
114 LLButton* line_up_btn = new LLButton(std::string("Line Up"), line_up_rect, 115 LLButton* line_up_btn = new LLButton(std::string("Line Up"), line_up_rect,
115 line_up_img, line_up_selected_img, LLStringUtil::null, 116 line_up_img, line_up_selected_img, LLStringUtil::null,
116 &LLScrollbar::onLineUpBtnPressed, this, LLFontGL::sSansSerif ); 117 &LLScrollbar::onLineUpBtnPressed, this, LLFontGL::getFontSansSerif() );
117 if( LLScrollbar::VERTICAL == mOrientation ) 118 if( LLScrollbar::VERTICAL == mOrientation )
118 { 119 {
119 line_up_btn->setFollowsRight(); 120 line_up_btn->setFollowsRight();
@@ -127,15 +128,18 @@ LLScrollbar::LLScrollbar(
127 } 128 }
128 line_up_btn->setHeldDownCallback( &LLScrollbar::onLineUpBtnPressed ); 129 line_up_btn->setHeldDownCallback( &LLScrollbar::onLineUpBtnPressed );
129 line_up_btn->setTabStop(FALSE); 130 line_up_btn->setTabStop(FALSE);
131 line_up_btn->setScaleImage(TRUE);
132
130 addChild(line_up_btn); 133 addChild(line_up_btn);
131 134
132 LLButton* line_down_btn = new LLButton(std::string("Line Down"), line_down_rect, 135 LLButton* line_down_btn = new LLButton(std::string("Line Down"), line_down_rect,
133 line_down_img, line_down_selected_img, LLStringUtil::null, 136 line_down_img, line_down_selected_img, LLStringUtil::null,
134 &LLScrollbar::onLineDownBtnPressed, this, LLFontGL::sSansSerif ); 137 &LLScrollbar::onLineDownBtnPressed, this, LLFontGL::getFontSansSerif() );
135 line_down_btn->setFollowsRight(); 138 line_down_btn->setFollowsRight();
136 line_down_btn->setFollowsBottom(); 139 line_down_btn->setFollowsBottom();
137 line_down_btn->setHeldDownCallback( &LLScrollbar::onLineDownBtnPressed ); 140 line_down_btn->setHeldDownCallback( &LLScrollbar::onLineDownBtnPressed );
138 line_down_btn->setTabStop(FALSE); 141 line_down_btn->setTabStop(FALSE);
142 line_down_btn->setScaleImage(TRUE);
139 addChild(line_down_btn); 143 addChild(line_down_btn);
140} 144}
141 145
@@ -148,20 +152,29 @@ LLScrollbar::~LLScrollbar()
148void LLScrollbar::setDocParams( S32 size, S32 pos ) 152void LLScrollbar::setDocParams( S32 size, S32 pos )
149{ 153{
150 mDocSize = size; 154 mDocSize = size;
151 mDocPos = llclamp( pos, 0, getDocPosMax() ); 155 setDocPos(pos);
152 mDocChanged = TRUE; 156 mDocChanged = TRUE;
153 157
154 updateThumbRect(); 158 updateThumbRect();
155} 159}
156 160
157void LLScrollbar::setDocPos(S32 pos) 161void LLScrollbar::setDocPos(S32 pos, BOOL update_thumb)
158{ 162{
163 pos = llclamp(pos, 0, getDocPosMax());
159 if (pos != mDocPos) 164 if (pos != mDocPos)
160 { 165 {
161 mDocPos = llclamp( pos, 0, getDocPosMax() ); 166 mDocPos = pos;
162 mDocChanged = TRUE; 167 mDocChanged = TRUE;
163 168
164 updateThumbRect(); 169 if( mChangeCallback )
170 {
171 mChangeCallback( mDocPos, this, mCallbackUserData );
172 }
173
174 if( update_thumb )
175 {
176 updateThumbRect();
177 }
165 } 178 }
166} 179}
167 180
@@ -170,7 +183,7 @@ void LLScrollbar::setDocSize(S32 size)
170 if (size != mDocSize) 183 if (size != mDocSize)
171 { 184 {
172 mDocSize = size; 185 mDocSize = size;
173 mDocPos = llclamp( mDocPos, 0, getDocPosMax() ); 186 setDocPos(mDocPos);
174 mDocChanged = TRUE; 187 mDocChanged = TRUE;
175 188
176 updateThumbRect(); 189 updateThumbRect();
@@ -182,7 +195,7 @@ void LLScrollbar::setPageSize( S32 page_size )
182 if (page_size != mPageSize) 195 if (page_size != mPageSize)
183 { 196 {
184 mPageSize = page_size; 197 mPageSize = page_size;
185 mDocPos = llclamp( mDocPos, 0, getDocPosMax() ); 198 setDocPos(mDocPos);
186 mDocChanged = TRUE; 199 mDocChanged = TRUE;
187 200
188 updateThumbRect(); 201 updateThumbRect();
@@ -208,9 +221,9 @@ void LLScrollbar::updateThumbRect()
208 const S32 THUMB_MIN_LENGTH = 16; 221 const S32 THUMB_MIN_LENGTH = 16;
209 222
210 S32 window_length = (mOrientation == LLScrollbar::HORIZONTAL) ? getRect().getWidth() : getRect().getHeight(); 223 S32 window_length = (mOrientation == LLScrollbar::HORIZONTAL) ? getRect().getWidth() : getRect().getHeight();
211 S32 thumb_bg_length = window_length - 2 * SCROLLBAR_SIZE; 224 S32 thumb_bg_length = llmax(0, window_length - 2 * SCROLLBAR_SIZE);
212 S32 visible_lines = llmin( mDocSize, mPageSize ); 225 S32 visible_lines = llmin( mDocSize, mPageSize );
213 S32 thumb_length = mDocSize ? llmax( visible_lines * thumb_bg_length / mDocSize, THUMB_MIN_LENGTH ) : thumb_bg_length; 226 S32 thumb_length = mDocSize ? llmin(llmax( visible_lines * thumb_bg_length / mDocSize, THUMB_MIN_LENGTH), thumb_bg_length) : thumb_bg_length;
214 227
215 S32 variable_lines = mDocSize - visible_lines; 228 S32 variable_lines = mDocSize - visible_lines;
216 229
@@ -218,7 +231,7 @@ void LLScrollbar::updateThumbRect()
218 { 231 {
219 S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE; 232 S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE;
220 S32 thumb_start_min = SCROLLBAR_SIZE + THUMB_MIN_LENGTH; 233 S32 thumb_start_min = SCROLLBAR_SIZE + THUMB_MIN_LENGTH;
221 S32 thumb_start = variable_lines ? llclamp( thumb_start_max - (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min, thumb_start_max ) : thumb_start_max; 234 S32 thumb_start = variable_lines ? llmin( llmax(thumb_start_max - (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_max;
222 235
223 mThumbRect.mLeft = 0; 236 mThumbRect.mLeft = 0;
224 mThumbRect.mTop = thumb_start; 237 mThumbRect.mTop = thumb_start;
@@ -230,7 +243,7 @@ void LLScrollbar::updateThumbRect()
230 // Horizontal 243 // Horizontal
231 S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE - thumb_length; 244 S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE - thumb_length;
232 S32 thumb_start_min = SCROLLBAR_SIZE; 245 S32 thumb_start_min = SCROLLBAR_SIZE;
233 S32 thumb_start = variable_lines ? llclamp( thumb_start_min + (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min, thumb_start_max ) : thumb_start_min; 246 S32 thumb_start = variable_lines ? llmin(llmax( thumb_start_min + (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_min;
234 247
235 mThumbRect.mLeft = thumb_start; 248 mThumbRect.mLeft = thumb_start;
236 mThumbRect.mTop = SCROLLBAR_SIZE; 249 mThumbRect.mTop = SCROLLBAR_SIZE;
@@ -446,7 +459,7 @@ BOOL LLScrollbar::handleMouseUp(S32 x, S32 y, MASK mask)
446 } 459 }
447 else 460 else
448 { 461 {
449 // Opaque, so don't just check children 462 // Opaque, so don't just check children
450 handled = LLView::handleMouseUp( x, y, mask ); 463 handled = LLView::handleMouseUp( x, y, mask );
451 } 464 }
452 465
@@ -455,21 +468,34 @@ BOOL LLScrollbar::handleMouseUp(S32 x, S32 y, MASK mask)
455 468
456void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent) 469void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent)
457{ 470{
471 if (width == getRect().getWidth() && height == getRect().getHeight()) return;
458 LLView::reshape( width, height, called_from_parent ); 472 LLView::reshape( width, height, called_from_parent );
473 LLButton* up_button = getChild<LLButton>("Line Up");
474 LLButton* down_button = getChild<LLButton>("Line Down");
475
476 if (mOrientation == VERTICAL)
477 {
478 up_button->reshape(up_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, SCROLLBAR_SIZE));
479 down_button->reshape(down_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, SCROLLBAR_SIZE));
480 up_button->setOrigin(up_button->getRect().mLeft, getRect().getHeight() - up_button->getRect().getHeight());
481 }
482 else
483 {
484 up_button->reshape(llmin(getRect().getWidth() / 2, SCROLLBAR_SIZE), up_button->getRect().getHeight());
485 down_button->reshape(llmin(getRect().getWidth() / 2, SCROLLBAR_SIZE), down_button->getRect().getHeight());
486 down_button->setOrigin(getRect().getWidth() - down_button->getRect().getWidth(), down_button->getRect().mBottom);
487 }
459 updateThumbRect(); 488 updateThumbRect();
460} 489}
461 490
462 491
463void LLScrollbar::draw() 492void LLScrollbar::draw()
464{ 493{
494 if (!getRect().isValid()) return;
495
465 S32 local_mouse_x; 496 S32 local_mouse_x;
466 S32 local_mouse_y; 497 S32 local_mouse_y;
467 LLCoordWindow cursor_pos_window; 498 LLUI::getCursorPositionLocal(this, &local_mouse_x, &local_mouse_y);
468 getWindow()->getCursorPosition(&cursor_pos_window);
469 LLCoordGL cursor_pos_gl;
470 getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl);
471
472 screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, &local_mouse_x, &local_mouse_y);
473 BOOL other_captor = gFocusMgr.getMouseCapture() && gFocusMgr.getMouseCapture() != this; 499 BOOL other_captor = gFocusMgr.getMouseCapture() && gFocusMgr.getMouseCapture() != this;
474 BOOL hovered = getEnabled() && !other_captor && (hasMouseCapture() || mThumbRect.pointInRect(local_mouse_x, local_mouse_y)); 500 BOOL hovered = getEnabled() && !other_captor && (hasMouseCapture() || mThumbRect.pointInRect(local_mouse_x, local_mouse_y));
475 if (hovered) 501 if (hovered)
@@ -536,21 +562,7 @@ void LLScrollbar::draw()
536 562
537void LLScrollbar::changeLine( S32 delta, BOOL update_thumb ) 563void LLScrollbar::changeLine( S32 delta, BOOL update_thumb )
538{ 564{
539 S32 new_pos = llclamp( mDocPos + delta, 0, getDocPosMax() ); 565 setDocPos(mDocPos + delta, update_thumb);
540 if( new_pos != mDocPos )
541 {
542 mDocPos = new_pos;
543 }
544
545 if( mChangeCallback )
546 {
547 mChangeCallback( mDocPos, this, mCallbackUserData );
548 }
549
550 if( update_thumb )
551 {
552 updateThumbRect();
553 }
554} 566}
555 567
556void LLScrollbar::setValue(const LLSD& value) 568void LLScrollbar::setValue(const LLSD& value)
@@ -566,22 +578,22 @@ BOOL LLScrollbar::handleKeyHere(KEY key, MASK mask)
566 switch( key ) 578 switch( key )
567 { 579 {
568 case KEY_HOME: 580 case KEY_HOME:
569 changeLine( -mDocPos, TRUE ); 581 setDocPos( 0 );
570 handled = TRUE; 582 handled = TRUE;
571 break; 583 break;
572 584
573 case KEY_END: 585 case KEY_END:
574 changeLine( getDocPosMax() - mDocPos, TRUE ); 586 setDocPos( getDocPosMax() );
575 handled = TRUE; 587 handled = TRUE;
576 break; 588 break;
577 589
578 case KEY_DOWN: 590 case KEY_DOWN:
579 changeLine( mStepSize, TRUE ); 591 setDocPos( getDocPos() + mStepSize );
580 handled = TRUE; 592 handled = TRUE;
581 break; 593 break;
582 594
583 case KEY_UP: 595 case KEY_UP:
584 changeLine( - mStepSize, TRUE ); 596 setDocPos( getDocPos() - mStepSize );
585 handled = TRUE; 597 handled = TRUE;
586 break; 598 break;
587 599
diff --git a/linden/indra/llui/llscrollbar.h b/linden/indra/llui/llscrollbar.h
index 0703263..0bbf866 100644
--- a/linden/indra/llui/llscrollbar.h
+++ b/linden/indra/llui/llscrollbar.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -81,7 +82,7 @@ public:
81 82
82 // How many "lines" the "document" has scrolled. 83 // How many "lines" the "document" has scrolled.
83 // 0 <= DocPos <= DocSize - DocVisibile 84 // 0 <= DocPos <= DocSize - DocVisibile
84 void setDocPos( S32 pos ); 85 void setDocPos( S32 pos, BOOL update_thumb = TRUE );
85 S32 getDocPos() const { return mDocPos; } 86 S32 getDocPos() const { return mDocPos; }
86 87
87 BOOL isAtBeginning(); 88 BOOL isAtBeginning();
diff --git a/linden/indra/llui/llscrollcontainer.cpp b/linden/indra/llui/llscrollcontainer.cpp
index f7c4200..cf03259 100644
--- a/linden/indra/llui/llscrollcontainer.cpp
+++ b/linden/indra/llui/llscrollcontainer.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llscrollcontainer.h b/linden/indra/llui/llscrollcontainer.h
index 80e67d2..70fc908 100644
--- a/linden/indra/llui/llscrollcontainer.h
+++ b/linden/indra/llui/llscrollcontainer.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llscrollingpanellist.cpp b/linden/indra/llui/llscrollingpanellist.cpp
index 0cd501c..05d0c6f 100644
--- a/linden/indra/llui/llscrollingpanellist.cpp
+++ b/linden/indra/llui/llscrollingpanellist.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llscrollingpanellist.h b/linden/indra/llui/llscrollingpanellist.h
index c96f12c..b9d7309 100644
--- a/linden/indra/llui/llscrollingpanellist.h
+++ b/linden/indra/llui/llscrollingpanellist.h
@@ -16,7 +16,8 @@
16 * 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
17 * 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
18 * 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
19 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 19 * online at
20 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
20 * 21 *
21 * By copying, modifying or distributing this software, you acknowledge 22 * By copying, modifying or distributing this software, you acknowledge
22 * that you have read and understood your obligations described above, 23 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llscrolllistctrl.cpp b/linden/indra/llui/llscrolllistctrl.cpp
index 7dba55f..7b6c125 100644
--- a/linden/indra/llui/llscrolllistctrl.cpp
+++ b/linden/indra/llui/llscrolllistctrl.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -378,6 +379,22 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
378 TRUE); 379 TRUE);
379} 380}
380 381
382LLScrollListDate::LLScrollListDate( const LLDate& date, const LLFontGL* font, S32 width, U8 font_style, LLFontGL::HAlign font_alignment, LLColor4& color, BOOL use_color, BOOL visible)
383: LLScrollListText(date.asRFC1123(), font, width, font_style, font_alignment, color, use_color, visible),
384 mDate(date)
385{
386}
387
388void LLScrollListDate::setValue(const LLSD& value)
389{
390 mDate = value.asDate();
391 LLScrollListText::setValue(mDate.asRFC1123());
392}
393
394const LLSD LLScrollListDate::getValue() const
395{
396 return mDate;
397}
381 398
382LLScrollListItem::~LLScrollListItem() 399LLScrollListItem::~LLScrollListItem()
383{ 400{
@@ -578,6 +595,7 @@ LLScrollListCtrl::LLScrollListCtrl(const std::string& name, const LLRect& rect,
578 mSearchColumn(0), 595 mSearchColumn(0),
579 mNumDynamicWidthColumns(0), 596 mNumDynamicWidthColumns(0),
580 mTotalStaticColumnWidth(0), 597 mTotalStaticColumnWidth(0),
598 mTotalColumnPadding(0),
581 mSorted(TRUE), 599 mSorted(TRUE),
582 mDirty(FALSE), 600 mDirty(FALSE),
583 mOriginalSelection(-1), 601 mOriginalSelection(-1),
@@ -627,6 +645,28 @@ LLScrollListCtrl::LLScrollListCtrl(const std::string& name, const LLRect& rect,
627 mLastSelected = NULL; 645 mLastSelected = NULL;
628} 646}
629 647
648S32 LLScrollListCtrl::getSearchColumn()
649{
650 // search for proper search column
651 if (mSearchColumn < 0)
652 {
653 LLScrollListItem* itemp = getFirstData();
654 if (itemp)
655 {
656 for(S32 column = 0; column < getNumColumns(); column++)
657 {
658 LLScrollListCell* cell = itemp->getColumn(column);
659 if (cell && cell->isText())
660 {
661 mSearchColumn = column;
662 break;
663 }
664 }
665 }
666 }
667 return llclamp(mSearchColumn, 0, getNumColumns());
668}
669
630LLScrollListCtrl::~LLScrollListCtrl() 670LLScrollListCtrl::~LLScrollListCtrl()
631{ 671{
632 std::for_each(mItemList.begin(), mItemList.end(), DeletePointer()); 672 std::for_each(mItemList.begin(), mItemList.end(), DeletePointer());
@@ -890,8 +930,8 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r
890// *TODO: Use bookkeeping to make this an incramental cost with item additions 930// *TODO: Use bookkeeping to make this an incramental cost with item additions
891void LLScrollListCtrl::calcColumnWidths() 931void LLScrollListCtrl::calcColumnWidths()
892{ 932{
893 const S32 HEADING_TEXT_PADDING = 30; 933 const S32 HEADING_TEXT_PADDING = 25;
894 const S32 COLUMN_TEXT_PADDING = 20; 934 const S32 COLUMN_TEXT_PADDING = 10;
895 935
896 mMaxContentWidth = 0; 936 mMaxContentWidth = 0;
897 937
@@ -904,30 +944,27 @@ void LLScrollListCtrl::calcColumnWidths()
904 if (!column) continue; 944 if (!column) continue;
905 945
906 // update column width 946 // update column width
907 S32 new_width = column->mWidth; 947 S32 new_width = column->getWidth();
908 if (column->mRelWidth >= 0) 948 if (column->mRelWidth >= 0)
909 { 949 {
910 new_width = (S32)llround(column->mRelWidth*mItemListRect.getWidth()); 950 new_width = (S32)llround(column->mRelWidth*mItemListRect.getWidth());
911 } 951 }
912 else if (column->mDynamicWidth) 952 else if (column->mDynamicWidth)
913 { 953 {
914 new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns; 954 new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns;
915 } 955 }
916 956
917 if (new_width != column->mWidth) 957 column->setWidth(new_width);
918 {
919 column->mWidth = new_width;
920 }
921 958
922 // update max content width for this column, by looking at all items 959 // update max content width for this column, by looking at all items
923 column->mMaxContentWidth = column->mHeader ? LLFontGL::sSansSerifSmall->getWidth(column->mLabel) + mColumnPadding + HEADING_TEXT_PADDING : 0; 960 column->mMaxContentWidth = column->mHeader ? LLFontGL::getFontSansSerifSmall()->getWidth(column->mLabel) + mColumnPadding + HEADING_TEXT_PADDING : 0;
924 item_list::iterator iter; 961 item_list::iterator iter;
925 for (iter = mItemList.begin(); iter != mItemList.end(); iter++) 962 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
926 { 963 {
927 LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex); 964 LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex);
928 if (!cellp) continue; 965 if (!cellp) continue;
929 966
930 column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth); 967 column->mMaxContentWidth = llmax(LLFontGL::getFontSansSerifSmall()->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
931 } 968 }
932 969
933 max_item_width += column->mMaxContentWidth; 970 max_item_width += column->mMaxContentWidth;
@@ -971,28 +1008,13 @@ void LLScrollListCtrl::updateColumns()
971{ 1008{
972 calcColumnWidths(); 1009 calcColumnWidths();
973 1010
974 // propagate column widths to individual cells
975 item_list::iterator iter;
976 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
977 {
978 LLScrollListItem *itemp = *iter;
979 S32 num_cols = itemp->getNumColumns();
980 S32 i = 0;
981 for (LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
982 {
983 if (i >= (S32)mColumnsIndexed.size()) break;
984
985 cell->setWidth(mColumnsIndexed[i]->mWidth);
986 }
987 }
988
989 // update column headers 1011 // update column headers
990 std::vector<LLScrollListColumn*>::iterator column_ordered_it; 1012 std::vector<LLScrollListColumn*>::iterator column_ordered_it;
991 S32 left = mItemListRect.mLeft; 1013 S32 left = mItemListRect.mLeft;
992 LLColumnHeader* last_header = NULL; 1014 LLColumnHeader* last_header = NULL;
993 for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it) 1015 for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it)
994 { 1016 {
995 if ((*column_ordered_it)->mWidth < 0) 1017 if ((*column_ordered_it)->getWidth() < 0)
996 { 1018 {
997 // skip hidden columns 1019 // skip hidden columns
998 continue; 1020 continue;
@@ -1001,9 +1023,11 @@ void LLScrollListCtrl::updateColumns()
1001 1023
1002 if (column->mHeader) 1024 if (column->mHeader)
1003 { 1025 {
1026 column->mHeader->updateResizeBars();
1027
1004 last_header = column->mHeader; 1028 last_header = column->mHeader;
1005 S32 top = mItemListRect.mTop; 1029 S32 top = mItemListRect.mTop;
1006 S32 right = left + column->mWidth; 1030 S32 right = left + column->getWidth();
1007 1031
1008 if (column->mIndex != (S32)mColumnsIndexed.size()-1) 1032 if (column->mIndex != (S32)mColumnsIndexed.size()-1)
1009 { 1033 {
@@ -1021,14 +1045,30 @@ void LLScrollListCtrl::updateColumns()
1021 } 1045 }
1022 } 1046 }
1023 1047
1024 //FIXME: stretch the entire last column if it is resizable (gestures windows shows truncated text in last column)
1025 // expand last column header we encountered to full list width 1048 // expand last column header we encountered to full list width
1026 if (last_header) 1049 if (last_header && last_header->canResize())
1027 { 1050 {
1028 S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft); 1051 S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft);
1029 last_header->reshape(new_width, last_header->getRect().getHeight()); 1052 last_header->reshape(new_width, last_header->getRect().getHeight());
1030 last_header->setVisible(mDisplayColumnHeaders && new_width > 0); 1053 last_header->setVisible(mDisplayColumnHeaders && new_width > 0);
1054 last_header->getColumn()->setWidth(new_width);
1055 }
1056
1057 // propagate column widths to individual cells
1058 item_list::iterator iter;
1059 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
1060 {
1061 LLScrollListItem *itemp = *iter;
1062 S32 num_cols = itemp->getNumColumns();
1063 S32 i = 0;
1064 for (LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
1065 {
1066 if (i >= (S32)mColumnsIndexed.size()) break;
1067
1068 cell->setWidth(mColumnsIndexed[i]->getWidth());
1069 }
1031 } 1070 }
1071
1032} 1072}
1033 1073
1034void LLScrollListCtrl::setDisplayHeading(BOOL display) 1074void LLScrollListCtrl::setDisplayHeading(BOOL display)
@@ -1490,7 +1530,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
1490 { 1530 {
1491 LLScrollListItem* item = *iter; 1531 LLScrollListItem* item = *iter;
1492 // Only select enabled items with matching names 1532 // Only select enabled items with matching names
1493 LLScrollListCell* cellp = item->getColumn(mSearchColumn); 1533 LLScrollListCell* cellp = item->getColumn(getSearchColumn());
1494 BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE; 1534 BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE;
1495 if (select) 1535 if (select)
1496 { 1536 {
@@ -1513,7 +1553,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
1513 LLScrollListItem* item = *iter; 1553 LLScrollListItem* item = *iter;
1514 1554
1515 // Only select enabled items with matching names 1555 // Only select enabled items with matching names
1516 LLScrollListCell* cellp = item->getColumn(mSearchColumn); 1556 LLScrollListCell* cellp = item->getColumn(getSearchColumn());
1517 if (!cellp) 1557 if (!cellp)
1518 { 1558 {
1519 continue; 1559 continue;
@@ -1743,6 +1783,8 @@ void LLScrollListCtrl::drawItems()
1743 1783
1744void LLScrollListCtrl::draw() 1784void LLScrollListCtrl::draw()
1745{ 1785{
1786 LLLocalClipRect clip(getLocalRect());
1787
1746 // if user specifies sort, make sure it is maintained 1788 // if user specifies sort, make sure it is maintained
1747 if (needsSorting() && !isSorted()) 1789 if (needsSorting() && !isSorted())
1748 { 1790 {
@@ -1816,7 +1858,7 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sti
1816 S32 rect_left = getColumnOffsetFromIndex(column_index) + mItemListRect.mLeft; 1858 S32 rect_left = getColumnOffsetFromIndex(column_index) + mItemListRect.mLeft;
1817 S32 rect_bottom = getRowOffsetFromIndex(getItemIndex(hit_item)); 1859 S32 rect_bottom = getRowOffsetFromIndex(getItemIndex(hit_item));
1818 LLRect cell_rect; 1860 LLRect cell_rect;
1819 cell_rect.setOriginAndSize(rect_left, rect_bottom, rect_left + columnp->mWidth, mLineHeight); 1861 cell_rect.setOriginAndSize(rect_left, rect_bottom, rect_left + columnp->getWidth(), mLineHeight);
1820 // Convert rect local to screen coordinates 1862 // Convert rect local to screen coordinates
1821 localPointToScreen( 1863 localPointToScreen(
1822 cell_rect.mLeft, cell_rect.mBottom, 1864 cell_rect.mLeft, cell_rect.mBottom,
@@ -2113,7 +2155,7 @@ S32 LLScrollListCtrl::getColumnIndexFromOffset(S32 x)
2113 ordered_columns_t::const_iterator end = mColumnsIndexed.end(); 2155 ordered_columns_t::const_iterator end = mColumnsIndexed.end();
2114 for ( ; iter != end; ++iter) 2156 for ( ; iter != end; ++iter)
2115 { 2157 {
2116 width = (*iter)->mWidth + mColumnPadding; 2158 width = (*iter)->getWidth() + mColumnPadding;
2117 right += width; 2159 right += width;
2118 if (left <= x && x < right ) 2160 if (left <= x && x < right )
2119 { 2161 {
@@ -2140,7 +2182,7 @@ S32 LLScrollListCtrl::getColumnOffsetFromIndex(S32 index)
2140 { 2182 {
2141 return column_offset; 2183 return column_offset;
2142 } 2184 }
2143 column_offset += (*iter)->mWidth + mColumnPadding; 2185 column_offset += (*iter)->getWidth() + mColumnPadding;
2144 } 2186 }
2145 2187
2146 // when running off the end, return the rightmost pixel 2188 // when running off the end, return the rightmost pixel
@@ -2292,7 +2334,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask )
2292 { 2334 {
2293 if (getFirstSelected()) 2335 if (getFirstSelected())
2294 { 2336 {
2295 LLScrollListCell* cellp = getFirstSelected()->getColumn(mSearchColumn); 2337 LLScrollListCell* cellp = getFirstSelected()->getColumn(getSearchColumn());
2296 if (cellp) 2338 if (cellp)
2297 { 2339 {
2298 cellp->highlightText(0, 0); 2340 cellp->highlightText(0, 0);
@@ -2379,7 +2421,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char)
2379 { 2421 {
2380 LLScrollListItem* item = *iter; 2422 LLScrollListItem* item = *iter;
2381 2423
2382 LLScrollListCell* cellp = item->getColumn(mSearchColumn); 2424 LLScrollListCell* cellp = item->getColumn(getSearchColumn());
2383 if (cellp) 2425 if (cellp)
2384 { 2426 {
2385 // Only select enabled items with matching first characters 2427 // Only select enabled items with matching first characters
@@ -2446,7 +2488,7 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_it
2446 { 2488 {
2447 if (mLastSelected) 2489 if (mLastSelected)
2448 { 2490 {
2449 LLScrollListCell* cellp = mLastSelected->getColumn(mSearchColumn); 2491 LLScrollListCell* cellp = mLastSelected->getColumn(getSearchColumn());
2450 if (cellp) 2492 if (cellp)
2451 { 2493 {
2452 cellp->highlightText(0, 0); 2494 cellp->highlightText(0, 0);
@@ -2474,7 +2516,7 @@ void LLScrollListCtrl::deselectItem(LLScrollListItem* itemp)
2474 } 2516 }
2475 2517
2476 itemp->setSelected(FALSE); 2518 itemp->setSelected(FALSE);
2477 LLScrollListCell* cellp = itemp->getColumn(mSearchColumn); 2519 LLScrollListCell* cellp = itemp->getColumn(getSearchColumn());
2478 if (cellp) 2520 if (cellp)
2479 { 2521 {
2480 cellp->highlightText(0, 0); 2522 cellp->highlightText(0, 0);
@@ -2501,9 +2543,14 @@ struct SameSortColumn
2501 bool operator()(std::pair<S32, BOOL> sort_column) { return sort_column.first == mColumn; } 2543 bool operator()(std::pair<S32, BOOL> sort_column) { return sort_column.first == mColumn; }
2502}; 2544};
2503 2545
2504BOOL LLScrollListCtrl::setSort(S32 column, BOOL ascending) 2546BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending)
2505{ 2547{
2506 sort_column_t new_sort_column(column, ascending); 2548 LLScrollListColumn* sort_column = getColumn(column_idx);
2549 if (!sort_column) return FALSE;
2550
2551 sort_column->mSortAscending = ascending;
2552
2553 sort_column_t new_sort_column(column_idx, ascending);
2507 2554
2508 if (mSortColumns.empty()) 2555 if (mSortColumns.empty())
2509 { 2556 {
@@ -2517,7 +2564,7 @@ BOOL LLScrollListCtrl::setSort(S32 column, BOOL ascending)
2517 2564
2518 // remove any existing sort criterion referencing this column 2565 // remove any existing sort criterion referencing this column
2519 // and add the new one 2566 // and add the new one
2520 mSortColumns.erase(remove_if(mSortColumns.begin(), mSortColumns.end(), SameSortColumn(column)), mSortColumns.end()); 2567 mSortColumns.erase(remove_if(mSortColumns.begin(), mSortColumns.end(), SameSortColumn(column_idx)), mSortColumns.end());
2521 mSortColumns.push_back(new_sort_column); 2568 mSortColumns.push_back(new_sort_column);
2522 2569
2523 // did the sort criteria change? 2570 // did the sort criteria change?
@@ -2643,6 +2690,12 @@ void LLScrollListCtrl::scrollToShowSelected()
2643 } 2690 }
2644} 2691}
2645 2692
2693void LLScrollListCtrl::updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width)
2694{
2695 mTotalStaticColumnWidth += llmax(0, new_width) - llmax(0, col->getWidth());
2696}
2697
2698
2646// virtual 2699// virtual
2647LLXMLNodePtr LLScrollListCtrl::getXML(bool save_children) const 2700LLXMLNodePtr LLScrollListCtrl::getXML(bool save_children) const
2648{ 2701{
@@ -2689,7 +2742,7 @@ LLXMLNodePtr LLScrollListCtrl::getXML(bool save_children) const
2689 2742
2690 child_node->createChild("name", TRUE)->setStringValue(column->mName); 2743 child_node->createChild("name", TRUE)->setStringValue(column->mName);
2691 child_node->createChild("label", TRUE)->setStringValue(column->mLabel); 2744 child_node->createChild("label", TRUE)->setStringValue(column->mLabel);
2692 child_node->createChild("width", TRUE)->setIntValue(column->mWidth); 2745 child_node->createChild("width", TRUE)->setIntValue(column->getWidth());
2693 } 2746 }
2694 2747
2695 return node; 2748 return node;
@@ -2813,15 +2866,9 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
2813 2866
2814 scroll_list->setSearchColumn(search_column); 2867 scroll_list->setSearchColumn(search_column);
2815 2868
2816 if (sort_column >= 0)
2817 {
2818 scroll_list->sortByColumnIndex(sort_column, sort_ascending);
2819 }
2820
2821 LLSD columns; 2869 LLSD columns;
2822 S32 index = 0; 2870 S32 index = 0;
2823 LLXMLNodePtr child; 2871 LLXMLNodePtr child;
2824 S32 total_static = 0;
2825 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) 2872 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
2826 { 2873 {
2827 if (child->hasName("column")) 2874 if (child->hasName("column"))
@@ -2850,8 +2897,6 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
2850 std::string tooltip; 2897 std::string tooltip;
2851 child->getAttributeString("tool_tip", tooltip); 2898 child->getAttributeString("tool_tip", tooltip);
2852 2899
2853 if(!columndynamicwidth) total_static += llmax(0, columnwidth);
2854
2855 F32 columnrelwidth = 0.f; 2900 F32 columnrelwidth = 0.f;
2856 child->getAttributeF32("relwidth", columnrelwidth); 2901 child->getAttributeF32("relwidth", columnrelwidth);
2857 2902
@@ -2872,9 +2917,13 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
2872 index++; 2917 index++;
2873 } 2918 }
2874 } 2919 }
2875 scroll_list->setTotalStaticColumnWidth(total_static);
2876 scroll_list->setColumnHeadings(columns); 2920 scroll_list->setColumnHeadings(columns);
2877 2921
2922 if (sort_column >= 0)
2923 {
2924 scroll_list->sortByColumnIndex(sort_column, sort_ascending);
2925 }
2926
2878 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) 2927 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
2879 { 2928 {
2880 if (child->hasName("row")) 2929 if (child->hasName("row"))
@@ -3019,22 +3068,26 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
3019 if (mColumns.find(name) == mColumns.end()) 3068 if (mColumns.find(name) == mColumns.end())
3020 { 3069 {
3021 // Add column 3070 // Add column
3022 mColumns[name] = LLScrollListColumn(column); 3071 mColumns[name] = LLScrollListColumn(column, this);
3023 LLScrollListColumn* new_column = &mColumns[name]; 3072 LLScrollListColumn* new_column = &mColumns[name];
3024 new_column->mParentCtrl = this; 3073 new_column->mParentCtrl = this;
3025 new_column->mIndex = mColumns.size()-1; 3074 new_column->mIndex = mColumns.size()-1;
3026 3075
3027 // Add button 3076 // Add button
3028 if (new_column->mWidth > 0 || new_column->mRelWidth > 0 || new_column->mDynamicWidth) 3077 if (new_column->getWidth() > 0 || new_column->mRelWidth > 0 || new_column->mDynamicWidth)
3029 { 3078 {
3079 if (getNumColumns() > 0)
3080 {
3081 mTotalColumnPadding += mColumnPadding;
3082 }
3030 if (new_column->mRelWidth >= 0) 3083 if (new_column->mRelWidth >= 0)
3031 { 3084 {
3032 new_column->mWidth = (S32)llround(new_column->mRelWidth*mItemListRect.getWidth()); 3085 new_column->setWidth((S32)llround(new_column->mRelWidth*mItemListRect.getWidth()));
3033 } 3086 }
3034 else if(new_column->mDynamicWidth) 3087 else if(new_column->mDynamicWidth)
3035 { 3088 {
3036 mNumDynamicWidthColumns++; 3089 mNumDynamicWidthColumns++;
3037 new_column->mWidth = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns; 3090 new_column->setWidth((mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns);
3038 } 3091 }
3039 S32 top = mItemListRect.mTop; 3092 S32 top = mItemListRect.mTop;
3040 S32 left = mItemListRect.mLeft; 3093 S32 left = mItemListRect.mLeft;
@@ -3043,14 +3096,14 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
3043 for (itor = mColumns.begin(); itor != mColumns.end(); ++itor) 3096 for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
3044 { 3097 {
3045 if (itor->second.mIndex < new_column->mIndex && 3098 if (itor->second.mIndex < new_column->mIndex &&
3046 itor->second.mWidth > 0) 3099 itor->second.getWidth() > 0)
3047 { 3100 {
3048 left += itor->second.mWidth + mColumnPadding; 3101 left += itor->second.getWidth() + mColumnPadding;
3049 } 3102 }
3050 } 3103 }
3051 } 3104 }
3052 std::string button_name = "btn_" + name; 3105 std::string button_name = "btn_" + name;
3053 S32 right = left+new_column->mWidth; 3106 S32 right = left+new_column->getWidth();
3054 if (new_column->mIndex != (S32)mColumns.size()-1) 3107 if (new_column->mIndex != (S32)mColumns.size()-1)
3055 { 3108 {
3056 right += mColumnPadding; 3109 right += mColumnPadding;
@@ -3145,6 +3198,8 @@ void LLScrollListCtrl::clearColumns()
3145 } 3198 }
3146 mColumns.clear(); 3199 mColumns.clear();
3147 mSortColumns.clear(); 3200 mSortColumns.clear();
3201 mTotalStaticColumnWidth = 0;
3202 mTotalColumnPadding = 0;
3148} 3203}
3149 3204
3150void LLScrollListCtrl::setColumnLabel(const std::string& column, const std::string& label) 3205void LLScrollListCtrl::setColumnLabel(const std::string& column, const std::string& label)
@@ -3244,7 +3299,7 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
3244 } 3299 }
3245 3300
3246 S32 index = columnp->mIndex; 3301 S32 index = columnp->mIndex;
3247 S32 width = columnp->mWidth; 3302 S32 width = columnp->getWidth();
3248 LLFontGL::HAlign font_alignment = columnp->mFontAlignment; 3303 LLFontGL::HAlign font_alignment = columnp->mFontAlignment;
3249 LLColor4 fcolor = LLColor4::black; 3304 LLColor4 fcolor = LLColor4::black;
3250 3305
@@ -3301,6 +3356,19 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
3301 } 3356 }
3302 new_item->setColumn(index, cell); 3357 new_item->setColumn(index, cell);
3303 } 3358 }
3359 else if (type == "date")
3360 {
3361 LLScrollListDate* cell = new LLScrollListDate(value.asDate(), font, width, font_style, font_alignment);
3362 if (has_color)
3363 {
3364 cell->setColor(color);
3365 }
3366 new_item->setColumn(index, cell);
3367 if (columnp->mHeader && !value.asString().empty())
3368 {
3369 columnp->mHeader->setHasResizableElement(TRUE);
3370 }
3371 }
3304 else 3372 else
3305 { 3373 {
3306 LLScrollListText* cell = new LLScrollListText(value.asString(), font, width, font_style, font_alignment, fcolor, TRUE); 3374 LLScrollListText* cell = new LLScrollListText(value.asString(), font, width, font_style, font_alignment, fcolor, TRUE);
@@ -3325,7 +3393,7 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
3325 if (new_item->getColumn(column_idx) == NULL) 3393 if (new_item->getColumn(column_idx) == NULL)
3326 { 3394 {
3327 LLScrollListColumn* column_ptr = &column_it->second; 3395 LLScrollListColumn* column_ptr = &column_it->second;
3328 new_item->setColumn(column_idx, new LLScrollListText(LLStringUtil::null, LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ), column_ptr->mWidth, LLFontGL::NORMAL)); 3396 new_item->setColumn(column_idx, new LLScrollListText(LLStringUtil::null, LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ), column_ptr->getWidth(), LLFontGL::NORMAL));
3329 } 3397 }
3330 } 3398 }
3331 3399
@@ -3469,6 +3537,7 @@ LLColumnHeader::LLColumnHeader(const std::string& label, const LLRect &rect, LLS
3469 mButton->setMouseDownCallback(onMouseDown); 3537 mButton->setMouseDownCallback(onMouseDown);
3470 3538
3471 mButton->setCallbackUserData(this); 3539 mButton->setCallbackUserData(this);
3540 mButton->setToolTip(label);
3472 3541
3473 mAscendingText = std::string("[LOW]...[HIGH](Ascending)"); // *TODO: Translate 3542 mAscendingText = std::string("[LOW]...[HIGH](Ascending)"); // *TODO: Translate
3474 mDescendingText = std::string("[HIGH]...[LOW](Descending)"); // *TODO: Translate 3543 mDescendingText = std::string("[HIGH]...[LOW](Descending)"); // *TODO: Translate
@@ -3556,7 +3625,7 @@ void LLColumnHeader::onClick(void* user_data)
3556 3625
3557 LLScrollListCtrl::onClickColumn(column); 3626 LLScrollListCtrl::onClickColumn(column);
3558 3627
3559 // propage new sort order to sort order list 3628 // propagate new sort order to sort order list
3560 headerp->mList->selectNthItem(column->mParentCtrl->getSortAscending() ? 0 : 1); 3629 headerp->mList->selectNthItem(column->mParentCtrl->getSortAscending() ? 0 : 1);
3561} 3630}
3562 3631
@@ -3642,11 +3711,11 @@ void LLColumnHeader::showList()
3642 descending_string = mDescendingText.getString(); 3711 descending_string = mDescendingText.getString();
3643 } 3712 }
3644 3713
3645 S32 text_width = LLFontGL::sSansSerifSmall->getWidth(ascending_string); 3714 S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(ascending_string);
3646 text_width = llmax(text_width, LLFontGL::sSansSerifSmall->getWidth(descending_string)) + 10; 3715 text_width = llmax(text_width, LLFontGL::getFontSansSerifSmall()->getWidth(descending_string)) + 10;
3647 text_width = llmax(text_width, getRect().getWidth() - 30); 3716 text_width = llmax(text_width, getRect().getWidth() - 30);
3648 3717
3649 mList->getColumn(0)->mWidth = text_width; 3718 mList->getColumn(0)->setWidth(text_width);
3650 ((LLScrollListText*)mList->getFirstData()->getColumn(0))->setText(ascending_string); 3719 ((LLScrollListText*)mList->getFirstData()->getColumn(0))->setText(ascending_string);
3651 ((LLScrollListText*)mList->getLastData()->getColumn(0))->setText(descending_string); 3720 ((LLScrollListText*)mList->getLastData()->getColumn(0))->setText(descending_string);
3652 3721
@@ -3688,7 +3757,7 @@ LLView* LLColumnHeader::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_d
3688 llassert(snap_edge == SNAP_RIGHT); 3757 llassert(snap_edge == SNAP_RIGHT);
3689 3758
3690 // use higher snap threshold for column headers 3759 // use higher snap threshold for column headers
3691 threshold = llmin(threshold, 15); 3760 threshold = llmin(threshold, 10);
3692 3761
3693 LLRect snap_rect = getSnapRect(); 3762 LLRect snap_rect = getSnapRect();
3694 3763
@@ -3727,47 +3796,48 @@ void LLColumnHeader::userSetShape(const LLRect& new_rect)
3727 3796
3728 if (delta_width != 0) 3797 if (delta_width != 0)
3729 { 3798 {
3730 S32 remaining_width = delta_width; 3799 S32 remaining_width = -delta_width;
3731 S32 col; 3800 S32 col;
3732 for (col = mColumn->mIndex + 1; col < mColumn->mParentCtrl->getNumColumns(); col++) 3801 for (col = mColumn->mIndex + 1; col < mColumn->mParentCtrl->getNumColumns(); col++)
3733 { 3802 {
3734 LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); 3803 LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
3735 if (!columnp) break; 3804 if (!columnp) continue;
3736 3805
3737 if (columnp->mHeader && columnp->mHeader->canResize()) 3806 if (columnp->mHeader && columnp->mHeader->canResize())
3738 { 3807 {
3739 // how many pixels in width can this column afford to give up? 3808 // how many pixels in width can this column afford to give up?
3740 S32 resize_buffer_amt = llmax(0, columnp->mWidth - MIN_COLUMN_WIDTH); 3809 S32 resize_buffer_amt = llmax(0, columnp->getWidth() - MIN_COLUMN_WIDTH);
3741 3810
3742 // user shrinking column, need to add width to other columns 3811 // user shrinking column, need to add width to other columns
3743 if (delta_width < 0) 3812 if (delta_width < 0)
3744 { 3813 {
3745 if (!columnp->mDynamicWidth && columnp->mWidth > 0) 3814 if (/*!columnp->mDynamicWidth && */columnp->getWidth() > 0)
3746 { 3815 {
3747 // statically sized column, give all remaining width to this column 3816 // statically sized column, give all remaining width to this column
3748 columnp->mWidth -= remaining_width; 3817 columnp->setWidth(columnp->getWidth() + remaining_width);
3749 if (columnp->mRelWidth > 0.f) 3818 if (columnp->mRelWidth > 0.f)
3750 { 3819 {
3751 columnp->mRelWidth = (F32)columnp->mWidth / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); 3820 columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
3752 } 3821 }
3822 // all padding went to this widget, we're done
3823 break;
3753 } 3824 }
3754 break;
3755 } 3825 }
3756 else 3826 else
3757 { 3827 {
3758 // user growing column, need to take width from other columns 3828 // user growing column, need to take width from other columns
3759 remaining_width -= resize_buffer_amt; 3829 remaining_width += resize_buffer_amt;
3760 3830
3761 if (!columnp->mDynamicWidth && columnp->mWidth > 0) 3831 if (/*!columnp->mDynamicWidth && */columnp->getWidth() > 0)
3762 { 3832 {
3763 columnp->mWidth -= llmin(columnp->mWidth - MIN_COLUMN_WIDTH, delta_width); 3833 columnp->setWidth(columnp->getWidth() - llmin(columnp->getWidth() - MIN_COLUMN_WIDTH, delta_width));
3764 if (columnp->mRelWidth > 0.f) 3834 if (columnp->mRelWidth > 0.f)
3765 { 3835 {
3766 columnp->mRelWidth = (F32)columnp->mWidth / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); 3836 columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
3767 } 3837 }
3768 } 3838 }
3769 3839
3770 if (remaining_width <= 0) 3840 if (remaining_width >= 0)
3771 { 3841 {
3772 // width sucked up from neighboring columns, done 3842 // width sucked up from neighboring columns, done
3773 break; 3843 break;
@@ -3779,14 +3849,14 @@ void LLColumnHeader::userSetShape(const LLRect& new_rect)
3779 // clamp resize amount to maximum that can be absorbed by other columns 3849 // clamp resize amount to maximum that can be absorbed by other columns
3780 if (delta_width > 0) 3850 if (delta_width > 0)
3781 { 3851 {
3782 delta_width -= llmax(remaining_width, 0); 3852 delta_width += llmin(remaining_width, 0);
3783 } 3853 }
3784 3854
3785 // propagate constrained delta_width to new width for this column 3855 // propagate constrained delta_width to new width for this column
3786 new_width = getRect().getWidth() + delta_width - mColumn->mParentCtrl->getColumnPadding(); 3856 new_width = getRect().getWidth() + delta_width - mColumn->mParentCtrl->getColumnPadding();
3787 3857
3788 // use requested width 3858 // use requested width
3789 mColumn->mWidth = new_width; 3859 mColumn->setWidth(new_width);
3790 3860
3791 // update proportional spacing 3861 // update proportional spacing
3792 if (mColumn->mRelWidth > 0.f) 3862 if (mColumn->mRelWidth > 0.f)
@@ -3804,36 +3874,40 @@ void LLColumnHeader::userSetShape(const LLRect& new_rect)
3804void LLColumnHeader::setHasResizableElement(BOOL resizable) 3874void LLColumnHeader::setHasResizableElement(BOOL resizable)
3805{ 3875{
3806 // for now, dynamically spaced columns can't be resized 3876 // for now, dynamically spaced columns can't be resized
3807 if (mColumn->mDynamicWidth) return; 3877// if (mColumn->mDynamicWidth) return;
3808 3878
3809 if (resizable != mHasResizableElement) 3879 if (mHasResizableElement != resizable)
3810 { 3880 {
3881 mColumn->mParentCtrl->dirtyColumns();
3811 mHasResizableElement = resizable; 3882 mHasResizableElement = resizable;
3883 }
3884}
3812 3885
3813 S32 num_resizable_columns = 0; 3886void LLColumnHeader::updateResizeBars()
3814 S32 col; 3887{
3815 for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) 3888 S32 num_resizable_columns = 0;
3889 S32 col;
3890 for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
3891 {
3892 LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
3893 if (columnp->mHeader && columnp->mHeader->canResize())
3816 { 3894 {
3817 LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); 3895 num_resizable_columns++;
3818 if (columnp->mHeader && columnp->mHeader->canResize())
3819 {
3820 num_resizable_columns++;
3821 }
3822 } 3896 }
3897 }
3823 3898
3824 S32 num_resizers_enabled = 0; 3899 S32 num_resizers_enabled = 0;
3825 3900
3826 // now enable/disable resize handles on resizable columns if we have at least two 3901 // now enable/disable resize handles on resizable columns if we have at least two
3827 for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) 3902 for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
3903 {
3904 LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
3905 if (!columnp->mHeader) continue;
3906 BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize();
3907 columnp->mHeader->enableResizeBar(enable);
3908 if (enable)
3828 { 3909 {
3829 LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); 3910 num_resizers_enabled++;
3830 if (!columnp->mHeader) continue;
3831 BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize();
3832 columnp->mHeader->enableResizeBar(enable);
3833 if (enable)
3834 {
3835 num_resizers_enabled++;
3836 }
3837 } 3911 }
3838 } 3912 }
3839} 3913}
@@ -3841,7 +3915,7 @@ void LLColumnHeader::setHasResizableElement(BOOL resizable)
3841void LLColumnHeader::enableResizeBar(BOOL enable) 3915void LLColumnHeader::enableResizeBar(BOOL enable)
3842{ 3916{
3843 // for now, dynamically spaced columns can't be resized 3917 // for now, dynamically spaced columns can't be resized
3844 if (!mColumn->mDynamicWidth) 3918 //if (!mColumn->mDynamicWidth)
3845 { 3919 {
3846 mResizeBar->setEnabled(enable); 3920 mResizeBar->setEnabled(enable);
3847 } 3921 }
@@ -3851,3 +3925,78 @@ BOOL LLColumnHeader::canResize()
3851{ 3925{
3852 return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth); 3926 return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth);
3853} 3927}
3928
3929void LLScrollListColumn::setWidth(S32 width)
3930{
3931 if (!mDynamicWidth && mRelWidth <= 0.f)
3932 {
3933 mParentCtrl->updateStaticColumnWidth(this, width);
3934 }
3935 mWidth = width;
3936}
3937
3938// Default constructor
3939LLScrollListColumn::LLScrollListColumn() :
3940 mName(),
3941 mSortingColumn(),
3942 mSortAscending(TRUE),
3943 mLabel(),
3944 mWidth(-1),
3945 mRelWidth(-1.0),
3946 mDynamicWidth(FALSE),
3947 mMaxContentWidth(0),
3948 mIndex(-1),
3949 mParentCtrl(NULL),
3950 mHeader(NULL),
3951 mFontAlignment(LLFontGL::LEFT)
3952{ }
3953
3954LLScrollListColumn::LLScrollListColumn(const LLSD &sd, LLScrollListCtrl* parent) :
3955 mWidth(0),
3956 mIndex (-1),
3957 mParentCtrl(parent),
3958 mHeader(NULL),
3959 mMaxContentWidth(0),
3960 mDynamicWidth(FALSE),
3961 mRelWidth(-1.f)
3962{
3963 mName = sd.get("name").asString();
3964 mSortingColumn = mName;
3965 if (sd.has("sort"))
3966 {
3967 mSortingColumn = sd.get("sort").asString();
3968 }
3969 mSortAscending = TRUE;
3970 if (sd.has("sort_ascending"))
3971 {
3972 mSortAscending = sd.get("sort_ascending").asBoolean();
3973 }
3974 mLabel = sd.get("label").asString();
3975 if (sd.has("relwidth") && (F32)sd.get("relwidth").asReal() > 0)
3976 {
3977 mRelWidth = (F32)sd.get("relwidth").asReal();
3978 if (mRelWidth < 0) mRelWidth = 0;
3979 if (mRelWidth > 1) mRelWidth = 1;
3980 mDynamicWidth = FALSE;
3981 }
3982 else if(sd.has("dynamicwidth") && (BOOL)sd.get("dynamicwidth").asBoolean() == TRUE)
3983 {
3984 mDynamicWidth = TRUE;
3985 mRelWidth = -1;
3986 }
3987 else
3988 {
3989
3990 setWidth(sd.get("width").asInteger());
3991 }
3992
3993 if (sd.has("halign"))
3994 {
3995 mFontAlignment = (LLFontGL::HAlign)llclamp(sd.get("halign").asInteger(), (S32)LLFontGL::LEFT, (S32)LLFontGL::HCENTER);
3996 }
3997 else
3998 {
3999 mFontAlignment = LLFontGL::LEFT;
4000 }
4001
4002}
diff --git a/linden/indra/llui/llscrolllistctrl.h b/linden/indra/llui/llscrolllistctrl.h
index f276562..72d8894 100644
--- a/linden/indra/llui/llscrolllistctrl.h
+++ b/linden/indra/llui/llscrolllistctrl.h
@@ -16,7 +16,8 @@
16 * 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
17 * 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
18 * 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
19 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 19 * online at
20 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
20 * 21 *
21 * By copying, modifying or distributing this software, you acknowledge 22 * By copying, modifying or distributing this software, you acknowledge
22 * that you have read and understood your obligations described above, 23 * that you have read and understood your obligations described above,
@@ -47,6 +48,7 @@
47#include "llcombobox.h" 48#include "llcombobox.h"
48#include "llscrollbar.h" 49#include "llscrollbar.h"
49#include "llresizebar.h" 50#include "llresizebar.h"
51#include "lldate.h"
50 52
51/* 53/*
52 * Represents a cell in a scrollable table. 54 * Represents a cell in a scrollable table.
@@ -133,6 +135,18 @@ private:
133 static U32 sCount; 135 static U32 sCount;
134}; 136};
135 137
138
139class LLScrollListDate : public LLScrollListText
140{
141public:
142 LLScrollListDate( const LLDate& date, const LLFontGL* font, S32 width=0, U8 font_style = LLFontGL::NORMAL, LLFontGL::HAlign font_alignment = LLFontGL::LEFT, LLColor4& color = LLColor4::black, BOOL use_color = FALSE, BOOL visible = TRUE);
143 virtual void setValue(const LLSD& value);
144 virtual const LLSD getValue() const;
145
146private:
147 LLDate mDate;
148};
149
136/* 150/*
137 * Cell displaying an image. 151 * Cell displaying an image.
138 */ 152 */
@@ -185,88 +199,11 @@ private:
185class LLScrollListColumn 199class LLScrollListColumn
186{ 200{
187public: 201public:
188 // Default constructor 202 LLScrollListColumn();
189 LLScrollListColumn() : 203 LLScrollListColumn(const LLSD &sd, LLScrollListCtrl* parent);
190 mName(), 204
191 mSortingColumn(), 205 void setWidth(S32 width);
192 mSortAscending(TRUE), 206 S32 getWidth() const { return mWidth; }
193 mLabel(),
194 mWidth(-1),
195 mRelWidth(-1.0),
196 mDynamicWidth(FALSE),
197 mMaxContentWidth(0),
198 mIndex(-1),
199 mParentCtrl(NULL),
200 mHeader(NULL),
201 mFontAlignment(LLFontGL::LEFT)
202 { }
203
204 LLScrollListColumn(std::string name, std::string label, S32 width, F32 relwidth) :
205 mName(name),
206 mSortingColumn(name),
207 mSortAscending(TRUE),
208 mLabel(label),
209 mWidth(width),
210 mRelWidth(relwidth),
211 mDynamicWidth(FALSE),
212 mMaxContentWidth(0),
213 mIndex(-1),
214 mParentCtrl(NULL),
215 mHeader(NULL),
216 mFontAlignment(LLFontGL::LEFT)
217 { }
218
219 LLScrollListColumn(const LLSD &sd)
220 {
221 mMaxContentWidth = 0;
222
223 mName = sd.get("name").asString();
224 mSortingColumn = mName;
225 if (sd.has("sort"))
226 {
227 mSortingColumn = sd.get("sort").asString();
228 }
229 mSortAscending = TRUE;
230 if (sd.has("sort_ascending"))
231 {
232 mSortAscending = sd.get("sort_ascending").asBoolean();
233 }
234 mLabel = sd.get("label").asString();
235 if (sd.has("relwidth") && (F32)sd.get("relwidth").asReal() > 0)
236 {
237 mRelWidth = (F32)sd.get("relwidth").asReal();
238 if (mRelWidth < 0) mRelWidth = 0;
239 if (mRelWidth > 1) mRelWidth = 1;
240 mDynamicWidth = FALSE;
241 mWidth = 0;
242 }
243 else if(sd.has("dynamicwidth") && (BOOL)sd.get("dynamicwidth").asBoolean() == TRUE)
244 {
245 mDynamicWidth = TRUE;
246 mRelWidth = -1;
247 mWidth = 0;
248 }
249 else
250 {
251 mWidth = sd.get("width").asInteger();
252 mDynamicWidth = FALSE;
253 mRelWidth = -1;
254 }
255
256 if (sd.has("halign"))
257 {
258 mFontAlignment = (LLFontGL::HAlign)llclamp(sd.get("halign").asInteger(), (S32)LLFontGL::LEFT, (S32)LLFontGL::HCENTER);
259 }
260 else
261 {
262 mFontAlignment = LLFontGL::LEFT;
263 }
264
265 mIndex = -1;
266 mParentCtrl = NULL;
267 mHeader = NULL;
268 mFontAlignment = LLFontGL::LEFT;
269 }
270 207
271 // Public data is fine so long as this remains a simple struct-like data class. 208 // Public data is fine so long as this remains a simple struct-like data class.
272 // If it ever gets any smarter than that, these should all become private 209 // If it ever gets any smarter than that, these should all become private
@@ -275,7 +212,6 @@ public:
275 std::string mSortingColumn; 212 std::string mSortingColumn;
276 BOOL mSortAscending; 213 BOOL mSortAscending;
277 std::string mLabel; 214 std::string mLabel;
278 S32 mWidth;
279 F32 mRelWidth; 215 F32 mRelWidth;
280 BOOL mDynamicWidth; 216 BOOL mDynamicWidth;
281 S32 mMaxContentWidth; 217 S32 mMaxContentWidth;
@@ -283,6 +219,10 @@ public:
283 LLScrollListCtrl* mParentCtrl; 219 LLScrollListCtrl* mParentCtrl;
284 class LLColumnHeader* mHeader; 220 class LLColumnHeader* mHeader;
285 LLFontGL::HAlign mFontAlignment; 221 LLFontGL::HAlign mFontAlignment;
222
223private:
224 S32 mWidth;
225
286}; 226};
287 227
288class LLColumnHeader : public LLComboBox 228class LLColumnHeader : public LLComboBox
@@ -301,6 +241,7 @@ public:
301 void setImage(const std::string &image_name); 241 void setImage(const std::string &image_name);
302 LLScrollListColumn* getColumn() { return mColumn; } 242 LLScrollListColumn* getColumn() { return mColumn; }
303 void setHasResizableElement(BOOL resizable); 243 void setHasResizableElement(BOOL resizable);
244 void updateResizeBars();
304 BOOL canResize(); 245 BOOL canResize();
305 void enableResizeBar(BOOL enable); 246 void enableResizeBar(BOOL enable);
306 std::string getLabel() { return mOrigLabel; } 247 std::string getLabel() { return mOrigLabel; }
@@ -551,8 +492,7 @@ public:
551 492
552 virtual S32 getScrollPos() const; 493 virtual S32 getScrollPos() const;
553 virtual void setScrollPos( S32 pos ); 494 virtual void setScrollPos( S32 pos );
554 495 S32 getSearchColumn();
555 S32 getSearchColumn() { return mSearchColumn; }
556 void setSearchColumn(S32 column) { mSearchColumn = column; } 496 void setSearchColumn(S32 column) { mSearchColumn = column; }
557 S32 getColumnIndexFromOffset(S32 x); 497 S32 getColumnIndexFromOffset(S32 x);
558 S32 getColumnOffsetFromIndex(S32 index); 498 S32 getColumnOffsetFromIndex(S32 index);
@@ -613,8 +553,9 @@ public:
613 virtual void deselect(); 553 virtual void deselect();
614 virtual BOOL canDeselect() const; 554 virtual BOOL canDeselect() const;
615 555
616 void setNumDynamicColumns(int num) { mNumDynamicWidthColumns = num; } 556 void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; }
617 void setTotalStaticColumnWidth(int width) { mTotalStaticColumnWidth = width; } 557 void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width);
558 S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; }
618 559
619 std::string getSortColumnName(); 560 std::string getSortColumnName();
620 BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; } 561 BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; }
@@ -719,6 +660,7 @@ private:
719 S32 mSearchColumn; 660 S32 mSearchColumn;
720 S32 mNumDynamicWidthColumns; 661 S32 mNumDynamicWidthColumns;
721 S32 mTotalStaticColumnWidth; 662 S32 mTotalStaticColumnWidth;
663 S32 mTotalColumnPadding;
722 664
723 BOOL mSorted; 665 BOOL mSorted;
724 666
diff --git a/linden/indra/llui/llslider.cpp b/linden/indra/llui/llslider.cpp
index 51b96c1..4dfc904 100644
--- a/linden/indra/llui/llslider.cpp
+++ b/linden/indra/llui/llslider.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llslider.h b/linden/indra/llui/llslider.h
index 94f5992..154685f 100644
--- a/linden/indra/llui/llslider.h
+++ b/linden/indra/llui/llslider.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llsliderctrl.cpp b/linden/indra/llui/llsliderctrl.cpp
index 477003b..31baddd 100644
--- a/linden/indra/llui/llsliderctrl.cpp
+++ b/linden/indra/llui/llsliderctrl.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -463,7 +464,7 @@ LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory
463 // HACK: Font might not be specified. 464 // HACK: Font might not be specified.
464 if (!font) 465 if (!font)
465 { 466 {
466 font = LLFontGL::sSansSerifSmall; 467 font = LLFontGL::getFontSansSerifSmall();
467 } 468 }
468 469
469 S32 label_width = 0; 470 S32 label_width = 0;
diff --git a/linden/indra/llui/llsliderctrl.h b/linden/indra/llui/llsliderctrl.h
index 56f4661..272dd7f 100644
--- a/linden/indra/llui/llsliderctrl.h
+++ b/linden/indra/llui/llsliderctrl.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llspinctrl.cpp b/linden/indra/llui/llspinctrl.cpp
index e1b47eb..c54a2cd 100644
--- a/linden/indra/llui/llspinctrl.cpp
+++ b/linden/indra/llui/llspinctrl.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -98,7 +99,7 @@ LLSpinCtrl::LLSpinCtrl( const std::string& name, const LLRect& rect, const std::
98 out_id, 99 out_id,
99 in_id, 100 in_id,
100 LLStringUtil::null, 101 LLStringUtil::null,
101 &LLSpinCtrl::onUpBtn, this, LLFontGL::sSansSerif ); 102 &LLSpinCtrl::onUpBtn, this, LLFontGL::getFontSansSerif() );
102 mUpBtn->setFollowsLeft(); 103 mUpBtn->setFollowsLeft();
103 mUpBtn->setFollowsBottom(); 104 mUpBtn->setFollowsBottom();
104 mUpBtn->setHeldDownCallback( &LLSpinCtrl::onUpBtn ); 105 mUpBtn->setHeldDownCallback( &LLSpinCtrl::onUpBtn );
@@ -112,7 +113,7 @@ LLSpinCtrl::LLSpinCtrl( const std::string& name, const LLRect& rect, const std::
112 out_id, 113 out_id,
113 in_id, 114 in_id,
114 LLStringUtil::null, 115 LLStringUtil::null,
115 &LLSpinCtrl::onDownBtn, this, LLFontGL::sSansSerif ); 116 &LLSpinCtrl::onDownBtn, this, LLFontGL::getFontSansSerif() );
116 mDownBtn->setFollowsLeft(); 117 mDownBtn->setFollowsLeft();
117 mDownBtn->setFollowsBottom(); 118 mDownBtn->setFollowsBottom();
118 mDownBtn->setHeldDownCallback( &LLSpinCtrl::onDownBtn ); 119 mDownBtn->setHeldDownCallback( &LLSpinCtrl::onDownBtn );
diff --git a/linden/indra/llui/llspinctrl.h b/linden/indra/llui/llspinctrl.h
index 1a96767..dfd0eb3 100644
--- a/linden/indra/llui/llspinctrl.h
+++ b/linden/indra/llui/llspinctrl.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -81,6 +82,7 @@ public:
81 virtual void setFocus( BOOL b ); 82 virtual void setFocus( BOOL b );
82 virtual void clear(); 83 virtual void clear();
83 virtual BOOL isDirty() const { return( mValue != mInitialValue ); } 84 virtual BOOL isDirty() const { return( mValue != mInitialValue ); }
85 virtual void resetDirty() { mInitialValue = mValue; }
84 86
85 virtual void setPrecision(S32 precision); 87 virtual void setPrecision(S32 precision);
86 virtual void setMinValue(F32 min) { mMinValue = min; } 88 virtual void setMinValue(F32 min) { mMinValue = min; }
diff --git a/linden/indra/llui/llstyle.cpp b/linden/indra/llui/llstyle.cpp
index fc6c14e..a716cbb 100644
--- a/linden/indra/llui/llstyle.cpp
+++ b/linden/indra/llui/llstyle.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llstyle.h b/linden/indra/llui/llstyle.h
index 8dc1a40..3ad379c 100644
--- a/linden/indra/llui/llstyle.h
+++ b/linden/indra/llui/llstyle.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lltabcontainer.cpp b/linden/indra/llui/lltabcontainer.cpp
index 6b028d4..f416948 100644
--- a/linden/indra/llui/lltabcontainer.cpp
+++ b/linden/indra/llui/lltabcontainer.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -70,6 +71,7 @@ LLTabContainer::LLTabContainer(const std::string& name, const LLRect& rect, TabP
70 : 71 :
71 LLPanel(name, rect, bordered), 72 LLPanel(name, rect, bordered),
72 mCurrentTabIdx(-1), 73 mCurrentTabIdx(-1),
74 mNextTabIdx(-1),
73 mTabsHidden(FALSE), 75 mTabsHidden(FALSE),
74 mScrolled(FALSE), 76 mScrolled(FALSE),
75 mScrollPos(0), 77 mScrollPos(0),
@@ -1149,9 +1151,37 @@ BOOL LLTabContainer::selectTab(S32 which)
1149 { 1151 {
1150 return FALSE; 1152 return FALSE;
1151 } 1153 }
1152 1154
1155 if (!selected_tuple->mPrecommitChangeCallback)
1156 {
1157 return setTab(which);
1158 }
1159
1160 mNextTabIdx = which;
1161 selected_tuple->mPrecommitChangeCallback(selected_tuple->mUserData, false);
1162 return TRUE;
1163}
1164
1165BOOL LLTabContainer::setTab(S32 which)
1166{
1167 if (which == -1)
1168 {
1169 if (mNextTabIdx == -1)
1170 {
1171 return FALSE;
1172 }
1173 which = mNextTabIdx;
1174 mNextTabIdx = -1;
1175 }
1176
1177 LLTabTuple* selected_tuple = getTab(which);
1178 if (!selected_tuple)
1179 {
1180 return FALSE;
1181 }
1182
1153 BOOL is_visible = FALSE; 1183 BOOL is_visible = FALSE;
1154 if (getTab(which)->mButton->getEnabled()) 1184 if (selected_tuple->mButton->getEnabled())
1155 { 1185 {
1156 setCurrentPanelIndex(which); 1186 setCurrentPanelIndex(which);
1157 1187
@@ -1331,6 +1361,15 @@ void LLTabContainer::setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(v
1331 } 1361 }
1332} 1362}
1333 1363
1364void LLTabContainer::setTabPrecommitChangeCallback(LLPanel* tab, void (*on_precommit)(void*, bool))
1365{
1366 LLTabTuple* tuplep = getTabByPanel(tab);
1367 if (tuplep)
1368 {
1369 tuplep->mPrecommitChangeCallback = on_precommit;
1370 }
1371}
1372
1334void LLTabContainer::setTabUserData(LLPanel* tab, void* userdata) 1373void LLTabContainer::setTabUserData(LLPanel* tab, void* userdata)
1335{ 1374{
1336 LLTabTuple* tuplep = getTabByPanel(tab); 1375 LLTabTuple* tuplep = getTabByPanel(tab);
@@ -1370,11 +1409,6 @@ void LLTabContainer::onTabBtn( void* userdata )
1370 LLTabTuple* tuple = (LLTabTuple*) userdata; 1409 LLTabTuple* tuple = (LLTabTuple*) userdata;
1371 LLTabContainer* self = tuple->mTabContainer; 1410 LLTabContainer* self = tuple->mTabContainer;
1372 self->selectTabPanel( tuple->mTabPanel ); 1411 self->selectTabPanel( tuple->mTabPanel );
1373
1374 if( tuple->mOnChangeCallback )
1375 {
1376 tuple->mOnChangeCallback( tuple->mUserData, true );
1377 }
1378 1412
1379 tuple->mTabPanel->setFocus(TRUE); 1413 tuple->mTabPanel->setFocus(TRUE);
1380} 1414}
@@ -1624,14 +1658,14 @@ void LLTabContainer::initButtons()
1624 in_id = "UIImgBtnJumpLeftInUUID"; 1658 in_id = "UIImgBtnJumpLeftInUUID";
1625 mJumpPrevArrowBtn = new LLButton(std::string("Jump Left Arrow"), jump_left_arrow_btn_rect, 1659 mJumpPrevArrowBtn = new LLButton(std::string("Jump Left Arrow"), jump_left_arrow_btn_rect,
1626 out_id, in_id, LLStringUtil::null, 1660 out_id, in_id, LLStringUtil::null,
1627 &LLTabContainer::onJumpFirstBtn, this, LLFontGL::sSansSerif ); 1661 &LLTabContainer::onJumpFirstBtn, this, LLFontGL::getFontSansSerif() );
1628 mJumpPrevArrowBtn->setFollowsLeft(); 1662 mJumpPrevArrowBtn->setFollowsLeft();
1629 1663
1630 out_id = "UIImgBtnScrollLeftOutUUID"; 1664 out_id = "UIImgBtnScrollLeftOutUUID";
1631 in_id = "UIImgBtnScrollLeftInUUID"; 1665 in_id = "UIImgBtnScrollLeftInUUID";
1632 mPrevArrowBtn = new LLButton(std::string("Left Arrow"), left_arrow_btn_rect, 1666 mPrevArrowBtn = new LLButton(std::string("Left Arrow"), left_arrow_btn_rect,
1633 out_id, in_id, LLStringUtil::null, 1667 out_id, in_id, LLStringUtil::null,
1634 &LLTabContainer::onPrevBtn, this, LLFontGL::sSansSerif ); 1668 &LLTabContainer::onPrevBtn, this, LLFontGL::getFontSansSerif() );
1635 mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld); 1669 mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld);
1636 mPrevArrowBtn->setFollowsLeft(); 1670 mPrevArrowBtn->setFollowsLeft();
1637 1671
@@ -1640,7 +1674,7 @@ void LLTabContainer::initButtons()
1640 mJumpNextArrowBtn = new LLButton(std::string("Jump Right Arrow"), jump_right_arrow_btn_rect, 1674 mJumpNextArrowBtn = new LLButton(std::string("Jump Right Arrow"), jump_right_arrow_btn_rect,
1641 out_id, in_id, LLStringUtil::null, 1675 out_id, in_id, LLStringUtil::null,
1642 &LLTabContainer::onJumpLastBtn, this, 1676 &LLTabContainer::onJumpLastBtn, this,
1643 LLFontGL::sSansSerif); 1677 LLFontGL::getFontSansSerif());
1644 mJumpNextArrowBtn->setFollowsRight(); 1678 mJumpNextArrowBtn->setFollowsRight();
1645 1679
1646 out_id = "UIImgBtnScrollRightOutUUID"; 1680 out_id = "UIImgBtnScrollRightOutUUID";
@@ -1648,7 +1682,7 @@ void LLTabContainer::initButtons()
1648 mNextArrowBtn = new LLButton(std::string("Right Arrow"), right_arrow_btn_rect, 1682 mNextArrowBtn = new LLButton(std::string("Right Arrow"), right_arrow_btn_rect,
1649 out_id, in_id, LLStringUtil::null, 1683 out_id, in_id, LLStringUtil::null,
1650 &LLTabContainer::onNextBtn, this, 1684 &LLTabContainer::onNextBtn, this,
1651 LLFontGL::sSansSerif); 1685 LLFontGL::getFontSansSerif());
1652 mNextArrowBtn->setFollowsRight(); 1686 mNextArrowBtn->setFollowsRight();
1653 1687
1654 if( getTabPosition() == TOP ) 1688 if( getTabPosition() == TOP )
diff --git a/linden/indra/llui/lltabcontainer.h b/linden/indra/llui/lltabcontainer.h
index 96400f0..8117cde 100644
--- a/linden/indra/llui/lltabcontainer.h
+++ b/linden/indra/llui/lltabcontainer.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -107,6 +108,7 @@ public:
107 BOOL selectTabPanel( LLPanel* child ); 108 BOOL selectTabPanel( LLPanel* child );
108 BOOL selectTab(S32 which); 109 BOOL selectTab(S32 which);
109 BOOL selectTabByName(const std::string& title); 110 BOOL selectTabByName(const std::string& title);
111 BOOL setTab(S32 which);
110 112
111 BOOL getTabPanelFlashing(LLPanel* child); 113 BOOL getTabPanelFlashing(LLPanel* child);
112 void setTabPanelFlashing(LLPanel* child, BOOL state); 114 void setTabPanelFlashing(LLPanel* child, BOOL state);
@@ -118,6 +120,7 @@ public:
118 S32 getTopBorderHeight() const; 120 S32 getTopBorderHeight() const;
119 121
120 void setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*,bool)); 122 void setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*,bool));
123 void setTabPrecommitChangeCallback(LLPanel* tab, void (*on_precommit)(void*, bool));
121 void setTabUserData(LLPanel* tab, void* userdata); 124 void setTabUserData(LLPanel* tab, void* userdata);
122 125
123 void setRightTabBtnOffset( S32 offset ); 126 void setRightTabBtnOffset( S32 offset );
@@ -147,12 +150,14 @@ private:
147 struct LLTabTuple 150 struct LLTabTuple
148 { 151 {
149 LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b, 152 LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b,
150 void (*cb)(void*,bool), void* userdata, LLTextBox* placeholder = NULL ) 153 void (*cb)(void*,bool), void* userdata, LLTextBox* placeholder = NULL,
154 void (*pcb)(void*,bool) = NULL)
151 : 155 :
152 mTabContainer(c), 156 mTabContainer(c),
153 mTabPanel(p), 157 mTabPanel(p),
154 mButton(b), 158 mButton(b),
155 mOnChangeCallback( cb ), 159 mOnChangeCallback( cb ),
160 mPrecommitChangeCallback( pcb ),
156 mUserData( userdata ), 161 mUserData( userdata ),
157 mOldState(FALSE), 162 mOldState(FALSE),
158 mPlaceholderText(placeholder), 163 mPlaceholderText(placeholder),
@@ -163,6 +168,9 @@ private:
163 LLPanel* mTabPanel; 168 LLPanel* mTabPanel;
164 LLButton* mButton; 169 LLButton* mButton;
165 void (*mOnChangeCallback)(void*, bool); 170 void (*mOnChangeCallback)(void*, bool);
171 void (*mPrecommitChangeCallback)(void*,bool); // Precommit callback gets called before tab is changed and
172 // can prevent it from being changed. onChangeCallback is called
173 // immediately after tab is actually changed - Nyx
166 void* mUserData; 174 void* mUserData;
167 BOOL mOldState; 175 BOOL mOldState;
168 LLTextBox* mPlaceholderText; 176 LLTextBox* mPlaceholderText;
@@ -199,6 +207,7 @@ private:
199 tuple_list_t mTabList; 207 tuple_list_t mTabList;
200 208
201 S32 mCurrentTabIdx; 209 S32 mCurrentTabIdx;
210 S32 mNextTabIdx;
202 BOOL mTabsHidden; 211 BOOL mTabsHidden;
203 212
204 BOOL mScrolled; 213 BOOL mScrolled;
diff --git a/linden/indra/llui/lltabcontainervertical.cpp b/linden/indra/llui/lltabcontainervertical.cpp
index fa24ed1..a729c95 100644
--- a/linden/indra/llui/lltabcontainervertical.cpp
+++ b/linden/indra/llui/lltabcontainervertical.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lltabcontainervertical.h b/linden/indra/llui/lltabcontainervertical.h
index d01d20a..ce42367 100644
--- a/linden/indra/llui/lltabcontainervertical.h
+++ b/linden/indra/llui/lltabcontainervertical.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lltextbox.cpp b/linden/indra/llui/lltextbox.cpp
index f43b7d2..89893bc 100644
--- a/linden/indra/llui/lltextbox.cpp
+++ b/linden/indra/llui/lltextbox.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -33,32 +34,16 @@
33#include "lltextbox.h" 34#include "lltextbox.h"
34#include "lluictrlfactory.h" 35#include "lluictrlfactory.h"
35#include "llfocusmgr.h" 36#include "llfocusmgr.h"
37#include "llwindow.h"
36 38
37static LLRegisterWidget<LLTextBox> r("text"); 39static LLRegisterWidget<LLTextBox> r("text");
38 40
39LLTextBox::LLTextBox(const std::string& name, const LLRect& rect, const std::string& text, 41LLTextBox::LLTextBox(const std::string& name, const LLRect& rect, const std::string& text,
40 const LLFontGL* font, BOOL mouse_opaque) 42 const LLFontGL* font, BOOL mouse_opaque)
41: LLUICtrl(name, rect, mouse_opaque, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP ), 43: LLUICtrl(name, rect, mouse_opaque, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP ),
42 mFontGL(font ? font : LLFontGL::sSansSerifSmall), 44 mFontGL(font ? font : LLFontGL::getFontSansSerifSmall())
43 mTextColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
44 mDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ),
45 mBackgroundColor( LLUI::sColorsGroup->getColor( "DefaultBackgroundColor" ) ),
46 mBorderColor( LLUI::sColorsGroup->getColor( "DefaultHighlightLight" ) ),
47 mHoverColor( LLUI::sColorsGroup->getColor( "LabelSelectedColor" ) ),
48 mHoverActive( FALSE ),
49 mHasHover( FALSE ),
50 mBackgroundVisible( FALSE ),
51 mBorderVisible( FALSE ),
52 mFontStyle(LLFontGL::DROP_SHADOW_SOFT),
53 mBorderDropShadowVisible( FALSE ),
54 mUseEllipses( FALSE ),
55 mHPad(0),
56 mVPad(0),
57 mHAlign( LLFontGL::LEFT ),
58 mVAlign( LLFontGL::TOP ),
59 mClickedCallback(NULL),
60 mCallbackUserData(NULL)
61{ 45{
46 initDefaults();
62 setText( text ); 47 setText( text );
63 setTabStop(FALSE); 48 setTabStop(FALSE);
64} 49}
@@ -66,26 +51,9 @@ LLTextBox::LLTextBox(const std::string& name, const LLRect& rect, const std::str
66LLTextBox::LLTextBox(const std::string& name, const std::string& text, F32 max_width, 51LLTextBox::LLTextBox(const std::string& name, const std::string& text, F32 max_width,
67 const LLFontGL* font, BOOL mouse_opaque) : 52 const LLFontGL* font, BOOL mouse_opaque) :
68 LLUICtrl(name, LLRect(0, 0, 1, 1), mouse_opaque, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP), 53 LLUICtrl(name, LLRect(0, 0, 1, 1), mouse_opaque, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP),
69 mFontGL(font ? font : LLFontGL::sSansSerifSmall), 54 mFontGL(font ? font : LLFontGL::getFontSansSerifSmall())
70 mTextColor(LLUI::sColorsGroup->getColor("LabelTextColor")),
71 mDisabledColor(LLUI::sColorsGroup->getColor("LabelDisabledColor")),
72 mBackgroundColor(LLUI::sColorsGroup->getColor("DefaultBackgroundColor")),
73 mBorderColor(LLUI::sColorsGroup->getColor("DefaultHighlightLight")),
74 mHoverColor( LLUI::sColorsGroup->getColor( "LabelSelectedColor" ) ),
75 mHoverActive( FALSE ),
76 mHasHover( FALSE ),
77 mBackgroundVisible(FALSE),
78 mBorderVisible(FALSE),
79 mFontStyle(LLFontGL::DROP_SHADOW_SOFT),
80 mBorderDropShadowVisible(FALSE),
81 mUseEllipses( FALSE ),
82 mHPad(0),
83 mVPad(0),
84 mHAlign(LLFontGL::LEFT),
85 mVAlign( LLFontGL::TOP ),
86 mClickedCallback(NULL),
87 mCallbackUserData(NULL)
88{ 55{
56 initDefaults();
89 setWrappedText(text, max_width); 57 setWrappedText(text, max_width);
90 reshapeToFitText(); 58 reshapeToFitText();
91 setTabStop(FALSE); 59 setTabStop(FALSE);
@@ -93,47 +61,34 @@ LLTextBox::LLTextBox(const std::string& name, const std::string& text, F32 max_w
93 61
94LLTextBox::LLTextBox(const std::string& name_and_label, const LLRect& rect) : 62LLTextBox::LLTextBox(const std::string& name_and_label, const LLRect& rect) :
95 LLUICtrl(name_and_label, rect, TRUE, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP), 63 LLUICtrl(name_and_label, rect, TRUE, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP),
96 mFontGL(LLFontGL::sSansSerifSmall), 64 mFontGL(LLFontGL::getFontSansSerifSmall())
97 mTextColor(LLUI::sColorsGroup->getColor("LabelTextColor")),
98 mDisabledColor(LLUI::sColorsGroup->getColor("LabelDisabledColor")),
99 mBackgroundColor(LLUI::sColorsGroup->getColor("DefaultBackgroundColor")),
100 mBorderColor(LLUI::sColorsGroup->getColor("DefaultHighlightLight")),
101 mBackgroundVisible(FALSE),
102 mBorderVisible(FALSE),
103 mFontStyle(LLFontGL::DROP_SHADOW_SOFT),
104 mBorderDropShadowVisible(FALSE),
105 mHPad(0),
106 mVPad(0),
107 mHAlign(LLFontGL::LEFT),
108 mVAlign( LLFontGL::TOP ),
109 mClickedCallback(NULL),
110 mCallbackUserData(NULL)
111{ 65{
66 initDefaults();
112 setText( name_and_label ); 67 setText( name_and_label );
113 setTabStop(FALSE); 68 setTabStop(FALSE);
114} 69}
115 70
116LLTextBox::LLTextBox(const std::string& name_and_label) : 71void LLTextBox::initDefaults()
117 LLUICtrl(name_and_label, LLRect(0, 0, 1, 1), TRUE, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP),
118 mFontGL(LLFontGL::sSansSerifSmall),
119 mTextColor(LLUI::sColorsGroup->getColor("LabelTextColor")),
120 mDisabledColor(LLUI::sColorsGroup->getColor("LabelDisabledColor")),
121 mBackgroundColor(LLUI::sColorsGroup->getColor("DefaultBackgroundColor")),
122 mBorderColor(LLUI::sColorsGroup->getColor("DefaultHighlightLight")),
123 mBackgroundVisible(FALSE),
124 mBorderVisible(FALSE),
125 mFontStyle(LLFontGL::DROP_SHADOW_SOFT),
126 mBorderDropShadowVisible(FALSE),
127 mHPad(0),
128 mVPad(0),
129 mHAlign(LLFontGL::LEFT),
130 mVAlign( LLFontGL::TOP ),
131 mClickedCallback(NULL),
132 mCallbackUserData(NULL)
133{ 72{
134 setWrappedText(name_and_label); 73 mTextColor = LLUI::sColorsGroup->getColor("LabelTextColor");
135 reshapeToFitText(); 74 mDisabledColor = LLUI::sColorsGroup->getColor("LabelDisabledColor");
136 setTabStop(FALSE); 75 mBackgroundColor = LLUI::sColorsGroup->getColor("DefaultBackgroundColor");
76 mBorderColor = LLUI::sColorsGroup->getColor("DefaultHighlightLight");
77 mHoverColor = LLUI::sColorsGroup->getColor( "LabelSelectedColor" );
78 mHoverActive = FALSE;
79 mHasHover = FALSE;
80 mBackgroundVisible = FALSE;
81 mBorderVisible = FALSE;
82 mFontStyle = LLFontGL::DROP_SHADOW_SOFT;
83 mBorderDropShadowVisible = FALSE;
84 mUseEllipses = FALSE;
85 mLineSpacing = 0;
86 mHPad = 0;
87 mVPad = 0;
88 mHAlign = LLFontGL::LEFT;
89 mVAlign = LLFontGL::TOP;
90 mClickedCallback = NULL;
91 mCallbackUserData = NULL;
137} 92}
138 93
139BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask) 94BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask)
@@ -193,12 +148,14 @@ BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask)
193 148
194BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask) 149BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask)
195{ 150{
151 BOOL handled = LLView::handleHover(x,y,mask);
196 if(mHoverActive) 152 if(mHoverActive)
197 { 153 {
198 mHasHover = TRUE; // This should be set every frame during a hover. 154 mHasHover = TRUE; // This should be set every frame during a hover.
199 return TRUE; 155 getWindow()->setCursor(UI_CURSOR_ARROW);
200 } 156 }
201 return LLView::handleHover(x,y,mask); 157
158 return (handled || mHasHover);
202} 159}
203 160
204void LLTextBox::setText(const LLStringExplicit& text) 161void LLTextBox::setText(const LLStringExplicit& text)
@@ -412,7 +369,7 @@ void LLTextBox::drawText( S32 x, S32 y, const LLColor4& color )
412 mFontStyle, 369 mFontStyle,
413 line_length, getRect().getWidth(), NULL, TRUE, mUseEllipses ); 370 line_length, getRect().getWidth(), NULL, TRUE, mUseEllipses );
414 cur_pos += line_length + 1; 371 cur_pos += line_length + 1;
415 y -= llfloor(mFontGL->getLineHeight()); 372 y -= llfloor(mFontGL->getLineHeight()) + mLineSpacing;
416 } 373 }
417 } 374 }
418} 375}
@@ -469,6 +426,8 @@ LLView* LLTextBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
469 426
470 text_box->initFromXML(node, parent); 427 text_box->initFromXML(node, parent);
471 428
429 node->getAttributeS32("line_spacing", text_box->mLineSpacing);
430
472 std::string font_style; 431 std::string font_style;
473 if (node->getAttributeString("font-style", font_style)) 432 if (node->getAttributeString("font-style", font_style))
474 { 433 {
diff --git a/linden/indra/llui/lltextbox.h b/linden/indra/llui/lltextbox.h
index 83e4a9b..07a6aa3 100644
--- a/linden/indra/llui/lltextbox.h
+++ b/linden/indra/llui/lltextbox.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -54,7 +55,10 @@ public:
54 55
55 // "Simple" constructors for text boxes that have the same name and label *TO BE DEPRECATED* 56 // "Simple" constructors for text boxes that have the same name and label *TO BE DEPRECATED*
56 LLTextBox(const std::string& name_and_label, const LLRect& rect); 57 LLTextBox(const std::string& name_and_label, const LLRect& rect);
57 LLTextBox(const std::string& name_and_label); 58
59 // Consolidate common member initialization
60 // 20+ initializers times 3+ constructors is unmaintainable.
61 void initDefaults();
58 62
59 virtual ~LLTextBox() {} 63 virtual ~LLTextBox() {}
60 64
@@ -88,8 +92,7 @@ public:
88 void setVPad(S32 pixels) { mVPad = pixels; } 92 void setVPad(S32 pixels) { mVPad = pixels; }
89 void setRightAlign() { mHAlign = LLFontGL::RIGHT; } 93 void setRightAlign() { mHAlign = LLFontGL::RIGHT; }
90 void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } 94 void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; }
91 void setClickedCallback( void (*cb)(void *data) ){ mClickedCallback = cb; } // mouse down and up within button 95 void setClickedCallback( void (*cb)(void *data), void* data = NULL ){ mClickedCallback = cb; mCallbackUserData = data; } // mouse down and up within button
92 void setCallbackUserData( void* data ) { mCallbackUserData = data; }
93 96
94 const LLFontGL* getFont() const { return mFontGL; } 97 const LLFontGL* getFont() const { return mFontGL; }
95 98
@@ -124,6 +127,8 @@ private:
124 BOOL mBorderDropShadowVisible; 127 BOOL mBorderDropShadowVisible;
125 BOOL mUseEllipses; 128 BOOL mUseEllipses;
126 129
130 S32 mLineSpacing;
131
127 S32 mHPad; 132 S32 mHPad;
128 S32 mVPad; 133 S32 mVPad;
129 LLFontGL::HAlign mHAlign; 134 LLFontGL::HAlign mHAlign;
diff --git a/linden/indra/llui/lltexteditor.cpp b/linden/indra/llui/lltexteditor.cpp
index 62064d9..7928887 100644
--- a/linden/indra/llui/lltexteditor.cpp
+++ b/linden/indra/llui/lltexteditor.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -56,6 +57,7 @@
56#include "llcontrol.h" 57#include "llcontrol.h"
57#include "llimagegl.h" 58#include "llimagegl.h"
58#include "llwindow.h" 59#include "llwindow.h"
60#include "lltextparser.h"
59#include <queue> 61#include <queue>
60 62
61// 63//
@@ -299,7 +301,7 @@ LLTextEditor::LLTextEditor(
299 } 301 }
300 else 302 else
301 { 303 {
302 mGLFont = LLFontGL::sSansSerif; 304 mGLFont = LLFontGL::getFontSansSerif();
303 } 305 }
304 306
305 updateTextRect(); 307 updateTextRect();
@@ -382,7 +384,7 @@ void LLTextEditor::updateLineStartList(S32 startpos)
382{ 384{
383 updateSegments(); 385 updateSegments();
384 386
385 bindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); 387 bindEmbeddedChars(mGLFont);
386 388
387 S32 seg_num = mSegments.size(); 389 S32 seg_num = mSegments.size();
388 S32 seg_idx = 0; 390 S32 seg_idx = 0;
@@ -460,7 +462,7 @@ void LLTextEditor::updateLineStartList(S32 startpos)
460 } 462 }
461 } 463 }
462 464
463 unbindEmbeddedChars(const_cast<LLFontGL*>(mGLFont)); 465 unbindEmbeddedChars(mGLFont);
464 466
465 mScrollbar->setDocSize( getLineCount() ); 467 mScrollbar->setDocSize( getLineCount() );
466 468
@@ -851,13 +853,13 @@ S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL rou
851 if (mAllowEmbeddedItems) 853 if (mAllowEmbeddedItems)
852 { 854 {
853 // Figure out which character we're nearest to. 855 // Figure out which character we're nearest to.
854 bindEmbeddedChars(const_cast<LLFontGL*>(mGLFont)); 856 bindEmbeddedChars(mGLFont);
855 pos = mGLFont->charFromPixelOffset(mWText.c_str(), line_start, 857 pos = mGLFont->charFromPixelOffset(mWText.c_str(), line_start,
856 (F32)(local_x - mTextRect.mLeft), 858 (F32)(local_x - mTextRect.mLeft),
857 (F32)(mTextRect.getWidth()), 859 (F32)(mTextRect.getWidth()),
858 line_len, 860 line_len,
859 round, TRUE); 861 round, TRUE);
860 unbindEmbeddedChars(const_cast<LLFontGL*>(mGLFont)); 862 unbindEmbeddedChars(mGLFont);
861 } 863 }
862 else 864 else
863 { 865 {
@@ -1009,7 +1011,7 @@ void LLTextEditor::indentSelectedLines( S32 spaces )
1009 } 1011 }
1010 else 1012 else
1011 { 1013 {
1012 while( right < getLength() && (text[right] != '\n') ) 1014 while( (text[right] != '\n') && (right <= getLength() ) )
1013 { 1015 {
1014 right++; 1016 right++;
1015 } 1017 }
@@ -1321,6 +1323,8 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
1321 1323
1322 setCursorAtLocalPos( x, y, TRUE ); 1324 setCursorAtLocalPos( x, y, TRUE );
1323 endSelection(); 1325 endSelection();
1326
1327 updateScrollFromCursor();
1324 } 1328 }
1325 1329
1326 if( !hasSelection() ) 1330 if( !hasSelection() )
@@ -2928,7 +2932,7 @@ void LLTextEditor::drawText()
2928 // draw the line numbers 2932 // draw the line numbers
2929 if( mShowLineNumbers && !cur_line_is_continuation) 2933 if( mShowLineNumbers && !cur_line_is_continuation)
2930 { 2934 {
2931 const LLFontGL *num_font = LLFontGL::sMonospace; 2935 const LLFontGL *num_font = LLFontGL::getFontMonospace();
2932 F32 y_top = text_y + ((F32)llround(num_font->getLineHeight()) / 2); 2936 F32 y_top = text_y + ((F32)llround(num_font->getLineHeight()) / 2);
2933 const LLWString ltext = utf8str_to_wstring(llformat("%*d", UI_TEXTEDITOR_LINE_NUMBER_DIGITS, cur_line_num )); 2937 const LLWString ltext = utf8str_to_wstring(llformat("%*d", UI_TEXTEDITOR_LINE_NUMBER_DIGITS, cur_line_num ));
2934 BOOL is_cur_line = getCurrentLine() == cur_line_num; 2938 BOOL is_cur_line = getCurrentLine() == cur_line_num;
@@ -3113,7 +3117,7 @@ void LLTextEditor::draw()
3113 { 3117 {
3114 LLLocalClipRect clip(LLRect(0, getRect().getHeight(), getRect().getWidth() - (mScrollbar->getVisible() ? SCROLLBAR_SIZE : 0), 0)); 3118 LLLocalClipRect clip(LLRect(0, getRect().getHeight(), getRect().getWidth() - (mScrollbar->getVisible() ? SCROLLBAR_SIZE : 0), 0));
3115 3119
3116 bindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); 3120 bindEmbeddedChars(mGLFont);
3117 3121
3118 drawBackground(); 3122 drawBackground();
3119 drawSelectionBackground(); 3123 drawSelectionBackground();
@@ -3121,7 +3125,7 @@ void LLTextEditor::draw()
3121 drawText(); 3125 drawText();
3122 drawCursor(); 3126 drawCursor();
3123 3127
3124 unbindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); 3128 unbindEmbeddedChars(mGLFont);
3125 3129
3126 //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret 3130 //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret
3127 // when in readonly mode 3131 // when in readonly mode
@@ -3242,7 +3246,7 @@ void LLTextEditor::changePage( S32 delta )
3242 3246
3243void LLTextEditor::changeLine( S32 delta ) 3247void LLTextEditor::changeLine( S32 delta )
3244{ 3248{
3245 bindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); 3249 bindEmbeddedChars(mGLFont);
3246 3250
3247 S32 line, offset; 3251 S32 line, offset;
3248 getLineAndOffset( mCursorPos, &line, &offset ); 3252 getLineAndOffset( mCursorPos, &line, &offset );
@@ -3269,7 +3273,7 @@ void LLTextEditor::changeLine( S32 delta )
3269 } 3273 }
3270 else 3274 else
3271 { 3275 {
3272 unbindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); 3276 unbindEmbeddedChars(mGLFont);
3273 return; 3277 return;
3274 } 3278 }
3275 3279
@@ -3294,7 +3298,7 @@ void LLTextEditor::changeLine( S32 delta )
3294 3298
3295 // put desired position into remember-buffer after setCursorPos() 3299 // put desired position into remember-buffer after setCursorPos()
3296 mDesiredXPixel = desired_x_pixel; 3300 mDesiredXPixel = desired_x_pixel;
3297 unbindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); 3301 unbindEmbeddedChars(mGLFont);
3298} 3302}
3299 3303
3300BOOL LLTextEditor::isScrolledToTop() 3304BOOL LLTextEditor::isScrolledToTop()
@@ -3384,7 +3388,9 @@ void LLTextEditor::endOfLine()
3384 3388
3385void LLTextEditor::endOfDoc() 3389void LLTextEditor::endOfDoc()
3386{ 3390{
3387 mScrollbar->setDocPos( mScrollbar->getDocPosMax() ); 3391 mScrollbar->setDocPos(mScrollbar->getDocPosMax());
3392 mScrolledToBottom = true;
3393
3388 S32 len = getLength(); 3394 S32 len = getLength();
3389 if( len ) 3395 if( len )
3390 { 3396 {
@@ -3514,18 +3520,26 @@ void LLTextEditor::appendColoredText(const std::string &new_text,
3514 const LLColor4 &color, 3520 const LLColor4 &color,
3515 const std::string& font_name) 3521 const std::string& font_name)
3516{ 3522{
3523 LLColor4 lcolor=color;
3524 if (mParseHighlights)
3525 {
3526 LLTextParser* highlight = LLTextParser::getInstance();
3527 highlight->parseFullLineHighlights(new_text, &lcolor);
3528 }
3529
3517 LLStyleSP style(new LLStyle); 3530 LLStyleSP style(new LLStyle);
3518 style->setVisible(true); 3531 style->setVisible(true);
3519 style->setColor(color); 3532 style->setColor(lcolor);
3520 style->setFontName(font_name); 3533 style->setFontName(font_name);
3521 appendStyledText(new_text, allow_undo, prepend_newline, &style); 3534 appendStyledText(new_text, allow_undo, prepend_newline, style);
3522} 3535}
3523 3536
3524void LLTextEditor::appendStyledText(const std::string &new_text, 3537void LLTextEditor::appendStyledText(const std::string &new_text,
3525 bool allow_undo, 3538 bool allow_undo,
3526 bool prepend_newline, 3539 bool prepend_newline,
3527 const LLStyleSP *stylep) 3540 LLStyleSP stylep)
3528{ 3541{
3542 S32 part = (S32)LLTextParser::WHOLE;
3529 if(mParseHTML) 3543 if(mParseHTML)
3530 { 3544 {
3531 3545
@@ -3538,34 +3552,80 @@ void LLTextEditor::appendStyledText(const std::string &new_text,
3538 html->setColor(mLinkColor); 3552 html->setColor(mLinkColor);
3539 if (stylep) 3553 if (stylep)
3540 { 3554 {
3541 html->setFontName((*stylep)->getFontString()); 3555 html->setFontName(stylep->getFontString());
3542 } 3556 }
3543 html->mUnderline = TRUE; 3557 html->mUnderline = TRUE;
3544 3558
3545 if (start > 0) appendText(text.substr(0,start),allow_undo, prepend_newline, stylep); 3559 if (start > 0)
3560 {
3561 if (part == (S32)LLTextParser::WHOLE ||
3562 part == (S32)LLTextParser::START)
3563 {
3564 part = (S32)LLTextParser::START;
3565 }
3566 else
3567 {
3568 part = (S32)LLTextParser::MIDDLE;
3569 }
3570 std::string subtext=text.substr(0,start);
3571 appendHighlightedText(subtext,allow_undo, prepend_newline, part, stylep);
3572 }
3573
3546 html->setLinkHREF(text.substr(start,end-start)); 3574 html->setLinkHREF(text.substr(start,end-start));
3547 appendText(text.substr(start, end-start),allow_undo, prepend_newline, &html); 3575 appendText(text.substr(start, end-start),allow_undo, prepend_newline, html);
3548 if (end < (S32)text.length()) 3576 if (end < (S32)text.length())
3549 { 3577 {
3550 text = text.substr(end,text.length() - end); 3578 text = text.substr(end,text.length() - end);
3551 end=0; 3579 end=0;
3580 part=(S32)LLTextParser::END;
3552 } 3581 }
3553 else 3582 else
3554 { 3583 {
3555 break; 3584 break;
3556 } 3585 }
3557 } 3586 }
3558 if (end < (S32)text.length()) appendText(text,allow_undo, prepend_newline, stylep); 3587 if (part != (S32)LLTextParser::WHOLE) part=(S32)LLTextParser::END;
3588 if (end < (S32)text.length()) appendHighlightedText(text,allow_undo, prepend_newline, part, stylep);
3559 } 3589 }
3560 else 3590 else
3561 { 3591 {
3562 appendText(new_text, allow_undo, prepend_newline, stylep); 3592 appendHighlightedText(new_text, allow_undo, prepend_newline, part, stylep);
3563 } 3593 }
3564} 3594}
3565 3595
3596void LLTextEditor::appendHighlightedText(const std::string &new_text,
3597 bool allow_undo,
3598 bool prepend_newline,
3599 S32 highlight_part,
3600 LLStyleSP stylep)
3601{
3602 if (mParseHighlights)
3603 {
3604 LLTextParser* highlight = LLTextParser::getInstance();
3605
3606 if (highlight && stylep)
3607 {
3608 LLSD pieces = highlight->parsePartialLineHighlights(new_text, stylep->getColor(), highlight_part);
3609 bool lprepend=prepend_newline;
3610 for (S32 i=0;i<pieces.size();i++)
3611 {
3612 LLSD color_llsd = pieces[i]["color"];
3613 LLColor4 lcolor;
3614 lcolor.setValue(color_llsd);
3615 LLStyleSP lstylep(new LLStyle(*stylep));
3616 lstylep->setColor(lcolor);
3617 if (i != 0 && (pieces.size() > 1) ) lprepend=FALSE;
3618 appendText((std::string)pieces[i]["text"], allow_undo, lprepend, lstylep);
3619 }
3620 return;
3621 }
3622 }
3623 appendText(new_text, allow_undo, prepend_newline, stylep);
3624}
3625
3566// Appends new text to end of document 3626// Appends new text to end of document
3567void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool prepend_newline, 3627void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool prepend_newline,
3568 const LLStyleSP *stylep) 3628 const LLStyleSP stylep)
3569{ 3629{
3570 // Save old state 3630 // Save old state
3571 BOOL was_scrolled_to_bottom = (mScrollbar->getDocPos() == mScrollbar->getDocPosMax()); 3631 BOOL was_scrolled_to_bottom = (mScrollbar->getDocPos() == mScrollbar->getDocPosMax());
@@ -3597,7 +3657,7 @@ void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool
3597 { 3657 {
3598 S32 segment_start = old_length; 3658 S32 segment_start = old_length;
3599 S32 segment_end = getLength(); 3659 S32 segment_end = getLength();
3600 LLTextSegment* segment = new LLTextSegment(*stylep, segment_start, segment_end ); 3660 LLTextSegment* segment = new LLTextSegment(stylep, segment_start, segment_end );
3601 mSegments.push_back(segment); 3661 mSegments.push_back(segment);
3602 } 3662 }
3603 3663
@@ -4270,7 +4330,6 @@ S32 LLTextEditor::findHTMLToken(const std::string &line, S32 pos, BOOL reverse)
4270 } 4330 }
4271 else 4331 else
4272 { 4332 {
4273
4274 for (int index=pos; index<(S32)line.length(); index++) 4333 for (int index=pos; index<(S32)line.length(); index++)
4275 { 4334 {
4276 char c = line[index]; 4335 char c = line[index];
diff --git a/linden/indra/llui/lltexteditor.h b/linden/indra/llui/lltexteditor.h
index 61341e2..56825e7 100644
--- a/linden/indra/llui/lltexteditor.h
+++ b/linden/indra/llui/lltexteditor.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -75,6 +76,7 @@ public:
75 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory); 76 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
76 void setTextEditorParameters(LLXMLNodePtr node); 77 void setTextEditorParameters(LLXMLNodePtr node);
77 void setParseHTML(BOOL parsing) {mParseHTML=parsing;} 78 void setParseHTML(BOOL parsing) {mParseHTML=parsing;}
79 void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;}
78 80
79 // mousehandler overrides 81 // mousehandler overrides
80 virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); 82 virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
@@ -139,7 +141,7 @@ public:
139 void insertText(const std::string &text); 141 void insertText(const std::string &text);
140 // appends text at end 142 // appends text at end
141 void appendText(const std::string &wtext, bool allow_undo, bool prepend_newline, 143 void appendText(const std::string &wtext, bool allow_undo, bool prepend_newline,
142 const LLStyleSP *stylep = NULL); 144 const LLStyleSP stylep = NULL);
143 145
144 void appendColoredText(const std::string &wtext, bool allow_undo, 146 void appendColoredText(const std::string &wtext, bool allow_undo,
145 bool prepend_newline, 147 bool prepend_newline,
@@ -148,8 +150,11 @@ public:
148 // if styled text starts a line, you need to prepend a newline. 150 // if styled text starts a line, you need to prepend a newline.
149 void appendStyledText(const std::string &new_text, bool allow_undo, 151 void appendStyledText(const std::string &new_text, bool allow_undo,
150 bool prepend_newline, 152 bool prepend_newline,
151 const LLStyleSP *stylep = NULL); 153 LLStyleSP stylep = NULL);
152 154 void appendHighlightedText(const std::string &new_text, bool allow_undo,
155 bool prepend_newline, S32 highlight_part,
156 LLStyleSP stylep);
157
153 // Removes text from the end of document 158 // Removes text from the end of document
154 // Does not change highlight or cursor position. 159 // Does not change highlight or cursor position.
155 void removeTextFromEnd(S32 num_chars); 160 void removeTextFromEnd(S32 num_chars);
@@ -312,8 +317,8 @@ protected:
312 virtual BOOL handleMouseUpOverSegment(S32 x, S32 y, MASK mask); 317 virtual BOOL handleMouseUpOverSegment(S32 x, S32 y, MASK mask);
313 318
314 virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } 319 virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; }
315 virtual void bindEmbeddedChars(LLFontGL* font) const {} 320 virtual void bindEmbeddedChars(const LLFontGL* font) const {}
316 virtual void unbindEmbeddedChars(LLFontGL* font) const {} 321 virtual void unbindEmbeddedChars(const LLFontGL* font) const {}
317 322
318 S32 findHTMLToken(const std::string &line, S32 pos, BOOL reverse) const; 323 S32 findHTMLToken(const std::string &line, S32 pos, BOOL reverse) const;
319 BOOL findHTML(const std::string &line, S32 *begin, S32 *end) const; 324 BOOL findHTML(const std::string &line, S32 *begin, S32 *end) const;
@@ -401,6 +406,7 @@ protected:
401 S32 mLastSelectionY; 406 S32 mLastSelectionY;
402 407
403 BOOL mParseHTML; 408 BOOL mParseHTML;
409 BOOL mParseHighlights;
404 std::string mHTML; 410 std::string mHTML;
405 411
406 typedef std::vector<LLTextSegment *> segment_list_t; 412 typedef std::vector<LLTextSegment *> segment_list_t;
diff --git a/linden/indra/llui/lltextparser.cpp b/linden/indra/llui/lltextparser.cpp
new file mode 100644
index 0000000..925b118
--- /dev/null
+++ b/linden/indra/llui/lltextparser.cpp
@@ -0,0 +1,299 @@
1/**
2 * @file lltexteditor.cpp
3 * @brief LLTextEditor base class
4 *
5 * $LicenseInfo:firstyear=2001&license=viewergpl$
6 *
7 * Copyright (c) 2001-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * 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
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "linden_common.h"
34
35#include "llsd.h"
36#include "llsdserialize.h"
37#include "llerror.h"
38#include "lluuid.h"
39#include "llstring.h"
40#include "message.h"
41#include "llmath.h"
42#include "v4color.h"
43#include "audioengine.h"
44#include "llwindow.h"
45#include "lldir.h"
46
47#include "lltextparser.h"
48//#include "lltexttospeech.h"
49
50// Routines used for parsing text for TextParsers and html
51
52LLTextParser* LLTextParser::sInstance = NULL;
53
54//
55// Constants
56//
57const F32 SOUND_GAIN = 1.0f;
58
59//
60// Member Functions
61//
62
63LLTextParser::~LLTextParser()
64{
65 sInstance=NULL;
66}
67
68// static
69LLTextParser* LLTextParser::getInstance()
70{
71 if (!sInstance)
72 {
73 sInstance = new LLTextParser();
74 sInstance->loadFromDisk();
75 }
76 return sInstance;
77}
78
79void LLTextParser::triggerAlerts(LLUUID agent_id, LLVector3d position, std::string text, LLWindow* viewer_window)
80{
81// bool spoken=FALSE;
82 for (S32 i=0;i<mHighlights.size();i++)
83 {
84 if (findPattern(text,mHighlights[i]) >= 0 )
85 {
86 if(gAudiop)
87 {
88 if ((std::string)mHighlights[i]["sound_lluuid"] != LLUUID::null.asString())
89 {
90 gAudiop->triggerSound(mHighlights[i]["sound_lluuid"].asUUID(), agent_id, SOUND_GAIN, LLAudioEngine::AUDIO_TYPE_UI, position);
91 }
92/*
93 if (!spoken)
94 {
95 LLTextToSpeech* text_to_speech = NULL;
96 text_to_speech = LLTextToSpeech::getInstance();
97 spoken = text_to_speech->speak((LLString)mHighlights[i]["voice"],text);
98 }
99 */
100 }
101 if (mHighlights[i]["flash"])
102 {
103 if (viewer_window && viewer_window->getMinimized())
104 {
105 viewer_window->flashIcon(5.f);
106 }
107 }
108 }
109 }
110}
111
112S32 LLTextParser::findPattern(const std::string &text, LLSD highlight)
113{
114 if (!highlight.has("pattern")) return -1;
115
116 std::string pattern=std::string(highlight["pattern"]);
117 std::string ltext=text;
118
119 if (!(bool)highlight["case_sensitive"])
120 {
121 ltext = utf8str_tolower(text);
122 pattern= utf8str_tolower(pattern);
123 }
124
125 size_t found=std::string::npos;
126
127 switch ((S32)highlight["condition"])
128 {
129 case CONTAINS:
130 found = ltext.find(pattern);
131 break;
132 case MATCHES:
133 found = (! ltext.compare(pattern) ? 0 : std::string::npos);
134 break;
135 case STARTS_WITH:
136 found = (! ltext.find(pattern) ? 0 : std::string::npos);
137 break;
138 case ENDS_WITH:
139 S32 pos = ltext.rfind(pattern);
140 if (pos >= 0 && (ltext.length()-pattern.length()==pos)) found = pos;
141 break;
142 }
143 return found;
144}
145
146LLSD LLTextParser::parsePartialLineHighlights(const std::string &text, const LLColor4 &color, S32 part, S32 index)
147{
148 //evil recursive string atomizer.
149 LLSD ret_llsd, start_llsd, middle_llsd, end_llsd;
150
151 for (S32 i=index;i<mHighlights.size();i++)
152 {
153 S32 condition = mHighlights[i]["condition"];
154 if ((S32)mHighlights[i]["highlight"]==PART && condition!=MATCHES)
155 {
156 if ( (condition==STARTS_WITH && part==START) ||
157 (condition==ENDS_WITH && part==END) ||
158 condition==CONTAINS || part==WHOLE )
159 {
160 S32 start = findPattern(text,mHighlights[i]);
161 if (start >= 0 )
162 {
163 S32 end = std::string(mHighlights[i]["pattern"]).length();
164 S32 len = text.length();
165 S32 newpart;
166 if (start==0)
167 {
168 start_llsd[0]["text"] =text.substr(0,end);
169 start_llsd[0]["color"]=mHighlights[i]["color"];
170
171 if (end < len)
172 {
173 if (part==END || part==WHOLE) newpart=END; else newpart=MIDDLE;
174 end_llsd=parsePartialLineHighlights(text.substr( end ),color,newpart,i);
175 }
176 }
177 else
178 {
179 if (part==START || part==WHOLE) newpart=START; else newpart=MIDDLE;
180
181 start_llsd=parsePartialLineHighlights(text.substr(0,start),color,newpart,i+1);
182
183 if (end < len)
184 {
185 middle_llsd[0]["text"] =text.substr(start,end);
186 middle_llsd[0]["color"]=mHighlights[i]["color"];
187
188 if (part==END || part==WHOLE) newpart=END; else newpart=MIDDLE;
189
190 end_llsd=parsePartialLineHighlights(text.substr( (start+end) ),color,newpart,i);
191 }
192 else
193 {
194 end_llsd[0]["text"] =text.substr(start,end);
195 end_llsd[0]["color"]=mHighlights[i]["color"];
196 }
197 }
198
199 S32 retcount=0;
200
201 //FIXME These loops should be wrapped into a subroutine.
202 for (LLSD::array_iterator iter = start_llsd.beginArray();
203 iter != start_llsd.endArray();++iter)
204 {
205 LLSD highlight = *iter;
206 ret_llsd[retcount++]=highlight;
207 }
208
209 for (LLSD::array_iterator iter = middle_llsd.beginArray();
210 iter != middle_llsd.endArray();++iter)
211 {
212 LLSD highlight = *iter;
213 ret_llsd[retcount++]=highlight;
214 }
215
216 for (LLSD::array_iterator iter = end_llsd.beginArray();
217 iter != end_llsd.endArray();++iter)
218 {
219 LLSD highlight = *iter;
220 ret_llsd[retcount++]=highlight;
221 }
222
223 return ret_llsd;
224 }
225 }
226 }
227 }
228
229 //No patterns found. Just send back what was passed in.
230 ret_llsd[0]["text"] =text;
231 LLSD color_sd = color.getValue();
232 ret_llsd[0]["color"]=color_sd;
233 return ret_llsd;
234}
235
236bool LLTextParser::parseFullLineHighlights(const std::string &text, LLColor4 *color)
237{
238 for (S32 i=0;i<mHighlights.size();i++)
239 {
240 if ((S32)mHighlights[i]["highlight"]==ALL || (S32)mHighlights[i]["condition"]==MATCHES)
241 {
242 if (findPattern(text,mHighlights[i]) >= 0 )
243 {
244 LLSD color_llsd = mHighlights[i]["color"];
245 color->setValue(color_llsd);
246 return TRUE;
247 }
248 }
249 }
250 return FALSE; //No matches found.
251}
252
253std::string LLTextParser::getFileName()
254{
255 std::string path=gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "");
256
257 if (!path.empty())
258 {
259 path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "highlights.xml");
260 }
261 return path;
262}
263
264LLSD LLTextParser::loadFromDisk()
265{
266 std::string filename=getFileName();
267 if (filename.empty())
268 {
269 llwarns << "LLTextParser::loadFromDisk() no valid user directory." << llendl;
270 }
271 else
272 {
273 llifstream file;
274 file.open(filename.c_str());
275 if (file.is_open())
276 {
277 LLSDSerialize::fromXML(mHighlights, file);
278 }
279 file.close();
280 }
281
282 return mHighlights;
283}
284
285bool LLTextParser::saveToDisk(LLSD highlights)
286{
287 mHighlights=highlights;
288 std::string filename=getFileName();
289 if (filename.empty())
290 {
291 llwarns << "LLTextParser::saveToDisk() no valid user directory." << llendl;
292 return FALSE;
293 }
294 llofstream file;
295 file.open(filename.c_str());
296 LLSDSerialize::toPrettyXML(mHighlights, file);
297 file.close();
298 return TRUE;
299}
diff --git a/linden/indra/llui/lltextparser.h b/linden/indra/llui/lltextparser.h
new file mode 100644
index 0000000..d69e3a2
--- /dev/null
+++ b/linden/indra/llui/lltextparser.h
@@ -0,0 +1,73 @@
1/**
2 * @file llTextParser.h
3 * @brief GUI for user-defined highlights
4 *
5 * $LicenseInfo:firstyear=2002&license=viewergpl$
6 *
7 * Copyright (c) 2002-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * 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
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 *
32 */
33
34#ifndef LL_LLTEXTPARSER_H
35#define LL_LLTEXTPARSER_H
36
37#include <vector>
38#include "linden_common.h"
39
40#include "lltextparser.h"
41
42class LLSD;
43class LLUUID;
44class LLVector3d;
45class LLColor4;
46
47class LLTextParser
48{
49public:
50 enum ConditionType { CONTAINS, MATCHES, STARTS_WITH, ENDS_WITH };
51 enum HighlightType { PART, ALL };
52 enum HighlightPosition { WHOLE, START, MIDDLE, END };
53 enum DialogAction { ACTION_NONE, ACTION_CLOSE, ACTION_ADD, ACTION_COPY, ACTION_UPDATE };
54
55 static LLTextParser* getInstance();
56 LLTextParser(){};
57 ~LLTextParser();
58
59 S32 findPattern(const std::string &text, LLSD highlight);
60 LLSD parsePartialLineHighlights(const std::string &text,const LLColor4 &color,S32 part=WHOLE, S32 index=0);
61 bool parseFullLineHighlights(const std::string &text, LLColor4 *color);
62 void triggerAlerts(LLUUID agent_id, LLVector3d position, std::string text, LLWindow* viewer_window);
63
64 std::string getFileName();
65 LLSD loadFromDisk();
66 bool saveToDisk(LLSD highlights);
67public:
68 LLSD mHighlights;
69private:
70 static LLTextParser* sInstance;
71};
72
73#endif
diff --git a/linden/indra/llui/llui.cpp b/linden/indra/llui/llui.cpp
index f3e73fd..57ce13c 100644
--- a/linden/indra/llui/llui.cpp
+++ b/linden/indra/llui/llui.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -30,6 +31,7 @@
30 */ 31 */
31 32
32// Utilities functions the user interface needs 33// Utilities functions the user interface needs
34
33#include "linden_common.h" 35#include "linden_common.h"
34 36
35#include <string> 37#include <string>
@@ -65,6 +67,7 @@ std::map<std::string, std::string> gTranslation;
65std::list<std::string> gUntranslated; 67std::list<std::string> gUntranslated;
66 68
67LLControlGroup* LLUI::sConfigGroup = NULL; 69LLControlGroup* LLUI::sConfigGroup = NULL;
70LLControlGroup* LLUI::sIgnoresGroup = NULL;
68LLControlGroup* LLUI::sColorsGroup = NULL; 71LLControlGroup* LLUI::sColorsGroup = NULL;
69LLImageProviderInterface* LLUI::sImageProvider = NULL; 72LLImageProviderInterface* LLUI::sImageProvider = NULL;
70LLUIAudioCallback LLUI::sAudioCallback = NULL; 73LLUIAudioCallback LLUI::sAudioCallback = NULL;
@@ -90,7 +93,7 @@ void make_ui_sound(const char* namep)
90 LLUUID uuid(LLUI::sConfigGroup->getString(name)); 93 LLUUID uuid(LLUI::sConfigGroup->getString(name));
91 if (uuid.isNull()) 94 if (uuid.isNull())
92 { 95 {
93 if ("00000000-0000-0000-0000-000000000000" == LLUI::sConfigGroup->getString(name)) 96 if (LLUI::sConfigGroup->getString(name) == LLUUID::null.asString())
94 { 97 {
95 if (LLUI::sConfigGroup->getBOOL("UISndDebugSpamToggle")) 98 if (LLUI::sConfigGroup->getBOOL("UISndDebugSpamToggle"))
96 { 99 {
@@ -1552,6 +1555,7 @@ bool handleShowXUINamesChanged(const LLSD& newvalue)
1552} 1555}
1553 1556
1554void LLUI::initClass(LLControlGroup* config, 1557void LLUI::initClass(LLControlGroup* config,
1558 LLControlGroup* ignores,
1555 LLControlGroup* colors, 1559 LLControlGroup* colors,
1556 LLImageProviderInterface* image_provider, 1560 LLImageProviderInterface* image_provider,
1557 LLUIAudioCallback audio_callback, 1561 LLUIAudioCallback audio_callback,
@@ -1559,7 +1563,16 @@ void LLUI::initClass(LLControlGroup* config,
1559 const std::string& language) 1563 const std::string& language)
1560{ 1564{
1561 sConfigGroup = config; 1565 sConfigGroup = config;
1566 sIgnoresGroup = ignores;
1562 sColorsGroup = colors; 1567 sColorsGroup = colors;
1568
1569 if (sConfigGroup == NULL
1570 || sIgnoresGroup == NULL
1571 || sColorsGroup == NULL)
1572 {
1573 llerrs << "Failure to initialize configuration groups" << llendl;
1574 }
1575
1563 sImageProvider = image_provider; 1576 sImageProvider = image_provider;
1564 sAudioCallback = audio_callback; 1577 sAudioCallback = audio_callback;
1565 sGLScaleFactor = (scale_factor == NULL) ? LLVector2(1.f, 1.f) : *scale_factor; 1578 sGLScaleFactor = (scale_factor == NULL) ? LLVector2(1.f, 1.f) : *scale_factor;
@@ -1567,7 +1580,7 @@ void LLUI::initClass(LLControlGroup* config,
1567 LLFontGL::sShadowColor = colors->getColor("ColorDropShadow"); 1580 LLFontGL::sShadowColor = colors->getColor("ColorDropShadow");
1568 1581
1569 LLUI::sShowXUINames = LLUI::sConfigGroup->getBOOL("ShowXUINames"); 1582 LLUI::sShowXUINames = LLUI::sConfigGroup->getBOOL("ShowXUINames");
1570 LLUI::sConfigGroup->getControl("ShowXUINames")->getSignal()->connect(boost::bind(&handleShowXUINamesChanged, _1)); 1583 LLUI::sConfigGroup->getControl("ShowXUINames")->getSignal()->connect(&handleShowXUINamesChanged);
1571} 1584}
1572 1585
1573void LLUI::cleanupClass() 1586void LLUI::cleanupClass()
@@ -1645,6 +1658,18 @@ void LLUI::setCursorPositionLocal(const LLView* viewp, S32 x, S32 y)
1645 setCursorPositionScreen(screen_x, screen_y); 1658 setCursorPositionScreen(screen_x, screen_y);
1646} 1659}
1647 1660
1661//static
1662void LLUI::getCursorPositionLocal(const LLView* viewp, S32 *x, S32 *y)
1663{
1664 LLCoordWindow cursor_pos_window;
1665 LLView::getWindow()->getCursorPosition(&cursor_pos_window);
1666 LLCoordGL cursor_pos_gl;
1667 LLView::getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl);
1668 cursor_pos_gl.mX = llround((F32)cursor_pos_gl.mX / LLUI::sGLScaleFactor.mV[VX]);
1669 cursor_pos_gl.mY = llround((F32)cursor_pos_gl.mY / LLUI::sGLScaleFactor.mV[VY]);
1670 viewp->screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, x, y);
1671}
1672
1648// On Windows, the user typically sets the language when they install the 1673// On Windows, the user typically sets the language when they install the
1649// app (by running it with a shortcut that sets InstallLanguage). On Mac, 1674// app (by running it with a shortcut that sets InstallLanguage). On Mac,
1650// or on Windows if the SecondLife.exe executable is run directly, the 1675// or on Windows if the SecondLife.exe executable is run directly, the
diff --git a/linden/indra/llui/llui.h b/linden/indra/llui/llui.h
index 1e731f1..ebcc730 100644
--- a/linden/indra/llui/llui.h
+++ b/linden/indra/llui/llui.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -42,6 +43,7 @@
42#include "llgl.h" // *TODO: break this dependency 43#include "llgl.h" // *TODO: break this dependency
43#include <stack> 44#include <stack>
44//#include "llimagegl.h" 45//#include "llimagegl.h"
46#include <boost/signal.hpp>
45 47
46// LLUIFactory 48// LLUIFactory
47#include "llsd.h" 49#include "llsd.h"
@@ -150,11 +152,13 @@ typedef void (*LLUIAudioCallback)(const LLUUID& uuid);
150 152
151class LLUI 153class LLUI
152{ 154{
155 LOG_CLASS(LLUI);
153public: 156public:
154 // 157 //
155 // Methods 158 // Methods
156 // 159 //
157 static void initClass(LLControlGroup* config, 160 static void initClass(LLControlGroup* config,
161 LLControlGroup* ignores,
158 LLControlGroup* colors, 162 LLControlGroup* colors,
159 LLImageProviderInterface* image_provider, 163 LLImageProviderInterface* image_provider,
160 LLUIAudioCallback audio_callback = NULL, 164 LLUIAudioCallback audio_callback = NULL,
@@ -175,6 +179,7 @@ public:
175 static std::string locateSkin(const std::string& filename); 179 static std::string locateSkin(const std::string& filename);
176 static void setCursorPositionScreen(S32 x, S32 y); 180 static void setCursorPositionScreen(S32 x, S32 y);
177 static void setCursorPositionLocal(const LLView* viewp, S32 x, S32 y); 181 static void setCursorPositionLocal(const LLView* viewp, S32 x, S32 y);
182 static void getCursorPositionLocal(const LLView* viewp, S32 *x, S32 *y);
178 static void setScaleFactor(const LLVector2& scale_factor); 183 static void setScaleFactor(const LLVector2& scale_factor);
179 static void setLineWidth(F32 width); 184 static void setLineWidth(F32 width);
180 static LLUIImage* getUIImage(const std::string& name); 185 static LLUIImage* getUIImage(const std::string& name);
@@ -189,6 +194,7 @@ public:
189 // Data 194 // Data
190 // 195 //
191 static LLControlGroup* sConfigGroup; 196 static LLControlGroup* sConfigGroup;
197 static LLControlGroup* sIgnoresGroup;
192 static LLControlGroup* sColorsGroup; 198 static LLControlGroup* sColorsGroup;
193 static LLImageProviderInterface* sImageProvider; 199 static LLImageProviderInterface* sImageProvider;
194 static LLUIAudioCallback sAudioCallback; 200 static LLUIAudioCallback sAudioCallback;
@@ -596,4 +602,237 @@ public:
596 virtual void cleanUp() = 0; 602 virtual void cleanUp() = 0;
597}; 603};
598 604
605// This mix-in class adds support for tracking all instances of the specificed class parameter T
606// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
607// If KEY is not provided, then instances are stored in a simple list
608template<typename T, typename KEY = T*>
609class LLInstanceTracker : boost::noncopyable
610{
611public:
612 typedef typename std::map<KEY, T*>::iterator instance_iter;
613 typedef typename std::map<KEY, T*>::const_iterator instance_const_iter;
614
615 static T* getInstance(KEY k) { instance_iter found = sInstances.find(k); return (found == sInstances.end()) ? NULL : found->second; }
616
617 static instance_iter beginInstances() { return sInstances.begin(); }
618 static instance_iter endInstances() { return sInstances.end(); }
619 static S32 instanceCount() { return sInstances.size(); }
620protected:
621 LLInstanceTracker(KEY key) { add(key); }
622 virtual ~LLInstanceTracker() { remove(); }
623 virtual void setKey(KEY key) { remove(); add(key); }
624 virtual const KEY& getKey() const { return mKey; }
625
626private:
627 void add(KEY key)
628 {
629 mKey = key;
630 sInstances[key] = static_cast<T*>(this);
631 }
632 void remove() { sInstances.erase(mKey); }
633
634private:
635
636 KEY mKey;
637 static std::map<KEY, T*> sInstances;
638};
639
640template<typename T>
641class LLInstanceTracker<T, T*> : boost::noncopyable
642{
643public:
644 typedef typename std::set<T*>::iterator instance_iter;
645 typedef typename std::set<T*>::const_iterator instance_const_iter;
646
647 static instance_iter instancesBegin() { return sInstances.begin(); }
648 static instance_iter instancesEnd() { return sInstances.end(); }
649 static S32 instanceCount() { return sInstances.size(); }
650
651protected:
652 LLInstanceTracker() { sInstances.insert(static_cast<T*>(this)); }
653 virtual ~LLInstanceTracker() { sInstances.erase(static_cast<T*>(this)); }
654
655 static std::set<T*> sInstances;
656};
657
658template <typename T, typename KEY> std::map<KEY, T*> LLInstanceTracker<T, KEY>::sInstances;
659template <typename T> std::set<T*> LLInstanceTracker<T, T*>::sInstances;
660
661class LLCallbackRegistry
662{
663public:
664 typedef boost::signal<void()> callback_signal_t;
665
666 void registerCallback(const callback_signal_t::slot_type& slot)
667 {
668 mCallbacks.connect(slot);
669 }
670
671 void fireCallbacks()
672 {
673 mCallbacks();
674 }
675
676private:
677 callback_signal_t mCallbacks;
678};
679
680class LLInitClassList :
681 public LLCallbackRegistry,
682 public LLSingleton<LLInitClassList>
683{
684 friend class LLSingleton<LLInitClassList>;
685private:
686 LLInitClassList() {}
687};
688
689class LLDestroyClassList :
690 public LLCallbackRegistry,
691 public LLSingleton<LLDestroyClassList>
692{
693 friend class LLSingleton<LLDestroyClassList>;
694private:
695 LLDestroyClassList() {}
696};
697
698template<typename T>
699class LLRegisterWith
700{
701public:
702 LLRegisterWith(boost::function<void ()> func)
703 {
704 T::instance().registerCallback(func);
705 }
706
707 // this avoids a MSVC bug where non-referenced static members are "optimized" away
708 // even if their constructors have side effects
709 void reference()
710 {
711 S32 dummy;
712 dummy = 0;
713 }
714};
715
716template<typename T>
717class LLInitClass
718{
719public:
720 LLInitClass() { sRegister.reference(); }
721
722 static LLRegisterWith<LLInitClassList> sRegister;
723private:
724
725 static void initClass()
726 {
727 llerrs << "No static initClass() method defined for " << typeid(T).name() << llendl;
728 }
729};
730
731template<typename T>
732class LLDestroyClass
733{
734public:
735 LLDestroyClass() { sRegister.reference(); }
736
737 static LLRegisterWith<LLDestroyClassList> sRegister;
738private:
739
740 static void destroyClass()
741 {
742 llerrs << "No static destroyClass() method defined for " << typeid(T).name() << llendl;
743 }
744};
745
746template <typename T> LLRegisterWith<LLInitClassList> LLInitClass<T>::sRegister(&T::initClass);
747template <typename T> LLRegisterWith<LLDestroyClassList> LLDestroyClass<T>::sRegister(&T::destroyClass);
748
749
750template <typename DERIVED>
751class LLParamBlock
752{
753protected:
754 LLParamBlock() { sBlock = (DERIVED*)this; }
755
756 typedef typename boost::add_const<DERIVED>::type Tconst;
757
758 template <typename T>
759 class LLMandatoryParam
760 {
761 public:
762 typedef typename boost::add_const<T>::type T_const;
763
764 LLMandatoryParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {}
765 LLMandatoryParam(const LLMandatoryParam<T>& other) : mVal(other.mVal) {}
766
767 DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; }
768 operator T() const { return mVal; }
769 T operator=(T_const set_value) { mVal = set_value; return mVal; }
770
771 private:
772 T mVal;
773 DERIVED* mBlock;
774 };
775
776 template <typename T>
777 class LLOptionalParam
778 {
779 public:
780 typedef typename boost::add_const<T>::type T_const;
781
782 LLOptionalParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {}
783 LLOptionalParam() : mBlock(sBlock) {}
784 LLOptionalParam(const LLOptionalParam<T>& other) : mVal(other.mVal) {}
785
786 DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; }
787 operator T() const { return mVal; }
788 T operator=(T_const set_value) { mVal = set_value; return mVal; }
789
790 private:
791 T mVal;
792 DERIVED* mBlock;
793 };
794
795 // specialization that requires initialization for reference types
796 template <typename T>
797 class LLOptionalParam <T&>
798 {
799 public:
800 typedef typename boost::add_const<T&>::type T_const;
801
802 LLOptionalParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {}
803 LLOptionalParam(const LLOptionalParam<T&>& other) : mVal(other.mVal) {}
804
805 DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; }
806 operator T&() const { return mVal; }
807 T& operator=(T_const set_value) { mVal = set_value; return mVal; }
808
809 private:
810 T& mVal;
811 DERIVED* mBlock;
812 };
813
814 // specialization that initializes pointer params to NULL
815 template<typename T>
816 class LLOptionalParam<T*>
817 {
818 public:
819 typedef typename boost::add_const<T*>::type T_const;
820
821 LLOptionalParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {}
822 LLOptionalParam() : mVal((T*)NULL), mBlock(sBlock) {}
823 LLOptionalParam(const LLOptionalParam<T*>& other) : mVal(other.mVal) {}
824
825 DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; }
826 operator T*() const { return mVal; }
827 T* operator=(T_const set_value) { mVal = set_value; return mVal; }
828 private:
829 T* mVal;
830 DERIVED* mBlock;
831 };
832
833 static DERIVED* sBlock;
834};
835
836template <typename T> T* LLParamBlock<T>::sBlock = NULL;
837
599#endif 838#endif
diff --git a/linden/indra/llui/lluiconstants.h b/linden/indra/llui/lluiconstants.h
index 14e7a81..f04062a 100644
--- a/linden/indra/llui/lluiconstants.h
+++ b/linden/indra/llui/lluiconstants.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lluictrl.cpp b/linden/indra/llui/lluictrl.cpp
index b2c14df..9d97312 100644
--- a/linden/indra/llui/lluictrl.cpp
+++ b/linden/indra/llui/lluictrl.cpp
@@ -18,7 +18,8 @@
18 * There are special exceptions to the terms and conditions of the GPL as 18 * There are special exceptions to the terms and conditions of the GPL as
19 * it is applied to this Source Code. View the full text of the exception 19 * it is applied to this Source Code. View the full text of the exception
20 * in the file doc/FLOSS-exception.txt in this software distribution, or 20 * in the file doc/FLOSS-exception.txt in this software distribution, or
21 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 21 * online at
22 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 * 23 *
23 * By copying, modifying or distributing this software, you acknowledge 24 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above, 25 * that you have read and understood your obligations described above,
@@ -475,10 +476,10 @@ BOOL LLUICtrl::focusPrevItem(BOOL text_fields_only)
475 return focusPrev(result); 476 return focusPrev(result);
476} 477}
477 478
478LLUICtrl* LLUICtrl::findRootMostFocusRoot() const 479LLUICtrl* LLUICtrl::findRootMostFocusRoot()
479{ 480{
480 const LLUICtrl* focus_root = NULL; 481 LLUICtrl* focus_root = NULL;
481 const LLUICtrl* next_view = this; 482 LLUICtrl* next_view = this;
482 while(next_view) 483 while(next_view)
483 { 484 {
484 if (next_view->isFocusRoot()) 485 if (next_view->isFocusRoot())
@@ -487,9 +488,8 @@ LLUICtrl* LLUICtrl::findRootMostFocusRoot() const
487 } 488 }
488 next_view = next_view->getParentUICtrl(); 489 next_view = next_view->getParentUICtrl();
489 } 490 }
490 // since focus_root could be this, need to cast away const to return 491
491 // a non-const result 492 return focus_root;
492 return const_cast<LLUICtrl*>(focus_root);
493} 493}
494 494
495 495
@@ -551,19 +551,6 @@ LLView* LLUICtrl::fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFacto
551} 551}
552 552
553 553
554// *NOTE: If other classes derive from LLPanel, they will need to be
555// added to this function.
556LLPanel* LLUICtrl::getParentPanel() const
557{
558 LLView* parent = getParent();
559 LLPanel* parent_panel = dynamic_cast<LLPanel*>(parent);
560 while (!parent_panel)
561 {
562 parent = parent->getParent();
563 }
564 return (LLPanel*)(parent);
565}
566
567// Skip over any parents that are not LLUICtrl's 554// Skip over any parents that are not LLUICtrl's
568// Used in focus logic since only LLUICtrl elements can have focus 555// Used in focus logic since only LLUICtrl elements can have focus
569LLUICtrl* LLUICtrl::getParentUICtrl() const 556LLUICtrl* LLUICtrl::getParentUICtrl() const
diff --git a/linden/indra/llui/lluictrl.h b/linden/indra/llui/lluictrl.h
index f11ece7..db41af8 100644
--- a/linden/indra/llui/lluictrl.h
+++ b/linden/indra/llui/lluictrl.h
@@ -18,7 +18,8 @@
18 * There are special exceptions to the terms and conditions of the GPL as 18 * There are special exceptions to the terms and conditions of the GPL as
19 * it is applied to this Source Code. View the full text of the exception 19 * it is applied to this Source Code. View the full text of the exception
20 * in the file doc/FLOSS-exception.txt in this software distribution, or 20 * in the file doc/FLOSS-exception.txt in this software distribution, or
21 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 21 * online at
22 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 * 23 *
23 * By copying, modifying or distributing this software, you acknowledge 24 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above, 25 * that you have read and understood your obligations described above,
@@ -130,9 +131,7 @@ public:
130 void setTabStop( BOOL b ); 131 void setTabStop( BOOL b );
131 BOOL hasTabStop() const; 132 BOOL hasTabStop() const;
132 133
133 // Returns containing panel/floater or NULL if none found. 134 LLUICtrl* getParentUICtrl() const;
134 class LLPanel* getParentPanel() const;
135 class LLUICtrl* getParentUICtrl() const;
136 135
137 void* getCallbackUserData() const { return mCallbackUserData; } 136 void* getCallbackUserData() const { return mCallbackUserData; }
138 void setCallbackUserData( void* data ) { mCallbackUserData = data; } 137 void setCallbackUserData( void* data ) { mCallbackUserData = data; }
@@ -143,7 +142,7 @@ public:
143 142
144 static LLView* fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory); 143 static LLView* fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory);
145 144
146 LLUICtrl* findRootMostFocusRoot() const; 145 LLUICtrl* findRootMostFocusRoot();
147 146
148 class LLTextInputFilter : public LLQueryFilter, public LLSingleton<LLTextInputFilter> 147 class LLTextInputFilter : public LLQueryFilter, public LLSingleton<LLTextInputFilter>
149 { 148 {
diff --git a/linden/indra/llui/lluictrlfactory.cpp b/linden/indra/llui/lluictrlfactory.cpp
index 07de717..983cc53 100644
--- a/linden/indra/llui/lluictrlfactory.cpp
+++ b/linden/indra/llui/lluictrlfactory.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -148,7 +149,11 @@ void LLUICtrlFactory::setupPaths()
148 } 149 }
149} 150}
150 151
151 152// static
153const std::vector<std::string>& LLUICtrlFactory::getXUIPaths()
154{
155 return sXUIPaths;
156}
152 157
153//----------------------------------------------------------------------------- 158//-----------------------------------------------------------------------------
154// getLayeredXMLNode() 159// getLayeredXMLNode()
diff --git a/linden/indra/llui/lluictrlfactory.h b/linden/indra/llui/lluictrlfactory.h
index b5b2853..5e7c24e 100644
--- a/linden/indra/llui/lluictrlfactory.h
+++ b/linden/indra/llui/lluictrlfactory.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -77,7 +78,10 @@ public:
77 78
78 static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root); 79 static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root);
79 80
81 static const std::vector<std::string>& getXUIPaths();
82
80private: 83private:
84 bool getLayeredXMLNodeImpl(const std::string &filename, LLXMLNodePtr& root);
81 85
82 typedef std::map<LLHandle<LLPanel>, std::string> built_panel_t; 86 typedef std::map<LLHandle<LLPanel>, std::string> built_panel_t;
83 built_panel_t mBuiltPanels; 87 built_panel_t mBuiltPanels;
diff --git a/linden/indra/llui/lluifwd.h b/linden/indra/llui/lluifwd.h
index ab8eb63..32d5c9b 100644
--- a/linden/indra/llui/lluifwd.h
+++ b/linden/indra/llui/lluifwd.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/lluistring.cpp b/linden/indra/llui/lluistring.cpp
index 974047f..0b76b8e 100644
--- a/linden/indra/llui/lluistring.cpp
+++ b/linden/indra/llui/lluistring.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -31,6 +32,7 @@
31 32
32#include "linden_common.h" 33#include "linden_common.h"
33#include "lluistring.h" 34#include "lluistring.h"
35#include "llsd.h"
34 36
35const LLStringUtil::format_map_t LLUIString::sNullArgs; 37const LLStringUtil::format_map_t LLUIString::sNullArgs;
36 38
@@ -54,6 +56,18 @@ void LLUIString::setArgList(const LLStringUtil::format_map_t& args)
54 format(); 56 format();
55} 57}
56 58
59void LLUIString::setArgs(const LLSD& sd)
60{
61 if (!sd.isMap()) return;
62 for(LLSD::map_const_iterator sd_it = sd.beginMap();
63 sd_it != sd.endMap();
64 ++sd_it)
65 {
66 setArg(sd_it->first, sd_it->second.asString());
67 }
68 format();
69}
70
57void LLUIString::setArg(const std::string& key, const std::string& replacement) 71void LLUIString::setArg(const std::string& key, const std::string& replacement)
58{ 72{
59 mArgs[key] = replacement; 73 mArgs[key] = replacement;
diff --git a/linden/indra/llui/lluistring.h b/linden/indra/llui/lluistring.h
index 5983e1d..aedeca2 100644
--- a/linden/indra/llui/lluistring.h
+++ b/linden/indra/llui/lluistring.h
@@ -18,7 +18,8 @@
18 * There are special exceptions to the terms and conditions of the GPL as 18 * There are special exceptions to the terms and conditions of the GPL as
19 * it is applied to this Source Code. View the full text of the exception 19 * it is applied to this Source Code. View the full text of the exception
20 * in the file doc/FLOSS-exception.txt in this software distribution, or 20 * in the file doc/FLOSS-exception.txt in this software distribution, or
21 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 21 * online at
22 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 * 23 *
23 * By copying, modifying or distributing this software, you acknowledge 24 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above, 25 * that you have read and understood your obligations described above,
@@ -50,9 +51,9 @@
50// llinfos << mMessage.getString() << llendl; // outputs "Welcome Steve to Second Life" 51// llinfos << mMessage.getString() << llendl; // outputs "Welcome Steve to Second Life"
51// mMessage.setArg("[USERNAME]", "Joe"); 52// mMessage.setArg("[USERNAME]", "Joe");
52// llinfos << mMessage.getString() << llendl; // outputs "Welcome Joe to Second Life" 53// llinfos << mMessage.getString() << llendl; // outputs "Welcome Joe to Second Life"
53// mMessage = "Recepción a la [SECONDLIFE] [USERNAME]" 54// mMessage = "Recepci￳n a la [SECONDLIFE] [USERNAME]"
54// mMessage.setArg("[SECONDLIFE]", "Segunda Vida"); 55// mMessage.setArg("[SECONDLIFE]", "Segunda Vida");
55// llinfos << mMessage.getString() << llendl; // outputs "Recepción a la Segunda Vida Joe" 56// llinfos << mMessage.getString() << llendl; // outputs "Recepci￳n a la Segunda Vida Joe"
56 57
57// Implementation Notes: 58// Implementation Notes:
58// Attempting to have operator[](const std::string& s) return mArgs[s] fails because we have 59// Attempting to have operator[](const std::string& s) return mArgs[s] fails because we have
@@ -71,6 +72,8 @@ public:
71 LLUIString& operator=(const std::string& s) { assign(s); return *this; } 72 LLUIString& operator=(const std::string& s) { assign(s); return *this; }
72 73
73 void setArgList(const LLStringUtil::format_map_t& args); 74 void setArgList(const LLStringUtil::format_map_t& args);
75 void setArgs(const LLStringUtil::format_map_t& args) { setArgList(args); }
76 void setArgs(const class LLSD& sd);
74 void setArg(const std::string& key, const std::string& replacement); 77 void setArg(const std::string& key, const std::string& replacement);
75 78
76 const std::string& getString() const { return mResult; } 79 const std::string& getString() const { return mResult; }
diff --git a/linden/indra/llui/lluitrans.cpp b/linden/indra/llui/lluitrans.cpp
new file mode 100644
index 0000000..920fe6a
--- /dev/null
+++ b/linden/indra/llui/lluitrans.cpp
@@ -0,0 +1,101 @@
1/**
2 * @file lluitrans.cpp
3 * @brief LLUITrans implementation
4 *
5 * $LicenseInfo:firstyear=2000&license=viewergpl$
6 *
7 * Copyright (c) 2000-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * 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
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33
34#include "linden_common.h"
35#include "lluitrans.h"
36#include "llxmlnode.h"
37#include "lluictrlfactory.h"
38#include "llalertdialog.h"
39
40#include <map>
41
42LLUITrans::template_map_t LLUITrans::sStringTemplates;
43
44//static
45bool LLUITrans::parseStrings(const std::string& xml_filename)
46{
47 LLXMLNodePtr root;
48 BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
49
50 if (!success || root.isNull() || !root->hasName( "strings" ))
51 {
52 llerrs << "Problem reading strings: " << xml_filename << llendl;
53 return false;
54 }
55
56 for (LLXMLNode* string = root->getFirstChild();
57 string != NULL; string = string->getNextSibling())
58 {
59 if (!string->hasName("string"))
60 {
61 continue;
62 }
63
64 std::string string_name;
65
66 if (! string->getAttributeString("name", string_name))
67 {
68 llwarns << "Unable to parse string with no name" << llendl;
69 continue;
70 }
71
72 LLUITransTemplate xml_template(string_name, string->getTextContents());
73 sStringTemplates[xml_template.mName] = xml_template;
74 }
75
76 return true;
77}
78
79//static
80std::string LLUITrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args)
81{
82 template_map_t::iterator iter = sStringTemplates.find(xml_desc);
83
84 if (iter != sStringTemplates.end())
85 {
86 std::string text = iter->second.mText;
87 LLStringUtil::format(text, args);
88
89 return text;
90 }
91 else
92 {
93 LLSD args;
94 args["STRING_NAME"] = xml_desc;
95 LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;
96 LLNotifications::instance().add("MissingString", args);
97
98 return xml_desc;
99 }
100}
101
diff --git a/linden/indra/llui/lluitrans.h b/linden/indra/llui/lluitrans.h
new file mode 100644
index 0000000..32fb468
--- /dev/null
+++ b/linden/indra/llui/lluitrans.h
@@ -0,0 +1,87 @@
1/**
2 * @file lluitrans.h
3 * @brief LLUITrans definition
4 *
5 * $LicenseInfo:firstyear=2000&license=viewergpl$
6 *
7 * Copyright (c) 2000-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * 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
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#ifndef LL_UI_TRANS_H
34#define LL_UI_TRANS_H
35
36#include <map>
37
38/**
39 * @brief String template loaded from strings.xml
40 */
41class LLUITransTemplate
42{
43public:
44 LLUITransTemplate(const std::string& name = LLStringUtil::null, const std::string& text = LLStringUtil::null) : mName(name), mText(text) {}
45
46 std::string mName;
47 std::string mText;
48};
49
50class LLUITrans
51{
52public:
53 LLUITrans();
54
55 /**
56 * @brief Parses the xml file that holds the strings. Used once on startup
57 * @param xml_filename Filename to parse
58 * @returns true if the file was parsed successfully, true if something went wrong
59 */
60 static bool parseStrings(const std::string& xml_filename);
61
62 /**
63 * @brief Returns a translated string
64 * @param xml_desc String's description
65 * @param args A list of substrings to replace in the string
66 * @returns Translated string
67 */
68 static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args);
69
70 /**
71 * @brief Returns a translated string
72 * @param xml_desc String's description
73 * @returns Translated string
74 */
75 static std::string getString(const std::string &xml_desc)
76 {
77 LLStringUtil::format_map_t empty;
78 return getString(xml_desc, empty);
79 }
80
81
82private:
83 typedef std::map<std::string, LLUITransTemplate > template_map_t;
84 static template_map_t sStringTemplates;
85};
86
87#endif
diff --git a/linden/indra/llui/lluixmltags.h b/linden/indra/llui/lluixmltags.h
index da31136..0456666 100644
--- a/linden/indra/llui/lluixmltags.h
+++ b/linden/indra/llui/lluixmltags.h
@@ -16,7 +16,8 @@
16 * 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
17 * 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
18 * 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
19 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 19 * online at
20 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
20 * 21 *
21 * By copying, modifying or distributing this software, you acknowledge 22 * By copying, modifying or distributing this software, you acknowledge
22 * that you have read and understood your obligations described above, 23 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llundo.cpp b/linden/indra/llui/llundo.cpp
index 05c8c11..8f57636 100644
--- a/linden/indra/llui/llundo.cpp
+++ b/linden/indra/llui/llundo.cpp
@@ -16,7 +16,8 @@
16 * 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
17 * 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
18 * 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
19 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 19 * online at
20 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
20 * 21 *
21 * By copying, modifying or distributing this software, you acknowledge 22 * By copying, modifying or distributing this software, you acknowledge
22 * that you have read and understood your obligations described above, 23 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llundo.h b/linden/indra/llui/llundo.h
index 55d164e..b2edb57 100644
--- a/linden/indra/llui/llundo.h
+++ b/linden/indra/llui/llundo.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llview.cpp b/linden/indra/llui/llview.cpp
index 9cdf481..444922a 100644
--- a/linden/indra/llui/llview.cpp
+++ b/linden/indra/llui/llview.cpp
@@ -18,7 +18,8 @@
18 * There are special exceptions to the terms and conditions of the GPL as 18 * There are special exceptions to the terms and conditions of the GPL as
19 * it is applied to this Source Code. View the full text of the exception 19 * it is applied to this Source Code. View the full text of the exception
20 * in the file doc/FLOSS-exception.txt in this software distribution, or 20 * in the file doc/FLOSS-exception.txt in this software distribution, or
21 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 21 * online at
22 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 * 23 *
23 * By copying, modifying or distributing this software, you acknowledge 24 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above, 25 * that you have read and understood your obligations described above,
@@ -85,7 +86,8 @@ LLView::LLView() :
85 mLastVisible(TRUE), 86 mLastVisible(TRUE),
86 mUseBoundingRect(FALSE), 87 mUseBoundingRect(FALSE),
87 mVisible(TRUE), 88 mVisible(TRUE),
88 mNextInsertionOrdinal(0) 89 mNextInsertionOrdinal(0),
90 mHoverCursor(UI_CURSOR_ARROW)
89{ 91{
90} 92}
91 93
@@ -102,7 +104,8 @@ LLView::LLView(const std::string& name, BOOL mouse_opaque) :
102 mLastVisible(TRUE), 104 mLastVisible(TRUE),
103 mUseBoundingRect(FALSE), 105 mUseBoundingRect(FALSE),
104 mVisible(TRUE), 106 mVisible(TRUE),
105 mNextInsertionOrdinal(0) 107 mNextInsertionOrdinal(0),
108 mHoverCursor(UI_CURSOR_ARROW)
106{ 109{
107} 110}
108 111
@@ -123,7 +126,8 @@ LLView::LLView(
123 mLastVisible(TRUE), 126 mLastVisible(TRUE),
124 mUseBoundingRect(FALSE), 127 mUseBoundingRect(FALSE),
125 mVisible(TRUE), 128 mVisible(TRUE),
126 mNextInsertionOrdinal(0) 129 mNextInsertionOrdinal(0),
130 mHoverCursor(UI_CURSOR_ARROW)
127{ 131{
128} 132}
129 133
@@ -657,7 +661,7 @@ BOOL LLView::handleHover(S32 x, S32 y, MASK mask)
657 if( !handled 661 if( !handled
658 && blockMouseEvent(x, y) ) 662 && blockMouseEvent(x, y) )
659 { 663 {
660 LLUI::sWindow->setCursor(UI_CURSOR_ARROW); 664 LLUI::sWindow->setCursor(mHoverCursor);
661 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; 665 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
662 handled = TRUE; 666 handled = TRUE;
663 } 667 }
@@ -705,9 +709,11 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_s
705 LLView* viewp = *child_it; 709 LLView* viewp = *child_it;
706 S32 local_x = x - viewp->mRect.mLeft; 710 S32 local_x = x - viewp->mRect.mLeft;
707 S32 local_y = y - viewp->mRect.mBottom; 711 S32 local_y = y - viewp->mRect.mBottom;
712 // Allow tooltips for disabled views so we can explain to the user why
713 // the view is disabled. JC
708 if( viewp->pointInView(local_x, local_y) 714 if( viewp->pointInView(local_x, local_y)
709 && viewp->getVisible() 715 && viewp->getVisible()
710 && viewp->getEnabled() 716 // && viewp->getEnabled()
711 && viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen )) 717 && viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ))
712 { 718 {
713 // child provided a tooltip, just return 719 // child provided a tooltip, just return
@@ -1257,7 +1263,7 @@ void LLView::draw()
1257 { 1263 {
1258 LLView *viewp = *child_iter; 1264 LLView *viewp = *child_iter;
1259 1265
1260 if (viewp->getVisible() && viewp != focus_view) 1266 if (viewp->getVisible() && viewp != focus_view && viewp->getRect().isValid())
1261 { 1267 {
1262 // Only draw views that are within the root view 1268 // Only draw views that are within the root view
1263 localRectToScreen(viewp->getRect(),&screenRect); 1269 localRectToScreen(viewp->getRect(),&screenRect);
@@ -1340,7 +1346,7 @@ void LLView::drawDebugRect()
1340 y = debug_rect.getHeight()/2; 1346 y = debug_rect.getHeight()/2;
1341 std::string debug_text = llformat("%s (%d x %d)", getName().c_str(), 1347 std::string debug_text = llformat("%s (%d x %d)", getName().c_str(),
1342 debug_rect.getWidth(), debug_rect.getHeight()); 1348 debug_rect.getWidth(), debug_rect.getHeight());
1343 LLFontGL::sSansSerifSmall->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color, 1349 LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
1344 LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, 1350 LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL,
1345 S32_MAX, S32_MAX, NULL, FALSE); 1351 S32_MAX, S32_MAX, NULL, FALSE);
1346 } 1352 }
@@ -1354,7 +1360,8 @@ void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_dr
1354 { 1360 {
1355 ++sDepth; 1361 ++sDepth;
1356 1362
1357 if (childp->getVisible() || force_draw) 1363 if ((childp->getVisible() && childp->getRect().isValid())
1364 || force_draw)
1358 { 1365 {
1359 glMatrixMode(GL_MODELVIEW); 1366 glMatrixMode(GL_MODELVIEW);
1360 LLUI::pushMatrix(); 1367 LLUI::pushMatrix();
@@ -2544,6 +2551,13 @@ void LLView::initFromXML(LLXMLNodePtr node, LLView* parent)
2544 node->getAttributeBOOL("visible", visible); 2551 node->getAttributeBOOL("visible", visible);
2545 setVisible(visible); 2552 setVisible(visible);
2546 } 2553 }
2554
2555 if (node->hasAttribute("hover_cursor"))
2556 {
2557 std::string cursor_string;
2558 node->getAttributeString("hover_cursor", cursor_string);
2559 mHoverCursor = getCursorFromString(cursor_string);
2560 }
2547 2561
2548 node->getAttributeBOOL("use_bounding_rect", mUseBoundingRect); 2562 node->getAttributeBOOL("use_bounding_rect", mUseBoundingRect);
2549 node->getAttributeBOOL("mouse_opaque", mMouseOpaque); 2563 node->getAttributeBOOL("mouse_opaque", mMouseOpaque);
@@ -2595,19 +2609,40 @@ void LLView::parseFollowsFlags(LLXMLNodePtr node)
2595 } 2609 }
2596} 2610}
2597 2611
2598
2599// static 2612// static
2600LLFontGL* LLView::selectFont(LLXMLNodePtr node) 2613LLFontGL* LLView::selectFont(LLXMLNodePtr node)
2601{ 2614{
2602 LLFontGL* gl_font = NULL; 2615 std::string font_name, font_size, font_style;
2603 2616 U8 style = 0;
2617
2604 if (node->hasAttribute("font")) 2618 if (node->hasAttribute("font"))
2605 { 2619 {
2606 std::string font_name;
2607 node->getAttributeString("font", font_name); 2620 node->getAttributeString("font", font_name);
2621 }
2622
2623 if (node->hasAttribute("font_size"))
2624 {
2625 node->getAttributeString("font_size", font_size);
2626 }
2608 2627
2609 gl_font = LLFontGL::fontFromName(font_name); 2628 if (node->hasAttribute("font_style"))
2629 {
2630 node->getAttributeString("font_style", font_style);
2631 style = LLFontGL::getStyleFromString(font_style);
2632 }
2633
2634 if (node->hasAttribute("font-style"))
2635 {
2636 node->getAttributeString("font-style", font_style);
2637 style = LLFontGL::getStyleFromString(font_style);
2610 } 2638 }
2639
2640 if (font_name.empty())
2641 return NULL;
2642
2643 LLFontDescriptor desc(font_name, font_size, style);
2644 LLFontGL* gl_font = LLFontGL::getFont(desc);
2645
2611 return gl_font; 2646 return gl_font;
2612} 2647}
2613 2648
diff --git a/linden/indra/llui/llview.h b/linden/indra/llui/llview.h
index 80dd348..b5a34bd 100644
--- a/linden/indra/llui/llview.h
+++ b/linden/indra/llui/llview.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -51,6 +52,7 @@
51#include "llxmlnode.h" 52#include "llxmlnode.h"
52#include "stdenums.h" 53#include "stdenums.h"
53#include "lluistring.h" 54#include "lluistring.h"
55#include "llcursortypes.h"
54 56
55const U32 FOLLOWS_NONE = 0x00; 57const U32 FOLLOWS_NONE = 0x00;
56const U32 FOLLOWS_LEFT = 0x01; 58const U32 FOLLOWS_LEFT = 0x01;
@@ -484,7 +486,7 @@ public:
484 // did we find *something* with that name? 486 // did we find *something* with that name?
485 if (child) 487 if (child)
486 { 488 {
487 llwarns << "Found child named " << name << " but of wrong type" << llendl; 489 llwarns << "Found child named " << name << " but of wrong type " << typeid(child).name() << ", expecting " << typeid(T).name() << llendl;
488 } 490 }
489 if (create_if_missing) 491 if (create_if_missing)
490 { 492 {
@@ -495,6 +497,11 @@ public:
495 return result; 497 return result;
496 } 498 }
497 499
500 template <class T> T& getChildRef(const std::string& name, BOOL recurse = TRUE) const
501 {
502 return *getChild<T>(name, recurse, TRUE);
503 }
504
498 virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const; 505 virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const;
499 506
500 template <class T> T* createDummyWidget(const std::string& name) const 507 template <class T> T* createDummyWidget(const std::string& name) const
@@ -649,6 +656,8 @@ private:
649 mutable dummy_widget_map_t mDummyWidgets; 656 mutable dummy_widget_map_t mDummyWidgets;
650 657
651 boost::signals::connection mControlConnection; 658 boost::signals::connection mControlConnection;
659
660 ECursorType mHoverCursor;
652 661
653public: 662public:
654 static BOOL sDebugRects; // Draw debug rects behind everything. 663 static BOOL sDebugRects; // Draw debug rects behind everything.
diff --git a/linden/indra/llui/llviewborder.cpp b/linden/indra/llui/llviewborder.cpp
index ae24694..d4a9e9d 100644
--- a/linden/indra/llui/llviewborder.cpp
+++ b/linden/indra/llui/llviewborder.cpp
@@ -16,7 +16,8 @@
16 * 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
17 * 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
18 * 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
19 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 19 * online at
20 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
20 * 21 *
21 * By copying, modifying or distributing this software, you acknowledge 22 * By copying, modifying or distributing this software, you acknowledge
22 * that you have read and understood your obligations described above, 23 * that you have read and understood your obligations described above,
@@ -231,8 +232,7 @@ void LLViewBorder::drawTextures()
231 //gGL.color4fv(UI_VERTEX_COLOR.mV); 232 //gGL.color4fv(UI_VERTEX_COLOR.mV);
232 233
233 //gGL.getTexUnit(0)->bind(mTexture); 234 //gGL.getTexUnit(0)->bind(mTexture);
234 //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); 235 //gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
235 //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
236 236
237 //drawTextureTrapezoid( 0.f, mBorderWidth, getRect().getWidth(), 0, 0 ); 237 //drawTextureTrapezoid( 0.f, mBorderWidth, getRect().getWidth(), 0, 0 );
238 //drawTextureTrapezoid( 90.f, mBorderWidth, getRect().getHeight(), (F32)getRect().getWidth(),0 ); 238 //drawTextureTrapezoid( 90.f, mBorderWidth, getRect().getHeight(), (F32)getRect().getWidth(),0 );
diff --git a/linden/indra/llui/llviewborder.h b/linden/indra/llui/llviewborder.h
index 7f72d54..a40e653 100644
--- a/linden/indra/llui/llviewborder.h
+++ b/linden/indra/llui/llviewborder.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llviewquery.cpp b/linden/indra/llui/llviewquery.cpp
index fe3c308..bdb3d22 100644
--- a/linden/indra/llui/llviewquery.cpp
+++ b/linden/indra/llui/llviewquery.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llui/llviewquery.h b/linden/indra/llui/llviewquery.h
index a8cec09..e87795f 100644
--- a/linden/indra/llui/llviewquery.h
+++ b/linden/indra/llui/llviewquery.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * 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 18 * 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 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,