/indra/newview/llpanelclassified.cpp
C++ | 1169 lines | 870 code | 206 blank | 93 comment | 65 complexity | 7de975b060f3568cba8cda7657c0ee2a MD5 | raw file
Possible License(s): LGPL-2.1
- /**
- * @file llpanelclassified.cpp
- * @brief LLPanelClassified class implementation
- *
- * $LicenseInfo:firstyear=2005&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$
- */
- // 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 "llhttpclient.h"
- #include "llnotifications.h"
- #include "llnotificationsutil.h"
- #include "llparcel.h"
- #include "llagent.h"
- #include "llclassifiedflags.h"
- #include "llclassifiedstatsresponder.h"
- #include "llcommandhandler.h" // for classified HTML detail page click tracking
- #include "lliconctrl.h"
- #include "lllineeditor.h"
- #include "llcombobox.h"
- #include "lltexturectrl.h"
- #include "lltexteditor.h"
- #include "llviewerparcelmgr.h"
- #include "llfloaterworldmap.h"
- #include "llviewergenericmessage.h" // send_generic_message
- #include "llviewerregion.h"
- #include "lltrans.h"
- #include "llscrollcontainer.h"
- #include "llstatusbar.h"
- const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$
- //static
- LLPanelClassifiedInfo::panel_list_t LLPanelClassifiedInfo::sAllPanels;
- // "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;
- // Just to debug errors. Can be thrown away later.
- class LLClassifiedClickMessageResponder : public LLHTTPClient::Responder
- {
- LOG_CLASS(LLClassifiedClickMessageResponder);
- public:
- // If we get back an error (not found, etc...), handle it here
- virtual void errorWithContent(
- U32 status,
- const std::string& reason,
- const LLSD& content)
- {
- llwarns << "Sending click message failed (" << status << "): [" << reason << "]" << llendl;
- llwarns << "Content: [" << content << "]" << llendl;
- }
- };
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- 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);
- }
- // static
- LLPanelClassifiedInfo* LLPanelClassifiedInfo::create()
- {
- LLPanelClassifiedInfo* panel = new LLPanelClassifiedInfo();
- panel->buildFromFile("panel_classified_info.xml");
- return panel;
- }
- BOOL LLPanelClassifiedInfo::postBuild()
- {
- childSetAction("back_btn", boost::bind(&LLPanelClassifiedInfo::onExit, this));
- 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::setExitCallback(const commit_callback_t& cb)
- {
- getChild<LLButton>("back_btn")->setClickedCallback(cb);
- }
- void LLPanelClassifiedInfo::setEditClassifiedCallback(const commit_callback_t& cb)
- {
- getChild<LLButton>("edit_btn")->setClickedCallback(cb);
- }
- 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"]);
- llinfos << "Opening classified [" << getClassifiedName() << "] (" << getClassifiedId() << ")" << llendl;
- LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this);
- LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId());
- gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough);
- // 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())
- {
- llinfos << "Classified stat request via capability" << llendl;
- LLSD body;
- body["classified_id"] = getClassifiedId();
- LLHTTPClient::post(url, body, new LLClassifiedStatsResponder(getClassifiedId()));
- }
- // Update classified click stats.
- // *TODO: Should we do this when opening not from search?
- sendClickMessage("profile");
- setInfoLoaded(false);
- }
- 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);
- }
- }
- }
- 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)
- {
- llinfos << "Click-through data for classified " << classified_id << " arrived: ["
- << teleport << ", " << map << ", " << profile << "] ("
- << (from_new_table ? "new" : "old") << ")" << llendl;
- 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;
- }
- llinfos << "Updating classified info panel" << llendl;
- // 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());
- llinfos << "teleport: " << llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld)
- << ", map: " << llformat("%d", self->mMapClicksNew + self->mMapClicksOld)
- << ", profile: " << llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld)
- << llendl;
- }
- }
- // 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 = llround((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS;
- S32 region_y = llround((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS;
- S32 region_z = llround((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)
- {
- // 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");
- llinfos << "Sending click msg via capability (url=" << url << ")" << llendl;
- llinfos << "body: [" << body << "]" << llendl;
- LLHTTPClient::post(url, body, new LLClassifiedClickMessageResponder());
- }
- 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());
- }
- }
- void LLPanelClassifiedInfo::onExit()
- {
- LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
- gGenericDispatcher.addHandler("classifiedclickthrough", NULL); // deregister our handler
- }
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- static const S32 CB_ITEM_MATURE = 0;
- static const S32 CB_ITEM_PG = 1;
- LLPanelClassifiedEdit::LLPanelClassifiedEdit()
- : LLPanelClassifiedInfo()
- , mIsNew(false)
- , mIsNewWithErrors(false)
- , mCanClose(false)
- , mPublishFloater(NULL)
- {
- }
- LLPanelClassifiedEdit::~LLPanelClassifiedEdit()
- {
- }
- //static
- LLPanelClassifiedEdit* LLPanelClassifiedEdit::create()
- {
- LLPanelClassifiedEdit* panel = new LLPanelClassifiedEdit();
- panel->buildFromFile("panel_edit_classified.xml");
- return panel;
- }
- BOOL LLPanelClassifiedEdit::postBuild()
- {
- LLPanelClassifiedInfo::postBuild();
- LLTextureCtrl* snapshot = getChild<LLTextureCtrl>("classified_snapshot");
- snapshot->setOnSelectCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this));
- LLUICtrl* edit_icon = getChild<LLUICtrl>("edit_icon");
- snapshot->setMouseEnterCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseEnter, this, edit_icon));
- snapshot->setMouseLeaveCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseLeave, this, edit_icon));
- edit_icon->setVisible(false);
- LLLineEditor* line_edit = getChild<LLLineEditor>("classified_name");
- line_edit->setKeystrokeCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL);
- LLTextEditor* text_edit = getChild<LLTextEditor>("classified_desc");
- text_edit->setKeystrokeCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this));
- LLComboBox* combobox = getChild<LLComboBox>( "category");
- LLClassifiedInfo::cat_map::iterator iter;
- for (iter = LLClassifiedInfo::sCategories.begin();
- iter != LLClassifiedInfo::sCategories.end();
- iter++)
- {
- combobox->add(LLTrans::getString(iter->second));
- }
- combobox->setCommitCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this));
- childSetCommitCallback("content_type", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL);
- childSetCommitCallback("price_for_listing", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL);
- childSetCommitCallback("auto_renew", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL);
- childSetAction("save_changes_btn", boost::bind(&LLPanelClassifiedEdit::onSaveClick, this));
- childSetAction("set_to_curr_location_btn", boost::bind(&LLPanelClassifiedEdit::onSetLocationClick, this));
- mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelClassifiedEdit::onTextureSelected, this));
- return TRUE;
- }
- void LLPanelClassifiedEdit::fillIn(const LLSD& key)
- {
- setAvatarId(gAgent.getID());
- if(key.isUndefined())
- {
- setPosGlobal(gAgent.getPositionGlobal());
- LLUUID snapshot_id = LLUUID::null;
- std::string desc;
- LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
- if(parcel)
- {
- desc = parcel->getDesc();
- snapshot_id = parcel->getSnapshotID();
- }
- std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish");
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- region_name = region->getName();
- }
- getChild<LLUICtrl>("classified_name")->setValue(makeClassifiedName());
- getChild<LLUICtrl>("classified_desc")->setValue(desc);
- setSnapshotId(snapshot_id);
- setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal()));
- // server will set valid parcel id
- setParcelId(LLUUID::null);
- }
- else
- {
- setClassifiedId(key["classified_id"]);
- setClassifiedName(key["name"]);
- setDescription(key["desc"]);
- setSnapshotId(key["snapshot_id"]);
- setCategory((U32)key["category"].asInteger());
- setContentType((U32)key["content_type"].asInteger());
- setClassifiedLocation(key["location_text"]);
- getChild<LLUICtrl>("auto_renew")->setValue(key["auto_renew"]);
- getChild<LLUICtrl>("price_for_listing")->setValue(key["price_for_listing"].asInteger());
- }
- }
- void LLPanelClassifiedEdit::onOpen(const LLSD& key)
- {
- mIsNew = key.isUndefined();
-
- scrollToTop();
- // classified is not created yet
- bool is_new = isNew() || isNewWithErrors();
- if(is_new)
- {
- resetData();
- resetControls();
- fillIn(key);
- if(isNew())
- {
- LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this);
- }
- }
- else
- {
- LLPanelClassifiedInfo::onOpen(key);
- }
- std::string save_btn_label = is_new ? getString("publish_label") : getString("save_label");
- getChild<LLUICtrl>("save_changes_btn")->setLabelArg("[LABEL]", save_btn_label);
- enableVerbs(is_new);
- enableEditing(is_new);
- showEditing(!is_new);
- resetDirty();
- setInfoLoaded(false);
- }
- void LLPanelClassifiedEdit::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)
- {
- // see LLPanelClassifiedEdit::sendUpdate() for notes
- mIsNewWithErrors = false;
- // for just created classified - panel will probably be closed when we get here.
- if(!getVisible())
- {
- return;
- }
- enableEditing(true);
- setClassifiedName(c_info->name);
- setDescription(c_info->description);
- setSnapshotId(c_info->snapshot_id);
- setPosGlobal(c_info->pos_global);
- setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global));
- // *HACK see LLPanelClassifiedEdit::sendUpdate()
- setCategory(c_info->category - 1);
- bool mature = is_cf_mature(c_info->flags);
- bool auto_renew = is_cf_auto_renew(c_info->flags);
- setContentType(mature ? CB_ITEM_MATURE : CB_ITEM_PG);
- getChild<LLUICtrl>("auto_renew")->setValue(auto_renew);
- getChild<LLUICtrl>("price_for_listing")->setValue(c_info->price_for_listing);
- getChildView("price_for_listing")->setEnabled(isNew());
- resetDirty();
- setInfoLoaded(true);
- enableVerbs(false);
- // for just created classified - in case user opened edit panel before processProperties() callback
- getChild<LLUICtrl>("save_changes_btn")->setLabelArg("[LABEL]", getString("save_label"));
- }
- }
- }
- BOOL LLPanelClassifiedEdit::isDirty() const
- {
- if(mIsNew)
- {
- return TRUE;
- }
- BOOL dirty = false;
- dirty |= LLPanelClassifiedInfo::isDirty();
- dirty |= getChild<LLUICtrl>("classified_snapshot")->isDirty();
- dirty |= getChild<LLUICtrl>("classified_name")->isDirty();
- dirty |= getChild<LLUICtrl>("classified_desc")->isDirty();
- dirty |= getChild<LLUICtrl>("category")->isDirty();
- dirty |= getChild<LLUICtrl>("content_type")->isDirty();
- dirty |= getChild<LLUICtrl>("auto_renew")->isDirty();
- dirty |= getChild<LLUICtrl>("price_for_listing")->isDirty();
- return dirty;
- }
- void LLPanelClassifiedEdit::resetDirty()
- {
- LLPanelClassifiedInfo::resetDirty();
- getChild<LLUICtrl>("classified_snapshot")->resetDirty();
- getChild<LLUICtrl>("classified_name")->resetDirty();
- LLTextEditor* desc = getChild<LLTextEditor>("classified_desc");
- // call blockUndo() to really reset dirty(and make isDirty work as intended)
- desc->blockUndo();
- desc->resetDirty();
- getChild<LLUICtrl>("category")->resetDirty();
- getChild<LLUICtrl>("content_type")->resetDirty();
- getChild<LLUICtrl>("auto_renew")->resetDirty();
- getChild<LLUICtrl>("price_for_listing")->resetDirty();
- }
- void LLPanelClassifiedEdit::setSaveCallback(const commit_signal_t::slot_type& cb)
- {
- mSaveButtonClickedSignal.connect(cb);
- }
- void LLPanelClassifiedEdit::setCancelCallback(const commit_signal_t::slot_type& cb)
- {
- getChild<LLButton>("cancel_btn")->setClickedCallback(cb);
- }
- void LLPanelClassifiedEdit::resetControls()
- {
- LLPanelClassifiedInfo::resetControls();
- getChild<LLComboBox>("category")->setCurrentByIndex(0);
- getChild<LLComboBox>("content_type")->setCurrentByIndex(0);
- getChild<LLUICtrl>("auto_renew")->setValue(false);
- getChild<LLUICtrl>("price_for_listing")->setValue(MINIMUM_PRICE_FOR_LISTING);
- getChildView("price_for_listing")->setEnabled(TRUE);
- }
- bool LLPanelClassifiedEdit::canClose()
- {
- return mCanClose;
- }
- void LLPanelClassifiedEdit::draw()
- {
- LLPanel::draw();
- // Need to re-stretch on every draw because LLTextureCtrl::onSelectCallback
- // does not trigger callbacks when user navigates through images.
- stretchSnapshot();
- }
- void LLPanelClassifiedEdit::stretchSnapshot()
- {
- LLPanelClassifiedInfo::stretchSnapshot();
- getChild<LLUICtrl>("edit_icon")->setShape(mSnapshotCtrl->getRect());
- }
- U32 LLPanelClassifiedEdit::getContentType()
- {
- LLComboBox* ct_cb = getChild<LLComboBox>("content_type");
- return ct_cb->getCurrentIndex();
- }
- void LLPanelClassifiedEdit::setContentType(U32 content_type)
- {
- LLComboBox* ct_cb = getChild<LLComboBox>("content_type");
- ct_cb->setCurrentByIndex(content_type);
- ct_cb->resetDirty();
- }
- bool LLPanelClassifiedEdit::getAutoRenew()
- {
- return getChild<LLUICtrl>("auto_renew")->getValue().asBoolean();
- }
- void LLPanelClassifiedEdit::sendUpdate()
- {
- LLAvatarClassifiedInfo c_data;
- if(getClassifiedId().isNull())
- {
- setClassifiedId(LLUUID::generateNewID());
- }
- c_data.agent_id = gAgent.getID();
- c_data.classified_id = getClassifiedId();
- // *HACK
- // Categories on server start with 1 while combo-box index starts with 0
- c_data.category = getCategory() + 1;
- c_data.name = getClassifiedName();
- c_data.description = getDescription();
- c_data.parcel_id = getParcelId();
- c_data.snapshot_id = getSnapshotId();
- c_data.pos_global = getPosGlobal();
- c_data.flags = getFlags();
- c_data.price_for_listing = getPriceForListing();
- LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoUpdate(&c_data);
-
- if(isNew())
- {
- // Lets assume there will be some error.
- // Successful sendClassifiedInfoUpdate will trigger processProperties and
- // let us know there was no error.
- mIsNewWithErrors = true;
- }
- }
- U32 LLPanelClassifiedEdit::getCategory()
- {
- LLComboBox* cat_cb = getChild<LLComboBox>("category");
- return cat_cb->getCurrentIndex();
- }
- void LLPanelClassifiedEdit::setCategory(U32 category)
- {
- LLComboBox* cat_cb = getChild<LLComboBox>("category");
- cat_cb->setCurrentByIndex(category);
- cat_cb->resetDirty();
- }
- U8 LLPanelClassifiedEdit::getFlags()
- {
- bool auto_renew = getChild<LLUICtrl>("auto_renew")->getValue().asBoolean();
- LLComboBox* content_cb = getChild<LLComboBox>("content_type");
- bool mature = content_cb->getCurrentIndex() == CB_ITEM_MATURE;
-
- return pack_classified_flags_request(auto_renew, false, mature, false);
- }
- void LLPanelClassifiedEdit::enableVerbs(bool enable)
- {
- getChildView("save_changes_btn")->setEnabled(enable);
- }
- void LLPanelClassifiedEdit::enableEditing(bool enable)
- {
- getChildView("classified_snapshot")->setEnabled(enable);
- getChildView("classified_name")->setEnabled(enable);
- getChildView("classified_desc")->setEnabled(enable);
- getChildView("set_to_curr_location_btn")->setEnabled(enable);
- getChildView("category")->setEnabled(enable);
- getChildView("content_type")->setEnabled(enable);
- getChildView("price_for_listing")->setEnabled(enable);
- getChildView("auto_renew")->setEnabled(enable);
- }
- void LLPanelClassifiedEdit::showEditing(bool show)
- {
- getChildView("price_for_listing_label")->setVisible( show);
- getChildView("price_for_listing")->setVisible( show);
- }
- std::string LLPanelClassifiedEdit::makeClassifiedName()
- {
- std::string name;
- LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
- if(parcel)
- {
- name = parcel->getName();
- }
- if(!name.empty())
- {
- return name;
- }
- LLViewerRegion* region = gAgent.getRegion();
- if(region)
- {
- name = region->getName();
- }
- return name;
- }
- S32 LLPanelClassifiedEdit::getPriceForListing()
- {
- return getChild<LLUICtrl>("price_for_listing")->getValue().asInteger();
- }
- void LLPanelClassifiedEdit::setPriceForListing(S32 price)
- {
- getChild<LLUICtrl>("price_for_listing")->setValue(price);
- }
- void LLPanelClassifiedEdit::onSetLocationClick()
- {
- setPosGlobal(gAgent.getPositionGlobal());
- setParcelId(LLUUID::null);
- std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish");
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- region_name = region->getName();
- }
- setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal()));
- // mark classified as dirty
- setValue(LLSD());
- onChange();
- }
- void LLPanelClassifiedEdit::onChange()
- {
- enableVerbs(isDirty());
- }
- void LLPanelClassifiedEdit::onSaveClick()
- {
- mCanClose = false;
- if(!isValidName())
- {
- notifyInvalidName();
- return;
- }
- if(isNew() || isNewWithErrors())
- {
- if(gStatusBar->getBalance() < getPriceForListing())
- {
- LLNotificationsUtil::add("ClassifiedInsufficientFunds");
- return;
- }
- mPublishFloater = LLFloaterReg::findTypedInstance<LLPublishClassifiedFloater>(
- "publish_classified", LLSD());
- if(!mPublishFloater)
- {
- mPublishFloater = LLFloaterReg::getTypedInstance<LLPublishClassifiedFloater>(
- "publish_classified", LLSD());
- mPublishFloater->setPublishClickedCallback(boost::bind
- (&LLPanelClassifiedEdit::onPublishFloaterPublishClicked, this));
- }
- // set spinner value before it has focus or value wont be set
- mPublishFloater->setPrice(getPriceForListing());
- mPublishFloater->openFloater(mPublishFloater->getKey());
- mPublishFloater->center();
- }
- else
- {
- doSave();
- }
- }
- void LLPanelClassifiedEdit::doSave()
- {
- mCanClose = true;
- sendUpdate();
- resetDirty();
- mSaveButtonClickedSignal(this, LLSD());
- }
- void LLPanelClassifiedEdit::onPublishFloaterPublishClicked()
- {
- setPriceForListing(mPublishFloater->getPrice());
- doSave();
- }
- std::string LLPanelClassifiedEdit::getLocationNotice()
- {
- static std::string location_notice = getString("location_notice");
- return location_notice;
- }
- bool LLPanelClassifiedEdit::isValidName()
- {
- std::string name = getClassifiedName();
- if (name.empty())
- {
- return false;
- }
- if (!isalnum(name[0]))
- {
- return false;
- }
- return true;
- }
- void LLPanelClassifiedEdit::notifyInvalidName()
- {
- std::string name = getClassifiedName();
- if (name.empty())
- {
- LLNotificationsUtil::add("BlankClassifiedName");
- }
- else if (!isalnum(name[0]))
- {
- LLNotificationsUtil::add("ClassifiedMustBeAlphanumeric");
- }
- }
- void LLPanelClassifiedEdit::onTexturePickerMouseEnter(LLUICtrl* ctrl)
- {
- ctrl->setVisible(TRUE);
- }
- void LLPanelClassifiedEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl)
- {
- ctrl->setVisible(FALSE);
- }
- void LLPanelClassifiedEdit::onTextureSelected()
- {
- setSnapshotId(mSnapshotCtrl->getValue().asUUID());
- }
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- LLPublishClassifiedFloater::LLPublishClassifiedFloater(const LLSD& key)
- : LLFloater(key)
- {
- }
- LLPublishClassifiedFloater::~LLPublishClassifiedFloater()
- {
- }
- BOOL LLPublishClassifiedFloater::postBuild()
- {
- LLFloater::postBuild();
- childSetAction("publish_btn", boost::bind(&LLFloater::closeFloater, this, false));
- childSetAction("cancel_btn", boost::bind(&LLFloater::closeFloater, this, false));
- return TRUE;
- }
- void LLPublishClassifiedFloater::setPrice(S32 price)
- {
- getChild<LLUICtrl>("price_for_listing")->setValue(price);
- }
- S32 LLPublishClassifiedFloater::getPrice()
- {
- return getChild<LLUICtrl>("price_for_listing")->getValue().asInteger();
- }
- void LLPublishClassifiedFloater::setPublishClickedCallback(const commit_signal_t::slot_type& cb)
- {
- getChild<LLButton>("publish_btn")->setClickedCallback(cb);
- }
- void LLPublishClassifiedFloater::setCancelClickedCallback(const commit_signal_t::slot_type& cb)
- {
- getChild<LLButton>("cancel_btn")->setClickedCallback(cb);
- }
- //EOF