/** * @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 "llparcel.h" #include "llviewerparcelmgr.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" LLPanelPick::LLPanelPick(BOOL edit_mode/* = FALSE */) : LLPanel(), LLAvatarPropertiesObserver(), LLRemoteParcelInfoObserver(), mEditMode(edit_mode), mSnapshotCtrl(NULL), mPickId(LLUUID::null), mCreatorId(LLUUID::null), mDataReceived(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) { 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); setPickLocation(pick_data->location_text); 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; } // Fill in some reasonable defaults for a new pick. void LLPanelPick::createNewPick() { mPickId.generate(); mCreatorId = gAgent.getID(); mPosGlobal = gAgent.getPositionGlobal(); // Try to fill in the current parcel LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (parcel) { setPickName(parcel->getName()); setPickDesc(parcel->getDesc()); mSnapshotCtrl->setImageAssetID(parcel->getSnapshotID()); } sendUpdate(); childSetLabelArg(XML_BTN_SAVE, SAVE_BTN_LABEL, std::string("Pick")); } /*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(); 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::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(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; LLUUID pick_id = mPickId; LLUUID creator_id = mCreatorId; reset(); init(creator_id, pick_id); } // static void LLPanelPick::onClickSet() { if (!mEditMode) return; if (!mDataReceived) return; // Save location for later. mPosGlobal = gAgent.getPositionGlobal(); S32 region_x = llround((F32)mPosGlobal.mdV[VX]) % REGION_WIDTH_UNITS; S32 region_y = llround((F32)mPosGlobal.mdV[VY]) % REGION_WIDTH_UNITS; S32 region_z = llround((F32)mPosGlobal.mdV[VZ]); std::string location_text = "(will update after save), "; location_text.append(mSimName); location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); setPickLocation(location_text); } // static void LLPanelPick::onClickSave() { if (!mEditMode) return; if (!mDataReceived) return; sendUpdate(); 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 }