//compares two LLSD's bool llsds_are_equal(const LLSD& llsd_1, const LLSD& llsd_2) { llassert(llsd_1.isDefined()); llassert(llsd_2.isDefined()); if (llsd_1.type() != llsd_2.type()) return false; if (!llsd_1.isMap()) { if (llsd_1.isUUID()) return llsd_1.asUUID() == llsd_2.asUUID(); //assumptions that string representaion is enough for other types return llsd_1.asString() == llsd_2.asString(); } if (llsd_1.size() != llsd_2.size()) return false; LLSD::map_const_iterator llsd_1_it = llsd_1.beginMap(); LLSD::map_const_iterator llsd_2_it = llsd_2.beginMap(); for (S32 i = 0; i < llsd_1.size(); ++i) { if ((*llsd_1_it).first != (*llsd_2_it).first) return false; if (!llsds_are_equal((*llsd_1_it).second, (*llsd_2_it).second)) return false; ++llsd_1_it; ++llsd_2_it; } return true; }
void LLScrollListIcon::setValue(const LLSD& value) { if (value.isUUID()) { // don't use default image specified by LLUUID::null, use no image in that case LLUUID image_id = value.asUUID(); mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL); } else { std::string value_string = value.asString(); if (LLUUID::validate(value_string)) { setValue(LLUUID(value_string)); } else if (!value_string.empty()) { mIcon = LLUI::getUIImage(value.asString()); } else { mIcon = NULL; } } }
void LLGroupIconCtrl::setValue(const LLSD& value) { if (value.isUUID()) { LLGroupMgr* gm = LLGroupMgr::getInstance(); if (mGroupId.notNull()) { gm->removeObserver(this); } if (mGroupId != value.asUUID()) { mGroupId = value.asUUID(); mID = mGroupId; // set LLGroupMgrObserver::mID to make callbacks work // Check if cache already contains image_id for that group if (!updateFromCache()) { LLIconCtrl::setValue(mDefaultIconName); gm->addObserver(this); gm->sendGroupPropertiesRequest(mGroupId); } } } else { LLIconCtrl::setValue(value); } }
// virtual void LLIconCtrl::setValue(const LLSD& value ) { if (value.isUUID()) { setImage(value.asUUID()); } else { setImage(value.asString()); } }
//virtual void LLAvatarIconCtrl::setValue(const LLSD& value) { if (value.isUUID()) { LLAvatarPropertiesProcessor* app = LLAvatarPropertiesProcessor::getInstance(); if (mAvatarId.notNull()) { app->removeObserver(mAvatarId, this); } if (mAvatarId != value.asUUID()) { mAvatarId = value.asUUID(); // *BUG: This will return stale icons if a user changes their // profile picture. However, otherwise we send too many upstream // AvatarPropertiesRequest messages. // to get fresh avatar icon use // LLAvatarIconIDCache::getInstance()->remove(avatar_id); // Check if cache already contains image_id for that avatar if (!updateFromCache()) { // *TODO: Consider getting avatar icon/badge directly from // People API, rather than sending AvatarPropertyRequest // messages. People API already hits the user table. LLIconCtrl::setValue(mDefaultIconName); app->addObserver(mAvatarId, this); app->sendAvatarPropertiesRequest(mAvatarId); } } } else { LLIconCtrl::setValue(value); } LLAvatarNameCache::get(mAvatarId, boost::bind(&LLAvatarIconCtrl::onAvatarNameCache, this, _1, _2)); }
//virtual void LLAvatarIconCtrl::setValue(const LLSD& value) { if (value.isUUID()) { LLAvatarPropertiesProcessor* app = LLAvatarPropertiesProcessor::getInstance(); if (mAvatarId.notNull()) { app->removeObserver(mAvatarId, this); } if (mAvatarId != value.asUUID()) { mAvatarId = value.asUUID(); // *BUG: This will return stale icons if a user changes their // profile picture. However, otherwise we send too many upstream // AvatarPropertiesRequest messages. // to get fresh avatar icon use // LLAvatarIconIDCache::getInstance()->remove(avatar_id); // Check if cache already contains image_id for that avatar if (!updateFromCache()) { LLIconCtrl::setValue(mDefaultIconName); app->addObserver(mAvatarId, this); app->sendAvatarPropertiesRequest(mAvatarId); } } } else { LLIconCtrl::setValue(value); } if (gCacheName) { gCacheName->get(mAvatarId, FALSE, boost::bind(&LLAvatarIconCtrl::nameUpdatedCallback, this, _1, _2, _3, _4)); } }
// see docstring in .h file std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx) { // An undefined prototype means that any data is valid. // An undefined slot in an array or map prototype means that any data // may fill that slot. if (prototype.isUndefined()) return ""; // A prototype array must match a data array with at least as many // entries. Moreover, every prototype entry must match the // corresponding data entry. if (prototype.isArray()) { if (! data.isArray()) { return STRINGIZE(colon(pfx) << "Array" << op << sTypes.lookup(data.type())); } if (data.size() < prototype.size()) { return STRINGIZE(colon(pfx) << "Array size " << prototype.size() << op << "Array size " << data.size()); } for (LLSD::Integer i = 0; i < prototype.size(); ++i) { std::string match(llsd_matches(prototype[i], data[i], STRINGIZE('[' << i << ']'))); if (! match.empty()) { return match; } } return ""; } // A prototype map must match a data map. Every key in the prototype // must have a corresponding key in the data map; every value in the // prototype must match the corresponding key's value in the data. if (prototype.isMap()) { if (! data.isMap()) { return STRINGIZE(colon(pfx) << "Map" << op << sTypes.lookup(data.type())); } // If there are a number of keys missing from the data, it would be // frustrating to a coder to discover them one at a time, with a big // build each time. Enumerate all missing keys. std::ostringstream out; out << colon(pfx); const char* init = "Map missing keys: "; const char* sep = init; for (LLSD::map_const_iterator mi = prototype.beginMap(); mi != prototype.endMap(); ++mi) { if (! data.has(mi->first)) { out << sep << mi->first; sep = ", "; } } // So... are we missing any keys? if (sep != init) { return out.str(); } // Good, the data block contains all the keys required by the // prototype. Now match the prototype entries. for (LLSD::map_const_iterator mi2 = prototype.beginMap(); mi2 != prototype.endMap(); ++mi2) { std::string match(llsd_matches(mi2->second, data[mi2->first], STRINGIZE("['" << mi2->first << "']"))); if (! match.empty()) { return match; } } return ""; } // A String prototype can match String, Boolean, Integer, Real, UUID, // Date and URI, because any of these can be converted to String. if (prototype.isString()) { static LLSD::Type accept[] = { LLSD::TypeBoolean, LLSD::TypeInteger, LLSD::TypeReal, LLSD::TypeUUID, LLSD::TypeDate, LLSD::TypeURI }; return match_types(prototype.type(), TypeVector(boost::begin(accept), boost::end(accept)), data.type(), pfx); } // Boolean, Integer, Real match each other or String. TBD: ensure that // a String value is numeric. if (prototype.isBoolean() || prototype.isInteger() || prototype.isReal()) { static LLSD::Type all[] = { LLSD::TypeBoolean, LLSD::TypeInteger, LLSD::TypeReal, LLSD::TypeString }; // Funny business: shuffle the set of acceptable types to include all // but the prototype's type. Get the acceptable types in a set. std::set<LLSD::Type> rest(boost::begin(all), boost::end(all)); // Remove the prototype's type because we pass that separately. rest.erase(prototype.type()); return match_types(prototype.type(), TypeVector(rest.begin(), rest.end()), data.type(), pfx); } // UUID, Date and URI match themselves or String. if (prototype.isUUID() || prototype.isDate() || prototype.isURI()) { static LLSD::Type accept[] = { LLSD::TypeString }; return match_types(prototype.type(), TypeVector(boost::begin(accept), boost::end(accept)), data.type(), pfx); } // We don't yet know the conversion semantics associated with any new LLSD // data type that might be added, so until we've been extended to handle // them, assume it's strict: the new type matches only itself. (This is // true of Binary, which is why we don't handle that case separately.) Too // bad LLSD doesn't define isConvertible(Type to, Type from). return match_types(prototype.type(), TypeVector(), data.type(), pfx); }