diff options
53 files changed, 1321 insertions, 318 deletions
| diff --git a/autobuild.xml b/autobuild.xml index 37371746d5..9710b7a083 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -408,11 +408,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>f6835c4d7745cd1cadfbce47b40331d08affb532</string> +              <string>e03eb77224290c875ff84f75b7fe3d0e7c162c94</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://github.com/secondlife/3p-dictionaries/releases/download/v1.0.1-dev2.gf887629-f887629/dictionaries-common-None.tar.zst</string> +              <string>https://github.com/secondlife/3p-dictionaries/releases/download/v1-a01bb6c/dictionaries-1.a01bb6c-common-a01bb6c.tar.zst</string>              </map>              <key>name</key>              <string>common</string> @@ -425,7 +425,7 @@          <key>copyright</key>          <string>Copyright 2014 Apache OpenOffice software</string>          <key>version</key> -        <string>None</string> +        <string>1.a01bb6c</string>          <key>name</key>          <string>dictionaries</string>          <key>description</key> @@ -734,11 +734,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>6604c1cca515d287e697997a8d5593d1cae172a9</string> +              <string>066625e7aa7f697a4b6cd461aad960c57181011f</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://github.com/secondlife/3p-glh_linear/releases/download/v1.0.1-dev2.g3253ed7-3253ed7/glh_linear-common-None.tar.zst</string> +              <string>https://github.com/secondlife/3p-glh_linear/releases/download/v1.0.1-dev4-984c397/glh_linear-1.0.1-dev4-common-984c397.tar.zst</string>              </map>              <key>name</key>              <string>common</string> @@ -751,7 +751,7 @@          <key>copyright</key>          <string>Copyright (c) 2000 Cass Everitt</string>          <key>version</key> -        <string>None</string> +        <string>1.0.1-dev4</string>          <key>name</key>          <string>glh_linear</string>          <key>description</key> @@ -882,11 +882,11 @@                <key>creds</key>                <string>github</string>                <key>hash</key> -              <string>a193ff65d6db48626d65d96c6124c6efca85e8ec</string> +              <string>ae2c2a215b1bc2e3f37a67e301926dc405902d1a</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/108912596</string> +              <string>https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/136778143</string>              </map>              <key>name</key>              <string>darwin64</string> @@ -910,11 +910,11 @@                <key>creds</key>                <string>github</string>                <key>hash</key> -              <string>ebfb82b6143874e7938b9d1e8a70d0a2e28aa818</string> +              <string>0393dd75c58f7046bed47e62a8884a78cb02a5c3</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/108912599</string> +              <string>https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/136778145</string>              </map>              <key>name</key>              <string>windows64</string> @@ -1120,11 +1120,11 @@                <key>creds</key>                <string>github</string>                <key>hash</key> -              <string>bcc7e2c34896fc9cbc41828dee8a4ddf54f10453</string> +              <string>ad72fa1d103df777906f0d98f3e882b9916aeada</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://api.github.com/repos/secondlife/3p-kdu/releases/assets/108298968</string> +              <string>https://api.github.com/repos/secondlife/3p-kdu/releases/assets/136774118</string>              </map>              <key>name</key>              <string>darwin64</string> @@ -1136,11 +1136,11 @@                <key>creds</key>                <string>github</string>                <key>hash</key> -              <string>9de772df2ed12e9c742df6c90670c7cbbb9c93a6</string> +              <string>e46e4ac93a237b5c4a14183766f76ba5d58935a2</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://api.github.com/repos/secondlife/3p-kdu/releases/assets/108298969</string> +              <string>https://api.github.com/repos/secondlife/3p-kdu/releases/assets/136774125</string>              </map>              <key>name</key>              <string>linux64</string> @@ -1152,15 +1152,31 @@                <key>creds</key>                <string>github</string>                <key>hash</key> -              <string>92533ff0f8c1881ad85e75800f9072c413ccf7b7</string> +              <string>bb37557f78c72b26580a521f8b8dabfa1b34e6e6</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://api.github.com/repos/secondlife/3p-kdu/releases/assets/108298970</string> +              <string>https://api.github.com/repos/secondlife/3p-kdu/releases/assets/136774126</string>              </map>              <key>name</key>              <string>windows64</string>            </map> +          <key>linux</key> +          <map> +            <key>archive</key> +            <map> +              <key>creds</key> +              <string>github</string> +              <key>hash</key> +              <string>711b82f9f588d3a125af7dcd8c81f93d9c343a7d</string> +              <key>hash_algorithm</key> +              <string>sha1</string> +              <key>url</key> +              <string>https://api.github.com/repos/secondlife/3p-kdu/releases/assets/136774121</string> +            </map> +            <key>name</key> +            <string>linux</string> +          </map>          </map>          <key>license</key>          <string>Kakadu</string> @@ -1169,7 +1185,7 @@          <key>copyright</key>          <string>Kakadu software</string>          <key>version</key> -        <string>7.10.4.539108</string> +        <string>7.10.4.4b9ec5f</string>          <key>name</key>          <string>kdu</string>          <key>description</key> @@ -1468,11 +1484,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>e50ea94bbaa4ff41bf53b84b7192df1a694c5337</string> +              <string>d3c1f7f947a2d8e89a98af816be2492afb42dfbc</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://github.com/secondlife/llca/releases/download/v202310121525.0-d22bd98/llca-202310121530.0-common-d22bd98.tar.zst</string> +              <string>https://github.com/secondlife/llca/releases/download/v202311020117.0-0f5d9c3/llca-202311012318.0-common-0f5d9c3.tar.zst</string>              </map>              <key>name</key>              <string>common</string> diff --git a/doc/contributions.txt b/doc/contributions.txt index af8b259c74..3e49ecb3e5 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -842,6 +842,7 @@ Kadah Coba  Jondan Lundquist  Joosten Briebers      MAINT-7074 +    BUG-225288  Josef Munster  Josette Windlow  Juilan Tripsa diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 0a213bddef..aa9a258723 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -152,12 +152,21 @@ void LLEventPumps::clear()      }  } -void LLEventPumps::reset() +void LLEventPumps::reset(bool log_pumps)  {      // Reset every known LLEventPump instance. Leave it up to each instance to      // decide what to do with the reset() call. +    if (log_pumps) +    { +        LL_INFOS() << "Resetting " << (S32)mPumpMap.size() << " pumps" << LL_ENDL; +    } +      for (PumpMap::value_type& pair : mPumpMap)      { +        if (log_pumps) +        { +            LL_INFOS() << "Resetting pump " << pair.first << LL_ENDL; +        }          pair.second->reset();      }  } @@ -314,9 +323,11 @@ std::string LLEventPump::inventName(const std::string& pfx)  void LLEventPump::clear()  { +    LLMutexLock lock(&mConnectionListMutex);      // Destroy the original LLStandardSignal instance, replacing it with a      // whole new one.      mSignal = std::make_shared<LLStandardSignal>(); +      mConnections.clear();  } @@ -324,6 +335,7 @@ void LLEventPump::reset()  {      // Resetting mSignal is supposed to disconnect everything on its own      // But due to crash on 'reset' added explicit cleanup to get more data +    LLMutexLock lock(&mConnectionListMutex);      ConnectionMap::const_iterator iter = mConnections.begin();      ConnectionMap::const_iterator end = mConnections.end();      while (iter!=end) @@ -348,6 +360,8 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL          return LLBoundListener();      } +    LLMutexLock lock(&mConnectionListMutex); +      float nodePosition = 1.0;      // if the supplied name is empty we are not interested in the ordering mechanism  @@ -507,8 +521,9 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL      return bound;  } -LLBoundListener LLEventPump::getListener(const std::string& name) const +LLBoundListener LLEventPump::getListener(const std::string& name)  { +    LLMutexLock lock(&mConnectionListMutex);      ConnectionMap::const_iterator found = mConnections.find(name);      if (found != mConnections.end())      { @@ -520,6 +535,7 @@ LLBoundListener LLEventPump::getListener(const std::string& name) const  void LLEventPump::stopListening(const std::string& name)  { +    LLMutexLock lock(&mConnectionListMutex);      ConnectionMap::iterator found = mConnections.find(name);      if (found != mConnections.end())      { diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index ae6e5aabc9..b5c4e58c9c 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -293,7 +293,7 @@ public:       * Reset all known LLEventPump instances       * workaround for DEV-35406 crash on shutdown       */ -    void reset(); +    void reset(bool log_pumps = false);  private:      friend class LLEventPump; @@ -519,7 +519,7 @@ public:      /// Get the LLBoundListener associated with the passed name (dummy      /// LLBoundListener if not found) -    virtual LLBoundListener getListener(const std::string& name) const; +    virtual LLBoundListener getListener(const std::string& name);      /**       * Instantiate one of these to block an existing connection:       * @code @@ -562,6 +562,7 @@ private:      LLHandle<LLEventPumps> mRegistry;      std::string mName; +    LLMutex mConnectionListMutex;  protected:      virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 7cdf7254ff..574b9b8b3b 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -38,6 +38,7 @@  #include <mach/mach_host.h>  #elif LL_LINUX  # include <unistd.h> +# include <sys/resource.h>  #endif  #include "llmemory.h" @@ -273,33 +274,16 @@ U64 LLMemory::getCurrentRSS()  U64 LLMemory::getCurrentRSS()  { -	static const char statPath[] = "/proc/self/stat"; -	LLFILE *fp = LLFile::fopen(statPath, "r"); -	U64 rss = 0; +	struct rusage usage; -	if (fp == NULL) -	{ -		LL_WARNS() << "couldn't open " << statPath << LL_ENDL; +	if (getrusage(RUSAGE_SELF, &usage) != 0) { +		// Error handling code could be here  		return 0;  	} -	// Eee-yew!	 See Documentation/filesystems/proc.txt in your -	// nearest friendly kernel tree for details. -	 -	{ -		int ret = fscanf(fp, "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*d %*d " -						 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %Lu", -						 &rss); -		if (ret != 1) -		{ -			LL_WARNS() << "couldn't parse contents of " << statPath << LL_ENDL; -			rss = 0; -		} -	} -	 -	fclose(fp); - -	return rss; +	// ru_maxrss (since Linux 2.6.32) +	// This is the maximum resident set size used (in kilobytes). +	return usage.ru_maxrss * 1024;  }  #else diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 9f7768f78e..b7013dbb6e 100644 --- a/indra/llmessage/lldatapacker.cpp +++ b/indra/llmessage/lldatapacker.cpp @@ -298,6 +298,13 @@ BOOL LLDataPackerBinaryBuffer::unpackBinaryData(U8 *value, S32 &size, const char  	}  	htolememcpy(&size, mCurBufferp, MVT_S32, 4); + +    if (size < 0) +    { +        LL_WARNS() << "LLDataPackerBinaryBuffer::unpackBinaryData unpacked invalid size, aborting!" << LL_ENDL; +        return FALSE; +    } +  	mCurBufferp += 4;  	if (!verifyLength(size, name)) diff --git a/indra/llui/llfiltereditor.h b/indra/llui/llfiltereditor.h index 3a05bc05a1..52cad3bff4 100644 --- a/indra/llui/llfiltereditor.h +++ b/indra/llui/llfiltereditor.h @@ -43,6 +43,7 @@ class LLFilterEditor : public LLSearchEditor  public:  	struct Params : public LLInitParam::Block<Params, LLSearchEditor::Params>  	{}; +    virtual ~LLFilterEditor() {}  protected:  	LLFilterEditor(const Params&); diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 2303cd24b7..c67db54ea6 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1772,6 +1772,8 @@ void LLFloater::onClickTearOff(LLFloater* self)  		{  			if (self->mSaveRect)  			{ +                LLRect screen_rect = self->calcScreenRect(); +                self->mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert();  				self->storeRectControl();  			}  			self->setMinimized(FALSE); // to reenable minimize button if it was minimized diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index d736aa6634..d87241a9bf 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -994,6 +994,7 @@ LLBoundListener LLNotificationChannelBase::connectChangedImpl(const LLEventListe  	// all of the notifications that are already in the channel  	// we use a special signal called "load" in case the channel wants to care  	// only about new notifications +    LLMutexLock lock(&mItemsMutex);  	for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)  	{  		slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); @@ -1171,29 +1172,33 @@ LLNotificationChannel::LLNotificationChannel(const std::string& name,  	connectToChannel(parent);  } -bool LLNotificationChannel::isEmpty() const +LLNotificationChannel::~LLNotificationChannel()  { -	return mItems.empty(); +    for (LLBoundListener &listener : mListeners) +    { +        listener.disconnect(); +    }  } -S32 LLNotificationChannel::size() const +bool LLNotificationChannel::isEmpty() const  { -	return mItems.size(); +	return mItems.empty();  } -LLNotificationChannel::Iterator LLNotificationChannel::begin() +S32 LLNotificationChannel::size() const  { -	return mItems.begin(); +    return mItems.size();  } -LLNotificationChannel::Iterator LLNotificationChannel::end() +size_t LLNotificationChannel::size()  { -	return mItems.end(); +	return mItems.size();  } -size_t LLNotificationChannel::size() +void LLNotificationChannel::forEachNotification(NotificationProcess process)  { -	return mItems.size(); +    LLMutexLock lock(&mItemsMutex); +    std::for_each(mItems.begin(), mItems.end(), process);  }  std::string LLNotificationChannel::summarize() @@ -1201,7 +1206,8 @@ std::string LLNotificationChannel::summarize()  	std::string s("Channel '");  	s += mName;  	s += "'\n  "; -	for (LLNotificationChannel::Iterator it = begin(); it != end(); ++it) +    LLMutexLock lock(&mItemsMutex); +	for (LLNotificationChannel::Iterator it = mItems.begin(); it != mItems.end(); ++it)  	{  		s += (*it)->summarize();  		s += "\n  "; @@ -1213,14 +1219,14 @@ void LLNotificationChannel::connectToChannel( const std::string& channel_name )  {  	if (channel_name.empty())  	{ -		LLNotifications::instance().connectChanged( -			boost::bind(&LLNotificationChannelBase::updateItem, this, _1)); +        mListeners.push_back(LLNotifications::instance().connectChanged( +			boost::bind(&LLNotificationChannelBase::updateItem, this, _1)));  	}  	else  	{  		mParents.push_back(channel_name);  		LLNotificationChannelPtr p = LLNotifications::instance().getChannel(channel_name); -		p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1)); +        mListeners.push_back(p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1)));  	}  } @@ -1728,6 +1734,7 @@ void LLNotifications::cancel(LLNotificationPtr pNotif)  void LLNotifications::cancelByName(const std::string& name)  { +    LLMutexLock lock(&mItemsMutex);  	std::vector<LLNotificationPtr> notifs_to_cancel;  	for (LLNotificationSet::iterator it=mItems.begin(), end_it = mItems.end();  		it != end_it; @@ -1752,6 +1759,7 @@ void LLNotifications::cancelByName(const std::string& name)  void LLNotifications::cancelByOwner(const LLUUID ownerId)  { +    LLMutexLock lock(&mItemsMutex);  	std::vector<LLNotificationPtr> notifs_to_cancel;  	for (LLNotificationSet::iterator it = mItems.begin(), end_it = mItems.end();  		 it != end_it; @@ -1799,11 +1807,6 @@ LLNotificationPtr LLNotifications::find(LLUUID uuid)  	}  } -void LLNotifications::forEachNotification(NotificationProcess process) -{ -	std::for_each(mItems.begin(), mItems.end(), process); -} -  std::string LLNotifications::getGlobalString(const std::string& key) const  {  	GlobalStringMap::const_iterator it = mGlobalStrings.find(key); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 921398a693..4d71d189f2 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -738,16 +738,19 @@ class LLNotificationChannelBase :  {  	LOG_CLASS(LLNotificationChannelBase);  public: -	LLNotificationChannelBase(LLNotificationFilter filter)  -	:	mFilter(filter),  -		mItems()  -	{} +    LLNotificationChannelBase(LLNotificationFilter filter)  +    : mFilter(filter) +    , mItems()  +    , mItemsMutex() +    {} +      virtual ~LLNotificationChannelBase()      {          // explicit cleanup for easier issue detection          mChanged.disconnect_all_slots();          mPassedFilter.disconnect_all_slots();          mFailedFilter.disconnect_all_slots(); +        LLMutexLock lock(&mItemsMutex);          mItems.clear();      }  	// you can also connect to a Channel, so you can be notified of @@ -786,6 +789,7 @@ protected:  	LLStandardSignal mChanged;  	LLStandardSignal mPassedFilter;  	LLStandardSignal mFailedFilter; +    LLMutex mItemsMutex;  	// these are action methods that subclasses can override to take action   	// on specific types of changes; the management of the mItems list is @@ -835,7 +839,7 @@ public:  	LLNotificationChannel(const Params& p = Params());  	LLNotificationChannel(const std::string& name, const std::string& parent, LLNotificationFilter filter); -	virtual ~LLNotificationChannel() {} +	virtual ~LLNotificationChannel();  	typedef LLNotificationSet::iterator Iterator;  	std::string getName() const { return mName; } @@ -844,21 +848,23 @@ public:  	{  		return boost::iterator_range<parents_iter>(mParents);  	} -     -	void connectToChannel(const std::string& channel_name); -     +      bool isEmpty() const;      S32 size() const; -     -    Iterator begin(); -    Iterator end(); -	size_t size(); -	 +    size_t size(); + +    typedef boost::function<void(LLNotificationPtr)> NotificationProcess; +    void forEachNotification(NotificationProcess process); +  	std::string summarize(); +protected: +    void connectToChannel(const std::string& channel_name); +  private:  	std::string mName;  	std::vector<std::string> mParents; +    std::vector<LLBoundListener> mListeners;  };  // An interface class to provide a clean linker seam to the LLNotifications class. @@ -924,10 +930,6 @@ public:  	void update(const LLNotificationPtr pNotif);  	LLNotificationPtr find(LLUUID uuid); -	 -	typedef boost::function<void (LLNotificationPtr)> NotificationProcess; -	 -	void forEachNotification(NotificationProcess process);  	// This is all stuff for managing the templates  	// take your template out diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp index e73ba1fbe9..83b5bf03ac 100644 --- a/indra/llui/llnotificationslistener.cpp +++ b/indra/llui/llnotificationslistener.cpp @@ -149,11 +149,11 @@ void LLNotificationsListener::listChannelNotifications(const LLSD& params) const      if (channel)      {          LLSD notifications(LLSD::emptyArray()); -        for (LLNotificationChannel::Iterator ni(channel->begin()), nend(channel->end()); -             ni != nend; ++ni) -        { -            notifications.append(asLLSD(*ni)); -        } +        std::function<void(LLNotificationPtr)> func = [notifications](LLNotificationPtr ni) mutable +            { +                notifications.append(asLLSD(ni)); +            }; +        channel->forEachNotification(func);          response["notifications"] = notifications;      }      LLEventPumps::instance().obtain(params["reply"]).post(response); diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp index bafeef41fb..7a88ecc76f 100644 --- a/indra/llui/llsearcheditor.cpp +++ b/indra/llui/llsearcheditor.cpp @@ -104,6 +104,14 @@ LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p)  	}  } +LLSearchEditor::~LLSearchEditor() +{ +    mSearchButton = NULL; +    mClearButton = NULL; +    mSearchEditor->deleteAllChildren(); +    deleteAllChildren(); +} +  //virtual  void LLSearchEditor::draw()  { diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h index c0f3c1d60c..bd51988d07 100644 --- a/indra/llui/llsearcheditor.h +++ b/indra/llui/llsearcheditor.h @@ -74,7 +74,7 @@ protected:  	friend class LLUICtrlFactory;  public: -	virtual ~LLSearchEditor() {} +	virtual ~LLSearchEditor();  	/*virtual*/ void	draw(); diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index a6552d4ff1..328d36c6e1 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -440,7 +440,13 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params)  	tooltip_params.rect = LLRect (0, 1, 1, 0);  	if (tooltip_params.create_callback.isProvided()) -		mToolTip = tooltip_params.create_callback()(tooltip_params); +    { +        mToolTip = tooltip_params.create_callback()(tooltip_params); +        if (mToolTip == NULL)  +        { +            return; +        } +    }  	else  		mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params); @@ -492,7 +498,7 @@ void LLToolTipMgr::show(const LLToolTip::Params& params)  {  	if (!params.styled_message.isProvided()   		&& (!params.message.isProvided() || params.message().empty()) -		&& !params.image.isProvided()) return; +		&& !params.image.isProvided() && !params.create_callback.isProvided()) return;  	// fill in default tooltip params from tool_tip.xml  	LLToolTip::Params params_with_defaults(params); diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index 391a377280..07856edefc 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -71,7 +71,7 @@ HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam)      BSTR pNamespace = nullptr;      *pdwAdapterRam = 0; -    hrCoInitialize = CoInitialize( 0 ); +    hrCoInitialize = CoInitializeEx(0, COINIT_MULTITHREADED);      hr = CoCreateInstance( CLSID_WbemLocator,                             nullptr, @@ -234,7 +234,7 @@ std::string LLDXHardware::getDriverVersionWMI(EGPUVendor vendor)  	std::string mDriverVersion;  	HRESULT hrCoInitialize = S_OK;  	HRESULT hres; -	hrCoInitialize = CoInitialize(0); +	hrCoInitialize = CoInitializeEx(0, COINIT_MULTITHREADED);  	IWbemLocator *pLoc = NULL;  	hres = CoCreateInstance( @@ -687,7 +687,7 @@ BOOL LLDXHardware::getInfo(BOOL vram_only)  	BOOL ok = FALSE;      HRESULT       hr; -    CoInitialize(NULL); +    CoInitializeEx(NULL, COINIT_MULTITHREADED);      IDxDiagProvider *dx_diag_providerp = NULL;      IDxDiagContainer *dx_diag_rootp = NULL; @@ -976,7 +976,7 @@ LLSD LLDXHardware::getDisplayInfo()  	LLTimer hw_timer;      HRESULT       hr;  	LLSD ret; -    CoInitialize(NULL); +    CoInitializeEx(NULL, COINIT_MULTITHREADED);      IDxDiagProvider *dx_diag_providerp = NULL;      IDxDiagContainer *dx_diag_rootp = NULL; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c5477fdbd5..f0a6992884 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -233,6 +233,7 @@ set(viewer_SOURCE_FILES      llfloaterimcontainer.cpp      llfloaterinspect.cpp      llfloaterinventorysettings.cpp +    llfloaterinventorythumbnailshelper.cpp      llfloaterjoystick.cpp      llfloaterlagmeter.cpp      llfloaterland.cpp @@ -887,6 +888,7 @@ set(viewer_HEADER_FILES      llfloaterimcontainer.h      llfloaterinspect.h      llfloaterinventorysettings.h +    llfloaterinventorythumbnailshelper.h      llfloaterjoystick.h      llfloaterlagmeter.h      llfloaterland.h diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index a273afab52..4fba730395 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -4335,6 +4335,10 @@ void LLAgent::teleportRequest(  // Landmark ID = LLUUID::null means teleport home  void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)  { +    if (landmark_asset_id.isNull()) +    { +        gAgentCamera.resetView(); +    }  	mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLandmark(landmark_asset_id));  	startTeleportRequest();  } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 1fc4a8532d..862006aba6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1711,7 +1711,7 @@ bool LLAppViewer::cleanup()      LLNotifications::instance().clear();  	// workaround for DEV-35406 crash on shutdown -	LLEventPumps::instance().reset(); +	LLEventPumps::instance().reset(true);  	//dump scene loading monitor results  	if (LLSceneMonitor::instanceExists()) diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index cc4f4536a4..3444f50e52 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -177,6 +177,11 @@ LLNotificationChiclet::LLNotificationChiclet(const Params& p)  	LLFloaterNotificationsTabbed::getInstance()->setSysWellChiclet(this);  } +LLNotificationChiclet::~LLNotificationChiclet() +{ +    mNotificationChannel.reset(); +} +  void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)  {  	std::string action = user_data.asString(); diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index 58a797218f..1698fa269a 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -531,8 +531,9 @@ public:  	struct Params : public LLInitParam::Block<Params, LLSysWellChiclet::Params>{};  protected: -	struct ChicletNotificationChannel : public LLNotificationChannel +	class ChicletNotificationChannel : public LLNotificationChannel  	{ +    public:  		ChicletNotificationChannel(LLNotificationChiclet* chiclet)   			: LLNotificationChannel(LLNotificationChannel::Params().filter(filterNotification).name(chiclet->getSessionId().asString()))  			, mChiclet(chiclet) @@ -542,6 +543,7 @@ protected:  			connectToChannel("Offer");  			connectToChannel("Notifications");  		} +        virtual ~ChicletNotificationChannel() {}  		static bool filterNotification(LLNotificationPtr notify);  		// connect counter updaters to the corresponding signals @@ -553,9 +555,10 @@ protected:  	};  	boost::scoped_ptr<ChicletNotificationChannel> mNotificationChannel; -				 -	LLNotificationChiclet(const Params& p); -				 + +    LLNotificationChiclet(const Params& p); +    ~LLNotificationChiclet(); +  	/**  	 * Processes clicks on chiclet menu.  	 */ diff --git a/indra/newview/llfloaterinventorythumbnailshelper.cpp b/indra/newview/llfloaterinventorythumbnailshelper.cpp new file mode 100644 index 0000000000..814f88e9b9 --- /dev/null +++ b/indra/newview/llfloaterinventorythumbnailshelper.cpp @@ -0,0 +1,543 @@ +/** + * @file llfloaterinventorythumbnailshelper.cpp + * @author Callum Prentice + * @brief LLFloaterInventoryThumbnailsHelper class implementation + * + * Usage instructions and some brief notes can be found in Confluence here: + * https://lindenlab.atlassian.net/wiki/spaces/~174746736/pages/2928672843/Inventory+Thumbnail+Helper+Tool + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llaisapi.h" +#include "llclipboard.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llscrolllistctrl.h" +#include "lltexteditor.h" +#include "lluictrlfactory.h" +#include "lluuid.h" + +#include "llfloaterinventorythumbnailshelper.h" + +LLFloaterInventoryThumbnailsHelper::LLFloaterInventoryThumbnailsHelper(const LLSD& key) +    :   LLFloater("floater_inventory_thumbnails_helper") +{ +} + +LLFloaterInventoryThumbnailsHelper::~LLFloaterInventoryThumbnailsHelper() +{ +} + +BOOL LLFloaterInventoryThumbnailsHelper::postBuild() +{ +    mInventoryThumbnailsList = getChild<LLScrollListCtrl>("inventory_thumbnails_list"); +    mInventoryThumbnailsList->setAllowMultipleSelection(true); + +    mOutputLog = getChild<LLTextEditor>("output_log"); +    mOutputLog->setMaxTextLength(0xffff * 0x10); + +    mPasteItemsBtn = getChild<LLUICtrl>("paste_items_btn"); +    mPasteItemsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onPasteItems, this)); +    mPasteItemsBtn->setEnabled(true); + +    mPasteTexturesBtn = getChild<LLUICtrl>("paste_textures_btn"); +    mPasteTexturesBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onPasteTextures, this)); +    mPasteTexturesBtn->setEnabled(true); + +    mWriteThumbnailsBtn = getChild<LLUICtrl>("write_thumbnails_btn"); +    mWriteThumbnailsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onWriteThumbnails, this)); +    mWriteThumbnailsBtn->setEnabled(false); + +    mLogMissingThumbnailsBtn = getChild<LLUICtrl>("log_missing_thumbnails_btn"); +    mLogMissingThumbnailsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onLogMissingThumbnails, this)); +    mLogMissingThumbnailsBtn->setEnabled(false); + +    mClearThumbnailsBtn = getChild<LLUICtrl>("clear_thumbnails_btn"); +    mClearThumbnailsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onClearThumbnails, this)); +    mClearThumbnailsBtn->setEnabled(false); + +    return true; +} + +// Records an entry in the pasted items - saves it to a map and writes it to the log +// window for later confirmation/validation - since it uses a map, duplicates (based on +// the name) are discarded +void LLFloaterInventoryThumbnailsHelper::recordInventoryItemEntry(LLViewerInventoryItem* item) +{ +    const std::string name = item->getName(); + +    std::map<std::string, LLViewerInventoryItem*>::iterator iter = mItemNamesItems.find(name); +    if (iter == mItemNamesItems.end()) +    { +        mItemNamesItems.insert({name, item}); + +        writeToLog( +            STRINGIZE( +                "ITEM " << mItemNamesItems.size() << "> " << +                name << +                std::endl +            ), false); +    } +    else +    { +        // dupe - do not save +    } +} + +// Called when the user has copied items from their inventory and selects the Paste Items button +// in the UI - iterates over items and folders and saves details of each one. +// The first use of this tool is for updating NUX items and as such, only looks for OBJECTS, +// CLOTHING and BODYPARTS - later versions of this tool should make that selection editable. +void LLFloaterInventoryThumbnailsHelper::onPasteItems() +{ +    if (!LLClipboard::instance().hasContents()) +    { +        return; +    } + +    writeToLog( +        STRINGIZE( +            "\n==== Pasting items from inventory ====" << +            std::endl +        ), false); + +    std::vector<LLUUID> objects; +    LLClipboard::instance().pasteFromClipboard(objects); +    size_t count = objects.size(); + +    for (size_t i = 0; i < count; i++) +    { +        const LLUUID& entry = objects.at(i); + +        // Check for a folder +        const LLInventoryCategory* cat = gInventory.getCategory(entry); +        if (cat) +        { +            LLInventoryModel::cat_array_t cat_array; +            LLInventoryModel::item_array_t item_array; + +            LLIsType is_object(LLAssetType::AT_OBJECT); +            gInventory.collectDescendentsIf(cat->getUUID(), +                                            cat_array, +                                            item_array, +                                            LLInventoryModel::EXCLUDE_TRASH, +                                            is_object); + +            LLIsType is_bodypart(LLAssetType::AT_BODYPART); +            gInventory.collectDescendentsIf(cat->getUUID(), +                                            cat_array, +                                            item_array, +                                            LLInventoryModel::EXCLUDE_TRASH, +                                            is_bodypart); + +            LLIsType is_clothing(LLAssetType::AT_CLOTHING); +            gInventory.collectDescendentsIf(cat->getUUID(), +                                            cat_array, +                                            item_array, +                                            LLInventoryModel::EXCLUDE_TRASH, +                                            is_clothing); + +            for (size_t i = 0; i < item_array.size(); i++) +            { +                LLViewerInventoryItem* item = item_array.at(i); +                recordInventoryItemEntry(item); +            } +        } + +        // Check for an item +        LLViewerInventoryItem* item = gInventory.getItem(entry); +        if (item) +        { +            const LLAssetType::EType item_type = item->getType(); +            if (item_type == LLAssetType::AT_OBJECT || item_type == LLAssetType::AT_BODYPART || item_type == LLAssetType::AT_CLOTHING) +            { +                recordInventoryItemEntry(item); +            } +        } +    } + +    // update the main list view based on what we found +    updateDisplayList(); + +    // update the buttons enabled state based on what we found/saved +    updateButtonStates(); +} + +// Records a entry in the pasted textures - saves it to a map and writes it to the log +// window for later confirmation/validation - since it uses a map, duplicates (based on +// the name) are discarded +void LLFloaterInventoryThumbnailsHelper::recordTextureItemEntry(LLViewerInventoryItem* item) +{ +    const std::string name = item->getName(); + +    std::map<std::string, LLUUID>::iterator iter = mTextureNamesIDs.find(name); +    if (iter == mTextureNamesIDs.end()) +    { +        LLUUID id = item->getAssetUUID(); +        mTextureNamesIDs.insert({name, id}); + +        writeToLog( +            STRINGIZE( +                "TEXTURE " << mTextureNamesIDs.size() << "> " << +                name << +                //" | " << +                //id.asString() << +                std::endl +            ), false); +    } +    else +    { +        // dupe - do not save +    } +} + +// Called when the user has copied textures from their inventory and selects the Paste Textures +// button in the UI - iterates over textures and folders and saves details of each one. +void LLFloaterInventoryThumbnailsHelper::onPasteTextures() +{ +    if (!LLClipboard::instance().hasContents()) +    { +        return; +    } + +    writeToLog( +        STRINGIZE( +            "\n==== Pasting textures from inventory ====" << +            std::endl +        ), false); + +    std::vector<LLUUID> objects; +    LLClipboard::instance().pasteFromClipboard(objects); +    size_t count = objects.size(); + +    for (size_t i = 0; i < count; i++) +    { +        const LLUUID& entry = objects.at(i); + +        const LLInventoryCategory* cat = gInventory.getCategory(entry); +        if (cat) +        { +            LLInventoryModel::cat_array_t cat_array; +            LLInventoryModel::item_array_t item_array; + +            LLIsType is_object(LLAssetType::AT_TEXTURE); +            gInventory.collectDescendentsIf(cat->getUUID(), +                                            cat_array, +                                            item_array, +                                            LLInventoryModel::EXCLUDE_TRASH, +                                            is_object); + +            for (size_t i = 0; i < item_array.size(); i++) +            { +                LLViewerInventoryItem* item = item_array.at(i); +                recordTextureItemEntry(item); +            } +        } + +        LLViewerInventoryItem* item = gInventory.getItem(entry); +        if (item) +        { +            const LLAssetType::EType item_type = item->getType(); +            if (item_type == LLAssetType::AT_TEXTURE) +            { +                recordTextureItemEntry(item); +            } +        } +    } + +    // update the main list view based on what we found +    updateDisplayList(); + +    // update the buttons enabled state based on what we found/saved +    updateButtonStates(); +} + +// Updates the main list of entries in the UI based on what is in the maps/storage +void LLFloaterInventoryThumbnailsHelper::updateDisplayList() +{ +    mInventoryThumbnailsList->deleteAllItems(); + +    std::map<std::string, LLViewerInventoryItem*>::iterator item_iter = mItemNamesItems.begin(); +    while (item_iter != mItemNamesItems.end()) +    { +        std::string item_name = (*item_iter).first; + +        std::string existing_texture_name = std::string(); +        LLUUID existing_thumbnail_id = (*item_iter).second->getThumbnailUUID(); +        if (existing_thumbnail_id != LLUUID::null) +        { +            existing_texture_name = existing_thumbnail_id.asString(); +        } +        else +        { +            existing_texture_name = "none"; +        } + +        std::string new_texture_name = std::string(); +        std::map<std::string, LLUUID>::iterator texture_iter = mTextureNamesIDs.find(item_name); +        if (texture_iter != mTextureNamesIDs.end()) +        { +            new_texture_name = (*texture_iter).first; +        } +        else +        { +            new_texture_name = "missing"; +        } + +        LLSD row; +        row["columns"][EListColumnNum::NAME]["column"] = "item_name"; +        row["columns"][EListColumnNum::NAME]["type"] = "text"; +        row["columns"][EListColumnNum::NAME]["value"] = item_name; +        row["columns"][EListColumnNum::NAME]["font"]["name"] = "Monospace"; + +        row["columns"][EListColumnNum::EXISTING_TEXTURE]["column"] = "existing_texture"; +        row["columns"][EListColumnNum::EXISTING_TEXTURE]["type"] = "text"; +        row["columns"][EListColumnNum::EXISTING_TEXTURE]["font"]["name"] = "Monospace"; +        row["columns"][EListColumnNum::EXISTING_TEXTURE]["value"] = existing_texture_name; + +        row["columns"][EListColumnNum::NEW_TEXTURE]["column"] = "new_texture"; +        row["columns"][EListColumnNum::NEW_TEXTURE]["type"] = "text"; +        row["columns"][EListColumnNum::NEW_TEXTURE]["font"]["name"] = "Monospace"; +        row["columns"][EListColumnNum::NEW_TEXTURE]["value"] = new_texture_name; + +        mInventoryThumbnailsList->addElement(row); + +        ++item_iter; +    } +} + +#if 1 +// *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model. +// temp code in transition +void inventoryThumbnailsHelperCb(LLPointer<LLInventoryCallback> cb, LLUUID id) +{ +    if (cb.notNull()) +    { +        cb->fire(id); +    } +} +#endif + +// Makes calls to the AIS v3 API to record the local changes made to the thumbnails. +// If this is not called, the operations (e.g. set thumbnail or clear thumbnail) +// appear to work but do not push the changes back to the inventory (local cache view only) +bool writeInventoryThumbnailID(LLUUID item_id, LLUUID thumbnail_asset_id) +{ +    if (AISAPI::isAvailable()) +    { + +        LLSD updates; +        updates["thumbnail"] = LLSD().with("asset_id", thumbnail_asset_id.asString()); + +        LLPointer<LLInventoryCallback> cb; + +        AISAPI::completion_t cr = boost::bind(&inventoryThumbnailsHelperCb, cb, _1); +        AISAPI::UpdateItem(item_id, updates, cr); + +        return true; +    } +    else +    { +        LL_WARNS() << "Unable to write inventory thumbnail because the AIS API is not available" << LL_ENDL; +        return false; +    } +} + +// Called when the Write Thumbanils button is pushed. Iterates over the name/item and +// name/.texture maps and where it finds a common name, extracts what is needed and +// writes the thumbnail accordingly. +void LLFloaterInventoryThumbnailsHelper::onWriteThumbnails() +{ +    // create and show confirmation (Yes/No) textbox since this is a destructive operation +    LLNotificationsUtil::add("WriteInventoryThumbnailsWarning", LLSD(), LLSD(), +                             [&](const LLSD & notif, const LLSD & resp) +    { +        S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); +        if (opt == 0) +        { +            std::map<std::string, LLViewerInventoryItem*>::iterator item_iter = mItemNamesItems.begin(); +            while (item_iter != mItemNamesItems.end()) +            { +                std::string item_name = (*item_iter).first; + +                std::map<std::string, LLUUID>::iterator texture_iter = mTextureNamesIDs.find(item_name); +                if (texture_iter != mTextureNamesIDs.end()) +                { +                    LLUUID item_id = (*item_iter).second->getUUID(); + +                    LLUUID thumbnail_asset_id = (*texture_iter).second; + +                    writeToLog( +                        STRINGIZE( +                            "WRITING THUMB " << +                            (*item_iter).first << +                            "\n" << +                            "item ID: " << +                            item_id << +                            "\n" << +                            "thumbnail texture ID: " << +                            thumbnail_asset_id << +                            "\n" +                        ), true); + + +                    (*item_iter).second->setThumbnailUUID(thumbnail_asset_id); + +                    // This additional step (notifying AIS API) is required +                    // to make the changes persist outside of the local cache +                    writeInventoryThumbnailID(item_id, thumbnail_asset_id); +                } + +                ++item_iter; +            } + +            updateDisplayList(); +        } +        else +        { +            LL_INFOS() << "Writing new thumbnails was canceled" << LL_ENDL; +        } +    }); +} + +// Called when the Log Items with Missing Thumbnails is selected. This merely writes +// a list of all the items for which the thumbnail ID is Null. Typical use case is to +// copy from the log window, pasted to Slack to illustrate which items are missing +// a thumbnail +void LLFloaterInventoryThumbnailsHelper::onLogMissingThumbnails() +{ +    std::map<std::string, LLViewerInventoryItem*>::iterator item_iter = mItemNamesItems.begin(); +    while (item_iter != mItemNamesItems.end()) +    { +        LLUUID thumbnail_id = (*item_iter).second->getThumbnailUUID(); + +        if (thumbnail_id == LLUUID::null) +        { +            writeToLog( +                STRINGIZE( +                    "Missing thumbnail: " << +                    (*item_iter).first << +                    std::endl +                ), true); +        } + +        ++item_iter; +    } +} + +// Called when the Clear Thumbnail button is selected.  Code to perform the clear (really +// just writing a NULL UUID into the thumbnail field) is behind an "Are you Sure?" dialog +// since it cannot be undone and potentinally, you could remove the thumbnails from your +// whole inventory this way. +void LLFloaterInventoryThumbnailsHelper::onClearThumbnails() +{ +    // create and show confirmation (Yes/No) textbox since this is a destructive operation +    LLNotificationsUtil::add("ClearInventoryThumbnailsWarning", LLSD(), LLSD(), +                             [&](const LLSD & notif, const LLSD & resp) +    { +        S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); +        if (opt == 0) +        { +            std::map<std::string, LLViewerInventoryItem*>::iterator item_iter = mItemNamesItems.begin(); +            while (item_iter != mItemNamesItems.end()) +            { +                (*item_iter).second->setThumbnailUUID(LLUUID::null); + +                // This additional step (notifying AIS API) is required +                // to make the changes persist outside of the local cache +                const LLUUID item_id = (*item_iter).second->getUUID(); +                writeInventoryThumbnailID(item_id, LLUUID::null); + +                ++item_iter; +            } + +            updateDisplayList(); +        } +        else +        { +            LL_INFOS() << "Clearing on thumbnails was canceled" << LL_ENDL; +        } +    }); +} + +// Update the endabled state of some of the UI buttons based on what has +// been recorded so far.  For example, if there are no valid item/texture pairs, +// then the Write Thumbnails button is not enabled. +void LLFloaterInventoryThumbnailsHelper::updateButtonStates() +{ +    size_t found_count = 0; + +    std::map<std::string, LLViewerInventoryItem*>::iterator item_iter = mItemNamesItems.begin(); +    while (item_iter != mItemNamesItems.end()) +    { +        std::string item_name = (*item_iter).first; + +        std::map<std::string, LLUUID>::iterator texture_iter = mTextureNamesIDs.find(item_name); +        if (texture_iter != mTextureNamesIDs.end()) +        { +            found_count++; +        } + +        ++item_iter; +    } + +    // the "Write Thumbnails" button is only enabled when there is at least one +    // item with a matching texture ready to be written to the thumbnail field +    if (found_count > 0) +    { +        mWriteThumbnailsBtn->setEnabled(true); +    } +    else +    { +        mWriteThumbnailsBtn->setEnabled(false); +    } + +    // The "Log Missing Items" and "Clear Thumbnails" buttons are only enabled +    // when there is at least 1 item that was pasted from inventory (doesn't need +    // to have a matching texture for these operations) +    if (mItemNamesItems.size() > 0) +    { +        mLogMissingThumbnailsBtn->setEnabled(true); +        mClearThumbnailsBtn->setEnabled(true); +    } +    else +    { +        mLogMissingThumbnailsBtn->setEnabled(false); +        mClearThumbnailsBtn->setEnabled(false); +    } +} + +// Helper function for writing a line to the log window. Currently the only additional +// feature is that it scrolls to the bottom each time a line is written but it +// is envisaged that other common actions will be added here eventually - E.G. write eavh +// line to the Second Life log too for example. +void LLFloaterInventoryThumbnailsHelper::writeToLog(std::string logline, bool prepend_newline) +{ +    mOutputLog->appendText(logline, prepend_newline); + +    mOutputLog->setCursorAndScrollToEnd(); +} diff --git a/indra/newview/llfloaterinventorythumbnailshelper.h b/indra/newview/llfloaterinventorythumbnailshelper.h new file mode 100644 index 0000000000..b42a85d1a5 --- /dev/null +++ b/indra/newview/llfloaterinventorythumbnailshelper.h @@ -0,0 +1,82 @@ +/** + * @file llfloaterinventorythumbnailshelper.h + * @author Callum Prentice + * @brief Helper floater for bulk processing of inventory thumbnails tool + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERINVENTORYTHUMBNAILSHELPER_H +#define LL_LLFLOATERINVENTORYTHUMBNAILSHELPER_H + +#include "llfloater.h" +class LLTextEditor; +class LLScrollListCtrl; +class LLViewerInventoryItem; +class LLUUID; + +class LLFloaterInventoryThumbnailsHelper: +    public LLFloater +{ +        friend class LLFloaterReg; +    private: +        LLFloaterInventoryThumbnailsHelper(const LLSD& key); +        BOOL postBuild() override; +        ~LLFloaterInventoryThumbnailsHelper(); + +        LLScrollListCtrl* mInventoryThumbnailsList; + +        LLTextEditor* mOutputLog; + +        LLUICtrl* mPasteItemsBtn; +        void onPasteItems(); + +        LLUICtrl* mPasteTexturesBtn; +        void onPasteTextures(); + +        LLUICtrl* mWriteThumbnailsBtn; +        void onWriteThumbnails(); + +        LLUICtrl* mLogMissingThumbnailsBtn; +        void onLogMissingThumbnails(); + +        LLUICtrl* mClearThumbnailsBtn; +        void onClearThumbnails(); + +        void recordInventoryItemEntry(LLViewerInventoryItem* item); +        void recordTextureItemEntry(LLViewerInventoryItem* item); +        void updateButtonStates(); +        void updateDisplayList(); +        void writeToLog(std::string logline, bool prepend_newline); + +        std::map<std::string, LLViewerInventoryItem*> mItemNamesItems; +        std::map<std::string, LLUUID> mTextureNamesIDs; + +        enum EListColumnNum +        { +            NAME = 0, +            EXISTING_TEXTURE = 1, +            NEW_TEXTURE = 2 +        }; +}; + +#endif // LL_LLFLOATERINVENTORYTHUMBNAILSHELPER_H diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 8f3ec8af05..e509e8cef1 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -290,6 +290,7 @@ void* LLFloaterWorldMap::createWorldMapView(void* data)  BOOL LLFloaterWorldMap::postBuild()  {      mMapView = dynamic_cast<LLWorldMapView*>(getChild<LLPanel>("objects_mapview")); +    mMapView->setPan(0, 0, true);  	LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");  	avatar_combo->selectFirstItem(); diff --git a/indra/newview/llinspecttexture.cpp b/indra/newview/llinspecttexture.cpp index da4e3c0949..76e428b7d0 100644 --- a/indra/newview/llinspecttexture.cpp +++ b/indra/newview/llinspecttexture.cpp @@ -84,7 +84,10 @@ LLToolTip* LLInspectTextureUtil::createInventoryToolTip(LLToolTip::Params p)                          }                      }  				} - +                if ((!p.message.isProvided() || p.message().empty()))  +                { +                    return NULL; +                }  				// No or more than one texture found => show default tooltip  				return LLUICtrlFactory::create<LLToolTip>(p);  			} diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index cb5316ddf4..de987d2dbd 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2810,7 +2810,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,              is_movable = can_move_folder_to_marketplace(master_folder, dest_folder, inv_cat, tooltip_msg, bundle_size);  		} -		if (is_movable) +		if (is_movable && !move_is_into_landmarks)  		{  			LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);  			is_movable = active_panel != NULL; diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 4aeacae6ed..6662f14b12 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -462,6 +462,13 @@ void copy_inventory_category(LLInventoryModel* model,  	gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID());  } +void copy_cb(const LLUUID& dest_folder, const LLUUID& root_id) +{ +    // Decrement the count in root_id since that one item won't be copied over +    LLMarketplaceData::instance().decrementValidationWaiting(root_id); +    update_folder_cb(dest_folder); +}; +  void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items)  {  	model->notifyObservers(); @@ -480,12 +487,21 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode  		LLMarketplaceData::instance().setValidationWaiting(root_id, count_descendants_items(cat->getUUID()));  	} +    LLPointer<LLInventoryCallback> cb; +    if (root_copy_id.isNull()) +    { +        cb = new LLBoostFuncInventoryCallback(boost::bind(copy_cb, new_cat_uuid, root_id)); +    } +    else +    { +        cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid)); +    } +  	// Copy all the items  	LLInventoryModel::item_array_t item_array_copy = *item_array;  	for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++)  	{  		LLInventoryItem* item = *iter; -		LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid));  		if (item->getIsLinkType())  		{ @@ -500,8 +516,11 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode  				LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *)item;  				gInventory.changeItemParent(viewer_inv_item, new_cat_uuid, true);  			} -			// Decrement the count in root_id since that one item won't be copied over -			LLMarketplaceData::instance().decrementValidationWaiting(root_id); +            if (root_copy_id.isNull()) +            { +                // Decrement the count in root_id since that one item won't be copied over +                LLMarketplaceData::instance().decrementValidationWaiting(root_id); +            }  		}  		else  		{ diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 62180bb066..212f8b0446 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -2386,30 +2386,46 @@ BOOL LLInventoryGallery::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,      return handled;  } -void LLInventoryGallery::startDrag() +void LLInventoryGallery::startDrag()   {      std::vector<EDragAndDropType> types;      uuid_vec_t ids; +    LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_AGENT;      for (LLUUID& selected_id : mSelectedItemIDs)      {          const LLInventoryItem* item = gInventory.getItem(selected_id);          if (item)          { +            if (item->getPermissions().getOwner() == ALEXANDRIA_LINDEN_ID) +            { +                src = LLToolDragAndDrop::SOURCE_LIBRARY; +            } +              EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(item->getType());              types.push_back(type);              ids.push_back(selected_id);          }          const LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id);         -        if (cat && gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID()) -            && !LLFolderType::lookupIsProtectedType((cat)->getPreferredType())) +        if (cat)          { -            EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(cat->getType()); -            types.push_back(type); -            ids.push_back(selected_id); +            if (gInventory.isObjectDescendentOf(selected_id, gInventory.getLibraryRootFolderID())) +            { +                src = LLToolDragAndDrop::SOURCE_LIBRARY; +                EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(cat->getType()); +                types.push_back(type); +                ids.push_back(selected_id); +            } +            else if (gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID()) +                && !LLFolderType::lookupIsProtectedType((cat)->getPreferredType())) +            { +                EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(cat->getType()); +                types.push_back(type); +                ids.push_back(selected_id); +            }          }      } -    LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, LLToolDragAndDrop::SOURCE_AGENT); +    LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, src);  }  bool LLInventoryGallery::areViewsInitialized() diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 281a8bc789..655bdfca6b 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -358,7 +358,6 @@ void LLInventoryFetchItemsObserver::startFetch()                      {                          // Start fetching whole folder since we need all items                          LLInventoryModelBackgroundFetch::getInstance()->scheduleFolderFetch(folder.first, true); -                      }                      else                      { diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp index 583742f970..8f03b13d2d 100644 --- a/indra/newview/llmachineid.cpp +++ b/indra/newview/llmachineid.cpp @@ -88,6 +88,7 @@ void LLWMIMethods::initCOMObjects()      mHR = CoInitializeEx(0, COINIT_MULTITHREADED);      if (FAILED(mHR))      { +        // if result S_FALSE, it's already initialized          LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << std::hex << mHR << LL_ENDL;          return;      } diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 8784f403cb..d27ee941a6 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -611,27 +611,17 @@ private:      static void onIdleProcessQueue(void *userdata);      // doesn't hold just marketplace related ids -    static std::set<LLUUID> sAddQueue;      static std::set<LLUUID> sStructureQueue;      static bool sProcessingQueue;  }; -std::set<LLUUID> LLMarketplaceInventoryObserver::sAddQueue;  std::set<LLUUID> LLMarketplaceInventoryObserver::sStructureQueue;  bool LLMarketplaceInventoryObserver::sProcessingQueue = false;  void LLMarketplaceInventoryObserver::changed(U32 mask)  { -	if (mask & LLInventoryObserver::ADD && LLMarketplaceData::instance().hasValidationWaiting()) -	{ -        // When things are added to the marketplace, we might need to re-validate and fix the containing listings -        // just add whole list even if it contains items and non-marketplace folders -        const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); -        sAddQueue.insert(changed_items.begin(), changed_items.end()); -	} -     -	if (mask & (LLInventoryObserver::INTERNAL | LLInventoryObserver::STRUCTURE)) -	{ +    if (mask & (LLInventoryObserver::INTERNAL | LLInventoryObserver::STRUCTURE)) +    {          // When things are changed in the inventory, this can trigger a host of changes in the marketplace listings folder:          // * stock counts changing : no copy items coming in and out will change the stock count on folders          // * version and listing folders : moving those might invalidate the marketplace data itself @@ -641,7 +631,7 @@ void LLMarketplaceInventoryObserver::changed(U32 mask)          sStructureQueue.insert(changed_items.begin(), changed_items.end());  	} -    if (!sProcessingQueue && (!sAddQueue.empty() || !sStructureQueue.empty())) +    if (!sProcessingQueue && !sStructureQueue.empty())      {          gIdleCallbacks.addFunction(onIdleProcessQueue, NULL);          // can do without sProcessingQueue, but it's usufull for simplicity and reliability @@ -655,40 +645,6 @@ void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata)      const U64 MAX_PROCESSING_TIME = 1000;      U64 stop_time = start_time + MAX_PROCESSING_TIME; -    if (!sAddQueue.empty()) -    { -        // Make a copy of sAddQueue since decrementValidationWaiting -        // can theoretically add more items -        std::set<LLUUID> add_queue(sAddQueue); -        sAddQueue.clear(); - -        std::set<LLUUID>::const_iterator id_it = add_queue.begin(); -        std::set<LLUUID>::const_iterator id_end = add_queue.end(); -        // First, count the number of items in this list... -        S32 count = 0; -        for (; id_it != id_end; ++id_it) -        { -            LLInventoryObject* obj = gInventory.getObject(*id_it); -            if (obj && (LLAssetType::AT_CATEGORY != obj->getType())) -            { -                count++; -            } -        } -        // Then, decrement the folders of that amount -        // Note that of all of those, only one folder will be a listing folder (if at all). -        // The other will be ignored by the decrement method. -        id_it = add_queue.begin(); -        for (; id_it != id_end; ++id_it) -        { -            LLInventoryObject* obj = gInventory.getObject(*id_it); -            if (obj && (LLAssetType::AT_CATEGORY == obj->getType())) -            { -                // can trigger notifyObservers -                LLMarketplaceData::instance().decrementValidationWaiting(obj->getUUID(), count); -            } -        } -    } -      while (!sStructureQueue.empty() && LLTimer::getTotalTime() < stop_time)      {          std::set<LLUUID>::const_iterator id_it = sStructureQueue.begin(); @@ -722,7 +678,7 @@ void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata)          sStructureQueue.erase(id_it);      } -    if (LLApp::isExiting() || (sAddQueue.empty() && sStructureQueue.empty())) +    if (LLApp::isExiting() || sStructureQueue.empty())      {          // Nothing to do anymore          gIdleCallbacks.deleteFunction(onIdleProcessQueue, NULL); diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index de988555c5..b26aabca4f 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1155,22 +1155,13 @@ LLContextMenu* LLOutfitGalleryContextMenu::createMenu()      registrar.add("Outfit.Delete", boost::bind(LLOutfitGallery::onRemoveOutfit, selected_id));      registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2));      registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitGalleryContextMenu::onThumbnail, this, selected_id)); +    registrar.add("Outfit.Save", boost::bind(&LLOutfitGalleryContextMenu::onSave, this, selected_id));      enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitGalleryContextMenu::onEnable, this, _2));      enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitGalleryContextMenu::onVisible, this, _2));      return createFromFile("menu_gallery_outfit_tab.xml");  } -void LLOutfitGalleryContextMenu::onThumbnail(const LLUUID& outfit_cat_id) -{ -    LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList); -    if (gallery && outfit_cat_id.notNull()) -    { -        LLSD data(outfit_cat_id); -        LLFloaterReg::showInstance("change_item_thumbnail", data); -    } -} -  void LLOutfitGalleryContextMenu::onCreate(const LLSD& data)  {      LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(data.asString()); @@ -1205,7 +1196,6 @@ void LLOutfitGalleryGearMenu::onUpdateItemsVisibility()      mMenu->setItemVisible("expand", FALSE);      mMenu->setItemVisible("collapse", FALSE);      mMenu->setItemVisible("thumbnail", have_selection); -    mMenu->setItemVisible("sepatator3", TRUE);      mMenu->setItemVisible("sort_folders_by_name", TRUE);      LLOutfitListGearMenuBase::onUpdateItemsVisibility();  } diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h index 9915752962..b18151599f 100644 --- a/indra/newview/lloutfitgallery.h +++ b/indra/newview/lloutfitgallery.h @@ -195,17 +195,13 @@ public:      friend class LLOutfitGallery;      LLOutfitGalleryContextMenu(LLOutfitListBase* outfit_list) -    : LLOutfitContextMenu(outfit_list), -    mOutfitList(outfit_list){} +    : LLOutfitContextMenu(outfit_list){}  protected:      /* virtual */ LLContextMenu* createMenu();      bool onEnable(LLSD::String param);      bool onVisible(LLSD::String param); -    void onThumbnail(const LLUUID& outfit_cat_id);      void onCreate(const LLSD& data); -private: -    LLOutfitListBase*	mOutfitList;  }; diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 5c7792b0df..676444397f 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -37,6 +37,7 @@  #include "llappearancemgr.h"  #include "llfloaterreg.h"  #include "llfloatersidepanelcontainer.h" +#include "llinspecttexture.h"  #include "llinventoryfunctions.h"  #include "llinventorymodel.h"  #include "llmenubutton.h" @@ -62,7 +63,7 @@ bool LLOutfitTabNameComparator::compare(const LLAccordionCtrlTab* tab1, const LL      return (LLStringUtil::compareDict(name1, name2) < 0);  } -struct outfit_accordion_tab_params : public LLInitParam::Block<outfit_accordion_tab_params, LLAccordionCtrlTab::Params> +struct outfit_accordion_tab_params : public LLInitParam::Block<outfit_accordion_tab_params, LLOutfitAccordionCtrlTab::Params>  {  	Mandatory<LLWearableItemsList::Params> wearable_list; @@ -144,7 +145,8 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id)      std::string name = cat->getName();      outfit_accordion_tab_params tab_params(get_accordion_tab_params()); -    LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(tab_params); +    tab_params.cat_id = cat_id; +    LLOutfitAccordionCtrlTab *tab = LLUICtrlFactory::create<LLOutfitAccordionCtrlTab>(tab_params);      if (!tab) return;      LLWearableItemsList* wearable_list = LLUICtrlFactory::create<LLWearableItemsList>(tab_params.wearable_list);      wearable_list->setShape(tab->getLocalRect()); @@ -1028,6 +1030,8 @@ LLContextMenu* LLOutfitContextMenu::createMenu()      registrar.add("Outfit.Edit", boost::bind(editOutfit));      registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));      registrar.add("Outfit.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList)); +    registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitContextMenu::onThumbnail, this, selected_id)); +    registrar.add("Outfit.Save", boost::bind(&LLOutfitContextMenu::onSave, this, selected_id));      enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitContextMenu::onEnable, this, _2));      enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitContextMenu::onVisible, this, _2)); @@ -1092,6 +1096,31 @@ void LLOutfitContextMenu::renameOutfit(const LLUUID& outfit_cat_id)      LLAppearanceMgr::instance().renameOutfit(outfit_cat_id);  } +void LLOutfitContextMenu::onThumbnail(const LLUUID &outfit_cat_id) +{ +    if (outfit_cat_id.notNull()) +    { +        LLSD data(outfit_cat_id); +        LLFloaterReg::showInstance("change_item_thumbnail", data); +    } +} + +void LLOutfitContextMenu::onSave(const LLUUID &outfit_cat_id) +{ +    if (outfit_cat_id.notNull()) +    { +        LLNotificationsUtil::add("ConfirmOverwriteOutfit", LLSD(), LLSD(), +            [outfit_cat_id](const LLSD ¬if, const LLSD &resp) +        { +            S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); +            if (opt == 0) +            { +                LLAppearanceMgr::getInstance()->onOutfitFolderCreated(outfit_cat_id, true); +            } +        }); +    } +} +  LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist)      :   mOutfitList(olist),          mMenu(NULL) @@ -1110,6 +1139,7 @@ LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist)      registrar.add("Gear.Expand", boost::bind(&LLOutfitListBase::onExpandAllFolders, mOutfitList));      registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenuBase::onAdd, this)); +    registrar.add("Gear.Save", boost::bind(&LLOutfitListGearMenuBase::onSave, this));      registrar.add("Gear.Thumbnail", boost::bind(&LLOutfitListGearMenuBase::onThumbnail, this));      registrar.add("Gear.SortByName", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this)); @@ -1135,8 +1165,7 @@ void LLOutfitListGearMenuBase::onUpdateItemsVisibility()      if (!mMenu) return;      bool have_selection = getSelectedOutfitID().notNull(); -    mMenu->setItemVisible("sepatator1", have_selection); -    mMenu->setItemVisible("sepatator2", have_selection); +    mMenu->setItemVisible("wear_separator", have_selection);      mMenu->arrangeAndClear(); // update menu height  } @@ -1181,6 +1210,20 @@ void LLOutfitListGearMenuBase::onAdd()      }  } +void LLOutfitListGearMenuBase::onSave() +{ +    const LLUUID &selected_id = getSelectedOutfitID(); +    LLNotificationsUtil::add("ConfirmOverwriteOutfit", LLSD(), LLSD(), +        [selected_id](const LLSD ¬if, const LLSD &resp) +    { +        S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); +        if (opt == 0) +        { +            LLAppearanceMgr::getInstance()->onOutfitFolderCreated(selected_id, true); +        } +    }); +} +  void LLOutfitListGearMenuBase::onTakeOff()  {      // Take off selected outfit. @@ -1234,15 +1277,6 @@ bool LLOutfitListGearMenuBase::onVisible(LLSD::String param)          return false;      } -    // *TODO This condition leads to menu item behavior inconsistent with -    // "Wear" button behavior and should be modified or removed. -    bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == selected_outfit_id; - -    if ("wear" == param) -    { -        return !is_worn; -    } -      return true;  } @@ -1270,10 +1304,29 @@ void LLOutfitListGearMenu::onUpdateItemsVisibility()      if (!mMenu) return;      mMenu->setItemVisible("expand", TRUE);      mMenu->setItemVisible("collapse", TRUE); -    mMenu->setItemVisible("thumbnail", FALSE); // Never visible? -    mMenu->setItemVisible("sepatator3", FALSE); +    mMenu->setItemVisible("thumbnail", getSelectedOutfitID().notNull());      mMenu->setItemVisible("sort_folders_by_name", FALSE);      LLOutfitListGearMenuBase::onUpdateItemsVisibility();  } +BOOL LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) +{ +    if (y >= getLocalRect().getHeight() - getHeaderHeight())  +    { +        LLSD params; +        params["inv_type"] = LLInventoryType::IT_CATEGORY; +        params["thumbnail_id"] = gInventory.getCategory(mFolderID)->getThumbnailUUID(); +        params["item_id"] = mFolderID; + +        LLToolTipMgr::instance().show(LLToolTip::Params() +                                    .message(getToolTip()) +                                    .sticky_rect(calcScreenRect()) +                                    .delay_time(LLView::getTooltipTimeout()) +                                    .create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1)) +                                    .create_params(params)); +        return TRUE; +    } + +    return LLAccordionCtrlTab::handleToolTip(x, y, mask); +}  // EOF diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index 66b3165169..6eeccddb07 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -31,6 +31,7 @@  #include "llpanel.h"  // newview +#include "llaccordionctrltab.h"  #include "llinventorymodel.h"  #include "lllistcontextmenu.h"  #include "llpanelappearancetab.h" @@ -147,6 +148,9 @@ protected:      static void renameOutfit(const LLUUID& outfit_cat_id); +    void onThumbnail(const LLUUID &outfit_cat_id); +    void onSave(const LLUUID &outfit_cat_id); +  private:      LLOutfitListBase*	mOutfitList;  }; @@ -178,6 +182,7 @@ private:      void onAdd();      void onTakeOff();      void onRename(); +    void onSave();      void onCreate(const LLSD& data);      bool onEnable(LLSD::String param);      bool onVisible(LLSD::String param); @@ -193,7 +198,27 @@ protected:      /*virtual*/ void onUpdateItemsVisibility();  }; -/** +class LLOutfitAccordionCtrlTab : public LLAccordionCtrlTab +{ +public: +    struct Params : public LLInitParam::Block<Params, LLAccordionCtrlTab::Params> +    { +        Optional<LLUUID> cat_id; +        Params() : cat_id("cat_id") {} +    }; + +    virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); + + protected: +    LLOutfitAccordionCtrlTab(const LLOutfitAccordionCtrlTab::Params &p)  +        : LLAccordionCtrlTab(p),  +          mFolderID(p.cat_id) +    {} +    friend class LLUICtrlFactory; + +    LLUUID mFolderID; +}; +  /**   * @class LLOutfitsList   *   * A list of agents's outfits from "My Outfits" inventory category diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index b938b30479..3ed444a5af 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -1067,6 +1067,12 @@ void LLTeleportHistoryPanel::onGearMenuAction(const LLSD& userdata)          LLLandmarkActions::getSLURLfromPosGlobal(globalPos,              boost::bind(&LLTeleportHistoryPanel::gotSLURLCallback, _1));      } +    else if ("remove" == command_name) +    { +        LLTeleportHistoryStorage::getInstance()->removeItem(index); +        LLTeleportHistoryStorage::getInstance()->save(); +        showTeleportHistory(); +    }  }  bool LLTeleportHistoryPanel::isActionEnabled(const LLSD& userdata) const @@ -1121,7 +1127,8 @@ bool LLTeleportHistoryPanel::isActionEnabled(const LLSD& userdata) const      if ("teleport" == command_name          || "view" == command_name          || "show_on_map" == command_name -        || "copy_slurl" == command_name) +        || "copy_slurl" == command_name +        || "remove" == command_name)      {          if (!mLastSelectedFlatlList)          { diff --git a/indra/newview/llperfstats.cpp b/indra/newview/llperfstats.cpp index 64e66d520b..8718f7e7b0 100644 --- a/indra/newview/llperfstats.cpp +++ b/indra/newview/llperfstats.cpp @@ -69,7 +69,7 @@ namespace LLPerfStats      {          assert_main_thread();          // these following variables are proxies for pipeline statics we do not need a two way update (no llviewercontrol handler) -        if( tuningFlag & NonImpostors ){ gSavedSettings.setU32("IndirectMaxNonImpostors", nonImpostors); }; +        if( tuningFlag & NonImpostors ){ gSavedSettings.setU32("RenderAvatarMaxNonImpostors", nonImpostors); };          if( tuningFlag & ReflectionDetail ){ gSavedSettings.setS32("RenderReflectionDetail", reflectionDetail); };          if( tuningFlag & FarClip ){ gSavedSettings.setF32("RenderFarClip", farClip); };          if( tuningFlag & UserMinDrawDistance ){ gSavedSettings.setF32("AutoTuneRenderFarClipMin", userMinDrawDistance); }; @@ -378,7 +378,7 @@ namespace LLPerfStats              auto count = countNearbyAvatars(std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance));              if( count != tunables.nonImpostors )              { -                tunables.updateNonImposters( (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER ); +                tunables.updateNonImposters( (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : 0 );                  LL_DEBUGS("AutoTune") << "There are " << count << "avatars within " << std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance) << "m of the camera" << LL_ENDL;              }          } diff --git a/indra/newview/llplacesinventorypanel.cpp b/indra/newview/llplacesinventorypanel.cpp index 1c14acd843..f3455bb4f0 100644 --- a/indra/newview/llplacesinventorypanel.cpp +++ b/indra/newview/llplacesinventorypanel.cpp @@ -120,3 +120,13 @@ S32	LLPlacesInventoryPanel::notify(const LLSD& info)  	}  	return 0;  } + +BOOL LLPlacesInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, +                                                      EAcceptance *accept, std::string &tooltip_msg) +{ +    if (mAcceptsDragAndDrop)  +    { +        return LLInventoryPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); +    } +    return FALSE; +} diff --git a/indra/newview/llplacesinventorypanel.h b/indra/newview/llplacesinventorypanel.h index 3c27964ec5..81b623b045 100644 --- a/indra/newview/llplacesinventorypanel.h +++ b/indra/newview/llplacesinventorypanel.h @@ -47,11 +47,14 @@ public:  	LLPlacesInventoryPanel(const Params& p);  	~LLPlacesInventoryPanel(); -    LLFolderView * createFolderRoot(LLUUID root_id ); +    LLFolderView * createFolderRoot(LLUUID root_id ) override;  	void saveFolderState();  	void restoreFolderState(); -	virtual S32	notify(const LLSD& info) ; +	virtual S32	notify(const LLSD& info) override; + +    BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, +                            EAcceptance *accept, std::string &tooltip_msg) override;  private:  	LLSaveFolderState*			mSavedFolderState; diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 6da0e9d695..19e2655bf9 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -86,6 +86,7 @@  #include "llfloaterimsession.h"  #include "llfloaterinspect.h"  #include "llfloaterinventorysettings.h" +#include "llfloaterinventorythumbnailshelper.h"  #include "llfloaterjoystick.h"  #include "llfloaterlagmeter.h"  #include "llfloaterland.h" @@ -243,6 +244,7 @@ public:                  "group_picker",                  "hud",                  "incoming_call", +                "inventory_thumbnails_helper",                  "linkreplace",                  "mem_leaking",                  "marketplace_validation", @@ -329,7 +331,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("build", "floater_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTools>);  	LLFloaterReg::add("build_options", "floater_build_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuildOptions>);  	LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBump>); - +      	LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>);  	LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCameraPresets>);  	LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>); @@ -376,6 +378,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>);  	LLFloaterReg::add("inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>);  	LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>); +    LLFloaterReg::add("inventory_thumbnails_helper", "floater_inventory_thumbnails_helper.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterInventoryThumbnailsHelper>);  	LLFloaterReg::add("item_properties", "floater_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>);      LLFloaterReg::add("task_properties", "floater_task_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>);      LLFloaterReg::add("inventory_settings", "floater_inventory_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventorySettings>); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index ada898b98c..55e43352bc 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4158,6 +4158,12 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)  					LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id);  					for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it)  					{ +						if (anim_it->first != object_id) +						{ +							// elements with the same key are always contiguous, bail if we went past the +							// end of this object's animations +							break; +						}  						if (anim_it->second == animation_id)  						{  							anim_found = TRUE; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 5bc7523be1..a53bd982d4 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -2043,6 +2043,7 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)  			{  				LL_WARNS() << objectp->mID << " has self as parent, skipping!"   					<< LL_ENDL; +                ++iter;  				continue;  			} diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 6e5b387b36..34efb39848 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -834,7 +834,11 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id)  	for (AnimSourceIterator motion_it = mAnimationSources.find(source_id); motion_it != mAnimationSources.end(); )  	{  		gAgent.sendAnimationRequest(motion_it->second, ANIM_REQUEST_STOP); -		mAnimationSources.erase(motion_it++); +		mAnimationSources.erase(motion_it); +		// Must find() after each erase() to deal with potential iterator invalidation +		// This also ensures that we don't go past the end of this source's animations +		// into those of another source. +		motion_it = mAnimationSources.find(source_id);  	} diff --git a/indra/newview/skins/default/xui/en/floater_inventory_thumbnails_helper.xml b/indra/newview/skins/default/xui/en/floater_inventory_thumbnails_helper.xml new file mode 100644 index 0000000000..aa3500bac2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_inventory_thumbnails_helper.xml @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater +  legacy_header_height="18" +  can_resize="false" +  height="600" +  layout="topleft" +  min_height="175" +  min_width="500" +  name="contents" +  help_topic="contents" +  title="Inventory Thumbnails Helper" +  width="800"> +    <scroll_list +       top="20" +       height="350" +       draw_stripes="true" +       draw_heading="true" +       follows="all" +       layout="topleft" +       left="8" +       multi_select="true" +       name="inventory_thumbnails_list" +       right="-8" +       tool_tip="Paste items from your inventory"> +        <scroll_list.columns +             dynamic_width="true" +             label="Inventory Item" +             name="item_name" +             relative_width="0.4" /> +        <scroll_list.columns +             dynamic_width="true" +             label="Existing Texture" +             name="existing_texture" +             relative_width="0.3" /> +        <scroll_list.columns +             dynamic_width="true" +             label="New Texture" +             name="new_texture" +             relative_width="0.3" /> +    </scroll_list> +    <text_editor +      top="375" +      height="140" +      follows="all" +      left="8" +      right="-8" +      name="output_log" +      font="Monospace" +      text_color="0.1 0.5 0.1 1.0" +      width="480"> +    </text_editor> +    <button +      follows="left|bottom" +      height="20" +      label="Paste items from Inventory" +      layout="topleft" +      left="10" +      name="paste_items_btn" +      bottom="-60" +      width="235" /> +    <button +      follows="left|bottom" +      height="20" +      label="Paste textures from Inventory" +      layout="topleft" +      left_delta="0" +      name="paste_textures_btn" +      top_delta="26	" +      width="235" /> +    <button +      follows="left|bottom" +      height="20" +      label="Write Thumbnails" +      layout="topleft" +      left_delta="0" +      name="write_thumbnails_btn" +      top_delta="26	" +      width="235" /> +    <button +      follows="left|bottom" +      height="20" +      label="Log items with no thumbnail" +      layout="bottomleft" +      right="-10" +      name="log_missing_thumbnails_btn" +      bottom="60" +      width="235" /> +    <button +      follows="left|bottom" +      height="20" +      label="Clear thumbnails from pasted items" +      layout="bottomleft" +      right="-10" +      name="clear_thumbnails_btn" +      top_delta="26" +      width="235" /> + + +</floater>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml index d82c453e5f..8cf0479b27 100644 --- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml @@ -35,7 +35,7 @@       layout="topleft"       name="Folder Wearables Separator" />      <menu_item_call -     label="Replace Current Outfit" +     label="Replace current outfit"       layout="topleft"       name="Replace Outfit">          <menu_item_call.on_click @@ -43,7 +43,7 @@           parameter="replaceoutfit" />      </menu_item_call>      <menu_item_call -     label="Add To Current Outfit" +     label="Add folder items"       layout="topleft"       name="Add To Outfit">          <menu_item_call.on_click @@ -51,7 +51,7 @@           parameter="addtooutfit" />      </menu_item_call>      <menu_item_call -     label="Remove From Current Outfit" +     label="Take off folder items"       layout="topleft"       name="Remove From Outfit">          <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml index 0ca505dd5d..c93a92b2b7 100755 --- a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml @@ -3,7 +3,7 @@      layout="topleft"      name="Outfit">      <menu_item_call -        label="Wear - Replace Current Outfit" +        label="Replace current outfit"          layout="topleft"          name="wear_replace">          <on_click @@ -16,7 +16,7 @@          parameter="wear_replace" />      </menu_item_call>      <menu_item_call -        label="Wear - Add to Current Outfit" +        label="Add outfit items"          layout="topleft"          name="wear_add">          <on_click @@ -29,7 +29,7 @@          parameter="wear_add" />      </menu_item_call>      <menu_item_call -        label="Take Off - Remove from Current Outfit" +        label="Take off outfit items"          layout="topleft"          name="take_off">          <on_click @@ -41,17 +41,60 @@          function="Outfit.OnVisible"          parameter="take_off" />      </menu_item_call> +    <menu_item_separator/>      <menu_item_call -     label="Image..." -     layout="topleft" -     name="thumbnail"> +        label="Image..." +        layout="topleft" +        name="thumbnail"> +        <on_click +        function="Outfit.Thumbnail" /> +    </menu_item_call> +    <menu_item_call +        label="Edit outfit" +        layout="topleft" +        name="edit"> +        <on_click +        function="Outfit.Edit" /> +        <on_visible +        function="Outfit.OnVisible" +        parameter="edit" /> +    </menu_item_call> +    <menu_item_call +        label="Rename outfit" +        layout="topleft" +        name="rename"> +        <on_click +        function="Outfit.Rename" /> +        <on_enable +        function="Outfit.OnEnable" +        parameter="rename" /> +    </menu_item_call> +    <menu_item_call +        label="Save to this outfit" +        layout="topleft" +        name="save"> +        <on_click +         function="Outfit.Save" /> +    </menu_item_call> +    <menu_item_separator> +        <on_visible +        function="Outfit.OnVisible" +        parameter="delete" /> +    </menu_item_separator> +    <menu_item_call +        label="Delete outfit" +        layout="topleft" +        name="delete">          <on_click -         function="Outfit.Thumbnail" /> +        function="Outfit.Delete" /> +        <on_visible +        function="Outfit.OnVisible" +        parameter="delete" />      </menu_item_call> -    <menu_item_separator name="sepatator1" /> +    <menu_item_separator/>      <menu          height="175" -        label="New Clothes" +        label="New clothes"          layout="topleft"          left_delta="0"          mouse_opaque="false" @@ -157,7 +200,7 @@      </menu>      <menu          height="85" -        label="New Body Parts" +        label="New body parts"          layout="topleft"          left_delta="0"          mouse_opaque="false" @@ -197,35 +240,4 @@              parameter="eyes" />          </menu_item_call>      </menu> -    <menu_item_separator name="sepatator2" /> -    <menu_item_call -        label="Edit Outfit" -        layout="topleft" -        name="edit"> -        <on_click -        function="Outfit.Edit" /> -        <on_visible -        function="Outfit.OnVisible" -        parameter="edit" /> -    </menu_item_call> -    <menu_item_call -        label="Rename Outfit" -        layout="topleft" -        name="rename"> -        <on_click -        function="Outfit.Rename" /> -        <on_enable -        function="Outfit.OnEnable" -        parameter="rename" /> -    </menu_item_call> -    <menu_item_call -        label="Delete Outfit" -        layout="topleft" -        name="delete"> -        <on_click -        function="Outfit.Delete" /> -        <on_visible -        function="Outfit.OnVisible" -        parameter="delete" /> -    </menu_item_call>  </context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 3a8f360e2d..71f450baac 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -264,7 +264,7 @@       layout="topleft"       name="Folder Wearables Separator" />      <menu_item_call -     label="Replace Current Outfit" +     label="Replace current outfit"       layout="topleft"       name="Replace Outfit">          <menu_item_call.on_click @@ -272,7 +272,7 @@           parameter="replaceoutfit" />      </menu_item_call>      <menu_item_call -     label="Add To Current Outfit" +     label="Add folder items"       layout="topleft"       name="Add To Outfit">          <menu_item_call.on_click @@ -280,7 +280,7 @@           parameter="addtooutfit" />      </menu_item_call>      <menu_item_call -     label="Remove From Current Outfit" +     label="Take off folder items"       layout="topleft"       name="Remove From Outfit">          <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml index e216962d12..e7a453766b 100644 --- a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml @@ -4,7 +4,7 @@   visible="false"   name="Gear Outfit">      <menu_item_call -     label="Wear - Replace Current Outfit" +     label="Replace current outfit"       layout="topleft"       name="wear">          <on_click @@ -17,7 +17,7 @@           parameter="wear" />      </menu_item_call>      <menu_item_call -     label="Wear - Add to Current Outfit" +     label="Add outfit items"       layout="topleft"       name="wear_add">          <on_click @@ -25,9 +25,11 @@          <on_enable           function="Gear.OnEnable"           parameter="wear_add" /> +        <on_visible +         function="Gear.OnVisible"/>      </menu_item_call>      <menu_item_call -     label="Take Off - Remove from Current Outfit" +     label="Take off outfit items"       layout="topleft"       name="take_off">          <on_click @@ -39,19 +41,88 @@           function="Gear.OnVisible"           parameter="take_off" />      </menu_item_call> +    <menu_item_separator name="wear_separator" />      <menu_item_call       label="Image..."       layout="topleft"       name="thumbnail"> +       <on_click +        function="Gear.Thumbnail" /> +    </menu_item_call> +    <menu_item_call +     label="Rename outfit" +     layout="topleft" +     name="rename"> +        <on_click +         function="Gear.Rename" /> +        <on_enable +         function="Gear.OnEnable" +         parameter="rename" /> +        <on_visible +         function="Gear.OnVisible" +         parameter="rename" /> +    </menu_item_call> +    <menu_item_call +     label="Save to this outfit" +     layout="topleft" +     name="save"> +        <on_click +         function="Gear.Save" /> +        <on_visible +         function="Gear.OnVisible"/> +    </menu_item_call> +    <menu_item_separator> +        <on_visible +        function="Gear.OnVisible" +        parameter="delete" /> +    </menu_item_separator> +    <menu_item_call +     label="Delete outfit" +     layout="topleft" +     name="delete_outfit"> +        <on_click +         function="Gear.Delete" /> +        <on_enable +         function="Gear.OnEnable" +         parameter="delete" /> +        <on_visible +         function="Gear.OnVisible" +         parameter="delete" /> +    </menu_item_call> +    <menu_item_separator> +        <on_visible +         function="Gear.OnVisible"/> +    </menu_item_separator> +    <menu_item_check +     label="Sort folders always by name" +     layout="topleft" +     name="sort_folders_by_name"> +        <on_click +         function="Gear.SortByName" /> +        <on_check +         function="CheckControl" +         parameter="OutfitGallerySortByName" /> +    </menu_item_check> +        <menu_item_call +     label="Expand all folders" +     layout="topleft" +     name="expand"> +        <on_click +         function="Gear.Expand" /> +    </menu_item_call> +    <menu_item_call +     label="Collapse all folders" +     layout="topleft" +     name="collapse">          <on_click -         function="Gear.Thumbnail" /> +         function="Gear.Collapse" />      </menu_item_call> -  <menu_item_separator name="sepatator1" /> +  <menu_item_separator/>              <!-- copied (with minor modifications) from menu_inventory_add.xml -->              <!--  *TODO: generate dynamically? -->              <menu               height="175" -             label="New Clothes" +             label="New clothes"               layout="topleft"               left_delta="0"               mouse_opaque="false" @@ -165,7 +236,7 @@              </menu>              <menu               height="85" -             label="New Body Parts" +             label="New body parts"               layout="topleft"               left_delta="0"               mouse_opaque="false" @@ -206,57 +277,4 @@                  </menu_item_call>              </menu>              <!-- copied from menu_inventory_add.xml --> - -    <menu_item_separator name="sepatator2" /> -    <menu_item_call -     label="Expand all folders" -     layout="topleft" -     name="expand"> -        <on_click -         function="Gear.Expand" /> -    </menu_item_call> -    <menu_item_call -     label="Collapse all folders" -     layout="topleft" -     name="collapse"> -        <on_click -         function="Gear.Collapse" /> -    </menu_item_call> -    <menu_item_call -     label="Rename Outfit" -     layout="topleft" -     name="rename"> -        <on_click -         function="Gear.Rename" /> -        <on_enable -         function="Gear.OnEnable" -         parameter="rename" /> -        <on_visible -         function="Gear.OnVisible" -         parameter="rename" /> -    </menu_item_call> -    <menu_item_call -     label="Delete Outfit" -     layout="topleft" -     name="delete_outfit"> -        <on_click -         function="Gear.Delete" /> -        <on_enable -         function="Gear.OnEnable" -         parameter="delete" /> -        <on_visible -         function="Gear.OnVisible" -         parameter="delete" /> -    </menu_item_call> -    <menu_item_separator name="sepatator3" /> -    <menu_item_check -     label="Sort Folders Always by Name" -     layout="topleft" -     name="sort_folders_by_name"> -        <on_click -         function="Gear.SortByName" /> -        <on_check -         function="CheckControl" -         parameter="OutfitGallerySortByName" /> -    </menu_item_check>  </toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml index 8c8bb29baf..522e41df42 100644 --- a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml @@ -3,7 +3,7 @@   layout="topleft"   name="Outfit">      <menu_item_call -     label="Wear - Replace Current Outfit" +     label="Replace current outfit"       layout="topleft"       name="wear_replace">          <on_click @@ -16,7 +16,7 @@           parameter="wear_replace" />      </menu_item_call>      <menu_item_call -     label="Wear - Add to Current Outfit" +     label="Add outfit items"       layout="topleft"       name="wear_add">          <on_click @@ -29,7 +29,7 @@           parameter="wear_add" />      </menu_item_call>      <menu_item_call -     label="Take Off - Remove from Current Outfit" +     label="Take off outfit items"       layout="topleft"       name="take_off">          <on_click @@ -41,19 +41,26 @@           function="Outfit.OnVisible"           parameter="take_off" />      </menu_item_call> +    <menu_item_separator />      <menu_item_call -     label="Edit Outfit" -     layout="topleft" -     name="edit"> +        label="Image..." +        layout="topleft" +        name="thumbnail"> +        <on_click +        function="Outfit.Thumbnail" /> +    </menu_item_call> +    <menu_item_call +        label="Edit outfit" +        layout="topleft" +        name="edit">          <on_click           function="Outfit.Edit" />          <on_visible           function="Outfit.OnVisible"           parameter="edit" />      </menu_item_call> -    <menu_item_separator />      <menu_item_call -     label="Rename Outfit" +     label="Rename outfit"       layout="topleft"       name="rename">          <on_click @@ -63,7 +70,19 @@           parameter="rename" />      </menu_item_call>      <menu_item_call -     label="Delete Outfit" +     label="Save to this outfit" +     layout="topleft" +     name="save"> +        <on_click +         function="Outfit.Save" /> +    </menu_item_call> +    <menu_item_separator> +        <on_visible +        function="Outfit.OnVisible" +        parameter="delete" /> +    </menu_item_separator> +    <menu_item_call +     label="Delete outfit"       layout="topleft"       name="delete">          <on_click diff --git a/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml index 153e5a70a9..9bbfdd4291 100644 --- a/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml @@ -49,4 +49,17 @@           function="TeleportHistory.GearMenu.Enable"           parameter="copy_slurl" />      </menu_item_call> +    <menu_item_separator +     layout="topleft" /> +    <menu_item_call +     label="Remove from history" +     layout="topleft" +     name="remove_from_history"> +        <on_click +         function="TeleportHistory.GearMenu.Action" +         parameter="remove" /> +        <on_enable +         function="TeleportHistory.GearMenu.Enable" +         parameter="remove" /> +    </menu_item_call>  </toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 0bfdead6e7..3a671420be 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3520,6 +3520,21 @@ function="World.EnvPreset"               function="Advanced.WebContentTest"               parameter="http://duckduckgo.com"/>            </menu_item_call> +            <menu_item_call +             label="Inventory Thumbnails Helper" +             name="Inventory Thumbnails Helper" +				shortcut="control|alt|shift|X"> +                <menu_item_call.on_click +                 function="Floater.Show" +                 parameter="inventory_thumbnails_helper" /> +            </menu_item_call> +            <menu_item_call +           label="FB Connect Test" +           name="FB Connect Test"> +            <menu_item_call.on_click +             function="Advanced.WebContentTest" +             parameter="https://cryptic-ridge-1632.herokuapp.com/"/> +          </menu_item_call>            <menu_item_call               label="Dump SelectMgr"               name="Dump SelectMgr"> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index d1838fc7ef..ca93ca71ef 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -12248,6 +12248,50 @@ Would you like to save them first?         notext="No"         yestext="Yes"/>    </notification> + +  <notification +   icon="alertmodal.tga" +   name="ConfirmOverwriteOutfit" +   type="alertmodal"> +      <unique/> +This will replace the items in the +selected outfit with the items you +are wearing now. +      <tag>confirm</tag> +      <usetemplate +       ignoretext="Confirm before overwriting outfit" +       name="okcancelignore" +       notext="Cancel" +       yestext="Save"/> +  </notification> +     +  <notification +    icon="alertmodal.tga" +    name="ClearInventoryThumbnailsWarning" +    type="alertmodal"> +        You are about to remove thumbnail images from the inventory items in the list. This change cannot be undone. + +        Would you like to proceed? +   <tag>confirm</tag> +   <usetemplate +       name="okcancelbuttons" +       notext="No" +       yestext="Yes"/> +  </notification> + +  <notification +    icon="alertmodal.tga" +    name="WriteInventoryThumbnailsWarning" +    type="alertmodal"> +        You are about to overwrite thumbnail images for some or all of the inventory items in the list. This change cannot be undone. + +        Would you like to proceed? +   <tag>confirm</tag> +   <usetemplate +       name="okcancelbuttons" +       notext="No" +       yestext="Yes"/> +  </notification>    <notification      icon="notifytip.tga" diff --git a/indra/newview/skins/default/xui/en/panel_settings_water.xml b/indra/newview/skins/default/xui/en/panel_settings_water.xml index f19629df26..da2f915425 100644 --- a/indra/newview/skins/default/xui/en/panel_settings_water.xml +++ b/indra/newview/skins/default/xui/en/panel_settings_water.xml @@ -65,7 +65,7 @@                  Density Exponent:              </text>              <slider -                    decimal_digits="1" +                    decimal_digits="2"                      follows="left|top"                      height="16"                      increment="0.01" diff --git a/scripts/code_tools/modified_strings.py b/scripts/code_tools/modified_strings.py index e7a9d239dc..20ed1b0555 100644 --- a/scripts/code_tools/modified_strings.py +++ b/scripts/code_tools/modified_strings.py @@ -162,6 +162,8 @@ def make_translation_table(mod_tree, base_tree, lang, args):          filename = mod_blob.path          if mod_blob.type == "tree": # directory, skip              continue +        if args.files and os.path.basename(filename) not in args.files: +            continue # process only the specified files          if args.verbose:              print(filename) @@ -325,9 +327,11 @@ if __name__ == "__main__":      parser.add_argument("--deleted", action="store_true", default = False, help="show all translated entities which don't exist in english")      parser.add_argument("--skip_spreadsheet", action="store_true", default = False, help="skip creating the translation spreadsheet")      parser.add_argument("--rev", help="revision with modified strings, default HEAD", default="HEAD") -    parser.add_argument("--rev_base", help="previous revision to compare against, default master", default="master") +    parser.add_argument("--rev_base", help="previous revision to compare against, default main", default="main")      parser.add_argument("--base_lang", help="base language, default en (normally leave unchanged - other values are only useful for testing)", default="en")      parser.add_argument("--lang", help="target languages, or 'all_valid' or 'supported'; default is 'supported'", nargs="+", default = ["supported"]) +    parser.add_argument("--files", help='list of files to process', metavar='F', type=str, nargs='*') +    parser.add_argument("--outfile", help='name of the output file', type=str, nargs='?', default="SL_Translations.xlsx")      args = parser.parse_args()      cwd = os.getcwd() @@ -370,7 +374,7 @@ if __name__ == "__main__":      print("Target language(s) are", ",".join(sorted(langs)))      sys.stdout.flush() -    outfile = "SL_Translations.xlsx" +    outfile = args.outfile      try:          f = open(outfile,"a+")          f.close() | 
