bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, const std::string& scope, LLInitParam::BaseBlock& block) { typedef boost::tokenizer<boost::char_separator<char> > tokenizer; boost::char_separator<char> sep("."); bool values_parsed = false; // submit attributes for current node values_parsed |= readAttributes(nodep, block); // treat text contents of xml node as "value" parameter std::string text_contents = nodep->getSanitizedValue(); if (!text_contents.empty()) { mCurReadNode = nodep; mNameStack.push_back(std::make_pair(std::string("value"), newParseGeneration())); // child nodes are not necessarily valid parameters (could be a child widget) // so don't complain once we've recursed bool silent = mCurReadDepth > 0; if (!block.submitValue(mNameStack, *this, true)) { mNameStack.pop_back(); block.submitValue(mNameStack, *this, silent); } else { mNameStack.pop_back(); } } // then traverse children // child node must start with last name of parent node (our "scope") // for example: "<button><button.param nested_param1="foo"><param.nested_param2 nested_param3="bar"/></button.param></button>" // which equates to the following nesting: // button // param // nested_param1 // nested_param2 // nested_param3 mCurReadDepth++; for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();) { std::string child_name(childp->getName()->mString); S32 num_tokens_pushed = 0; // for non "dotted" child nodes check to see if child node maps to another widget type // and if not, treat as a child element of the current node // e.g. <button><rect left="10"/></button> will interpret <rect> as "button.rect" // since there is no widget named "rect" if (child_name.find(".") == std::string::npos) { mNameStack.push_back(std::make_pair(child_name, newParseGeneration())); num_tokens_pushed++; } else { // parse out "dotted" name into individual tokens tokenizer name_tokens(child_name, sep); tokenizer::iterator name_token_it = name_tokens.begin(); if(name_token_it == name_tokens.end()) { childp = childp->getNextSibling(); continue; } // check for proper nesting if(!scope.empty() && *name_token_it != scope) { childp = childp->getNextSibling(); continue; } // now ignore first token ++name_token_it; // copy remaining tokens on to our running token list for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) { mNameStack.push_back(std::make_pair(*token_to_push, newParseGeneration())); num_tokens_pushed++; } } // recurse and visit children XML nodes if(readXUIImpl(childp, mNameStack.empty() ? scope : mNameStack.back().first, block)) { // child node successfully parsed, remove from DOM values_parsed = true; LLXMLNodePtr node_to_remove = childp; childp = childp->getNextSibling(); nodep->deleteChild(node_to_remove); } else { childp = childp->getNextSibling(); } while(num_tokens_pushed-- > 0) { mNameStack.pop_back(); } } mCurReadDepth--; return values_parsed; }
//static void LLUICtrlFactory::copyName(LLXMLNodePtr src, LLXMLNodePtr dest) { dest->setName(src->getName()->mString); }
bool LLNotifications::loadTemplates() { const std::string xml_filename = "notifications.xml"; LLXMLNodePtr root; BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); if (!success || root.isNull() || !root->hasName( "notifications" )) { llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl; return false; } clearTemplates(); for (LLXMLNodePtr item = root->getFirstChild(); item.notNull(); item = item->getNextSibling()) { // we do this FIRST so that item can be changed if we // encounter a usetemplate -- we just replace the // current xml node and keep processing item = checkForXMLTemplate(item); if (item->hasName("global")) { std::string global_name; if (item->getAttributeString("name", global_name)) { mGlobalStrings[global_name] = item->getTextContents(); } continue; } if (item->hasName("template")) { // store an xml template; templates must have a single node (can contain // other nodes) std::string name; item->getAttributeString("name", name); LLXMLNodePtr ptr = item->getFirstChild(); mXmlTemplates[name] = ptr; continue; } if (!item->hasName("notification")) { llwarns << "Unexpected entity " << item->getName()->mString << " found in " << xml_filename << llendl; continue; } // now we know we have a notification entry, so let's build it LLNotificationTemplatePtr pTemplate(new LLNotificationTemplate()); if (!item->getAttributeString("name", pTemplate->mName)) { llwarns << "Unable to parse notification with no name" << llendl; continue; } LL_DEBUGS("Notifications") << "Parsing " << pTemplate->mName << LL_ENDL; pTemplate->mMessage = item->getTextContents(); pTemplate->mDefaultFunctor = pTemplate->mName; item->getAttributeString("type", pTemplate->mType); item->getAttributeString("icon", pTemplate->mIcon); item->getAttributeString("label", pTemplate->mLabel); item->getAttributeU32("duration", pTemplate->mExpireSeconds); item->getAttributeU32("expireOption", pTemplate->mExpireOption); std::string priority; item->getAttributeString("priority", priority); pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL; if (!priority.empty()) { if (priority == "low") pTemplate->mPriority = NOTIFICATION_PRIORITY_LOW; if (priority == "normal") pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL; if (priority == "high") pTemplate->mPriority = NOTIFICATION_PRIORITY_HIGH; if (priority == "critical") pTemplate->mPriority = NOTIFICATION_PRIORITY_CRITICAL; } item->getAttributeString("functor", pTemplate->mDefaultFunctor); BOOL persist = false; item->getAttributeBOOL("persist", persist); pTemplate->mPersist = persist; std::string sound; item->getAttributeString("sound", sound); if (!sound.empty()) { // TODO: test for bad sound effect name / missing effect pTemplate->mSoundEffect = LLUUID(LLUI::sConfigGroup->getString(sound.c_str())); } for (LLXMLNodePtr child = item->getFirstChild(); !child.isNull(); child = child->getNextSibling()) { child = checkForXMLTemplate(child); // <url> if (child->hasName("url")) { pTemplate->mURL = child->getTextContents(); child->getAttributeU32("option", pTemplate->mURLOption); } if (child->hasName("unique")) { pTemplate->mUnique = true; for (LLXMLNodePtr formitem = child->getFirstChild(); !formitem.isNull(); formitem = formitem->getNextSibling()) { if (formitem->hasName("context")) { std::string key; formitem->getAttributeString("key", key); pTemplate->mUniqueContext.push_back(key); //llwarns << "adding " << key << " to unique context" << llendl; } else { llwarns << "'unique' has unrecognized subelement " << formitem->getName()->mString << llendl; } } } // <form> if (child->hasName("form")) { pTemplate->mForm = LLNotificationFormPtr(new LLNotificationForm(pTemplate->mName, child)); } } addTemplate(pTemplate->mName, pTemplate); } //std::ostringstream ostream; //root->writeToOstream(ostream, "\n "); //llwarns << ostream.str() << llendl; return true; }
void LLUICtrl::initFromXML(LLXMLNodePtr node, LLView* parent) { std::string name; if(node->getAttributeString("name", name)) setName(name); BOOL has_tab_stop = hasTabStop(); node->getAttributeBOOL("tab_stop", has_tab_stop); setTabStop(has_tab_stop); node->getAttributeBOOL("requests_front", mRequestsFront); std::string str = node->getName()->mString; std::string attrib_str; LLXMLNodePtr child_node; //Since so many other callback 'types' piggyback off of the commitcallback registrar as well as use the same callback signature //we can assemble a nice little static list to iterate down instead of copy-pasting mostly similar code for each instance. //Validate/enable callbacks differ, as it uses its own registry/callback signature. This could be worked around with a template, but keeping //all the code local to this scope is more beneficial. typedef boost::signals2::connection (LLUICtrl::*commit_fn)( const commit_signal_t::slot_type& cb ); static std::pair<std::string,commit_fn> sCallbackRegistryMap[3] = { std::pair<std::string,commit_fn>(".commit_callback",&LLUICtrl::setCommitCallback), std::pair<std::string,commit_fn>(".mouseenter_callback",&LLUICtrl::setMouseEnterCallback), std::pair<std::string,commit_fn>(".mouseleave_callback",&LLUICtrl::setMouseLeaveCallback) }; for(S32 i= 0; i < sizeof(sCallbackRegistryMap)/sizeof(sCallbackRegistryMap[0]);++i) { if(node->getChild((str+sCallbackRegistryMap[i].first).c_str(),child_node,false)) { if(child_node->getAttributeString("function",attrib_str)) { commit_callback_t* func = (CommitCallbackRegistry::getValue(attrib_str)); if (func) { if(child_node->getAttributeString("parameter",attrib_str)) (this->*sCallbackRegistryMap[i].second)(boost::bind((*func), this, LLSD(attrib_str))); else (this->*sCallbackRegistryMap[i].second)(commit_signal_t::slot_type(*func)); } } } } if(node->getChild((str+".validate_callback").c_str(),child_node,false)) { if(child_node->getAttributeString("function",attrib_str)) { enable_callback_t* func = (EnableCallbackRegistry::getValue(attrib_str)); if (func) { if(child_node->getAttributeString("parameter",attrib_str)) setValidateCallback(boost::bind((*func), this, LLSD(attrib_str))); else setValidateCallback(enable_signal_t::slot_type(*func)); } } } LLView::initFromXML(node, parent); if (node->getAttributeString("enabled_control", attrib_str)) { LLControlVariable* control = findControl(attrib_str); if (control) setEnabledControlVariable(control); } if (node->getAttributeString("disabled_control", attrib_str)) { LLControlVariable* control = findControl(attrib_str); if (control) setDisabledControlVariable(control); } if(node->getAttributeString("visibility_control",attrib_str) || node->getAttributeString("visiblity_control",attrib_str)) { LLControlVariable* control = findControl(attrib_str); if (control) setMakeVisibleControlVariable(control); } if(node->getAttributeString("invisibility_control",attrib_str) || node->getAttributeString("invisiblity_control",attrib_str)) { LLControlVariable* control = findControl(attrib_str); if (control) setMakeInvisibleControlVariable(control); } }
BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params) { Params params(default_params); { LLFastTimer timer(FTM_PANEL_SETUP); LLXMLNodePtr referenced_xml; std::string xml_filename = mXMLFilename; // if the panel didn't provide a filename, check the node if (xml_filename.empty()) { node->getAttributeString("filename", xml_filename); setXMLFilename(xml_filename); } LLXUIParser parser; if (!xml_filename.empty()) { LLUICtrlFactory::instance().pushFileName(xml_filename); LLFastTimer timer(FTM_EXTERNAL_PANEL_LOAD); if (output_node) { //if we are exporting, we want to export the current xml //not the referenced xml parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); Params output_params(params); setupParamsForExport(output_params, parent); output_node->setName(node->getName()->mString); parser.writeXUI(output_node, output_params, &default_params); return TRUE; } if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml)) { llwarns << "Couldn't parse panel from: " << xml_filename << llendl; return FALSE; } parser.readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName()); // add children using dimensions from referenced xml for consistent layout setShape(params.rect); LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance()); LLUICtrlFactory::instance().popFileName(); } // ask LLUICtrlFactory for filename, since xml_filename might be empty parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); if (output_node) { Params output_params(params); setupParamsForExport(output_params, parent); output_node->setName(node->getName()->mString); parser.writeXUI(output_node, output_params, &default_params); } params.from_xui = true; applyXUILayout(params, parent); { LLFastTimer timer(FTM_PANEL_CONSTRUCTION); initFromParams(params); } // add children LLUICtrlFactory::createChildren(this, node, child_registry_t::instance(), output_node); // Connect to parent after children are built, because tab containers // do a reshape() on their child panels, which requires that the children // be built/added. JC if (parent) { S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : parent->getLastTabGroup(); parent->addChild(this, tab_group); } { LLFastTimer timer(FTM_PANEL_POSTBUILD); postBuild(); } } return TRUE; }