diff --git a/indra/newview/omnifilter.cpp b/indra/newview/omnifilter.cpp
index 260111015d..e9874372bf 100644
--- a/indra/newview/omnifilter.cpp
+++ b/indra/newview/omnifilter.cpp
@@ -217,6 +217,66 @@ void Omnifilter::onRemoveNeedleClicked()
onSelectNeedle();
}
+// [FIRE-36649] - Add reordering to OmniFilter
+// Handles re-ordering the list of needle names when the UI is sorted.
+void Omnifilter::onSortChanged()
+{
+ static OmnifilterEngine* omni_filter_engine = OmnifilterEngine::getInstance();
+ if (!omni_filter_engine)
+ {
+ return;
+ }
+ // Loop over the list of thems
+ for (S32 index = 0; index < mNeedleListCtrl->getItemCount(); index++)
+ {
+ const LLScrollListItem* needle_item = mNeedleListCtrl->getAllData()[index];
+ if (needle_item)
+ {
+ const LLScrollListCell* needle_name_cell = needle_item->getColumn(NEEDLE_NAME_COLUMN);
+ if (needle_name_cell)
+ {
+ const std::string& needle_name = needle_name_cell->getValue().asString();
+ if (!needle_name.empty())
+ {
+ omni_filter_engine->setOrderedNeedleName(index, needle_name);
+ }
+ }
+ }
+ }
+ // Flag as dirty the system will save the changes to the order.
+ omni_filter_engine->setDirty(true);
+}
+
+// Moves an selected filter up on place
+void Omnifilter::onUpNeedleClicked()
+{
+ static OmnifilterEngine* omni_filter_engine = OmnifilterEngine::getInstance();
+ S32 current_index = mNeedleListCtrl->getFirstSelectedIndex();
+
+ // Don't try to move the first item up.
+ if (current_index > 0)
+ {
+ // Order is based upon 0 is the top of the screen in the list, so have to subtract 1 to get up visually.
+ omni_filter_engine->swapNeedles(current_index, current_index - 1);
+ mNeedleListCtrl->swapWithPrevious(current_index);
+ }
+}
+
+void Omnifilter::onDownNeedleClicked()
+{
+ static OmnifilterEngine* omni_filter_engine = OmnifilterEngine::getInstance();
+ S32 current_index = mNeedleListCtrl->getFirstSelectedIndex();
+
+ // If the value is within range of the filter list, prevents from going past the end of the list
+ if (omni_filter_engine->getOrderedNeedleListSize() > 1 && current_index < omni_filter_engine->getOrderedNeedleListSize() - 1)
+ {
+ // Order is based upon 0 is the top of the screen in the list, so have to add 1 to get down visually.
+ omni_filter_engine->swapNeedles(current_index, current_index + 1);
+ mNeedleListCtrl->swapWithNext(current_index);
+ }
+}
+// [FIRE-36649]
+
void Omnifilter::onNeedleNameChanged()
{
const std::string& old_name = mNeedleListCtrl->getSelectedItemLabel(NEEDLE_NAME_COLUMN);
@@ -309,6 +369,11 @@ bool Omnifilter::postBuild()
mNeedleListCtrl = getChild("needle_list");
mAddNeedleBtn = getChild("add_needle");
mRemoveNeedleBtn = getChild("remove_needle");
+ // [FIRE-36649] - Add reordering to OmniFilter
+ // Add the up and down buttons for re-aranging the order of the needles
+ mUpNeedleBtn = getChild("up_needle");
+ mDownNeedleBtn = getChild("down_needle");
+ // [FIRE-36649]
mFilterLogCtrl = getChild("filter_log");
mPanelDetails = getChild("panel_details");
mNeedleNameCtrl = getChild("needle_name");
@@ -347,8 +412,13 @@ bool Omnifilter::postBuild()
mFilterLogCtrl->deleteAllItems();
auto& instance = OmnifilterEngine::instance();
- for (const auto& [needle_name, needle] : instance.getNeedleList())
+ // [FIRE-36649] - Add reordering to OmniFilter
+ //for (const auto& [needle_name, needle] : instance.getNeedleList())
+ // Loop over the ordered list
+ for (const auto& needle_name : instance.getOrderedNeedleList())
{
+ const auto& needle = instance.getNeedleList()[needle_name];
+ // [FIRE-36649]
addNeedle(needle_name, needle);
}
@@ -370,6 +440,12 @@ bool Omnifilter::postBuild()
mNeedleListCtrl->setCommitCallback(boost::bind(&Omnifilter::onSelectNeedle, this));
mAddNeedleBtn->setCommitCallback(boost::bind(&Omnifilter::onAddNeedleClicked, this));
mRemoveNeedleBtn->setCommitCallback(boost::bind(&Omnifilter::onRemoveNeedleClicked, this));
+ // [FIRE-36649] - Add reordering to OmniFilter
+ // Add the callbacks for the up and down buttons to re-order the filter list
+ mNeedleListCtrl->setSortChangedCallback(boost::bind(&Omnifilter::onSortChanged, this));
+ mUpNeedleBtn->setCommitCallback(boost::bind(&Omnifilter::onUpNeedleClicked, this));
+ mDownNeedleBtn->setCommitCallback(boost::bind(&Omnifilter::onDownNeedleClicked, this));
+ // [FIRE-36649]
mNeedleNameCtrl->setCommitCallback(boost::bind(&Omnifilter::onNeedleNameChanged, this));
mSenderNameCtrl->setCommitCallback(boost::bind(&Omnifilter::onNeedleChanged, this));
mSenderCaseSensitiveCheck->setCommitCallback(boost::bind(&Omnifilter::onNeedleChanged, this));
diff --git a/indra/newview/omnifilter.h b/indra/newview/omnifilter.h
index e36f35f8e2..7aafa3712b 100644
--- a/indra/newview/omnifilter.h
+++ b/indra/newview/omnifilter.h
@@ -55,6 +55,11 @@ protected:
void onNeedleChanged();
void onAddNeedleClicked();
void onRemoveNeedleClicked();
+ // [FIRE-36649] - Add reordering to OmniFilter
+ void onSortChanged();
+ void onUpNeedleClicked();
+ void onDownNeedleClicked();
+ // [FIRE-36649]
void onNeedleNameChanged();
void onNeedleCheckboxChanged(LLUICtrl* ctrl);
void onOwnerChanged();
@@ -64,6 +69,10 @@ protected:
FSScrollListCtrl* mNeedleListCtrl{ nullptr };
LLButton* mAddNeedleBtn{ nullptr };
LLButton* mRemoveNeedleBtn{ nullptr };
+ // [FIRE-36649] - Add reordering to OmniFilter
+ LLButton* mUpNeedleBtn{ nullptr };
+ LLButton* mDownNeedleBtn{ nullptr };
+ // [FIRE-36649]
FSScrollListCtrl* mFilterLogCtrl{ nullptr };
LLPanel* mPanelDetails{ nullptr };
LLLineEditor* mNeedleNameCtrl{ nullptr };
diff --git a/indra/newview/omnifilterengine.cpp b/indra/newview/omnifilterengine.cpp
index ae7b882d99..3c8b4146db 100644
--- a/indra/newview/omnifilterengine.cpp
+++ b/indra/newview/omnifilterengine.cpp
@@ -134,8 +134,13 @@ bool OmnifilterEngine::matchStrings(std::string_view needle_string, std::string_
const OmnifilterEngine::Needle* OmnifilterEngine::match(const Haystack& haystack)
{
- for (const auto& [needle_name, needle]: mNeedles)
+ // [FIRE-36649] - Add reordering to OmniFilter
+ // Use ordered needle list to get the names of the needles in specified order and not the order added to the map.
+ for (const auto& needle_name : mOrderedNeedles)
+ //for (const auto& [needle_name, needle]: mNeedles)
{
+ const auto& needle = mNeedles[needle_name];
+ // [FIRE-36649]
if (!needle.mEnabled)
{
continue;
@@ -193,6 +198,10 @@ OmnifilterEngine::Needle& OmnifilterEngine::newNeedle(const std::string& needle_
mNeedles[needle_name] = new_needle;
}
setDirty(true);
+ // [FIRE-36649] - Add reordering to OmniFilter
+ // Add to the ordered needle vector the name of the new needle
+ mOrderedNeedles.push_back(needle_name);
+ // [FIRE-36649]
return mNeedles[needle_name];
}
@@ -202,12 +211,26 @@ void OmnifilterEngine::renameNeedle(const std::string& old_name, const std::stri
auto node_handler = mNeedles.extract(old_name);
node_handler.key() = new_name;
mNeedles.insert(std::move(node_handler));
+ // [FIRE-36649] - Add reordering to OmniFilter
+ // Find the index of the given old name
+ S32 found_index = getOrderedNeedleIndex(old_name);
+ // If the name was found (-1 when not found), set the ordered needle vector at the found index to the new value
+ if (found_index >= 0)
+ mOrderedNeedles[found_index] = new_name;
+ // [FIRE-36649]
setDirty(true);
}
void OmnifilterEngine::deleteNeedle(const std::string& needle_name)
{
+ // [FIRE-36649] - Add reordering to OmniFilter
+ // Find the index of the given needle name
+ S32 found_index = getOrderedNeedleIndex(needle_name);
+ // If the name was found (-1 when not found), erase the need based upon the offset
+ if (found_index >= 0)
+ mOrderedNeedles.erase(mOrderedNeedles.begin() + found_index);
+ // [FIRE-36649]
mNeedles.erase(needle_name);
setDirty(true);
}
@@ -217,6 +240,77 @@ OmnifilterEngine::needle_list_t& OmnifilterEngine::getNeedleList()
return mNeedles;
}
+// [FIRE-36649] - Add reordering to OmniFilter
+// Get the name from the vector of ordered needles at the specified index
+std::string_view OmnifilterEngine::getOrderedNeedleName(const S32 index) const
+{
+ // If the index is within the range of the vector, return the stored value
+ if (index >= 0 && index < mOrderedNeedles.size() && mOrderedNeedles.size() > 0)
+ {
+ return mOrderedNeedles[index];
+ }
+
+ // Return an empty string if not found.
+ return "";
+}
+
+// Get a needle at a specified index, returns nullptr if none is found ("")
+const OmnifilterEngine::Needle* OmnifilterEngine::getOrderedNeedle(const S32 index)
+{
+ std::string_view found_needle = getOrderedNeedleName(index);
+ if (found_needle.empty())
+ {
+ return nullptr;
+ }
+
+ return &mNeedles[std::string(found_needle)];
+}
+
+// Re-assigns a name to a specified needle location in the Ordered list
+bool OmnifilterEngine::setOrderedNeedleName(const S32 needle_index, std::string_view new_name)
+{
+ // If the index is invalid, return false
+ if (needle_index < 0 || needle_index > mOrderedNeedles.size())
+ {
+ return false;
+ }
+
+ // Otherwise assign the new name to the ordered needle at the specified index.
+ mOrderedNeedles[needle_index] = new_name;
+
+ return true;
+}
+
+S32 OmnifilterEngine::getOrderedNeedleIndex(std::string_view lookup_name)
+{
+ for (S32 index = 0; index < mOrderedNeedles.size(); index++)
+ {
+ if (mOrderedNeedles[index] == lookup_name)
+ {
+ return index;
+ }
+ }
+
+ return -1;
+}
+
+// Swaps 2 ordered needles
+bool OmnifilterEngine::swapNeedles(S32 index1, S32 index2)
+{
+ // Validation check to make sure the indexs are valid and if not to return false
+ if (index1 < 0 || index1 > mOrderedNeedles.size() || index2 < 0 || index2 > mOrderedNeedles.size() || index1 == index2)
+ {
+ return false;
+ }
+ // Perform the actual swap
+ std::swap(mOrderedNeedles[index1], mOrderedNeedles[index2]);
+ // Force a view update
+ setDirty(true);
+
+ return true;
+}
+// [FIRE-36649]
+
void OmnifilterEngine::setDirty(bool dirty)
{
mDirty = dirty;
@@ -297,6 +391,12 @@ void OmnifilterEngine::loadNeedles()
return;
}
+ // [FIRE-36649] - Add reordering to OmniFilter
+ // Clear the vector of filters
+ mOrderedNeedles.clear();
+ // Pre-allocate space for the list of needle names, so we can use an index into it for assignments down below
+ mOrderedNeedles.resize(needles_llsd.size());
+ // [FIRE-36649]
for (const auto& [new_needle_name, needle_data] : llsd::inMap(needles_llsd))
{
Needle new_needle;
@@ -327,6 +427,13 @@ void OmnifilterEngine::loadNeedles()
}
mNeedles[new_needle_name] = new_needle;
+ // [FIRE-36649] - Add reordering to OmniFilter
+ // Add the loaded needle name to the ordered needle list
+ // Needles are stored in order added to the map originally so use the
+ // order value stored to restore the order back to the user
+ // defined order.
+ mOrderedNeedles[needle_data["order"].asInteger()] = new_needle_name;
+ // [/FIRE-36649]
}
}
@@ -353,8 +460,16 @@ void OmnifilterEngine::saveNeedles()
LLSD needles_llsd;
- for (const auto& [needle_name, needle] : mNeedles)
+ // [FIRE-36649] - Add reordering to OmniFilter
+ // Use ordered needle list to get the names of the needles in specified order and not the order added to the map.
+ //for (const auto& [needle_name, needle] : mNeedles)
+ S32 order = 0;
+ for (const auto& needle_name : mOrderedNeedles)
{
+ const auto& needle = mNeedles[needle_name];
+ // Store the order of the needle
+ needles_llsd[needle_name]["order"] = order++;
+ // [FIRE-36649]
needles_llsd[needle_name]["sender_name"] = needle.mSenderName;
needles_llsd[needle_name]["content"] = needle.mContent;
needles_llsd[needle_name]["region_name"] = needle.mRegionName;
diff --git a/indra/newview/omnifilterengine.h b/indra/newview/omnifilterengine.h
index 1830058989..5fb2020884 100644
--- a/indra/newview/omnifilterengine.h
+++ b/indra/newview/omnifilterengine.h
@@ -103,6 +103,18 @@ class OmnifilterEngine
typedef std::map> needle_list_t;
needle_list_t& getNeedleList();
+ // [FIRE-36649] - Add reordering to OmniFilter
+ // Typedef for the ordered list which is a vector of strings, used to keep track of the map order, which uses strings to lookup the
+ // needles.
+ typedef std::vector needle_ordered_list_t;
+ needle_ordered_list_t& getOrderedNeedleList() { return mOrderedNeedles; };
+ S32 getOrderedNeedleListSize() const { return static_cast(mOrderedNeedles.size()); };
+ std::string_view getOrderedNeedleName(const S32 index) const;
+ S32 getOrderedNeedleIndex(std::string_view);
+ bool setOrderedNeedleName(const S32 needle_index, std::string_view new_name);
+ const Needle* getOrderedNeedle(const S32 index);
+ bool swapNeedles(const S32 index1, const S32 index2);
+ // [FIRE-36649]
Needle& newNeedle(const std::string& needle_name);
void renameNeedle(const std::string& old_name, const std::string& new_name);
@@ -129,6 +141,9 @@ class OmnifilterEngine
protected:
needle_list_t mNeedles;
+ // [FIRE-36649] - Add reordering to OmniFilter
+ needle_ordered_list_t mOrderedNeedles;
+ // [FIRE-36649]
std::string mNeedlesXMLPath;
diff --git a/indra/newview/skins/default/xui/en/floater_omnifilter.xml b/indra/newview/skins/default/xui/en/floater_omnifilter.xml
index 768af06c65..d096a175b1 100644
--- a/indra/newview/skins/default/xui/en/floater_omnifilter.xml
+++ b/indra/newview/skins/default/xui/en/floater_omnifilter.xml
@@ -33,7 +33,7 @@
+
+
+
+