diff options
Diffstat (limited to 'indra')
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", ¬ificationFilter, 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"):  | 
