diff options
Diffstat (limited to 'indra/newview/llsettingspicker.cpp')
-rw-r--r-- | indra/newview/llsettingspicker.cpp | 509 |
1 files changed, 509 insertions, 0 deletions
diff --git a/indra/newview/llsettingspicker.cpp b/indra/newview/llsettingspicker.cpp new file mode 100644 index 0000000000..b47821ddf2 --- /dev/null +++ b/indra/newview/llsettingspicker.cpp @@ -0,0 +1,509 @@ +/** +* @author Rider Linden +* @brief LLSettingsPicker class header file including related functions +* +* $LicenseInfo:firstyear=2018&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, 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 "llsettingspicker.h" + +#include "llcombobox.h" +#include "llfiltereditor.h" +#include "llfolderviewmodel.h" +#include "llinventory.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llinventoryobserver.h" +#include "llinventorypanel.h" +#include "llsettingsvo.h" + +#include "lldraghandle.h" +#include "llviewercontrol.h" +#include "llagent.h" + +//========================================================================= +namespace +{ + const std::string FLOATER_DEFINITION_XML("floater_settings_picker.xml"); + + const std::string FLT_INVENTORY_SEARCH("flt_inventory_search"); + const std::string CMB_TRACK_SELECTION("track_selection"); + const std::string PNL_INVENTORY("pnl_inventory"); + const std::string PNL_COMBO("pnl_combo"); + const std::string BTN_SELECT("btn_select"); + const std::string BTN_CANCEL("btn_cancel"); + + // strings in xml + + const std::string STR_TITLE_PREFIX = "pick title"; + const std::string STR_TITLE_TRACK = "pick_track"; + const std::string STR_TITLE_SETTINGS = "pick_settings"; + const std::string STR_TRACK_WATER = "track_water"; + const std::string STR_TRACK_GROUND = "track_ground"; + const std::string STR_TRACK_SKY = "track_sky"; +} +//========================================================================= + +LLFloaterSettingsPicker::LLFloaterSettingsPicker(LLView * owner, LLUUID initial_item_id, const LLSD ¶ms): + LLFloater(params), + mOwnerHandle(), + mActive(true), + mContextConeOpacity(0.0f), + mSettingItemID(initial_item_id), + mTrackMode(TRACK_NONE), + mImmediateFilterPermMask(PERM_NONE) +{ + mOwnerHandle = owner->getHandle(); + + buildFromFile(FLOATER_DEFINITION_XML); + setCanMinimize(FALSE); +} + + +LLFloaterSettingsPicker::~LLFloaterSettingsPicker() +{ + +} + +//------------------------------------------------------------------------- +BOOL LLFloaterSettingsPicker::postBuild() +{ + if (!LLFloater::postBuild()) + return FALSE; + + std::string prefix = getString(STR_TITLE_PREFIX); + std::string label = getString(STR_TITLE_SETTINGS); + setTitle(prefix + " " + label); + + mFilterEdit = getChild<LLFilterEditor>(FLT_INVENTORY_SEARCH); + mFilterEdit->setCommitCallback([this](LLUICtrl*, const LLSD& param){ onFilterEdit(param.asString()); }); + + mInventoryPanel = getChild<LLInventoryPanel>(PNL_INVENTORY); + if (mInventoryPanel) + { + U32 filter_types = 0x0; + filter_types |= 0x1 << LLInventoryType::IT_SETTINGS; + + mInventoryPanel->setFilterTypes(filter_types); + mInventoryPanel->setFilterPermMask(mImmediateFilterPermMask); + + mInventoryPanel->setSelectCallback([this](const LLFloaterSettingsPicker::itemlist_t &items, bool useraction){ onSelectionChange(items, useraction); }); + mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + mInventoryPanel->setSuppressOpenItemAction(true); + + // Disable auto selecting first filtered item because it takes away + // selection from the item set by LLTextureCtrl owning this floater. + mInventoryPanel->getRootFolder()->setAutoSelectOverride(TRUE); + + // don't put keyboard focus on selected item, because the selection callback + // will assume that this was user input + if (!mSettingItemID.isNull()) + { + //todo: this is bad idea + mInventoryPanel->setSelection(mSettingItemID, TAKE_FOCUS_NO); + } + getChild<LLView>(BTN_SELECT)->setEnabled(mSettingItemID.notNull()); + } + + mNoCopySettingsSelected = FALSE; + + childSetAction(BTN_CANCEL, [this](LLUICtrl*, const LLSD& param){ onButtonCancel(); }); + childSetAction(BTN_SELECT, [this](LLUICtrl*, const LLSD& param){ onButtonSelect(); }); + + getChild<LLPanel>(PNL_COMBO)->setVisible(mTrackMode != TRACK_NONE); + + // update permission filter once UI is fully initialized + mSavedFolderState.setApply(FALSE); + + return TRUE; +} + +void LLFloaterSettingsPicker::onClose(bool app_quitting) +{ + if (app_quitting) + return; + + mCloseSignal(); + LLView *owner = mOwnerHandle.get(); + if (owner) + { + owner->setFocus(TRUE); + } + mSettingItemID.setNull(); + mInventoryPanel->getRootFolder()->clearSelection(); +} + +void LLFloaterSettingsPicker::setValue(const LLSD& value) +{ + mSettingItemID = value.asUUID(); +} + +LLSD LLFloaterSettingsPicker::getValue() const +{ + return LLSD(mSettingItemID); +} + +void LLFloaterSettingsPicker::setSettingsFilter(LLSettingsType::type_e type) +{ + U64 filter = 0xFFFFFFFFFFFFFFFF; + if (type != LLSettingsType::ST_NONE) + { + filter = static_cast<S64>(0x1) << static_cast<S64>(type); + } + + mInventoryPanel->setFilterSettingsTypes(filter); +} + +void LLFloaterSettingsPicker::setTrackMode(ETrackMode mode) +{ + mTrackMode = mode; + getChild<LLPanel>(PNL_COMBO)->setVisible(mode != TRACK_NONE); + + std::string prefix = getString(STR_TITLE_PREFIX); + std::string label; + if (mode != TRACK_NONE) + { + label = getString(STR_TITLE_TRACK); + } + else + { + label = getString(STR_TITLE_SETTINGS); + } + setTitle(prefix + " " + label); +} + +void LLFloaterSettingsPicker::draw() +{ + LLView *owner = mOwnerHandle.get(); + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, owner); + + LLFloater::draw(); +} + + +//========================================================================= +void LLFloaterSettingsPicker::onFilterEdit(const std::string& search_string) +{ + std::string upper_case_search_string = search_string; + LLStringUtil::toUpper(upper_case_search_string); + + if (upper_case_search_string.empty()) + { + if (mInventoryPanel->getFilterSubString().empty()) + { + // current filter and new filter empty, do nothing + return; + } + + mSavedFolderState.setApply(TRUE); + mInventoryPanel->getRootFolder()->applyFunctorRecursively(mSavedFolderState); + // add folder with current item to list of previously opened folders + LLOpenFoldersWithSelection opener; + mInventoryPanel->getRootFolder()->applyFunctorRecursively(opener); + mInventoryPanel->getRootFolder()->scrollToShowSelection(); + + } + else if (mInventoryPanel->getFilterSubString().empty()) + { + // first letter in search term, save existing folder open state + if (!mInventoryPanel->getFilter().isNotDefault()) + { + mSavedFolderState.setApply(FALSE); + mInventoryPanel->getRootFolder()->applyFunctorRecursively(mSavedFolderState); + } + } + + mInventoryPanel->setFilterSubString(search_string); +} + +void LLFloaterSettingsPicker::onSelectionChange(const LLFloaterSettingsPicker::itemlist_t &items, bool user_action) +{ + bool is_item = false; + LLUUID asset_id; + if (items.size()) + { + LLFolderViewItem* first_item = items.front(); + + mNoCopySettingsSelected = false; + if (first_item) + { + LLItemBridge *bridge_model = dynamic_cast<LLItemBridge *>(first_item->getViewModelItem()); + if (bridge_model && bridge_model->getItem()) + { + if (!bridge_model->isItemCopyable()) + { + mNoCopySettingsSelected = true; + } + setSettingsItemId(bridge_model->getItem()->getUUID(), false); + asset_id = bridge_model->getItem()->getAssetUUID(); + mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here? + is_item = true; + + if (user_action) + { + mChangeIDSignal(mSettingItemID); + } + } + } + } + bool track_picker_enabled = mTrackMode != TRACK_NONE; + + getChild<LLView>(CMB_TRACK_SELECTION)->setEnabled(track_picker_enabled && mSettingAssetID == asset_id); + getChild<LLView>(BTN_SELECT)->setEnabled(is_item && (!track_picker_enabled || mSettingAssetID == asset_id)); + if (track_picker_enabled && asset_id.notNull() && mSettingAssetID != asset_id) + { + LLUUID item_id = mSettingItemID; + LLHandle<LLFloater> handle = getHandle(); + LLSettingsVOBase::getSettingsAsset(asset_id, + [item_id, handle](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) { LLFloaterSettingsPicker::onAssetLoadedCb(handle, item_id, asset_id, settings, status); }); + } +} + +void LLFloaterSettingsPicker::onAssetLoadedCb(LLHandle<LLFloater> handle, LLUUID item_id, LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status) +{ + if (handle.isDead() || status) + { + return; + } + + LLFloaterSettingsPicker *picker = static_cast<LLFloaterSettingsPicker *>(handle.get()); + + if (picker->mSettingItemID != item_id) + { + return; + } + + picker->onAssetLoaded(asset_id, settings); +} + +void LLFloaterSettingsPicker::onAssetLoaded(LLUUID asset_id, LLSettingsBase::ptr_t settings) +{ + LLComboBox* track_selection = getChild<LLComboBox>(CMB_TRACK_SELECTION); + track_selection->clear(); + track_selection->removeall(); + if (!settings) + { + LL_WARNS() << "Failed to load asset " << asset_id << LL_ENDL; + return; + } + LLSettingsDay::ptr_t pday = std::dynamic_pointer_cast<LLSettingsDay>(settings); + + if (!pday) + { + LL_WARNS() << "Wrong asset type received by id " << asset_id << LL_ENDL; + return; + } + + if (mTrackMode == TRACK_WATER) + { + track_selection->add(getString(STR_TRACK_WATER), LLSD::Integer(LLSettingsDay::TRACK_WATER), ADD_TOP, true); + } + else if (mTrackMode == TRACK_SKY) + { + // track 1 always present + track_selection->add(getString(STR_TRACK_GROUND), LLSD::Integer(LLSettingsDay::TRACK_GROUND_LEVEL), ADD_TOP, true); + LLUIString formatted_label = getString(STR_TRACK_SKY); + for (int i = 2; i < LLSettingsDay::TRACK_MAX; i++) + { + if (!pday->isTrackEmpty(i)) + { + formatted_label.setArg("[NUM]", llformat("%d", i)); + track_selection->add(formatted_label.getString(), LLSD::Integer(i), ADD_TOP, true); + } + } + } + + mSettingAssetID = asset_id; + track_selection->setEnabled(true); + track_selection->selectFirstItem(); + getChild<LLView>(BTN_SELECT)->setEnabled(true); +} + +void LLFloaterSettingsPicker::onButtonCancel() +{ + closeFloater(); +} + +void LLFloaterSettingsPicker::onButtonSelect() +{ + if (mCommitSignal) + { + LLSD res; + res["ItemId"] = mSettingItemID; + res["Track"] = getChild<LLComboBox>(CMB_TRACK_SELECTION)->getValue(); + (*mCommitSignal)(this, res); + } + closeFloater(); +} + +BOOL LLFloaterSettingsPicker::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + BOOL result = FALSE; + if (mSettingItemID.notNull() + && mInventoryPanel) + { + S32 inventory_x = x - mInventoryPanel->getRect().mLeft; + S32 inventory_y = y - mInventoryPanel->getRect().mBottom; + if (mInventoryPanel->parentPointInView(inventory_x, inventory_y)) + { + // make sure item is selected and visible + LLFolderViewItem* item_viewp = mInventoryPanel->getItemByID(mSettingItemID); + if (item_viewp && item_viewp->getIsCurSelection() && item_viewp->getVisible()) + { + LLRect target_rect; + item_viewp->localRectToOtherView(item_viewp->getLocalRect(), &target_rect, this); + if (target_rect.pointInRect(x, y)) + { + // Quick-apply + if (mCommitSignal) + { + LLSD res; + res["ItemId"] = mSettingItemID; + res["Track"] = getChild<LLComboBox>(CMB_TRACK_SELECTION)->getValue(); + (*mCommitSignal)(this, res); + } + closeFloater(); + // hit inside panel on selected item, double click should do nothing + result = TRUE; + } + } + } + } + + if (!result) + { + result = LLFloater::handleDoubleClick(x, y, mask); + } + return result; +} + +BOOL LLFloaterSettingsPicker::handleKeyHere(KEY key, MASK mask) +{ + if ((key == KEY_RETURN) && (mask == MASK_NONE)) + { + LLFolderViewItem* item_viewp = mInventoryPanel->getItemByID(mSettingItemID); + if (item_viewp && item_viewp->getIsCurSelection() && item_viewp->getVisible()) + { + // Quick-apply + if (mCommitSignal) + { + LLSD res; + res["ItemId"] = mSettingItemID; + res["Track"] = getChild<LLComboBox>(CMB_TRACK_SELECTION)->getValue(); + (*mCommitSignal)(this, res); + } + closeFloater(); + return TRUE; + } + } + + return LLFloater::handleKeyHere(key, mask); +} + +void LLFloaterSettingsPicker::onFocusLost() +{ + if (isInVisibleChain()) + { + closeFloater(); + } +} + +//========================================================================= +void LLFloaterSettingsPicker::setActive(bool active) +{ + mActive = active; +} + +void LLFloaterSettingsPicker::setSettingsItemId(const LLUUID &settings_id, bool set_selection) +{ + if (mSettingItemID != settings_id && mActive) + { + mNoCopySettingsSelected = false; + mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here? + mSettingItemID = settings_id; + if (mSettingItemID.isNull()) + { + mInventoryPanel->getRootFolder()->clearSelection(); + } + else + { + LLInventoryItem* itemp = gInventory.getItem(settings_id); + if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID())) + { + mNoCopySettingsSelected = true; + } + } + + if (set_selection) + { + mInventoryPanel->setSelection(settings_id, TAKE_FOCUS_NO); + } + } +} + +LLInventoryItem* LLFloaterSettingsPicker::findItem(const LLUUID& asset_id, bool copyable_only, bool ignore_library) +{ + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(asset_id); + + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + if (items.size()) + { + // search for copyable version first + for (S32 i = 0; i < items.size(); i++) + { + LLInventoryItem* itemp = items[i]; + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowCopyBy(gAgent.getID(), gAgent.getGroupID())) + { + if(!ignore_library || !gInventory.isObjectDescendentOf(itemp->getUUID(),gInventory.getLibraryRootFolderID())) + { + return itemp; + } + } + } + // otherwise just return first instance, unless copyable requested + if (copyable_only) + { + return nullptr; + } + else + { + if(!ignore_library || !gInventory.isObjectDescendentOf(items[0]->getUUID(),gInventory.getLibraryRootFolderID())) + { + return items[0]; + } + } + } + + return nullptr; +} |