summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llplugin/slplugin/CMakeLists.txt20
-rw-r--r--indra/llplugin/slplugin/slplugin.cpp94
-rw-r--r--indra/llplugin/slplugin/slplugin_info.plist4
-rw-r--r--indra/llui/llaccordionctrl.cpp22
-rw-r--r--indra/llui/llaccordionctrl.h1
-rw-r--r--indra/llui/llaccordionctrltab.cpp3
-rw-r--r--indra/llui/llbutton.cpp5
-rw-r--r--indra/llui/llbutton.h1
-rw-r--r--indra/llui/lliconctrl.h1
-rw-r--r--indra/llui/llnotifications.cpp158
-rw-r--r--indra/llui/llnotifications.h35
-rw-r--r--indra/llui/lltextbase.cpp1
-rw-r--r--indra/llui/llurlaction.cpp17
-rw-r--r--indra/llui/llurlaction.h3
-rw-r--r--indra/llvfs/lldir_mac.cpp2
-rw-r--r--indra/newview/CMakeLists.txt10
-rw-r--r--indra/newview/llagentwearables.cpp21
-rw-r--r--indra/newview/llagentwearables.h3
-rw-r--r--indra/newview/llagentwearablesfetch.cpp2
-rw-r--r--indra/newview/llappearancemgr.cpp216
-rw-r--r--indra/newview/llappearancemgr.h11
-rw-r--r--indra/newview/llchannelmanager.cpp45
-rw-r--r--indra/newview/llchatitemscontainerctrl.cpp4
-rw-r--r--indra/newview/llinventorybridge.cpp2
-rw-r--r--indra/newview/llinventoryitemslist.cpp141
-rw-r--r--indra/newview/llinventoryitemslist.h88
-rw-r--r--indra/newview/llinventoryobserver.cpp32
-rw-r--r--indra/newview/llinventoryobserver.h37
-rw-r--r--indra/newview/lllocationinputctrl.cpp74
-rw-r--r--indra/newview/lllocationinputctrl.h21
-rw-r--r--indra/newview/llnotificationstorage.cpp228
-rw-r--r--indra/newview/llnotificationstorage.h65
-rw-r--r--indra/newview/llnotificationtiphandler.cpp55
-rw-r--r--indra/newview/lloutfitslist.cpp265
-rw-r--r--indra/newview/lloutfitslist.h74
-rw-r--r--indra/newview/llpanelgroup.h2
-rw-r--r--indra/newview/llpanellogin.cpp2
-rw-r--r--indra/newview/llpanelme.cpp9
-rw-r--r--indra/newview/llpanelme.h1
-rw-r--r--indra/newview/llpanelonlinestatus.cpp60
-rw-r--r--indra/newview/llpanelonlinestatus.h53
-rw-r--r--indra/newview/llpaneloutfitsinventory.cpp143
-rw-r--r--indra/newview/llpaneloutfitsinventory.h16
-rw-r--r--indra/newview/llpanelpeople.cpp28
-rw-r--r--indra/newview/llpanelpeople.h1
-rw-r--r--indra/newview/llpanelplaces.cpp3
-rw-r--r--indra/newview/llscriptfloater.cpp10
-rw-r--r--indra/newview/llscriptfloater.h2
-rw-r--r--indra/newview/llsidepanelappearance.cpp4
-rw-r--r--indra/newview/lltoast.cpp8
-rw-r--r--indra/newview/lltoast.h1
-rw-r--r--indra/newview/lltoastnotifypanel.cpp2
-rw-r--r--indra/newview/lltoastpanel.cpp15
-rw-r--r--indra/newview/llviewerinventory.cpp4
-rw-r--r--indra/newview/llviewerinventory.h1
-rw-r--r--indra/newview/llviewermessage.cpp64
-rw-r--r--indra/newview/llviewermessage.h25
-rw-r--r--indra/newview/llwearableitemslist.cpp88
-rw-r--r--indra/newview/llwearableitemslist.h56
-rw-r--r--indra/newview/llworldmapview.cpp16
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_container.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_session.xml10
-rw-r--r--indra/newview/skins/default/xui/en/menu_object.xml8
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_agent.xml2
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_group.xml2
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_im_control_panel.xml40
-rw-r--r--indra/newview/skins/default/xui/en/panel_inventory_item.xml51
-rw-r--r--indra/newview/skins/default/xui/en/panel_my_profile.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfits_inventory.xml20
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfits_list.xml25
-rw-r--r--indra/newview/skins/default/xui/en/panel_people.xml19
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_world_map.xml8
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml5
-rw-r--r--indra/newview/skins/default/xui/en/widgets/location_input.xml4
-rwxr-xr-xindra/newview/viewer_manifest.py11
77 files changed, 2139 insertions, 467 deletions
diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt
index 4a7d670c23..c1536e85de 100644
--- a/indra/llplugin/slplugin/CMakeLists.txt
+++ b/indra/llplugin/slplugin/CMakeLists.txt
@@ -27,9 +27,15 @@ set(SLPlugin_SOURCE_FILES
add_executable(SLPlugin
WIN32
+ MACOSX_BUNDLE
${SLPlugin_SOURCE_FILES}
)
+set_target_properties(SLPlugin
+ PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist
+ )
+
target_link_libraries(SLPlugin
${LLPLUGIN_LIBRARIES}
${LLMESSAGE_LIBRARIES}
@@ -44,12 +50,16 @@ add_dependencies(SLPlugin
)
if (DARWIN)
- # Mac version needs to link against carbon, and also needs an embedded plist (to set LSBackgroundOnly)
+ # Mac version needs to link against Carbon
target_link_libraries(SLPlugin ${CARBON_LIBRARY})
- set_target_properties(
- SLPlugin
- PROPERTIES
- LINK_FLAGS "-Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist"
+ # Make sure the app bundle has a Resources directory (it will get populated by viewer-manifest.py later)
+ add_custom_command(
+ TARGET SLPlugin POST_BUILD
+ COMMAND mkdir
+ ARGS
+ -p
+ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/SLPlugin.app/Contents/Resources
)
endif (DARWIN)
+ll_deploy_sharedlibs_command(SLPlugin)
diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp
index 77240ce546..c18e2375f9 100644
--- a/indra/llplugin/slplugin/slplugin.cpp
+++ b/indra/llplugin/slplugin/slplugin.cpp
@@ -51,7 +51,7 @@
#endif
/*
- On Mac OS, since we call WaitNextEvent, this process will show up in the dock unless we set the LSBackgroundOnly flag in the Info.plist.
+ On Mac OS, since we call WaitNextEvent, this process will show up in the dock unless we set the LSBackgroundOnly or LSUIElement flag in the Info.plist.
Normally non-bundled binaries don't have an info.plist file, but it's possible to embed one in the binary by adding this to the linker flags:
@@ -60,7 +60,8 @@
which means adding this to the gcc flags:
-Wl,-sectcreate,__TEXT,__info_plist,/path/to/slplugin_info.plist
-
+
+ Now that SLPlugin is a bundled app on the Mac, this is no longer necessary (it can just use a regular Info.plist file), but I'm leaving this comment in for posterity.
*/
#if LL_DARWIN || LL_LINUX
@@ -239,6 +240,21 @@ int main(int argc, char **argv)
checkExceptionHandler();
#endif
+#if LL_DARWIN
+ // If the plugin opens a new window (such as the Flash plugin's fullscreen player), we may need to bring this plugin process to the foreground.
+ // Use this to track the current frontmost window and bring this process to the front if it changes.
+ WindowRef front_window = NULL;
+ WindowGroupRef layer_group = NULL;
+ int window_hack_state = 0;
+ CreateWindowGroup(kWindowGroupAttrFixedLevel, &layer_group);
+ if(layer_group)
+ {
+ // Start out with a window layer that's way out in front (fixes the problem with the menubar not getting hidden on first switch to fullscreen youtube)
+ SetWindowGroupName(layer_group, CFSTR("SLPlugin Layer"));
+ SetWindowGroupLevel(layer_group, kCGOverlayWindowLevel);
+ }
+#endif
+
while(!plugin->isDone())
{
timer.reset();
@@ -248,6 +264,80 @@ int main(int argc, char **argv)
// Some plugins (webkit at least) will want an event loop. This qualifies.
EventRecord evt;
WaitNextEvent(0, &evt, 0, NULL);
+
+ // Check for a change in this process's frontmost window.
+ if(FrontWindow() != front_window)
+ {
+ ProcessSerialNumber self = { 0, kCurrentProcess };
+ ProcessSerialNumber parent = { 0, kNoProcess };
+ ProcessSerialNumber front = { 0, kNoProcess };
+ Boolean this_is_front_process = false;
+ Boolean parent_is_front_process = false;
+ {
+ // Get this process's parent
+ ProcessInfoRec info;
+ info.processInfoLength = sizeof(ProcessInfoRec);
+ info.processName = NULL;
+ info.processAppSpec = NULL;
+ if(GetProcessInformation( &self, &info ) == noErr)
+ {
+ parent = info.processLauncher;
+ }
+
+ // and figure out whether this process or its parent are currently frontmost
+ if(GetFrontProcess(&front) == noErr)
+ {
+ (void) SameProcess(&self, &front, &this_is_front_process);
+ (void) SameProcess(&parent, &front, &parent_is_front_process);
+ }
+ }
+
+ if((FrontWindow() != NULL) && (front_window == NULL))
+ {
+ // Opening the first window
+
+ if(window_hack_state == 0)
+ {
+ // Next time through the event loop, lower the window group layer
+ window_hack_state = 1;
+ }
+
+ if(layer_group)
+ {
+ SetWindowGroup(FrontWindow(), layer_group);
+ }
+
+ if(parent_is_front_process)
+ {
+ // Bring this process's windows to the front.
+ (void) SetFrontProcess( &self );
+ }
+
+ ActivateWindow(FrontWindow(), true);
+ }
+ else if((FrontWindow() == NULL) && (front_window != NULL))
+ {
+ // Closing the last window
+
+ if(this_is_front_process)
+ {
+ // Try to bring this process's parent to the front
+ (void) SetFrontProcess(&parent);
+ }
+ }
+ else if(window_hack_state == 1)
+ {
+ if(layer_group)
+ {
+ // Set the window group level back to something less extreme
+ SetWindowGroupLevel(layer_group, kCGNormalWindowLevel);
+ }
+ window_hack_state = 2;
+ }
+
+ front_window = FrontWindow();
+
+ }
}
#endif
F64 elapsed = timer.getElapsedTimeF64();
diff --git a/indra/llplugin/slplugin/slplugin_info.plist b/indra/llplugin/slplugin/slplugin_info.plist
index b1daf87424..c4597380e0 100644
--- a/indra/llplugin/slplugin/slplugin_info.plist
+++ b/indra/llplugin/slplugin/slplugin_info.plist
@@ -6,7 +6,7 @@
<string>English</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
- <key>LSBackgroundOnly</key>
- <true/>
+ <key>LSUIElement</key>
+ <string>1</string>
</dict>
</plist>
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp
index cdcf780d2e..136fd2a9ac 100644
--- a/indra/llui/llaccordionctrl.cpp
+++ b/indra/llui/llaccordionctrl.cpp
@@ -332,11 +332,31 @@ void LLAccordionCtrl::addCollapsibleCtrl(LLView* view)
if(std::find(getChildList()->begin(),getChildList()->end(),accordion_tab) == getChildList()->end())
addChild(accordion_tab);
mAccordionTabs.push_back(accordion_tab);
-
+
accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, mAccordionTabs.size() - 1) );
}
+void LLAccordionCtrl::removeCollapsibleCtrl(LLView* view)
+{
+ LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view);
+ if(!accordion_tab)
+ return;
+
+ if(std::find(getChildList()->begin(),getChildList()->end(),accordion_tab) != getChildList()->end())
+ removeChild(accordion_tab);
+
+ for (std::vector<LLAccordionCtrlTab*>::iterator iter = mAccordionTabs.begin();
+ iter != mAccordionTabs.end(); ++iter)
+ {
+ if (accordion_tab == (*iter))
+ {
+ mAccordionTabs.erase(iter);
+ break;
+ }
+ }
+}
+
void LLAccordionCtrl::arrangeSinge()
{
S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter
diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h
index 7c29e545b7..ab7d6548ca 100644
--- a/indra/llui/llaccordionctrl.h
+++ b/indra/llui/llaccordionctrl.h
@@ -92,6 +92,7 @@ public:
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
void addCollapsibleCtrl(LLView* view);
+ void removeCollapsibleCtrl(LLView* view);
void arrange();
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index dfb427f293..d389236642 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -425,6 +425,9 @@ bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group)
setDisplayChildren(getDisplayChildren());
}
+ if (!mContainerPanel)
+ mContainerPanel = findContainerView();
+
return res;
}
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 33c6a8b6ac..0255061b12 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -1003,6 +1003,11 @@ void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image)
mFadeWhenDisabled = TRUE;
}
+void LLButton::setImagePressed(LLPointer<LLUIImage> image)
+{
+ mImagePressed = image;
+}
+
void LLButton::setImageHoverSelected(LLPointer<LLUIImage> image)
{
mImageHoverSelected = image;
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 6a1e3a9425..a4d81ed6c3 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -246,6 +246,7 @@ public:
void setImageHoverUnselected(LLPointer<LLUIImage> image);
void setImageDisabled(LLPointer<LLUIImage> image);
void setImageDisabledSelected(LLPointer<LLUIImage> image);
+ void setImagePressed(LLPointer<LLUIImage> image);
void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; }
BOOL getCommitOnReturn() const { return mCommitOnReturn; }
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index 66368f979b..7e37600409 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -73,6 +73,7 @@ public:
std::string getImageName() const;
void setColor(const LLColor4& color) { mColor = color; }
+ void setImage(LLPointer<LLUIImage> image) { mImagep = image; }
private:
void setIconImageDrawSize() ;
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 65ef53443b..7b8f51ae3c 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -48,122 +48,38 @@
const std::string NOTIFICATION_PERSIST_VERSION = "0.93";
-// local channel for notification history
-class LLNotificationHistoryChannel : public LLNotificationChannel
+// Local channel for persistent notifications
+// Stores only persistent notifications.
+// Class users can use connectChanged() to process persistent notifications
+// (see LLNotificationStorage for example).
+class LLPersistentNotificationChannel : public LLNotificationChannel
{
- LOG_CLASS(LLNotificationHistoryChannel);
+ LOG_CLASS(LLPersistentNotificationChannel);
public:
- LLNotificationHistoryChannel(const std::string& filename) :
- LLNotificationChannel("History", "Visible", &historyFilter, LLNotificationComparators::orderByUUID()),
- mFileName(filename)
+ LLPersistentNotificationChannel() :
+ LLNotificationChannel("Persistent", "Visible", &notificationFilter, LLNotificationComparators::orderByUUID())
{
- connectChanged(boost::bind(&LLNotificationHistoryChannel::historyHandler, this, _1));
- loadPersistentNotifications();
}
private:
- bool historyHandler(const LLSD& payload)
- {
- // we ignore "load" messages, but rewrite the persistence file on any other
- std::string sigtype = payload["sigtype"];
- if (sigtype != "load")
- {
- savePersistentNotifications();
- }
- return false;
- }
-
- // The history channel gets all notifications except those that have been cancelled
- static bool historyFilter(LLNotificationPtr pNotification)
- {
- return !pNotification->isCancelled();
- }
- void savePersistentNotifications()
+ // The channel gets all persistent notifications except those that have been canceled
+ static bool notificationFilter(LLNotificationPtr pNotification)
{
- /* NOTE: As of 2009-11-09 the reload of notifications on startup does not
- work, and has not worked for months. Skip saving notifications until the
- read can be fixed, because this hits the disk once per notification and
- causes log spam. James
-
- llinfos << "Saving open notifications to " << mFileName << llendl;
+ bool handle_notification = false;
- llofstream notify_file(mFileName.c_str());
- if (!notify_file.is_open())
- {
- llwarns << "Failed to open " << mFileName << llendl;
- return;
- }
-
- LLSD output;
- output["version"] = NOTIFICATION_PERSIST_VERSION;
- LLSD& data = output["data"];
-
- for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
- {
- if (!LLNotifications::instance().templateExists((*it)->getName())) continue;
+ handle_notification = pNotification->isPersistent()
+ && !pNotification->isCancelled();
- // only store notifications flagged as persisting
- LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate((*it)->getName());
- if (!templatep->mPersist) continue;
-
- data.append((*it)->asLLSD());
- }
-
- LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
- formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);
- */
+ return handle_notification;
}
- void loadPersistentNotifications()
- {
- llinfos << "Loading open notifications from " << mFileName << llendl;
-
- llifstream notify_file(mFileName.c_str());
- if (!notify_file.is_open())
- {
- llwarns << "Failed to open " << mFileName << llendl;
- return;
- }
-
- LLSD input;
- LLPointer<LLSDParser> parser = new LLSDXMLParser();
- if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0)
- {
- llwarns << "Failed to parse open notifications" << llendl;
- return;
- }
-
- if (input.isUndefined()) return;
- std::string version = input["version"];
- if (version != NOTIFICATION_PERSIST_VERSION)
- {
- llwarns << "Bad open notifications version: " << version << llendl;
- return;
- }
- LLSD& data = input["data"];
- if (data.isUndefined()) return;
-
- LLNotifications& instance = LLNotifications::instance();
- for (LLSD::array_const_iterator notification_it = data.beginArray();
- notification_it != data.endArray();
- ++notification_it)
- {
- instance.add(LLNotificationPtr(new LLNotification(*notification_it)));
- }
- }
-
- //virtual
void onDelete(LLNotificationPtr pNotification)
{
- // we want to keep deleted notifications in our log
+ // we want to keep deleted notifications in our log, otherwise some
+ // notifications will be lost on exit.
mItems.insert(pNotification);
-
- return;
}
-
-private:
- std::string mFileName;
};
bool filterIgnoredNotifications(LLNotificationPtr notification)
@@ -417,6 +333,10 @@ LLNotification::LLNotification(const LLNotification::Params& p) :
mTemporaryResponder = true;
}
+ else if(p.functor.responder.isChosen())
+ {
+ mResponder = p.functor.responder;
+ }
if(p.responder.isProvided())
{
@@ -462,6 +382,12 @@ LLSD LLNotification::asLLSD()
output["priority"] = (S32)mPriority;
output["responseFunctor"] = mResponseFunctorName;
output["reusable"] = mIsReusable;
+
+ if(mResponder)
+ {
+ output["responder"] = mResponder->asLLSD();
+ }
+
return output;
}
@@ -571,12 +497,20 @@ void LLNotification::respond(const LLSD& response)
// *TODO may remove mRespondedTo and use mResponce.isDefined() in isRespondedTo()
mRespondedTo = true;
mResponse = response;
- // look up the functor
- LLNotificationFunctorRegistry::ResponseFunctor functor =
- LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName);
- // and then call it
- functor(asLLSD(), response);
-
+
+ if(mResponder)
+ {
+ mResponder->handleRespond(asLLSD(), response);
+ }
+ else
+ {
+ // look up the functor
+ LLNotificationFunctorRegistry::ResponseFunctor functor =
+ LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName);
+ // and then call it
+ functor(asLLSD(), response);
+ }
+
if (mTemporaryResponder && !isReusable())
{
LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
@@ -621,6 +555,11 @@ void LLNotification::setResponseFunctor(const LLNotificationFunctorRegistry::Res
LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, cb);
}
+void LLNotification::setResponseFunctor(const LLNotificationResponderPtr& responder)
+{
+ mResponder = responder;
+}
+
bool LLNotification::payloadContainsAll(const std::vector<std::string>& required_fields) const
{
for(std::vector<std::string>::const_iterator required_fields_it = required_fields.begin();
@@ -1116,12 +1055,9 @@ void LLNotifications::createDefaultChannels()
LLNotificationChannel::buildChannel("Visible", "Ignore",
&LLNotificationFilters::includeEverything);
- // create special history channel
- //std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" );
- // use ^^^ when done debugging notifications serialization
- std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_USER_SETTINGS, "open_notifications.xml" );
+ // create special persistent notification channel
// this isn't a leak, don't worry about the empty "new"
- new LLNotificationHistoryChannel(notifications_log_file);
+ new LLPersistentNotificationChannel();
// connect action methods to these channels
LLNotifications::instance().getChannel("Expiration")->
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 1799ca65b7..c942a32512 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -116,8 +116,23 @@ typedef enum e_notification_priority
NOTIFICATION_PRIORITY_CRITICAL
} ENotificationPriority;
+class LLNotificationResponderInterface
+{
+public:
+ LLNotificationResponderInterface(){};
+ virtual ~LLNotificationResponderInterface(){};
+
+ virtual void handleRespond(const LLSD& notification, const LLSD& response) = 0;
+
+ virtual LLSD asLLSD() = 0;
+
+ virtual void fromLLSD(const LLSD& params) = 0;
+};
+
typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
+typedef boost::shared_ptr<LLNotificationResponderInterface> LLNotificationResponderPtr;
+
typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
@@ -303,10 +318,12 @@ public:
{
Alternative<std::string> name;
Alternative<LLNotificationFunctorRegistry::ResponseFunctor> function;
+ Alternative<LLNotificationResponderPtr> responder;
Functor()
: name("functor_name"),
- function("functor")
+ function("functor"),
+ responder("responder")
{}
};
Optional<Functor> functor;
@@ -349,12 +366,13 @@ private:
bool mIgnored;
ENotificationPriority mPriority;
LLNotificationFormPtr mForm;
- void* mResponderObj;
+ void* mResponderObj; // TODO - refactor/remove this field
bool mIsReusable;
-
+ LLNotificationResponderPtr mResponder;
+
// a reference to the template
LLNotificationTemplatePtr mTemplatep;
-
+
/*
We want to be able to store and reload notifications so that they can survive
a shutdown/restart of the client. So we can't simply pass in callbacks;
@@ -393,6 +411,8 @@ public:
void setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb);
+ void setResponseFunctor(const LLNotificationResponderPtr& responder);
+
typedef enum e_response_template_type
{
WITHOUT_DEFAULT_BUTTON,
@@ -459,7 +479,12 @@ public:
{
return mTemplatep->mName;
}
-
+
+ bool isPersistent() const
+ {
+ return mTemplatep->mPersist;
+ }
+
const LLUUID& id() const
{
return mId;
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index e08026eaf4..390ec234d3 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1507,6 +1507,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url));
registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url));
registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url));
+ registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url));
registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url));
registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url));
registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url));
diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp
index 679db5e39b..2f13a56b42 100644
--- a/indra/llui/llurlaction.cpp
+++ b/indra/llui/llurlaction.cpp
@@ -146,3 +146,20 @@ void LLUrlAction::copyLabelToClipboard(std::string url)
LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel()));
}
}
+
+void LLUrlAction::showProfile(std::string url)
+{
+ // Get id from 'secondlife:///app/{cmd}/{id}/{action}'
+ // and show its profile
+ LLURI uri(url);
+ LLSD path_array = uri.pathArray();
+ if (path_array.size() == 4)
+ {
+ std::string id_str = path_array.get(2).asString();
+ if (LLUUID::validate(id_str))
+ {
+ std::string cmd_str = path_array.get(1).asString();
+ executeSLURL("secondlife:///app/" + cmd_str + "/" + id_str + "/about");
+ }
+ }
+}
diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h
index 4830cf27ef..b96faf1b3f 100644
--- a/indra/llui/llurlaction.h
+++ b/indra/llui/llurlaction.h
@@ -79,6 +79,9 @@ public:
/// copy a Url to the clipboard
static void copyURLToClipboard(std::string url);
+ /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile
+ static void showProfile(std::string url);
+
/// specify the callbacks to enable this class's functionality
static void setOpenURLCallback(void (*cb) (const std::string& url));
static void setOpenURLInternalCallback(void (*cb) (const std::string& url));
diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp
index 7bc6f63e1f..8d3852002c 100644
--- a/indra/llvfs/lldir_mac.cpp
+++ b/indra/llvfs/lldir_mac.cpp
@@ -426,7 +426,7 @@ BOOL LLDir_Mac::fileExists(const std::string &filename) const
/*virtual*/ std::string LLDir_Mac::getLLPluginLauncher()
{
return gDirUtilp->getAppRODataDir() + gDirUtilp->getDirDelimiter() +
- "SLPlugin";
+ "SLPlugin.app/Contents/MacOS/SLPlugin";
}
/*virtual*/ std::string LLDir_Mac::getLLPluginFilename(std::string base_name)
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 73459345a4..c71ac9e781 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -258,6 +258,7 @@ set(viewer_SOURCE_FILES
llinventoryclipboard.cpp
llinventoryfilter.cpp
llinventoryfunctions.cpp
+ llinventoryitemslist.cpp
llinventorymodel.cpp
llinventorymodelbackgroundfetch.cpp
llinventoryobserver.cpp
@@ -302,7 +303,9 @@ set(viewer_SOURCE_FILES
llnotificationmanager.cpp
llnotificationofferhandler.cpp
llnotificationscripthandler.cpp
+ llnotificationstorage.cpp
llnotificationtiphandler.cpp
+ lloutfitslist.cpp
lloutputmonitorctrl.cpp
llpanelavatar.cpp
llpanelavatartag.cpp
@@ -335,6 +338,7 @@ set(viewer_SOURCE_FILES
llpanelnearbymedia.cpp
llpanelobject.cpp
llpanelobjectinventory.cpp
+ llpanelonlinestatus.cpp
llpaneloutfitedit.cpp
llpaneloutfitsinventory.cpp
llpanelpeople.cpp
@@ -536,6 +540,7 @@ set(viewer_SOURCE_FILES
llwaterparamset.cpp
llwearable.cpp
llwearabledictionary.cpp
+ llwearableitemslist.cpp
llwearablelist.cpp
llweb.cpp
llwind.cpp
@@ -766,6 +771,7 @@ set(viewer_HEADER_FILES
llinventoryclipboard.h
llinventoryfilter.h
llinventoryfunctions.h
+ llinventoryitemslist.h
llinventorymodel.h
llinventorymodelbackgroundfetch.h
llinventoryobserver.h
@@ -807,6 +813,8 @@ set(viewer_HEADER_FILES
llnetmap.h
llnotificationhandler.h
llnotificationmanager.h
+ llnotificationstorage.h
+ lloutfitslist.h
lloutputmonitorctrl.h
llpanelavatar.h
llpanelavatartag.h
@@ -839,6 +847,7 @@ set(viewer_HEADER_FILES
llpanelnearbymedia.h
llpanelobject.h
llpanelobjectinventory.h
+ llpanelonlinestatus.h
llpaneloutfitedit.h
llpaneloutfitsinventory.h
llpanelpeople.h
@@ -1042,6 +1051,7 @@ set(viewer_HEADER_FILES
llwaterparamset.h
llwearable.h
llwearabledictionary.h
+ llwearableitemslist.h
llwearablelist.h
llweb.h
llwind.h
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 7f248eee30..466f2d499d 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -1338,7 +1338,8 @@ public:
LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key);
LLPanelOutfitsInventory *outfit_panel =
dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory"));
- if (outfit_panel)
+ // TODO: add handling "My Outfits" tab.
+ if (outfit_panel && outfit_panel->isCOFPanelActive())
{
outfit_panel->getRootFolder()->clearSelection();
outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE);
@@ -1361,24 +1362,6 @@ private:
LLUUID mFolderID;
};
-LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name)
-{
- if (!isAgentAvatarValid()) return LLUUID::null;
-
- // First, make a folder in the My Outfits directory.
- const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
- LLUUID folder_id = gInventory.createNewCategory(
- parent_id,
- LLFolderType::FT_OUTFIT,
- new_folder_name);
-
- LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id);
- LLAppearanceMgr::instance().shallowCopyCategoryContents(LLAppearanceMgr::instance().getCOF(),folder_id, cb);
- LLAppearanceMgr::instance().createBaseOutfitLink(folder_id, cb);
-
- return folder_id;
-}
-
void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index)
{
LLUUID first_item_id = getWearableItemID((EWearableType)type, index);
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index b76367324c..585fd3f8b3 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -169,8 +169,7 @@ public:
const LLDynamicArray<S32>& wearables_to_include,
const LLDynamicArray<S32>& attachments_to_include,
BOOL rename_clothing);
-
- LLUUID makeNewOutfitLinks(const std::string& new_folder_name);
+
// Should only be called if we *know* we've never done so before, since users may
// not want the Library outfits to stay in their quick outfit selector and can delete them.
diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp
index 08d8ccfd23..03d09a3798 100644
--- a/indra/newview/llagentwearablesfetch.cpp
+++ b/indra/newview/llagentwearablesfetch.cpp
@@ -119,6 +119,7 @@ public:
item->getLinkedUUID(),
LLAppearanceMgr::instance().getCOF(),
item->getName(),
+ item->getDescription(),
LLAssetType::AT_LINK,
link_waiter);
}
@@ -507,6 +508,7 @@ void LLLibraryOutfitsFetch::contentsDone()
item->getLinkedUUID(),
new_outfit_folder_id,
item->getName(),
+ item->getDescription(),
LLAssetType::AT_LINK,
NULL);
}
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 4d18ff57fe..9e02886e4f 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -32,6 +32,7 @@
#include "llviewerprecompiledheaders.h"
+#include "llaccordionctrltab.h"
#include "llagent.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
@@ -42,6 +43,7 @@
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "llnotificationsutil.h"
+#include "llpaneloutfitsinventory.h"
#include "llselectmgr.h"
#include "llsidepanelappearance.h"
#include "llsidetray.h"
@@ -51,6 +53,8 @@
#include "llviewerregion.h"
#include "llwearablelist.h"
+char ORDER_NUMBER_SEPARATOR('@');
+
LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name)
{
LLInventoryModel::cat_array_t cat_array;
@@ -400,6 +404,7 @@ public:
item_id,
LLAppearanceMgr::instance().getCOF(),
itemp->getName(),
+ itemp->getDescription(),
LLAssetType::AT_LINK,
cb);
}
@@ -691,10 +696,13 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
{
case LLAssetType::AT_LINK:
{
+ //LLInventoryItem::getDescription() is used for a new description
+ //to propagate ordering information saved in descriptions of links
link_inventory_item(gAgent.getID(),
item->getLinkedUUID(),
dst_id,
item->getName(),
+ item->LLInventoryItem::getDescription(),
LLAssetType::AT_LINK, cb);
break;
}
@@ -708,6 +716,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
item->getLinkedUUID(),
dst_id,
item->getName(),
+ item->getDescription(),
LLAssetType::AT_LINK_FOLDER, cb);
}
break;
@@ -811,20 +820,7 @@ void LLAppearanceMgr::filterWearableItems(
{
// Divvy items into arrays by wearable type.
std::vector<LLInventoryModel::item_array_t> items_by_type(WT_COUNT);
- for (S32 i=0; i<items.count(); i++)
- {
- LLViewerInventoryItem *item = items.get(i);
- // Ignore non-wearables.
- if (!item->isWearableType())
- continue;
- EWearableType type = item->getWearableType();
- if(type < 0 || type >= WT_COUNT)
- {
- LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL;
- continue;
- }
- items_by_type[type].push_back(item);
- }
+ divvyWearablesByType(items, items_by_type);
// rebuild items list, retaining the last max_per_type of each array
items.clear();
@@ -853,6 +849,7 @@ void LLAppearanceMgr::linkAll(const LLUUID& category,
item->getLinkedUUID(),
category,
item->getName(),
+ item->LLInventoryItem::getDescription(),
LLAssetType::AT_LINK,
cb);
}
@@ -956,7 +953,7 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLI
if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
{
- link_inventory_item(gAgent.getID(), category, cof, catp->getName(),
+ link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "",
LLAssetType::AT_LINK_FOLDER, link_waiter);
new_outfit_name = catp->getName();
}
@@ -1016,6 +1013,18 @@ static void remove_non_link_items(LLInventoryModel::item_array_t &items)
items = pruned_items;
}
+//a predicate for sorting inventory items by actual descriptions
+bool sort_by_description(const LLInventoryItem* item1, const LLInventoryItem* item2)
+{
+ if (!item1 || !item2)
+ {
+ llwarning("either item1 or item2 is NULL", 0);
+ return true;
+ }
+
+ return item1->LLInventoryItem::getDescription() < item2->LLInventoryItem::getDescription();
+}
+
void LLAppearanceMgr::updateAppearanceFromCOF()
{
// update dirty flag to see if the state of the COF matches
@@ -1026,6 +1035,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF()
dumpCat(getCOF(),"COF, start");
+ updateClothingOrderingInfo();
+
bool follow_folder_links = true;
LLUUID current_outfit_id = getCOF();
@@ -1046,6 +1057,9 @@ void LLAppearanceMgr::updateAppearanceFromCOF()
return;
}
+ //preparing the list of wearables in the correct order for LLAgentWearables
+ std::sort(wear_items.begin(), wear_items.end(), sort_by_description);
+
LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
holder->mObjItems = obj_items;
@@ -1079,8 +1093,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF()
}
#endif
-
- holder->mFoundList.push_front(found);
+ //pushing back, not front, to preserve order of wearables for LLAgentWearables
+ holder->mFoundList.push_back(found);
}
else
{
@@ -1407,7 +1421,7 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update
// Are these links to different items of the same wearable
// type? If so, new item will replace old.
// MULTI-WEARABLES: revisit if more than one per type is allowed.
- else if (areMatchingWearables(vitem,inv_item))
+ else if (FALSE/*areMatchingWearables(vitem,inv_item)*/)
{
if (inv_item->getIsLinkType())
{
@@ -1430,6 +1444,7 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update
vitem->getLinkedUUID(),
getCOF(),
vitem->getName(),
+ vitem->getDescription(),
LLAssetType::AT_LINK,
cb);
}
@@ -1446,6 +1461,7 @@ void LLAppearanceMgr::addEnsembleLink( LLInventoryCategory* cat, bool do_update
cat->getLinkedUUID(),
getCOF(),
cat->getName(),
+ cat->getDescription(),
LLAssetType::AT_LINK_FOLDER,
cb);
#endif
@@ -1572,6 +1588,8 @@ bool LLAppearanceMgr::updateBaseOutfit()
const LLUUID base_outfit_id = getBaseOutfitUUID();
if (base_outfit_id.isNull()) return false;
+ updateClothingOrderingInfo();
+
// in a Base Outfit we do not remove items, only links
purgeCategory(base_outfit_id, false);
@@ -1581,6 +1599,168 @@ bool LLAppearanceMgr::updateBaseOutfit()
return true;
}
+void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type)
+{
+ items_by_type.reserve(WT_COUNT);
+ if (items.empty()) return;
+
+ for (S32 i=0; i<items.count(); i++)
+ {
+ LLViewerInventoryItem *item = items.get(i);
+ // Ignore non-wearables.
+ if (!item->isWearableType())
+ continue;
+ EWearableType type = item->getWearableType();
+ if(type < 0 || type >= WT_COUNT)
+ {
+ LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL;
+ continue;
+ }
+ items_by_type[type].push_back(item);
+ }
+}
+
+std::string build_order_string(EWearableType type, U32 i)
+{
+ std::ostringstream order_num;
+ order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i;
+ return order_num.str();
+}
+
+struct WearablesOrderComparator
+{
+ WearablesOrderComparator(const EWearableType type)
+ {
+ mControlSize = build_order_string(type, 0).size();
+ };
+
+ bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2)
+ {
+ if (!item1 || !item2)
+ {
+ llwarning("either item1 or item2 is NULL", 0);
+ return true;
+ }
+
+ const std::string& desc1 = item1->LLInventoryItem::getDescription();
+ const std::string& desc2 = item2->LLInventoryItem::getDescription();
+
+ bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]);
+ bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]);
+
+ if (item1_valid && item2_valid)
+ return desc1 < desc2;
+
+ //we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions,
+ //items with ordering information but not for the associated wearables type
+ if (!item1_valid && item2_valid)
+ return false;
+
+ return true;
+ }
+
+ U32 mControlSize;
+};
+
+void LLAppearanceMgr::updateClothingOrderingInfo()
+{
+ LLInventoryModel::item_array_t wear_items;
+ getDescendentsOfAssetType(getCOF(), wear_items, LLAssetType::AT_CLOTHING, false);
+
+ wearables_by_type_t items_by_type(WT_COUNT);
+ divvyWearablesByType(wear_items, items_by_type);
+
+ bool inventory_changed = false;
+ for (U32 type = WT_SHIRT; type < WT_COUNT; type++)
+ {
+
+ U32 size = items_by_type[type].size();
+ if (!size) continue;
+
+ //sinking down invalid items which need reordering
+ std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((EWearableType) type));
+
+ //requesting updates only for those links which don't have "valid" descriptions
+ for (U32 i = 0; i < size; i++)
+ {
+ LLViewerInventoryItem* item = items_by_type[type][i];
+ if (!item) continue;
+
+ std::string new_order_str = build_order_string((EWearableType)type, i);
+ if (new_order_str == item->LLInventoryItem::getDescription()) continue;
+
+ item->setDescription(new_order_str);
+ item->setComplete(TRUE);
+ item->updateServer(FALSE);
+ gInventory.updateItem(item);
+ inventory_changed = true;
+ }
+ }
+
+ //*TODO do we really need to notify observers?
+ if (inventory_changed) gInventory.notifyObservers();
+}
+
+
+
+
+class LLShowCreatedOutfit: public LLInventoryCallback
+{
+public:
+ LLShowCreatedOutfit(LLUUID& folder_id): mFolderID(folder_id)
+ {}
+
+ virtual ~LLShowCreatedOutfit()
+ {
+ LLSD key;
+ LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key);
+ LLPanelOutfitsInventory *outfit_panel =
+ dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory"));
+ if (outfit_panel)
+ {
+ outfit_panel->getRootFolder()->clearSelection();
+ outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE);
+ }
+
+ LLAccordionCtrlTab* tab_outfits = outfit_panel ? outfit_panel->findChild<LLAccordionCtrlTab>("tab_outfits") : 0;
+ if (tab_outfits && !tab_outfits->getDisplayChildren())
+ {
+ tab_outfits->changeOpenClose(tab_outfits->getDisplayChildren());
+ }
+
+ LLAppearanceMgr::getInstance()->updateIsDirty();
+ LLAppearanceMgr::getInstance()->updatePanelOutfitName("");
+ }
+
+ virtual void fire(const LLUUID&)
+ {}
+
+private:
+ LLUUID mFolderID;
+};
+
+LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name)
+{
+ if (!isAgentAvatarValid()) return LLUUID::null;
+
+ // First, make a folder in the My Outfits directory.
+ const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ LLUUID folder_id = gInventory.createNewCategory(
+ parent_id,
+ LLFolderType::FT_OUTFIT,
+ new_folder_name);
+
+ updateClothingOrderingInfo();
+
+ LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id);
+ shallowCopyCategoryContents(getCOF(),folder_id, cb);
+ createBaseOutfitLink(folder_id, cb);
+
+ dumpCat(folder_id,"COF, new outfit");
+
+ return folder_id;
+}
+
void LLAppearanceMgr::wearBaseOutfit()
{
const LLUUID& base_outfit_id = getBaseOutfitUUID();
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 7e35919892..efb5274c5b 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -138,12 +138,23 @@ public:
//Remove clothing or detach an object from the agent (a bodypart cannot be removed)
void removeItemFromAvatar(const LLUUID& item_id);
+
+ LLUUID makeNewOutfitLinks(const std::string& new_folder_name);
+
protected:
LLAppearanceMgr();
~LLAppearanceMgr();
private:
+ typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t;
+
+ //Divvy items into arrays by wearable type
+ static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type);
+
+ //Check ordering information on wearables stored in links' descriptions and update if it is invalid
+ void updateClothingOrderingInfo();
+
void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type);
void getDescendentsOfAssetType(const LLUUID& category,
diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp
index 769387c26c..4f9434030f 100644
--- a/indra/newview/llchannelmanager.cpp
+++ b/indra/newview/llchannelmanager.cpp
@@ -35,6 +35,7 @@
#include "llchannelmanager.h"
#include "llappviewer.h"
+#include "llnotificationstorage.h"
#include "llviewercontrol.h"
#include "llviewerwindow.h"
#include "llrootview.h"
@@ -107,31 +108,35 @@ void LLChannelManager::onLoginCompleted()
if(!away_notifications)
{
onStartUpToastClose();
- return;
}
-
- // create a channel for the StartUp Toast
- LLChannelManager::Params p;
- p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID"));
- p.channel_align = CA_RIGHT;
- mStartUpChannel = createChannel(p);
-
- if(!mStartUpChannel)
+ else
{
- onStartUpToastClose();
- return;
- }
+ // create a channel for the StartUp Toast
+ LLChannelManager::Params p;
+ p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID"));
+ p.channel_align = CA_RIGHT;
+ mStartUpChannel = createChannel(p);
- gViewerWindow->getRootView()->addChild(mStartUpChannel);
+ if(!mStartUpChannel)
+ {
+ onStartUpToastClose();
+ }
+ else
+ {
+ gViewerWindow->getRootView()->addChild(mStartUpChannel);
- // init channel's position and size
- S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
- S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
- mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound);
- mStartUpChannel->setMouseDownCallback(boost::bind(&LLNotificationWellWindow::onStartUpToastClick, LLNotificationWellWindow::getInstance(), _2, _3, _4));
+ // init channel's position and size
+ S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
+ S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
+ mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound);
+ mStartUpChannel->setMouseDownCallback(boost::bind(&LLNotificationWellWindow::onStartUpToastClick, LLNotificationWellWindow::getInstance(), _2, _3, _4));
+
+ mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));
+ mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime"));
+ }
+ }
- mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));
- mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime"));
+ LLPersistentNotificationStorage::getInstance()->loadNotifications();
}
//--------------------------------------------------------------------------
diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp
index aef36b677c..6ee14e8ba9 100644
--- a/indra/newview/llchatitemscontainerctrl.cpp
+++ b/indra/newview/llchatitemscontainerctrl.cpp
@@ -44,6 +44,8 @@
#include "llviewercontrol.h"
#include "llagentdata.h"
+#include "llslurl.h"
+
static const S32 msg_left_offset = 10;
static const S32 msg_right_offset = 10;
static const S32 msg_height_pad = 5;
@@ -190,6 +192,8 @@ void LLNearbyChatToastPanel::init(LLSD& notification)
style_params_name.font.name(font_name);
style_params_name.font.size(font_style_size);
+ style_params_name.link_href = LLSLURL::buildCommand("agent",mFromID,"about");
+
msg_text->appendText(str_sender, FALSE, style_params_name);
}
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 9762897491..9a83d9d3b1 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -2532,6 +2532,7 @@ void LLFolderBridge::pasteLinkFromClipboard()
item->getLinkedUUID(),
parent_id,
item->getName(),
+ item->getDescription(),
LLAssetType::AT_LINK,
LLPointer<LLInventoryCallback>(NULL));
}
@@ -3179,6 +3180,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
inv_item->getLinkedUUID(),
mUUID,
inv_item->getName(),
+ inv_item->getDescription(),
LLAssetType::AT_LINK,
cb);
}
diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp
new file mode 100644
index 0000000000..9489e0f2e4
--- /dev/null
+++ b/indra/newview/llinventoryitemslist.cpp
@@ -0,0 +1,141 @@
+/**
+ * @file llinventoryitemslist.cpp
+ * @brief A list of inventory items represented by LLFlatListView.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llinventoryitemslist.h"
+
+#include "lliconctrl.h"
+
+#include "llinventoryfunctions.h"
+#include "lltextutil.h"
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+LLPanelInventoryItem::LLPanelInventoryItem(LLAssetType::EType asset_type,
+ LLInventoryType::EType inventory_type,
+ U32 wearable_type,
+ const std::string &item_name,
+ const std::string &hl)
+: LLPanel()
+ ,mItemName(item_name)
+ ,mHighlightedText(hl)
+ ,mIcon(NULL)
+ ,mTitle(NULL)
+{
+ mItemIcon = get_item_icon(asset_type, inventory_type, wearable_type, FALSE);
+
+ LLUICtrlFactory::getInstance()->buildPanel(this, "panel_inventory_item.xml");
+}
+
+LLPanelInventoryItem::~LLPanelInventoryItem()
+{}
+
+//virtual
+BOOL LLPanelInventoryItem::postBuild()
+{
+ mIcon = getChild<LLIconCtrl>("item_icon");
+ mTitle = getChild<LLTextBox>("item_name");
+
+ updateItem();
+
+ return TRUE;
+}
+
+//virtual
+void LLPanelInventoryItem::setValue(const LLSD& value)
+{
+ if (!value.isMap()) return;
+ if (!value.has("selected")) return;
+ childSetVisible("selected_icon", value["selected"]);
+}
+
+void LLPanelInventoryItem::updateItem()
+{
+ if (mItemIcon.notNull())
+ mIcon->setImage(mItemIcon);
+
+ LLTextUtil::textboxSetHighlightedVal(
+ mTitle,
+ LLStyle::Params(),
+ mItemName,
+ mHighlightedText);
+}
+
+void LLPanelInventoryItem::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ childSetVisible("hovered_icon", true);
+
+ LLPanel::onMouseEnter(x, y, mask);
+}
+
+void LLPanelInventoryItem::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ childSetVisible("hovered_icon", false);
+
+ LLPanel::onMouseLeave(x, y, mask);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+LLInventoryItemsList::LLInventoryItemsList(const LLFlatListView::Params& p)
+: LLFlatListView(p)
+{}
+
+// virtual
+LLInventoryItemsList::~LLInventoryItemsList()
+{}
+
+void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item_array)
+{
+ clear();
+
+ for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
+ iter != item_array.end();
+ iter++)
+ {
+ LLViewerInventoryItem *item = (*iter);
+
+ LLPanelInventoryItem *list_item = new LLPanelInventoryItem(item->getType(),
+ item->getInventoryType(),
+ item->getFlags(),
+ item->getName(),
+ LLStringUtil::null);
+ if (!addItem(list_item, item->getUUID()))
+ {
+ llerrs << "Couldn't add flat item." << llendl;
+ }
+ }
+}
diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h
new file mode 100644
index 0000000000..bba739dbbf
--- /dev/null
+++ b/indra/newview/llinventoryitemslist.h
@@ -0,0 +1,88 @@
+/**
+ * @file llinventoryitemslist.h
+ * @brief A list of inventory items represented by LLFlatListView.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLINVENTORYITEMSLIST_H
+#define LL_LLINVENTORYITEMSLIST_H
+
+#include "llpanel.h"
+
+#include "llassettype.h"
+
+#include "llinventorytype.h"
+
+// newview
+#include "llflatlistview.h"
+#include "llinventorymodel.h"
+
+class LLIconCtrl;
+class LLTextBox;
+
+class LLPanelInventoryItem : public LLPanel
+{
+public:
+ LLPanelInventoryItem(LLAssetType::EType asset_type,
+ LLInventoryType::EType inventory_type,
+ U32 wearable_type,
+ const std::string &item_name,
+ const std::string &hl);
+ virtual ~LLPanelInventoryItem();
+
+ /*virtual*/ BOOL postBuild();
+ /*virtual*/ void setValue(const LLSD& value);
+
+ void updateItem();
+
+ void onMouseEnter(S32 x, S32 y, MASK mask);
+ void onMouseLeave(S32 x, S32 y, MASK mask);
+
+private:
+ LLIconCtrl* mIcon;
+ LLTextBox* mTitle;
+
+ LLUIImagePtr mItemIcon;
+ std::string mItemName;
+ std::string mHighlightedText;
+};
+
+
+class LLInventoryItemsList : public LLFlatListView
+{
+public:
+ virtual ~LLInventoryItemsList();
+
+ void refreshList(const LLInventoryModel::item_array_t item_array);
+
+protected:
+ friend class LLUICtrlFactory;
+ LLInventoryItemsList(const LLFlatListView::Params& p);
+};
+
+#endif //LL_LLINVENTORYITEMSLIST_H
diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp
index 29d99d328a..03006243f9 100644
--- a/indra/newview/llinventoryobserver.cpp
+++ b/indra/newview/llinventoryobserver.cpp
@@ -650,3 +650,35 @@ void LLInventoryTransactionObserver::changed(U32 mask)
}
}
}
+
+void LLInventoryCategoriesObserver::changed(U32 mask)
+{
+ if (!mCategoryMap.size())
+ return;
+
+ for (category_map_t::iterator iter = mCategoryMap.begin();
+ iter != mCategoryMap.end();
+ iter++)
+ {
+ // Inventory category version is used to find out if some changes
+ // to a category have been made.
+ S32 version = gInventory.getCategory((*iter).first)->getVersion();
+ if (version != (*iter).second.mVersion)
+ {
+ // Update category version in map.
+ (*iter).second.mVersion = version;
+ (*iter).second.mCallback();
+ }
+ }
+}
+
+void LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb)
+{
+ S32 version = gInventory.getCategory(cat_id)->getVersion();
+ mCategoryMap.insert(category_map_value_t(cat_id, LLCategoryData(cb, version)));
+}
+
+void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id)
+{
+ mCategoryMap.erase(mCategoryMap.find(cat_id));
+}
diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h
index 8d60df7e8d..e63b67d2ad 100644
--- a/indra/newview/llinventoryobserver.h
+++ b/indra/newview/llinventoryobserver.h
@@ -261,5 +261,40 @@ protected:
uuid_vec_t mIncomplete;
};
-#endif // LL_LLINVENTORYOBSERVERS_H
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInventoryCategoriesObserver
+//
+// This class is used for monitoring a list of inventory categories
+// and firing a callback when there are changes in any of them.
+// Categories are identified by their UUIDs.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLInventoryCategoriesObserver : public LLInventoryObserver
+{
+public:
+ typedef boost::function<void()> callback_t;
+
+ LLInventoryCategoriesObserver() {};
+ virtual void changed(U32 mask);
+
+ void addCategory(const LLUUID& cat_id, callback_t cb);
+ void removeCategory(const LLUUID& cat_id);
+protected:
+ struct LLCategoryData
+ {
+ LLCategoryData(callback_t cb, S32 version)
+ : mCallback(cb)
+ , mVersion(version)
+ {}
+
+ callback_t mCallback;
+ S32 mVersion;
+ };
+
+ typedef std::map<LLUUID, LLCategoryData> category_map_t;
+ typedef category_map_t::value_type category_map_value_t;
+
+ category_map_t mCategoryMap;
+};
+
+#endif // LL_LLINVENTORYOBSERVERS_H
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index 4e0be81f62..7abb4f4f16 100644
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -38,6 +38,7 @@
// common includes
#include "llbutton.h"
#include "llfocusmgr.h"
+#include "llhelp.h"
#include "llmenugl.h"
#include "llparcel.h"
#include "llstring.h"
@@ -177,6 +178,7 @@ static LLDefaultChildRegistry::Register<LLLocationInputCtrl> r("location_input")
LLLocationInputCtrl::Params::Params()
: icon_maturity_general("icon_maturity_general"),
icon_maturity_adult("icon_maturity_adult"),
+ icon_maturity_moderate("icon_maturity_moderate"),
add_landmark_image_enabled("add_landmark_image_enabled"),
add_landmark_image_disabled("add_landmark_image_disabled"),
add_landmark_image_hover("add_landmark_image_hover"),
@@ -186,14 +188,15 @@ LLLocationInputCtrl::Params::Params()
add_landmark_button("add_landmark_button"),
for_sale_button("for_sale_button"),
info_button("info_button"),
- maturity_icon("maturity_icon"),
+ maturity_button("maturity_button"),
voice_icon("voice_icon"),
fly_icon("fly_icon"),
push_icon("push_icon"),
build_icon("build_icon"),
scripts_icon("scripts_icon"),
damage_icon("damage_icon"),
- damage_text("damage_text")
+ damage_text("damage_text"),
+ maturity_help_topic("maturity_help_topic")
{
}
@@ -208,7 +211,9 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)
mLandmarkImageOn(NULL),
mLandmarkImageOff(NULL),
mIconMaturityGeneral(NULL),
- mIconMaturityAdult(NULL)
+ mIconMaturityAdult(NULL),
+ mIconMaturityModerate(NULL),
+ mMaturityHelpTopic(p.maturity_help_topic)
{
// Lets replace default LLLineEditor with LLLocationLineEditor
// to make needed escaping while copying and cutting url
@@ -276,10 +281,15 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)
{
mIconMaturityAdult = p.icon_maturity_adult;
}
+ if(p.icon_maturity_moderate())
+ {
+ mIconMaturityModerate = p.icon_maturity_moderate;
+ }
- LLIconCtrl::Params maturity_icon = p.maturity_icon;
- mMaturityIcon = LLUICtrlFactory::create<LLIconCtrl>(maturity_icon);
- addChild(mMaturityIcon);
+ LLButton::Params maturity_button = p.maturity_button;
+ mMaturityButton = LLUICtrlFactory::create<LLButton>(maturity_button);
+ addChild(mMaturityButton);
+ mMaturityButton->setClickedCallback(boost::bind(&LLLocationInputCtrl::onMaturityButtonClicked, this));
LLButton::Params for_sale_button = p.for_sale_button;
for_sale_button.tool_tip = LLTrans::getString("LocationCtrlForSaleTooltip");
@@ -576,7 +586,7 @@ void LLLocationInputCtrl::reshape(S32 width, S32 height, BOOL called_from_parent
if (isHumanReadableLocationVisible)
{
- refreshMaturityIcon();
+ refreshMaturityButton();
}
}
@@ -613,6 +623,11 @@ void LLLocationInputCtrl::onAgentParcelChange()
refresh();
}
+void LLLocationInputCtrl::onMaturityButtonClicked()
+{
+ LLUI::sHelpImpl->showTopic(mMaturityHelpTopic);
+}
+
void LLLocationInputCtrl::onLandmarkLoaded(LLLandmark* lm)
{
(void) lm;
@@ -736,7 +751,7 @@ void LLLocationInputCtrl::refreshLocation()
setText(location_name);
isHumanReadableLocationVisible = true;
- refreshMaturityIcon();
+ refreshMaturityButton();
}
// returns new right edge
@@ -852,37 +867,54 @@ void LLLocationInputCtrl::refreshHealth()
}
}
-void LLLocationInputCtrl::refreshMaturityIcon()
+void LLLocationInputCtrl::refreshMaturityButton()
{
// Updating maturity rating icon.
LLViewerRegion* region = gAgent.getRegion();
if (!region)
return;
+ bool button_visible = true;
+ LLPointer<LLUIImage> rating_image = NULL;
+ std::string rating_tooltip;
+
U8 sim_access = region->getSimAccess();
switch(sim_access)
{
case SIM_ACCESS_PG:
- mMaturityIcon->setValue(mIconMaturityGeneral->getName());
- mMaturityIcon->setVisible(TRUE);
+ rating_image = mIconMaturityGeneral;
+ rating_tooltip = LLTrans::getString("LocationCtrlGeneralIconTooltip");
break;
case SIM_ACCESS_ADULT:
- mMaturityIcon->setValue(mIconMaturityAdult->getName());
- mMaturityIcon->setVisible(TRUE);
+ rating_image = mIconMaturityAdult;
+ rating_tooltip = LLTrans::getString("LocationCtrlAdultIconTooltip");
+ break;
+
+ case SIM_ACCESS_MATURE:
+ rating_image = mIconMaturityModerate;
+ rating_tooltip = LLTrans::getString("LocationCtrlModerateIconTooltip");
break;
default:
- mMaturityIcon->setVisible(FALSE);
+ button_visible = false;
+ break;
}
- if (mMaturityIcon->getVisible())
+ mMaturityButton->setVisible(button_visible);
+ mMaturityButton->setToolTip(rating_tooltip);
+ if(rating_image)
+ {
+ mMaturityButton->setImageUnselected(rating_image);
+ mMaturityButton->setImagePressed(rating_image);
+ }
+ if (mMaturityButton->getVisible())
{
- positionMaturityIcon();
+ positionMaturityButton();
}
}
-void LLLocationInputCtrl::positionMaturityIcon()
+void LLLocationInputCtrl::positionMaturityButton()
{
const LLFontGL* font = mTextEntry->getFont();
if (!font)
@@ -894,11 +926,11 @@ void LLLocationInputCtrl::positionMaturityIcon()
// Calculate the right edge of rendered text + a whitespace.
left_pad = left_pad + font->getWidth(mTextEntry->getText()) + font->getWidth(" ");
- LLRect rect = mMaturityIcon->getRect();
- mMaturityIcon->setRect(rect.setOriginAndSize(left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
+ LLRect rect = mMaturityButton->getRect();
+ mMaturityButton->setRect(rect.setOriginAndSize(left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
// Hide icon if it text area is not width enough to display it, show otherwise.
- mMaturityIcon->setVisible(rect.mRight < mTextEntry->getRect().getWidth() - right_pad);
+ mMaturityButton->setVisible(rect.mRight < mTextEntry->getRect().getWidth() - right_pad);
}
void LLLocationInputCtrl::rebuildLocationHistory(const std::string& filter)
@@ -1014,7 +1046,7 @@ void LLLocationInputCtrl::changeLocationPresentation()
mTextEntry->setText(LLAgentUI::buildSLURL(false));
mTextEntry->selectAll();
- mMaturityIcon->setVisible(FALSE);
+ mMaturityButton->setVisible(FALSE);
isHumanReadableLocationVisible = false;
}
diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h
index f790140f07..fc7adf60b0 100644
--- a/indra/newview/lllocationinputctrl.h
+++ b/indra/newview/lllocationinputctrl.h
@@ -66,17 +66,19 @@ public:
{
Optional<LLUIImage*> icon_maturity_general,
icon_maturity_adult,
+ icon_maturity_moderate,
add_landmark_image_enabled,
add_landmark_image_disabled,
add_landmark_image_hover,
add_landmark_image_selected;
+ Optional<std::string> maturity_help_topic;
Optional<S32> icon_hpad,
add_landmark_hpad;
- Optional<LLButton::Params> add_landmark_button,
+ Optional<LLButton::Params> maturity_button,
+ add_landmark_button,
for_sale_button,
info_button;
- Optional<LLIconCtrl::Params> maturity_icon,
- voice_icon,
+ Optional<LLIconCtrl::Params> voice_icon,
fly_icon,
push_icon,
build_icon,
@@ -136,8 +138,8 @@ private:
void refreshParcelIcons();
// Refresh the value in the health percentage text field
void refreshHealth();
- void refreshMaturityIcon();
- void positionMaturityIcon();
+ void refreshMaturityButton();
+ void positionMaturityButton();
void rebuildLocationHistory(const std::string& filter = LLStringUtil::null);
bool findTeleportItemsByTitle(const LLTeleportHistoryItem& item, const std::string& filter);
@@ -156,6 +158,7 @@ private:
void onForSaleButtonClicked();
void onAddLandmarkButtonClicked();
void onAgentParcelChange();
+ void onMaturityButtonClicked();
// callbacks
bool onLocationContextMenuItemEnabled(const LLSD& userdata);
void onLocationContextMenuItemClicked(const LLSD& userdata);
@@ -168,7 +171,7 @@ private:
S32 mIconHPad; // pad between all icons
S32 mAddLandmarkHPad; // pad to left of landmark star
- LLIconCtrl* mMaturityIcon;
+ LLButton* mMaturityButton;
LLIconCtrl* mParcelIcon[ICON_COUNT];
LLTextBox* mDamageText;
@@ -182,14 +185,16 @@ private:
boost::signals2::connection mLocationHistoryConnection;
LLUIImage* mLandmarkImageOn;
LLUIImage* mLandmarkImageOff;
- LLUIImage* mIconMaturityGeneral;
- LLUIImage* mIconMaturityAdult;
+ LLPointer<LLUIImage> mIconMaturityGeneral;
+ LLPointer<LLUIImage> mIconMaturityAdult;
+ LLPointer<LLUIImage> mIconMaturityModerate;
std::string mAddLandmarkTooltip;
std::string mEditLandmarkTooltip;
// this field holds a human-readable form of the location string, it is needed to be able to compare copy-pated value and real location
std::string mHumanReadableLocation;
bool isHumanReadableLocationVisible;
+ std::string mMaturityHelpTopic;
};
#endif
diff --git a/indra/newview/llnotificationstorage.cpp b/indra/newview/llnotificationstorage.cpp
new file mode 100644
index 0000000000..316ff4324c
--- /dev/null
+++ b/indra/newview/llnotificationstorage.cpp
@@ -0,0 +1,228 @@
+/**
+* @file llnotificationstorage.cpp
+* @brief LLPersistentNotificationStorage class implementation
+*
+* $LicenseInfo:firstyear=2010&license=viewergpl$
+*
+* Copyright (c) 2010, Linden Research, Inc.
+*
+* Second Life Viewer Source Code
+* The source code in this file ("Source Code") is provided by Linden Lab
+* to you under the terms of the GNU General Public License, version 2.0
+* ("GPL"), unless you have obtained a separate licensing agreement
+* ("Other License"), formally executed by you and Linden Lab. Terms of
+* the GPL can be found in doc/GPL-license.txt in this distribution, or
+* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+*
+* There are special exceptions to the terms and conditions of the GPL as
+* it is applied to this Source Code. View the full text of the exception
+* in the file doc/FLOSS-exception.txt in this software distribution, or
+* online at
+* http://secondlifegrid.net/programs/open_source/licensing/flossexception
+*
+* By copying, modifying or distributing this software, you acknowledge
+* that you have read and understood your obligations described above,
+* and agree to abide by those obligations.
+*
+* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+* COMPLETENESS OR PERFORMANCE.
+* $/LicenseInfo$
+*/
+
+#include "llviewerprecompiledheaders.h" // must be first include
+#include "llnotificationstorage.h"
+
+#include "llxmlnode.h" // for linux compilers
+
+#include "llchannelmanager.h"
+#include "llscreenchannel.h"
+#include "llscriptfloater.h"
+#include "llsdserialize.h"
+#include "llviewermessage.h"
+
+//////////////////////////////////////////////////////////////////////////
+
+class LLResponderRegistry
+{
+public:
+
+ static void registerResponders();
+
+ static LLNotificationResponderInterface* createResponder(const std::string& notification_name, const LLSD& params);
+
+private:
+
+ template<typename RESPONDER_TYPE>
+ static LLNotificationResponderInterface* create(const LLSD& params)
+ {
+ RESPONDER_TYPE* responder = new RESPONDER_TYPE();
+ responder->fromLLSD(params);
+ return responder;
+ }
+
+ typedef boost::function<LLNotificationResponderInterface* (const LLSD& params)> responder_constructor_t;
+
+ static void add(const std::string& notification_name, const responder_constructor_t& ctr);
+
+private:
+
+ typedef std::map<std::string, responder_constructor_t> build_map_t;
+
+ static build_map_t sBuildMap;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+LLPersistentNotificationStorage::LLPersistentNotificationStorage()
+{
+ mFileName = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" );
+}
+
+bool LLPersistentNotificationStorage::onPersistentChannelChanged(const LLSD& payload)
+{
+ // we ignore "load" messages, but rewrite the persistence file on any other
+ const std::string sigtype = payload["sigtype"].asString();
+ if ("load" != sigtype)
+ {
+ saveNotifications();
+ }
+ return false;
+}
+
+void LLPersistentNotificationStorage::saveNotifications()
+{
+ // TODO - think about save optimization.
+
+ llofstream notify_file(mFileName.c_str());
+ if (!notify_file.is_open())
+ {
+ llwarns << "Failed to open " << mFileName << llendl;
+ return;
+ }
+
+ LLSD output;
+ LLSD& data = output["data"];
+
+ LLNotificationChannelPtr history_channel = LLNotifications::instance().getChannel("Persistent");
+ LLNotificationSet::iterator it = history_channel->begin();
+
+ for ( ; history_channel->end() != it; ++it)
+ {
+ LLNotificationPtr notification = *it;
+
+ // After a notification was placed in Persist channel, it can become
+ // responded, expired - in this case we are should not save it
+ if(notification->isRespondedTo()
+ || notification->isExpired())
+ {
+ continue;
+ }
+
+ data.append(notification->asLLSD());
+ }
+
+ LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
+ formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);
+}
+
+void LLPersistentNotificationStorage::loadNotifications()
+{
+ LLResponderRegistry::registerResponders();
+
+ LLNotifications::instance().getChannel("Persistent")->
+ connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1));
+
+ llifstream notify_file(mFileName.c_str());
+ if (!notify_file.is_open())
+ {
+ llwarns << "Failed to open " << mFileName << llendl;
+ return;
+ }
+
+ LLSD input;
+ LLPointer<LLSDParser> parser = new LLSDXMLParser();
+ if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0)
+ {
+ llwarns << "Failed to parse open notifications" << llendl;
+ return;
+ }
+
+ if (input.isUndefined())
+ {
+ return;
+ }
+
+ LLSD& data = input["data"];
+ if (data.isUndefined())
+ {
+ return;
+ }
+
+ using namespace LLNotificationsUI;
+ LLScreenChannel* notification_channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->
+ findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+
+ LLNotifications& instance = LLNotifications::instance();
+
+ for (LLSD::array_const_iterator notification_it = data.beginArray();
+ notification_it != data.endArray();
+ ++notification_it)
+ {
+ LLSD notification_params = *notification_it;
+ LLNotificationPtr notification(new LLNotification(notification_params));
+
+ LLNotificationResponderPtr responder(LLResponderRegistry::
+ createResponder(notification_params["name"], notification_params["responder"]));
+ notification->setResponseFunctor(responder);
+
+ instance.add(notification);
+
+ // hide script floaters so they don't confuse the user and don't overlap startup toast
+ LLScriptFloaterManager::getInstance()->setFloaterVisible(notification->getID(), false);
+
+ if(notification_channel)
+ {
+ // hide saved toasts so they don't confuse the user
+ notification_channel->hideToast(notification->getID());
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+LLResponderRegistry::build_map_t LLResponderRegistry::sBuildMap;
+
+void LLResponderRegistry::registerResponders()
+{
+ sBuildMap.clear();
+
+ add("ObjectGiveItem", &create<LLOfferInfo>);
+ add("UserGiveItem", &create<LLOfferInfo>);
+}
+
+LLNotificationResponderInterface* LLResponderRegistry::createResponder(const std::string& notification_name, const LLSD& params)
+{
+ build_map_t::const_iterator it = sBuildMap.find(notification_name);
+ if(sBuildMap.end() == it)
+ {
+ llwarns << "Responder for notification \'" << notification_name << "\' is not registered" << llendl;
+ return NULL;
+ }
+ responder_constructor_t ctr = it->second;
+ return ctr(params);
+}
+
+void LLResponderRegistry::add(const std::string& notification_name, const responder_constructor_t& ctr)
+{
+ if(sBuildMap.find(notification_name) != sBuildMap.end())
+ {
+ llwarns << "Responder is already registered : " << notification_name << llendl;
+ llassert(!"Responder already registered");
+ }
+ sBuildMap[notification_name] = ctr;
+}
+
+// EOF
diff --git a/indra/newview/llnotificationstorage.h b/indra/newview/llnotificationstorage.h
new file mode 100644
index 0000000000..5050781a85
--- /dev/null
+++ b/indra/newview/llnotificationstorage.h
@@ -0,0 +1,65 @@
+/**
+* @file llnotificationstorage.h
+* @brief LLNotificationStorage class declaration
+*
+* $LicenseInfo:firstyear=2010&license=viewergpl$
+*
+* Copyright (c) 2010, Linden Research, Inc.
+*
+* Second Life Viewer Source Code
+* The source code in this file ("Source Code") is provided by Linden Lab
+* to you under the terms of the GNU General Public License, version 2.0
+* ("GPL"), unless you have obtained a separate licensing agreement
+* ("Other License"), formally executed by you and Linden Lab. Terms of
+* the GPL can be found in doc/GPL-license.txt in this distribution, or
+* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+*
+* There are special exceptions to the terms and conditions of the GPL as
+* it is applied to this Source Code. View the full text of the exception
+* in the file doc/FLOSS-exception.txt in this software distribution, or
+* online at
+* http://secondlifegrid.net/programs/open_source/licensing/flossexception
+*
+* By copying, modifying or distributing this software, you acknowledge
+* that you have read and understood your obligations described above,
+* and agree to abide by those obligations.
+*
+* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+* COMPLETENESS OR PERFORMANCE.
+* $/LicenseInfo$
+*/
+
+#ifndef LL_NOTIFICATIONSTORAGE_H
+#define LL_NOTIFICATIONSTORAGE_H
+
+#include "llnotifications.h"
+
+// Class that saves not responded(unread) notifications.
+// Unread notifications are saved in open_notifications.xml in SL account folder
+//
+// Notifications that should be saved(if unread) are marked with persist="true" in notifications.xml
+// Notifications using functor responders are saved automatically (see llviewermessage.cpp
+// lure_callback_reg for example).
+// Notifications using object responders(LLOfferInfo) need additional tuning. Responder object should
+// be a) serializable(implement LLNotificationResponderInterface),
+// b) registered with LLResponderRegistry (found in llnotificationstorage.cpp).
+class LLPersistentNotificationStorage : public LLSingleton<LLPersistentNotificationStorage>
+{
+ LOG_CLASS(LLPersistentNotificationStorage);
+public:
+
+ LLPersistentNotificationStorage();
+
+ void saveNotifications();
+
+ void loadNotifications();
+
+private:
+
+ bool onPersistentChannelChanged(const LLSD& payload);
+
+ std::string mFileName;
+};
+
+#endif // LL_NOTIFICATIONSTORAGE_H
diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp
index e528f871af..df6f04b6ea 100644
--- a/indra/newview/llnotificationtiphandler.cpp
+++ b/indra/newview/llnotificationtiphandler.cpp
@@ -45,38 +45,6 @@
using namespace LLNotificationsUI;
-class LLOnlineStatusToast : public LLPanelTipToast
-{
-public:
-
- struct Params
- {
- LLNotificationPtr notification;
- LLUUID avatar_id;
- std::string message;
-
- Params() {}
- };
-
- LLOnlineStatusToast(Params& p) : LLPanelTipToast(p.notification)
- {
- LLUICtrlFactory::getInstance()->buildPanel(this, "panel_online_status_toast.xml");
-
- childSetValue("avatar_icon", p.avatar_id);
- childSetValue("message", p.message);
-
- if (p.notification->getPayload().has("respond_on_mousedown")
- && p.notification->getPayload()["respond_on_mousedown"] )
- {
- setMouseDownCallback(boost::bind(&LLNotification::respond, p.notification,
- p.notification->getResponseTemplate()));
- }
-
- // set line max count to 3 in case of a very long name
- snapToMessageHeight(getChild<LLTextBox>("message"), 3);
- }
-};
-
//--------------------------------------------------------------------------
LLTipHandler::LLTipHandler(e_notification_type type, const LLSD& id)
{
@@ -157,28 +125,7 @@ bool LLTipHandler::processNotification(const LLSD& notify)
return true;
}
- LLToastPanel* notify_box = NULL;
- // TODO: this should be implemented in LLToastPanel::buidPanelFromNotification
- if("FriendOffline" == notification->getName() || "FriendOnline" == notification->getName())
- {
- LLOnlineStatusToast::Params p;
- p.notification = notification;
- p.message = notification->getMessage();
- p.avatar_id = notification->getPayload()["FROM_ID"];
- notify_box = new LLOnlineStatusToast(p);
- }
- else
- {
- notify_box = LLToastPanel::buidPanelFromNotification(notification);
- }
-
- // TODO: this if statement should be removed after modification of
- // LLToastPanel::buidPanelFromNotification() to allow create generic tip panel
- // for all tip notifications except FriendOnline and FriendOffline
- if (notify_box == NULL)
- {
- notify_box = new LLToastNotifyPanel(notification);
- }
+ LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);
LLToast::Params p;
p.notif_id = notification->getID();
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
new file mode 100644
index 0000000000..ad42d80467
--- /dev/null
+++ b/indra/newview/lloutfitslist.cpp
@@ -0,0 +1,265 @@
+/**
+ * @file lloutfitslist.cpp
+ * @brief List of agent's outfits for My Appearance side panel.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lloutfitslist.h"
+
+#include "llaccordionctrl.h"
+#include "llaccordionctrltab.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+#include "llwearableitemslist.h"
+
+static LLRegisterPanelClassWrapper<LLOutfitsList> t_outfits_list("outfits_list");
+
+LLOutfitsList::LLOutfitsList()
+ : LLPanel()
+ , mAccordion(NULL)
+ , mListCommands(NULL)
+{}
+
+LLOutfitsList::~LLOutfitsList()
+{
+ if (gInventory.containsObserver(mCategoriesObserver))
+ {
+ gInventory.removeObserver(mCategoriesObserver);
+ delete mCategoriesObserver;
+ }
+
+ if (gInventory.containsObserver(this))
+ {
+ gInventory.removeObserver(this);
+ }
+}
+
+BOOL LLOutfitsList::postBuild()
+{
+ mAccordion = getChild<LLAccordionCtrl>("outfits_accordion");
+
+ mCategoriesObserver = new LLInventoryCategoriesObserver();
+ gInventory.addObserver(mCategoriesObserver);
+
+ gInventory.addObserver(this);
+
+ return TRUE;
+}
+
+//virtual
+void LLOutfitsList::changed(U32 mask)
+{
+ if (!gInventory.isInventoryUsable())
+ return;
+
+ // Start observing changes in "My Outfits" category.
+ const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ mCategoriesObserver->addCategory(outfits,
+ boost::bind(&LLOutfitsList::refreshList, this, outfits));
+
+ LLViewerInventoryCategory* category = gInventory.getCategory(outfits);
+ if (!category)
+ return;
+
+ // Fetch "My Outfits" contents and refresh the list to display
+ // initially fetched items. If not all items are fetched now
+ // the observer will refresh the list as soon as the new items
+ // arrive.
+ category->fetch();
+ refreshList(outfits);
+
+ // This observer is used to start the initial outfits fetch
+ // when inventory becomes usable. It is no longer needed because
+ // "My Outfits" category is now observed by
+ // LLInventoryCategoriesObserver.
+ gInventory.removeObserver(this);
+}
+
+void LLOutfitsList::refreshList(const LLUUID& category_id)
+{
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+
+ // Collect all sub-categories of a given category.
+ LLIsType is_category(LLAssetType::AT_CATEGORY);
+ gInventory.collectDescendentsIf(
+ category_id,
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_category);
+
+ uuid_vec_t vnew;
+
+ // Creating a vector of newly collected sub-categories UUIDs.
+ for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin();
+ iter != cat_array.end();
+ iter++)
+ {
+ vnew.push_back((*iter)->getUUID());
+ }
+
+ uuid_vec_t vcur;
+
+ // Creating a vector of currently displayed sub-categories UUIDs.
+ for (outfits_map_t::const_iterator iter = mOutfitsMap.begin();
+ iter != mOutfitsMap.end();
+ iter++)
+ {
+ vcur.push_back((*iter).first);
+ }
+
+ // Sorting both vectors to compare.
+ std::sort(vcur.begin(), vcur.end());
+ std::sort(vnew.begin(), vnew.end());
+
+ uuid_vec_t vadded;
+ uuid_vec_t vremoved;
+
+ uuid_vec_t::iterator it;
+ size_t maxsize = llmax(vcur.size(), vnew.size());
+ vadded.resize(maxsize);
+ vremoved.resize(maxsize);
+
+ // what to remove
+ it = set_difference(vcur.begin(), vcur.end(), vnew.begin(), vnew.end(), vremoved.begin());
+ vremoved.erase(it, vremoved.end());
+
+ // what to add
+ it = set_difference(vnew.begin(), vnew.end(), vcur.begin(), vcur.end(), vadded.begin());
+ vadded.erase(it, vadded.end());
+
+ // Handle added tabs.
+ for (uuid_vec_t::const_iterator iter = vadded.begin();
+ iter != vadded.end();
+ iter++)
+ {
+ const LLUUID cat_id = (*iter);
+ LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
+ if (!cat)
+ continue;
+
+ std::string name = cat->getName();
+
+ // *TODO: create accordion tabs and lists from XML.
+ LLAccordionCtrlTab::Params params;
+ params.name(name);
+ params.title(name);
+ params.rect(LLRect(0, 0, 315, 20));
+ params.display_children(false);
+ LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(params);
+
+ mAccordion->addCollapsibleCtrl(tab);
+
+ LLFlatListView::Params list_params;
+ LLWearableItemsList* list = LLUICtrlFactory::create<LLWearableItemsList>(list_params);
+
+ tab->addChild(list, 0);
+ tab->setDisplayChildren(false);
+
+ // Map the new tab with outfit category UUID.
+ mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab));
+
+ // Start observing the new outfit category.
+ mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id));
+
+ // Fetch the new outfit contents.
+ cat->fetch();
+
+ // Refresh the list of outfit items after fetch().
+ // Further list updates will be triggered by the category observer.
+ list->updateList(cat_id);
+ }
+
+ // Handle removed tabs.
+ for (uuid_vec_t::const_iterator iter=vremoved.begin(); iter != vremoved.end(); iter++)
+ {
+ outfits_map_t::iterator outfits_iter = mOutfitsMap.find((*iter));
+ if (outfits_iter != mOutfitsMap.end())
+ {
+ // An outfit is removed from the list. Do the following:
+ // 1. Remove outfit accordion tab from accordion.
+ mAccordion->removeCollapsibleCtrl(outfits_iter->second);
+
+ // 2. Remove outfit category from observer to stop monitoring its changes.
+ mCategoriesObserver->removeCategory(outfits_iter->first);
+
+ // 3. Remove category UUID to accordion tab mapping.
+ mOutfitsMap.erase(outfits_iter);
+ }
+ }
+
+ // Get changed items from inventory model and update outfit tabs
+ // which might have been renamed.
+ const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs();
+ for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
+ items_iter != changed_items.end();
+ ++items_iter)
+ {
+ updateOutfitTab(*items_iter);
+ }
+
+ mAccordion->arrange();
+}
+
+void LLOutfitsList::updateOutfitTab(const LLUUID& category_id)
+{
+ outfits_map_t::iterator outfits_iter = mOutfitsMap.find(category_id);
+ if (outfits_iter != mOutfitsMap.end())
+ {
+ LLViewerInventoryCategory *cat = gInventory.getCategory(category_id);
+ if (!cat)
+ return;
+
+ std::string name = cat->getName();
+
+ // Update tab name with the new category name.
+ LLAccordionCtrlTab* tab = outfits_iter->second;
+ if (tab)
+ {
+ tab->setName(name);
+ }
+
+ // Update tab title with the new category name using textbox
+ // in accordion tab header.
+ LLTextBox* tab_title = tab->findChild<LLTextBox>("dd_textbox");
+ if (tab_title)
+ {
+ tab_title->setText(name);
+ }
+ }
+}
+
+void LLOutfitsList::setFilterSubString(const std::string& string)
+{
+ mFilterSubString = string;
+}
+
+// EOF
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
new file mode 100644
index 0000000000..892e0a862a
--- /dev/null
+++ b/indra/newview/lloutfitslist.h
@@ -0,0 +1,74 @@
+/**
+ * @file lloutfitslist.h
+ * @brief List of agent's outfits for My Appearance side panel.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLOUTFITSLIST_H
+#define LL_LLOUTFITSLIST_H
+
+#include "llpanel.h"
+
+// newview
+#include "llinventoryobserver.h"
+
+class LLAccordionCtrl;
+class LLAccordionCtrlTab;
+class LLWearableItemsList;
+
+class LLOutfitsList : public LLPanel, public LLInventoryObserver
+{
+public:
+ LLOutfitsList();
+ virtual ~LLOutfitsList();
+
+ /*virtual*/ BOOL postBuild();
+
+ /*virtual*/ void changed(U32 mask);
+
+ void refreshList(const LLUUID& category_id);
+
+ // Update tab displaying outfit identified by category_id.
+ void updateOutfitTab(const LLUUID& category_id);
+
+ void setFilterSubString(const std::string& string);
+
+private:
+ LLInventoryCategoriesObserver* mCategoriesObserver;
+
+ LLAccordionCtrl* mAccordion;
+ LLPanel* mListCommands;
+
+ std::string mFilterSubString;
+
+ typedef std::map<LLUUID, LLAccordionCtrlTab*> outfits_map_t;
+ typedef outfits_map_t::value_type outfits_map_value_t;
+ outfits_map_t mOutfitsMap;
+};
+
+#endif //LL_LLOUTFITSLIST_H
diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h
index 136868a60d..359f252383 100644
--- a/indra/newview/llpanelgroup.h
+++ b/indra/newview/llpanelgroup.h
@@ -37,7 +37,7 @@
#include "lltimer.h"
#include "llvoiceclient.h"
-struct LLOfferInfo;
+class LLOfferInfo;
const S32 UPDATE_MEMBERS_PER_FRAME = 500;
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index ee4dcc44fe..529a368dc3 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -1007,7 +1007,7 @@ void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
{
if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE)
{
- LLNotificationsUtil::add("CapsKeyOn");
+// *TODO: use another way to notify user about enabled caps lock, see EXT-6858
sCapslockDidNotification = TRUE;
}
}
diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp
index 35acf8edcc..3f620869e0 100644
--- a/indra/newview/llpanelme.cpp
+++ b/indra/newview/llpanelme.cpp
@@ -63,7 +63,6 @@ BOOL LLPanelMe::postBuild()
LLPanelProfile::postBuild();
getTabContainer()[PANEL_PROFILE]->childSetAction("edit_profile_btn", boost::bind(&LLPanelMe::onEditProfileClicked, this), this);
- getTabContainer()[PANEL_PROFILE]->childSetAction("edit_appearance_btn", boost::bind(&LLPanelMe::onEditAppearanceClicked, this), this);
return TRUE;
}
@@ -141,14 +140,6 @@ void LLPanelMe::onEditProfileClicked()
togglePanel(mEditPanel, getAvatarId()); // open
}
-void LLPanelMe::onEditAppearanceClicked()
-{
- if (gAgentWearables.areWearablesLoaded())
- {
- gAgentCamera.changeCameraToCustomizeAvatar();
- }
-}
-
void LLPanelMe::onSaveChangesClicked()
{
LLAvatarData data = LLAvatarData();
diff --git a/indra/newview/llpanelme.h b/indra/newview/llpanelme.h
index 1325192bbf..f2b38de3d6 100644
--- a/indra/newview/llpanelme.h
+++ b/indra/newview/llpanelme.h
@@ -63,7 +63,6 @@ private:
void buildEditPanel();
void onEditProfileClicked();
- void onEditAppearanceClicked();
void onSaveChangesClicked();
void onCancelClicked();
diff --git a/indra/newview/llpanelonlinestatus.cpp b/indra/newview/llpanelonlinestatus.cpp
new file mode 100644
index 0000000000..6ba015b11c
--- /dev/null
+++ b/indra/newview/llpanelonlinestatus.cpp
@@ -0,0 +1,60 @@
+/**
+ * @file llpanelonlinestatus.cpp
+ * @brief Represents a class of online status tip toast panels.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llnotifications.h"
+#include "llpanelonlinestatus.h"
+
+LLPanelOnlineStatus::LLPanelOnlineStatus(
+ const LLNotificationPtr& notification) :
+ LLPanelTipToast(notification)
+{
+
+ LLUICtrlFactory::getInstance()->buildPanel(this,
+ "panel_online_status_toast.xml");
+
+
+ childSetValue("avatar_icon", notification->getPayload()["FROM_ID"]);
+ childSetValue("message", notification->getMessage());
+
+ if (notification->getPayload().has("respond_on_mousedown")
+ && notification->getPayload()["respond_on_mousedown"])
+ {
+ setMouseDownCallback(boost::bind(&LLNotification::respond,
+ notification, notification->getResponseTemplate()));
+ }
+
+ // set line max count to 3 in case of a very long name
+ snapToMessageHeight(getChild<LLTextBox> ("message"), 3);
+
+}
diff --git a/indra/newview/llpanelonlinestatus.h b/indra/newview/llpanelonlinestatus.h
new file mode 100644
index 0000000000..b47050c3a2
--- /dev/null
+++ b/indra/newview/llpanelonlinestatus.h
@@ -0,0 +1,53 @@
+/**
+ * @file llpanelonlinestatus.h
+ * @brief Represents a class of online status tip toast panels.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "llpaneltiptoast.h"
+
+#ifndef LL_PANELONLINESTATUS_H
+#define LL_PANELONLINESTATUS_H
+
+/**
+ * Represents online tip toast panel.
+ */
+class LLPanelOnlineStatus : public LLPanelTipToast
+{
+ // disallow instantiation of this class
+private:
+ // grant privileges to instantiate this class to LLToastPanel
+ friend class LLToastPanel;
+
+ LLPanelOnlineStatus(const LLNotificationPtr& notification);
+ virtual ~LLPanelOnlineStatus() {}
+};
+
+#endif /* LL_PANELONLINESTATUS_H */
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
index b78268da7b..789e85b46f 100644
--- a/indra/newview/llpaneloutfitsinventory.cpp
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -49,6 +49,7 @@
#include "lllineeditor.h"
#include "llmodaldialog.h"
#include "llnotificationsutil.h"
+#include "lloutfitslist.h"
#include "llsidepanelappearance.h"
#include "llsidetray.h"
#include "lltabcontainer.h"
@@ -71,7 +72,8 @@ bool LLPanelOutfitsInventory::sShowDebugEditor = false;
LLPanelOutfitsInventory::LLPanelOutfitsInventory() :
- mActivePanel(NULL),
+ mMyOutfitsPanel(NULL),
+ mCurrentOutfitPanel(NULL),
mParent(NULL)
{
mSavedFolderState = new LLSaveFolderState();
@@ -145,9 +147,17 @@ void LLPanelOutfitsInventory::setParent(LLSidepanelAppearance* parent)
void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
{
mFilterSubString = string;
+
+ // TODO: add handling "My Outfits" tab.
+ if (!isCOFPanelActive())
+ {
+ mMyOutfitsPanel->setFilterSubString(string);
+ return;
+ }
+
if (string == "")
{
- mActivePanel->setFilterSubString(LLStringUtil::null);
+ getActivePanel()->setFilterSubString(LLStringUtil::null);
// re-open folders that were initially open
mSavedFolderState->setApply(TRUE);
@@ -159,7 +169,7 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
LLInventoryModelBackgroundFetch::instance().start();
- if (mActivePanel->getFilterSubString().empty() && string.empty())
+ if (getActivePanel()->getFilterSubString().empty() && string.empty())
{
// current filter and new filter empty, do nothing
return;
@@ -173,7 +183,7 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
}
// set new filter string
- mActivePanel->setFilterSubString(string);
+ getActivePanel()->setFilterSubString(string);
}
void LLPanelOutfitsInventory::onWearButtonClick()
@@ -216,7 +226,7 @@ bool LLPanelOutfitsInventory::onSaveCommit(const LLSD& notification, const LLSD&
LLStringUtil::trim(outfit_name);
if( !outfit_name.empty() )
{
- LLUUID outfit_folder = gAgentWearables.makeNewOutfitLinks(outfit_name);
+ LLUUID outfit_folder = LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name);
LLSidepanelAppearance* panel_appearance =
dynamic_cast<LLSidepanelAppearance *>(LLSideTray::getInstance()->getPanel("sidepanel_appearance"));
@@ -267,6 +277,11 @@ void LLPanelOutfitsInventory::onSave()
void LLPanelOutfitsInventory::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action)
{
updateVerbs();
+
+ // TODO: add handling "My Outfits" tab.
+ if (!isCOFPanelActive())
+ return;
+
if (getRootFolder()->needsAutoRename() && items.size())
{
getRootFolder()->startRenamingSelectedItem();
@@ -284,6 +299,10 @@ void LLPanelOutfitsInventory::showEditOutfitPanel()
LLFolderViewEventListener *LLPanelOutfitsInventory::getCorrectListenerForAction()
{
+ // TODO: add handling "My Outfits" tab.
+ if (!isCOFPanelActive())
+ return NULL;
+
LLFolderViewItem* current_item = getRootFolder()->getCurSelectedItem();
if (!current_item)
return NULL;
@@ -311,7 +330,7 @@ bool LLPanelOutfitsInventory::getIsCorrectType(const LLFolderViewEventListener *
LLFolderView *LLPanelOutfitsInventory::getRootFolder()
{
- return mActivePanel->getRootFolder();
+ return getActivePanel()->getRootFolder();
}
//static
@@ -393,7 +412,11 @@ void LLPanelOutfitsInventory::onTrashButtonClick()
void LLPanelOutfitsInventory::onClipboardAction(const LLSD& userdata)
{
std::string command_name = userdata.asString();
- getActivePanel()->getRootFolder()->doToSelected(getActivePanel()->getModel(),command_name);
+ // TODO: add handling "My Outfits" tab.
+ if (isCOFPanelActive())
+ {
+ getActivePanel()->getRootFolder()->doToSelected(getActivePanel()->getModel(),command_name);
+ }
updateListCommands();
updateVerbs();
}
@@ -447,21 +470,26 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)
if (command_name == "delete" || command_name == "remove")
{
BOOL can_delete = FALSE;
- LLFolderView* root = getActivePanel()->getRootFolder();
- if (root)
+
+ // TODO: add handling "My Outfits" tab.
+ if (isCOFPanelActive())
{
- std::set<LLUUID> selection_set;
- root->getSelectionList(selection_set);
- can_delete = (selection_set.size() > 0);
- for (std::set<LLUUID>::iterator iter = selection_set.begin();
- iter != selection_set.end();
- ++iter)
+ LLFolderView* root = getActivePanel()->getRootFolder();
+ if (root)
{
- const LLUUID &item_id = (*iter);
- LLFolderViewItem *item = root->getItemByID(item_id);
- can_delete &= item->getListener()->isItemRemovable();
+ std::set<LLUUID> selection_set;
+ root->getSelectionList(selection_set);
+ can_delete = (selection_set.size() > 0);
+ for (std::set<LLUUID>::iterator iter = selection_set.begin();
+ iter != selection_set.end();
+ ++iter)
+ {
+ const LLUUID &item_id = (*iter);
+ LLFolderViewItem *item = root->getItemByID(item_id);
+ can_delete &= item->getListener()->isItemRemovable();
+ }
+ return can_delete;
}
- return can_delete;
}
return FALSE;
}
@@ -517,12 +545,17 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)
bool LLPanelOutfitsInventory::hasItemsSelected()
{
bool has_items_selected = false;
- LLFolderView* root = getActivePanel()->getRootFolder();
- if (root)
+
+ // TODO: add handling "My Outfits" tab.
+ if (isCOFPanelActive())
{
- std::set<LLUUID> selection_set;
- root->getSelectionList(selection_set);
- has_items_selected = (selection_set.size() > 0);
+ LLFolderView* root = getActivePanel()->getRootFolder();
+ if (root)
+ {
+ std::set<LLUUID> selection_set;
+ root->getSelectionList(selection_set);
+ has_items_selected = (selection_set.size() > 0);
+ }
}
return has_items_selected;
}
@@ -549,74 +582,58 @@ bool LLPanelOutfitsInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropTy
void LLPanelOutfitsInventory::initTabPanels()
{
- LLInventoryPanel *cof_panel = getChild<LLInventoryPanel>(COF_TAB_NAME);
- cof_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
- mTabPanels.push_back(cof_panel);
+ mCurrentOutfitPanel = getChild<LLInventoryPanel>(COF_TAB_NAME);
+ mCurrentOutfitPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
+ mCurrentOutfitPanel->setSelectCallback(boost::bind(&LLPanelOutfitsInventory::onTabSelectionChange, this, mCurrentOutfitPanel, _1, _2));
- LLInventoryPanel *myoutfits_panel = getChild<LLInventoryPanel>(OUTFITS_TAB_NAME);
- myoutfits_panel->setFilterTypes(1LL << LLFolderType::FT_OUTFIT, LLInventoryFilter::FILTERTYPE_CATEGORY);
- myoutfits_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
- mTabPanels.push_back(myoutfits_panel);
-
- for (tabpanels_vec_t::iterator iter = mTabPanels.begin();
- iter != mTabPanels.end();
- ++iter)
- {
- LLInventoryPanel *panel = (*iter);
- panel->setSelectCallback(boost::bind(&LLPanelOutfitsInventory::onTabSelectionChange, this, panel, _1, _2));
- }
+ mMyOutfitsPanel = getChild<LLOutfitsList>(OUTFITS_TAB_NAME);
mAppearanceTabs = getChild<LLTabContainer>("appearance_tabs");
mAppearanceTabs->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::onTabChange, this));
- mActivePanel = (LLInventoryPanel*)mAppearanceTabs->getCurrentPanel();
}
void LLPanelOutfitsInventory::onTabSelectionChange(LLInventoryPanel* tab_panel, const std::deque<LLFolderViewItem*> &items, BOOL user_action)
{
if (user_action && items.size() > 0)
{
- for (tabpanels_vec_t::iterator iter = mTabPanels.begin();
- iter != mTabPanels.end();
- ++iter)
+ // TODO: add handling "My Outfits" tab.
+ if (isCOFPanelActive())
{
- LLInventoryPanel *panel = (*iter);
- if (panel == tab_panel)
- {
- mActivePanel = panel;
- }
- else
- {
- panel->getRootFolder()->clearSelection();
- }
+ onSelectionChange(items, user_action);
+ }
+ else
+ {
+ mCurrentOutfitPanel->getRootFolder()->clearSelection();
}
}
- onSelectionChange(items, user_action);
}
void LLPanelOutfitsInventory::onTabChange()
{
- mActivePanel = (LLInventoryPanel*)childGetVisibleTab("appearance_tabs");
- if (!mActivePanel)
+ // TODO: add handling "My Outfits" tab.
+ if (isCOFPanelActive())
{
- return;
+ mCurrentOutfitPanel->setFilterSubString(mFilterSubString);
+ }
+ else
+ {
+ mMyOutfitsPanel->setFilterSubString(mFilterSubString);
}
- mActivePanel->setFilterSubString(mFilterSubString);
+
updateVerbs();
}
BOOL LLPanelOutfitsInventory::isTabPanel(LLInventoryPanel *panel) const
{
- for(tabpanels_vec_t::const_iterator it = mTabPanels.begin();
- it != mTabPanels.end();
- ++it)
+ // TODO: add handling "My Outfits" tab.
+ if (mCurrentOutfitPanel == panel)
{
- if (*it == panel)
- return TRUE;
+ return TRUE;
}
return FALSE;
}
BOOL LLPanelOutfitsInventory::isCOFPanelActive() const
{
- return (getActivePanel()->getName() == COF_TAB_NAME);
+ return (childGetVisibleTab("appearance_tabs")->getName() == COF_TAB_NAME);
}
diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h
index 5d0d27ee4f..4234cc45c5 100644
--- a/indra/newview/llpaneloutfitsinventory.h
+++ b/indra/newview/llpaneloutfitsinventory.h
@@ -40,6 +40,7 @@ class LLFolderView;
class LLFolderViewItem;
class LLFolderViewEventListener;
class LLInventoryPanel;
+class LLOutfitsList;
class LLSaveFolderState;
class LLButton;
class LLMenuGL;
@@ -88,20 +89,21 @@ private:
public:
//////////////////////////////////////////////////////////////////////////////////
// tab panels
- LLInventoryPanel* getActivePanel() { return mActivePanel; }
- const LLInventoryPanel* getActivePanel() const { return mActivePanel; }
+ // TODO: change getActivePanel() to return the active tab instead of returning
+ // a pointer to "Wearing" inventory panel.
+ LLInventoryPanel* getActivePanel() { return mCurrentOutfitPanel; }
+
BOOL isTabPanel(LLInventoryPanel *panel) const;
-
+ BOOL isCOFPanelActive() const;
+
protected:
void initTabPanels();
void onTabSelectionChange(LLInventoryPanel* tab_panel, const std::deque<LLFolderViewItem*> &items, BOOL user_action);
void onTabChange();
- BOOL isCOFPanelActive() const;
private:
- LLInventoryPanel* mActivePanel;
- typedef std::vector<LLInventoryPanel *> tabpanels_vec_t;
- tabpanels_vec_t mTabPanels;
+ LLOutfitsList* mMyOutfitsPanel;
+ LLInventoryPanel* mCurrentOutfitPanel;
// tab panels //
////////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index daa2a04f65..f60951ca66 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -645,6 +645,23 @@ void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI,
updateButtons();
}
+void LLPanelPeople::updateFriendListHelpText()
+{
+ // show special help text for just created account to help finding friends. EXT-4836
+ static LLTextBox* no_friends_text = getChild<LLTextBox>("no_friends_help_text");
+
+ // Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...)
+ // So, lets check all lists to avoid overlapping the text with online list. See EXT-6448.
+ bool any_friend_exists = mAllFriendList->filterHasMatches() || mOnlineFriendList->filterHasMatches();
+ no_friends_text->setVisible(!any_friend_exists);
+ if (no_friends_text->getVisible())
+ {
+ //update help text for empty lists
+ std::string message_name = mFilterSubString.empty() ? "no_friends_msg" : "no_filtered_friends_msg";
+ no_friends_text->setText(getString(message_name));
+ }
+}
+
void LLPanelPeople::updateFriendList()
{
if (!mOnlineFriendList || !mAllFriendList)
@@ -684,14 +701,6 @@ void LLPanelPeople::updateFriendList()
online_friendsp.push_back(buddy_id);
}
- // show special help text for just created account to help found friends. EXT-4836
- static LLTextBox* no_friends_text = getChild<LLTextBox>("no_friends_msg");
-
- // Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...)
- // So, lets check all lists to avoid overlapping the text with online list. See EXT-6448.
- bool any_friend_exists = (all_friendsp.size() > 0) || (online_friendsp.size() > 0);
- no_friends_text->setVisible(!any_friend_exists);
-
/*
* Avatarlists will be hidden by showFriendsAccordionsIfNeeded(), if they do not have items.
* But avatarlist can be updated only if it is visible @see LLAvatarList::draw();
@@ -1436,6 +1445,9 @@ void LLPanelPeople::showFriendsAccordionsIfNeeded()
// Rearrange accordions
LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion");
accordion->arrange();
+
+ // keep help text in a synchronization with accordions visibility.
+ updateFriendListHelpText();
}
}
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index 891381e2de..1bd3ea471c 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -73,6 +73,7 @@ private:
} ESortOrder;
// methods indirectly called by the updaters
+ void updateFriendListHelpText();
void updateFriendList();
void updateNearbyList();
void updateRecentList();
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index 17784c31e3..89293d0e50 100644
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -1071,8 +1071,7 @@ void LLPanelPlaces::updateVerbs()
mSaveBtn->setVisible(isLandmarkEditModeOn);
mCancelBtn->setVisible(isLandmarkEditModeOn);
mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn);
- mPlaceInfoBtn->setVisible(mPlaceInfoType != LANDMARK_INFO_TYPE && mPlaceInfoType != TELEPORT_HISTORY_INFO_TYPE
- && !is_create_landmark_visible && !isLandmarkEditModeOn);
+ mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn);
mShowOnMapBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos);
mPlaceInfoBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos);
diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp
index f35cb3516a..11b6c0a3ae 100644
--- a/indra/newview/llscriptfloater.cpp
+++ b/indra/newview/llscriptfloater.cpp
@@ -539,4 +539,14 @@ bool LLScriptFloaterManager::getFloaterPosition(const LLUUID& object_id, Floater
return false;
}
+void LLScriptFloaterManager::setFloaterVisible(const LLUUID& notification_id, bool visible)
+{
+ LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>(
+ "script_floater", notification_id);
+ if(floater)
+ {
+ floater->setVisible(visible);
+ }
+}
+
// EOF
diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h
index ec3ec4b540..dc0cfc2400 100644
--- a/indra/newview/llscriptfloater.h
+++ b/indra/newview/llscriptfloater.h
@@ -99,6 +99,8 @@ public:
bool getFloaterPosition(const LLUUID& object_id, FloaterPositionInfo& fpi);
+ void setFloaterVisible(const LLUUID& notification_id, bool visible);
+
protected:
typedef std::map<std::string, EObjectType> object_type_map;
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index abef47d4be..87494daaa9 100644
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -329,8 +329,8 @@ void LLSidepanelAppearance::updateVerbs()
if (mPanelOutfitsInventory && !is_look_info_visible)
{
- const bool is_correct_type = (mPanelOutfitsInventory->getCorrectListenerForAction() != NULL);
- mEditBtn->setEnabled(is_correct_type);
+// const bool is_correct_type = (mPanelOutfitsInventory->getCorrectListenerForAction() != NULL);
+// mEditBtn->setEnabled(is_correct_type);
}
else
{
diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp
index 22b12ee132..568cd4cb19 100644
--- a/indra/newview/lltoast.cpp
+++ b/indra/newview/lltoast.cpp
@@ -67,6 +67,7 @@ LLToast::Params::Params()
LLToast::LLToast(const LLToast::Params& p)
: LLModalDialog(LLSD(), p.is_modal),
mPanel(p.panel),
+ mToastLifetime(p.lifetime_secs),
mToastFadingTime(p.fading_time_secs),
mNotificationID(p.notif_id),
mSessionID(p.session_id),
@@ -241,6 +242,13 @@ void LLToast::draw()
drawChild(mHideBtn);
}
}
+
+ // if timer started and remaining time <= fading time
+ if (mTimer->getStarted() && (mToastLifetime
+ - mTimer->getEventTimer().getElapsedTimeF32()) <= mToastFadingTime)
+ {
+ setBackgroundOpaque(FALSE);
+ }
}
//--------------------------------------------------------------------------
diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h
index 4a213580da..4211f21ef1 100644
--- a/indra/newview/lltoast.h
+++ b/indra/newview/lltoast.h
@@ -209,6 +209,7 @@ private:
// timer counts a lifetime of a toast
std::auto_ptr<LLToastLifeTimer> mTimer;
+ F32 mToastLifetime; // in seconds
F32 mToastFadingTime; // in seconds
LLPanel* mPanel;
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp
index c9d2d404c0..089163929e 100644
--- a/indra/newview/lltoastnotifypanel.cpp
+++ b/indra/newview/lltoastnotifypanel.cpp
@@ -493,7 +493,7 @@ void LLToastNotifyPanel::onClickButton(void* data)
{
sButtonClickSignal(self->mNotification->getID(), button_name);
- if(new_info)
+ if(new_info && !self->mNotification->isPersistent())
{
self->mNotification->setResponseFunctor(
boost::bind(&LLOfferInfo::inventory_offer_callback, new_info, _1, _2));
diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp
index d142a0665b..71598b3169 100644
--- a/indra/newview/lltoastpanel.cpp
+++ b/indra/newview/lltoastpanel.cpp
@@ -33,6 +33,7 @@
#include "llviewerprecompiledheaders.h"
#include "llpanelgenerictip.h"
+#include "llpanelonlinestatus.h"
#include "llnotifications.h"
#include "lltoastpanel.h"
@@ -97,9 +98,19 @@ LLToastPanel* LLToastPanel::buidPanelFromNotification(
{
LLToastPanel* res = NULL;
- if (notification->getName() == "SystemMessageTip")
+ //process tip toast panels
+ if ("notifytip" == notification->getType())
{
- res = new LLPanelGenericTip(notification);
+ // if it is online/offline notification
+ if ("FriendOffline" == notification->getName() || "FriendOnline" == notification->getName())
+ {
+ res = new LLPanelOnlineStatus(notification);
+ }
+ // in all other case we use generic tip panel
+ else
+ {
+ res = new LLPanelGenericTip(notification);
+ }
}
/*
else if(...)
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 8a891b1462..f434d15843 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -923,6 +923,7 @@ void link_inventory_item(
const LLUUID& item_id,
const LLUUID& parent_id,
const std::string& new_name,
+ const std::string& new_description,
const LLAssetType::EType asset_type,
LLPointer<LLInventoryCallback> cb)
{
@@ -948,7 +949,6 @@ void link_inventory_item(
}
LLUUID transaction_id;
- std::string desc = "Broken link"; // This should only show if the object can't find its baseobj.
LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;
if (dynamic_cast<const LLInventoryCategory *>(baseobj))
{
@@ -979,7 +979,7 @@ void link_inventory_item(
msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);
msg->addStringFast(_PREHASH_Name, new_name);
- msg->addStringFast(_PREHASH_Description, desc);
+ msg->addStringFast(_PREHASH_Description, new_description);
}
gAgent.sendReliableMessage();
}
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 9d449399e8..f296ce35ff 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -339,6 +339,7 @@ void link_inventory_item(
const LLUUID& item_id,
const LLUUID& parent_id,
const std::string& new_name,
+ const std::string& new_description,
const LLAssetType::EType asset_type,
LLPointer<LLInventoryCallback> cb);
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index bc4e20d706..9c66279d31 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -1247,6 +1247,16 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id,
gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id));
}
+LLOfferInfo::LLOfferInfo()
+ : LLNotificationResponderInterface()
+ , mFromGroup(FALSE)
+ , mFromObject(FALSE)
+ , mIM(IM_NOTHING_SPECIAL)
+ , mType(LLAssetType::AT_NONE)
+ , mPersist(false)
+{
+}
+
LLOfferInfo::LLOfferInfo(const LLSD& sd)
{
mIM = (EInstantMessage)sd["im_type"].asInteger();
@@ -1260,6 +1270,7 @@ LLOfferInfo::LLOfferInfo(const LLSD& sd)
mFromName = sd["from_name"].asString();
mDesc = sd["description"].asString();
mHost = LLHost(sd["sender"].asString());
+ mPersist = sd["persist"].asBoolean();
}
LLOfferInfo::LLOfferInfo(const LLOfferInfo& info)
@@ -1275,6 +1286,7 @@ LLOfferInfo::LLOfferInfo(const LLOfferInfo& info)
mFromName = info.mFromName;
mDesc = info.mDesc;
mHost = info.mHost;
+ mPersist = info.mPersist;
}
LLSD LLOfferInfo::asLLSD()
@@ -1291,9 +1303,15 @@ LLSD LLOfferInfo::asLLSD()
sd["from_name"] = mFromName;
sd["description"] = mDesc;
sd["sender"] = mHost.getIPandPort();
+ sd["persist"] = mPersist;
return sd;
}
+void LLOfferInfo::fromLLSD(const LLSD& params)
+{
+ *this = params;
+}
+
void LLOfferInfo::send_auto_receive_response(void)
{
LLMessageSystem* msg = gMessageSystem;
@@ -1333,6 +1351,21 @@ void LLOfferInfo::send_auto_receive_response(void)
}
}
+void LLOfferInfo::handleRespond(const LLSD& notification, const LLSD& response)
+{
+ initRespondFunctionMap();
+
+ const std::string name = notification["name"].asString();
+ if(mRespondFunctions.find(name) == mRespondFunctions.end())
+ {
+ llwarns << "Unexpected notification name : " << name << llendl;
+ llassert(!"Unexpected notification name");
+ return;
+ }
+
+ mRespondFunctions[name](notification, response);
+}
+
bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response)
{
LLChat chat;
@@ -1469,7 +1502,10 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
gInventory.addObserver(opener);
}
- delete this;
+ if(!mPersist)
+ {
+ delete this;
+ }
return false;
}
@@ -1635,7 +1671,10 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
gInventory.addObserver(opener);
}
- delete this;
+ if(!mPersist)
+ {
+ delete this;
+ }
return false;
}
@@ -1651,6 +1690,15 @@ protected:
}
};
+void LLOfferInfo::initRespondFunctionMap()
+{
+ if(mRespondFunctions.empty())
+ {
+ mRespondFunctions["ObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2);
+ mRespondFunctions["UserGiveItem"] = boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2);
+ }
+}
+
void inventory_offer_handler(LLOfferInfo* info)
{
//Until throttling is implmented, busy mode should reject inventory instead of silently
@@ -1767,7 +1815,8 @@ void inventory_offer_handler(LLOfferInfo* info)
// Inventory Slurls don't currently work for non agent transfers, so only display the object name.
args["ITEM_SLURL"] = msg;
// Note: sets inventory_task_offer_callback as the callback
- p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_task_offer_callback, info, _1, _2));
+ p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info));
+ info->mPersist = true;
p.name = name_found ? "ObjectGiveItem" : "ObjectGiveItemUnknownUser";
// Pop up inv offer chiclet and let the user accept (keep), or reject (and silently delete) the inventory.
LLNotifications::instance().add(p);
@@ -1779,7 +1828,8 @@ void inventory_offer_handler(LLOfferInfo* info)
// *TODO fix memory leak
// inventory_offer_callback() is not invoked if user received notification and
// closes viewer(without responding the notification)
- p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2));
+ p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info));
+ info->mPersist = true;
p.name = "UserGiveItem";
// Prefetch the item into your local inventory.
@@ -1800,10 +1850,8 @@ void inventory_offer_handler(LLOfferInfo* info)
// Inform user that there is a script floater via toast system
{
payload["give_inventory_notification"] = TRUE;
- LLNotification::Params params(p.name);
- params.substitutions = p.substitutions;
- params.payload = payload;
- LLPostponedNotification::add<LLPostponedOfferNotification>( params, info->mFromID, false);
+ p.payload = payload;
+ LLPostponedNotification::add<LLPostponedOfferNotification>(p, info->mFromID, false);
}
}
}
diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h
index 7c021dc05f..72ad3c8926 100644
--- a/indra/newview/llviewermessage.h
+++ b/indra/newview/llviewermessage.h
@@ -40,6 +40,7 @@
#include "lluuid.h"
#include "message.h"
#include "stdenums.h"
+#include "llnotifications.h"
//
// Forward declarations
@@ -210,11 +211,10 @@ bool highlight_offered_item(const LLUUID& item_id);
void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid);
-struct LLOfferInfo
+class LLOfferInfo : public LLNotificationResponderInterface
{
- LLOfferInfo()
- : mFromGroup(FALSE), mFromObject(FALSE),
- mIM(IM_NOTHING_SPECIAL), mType(LLAssetType::AT_NONE) {};
+public:
+ LLOfferInfo();
LLOfferInfo(const LLSD& sd);
LLOfferInfo(const LLOfferInfo& info);
@@ -232,12 +232,27 @@ struct LLOfferInfo
std::string mFromName;
std::string mDesc;
LLHost mHost;
+ bool mPersist;
+
+ // LLNotificationResponderInterface implementation
+ /*virtual*/ LLSD asLLSD();
+ /*virtual*/ void fromLLSD(const LLSD& params);
+ /*virtual*/ void handleRespond(const LLSD& notification, const LLSD& response);
- LLSD asLLSD();
void send_auto_receive_response(void);
+
+ // TODO - replace all references with handleRespond()
bool inventory_offer_callback(const LLSD& notification, const LLSD& response);
bool inventory_task_offer_callback(const LLSD& notification, const LLSD& response);
+private:
+
+ void initRespondFunctionMap();
+
+ typedef boost::function<bool (const LLSD&, const LLSD&)> respond_function_t;
+ typedef std::map<std::string, respond_function_t> respond_function_map_t;
+
+ respond_function_map_t mRespondFunctions;
};
void process_feature_disabled_message(LLMessageSystem* msg, void**);
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
new file mode 100644
index 0000000000..ff309cbbc3
--- /dev/null
+++ b/indra/newview/llwearableitemslist.cpp
@@ -0,0 +1,88 @@
+/**
+ * @file llwearableitemslist.cpp
+ * @brief A flat list of wearable items.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llwearableitemslist.h"
+
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+
+class LLFindOutfitItems : public LLInventoryCollectFunctor
+{
+public:
+ LLFindOutfitItems() {}
+ virtual ~LLFindOutfitItems() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+};
+
+bool LLFindOutfitItems::operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item)
+{
+ if(item)
+ {
+ if((item->getType() == LLAssetType::AT_CLOTHING)
+ || (item->getType() == LLAssetType::AT_BODYPART)
+ || (item->getType() == LLAssetType::AT_OBJECT))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static const LLDefaultChildRegistry::Register<LLWearableItemsList> r("wearable_items_list");
+
+LLWearableItemsList::LLWearableItemsList(const LLFlatListView::Params& p)
+: LLInventoryItemsList(p)
+{}
+
+// virtual
+LLWearableItemsList::~LLWearableItemsList()
+{}
+
+void LLWearableItemsList::updateList(const LLUUID& category_id)
+{
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+
+ LLFindOutfitItems collector = LLFindOutfitItems();
+ // collectDescendentsIf takes non-const reference:
+ gInventory.collectDescendentsIf(
+ category_id,
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ collector);
+
+ refreshList(item_array);
+}
diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h
new file mode 100644
index 0000000000..e3b011912b
--- /dev/null
+++ b/indra/newview/llwearableitemslist.h
@@ -0,0 +1,56 @@
+/**
+ * @file llwearableitemslist.h
+ * @brief A flat list of wearable items.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLWEARABLEITEMSLIST_H
+#define LL_LLWEARABLEITEMSLIST_H
+
+#include "llpanel.h"
+
+#include "llassettype.h"
+
+#include "llinventorytype.h"
+
+// newview
+#include "llinventoryitemslist.h"
+
+class LLWearableItemsList : public LLInventoryItemsList
+{
+public:
+ virtual ~LLWearableItemsList();
+
+ void updateList(const LLUUID& category_id);
+
+protected:
+ friend class LLUICtrlFactory;
+ LLWearableItemsList(const LLFlatListView::Params& p);
+};
+
+#endif //LL_LLWEARABLEITEMSLIST_H
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 151180aae7..081a3721b1 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -1072,18 +1072,10 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
// zoomed out, so don't display anything about the count. JC
if (agent_count > 0)
{
- // Merov: i18n horror!!! Even using gettext(), concatenating strings is not localizable.
- // The singular/plural switch form here under might make no sense in some languages. Don't do that.
- message += llformat("\n%d ", agent_count);
-
- if (agent_count == 1)
- {
- message += "person";
- }
- else
- {
- message += "people";
- }
+ LLStringUtil::format_map_t string_args;
+ string_args["[NUMBER]"] = llformat("%d", agent_count);
+ message += '\n';
+ message += getString((agent_count == 1 ? "world_map_person" : "world_map_people") , string_args);
}
}
tooltip_msg.assign( message );
diff --git a/indra/newview/skins/default/xui/en/floater_im_container.xml b/indra/newview/skins/default/xui/en/floater_im_container.xml
index 65a05f3ec5..ced8c29199 100644
--- a/indra/newview/skins/default/xui/en/floater_im_container.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_container.xml
@@ -11,7 +11,7 @@
save_visibility="true"
single_instance="true"
title="CONVERSATIONS"
- width="392">
+ width="396">
<tab_container
follows="left|right|top|bottom"
height="390"
@@ -27,7 +27,7 @@
halign="left"
use_ellipses="true"
top="0"
- width="390" />
+ width="394" />
<icon
color="DefaultShadowLight"
enabled="false"
@@ -38,5 +38,5 @@
left="1"
name="im_box_tab_container_icon"
bottom="10"
- width="390" />
+ width="394" />
</multi_floater>
diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml
index 422e50f035..f537c81860 100644
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -13,7 +13,7 @@
can_minimize="true"
can_close="true"
visible="false"
- width="385"
+ width="394"
can_resize="true"
min_width="250"
min_height="190">
@@ -22,7 +22,7 @@
default_tab_group="2"
follows="all"
height="320"
- width="385"
+ width="394"
layout="topleft"
orientation="horizontal"
name="im_panels"
@@ -43,7 +43,7 @@
tab_group="2"
top="0"
height="200"
- width="245"
+ width="254"
user_resize="true">
<button
height="20"
@@ -70,7 +70,7 @@
parse_highlights="true"
allow_html="true"
left="1"
- width="240">
+ width="249">
</chat_history>
<line_editor
bottom="0"
@@ -81,7 +81,7 @@
layout="bottomleft"
name="chat_editor"
tab_group="3"
- width="240">
+ width="249">
</line_editor>
</layout_panel>
</layout_stack>
diff --git a/indra/newview/skins/default/xui/en/menu_object.xml b/indra/newview/skins/default/xui/en/menu_object.xml
index 8b10c7b049..6ca8766e3f 100644
--- a/indra/newview/skins/default/xui/en/menu_object.xml
+++ b/indra/newview/skins/default/xui/en/menu_object.xml
@@ -18,16 +18,16 @@
name="Edit...">
<menu_item_call.on_click
function="Object.Edit" />
- <menu_item_call.on_visible
+ <menu_item_call.on_visible
function="EnableEdit"/>
</menu_item_call>
<menu_item_call
label="Build"
name="Build">
<menu_item_call.on_click
- function="Object.Edit" />
- <menu_item_call.on_visible
- function="VisibleBuild"/>
+ function="Object.Build" />
+ <menu_item_call.on_visible
+ function="EnableEdit"/>
</menu_item_call>
<menu_item_call
enabled="false"
diff --git a/indra/newview/skins/default/xui/en/menu_url_agent.xml b/indra/newview/skins/default/xui/en/menu_url_agent.xml
index fa05dac148..73f0fa7979 100644
--- a/indra/newview/skins/default/xui/en/menu_url_agent.xml
+++ b/indra/newview/skins/default/xui/en/menu_url_agent.xml
@@ -7,7 +7,7 @@
layout="topleft"
name="show_agent">
<menu_item_call.on_click
- function="Url.Execute" />
+ function="Url.ShowProfile" />
</menu_item_call>
<menu_item_separator
layout="topleft" />
diff --git a/indra/newview/skins/default/xui/en/menu_url_group.xml b/indra/newview/skins/default/xui/en/menu_url_group.xml
index c5eaf94d22..2cb125ce09 100644
--- a/indra/newview/skins/default/xui/en/menu_url_group.xml
+++ b/indra/newview/skins/default/xui/en/menu_url_group.xml
@@ -7,7 +7,7 @@
layout="topleft"
name="show_group">
<menu_item_call.on_click
- function="Url.Execute" />
+ function="Url.ShowProfile" />
</menu_item_call>
<menu_item_separator
layout="topleft" />
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 7d886cda8e..59b43eeb00 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -5066,6 +5066,7 @@ No valid parcel could be found.
<notification
icon="notify.tga"
name="ObjectGiveItem"
+ persist="true"
type="offer">
An object named [OBJECTFROMNAME] owned by [NAME_SLURL] has given you this [OBJECTTYPE]:
[ITEM_SLURL]
@@ -5110,6 +5111,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th
<notification
icon="notify.tga"
name="UserGiveItem"
+ persist="true"
type="offer">
[NAME_SLURL] has given you this [OBJECTTYPE]:
[ITEM_SLURL]
@@ -5162,6 +5164,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th
<notification
icon="notify.tga"
name="TeleportOffered"
+ persist="true"
type="offer">
[NAME_SLURL] has offered to teleport you to their location:
@@ -5207,6 +5210,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th
<notification
icon="notify.tga"
name="OfferFriendship"
+ persist="true"
type="offer">
[NAME_SLURL] is offering friendship.
diff --git a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml
index 29c6a17c31..33a5e01e4c 100644
--- a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml
+++ b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml
@@ -3,14 +3,14 @@
border="false"
height="300"
name="panel_im_control_panel"
- width="110">
+ width="119">
<avatar_icon
follows="left|top"
height="105"
left_delta="5"
name="avatar_icon"
top="-5"
- width="105"/>
+ width="114"/>
<layout_stack
mouse_opaque="false"
border_size="0"
@@ -22,7 +22,7 @@
name="button_stack"
orientation="vertical"
top_pad="5"
- width="105">
+ width="114">
<layout_panel
mouse_opaque="false"
auto_resize="true"
@@ -31,7 +31,7 @@
layout="topleft"
left="2"
min_height="0"
- width="100"
+ width="109"
top="0"
name="spacer"
user_resize="false" />
@@ -41,7 +41,7 @@
height="20"
layout="topleft"
min_height="20"
- width="100"
+ width="109"
name="view_profile_btn_panel"
user_resize="false">
<button
@@ -50,7 +50,7 @@
label="Profile"
name="view_profile_btn"
top="0"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -58,7 +58,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="add_friend_btn_panel"
user_resize="false">
<button
@@ -67,7 +67,7 @@
label="Add Friend"
name="add_friend_btn"
top="5"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -75,7 +75,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="teleport_btn_panel"
user_resize="false">
<button
@@ -85,7 +85,7 @@
label="Teleport"
name="teleport_btn"
tool_tip = "Offer to teleport this person"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -93,7 +93,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="share_btn_panel"
user_resize="false">
<button
@@ -102,7 +102,7 @@
height="23"
label="Share"
name="share_btn"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -110,7 +110,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="pay_btn_panel"
user_resize="false">
<button
@@ -119,7 +119,7 @@
height="23"
label="Pay"
name="pay_btn"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -127,7 +127,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="call_btn_panel"
user_resize="false">
<button
@@ -135,7 +135,7 @@
height="23"
label="Call"
name="call_btn"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -143,7 +143,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="end_call_btn_panel"
user_resize="false"
visible="false">
@@ -152,7 +152,7 @@
height="23"
label="End Call"
name="end_call_btn"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -160,7 +160,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="voice_ctrls_btn_panel"
user_resize="false"
visible="false">
@@ -169,7 +169,7 @@
height="23"
label="Voice Controls"
name="voice_ctrls_btn"
- width="100" />
+ width="109" />
</layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_inventory_item.xml b/indra/newview/skins/default/xui/en/panel_inventory_item.xml
new file mode 100644
index 0000000000..f1b7b92ece
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_inventory_item.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="top|right|left"
+ height="20"
+ layout="topleft"
+ left="0"
+ name="inventory_item"
+ top="0"
+ width="380">
+ <icon
+ follows="top|right|left"
+ height="20"
+ image_name="ListItem_Over"
+ layout="topleft"
+ left="0"
+ name="hovered_icon"
+ top="0"
+ visible="false"
+ width="380" />
+ <icon
+ height="20"
+ follows="top|right|left"
+ image_name="ListItem_Select"
+ layout="topleft"
+ left="0"
+ name="selected_icon"
+ top="0"
+ visible="false"
+ width="380" />
+ <icon
+ height="16"
+ follows="top|left"
+ image_name="Inv_Object"
+ layout="topleft"
+ left="0"
+ name="item_icon"
+ top="0"
+ width="16" />
+ <text
+ follows="left|right"
+ height="20"
+ layout="topleft"
+ left_pad="5"
+ allow_html="false"
+ use_ellipses="true"
+ name="item_name"
+ text_color="white"
+ top="4"
+ value="..."
+ width="359" />
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_my_profile.xml b/indra/newview/skins/default/xui/en/panel_my_profile.xml
index 5e41d65720..841a4f5713 100644
--- a/indra/newview/skins/default/xui/en/panel_my_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_my_profile.xml
@@ -401,14 +401,6 @@
name="edit_profile_btn"
tool_tip="Edit your personal information"
width="152" />
- <button
- follows="bottom|right"
- height="23"
- label="Edit Appearance"
- left_pad="3"
- name="edit_appearance_btn"
- tool_tip="Create/edit your appearance: physical data, clothes and etc."
- width="153" />
</layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
index 66ed43efec..b8ad278da7 100644
--- a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
@@ -23,20 +23,16 @@
tab_position="top"
halign="center"
width="312">
- <inventory_panel
+ <panel
+ class="outfits_list"
+ filename="panel_outfits_list.xml"
+ height="490"
+ name="outfitslist_tab"
background_visible="true"
- background_opaque="true"
- label="MY OUTFITS"
- help_topic="my_outfits_tab"
- allow_multi_select="true"
follows="all"
- border="false"
- left="0"
- top="0"
- width="315"
- mouse_opaque="true"
- name="outfitslist_tab"
- start_folder="My Outfits" />
+ label="MY OUTFITS"
+ layout="topleft"
+ width="315" />
<inventory_panel
follows="all"
background_visible="true"
diff --git a/indra/newview/skins/default/xui/en/panel_outfits_list.xml b/indra/newview/skins/default/xui/en/panel_outfits_list.xml
new file mode 100644
index 0000000000..5cf94c25d7
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_outfits_list.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ border="false"
+ follows="all"
+ height="400"
+ name="Outfits"
+ layout="topleft"
+ left="0"
+ top="0"
+ width="313">
+ <accordion
+ background_visible="true"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ follows="all"
+ height="400"
+ layout="topleft"
+ left="3"
+ name="outfits_accordion"
+ top="0"
+ width="307">
+ </accordion>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 61784fede4..fa4213667b 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -30,6 +30,15 @@
name="no_friends"
value="No friends" />
<string
+ name="no_friends_msg">
+ Find friends using [secondlife:///app/search/people Search] or right-click on a Resident to add them as a friend.
+Looking for people to hang out with? Try the [secondlife:///app/worldmap World Map].
+ </string>
+ <string
+ name="no_filtered_friends_msg">
+ Didn't find what you're looking for? Try [secondlife:///app/search/people Search].
+ </string>
+ <string
name="people_filter_label"
value="Filter People" />
<string
@@ -265,14 +274,11 @@
<text
follows="all"
height="450"
- left="10"
- name="no_friends_msg"
+ left="13"
+ name="no_friends_help_text"
top="10"
width="293"
- wrap="true">
- Find friends using [secondlife:///app/search/people Search] or right-click on a Resident to add them as a friend.
-Looking for people to hang out with? Try the [secondlife:///app/worldmap World Map].
- </text>
+ wrap="true" />
</panel>
<panel
background_opaque="true"
@@ -293,6 +299,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
Values are set from appropriate strings at the top of file via LLPeoplePanel::postBuild()
-->
<group_list
+ allow_select="true"
background_visible="true"
bg_alpha_color="DkGray2"
bg_opaque_color="DkGray2"
diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml
index a666608103..d7a601d7a3 100644
--- a/indra/newview/skins/default/xui/en/panel_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile.xml
@@ -389,14 +389,6 @@
name="edit_profile_btn"
tool_tip="Edit your personal information"
width="130" />
- <button
- follows="bottom|right"
- height="23"
- label="Edit Appearance"
- left_pad="10"
- name="edit_appearance_btn"
- tool_tip="Create/edit your appearance: physical data, clothes and etc."
- width="130" />
</layout_panel>
</layout_stack>
diff --git a/indra/newview/skins/default/xui/en/panel_world_map.xml b/indra/newview/skins/default/xui/en/panel_world_map.xml
index 9f08d3a817..16860a6117 100644
--- a/indra/newview/skins/default/xui/en/panel_world_map.xml
+++ b/indra/newview/skins/default/xui/en/panel_world_map.xml
@@ -45,6 +45,14 @@
name="world_map_northwest">
NW
</panel.string>
+ <panel.string
+ name="world_map_person">
+ 1 person
+ </panel.string>
+ <panel.string
+ name="world_map_people">
+ [NUMBER] people
+ </panel.string>
<text
type="string"
length="1"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 066cccf076..c02df10ca7 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -1842,7 +1842,7 @@ Clears (deletes) the media and all params from the given face.
<string name="LeaveMouselook">Press ESC to return to World View</string>
<!-- inventory -->
- <string name="InventoryNoMatchingItems">No matching items found in inventory. Try [secondlife:///app/search/groups "Search"].</string>
+ <string name="InventoryNoMatchingItems">Didn't find what you're looking for? Try [secondlife:///app/search/all Search].</string>
<string name="FavoritesNoMatchingItems">Drag a landmark here to add it to your favorites.</string>
<string name="InventoryNoTexture">You do not have a copy of this texture in your inventory</string>
<!-- use value="" because they have preceding spaces -->
@@ -2898,6 +2898,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
<string name="LocationCtrlBuildTooltip">Building/dropping objects not allowed</string>
<string name="LocationCtrlScriptsTooltip">Scripts not allowed</string>
<string name="LocationCtrlDamageTooltip">Health</string>
+ <string name="LocationCtrlAdultIconTooltip">Adult Region</string>
+ <string name="LocationCtrlModerateIconTooltip">Moderate Region</string>
+ <string name="LocationCtrlGeneralIconTooltip">General Region</string>
<!-- Strings used by the (currently Linux) auto-updater app -->
<string name="UpdaterWindowTitle">
diff --git a/indra/newview/skins/default/xui/en/widgets/location_input.xml b/indra/newview/skins/default/xui/en/widgets/location_input.xml
index 1d61447e31..02ea661da3 100644
--- a/indra/newview/skins/default/xui/en/widgets/location_input.xml
+++ b/indra/newview/skins/default/xui/en/widgets/location_input.xml
@@ -6,6 +6,8 @@
<location_input font="SansSerifSmall"
icon_maturity_general="Parcel_PG_Light"
icon_maturity_adult="Parcel_R_Light"
+ icon_maturity_moderate="Parcel_M_Light"
+ maturity_help_topic="TODO"
add_landmark_image_enabled="Favorite_Star_Active"
add_landmark_image_disabled="Favorite_Star_Off"
add_landmark_image_hover="Favorite_Star_Over"
@@ -43,7 +45,7 @@
scale_image="false"
top="19"
left="-3" />
- <maturity_icon
+ <maturity_button
name="maturity_icon"
width="18"
height="16"
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 99dfc07cd5..044dbc9ed7 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -648,10 +648,14 @@ class DarwinManifest(ViewerManifest):
self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app")
self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app")
+ # plugin launcher
+ self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin.app", "SLPlugin.app")
+
# our apps dependencies on shared libs
if dylibs["llcommon"]:
mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources")
mac_updater_res_path = self.dst_path_of("mac-updater.app/Contents/Resources")
+ slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources")
for libfile in ("libllcommon.dylib",
"libapr-1.0.3.7.dylib",
"libaprutil-1.0.3.8.dylib",
@@ -665,9 +669,10 @@ class DarwinManifest(ViewerManifest):
{'target': target_lib,
'link' : os.path.join(mac_updater_res_path, libfile)}
)
-
- # plugin launcher
- self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin", "SLPlugin")
+ self.run_command("ln -sf %(target)r %(link)r" %
+ {'target': target_lib,
+ 'link' : os.path.join(slplugin_res_path, libfile)}
+ )
# plugins
if self.prefix(src="", dst="llplugin"):