/** * @file llpanelpick.cpp * @brief LLPanelPick class implementation * * $LicenseInfo:firstyear=2004&license=viewergpl$ * * Copyright (c) 2004-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ // Display of a "Top Pick" used both for the global top picks in the // Find directory, and also for each individual user's picks in their // profile. #include "llviewerprecompiledheaders.h" #include "llpanel.h" #include "message.h" #include "llagent.h" #include "llbutton.h" #include "lllineeditor.h" #include "llparcel.h" #include "llviewerparcelmgr.h" #include "lltexteditor.h" #include "lltexturectrl.h" #include "lluiconstants.h" #include "llworldmap.h" #include "llfloaterworldmap.h" #include "llfloaterreg.h" #include "llavatarpropertiesprocessor.h" #include "llpanelpick.h" #define XML_PANEL_EDIT_PICK "panel_edit_pick.xml" #define XML_PANEL_PICK_INFO "panel_pick_info.xml" #define XML_NAME "pick_name" #define XML_DESC "pick_desc" #define XML_SNAPSHOT "pick_snapshot" #define XML_LOCATION "pick_location" #define XML_BTN_SAVE "save_changes_btn" #define SAVE_BTN_LABEL "[WHAT]" #define LABEL_PICK = "Pick" #define LABEL_CHANGES = "Changes" std::string SET_LOCATION_NOTICE("(will update after save)"); LLPanelPick::LLPanelPick(BOOL edit_mode/* = FALSE */) : LLPanel(), LLAvatarPropertiesObserver(), LLRemoteParcelInfoObserver(), mEditMode(edit_mode), mSnapshotCtrl(NULL), mPickId(LLUUID::null), mCreatorId(LLUUID::null), mDataReceived(FALSE), mIsPickNew(false), mLocationChanged(false) { if (edit_mode) { LLUICtrlFactory::getInstance()->buildPanel(this, XML_PANEL_EDIT_PICK); LLAvatarPropertiesProcessor::instance().addObserver(gAgentID, this); } else { LLUICtrlFactory::getInstance()->buildPanel(this, XML_PANEL_PICK_INFO); } } LLPanelPick::~LLPanelPick() { if (mCreatorId.notNull()) LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorId, this); } void LLPanelPick::reset() { setEditMode(FALSE); mPickId.setNull(); mCreatorId.setNull(); mParcelId.setNull(); setPickName(""); setPickDesc(""); setPickLocation(""); mSnapshotCtrl->setImageAssetID(LLUUID::null); //*HACK just setting asset id to NULL not enough to clear //the texture controls, w/o setValid(FALSE) it continues to //draw the previously set image mSnapshotCtrl->setValid(FALSE); mDataReceived = FALSE; mPosGlobal.clearVec(); childSetValue("maturity", ""); } BOOL LLPanelPick::postBuild() { mSnapshotCtrl = getChild(XML_SNAPSHOT); if (mEditMode) { enableSaveButton(FALSE); mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelPick::onPickChanged, this, _1)); LLLineEditor* line_edit = getChild("pick_name"); line_edit->setKeystrokeCallback(boost::bind(&LLPanelPick::onPickChanged, this, _1), NULL); LLTextEditor* text_edit = getChild("pick_desc"); text_edit->setKeystrokeCallback(boost::bind(&LLPanelPick::onPickChanged, this, _1)); childSetAction("cancel_btn", boost::bind(&LLPanelPick::onClickCancel, this)); childSetAction("set_to_curr_location_btn", boost::bind(&LLPanelPick::onClickSet, this)); childSetAction(XML_BTN_SAVE, boost::bind(&LLPanelPick::onClickSave, this)); mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelPick::childSetVisible, this, "edit_icon", true)); mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelPick::childSetVisible, this, "edit_icon", false)); } else { childSetAction("edit_btn", boost::bind(&LLPanelPick::onClickEdit, this)); childSetAction("teleport_btn", boost::bind(&LLPanelPick::onClickTeleport, this)); childSetAction("show_on_map_btn", boost::bind(&LLPanelPick::onClickMap, this)); } // EXT-822. We have to process "Back" button click in both Edit & View Modes if (!mBackCb.empty()) { LLButton* button = findChild("back_btn"); if (button) button->setClickedCallback(mBackCb); } return TRUE; } void LLPanelPick::init(LLUUID creator_id, LLUUID pick_id) { mCreatorId = creator_id; mPickId = pick_id; //*TODO consider removing this, already called by setEditMode() updateButtons(); requestData(); } void LLPanelPick::requestData() { mDataReceived = FALSE; LLAvatarPropertiesProcessor::instance().addObserver(mCreatorId, this); LLAvatarPropertiesProcessor::instance().sendPickInfoRequest(mCreatorId, mPickId); } void LLPanelPick::init(LLPickData *pick_data) { mPickId = pick_data->pick_id; mCreatorId = pick_data->creator_id; setPickName(pick_data->name); setPickDesc(pick_data->desc); mSnapshotCtrl->setImageAssetID(pick_data->snapshot_id); //*HACK see reset() where the texture control was set to FALSE mSnapshotCtrl->setValid(TRUE); mPosGlobal = pick_data->pos_global; mSimName = pick_data->sim_name; mParcelId = pick_data->parcel_id; setPickLocation(createLocationText(pick_data->user_name, pick_data->original_name, pick_data->sim_name, pick_data->pos_global)); } void LLPanelPick::prepareNewPick(const LLVector3d pos_global, const std::string& name, const std::string& desc, const LLUUID& snapshot_id, const LLUUID& parcel_id) { mPickId.generate(); mCreatorId = gAgent.getID(); mPosGlobal = pos_global; setPickName(name); setPickDesc(desc); mSnapshotCtrl->setImageAssetID(snapshot_id); mParcelId = parcel_id; setPickLocation(createLocationText(std::string(""), SET_LOCATION_NOTICE, name, pos_global)); childSetLabelArg(XML_BTN_SAVE, SAVE_BTN_LABEL, std::string("Pick")); mIsPickNew = true; } // Fill in some reasonable defaults for a new pick. void LLPanelPick::prepareNewPick() { // Try to fill in the current parcel LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (parcel) { prepareNewPick(gAgent.getPositionGlobal(), parcel->getName(), parcel->getDesc(), parcel->getSnapshotID(), parcel->getID()); } } /*virtual*/ void LLPanelPick::processProperties(void* data, EAvatarProcessorType type) { if (APT_PICK_INFO != type) return; if (!data) return; LLPickData* pick_data = static_cast(data); if (!pick_data) return; if (mPickId != pick_data->pick_id) return; init(pick_data); mDataReceived = TRUE; LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorId, this); if (!mEditMode) { LLRemoteParcelInfoProcessor::getInstance()->addObserver(pick_data->parcel_id, this); LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(pick_data->parcel_id); } } void LLPanelPick::setEditMode( BOOL edit_mode ) { if (mEditMode == edit_mode) return; mEditMode = edit_mode; // preserve data before killing controls LLUUID snapshot_id = mSnapshotCtrl->getImageAssetID(); LLRect old_rect = getRect(); deleteAllChildren(); // *WORKAROUND: for EXT-931. Children are created for both XML_PANEL_EDIT_PICK & XML_PANEL_PICK_INFO files // The reason is in LLPanel::initPanelXML called from the LLUICtrlFactory::buildPanel(). // It creates children from the xml file stored while previous initializing in the "mXMLFilename" member // and then in creates children from the parameters passed from the LLUICtrlFactory::buildPanel(). // Xml filename is stored after LLPanel::initPanelXML is called (added with export-from-ll/viewer-2-0, r1594 into LLUICtrlFactory::buildPanel & LLUICtrlFactory::buildFloater) // In case panel creates children from the different xml files they appear from both files. // So, let clear xml filename related to this instance. setXMLFilename(""); if (edit_mode) { LLUICtrlFactory::getInstance()->buildPanel(this, XML_PANEL_EDIT_PICK); } else { LLUICtrlFactory::getInstance()->buildPanel(this, XML_PANEL_PICK_INFO); } //*NOTE this code is from LLPanelMeProfile.togglePanel()... doubt this is a right way to do things reshape(old_rect.getWidth(), old_rect.getHeight()); old_rect.setLeftTopAndSize(0, old_rect.getHeight(), old_rect.getWidth(), old_rect.getHeight()); setRect(old_rect); // time to restore data setPickName(mName); setPickDesc(mDesc); setPickLocation(mLocation); mSnapshotCtrl->setImageAssetID(snapshot_id); updateButtons(); } void LLPanelPick::onPickChanged(LLUICtrl* ctrl) { if(mLocationChanged) { // Pick was enabled in onClickSet return; } if( mSnapshotCtrl->isDirty() || getChild("pick_name")->isDirty() || getChild("pick_desc")->isDirty() ) { enableSaveButton(TRUE); } else { enableSaveButton(FALSE); } } ////////////////////////////////////////////////////////////////////////// // PROTECTED AREA ////////////////////////////////////////////////////////////////////////// //static std::string LLPanelPick::createLocationText(const std::string& owner_name, const std::string& original_name, const std::string& sim_name, const LLVector3d& pos_global) { std::string location_text; location_text.append(owner_name); if (!original_name.empty()) { if (!location_text.empty()) location_text.append(", "); 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 LLPanelPick::setPickName(std::string name) { if (mEditMode) { childSetValue(XML_NAME, name); } else { childSetWrappedText(XML_NAME, name); } //preserving non-wrapped text for info/edit modes switching mName = name; } void LLPanelPick::setPickDesc(std::string desc) { if (mEditMode) { childSetValue(XML_DESC, desc); } else { childSetWrappedText(XML_DESC, desc); } //preserving non-wrapped text for info/edit modes switching mDesc = desc; } void LLPanelPick::setPickLocation(const std::string& location) { childSetWrappedText(XML_LOCATION, location); //preserving non-wrapped text for info/edit modes switching mLocation = location; } std::string LLPanelPick::getPickName() { return childGetValue(XML_NAME).asString(); } std::string LLPanelPick::getPickDesc() { return childGetValue(XML_DESC).asString(); } std::string LLPanelPick::getPickLocation() { return childGetValue(XML_LOCATION).asString(); } void LLPanelPick::sendUpdate() { LLPickData pick_data; // If we don't have a pick id yet, we'll need to generate one, // otherwise we'll keep overwriting pick_id 00000 in the database. if (mPickId.isNull()) mPickId.generate(); pick_data.agent_id = gAgent.getID(); pick_data.session_id = gAgent.getSessionID(); pick_data.pick_id = mPickId; pick_data.creator_id = gAgentID; //legacy var need to be deleted pick_data.top_pick = FALSE; pick_data.parcel_id = mParcelId; pick_data.name = getPickName(); pick_data.desc = getPickDesc(); pick_data.snapshot_id = mSnapshotCtrl->getImageAssetID(); pick_data.pos_global = mPosGlobal; pick_data.sort_order = 0; pick_data.enabled = TRUE; mDataReceived = FALSE; LLAvatarPropertiesProcessor::instance().addObserver(gAgentID, this); LLAvatarPropertiesProcessor::instance().sendPickInfoUpdate(&pick_data); } //----------------------------------------- // "PICK INFO" (VIEW MODE) BUTTON HANDLERS //----------------------------------------- //static void LLPanelPick::onClickEdit() { if (mEditMode) return; if (!mDataReceived) return; setEditMode(TRUE); } //static void LLPanelPick::onClickTeleport() { teleport(mPosGlobal); } //static void LLPanelPick::onClickMap() { showOnMap(mPosGlobal); } //----------------------------------------- // "EDIT PICK" (EDIT MODE) BUTTON HANDLERS //----------------------------------------- //static void LLPanelPick::onClickCancel() { if (!mEditMode) return; if (mIsPickNew) { mBackCb(this, LLSD()); return; } LLUUID pick_id = mPickId; LLUUID creator_id = mCreatorId; reset(); init(creator_id, pick_id); } // static void LLPanelPick::onClickSet() { if (!mEditMode) return; if (!mIsPickNew && !mDataReceived) return; // Save location for later. mPosGlobal = gAgent.getPositionGlobal(); LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (parcel) { mParcelId = parcel->getID(); mSimName = parcel->getName(); } setPickLocation(createLocationText(std::string(""), SET_LOCATION_NOTICE, mSimName, mPosGlobal)); mLocationChanged = true; enableSaveButton(TRUE); } // static void LLPanelPick::onClickSave() { if (!mEditMode) return; if (!mIsPickNew && !mDataReceived) return; sendUpdate(); if (mIsPickNew) { mBackCb(this, LLSD()); return; } setEditMode(FALSE); } void LLPanelPick::updateButtons() { // on Pick Info panel (for non-Agent picks) edit_btn should be invisible if (mEditMode) { childSetLabelArg(XML_BTN_SAVE, SAVE_BTN_LABEL, std::string("Changes")); } else { if (mCreatorId != gAgentID) { childSetEnabled("edit_btn", FALSE); childSetVisible("edit_btn", FALSE); } else { childSetEnabled("edit_btn", TRUE); childSetVisible("edit_btn", TRUE); } } } void LLPanelPick::setExitCallback(commit_callback_t cb) { mBackCb = cb; LLButton* button = findChild("back_btn"); if (button) button->setClickedCallback(mBackCb); } //static void LLPanelPick::teleport(const LLVector3d& position) { if (!position.isExactlyZero()) { gAgent.teleportViaLocation(position); LLFloaterWorldMap::getInstance()->trackLocation(position); } } //static void LLPanelPick::showOnMap(const LLVector3d& position) { LLFloaterWorldMap::getInstance()->trackLocation(position); LLFloaterReg::showInstance("world_map", "center"); } void LLPanelPick::processParcelInfo(const LLParcelData& parcel_data) { if (mEditMode) return; // HACK: Flag 0x2 == adult region, // Flag 0x1 == mature region, otherwise assume PG std::string rating_icon = "icon_event.tga"; if (parcel_data.flags & 0x2) { rating_icon = "icon_event_adult.tga"; } else if (parcel_data.flags & 0x1) { rating_icon = "icon_event_mature.tga"; } childSetValue("maturity", rating_icon); //*NOTE we don't removeObserver(...) ourselves cause LLRemoveParcelProcessor does it for us } void LLPanelPick::enableSaveButton(bool enable) { if(!mEditMode) { return; } childSetEnabled(XML_BTN_SAVE, enable); }