diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/newview/llpanelclassified.cpp | |
parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) |
Fix line endlings
Diffstat (limited to 'indra/newview/llpanelclassified.cpp')
-rw-r--r-- | indra/newview/llpanelclassified.cpp | 1138 |
1 files changed, 569 insertions, 569 deletions
diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index fdbd4258c8..9fe8f39bd6 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -1,569 +1,569 @@ -/**
- * @file llpanelclassified.cpp
- * @brief LLPanelClassifiedInfo class implementation
- *
- * $LicenseInfo:firstyear=2021&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2021, 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$
- */
-
-// Display of a classified used both for the global view in the
-// Find directory, and also for each individual user's classified in their
-// profile.
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llpanelclassified.h"
-
-#include "lldispatcher.h"
-#include "llfloaterreg.h"
-#include "llparcel.h"
-
-#include "llagent.h"
-#include "llclassifiedflags.h"
-#include "lliconctrl.h"
-#include "lltexturectrl.h"
-#include "llfloaterworldmap.h"
-#include "llviewergenericmessage.h" // send_generic_message
-#include "llviewerregion.h"
-#include "llscrollcontainer.h"
-#include "llcorehttputil.h"
-
-//static
-LLPanelClassifiedInfo::panel_list_t LLPanelClassifiedInfo::sAllPanels;
-static LLPanelInjector<LLPanelClassifiedInfo> t_panel_panel_classified_info("panel_classified_info");
-
-// "classifiedclickthrough"
-// strings[0] = classified_id
-// strings[1] = teleport_clicks
-// strings[2] = map_clicks
-// strings[3] = profile_clicks
-class LLDispatchClassifiedClickThrough : public LLDispatchHandler
-{
-public:
- virtual bool operator()(
- const LLDispatcher* dispatcher,
- const std::string& key,
- const LLUUID& invoice,
- const sparam_t& strings)
- {
- if (strings.size() != 4) return false;
- LLUUID classified_id(strings[0]);
- S32 teleport_clicks = atoi(strings[1].c_str());
- S32 map_clicks = atoi(strings[2].c_str());
- S32 profile_clicks = atoi(strings[3].c_str());
-
- LLPanelClassifiedInfo::setClickThrough(
- classified_id, teleport_clicks, map_clicks, profile_clicks, false);
-
- return true;
- }
-};
-static LLDispatchClassifiedClickThrough sClassifiedClickThrough;
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-LLPanelClassifiedInfo::LLPanelClassifiedInfo()
- : LLPanel()
- , mInfoLoaded(false)
- , mScrollingPanel(NULL)
- , mScrollContainer(NULL)
- , mScrollingPanelMinHeight(0)
- , mScrollingPanelWidth(0)
- , mSnapshotStreched(false)
- , mTeleportClicksOld(0)
- , mMapClicksOld(0)
- , mProfileClicksOld(0)
- , mTeleportClicksNew(0)
- , mMapClicksNew(0)
- , mProfileClicksNew(0)
- , mSnapshotCtrl(NULL)
-{
- sAllPanels.push_back(this);
-}
-
-LLPanelClassifiedInfo::~LLPanelClassifiedInfo()
-{
- sAllPanels.remove(this);
-
- if (getAvatarId().notNull())
- {
- LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
- }
-}
-
-bool LLPanelClassifiedInfo::postBuild()
-{
- childSetAction("show_on_map_btn", boost::bind(&LLPanelClassifiedInfo::onMapClick, this));
- childSetAction("teleport_btn", boost::bind(&LLPanelClassifiedInfo::onTeleportClick, this));
-
- mScrollingPanel = getChild<LLPanel>("scroll_content_panel");
- mScrollContainer = getChild<LLScrollContainer>("profile_scroll");
-
- mScrollingPanelMinHeight = mScrollContainer->getScrolledViewRect().getHeight();
- mScrollingPanelWidth = mScrollingPanel->getRect().getWidth();
-
- mSnapshotCtrl = getChild<LLTextureCtrl>("classified_snapshot");
- mSnapshotRect = getDefaultSnapshotRect();
-
- return true;
-}
-
-void LLPanelClassifiedInfo::reshape(S32 width, S32 height, bool called_from_parent /* = true */)
-{
- LLPanel::reshape(width, height, called_from_parent);
-
- if (!mScrollContainer || !mScrollingPanel)
- return;
-
- static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
-
- S32 scroll_height = mScrollContainer->getRect().getHeight();
- if (mScrollingPanelMinHeight >= scroll_height)
- {
- mScrollingPanel->reshape(mScrollingPanelWidth, mScrollingPanelMinHeight);
- }
- else
- {
- mScrollingPanel->reshape(mScrollingPanelWidth + scrollbar_size, scroll_height);
- }
-
- mSnapshotRect = getDefaultSnapshotRect();
- stretchSnapshot();
-}
-
-void LLPanelClassifiedInfo::onOpen(const LLSD& key)
-{
- LLUUID avatar_id = key["classified_creator_id"];
- if(avatar_id.isNull())
- {
- return;
- }
-
- if(getAvatarId().notNull())
- {
- LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
- }
-
- setAvatarId(avatar_id);
-
- resetData();
- resetControls();
- scrollToTop();
-
- setClassifiedId(key["classified_id"]);
- setClassifiedName(key["classified_name"]);
- setDescription(key["classified_desc"]);
- setSnapshotId(key["classified_snapshot_id"]);
- setFromSearch(key["from_search"]);
-
- LL_INFOS() << "Opening classified [" << getClassifiedName() << "] (" << getClassifiedId() << ")" << LL_ENDL;
-
- LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this);
- LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId());
- gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough);
-
- if (gAgent.getRegion())
- {
- // While we're at it let's get the stats from the new table if that
- // capability exists.
- std::string url = gAgent.getRegion()->getCapability("SearchStatRequest");
- if (!url.empty())
- {
- LL_INFOS() << "Classified stat request via capability" << LL_ENDL;
- LLSD body;
- LLUUID classifiedId = getClassifiedId();
- body["classified_id"] = classifiedId;
- LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body,
- boost::bind(&LLPanelClassifiedInfo::handleSearchStatResponse, classifiedId, _1));
- }
- }
- // Update classified click stats.
- // *TODO: Should we do this when opening not from search?
- sendClickMessage("profile");
-
- setInfoLoaded(false);
-}
-
-/*static*/
-void LLPanelClassifiedInfo::handleSearchStatResponse(LLUUID classifiedId, LLSD result)
-{
- S32 teleport = result["teleport_clicks"].asInteger();
- S32 map = result["map_clicks"].asInteger();
- S32 profile = result["profile_clicks"].asInteger();
- S32 search_teleport = result["search_teleport_clicks"].asInteger();
- S32 search_map = result["search_map_clicks"].asInteger();
- S32 search_profile = result["search_profile_clicks"].asInteger();
-
- LLPanelClassifiedInfo::setClickThrough(classifiedId,
- teleport + search_teleport,
- map + search_map,
- profile + search_profile,
- true);
-}
-
-void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType type)
-{
- if(APT_CLASSIFIED_INFO == type)
- {
- LLAvatarClassifiedInfo* c_info = static_cast<LLAvatarClassifiedInfo*>(data);
- if(c_info && getClassifiedId() == c_info->classified_id)
- {
- setClassifiedName(c_info->name);
- setDescription(c_info->description);
- setSnapshotId(c_info->snapshot_id);
- setParcelId(c_info->parcel_id);
- setPosGlobal(c_info->pos_global);
- setSimName(c_info->sim_name);
-
- setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global));
- getChild<LLUICtrl>("category")->setValue(LLClassifiedInfo::sCategories[c_info->category]);
-
- static std::string mature_str = getString("type_mature");
- static std::string pg_str = getString("type_pg");
- static LLUIString price_str = getString("l$_price");
- static std::string date_fmt = getString("date_fmt");
-
- bool mature = is_cf_mature(c_info->flags);
- getChild<LLUICtrl>("content_type")->setValue(mature ? mature_str : pg_str);
- getChild<LLIconCtrl>("content_type_moderate")->setVisible(mature);
- getChild<LLIconCtrl>("content_type_general")->setVisible(!mature);
-
- std::string auto_renew_str = is_cf_auto_renew(c_info->flags) ?
- getString("auto_renew_on") : getString("auto_renew_off");
- getChild<LLUICtrl>("auto_renew")->setValue(auto_renew_str);
-
- price_str.setArg("[PRICE]", llformat("%d", c_info->price_for_listing));
- getChild<LLUICtrl>("price_for_listing")->setValue(LLSD(price_str));
-
- std::string date_str = date_fmt;
- LLStringUtil::format(date_str, LLSD().with("datetime", (S32) c_info->creation_date));
- getChild<LLUICtrl>("creation_date")->setValue(date_str);
-
- setInfoLoaded(true);
-
- LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
- }
- }
-}
-
-void LLPanelClassifiedInfo::resetData()
-{
- setClassifiedName(LLStringUtil::null);
- setDescription(LLStringUtil::null);
- setClassifiedLocation(LLStringUtil::null);
- setClassifiedId(LLUUID::null);
- setSnapshotId(LLUUID::null);
- setPosGlobal(LLVector3d::zero);
- setParcelId(LLUUID::null);
- setSimName(LLStringUtil::null);
- setFromSearch(false);
-
- // reset click stats
- mTeleportClicksOld = 0;
- mMapClicksOld = 0;
- mProfileClicksOld = 0;
- mTeleportClicksNew = 0;
- mMapClicksNew = 0;
- mProfileClicksNew = 0;
-
- getChild<LLUICtrl>("category")->setValue(LLStringUtil::null);
- getChild<LLUICtrl>("content_type")->setValue(LLStringUtil::null);
- getChild<LLUICtrl>("click_through_text")->setValue(LLStringUtil::null);
- getChild<LLUICtrl>("price_for_listing")->setValue(LLStringUtil::null);
- getChild<LLUICtrl>("auto_renew")->setValue(LLStringUtil::null);
- getChild<LLUICtrl>("creation_date")->setValue(LLStringUtil::null);
- getChild<LLUICtrl>("click_through_text")->setValue(LLStringUtil::null);
- getChild<LLIconCtrl>("content_type_moderate")->setVisible(false);
- getChild<LLIconCtrl>("content_type_general")->setVisible(false);
-}
-
-void LLPanelClassifiedInfo::resetControls()
-{
- bool is_self = getAvatarId() == gAgent.getID();
-
- getChildView("edit_btn")->setEnabled(is_self);
- getChildView("edit_btn")->setVisible( is_self);
- getChildView("price_layout_panel")->setVisible( is_self);
- getChildView("clickthrough_layout_panel")->setVisible( is_self);
-}
-
-void LLPanelClassifiedInfo::setClassifiedName(const std::string& name)
-{
- getChild<LLUICtrl>("classified_name")->setValue(name);
-}
-
-std::string LLPanelClassifiedInfo::getClassifiedName()
-{
- return getChild<LLUICtrl>("classified_name")->getValue().asString();
-}
-
-void LLPanelClassifiedInfo::setDescription(const std::string& desc)
-{
- getChild<LLUICtrl>("classified_desc")->setValue(desc);
-}
-
-std::string LLPanelClassifiedInfo::getDescription()
-{
- return getChild<LLUICtrl>("classified_desc")->getValue().asString();
-}
-
-void LLPanelClassifiedInfo::setClassifiedLocation(const std::string& location)
-{
- getChild<LLUICtrl>("classified_location")->setValue(location);
-}
-
-std::string LLPanelClassifiedInfo::getClassifiedLocation()
-{
- return getChild<LLUICtrl>("classified_location")->getValue().asString();
-}
-
-void LLPanelClassifiedInfo::setSnapshotId(const LLUUID& id)
-{
- mSnapshotCtrl->setValue(id);
- mSnapshotStreched = false;
-}
-
-void LLPanelClassifiedInfo::draw()
-{
- LLPanel::draw();
-
- // Stretch in draw because it takes some time to load a texture,
- // going to try to stretch snapshot until texture is loaded
- if(!mSnapshotStreched)
- {
- stretchSnapshot();
- }
-}
-
-LLUUID LLPanelClassifiedInfo::getSnapshotId()
-{
- return getChild<LLUICtrl>("classified_snapshot")->getValue().asUUID();
-}
-
-// static
-void LLPanelClassifiedInfo::setClickThrough(
- const LLUUID& classified_id,
- S32 teleport,
- S32 map,
- S32 profile,
- bool from_new_table)
-{
- LL_INFOS() << "Click-through data for classified " << classified_id << " arrived: ["
- << teleport << ", " << map << ", " << profile << "] ("
- << (from_new_table ? "new" : "old") << ")" << LL_ENDL;
-
- for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter)
- {
- LLPanelClassifiedInfo* self = *iter;
- if (self->getClassifiedId() != classified_id)
- {
- continue;
- }
-
- // *HACK: Skip LLPanelClassifiedEdit instances: they don't display clicks data.
- // Those instances should not be in the list at all.
- if (typeid(*self) != typeid(LLPanelClassifiedInfo))
- {
- continue;
- }
-
- LL_INFOS() << "Updating classified info panel" << LL_ENDL;
-
- // We need to check to see if the data came from the new stat_table
- // or the old classified table. We also need to cache the data from
- // the two separate sources so as to display the aggregate totals.
-
- if (from_new_table)
- {
- self->mTeleportClicksNew = teleport;
- self->mMapClicksNew = map;
- self->mProfileClicksNew = profile;
- }
- else
- {
- self->mTeleportClicksOld = teleport;
- self->mMapClicksOld = map;
- self->mProfileClicksOld = profile;
- }
-
- static LLUIString ct_str = self->getString("click_through_text_fmt");
-
- ct_str.setArg("[TELEPORT]", llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld));
- ct_str.setArg("[MAP]", llformat("%d", self->mMapClicksNew + self->mMapClicksOld));
- ct_str.setArg("[PROFILE]", llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld));
-
- self->getChild<LLUICtrl>("click_through_text")->setValue(ct_str.getString());
- // *HACK: remove this when there is enough room for click stats in the info panel
- self->getChildView("click_through_text")->setToolTip(ct_str.getString());
-
- LL_INFOS() << "teleport: " << llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld)
- << ", map: " << llformat("%d", self->mMapClicksNew + self->mMapClicksOld)
- << ", profile: " << llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld)
- << LL_ENDL;
- }
-}
-
-// static
-std::string LLPanelClassifiedInfo::createLocationText(
- const std::string& original_name,
- const std::string& sim_name,
- const LLVector3d& pos_global)
-{
- std::string location_text;
-
- location_text.append(original_name);
-
- if (!sim_name.empty())
- {
- if (!location_text.empty())
- location_text.append(", ");
- location_text.append(sim_name);
- }
-
- if (!location_text.empty())
- location_text.append(" ");
-
- if (!pos_global.isNull())
- {
- S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS;
- S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS;
- S32 region_z = ll_round((F32)pos_global.mdV[VZ]);
- location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z));
- }
-
- return location_text;
-}
-
-void LLPanelClassifiedInfo::stretchSnapshot()
-{
- // *NOTE dzaporozhan
- // Could be moved to LLTextureCtrl
-
- LLViewerFetchedTexture* texture = mSnapshotCtrl->getTexture();
-
- if(!texture)
- {
- return;
- }
-
- if(0 == texture->getOriginalWidth() || 0 == texture->getOriginalHeight())
- {
- // looks like texture is not loaded yet
- return;
- }
-
- LLRect rc = mSnapshotRect;
- // *HACK dzaporozhan
- // LLTextureCtrl uses BTN_HEIGHT_SMALL as bottom for texture which causes
- // drawn texture to be smaller than expected. (see LLTextureCtrl::draw())
- // Lets increase texture height to force texture look as expected.
- rc.mBottom -= BTN_HEIGHT_SMALL;
-
- F32 t_width = texture->getFullWidth();
- F32 t_height = texture->getFullHeight();
-
- F32 ratio = llmin<F32>( (rc.getWidth() / t_width), (rc.getHeight() / t_height) );
-
- t_width *= ratio;
- t_height *= ratio;
-
- rc.setCenterAndSize(rc.getCenterX(), rc.getCenterY(), llfloor(t_width), llfloor(t_height));
- mSnapshotCtrl->setShape(rc);
-
- mSnapshotStreched = true;
-}
-
-LLRect LLPanelClassifiedInfo::getDefaultSnapshotRect()
-{
- // Using scroll container makes getting default rect a hard task
- // because rect in postBuild() and in first reshape() is not the same.
- // Using snapshot_panel makes it easier to reshape snapshot.
- return getChild<LLUICtrl>("snapshot_panel")->getLocalRect();
-}
-
-void LLPanelClassifiedInfo::scrollToTop()
-{
- LLScrollContainer* scrollContainer = findChild<LLScrollContainer>("profile_scroll");
- if (scrollContainer)
- scrollContainer->goToTop();
-}
-
-// static
-// *TODO: move out of the panel
-void LLPanelClassifiedInfo::sendClickMessage(
- const std::string& type,
- bool from_search,
- const LLUUID& classified_id,
- const LLUUID& parcel_id,
- const LLVector3d& global_pos,
- const std::string& sim_name)
-{
- if (gAgent.getRegion())
- {
- // You're allowed to click on your own ads to reassure yourself
- // that the system is working.
- LLSD body;
- body["type"] = type;
- body["from_search"] = from_search;
- body["classified_id"] = classified_id;
- body["parcel_id"] = parcel_id;
- body["dest_pos_global"] = global_pos.getValue();
- body["region_name"] = sim_name;
-
- std::string url = gAgent.getRegion()->getCapability("SearchStatTracking");
- LL_INFOS() << "Sending click msg via capability (url=" << url << ")" << LL_ENDL;
- LL_INFOS() << "body: [" << body << "]" << LL_ENDL;
- LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
- "SearchStatTracking Click report sent.", "SearchStatTracking Click report NOT sent.");
- }
-}
-
-void LLPanelClassifiedInfo::sendClickMessage(const std::string& type)
-{
- sendClickMessage(
- type,
- fromSearch(),
- getClassifiedId(),
- getParcelId(),
- getPosGlobal(),
- getSimName());
-}
-
-void LLPanelClassifiedInfo::onMapClick()
-{
- sendClickMessage("map");
- LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal());
- LLFloaterReg::showInstance("world_map", "center");
-}
-
-void LLPanelClassifiedInfo::onTeleportClick()
-{
- if (!getPosGlobal().isExactlyZero())
- {
- sendClickMessage("teleport");
- gAgent.teleportViaLocation(getPosGlobal());
- LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal());
- }
-}
-
-//EOF
+/** + * @file llpanelclassified.cpp + * @brief LLPanelClassifiedInfo class implementation + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, 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$ + */ + +// Display of a classified used both for the global view in the +// Find directory, and also for each individual user's classified in their +// profile. + +#include "llviewerprecompiledheaders.h" + +#include "llpanelclassified.h" + +#include "lldispatcher.h" +#include "llfloaterreg.h" +#include "llparcel.h" + +#include "llagent.h" +#include "llclassifiedflags.h" +#include "lliconctrl.h" +#include "lltexturectrl.h" +#include "llfloaterworldmap.h" +#include "llviewergenericmessage.h" // send_generic_message +#include "llviewerregion.h" +#include "llscrollcontainer.h" +#include "llcorehttputil.h" + +//static +LLPanelClassifiedInfo::panel_list_t LLPanelClassifiedInfo::sAllPanels; +static LLPanelInjector<LLPanelClassifiedInfo> t_panel_panel_classified_info("panel_classified_info"); + +// "classifiedclickthrough" +// strings[0] = classified_id +// strings[1] = teleport_clicks +// strings[2] = map_clicks +// strings[3] = profile_clicks +class LLDispatchClassifiedClickThrough : public LLDispatchHandler +{ +public: + virtual bool operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) + { + if (strings.size() != 4) return false; + LLUUID classified_id(strings[0]); + S32 teleport_clicks = atoi(strings[1].c_str()); + S32 map_clicks = atoi(strings[2].c_str()); + S32 profile_clicks = atoi(strings[3].c_str()); + + LLPanelClassifiedInfo::setClickThrough( + classified_id, teleport_clicks, map_clicks, profile_clicks, false); + + return true; + } +}; +static LLDispatchClassifiedClickThrough sClassifiedClickThrough; + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPanelClassifiedInfo::LLPanelClassifiedInfo() + : LLPanel() + , mInfoLoaded(false) + , mScrollingPanel(NULL) + , mScrollContainer(NULL) + , mScrollingPanelMinHeight(0) + , mScrollingPanelWidth(0) + , mSnapshotStreched(false) + , mTeleportClicksOld(0) + , mMapClicksOld(0) + , mProfileClicksOld(0) + , mTeleportClicksNew(0) + , mMapClicksNew(0) + , mProfileClicksNew(0) + , mSnapshotCtrl(NULL) +{ + sAllPanels.push_back(this); +} + +LLPanelClassifiedInfo::~LLPanelClassifiedInfo() +{ + sAllPanels.remove(this); + + if (getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); + } +} + +bool LLPanelClassifiedInfo::postBuild() +{ + childSetAction("show_on_map_btn", boost::bind(&LLPanelClassifiedInfo::onMapClick, this)); + childSetAction("teleport_btn", boost::bind(&LLPanelClassifiedInfo::onTeleportClick, this)); + + mScrollingPanel = getChild<LLPanel>("scroll_content_panel"); + mScrollContainer = getChild<LLScrollContainer>("profile_scroll"); + + mScrollingPanelMinHeight = mScrollContainer->getScrolledViewRect().getHeight(); + mScrollingPanelWidth = mScrollingPanel->getRect().getWidth(); + + mSnapshotCtrl = getChild<LLTextureCtrl>("classified_snapshot"); + mSnapshotRect = getDefaultSnapshotRect(); + + return true; +} + +void LLPanelClassifiedInfo::reshape(S32 width, S32 height, bool called_from_parent /* = true */) +{ + LLPanel::reshape(width, height, called_from_parent); + + if (!mScrollContainer || !mScrollingPanel) + return; + + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + + S32 scroll_height = mScrollContainer->getRect().getHeight(); + if (mScrollingPanelMinHeight >= scroll_height) + { + mScrollingPanel->reshape(mScrollingPanelWidth, mScrollingPanelMinHeight); + } + else + { + mScrollingPanel->reshape(mScrollingPanelWidth + scrollbar_size, scroll_height); + } + + mSnapshotRect = getDefaultSnapshotRect(); + stretchSnapshot(); +} + +void LLPanelClassifiedInfo::onOpen(const LLSD& key) +{ + LLUUID avatar_id = key["classified_creator_id"]; + if(avatar_id.isNull()) + { + return; + } + + if(getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); + } + + setAvatarId(avatar_id); + + resetData(); + resetControls(); + scrollToTop(); + + setClassifiedId(key["classified_id"]); + setClassifiedName(key["classified_name"]); + setDescription(key["classified_desc"]); + setSnapshotId(key["classified_snapshot_id"]); + setFromSearch(key["from_search"]); + + LL_INFOS() << "Opening classified [" << getClassifiedName() << "] (" << getClassifiedId() << ")" << LL_ENDL; + + LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); + gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough); + + if (gAgent.getRegion()) + { + // While we're at it let's get the stats from the new table if that + // capability exists. + std::string url = gAgent.getRegion()->getCapability("SearchStatRequest"); + if (!url.empty()) + { + LL_INFOS() << "Classified stat request via capability" << LL_ENDL; + LLSD body; + LLUUID classifiedId = getClassifiedId(); + body["classified_id"] = classifiedId; + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body, + boost::bind(&LLPanelClassifiedInfo::handleSearchStatResponse, classifiedId, _1)); + } + } + // Update classified click stats. + // *TODO: Should we do this when opening not from search? + sendClickMessage("profile"); + + setInfoLoaded(false); +} + +/*static*/ +void LLPanelClassifiedInfo::handleSearchStatResponse(LLUUID classifiedId, LLSD result) +{ + S32 teleport = result["teleport_clicks"].asInteger(); + S32 map = result["map_clicks"].asInteger(); + S32 profile = result["profile_clicks"].asInteger(); + S32 search_teleport = result["search_teleport_clicks"].asInteger(); + S32 search_map = result["search_map_clicks"].asInteger(); + S32 search_profile = result["search_profile_clicks"].asInteger(); + + LLPanelClassifiedInfo::setClickThrough(classifiedId, + teleport + search_teleport, + map + search_map, + profile + search_profile, + true); +} + +void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType type) +{ + if(APT_CLASSIFIED_INFO == type) + { + LLAvatarClassifiedInfo* c_info = static_cast<LLAvatarClassifiedInfo*>(data); + if(c_info && getClassifiedId() == c_info->classified_id) + { + setClassifiedName(c_info->name); + setDescription(c_info->description); + setSnapshotId(c_info->snapshot_id); + setParcelId(c_info->parcel_id); + setPosGlobal(c_info->pos_global); + setSimName(c_info->sim_name); + + setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); + getChild<LLUICtrl>("category")->setValue(LLClassifiedInfo::sCategories[c_info->category]); + + static std::string mature_str = getString("type_mature"); + static std::string pg_str = getString("type_pg"); + static LLUIString price_str = getString("l$_price"); + static std::string date_fmt = getString("date_fmt"); + + bool mature = is_cf_mature(c_info->flags); + getChild<LLUICtrl>("content_type")->setValue(mature ? mature_str : pg_str); + getChild<LLIconCtrl>("content_type_moderate")->setVisible(mature); + getChild<LLIconCtrl>("content_type_general")->setVisible(!mature); + + std::string auto_renew_str = is_cf_auto_renew(c_info->flags) ? + getString("auto_renew_on") : getString("auto_renew_off"); + getChild<LLUICtrl>("auto_renew")->setValue(auto_renew_str); + + price_str.setArg("[PRICE]", llformat("%d", c_info->price_for_listing)); + getChild<LLUICtrl>("price_for_listing")->setValue(LLSD(price_str)); + + std::string date_str = date_fmt; + LLStringUtil::format(date_str, LLSD().with("datetime", (S32) c_info->creation_date)); + getChild<LLUICtrl>("creation_date")->setValue(date_str); + + setInfoLoaded(true); + + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); + } + } +} + +void LLPanelClassifiedInfo::resetData() +{ + setClassifiedName(LLStringUtil::null); + setDescription(LLStringUtil::null); + setClassifiedLocation(LLStringUtil::null); + setClassifiedId(LLUUID::null); + setSnapshotId(LLUUID::null); + setPosGlobal(LLVector3d::zero); + setParcelId(LLUUID::null); + setSimName(LLStringUtil::null); + setFromSearch(false); + + // reset click stats + mTeleportClicksOld = 0; + mMapClicksOld = 0; + mProfileClicksOld = 0; + mTeleportClicksNew = 0; + mMapClicksNew = 0; + mProfileClicksNew = 0; + + getChild<LLUICtrl>("category")->setValue(LLStringUtil::null); + getChild<LLUICtrl>("content_type")->setValue(LLStringUtil::null); + getChild<LLUICtrl>("click_through_text")->setValue(LLStringUtil::null); + getChild<LLUICtrl>("price_for_listing")->setValue(LLStringUtil::null); + getChild<LLUICtrl>("auto_renew")->setValue(LLStringUtil::null); + getChild<LLUICtrl>("creation_date")->setValue(LLStringUtil::null); + getChild<LLUICtrl>("click_through_text")->setValue(LLStringUtil::null); + getChild<LLIconCtrl>("content_type_moderate")->setVisible(false); + getChild<LLIconCtrl>("content_type_general")->setVisible(false); +} + +void LLPanelClassifiedInfo::resetControls() +{ + bool is_self = getAvatarId() == gAgent.getID(); + + getChildView("edit_btn")->setEnabled(is_self); + getChildView("edit_btn")->setVisible( is_self); + getChildView("price_layout_panel")->setVisible( is_self); + getChildView("clickthrough_layout_panel")->setVisible( is_self); +} + +void LLPanelClassifiedInfo::setClassifiedName(const std::string& name) +{ + getChild<LLUICtrl>("classified_name")->setValue(name); +} + +std::string LLPanelClassifiedInfo::getClassifiedName() +{ + return getChild<LLUICtrl>("classified_name")->getValue().asString(); +} + +void LLPanelClassifiedInfo::setDescription(const std::string& desc) +{ + getChild<LLUICtrl>("classified_desc")->setValue(desc); +} + +std::string LLPanelClassifiedInfo::getDescription() +{ + return getChild<LLUICtrl>("classified_desc")->getValue().asString(); +} + +void LLPanelClassifiedInfo::setClassifiedLocation(const std::string& location) +{ + getChild<LLUICtrl>("classified_location")->setValue(location); +} + +std::string LLPanelClassifiedInfo::getClassifiedLocation() +{ + return getChild<LLUICtrl>("classified_location")->getValue().asString(); +} + +void LLPanelClassifiedInfo::setSnapshotId(const LLUUID& id) +{ + mSnapshotCtrl->setValue(id); + mSnapshotStreched = false; +} + +void LLPanelClassifiedInfo::draw() +{ + LLPanel::draw(); + + // Stretch in draw because it takes some time to load a texture, + // going to try to stretch snapshot until texture is loaded + if(!mSnapshotStreched) + { + stretchSnapshot(); + } +} + +LLUUID LLPanelClassifiedInfo::getSnapshotId() +{ + return getChild<LLUICtrl>("classified_snapshot")->getValue().asUUID(); +} + +// static +void LLPanelClassifiedInfo::setClickThrough( + const LLUUID& classified_id, + S32 teleport, + S32 map, + S32 profile, + bool from_new_table) +{ + LL_INFOS() << "Click-through data for classified " << classified_id << " arrived: [" + << teleport << ", " << map << ", " << profile << "] (" + << (from_new_table ? "new" : "old") << ")" << LL_ENDL; + + for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) + { + LLPanelClassifiedInfo* self = *iter; + if (self->getClassifiedId() != classified_id) + { + continue; + } + + // *HACK: Skip LLPanelClassifiedEdit instances: they don't display clicks data. + // Those instances should not be in the list at all. + if (typeid(*self) != typeid(LLPanelClassifiedInfo)) + { + continue; + } + + LL_INFOS() << "Updating classified info panel" << LL_ENDL; + + // We need to check to see if the data came from the new stat_table + // or the old classified table. We also need to cache the data from + // the two separate sources so as to display the aggregate totals. + + if (from_new_table) + { + self->mTeleportClicksNew = teleport; + self->mMapClicksNew = map; + self->mProfileClicksNew = profile; + } + else + { + self->mTeleportClicksOld = teleport; + self->mMapClicksOld = map; + self->mProfileClicksOld = profile; + } + + static LLUIString ct_str = self->getString("click_through_text_fmt"); + + ct_str.setArg("[TELEPORT]", llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld)); + ct_str.setArg("[MAP]", llformat("%d", self->mMapClicksNew + self->mMapClicksOld)); + ct_str.setArg("[PROFILE]", llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld)); + + self->getChild<LLUICtrl>("click_through_text")->setValue(ct_str.getString()); + // *HACK: remove this when there is enough room for click stats in the info panel + self->getChildView("click_through_text")->setToolTip(ct_str.getString()); + + LL_INFOS() << "teleport: " << llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld) + << ", map: " << llformat("%d", self->mMapClicksNew + self->mMapClicksOld) + << ", profile: " << llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld) + << LL_ENDL; + } +} + +// static +std::string LLPanelClassifiedInfo::createLocationText( + const std::string& original_name, + const std::string& sim_name, + const LLVector3d& pos_global) +{ + std::string location_text; + + location_text.append(original_name); + + if (!sim_name.empty()) + { + if (!location_text.empty()) + location_text.append(", "); + location_text.append(sim_name); + } + + if (!location_text.empty()) + location_text.append(" "); + + if (!pos_global.isNull()) + { + S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = ll_round((F32)pos_global.mdV[VZ]); + location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); + } + + return location_text; +} + +void LLPanelClassifiedInfo::stretchSnapshot() +{ + // *NOTE dzaporozhan + // Could be moved to LLTextureCtrl + + LLViewerFetchedTexture* texture = mSnapshotCtrl->getTexture(); + + if(!texture) + { + return; + } + + if(0 == texture->getOriginalWidth() || 0 == texture->getOriginalHeight()) + { + // looks like texture is not loaded yet + return; + } + + LLRect rc = mSnapshotRect; + // *HACK dzaporozhan + // LLTextureCtrl uses BTN_HEIGHT_SMALL as bottom for texture which causes + // drawn texture to be smaller than expected. (see LLTextureCtrl::draw()) + // Lets increase texture height to force texture look as expected. + rc.mBottom -= BTN_HEIGHT_SMALL; + + F32 t_width = texture->getFullWidth(); + F32 t_height = texture->getFullHeight(); + + F32 ratio = llmin<F32>( (rc.getWidth() / t_width), (rc.getHeight() / t_height) ); + + t_width *= ratio; + t_height *= ratio; + + rc.setCenterAndSize(rc.getCenterX(), rc.getCenterY(), llfloor(t_width), llfloor(t_height)); + mSnapshotCtrl->setShape(rc); + + mSnapshotStreched = true; +} + +LLRect LLPanelClassifiedInfo::getDefaultSnapshotRect() +{ + // Using scroll container makes getting default rect a hard task + // because rect in postBuild() and in first reshape() is not the same. + // Using snapshot_panel makes it easier to reshape snapshot. + return getChild<LLUICtrl>("snapshot_panel")->getLocalRect(); +} + +void LLPanelClassifiedInfo::scrollToTop() +{ + LLScrollContainer* scrollContainer = findChild<LLScrollContainer>("profile_scroll"); + if (scrollContainer) + scrollContainer->goToTop(); +} + +// static +// *TODO: move out of the panel +void LLPanelClassifiedInfo::sendClickMessage( + const std::string& type, + bool from_search, + const LLUUID& classified_id, + const LLUUID& parcel_id, + const LLVector3d& global_pos, + const std::string& sim_name) +{ + if (gAgent.getRegion()) + { + // You're allowed to click on your own ads to reassure yourself + // that the system is working. + LLSD body; + body["type"] = type; + body["from_search"] = from_search; + body["classified_id"] = classified_id; + body["parcel_id"] = parcel_id; + body["dest_pos_global"] = global_pos.getValue(); + body["region_name"] = sim_name; + + std::string url = gAgent.getRegion()->getCapability("SearchStatTracking"); + LL_INFOS() << "Sending click msg via capability (url=" << url << ")" << LL_ENDL; + LL_INFOS() << "body: [" << body << "]" << LL_ENDL; + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, + "SearchStatTracking Click report sent.", "SearchStatTracking Click report NOT sent."); + } +} + +void LLPanelClassifiedInfo::sendClickMessage(const std::string& type) +{ + sendClickMessage( + type, + fromSearch(), + getClassifiedId(), + getParcelId(), + getPosGlobal(), + getSimName()); +} + +void LLPanelClassifiedInfo::onMapClick() +{ + sendClickMessage("map"); + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + LLFloaterReg::showInstance("world_map", "center"); +} + +void LLPanelClassifiedInfo::onTeleportClick() +{ + if (!getPosGlobal().isExactlyZero()) + { + sendClickMessage("teleport"); + gAgent.teleportViaLocation(getPosGlobal()); + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + } +} + +//EOF |